3

For an existing set of line features, I would like to generate a perpendicular line, of say 1km, at the midpoint of each existing line feature in ArcGIS.

I imagine that The methodology would be to:

  1. create a tangent line at the midpoint of each existing line feature
  2. calculate the angle of the tangent line
  3. based on the angle of the tangent line, calculate the location of the endpoint of the new line
  4. create the new line with the calculated endpoint of the new line and the existing midpoint of the old line

Let's assume that we are in a UTM projection and can use coordinates to calculate distance and direction.

How would I do this with ArcGIS tools or with ArcPy?

Will McInnes
  • 450
  • 3
  • 10
  • What have you got so far? What have you tried and where are you stuck? Is there any of your code that you can post to show where you're up to? The calculation of the points to form the new line are simple high school geometry calculations, do you have equations you want to implement? – Michael Stimson Jul 12 '16 at 22:04
  • 2
    You can download a Tool that creates Perpendicluar Lines at Line midpoints. The download errors out for me but the download is ok. ftp://lnnr.lummi-nsn.gov/GIS_Scripts/createperpendicularlines.zip – klewis Jul 12 '16 at 22:08
  • The perpendicular lines tool looks promising, I will test it out and get back. @Michael-Miles-Stimson, calculating a new line is relatively straighforward when you know the bearing of the tangent - where I'm stuck is how to calculate the tangent line for a point along a line in ArcMap. – Will McInnes Jul 12 '16 at 22:25
  • 1
    @WillMcInnes, get the midpoint of the line and then find the previous and next vertex. You can calculate the bearing between those two vertices, +/- 90°, and then drop a point 1km away. – Paul Jul 12 '16 at 22:45
  • Google says http://www.sagemath.org/calctut/tangent.html and a few more. You will need to decide if the ray is on the left or right when proceeding from vertex (n) to vertex (n + 1). Midpoint of a straight line is X = (X(n) + X(n + 1)) / 2 and likewise for Y - just an average of the X and Y. What I would need to see is how you're iterating existing line segments, generating the new tangent line features and storing them - there's a few methods for this in arcpy. If you were doing this in C# you could use IConstructPoint interface to do the maths. – Michael Stimson Jul 12 '16 at 22:53
  • 1
    The Lummi Create Perpendicular line tool as mentioned will create a line perpendicular to the mid point of the line. The tool will create the line left of, right of, or on both sides of the line-at the start, end, or midpoint...As mentioned, the tool is available here: lnnr.lummi-nsn.gov/GIS_Scripts/createperpendicularlines.zip klewis 22 had a time-out error but the Lummi FTP site will not time out a connection. Try downloading outside of your professional organizations firewall. – GBG Jul 13 '16 at 20:28

2 Answers2

11

Based on @Felix's answer, here's an approach that uses built-in methods on geometry objects. Supported on 10.3+.

from math import atan2, pi

# epsilon
e = 1e-10

def tangentLine(line, dist):
    '''creates a tangent line of length dist at line midpoint
    line - arcpy.Polyline() object
    dist - distance in meters
    '''

    midpoint = line.positionAlongLine(0.5, True)

    # get points immediately before and after midpoint
    before = line.positionAlongLine(0.5-e, True)
    after = line.positionAlongLine(0.5+e, True)

    dX = after.firstPoint.X - before.firstPoint.X
    dY = after.firstPoint.Y - before.firstPoint.Y

    # angle of the midpoint segment
    angle = atan2(dX, dY) * 180 / pi
    newpoint = midpoint.pointFromAngleAndDistance(angle + 90, dist)

    return arcpy.Polyline(arcpy.Array((midpoint.firstPoint, newpoint.firstPoint)))

You could use cursors to read the line geometries and write them to a new feature class. Or, for a "great" 1 liner:

arcpy.CopyFeatures_management([tangentLine(line, 1000)
    for line in arcpy.CopyFeatures_management("myFC", arcpy.Geometry())],
    "in_memory/tangentLines")

The +90 will place the tangent line on the right side of the input line (based on digitized direction).

Paul
  • 11,608
  • 1
  • 29
  • 47
8
  • Create midpoints, using one of multiple possible techniques.
  • Buffer them by small number, e.g. 0.5 m
  • Clip originals by buffer, output - SHAPEFILE

Use this field calculator expression on field Shape:

def RotateExtend(plyP,sLength):
 l=plyP.length
 ptX=plyP.positionAlongLine (l/2).firstPoint
 ptX0=plyP.firstPoint
 ptX1=plyP.lastPoint
 dX=float(ptX1.X)-float(ptX0.X)
 dY=float(ptX1.Y)-float(ptX0.Y)
 lenV=math.sqrt(dX*dX+dY*dY)
 sX=-dY*sLength/lenV;sY=dX*sLength/lenV
 leftP=arcpy.Point(ptX.X+sX,ptX.Y+sY)
 rightP=arcpy.Point(ptX.X-sX, ptX.Y-sY)
 array = arcpy.Array([leftP,rightP])
 section=arcpy.Polyline(array)
 return section

-------------------------------

RotateExtend( !Shape!, 1000)

UPDATE:

Ooops! it creates perpendicular, not tangent. Can be easily modified

FelixIP
  • 22,922
  • 3
  • 29
  • 61
  • Does this need to be used by an InsertCursor? Can I manually run this to add Polylines to a feature class? – klewis Jul 12 '16 at 23:11
  • Feature Vertices to Points tool with the midpoint option specified is one way to get midpoints. – Tom Dilts Jul 12 '16 at 23:15
  • @klewis it modifies existing short features, thus you cannot use it to create new – FelixIP Jul 13 '16 at 00:47
  • The buffer was the missing piece! I calculated the midpoint, buffered, and then created the perpendicular lines, worked great. – Will McInnes Jul 22 '16 at 17:22