ThinkGeo.com    |     Documentation    |     Premium Support

Perpendicular Line

Hi,


I have a road with Lanes (Polygons) and a Center Line (ShapeLine). I need to get the Lanes intercepted in the TrackShapeLayer.


I need that the Lanes have a perfect cut (90 degrees angles). So my aproach was:


 


1 - Use the Track to intercept with the Center Line (Polilyne).- Done


2 - Get the two Points of interception.- Done


3 - Get the Distance to the Begining of the Line (first vertex). -  Done


4- For each intercepted point, create a Perpendicular Line with a give lenght.


5- Use those new lines to cut the Polygons.


 


        private void TrackEnded(object sender, TrackEndedTrackInteractiveOverlayEventArgs e)
        {

            try
            {
                //Get Envelope
                AreaBaseShape areaBaseShape = (AreaBaseShape)winformsMap1.TrackOverlay.TrackShapeLayer.InternalFeatures[0].GetShape();

                //Get the CenterLineLayer
                ShapeFileFeatureLayer CenterLineLayer = (ShapeFileFeatureLayer)winformsMap1.StaticOverlay.Layers["CenterLineLayer"];

                //Get All the Features for CenterLineLayer
                Collection<Feature> features = CenterLineLayer.FeatureSource.GetAllFeatures(ReturningColumnsType.AllColumns);
                foreach (Feature feature in features)
                {
                    //Gets the MultipolygonShape and clip it using GetCrossing geometric function.
                    MultilineShape currentMultilineShape = (MultilineShape)(feature.GetShape());
                    MultipointShape overlapPointShape = currentMultilineShape.GetCrossing(areaBaseShape);

                    if (overlapPointShape != null && overlapPointShape.Points.Count >= 2)
                    {
                        //Measure Points Distance to origin
                        int count = 0;
                        double offset = 0;
                        Collection<PointShape> points = overlapPointShape.Points;
                        double[] Distances = new double[points.Count];
                        foreach (PointShape ps in points)
                        {
                            LineShape targetLineShape = currentMultilineShape.Lines[0];
                            LineShape tempLine = (LineShape)targetLineShape.GetLineOnALine(StartingPoint.FirstPoint, ps);
                            double crossPointDistance = tempLine.GetLength(GeographyUnit.Meter, DistanceUnit.Meter) - offset;
                            Distances[count] = crossPointDistance;
                            count++;
                        }
                    }
                }

                //Get All the Features for LanesLayer
                ShapeFileFeatureLayer LanesLayer = (ShapeFileFeatureLayer)winformsMap1.FindFeatureLayer("LanesLayer");
                Collection<Feature> Lanesfeatures = LanesLayer.FeatureSource.GetAllFeatures(ReturningColumnsType.AllColumns);
                foreach (Feature feature in Lanesfeatures)
                {
                    MultipolygonShape currentMultiPolygonShape = (MultipolygonShape)(feature.GetShape());
                    MultipolygonShape overlapMultiPolygonShape = currentMultiPolygonShape.GetIntersection(areaBaseShape);

                    if (overlapMultiPolygonShape != null)
                    {
                        SituationsLayer.EditTools.BeginTransaction();
                        SituationsLayer.EditTools.Add(overlapMultiPolygonShape.GetFeature());
                        SituationsLayer.EditTools.CommitTransaction();
                    }
                }

                //Referesh Map
                winformsMap1.Refresh(StaticOverlay);

            }
            catch(Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }

            //Clear Envelope
            winformsMap1.TrackOverlay.TrackShapeLayer.InternalFeatures.Clear();
        }


 


 In the image attached, the red line is the Center Line, there are two blue points and what I need to create are the two green lines and then cut the lanes.


 


Regards


Miguel



 


Miguel,
 
Thanks for your post!
 
You forgot attaching your demonstrated image, hope you can attached it if you still can not solve your problem.
 
