Question

Extend line in polygon to edge of this polygon

  • 10 December 2019
  • 3 replies
  • 45 views

Badge +2

Having trouble extending a line to the edge of the polygon it is in.

The above example are boxes (different colours) and centre lines (red lines) both as a separate datasets and an attribute that contains the ID connects them if needed. I would like to extend all the lines straight forward (both ways, thus adding the green line) until it touches the edge of the polygon it is in, similar performance as the Extend function in AutoCAD. Is there a similar transformer that does this with two datasets like this?

I tried the line extender and clipping and also the snapper but without satisfying results.

 


3 replies

Badge +3

I would think LineExtender followed by Clipper would form the basis for a solution?

Maybe the only thing you are missing is that for this to work, first get the Polygon ID attribute onto the inside line by a SpatialRelator first. Use the Inside line as the Requestor and the polygon as the Supplier.

Then use "PolygonID" as the Group By setting on the Clipper. With this set, this will restrict the Transformer to only clip each line with a clipping feature that has the same Polygon ID, and not use any of the other polygons to clip it..

The end result is then that all lines output on the Clipper's "Inside" port will be the lines trimmed to the boundary of the corresponding polygon with the same Polygon ID attribute.

Badge

1. LineOnAreaOverlayer to match the polygon to the line and get them to give each other their IDs.

 

2. A couple of AttributeCreators to concatenate their IDs to a new common ID (e.g. ID 45 from the line and ID 56 from the polygon results in a new combined ID of "45-56".

 

3. LineExtender to extend the line "a good bit" outside the polygon. (The "good bit" can be calculated or guessed.) Use the Stretched output port.

 

4. Clipper with the line as clippee and the polygon as clipper, group by common ID.
Badge +22

There are several options.

 

 

LineExtender and Clipper is the simplest,  but you absolutely want a common id between the polygon and centerline.  Counter on the polygon and SpatialFilter/Relator  to transfer the polygon id to the centerline,  and then use it as a group by on the clipper.

 

 

AnchoredSnapper with the polygons as the anchors and the centerlines as the candidates.   I don't really recommend this.

PythonCaller  to algebraically calculate the ray-line intersection point.  The math is explained at https://rootllama.wordpress.com/2014/06/20/ray-line-segment-intersection-test-in-2d/ 

 

The logic would be 
  • chop the polygon into 2 vertex line segments.   
  • convert the centerline into a forward ray
    • snip the centerline to the last two vertices
    •     def rayFromSegment(self, line):
              #returns a tuple of the end point of the line and the direction vertex
              o = np.array(line.getStartPoint().getXYZ())
              e = line.getEndPoint()
              p = np.array(e.getXYZ())
              #direction vertex
              d = p - o
              return (e,d)
  • for each side of the polygon calculate the intersection point
    •     def rayIntersectsSegment(self, ray, line):
              #origin and direction vector
              o = ray[0].getXYZ()
              d = ray[1]
              #segment start and end points
              a = np.array(line.getStartPoint().getXYZ())
              b = np.array(line.getEndPoint().getXYZ())
             
            #vectors 
              v1 = o-a
              v2 = b - a
              #0 is added to v3 Z to have consistent dimensionality since getYXZ() always returns a z value, even when the lines are 2D
              v3 = (-d[1],d[0],0)
              denom = np.dot(v2,v3)
              t1 = (np.cross(v2,v1) / denom)[2]
              t2 = np.dot(v1,v3)/denom
              if t1 >= 0.0 and t2 >= 0.0 and t2<=1.0:
                  p = o+t1*d
                  return fmeobjects.FMEPoint(p[0],p[1],p[2])
              else:
                  return None
  • determine which is the closest , you can use the squared distance to avoid expensive square root calculations.
    •     def squaredDistance(self, p1,p2):
              p1 = p1.getXYZ()
              p2 = p2.getXYZ()
              dX = p2[0]-p1[0]
              dY = p2[1]-p1[1]
              d = dX*dX + dY*dY
              return d
  • add the closest point to the end of the centerline.
  • repeat with the first two vertices in the reversed direction to get the backwards extension from the start of the centerline.

Reply