From you description, I know you want to get the perpendicular line for specified line with specified point. You can look at following code, it will ignore the intercepted point which is exactly match a vertex of line.
 

 private Collection<LineShape> GetPerpendicularLines(LineShape lineShape, Collection<PointShape> interceptedPoints)
        {
            Collection<LineShape> returnFeatures = new Collection<LineShape>();
            double length = 1.0;
            double pi2 = Math.PI / 2;
            double searchingTolerance = 0.000001;
            foreach (PointShape interceptedPoint in interceptedPoints)
            {
                RectangleShape searchingArea = new RectangleShape(interceptedPoint.X - searchingTolerance, interceptedPoint.Y + searchingTolerance, interceptedPoint.X + searchingTolerance, interceptedPoint.Y - searchingTolerance);

                // Check if the intercepted point is the vertex will be ignore, because we can not create perpendicular line crosses vertex.
                foreach (Vertex vertex in lineShape.Vertices)
                {
                    if (new PointShape(vertex).IsWithin(searchingArea))
                    {
                        continue;
                    }
                }

                double middleX = interceptedPoint.X;
                double middleY = interceptedPoint.Y;

                Vertex vertex1 = new Vertex();
                Vertex vertex2 = new Vertex();
                // Find the crossing point is between which two vertices
                for (int i = 0; i < lineShape.Vertices.Count - 1; i++)
                {
                    vertex1 = lineShape.Vertices[i];
                    vertex2 = lineShape.Vertices[i + 1];
                    LineShape currentLine = new LineShape(new Vertex[] { vertex1, vertex2 });
                    if (searchingArea.Intersects(currentLine))
                    {
                        break;
                    }
                }

                double angle = Math.Atan((vertex1.Y - vertex2.Y) / (vertex1.X - vertex2.X));

                double x = 0;
                double y = 0;

                if (angle > 0 && angle < pi2)
                {
                    if (vertex1.X > vertex2.X)
                    {
                        x = middleX + Math.Sin(angle) * length;
                        y = middleY - Math.Cos(angle) * length;
                    }
                    else
                    {
                        x = middleX - Math.Sin(angle) * length;
                        y = middleY + Math.Cos(angle) * length;
                    }
                }
                else
                {
                    if (vertex1.X > vertex2.X)
                    {
                        x = middleX + Math.Sin(angle) * length;
                        y = middleY - Math.Cos(angle) * length;
                    }
                    else
                    {
                        x = middleX - Math.Sin(angle) * length;
                        y = middleY + Math.Cos(angle) * length;
                    }
                }

                LineShape line = new LineShape(new Vertex[] { new Vertex(middleX, middleY), new Vertex(x, y) });
                returnFeatures.Add(line);
            }

            return returnFeatures;
        }

 
Please let me know if you have questions.
 
James
 

HI James,


Thanks for your help.


I'm trying to add the result to a InMemoryFeatureLayer but I can't see none of the lines.


 


Collection
<lineshape>
perpLines = GetPerpendicularLines(targetLineShape, points); foreach (LineShape line in perpLines) { SituationsLayer.EditTools.BeginTransaction(); SituationsLayer.EditTools.Add(line); SituationsLayer.EditTools.CommitTransaction(); }


This is the image I refer in the last post.


What I need is to get the polygons (the yellow ones) cutted by the green lines.



Best Regards


Miguel



 


Miguel,
 
Did you set DefaultLineStyle and ApplyUntilZoomLevel properties for InMemoryFeatureLayer which you mentioned.
 
           SituationsLayer.ZoomLevelSet.ZoomLevel01.DefaultLineStyle.OuterPen = new GeoPen(GeoColor.StandardColors.Red, 50);
            SituationsLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
 
And how many perpLines in result collection, I think it should be 2, right?
If you still can not see lines on the map, you can set the length longer, my sample code set it to 1.0
And my code is just a sample, it just want to guide you how to do that, but some parameter may not quite right, maybe mislead you. So about how to cut, I don’t want send your code, instead I tell you the steps and you can do by yourself, I think it’s better.
 
The following steps are how to get the polygons cut by two lines.


        
  1. Get bounding box of original polygons.

  2.     
  3. Get the intersected points between two lines and bounding box.

  4.     
  5. Use four intersected points to create a new polygon.

  6.     
  7. Get intersection polygon between new polygon and original polygons.


 
 
Please let me know if you have questions.
 
Thanks
 
James

Hi James,


Thanks for your help.


Now I can see the two lines.


The lines grow from the point in the CenterLine instead of Crossing the CenterLine. You can see it in the Red left line. The Red right line it's how it should be. I will have to review trigonometrybecause I don't use it for a long time.



Concerning the polygon interception, I didn't understud very well what you ment. The lanes can be a corner so if I get the envelope from the four interception points, I could left behind part of the lane.


What I think should be my aproach is (for each intercepted lane):


1) Create the lines

2) Intercept the lane, getting 4 points

3) Splitte the polygon in two polylines using each two points.

4) Join the obtained 2 lines with the original crossing lines an create the polygon.


  


 


But I don't know how to do it with ThinkGeo. I meant splitte the polygon in twp polylines


 Regards


Miguel


 



 


Miguel,
 
You are very close to your result.
 
I update my code a little, you can try this code. 
 

            //LineShape line = new LineShape(new Vertex[] { new Vertex(middleX, middleY), new Vertex(x, y) });

            Vertex anotherVertex = new Vertex(middleX * 2 - x, middleY * 2 - y);
            LineShape line = new LineShape(new Vertex[] { anotherVertex, new Vertex(x, y) });
            returnFeatures.Add(line);

 
The black polygon is a lane, two red lines are intercept lines which cross the lane. And the blue dash envelop is the bounding box of lane which I am said, four blue points are crossing points which you can create a new polygon.
 
 

    private static PolygonShape GetIntersectionPolygon(PolygonShape lanePolygon, LineShape interceptLine1, LineShape interceptLine2)
    {
        RectangleShape boundingBox = lanePolygon.GetBoundingBox();
        MultipointShape twoCrossingPoints1 = boundingBox.GetCrossing(interceptLine1);
        Vertex crossingVertex1 = new Vertex(twoCrossingPoints1.Points[0]);
        Vertex crossingVertex2 = new Vertex(twoCrossingPoints1.Points[1]);

        MultipointShape twoCrossingPoints2 = boundingBox.GetCrossing(interceptLine2);
        Vertex crossingVertex3 = new Vertex(twoCrossingPoints2.Points[1]);
        Vertex crossingVertex4 = new Vertex(twoCrossingPoints2.Points[0]);

        RingShape ringShape = new RingShape(new Vertex[] { crossingVertex1, crossingVertex2, crossingVertex3, crossingVertex4, crossingVertex1 });
        PolygonShape interceptPolygon = new PolygonShape(ringShape);

        MultipolygonShape crossingPolygons = lanePolygon.GetIntersection(interceptPolygon);

        return crossingPolygons.Polygons[0];
    }

 
Please let me know if you have questions.
 
Thanks
 
James

HI James,


Thanks for your help.


I think your solution works fine if we are working with a straight line polygon not a turn.


Consider the next example:


 


Your code doesn't work, right?


What I need is:


- Split the lane in two polylines: First one from V2 to V4 (PolyLine1) and the other from V1 to V3 (PolyLine2).

- Cut the Intercept lines (the red ones) between V1 and V2 (PolyLine3) and the other from V3 to V4 (PolyLine4).

- Create a polygon using the four polylines (PolyLine1 + PolyLine2 + PolyLine3 + PolyLine4).


Just for you to understand what I'm trying to do.

This problem is only because of the TrackShape will create polygons with bad cut in the lanes.

At this point I can get the polygons intercepted by the TrackShape, that is easy. What I get at this moment is in the next picture (without the red lines).



So the centerLine in the middle (we can barely see it) will gave me the PKs (distances of interception in kilometers), and now I only need the green polygon between the red lines (drawn from one line to the other).


The next image show what I need (without the red lines).



I saw in a post that this version of Thinkgeo can't split a polygon in lines. Is it true? In that case I don't see a solution for my problem.


The link to the post.

gis.thinkgeo.com/Support/Dis...fault.aspx


Regards


Miguel



 


Miguel,
 
Our developers write a Split method which pass in the polygon and line and return splitted two parts of polygon, I think you can look at it which will be helpful.
But the line has some restriction, the start vertex and end vertex of the line should be outside the polygon, the line just has two crossing points with polygon, I think your requirement is fit for it.
 
Please let me know if you have questions
 
Thanks
James

1460-Program.cs (10.4 KB)

Miguel,


I have updated the Split code and added a method called SplitPolygonShapeWithTwoLineShape which pass in a polygon and two lines, that will be more close to what you want.

Thanks


James


 


 



1463-Program.cs (11.6 KB)

Hi James,


It works very well. You had a lot of work with this.


Thanks for your help.



Best Regards


Miguel



James, 
  
   Can you e-mail Val with this link and send him the code.  I think this kind of feature would make a good addition to our code community at code.thinkgeo.com
  
 David

David, 
  
 Thanks for your suggestion! I think it’s a good idea that I will do it. 
  
 James