Select to view content in your preferred language

How do I create points along a polyline based on distance?

11225
19
10-01-2014 02:21 PM
JoshWhite
Regular Contributor III

Is there a tool or script out there than can be used to create points along a polyline based on a distance in table?

Josh White, AICP
Principal Planner

City of Arkansas City
Tags (1)
19 Replies
RichardFairhurst
MVP Honored Contributor

Actually, LR is more flexible than a python geometry object.  I can chain point events together and create line segment events and a line segment event table can be displayed as either points or segments, depending on how I set up the Route Event layer.  I can make the point fall on the line or offset to the side of the line with another event layer setting change.  And with another setting change I can get tangent or normal angles to the line at each point automatically to set rotations relative to the line with no real effort.  By setting up multiple layers I can make one LR table function as at least 5 different point or line segments layers simultaneously and do different geometry calculations from each layer that all write back to fields in one table.  So, LR is much more than a fixed point on a line (although it can become that with a simple export in seconds).

I only pursue code as a replacement for built-in tools if the built-in tools cannot do the task required or the code can outperform the tools.  Since python geometry does neither, I will promote LR until someone demonstrates they can beat it on one account or the other.

The Create Route tool is the starting point to create routes from lines.  It is reasonable to assume the table mentioned in this post already has a Route ID and distance, so the field that defines that ID would be used with the Create Route tool. Some type of orientation has to be assumed for the way the distances increase and the tool has a variety of options for maintaining the measures so that they comply with that orientation.  I personally use the Coordinate Priority option.  Once the routes are built, right click the table and choose the Create Route Event layer menu item.  The settings are pretty straight forward to choose the Routes, Route ID, and measure (distance) field.  If you need a side offset you can apply that with a side distance field.  Advanced settings let you get an error code for distances that fall off the line or get a tangent or normal angle in arithmetic or geographic angles.

0 Kudos
DanPatterson_Retired
MVP Emeritus

As Darren says it is easy it is fairly easy.. As an example, I have an example of a function that I use in the field calculator that allows you to get the X or Y coordinate tool for polylines or polygon perimeters.  It is much like the Calculate Geometry tool but allow for some fine tuning of the position and in what format to return (many threads contributed to its final form).  But in any event, it could easy be put into use.  The "shape" variable is either a shape like when running through a cursor or the shape field (!Shape!, usually) when using the field calculator

def pnt_along(shape, value, use_fraction, XorY):
    """
    :Required:
    :--------
    :  shape field, value (planar distance or decimal fraction, 0-1),
    :  use_fraction (True/False), XorY (X or Y):
    :
    :Returns:
    :-------
    :  A point x meters, or x decimal fraction along a line.
    :  User specifies whether X or Y coordinates.
    :
    :Useage:  For field calculator...
    :------
    :  pnt_along(!Shape!, 100, False, 'X')  #eg. X coordinate 100 m from start point
    :
    :Notes:  Project the data prior to using absoulte distances.
    :-----
    :
    """
    XorY = XorY.upper()
    if use_fraction and (value > 1.0):
        value = value/100.0
    if shape.type.lower() == "polygon":
        shape = shape.boundary()
    pnt = shape.positionAlongLine(value, use_fraction)
    if XorY == 'X':
        return pnt.centroid.X
    else:
        return pnt.centroid.Y
‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

in any event, enjoy... and thanks to the ideas of its predecessors

0 Kudos
RichardFairhurst
MVP Honored Contributor

Absolute distances with the positionAlongLine method always have to be in meters.  LR by default uses the length units of the original line when the Length option is checked in the Create Routes tool and that tool has the option to apply a conversion factor that can convert the measures to any units of measurement desired.

0 Kudos
JoshWhite
Regular Contributor III

Wow, looks like I opened a can of worms on that one.  They've released a new version of the CCTV processor that I am going to try out.

Josh White, AICP
Principal Planner

City of Arkansas City
0 Kudos
DarrenWiens2
MVP Honored Contributor

Richard, the units for positionAlongLine are determined by the spatial reference of the Polyline object. For example, the following snippet places a point 1000 feet from the start of the line, because "kentucky_line" uses the Kentucky State Plane US Feet projection:

>>> for row in arcpy.da.SearchCursor("kentucky_line", ["SHAPE@"]):

...     point = row[0].positionAlongLine(1000)

>>> arcpy.CopyFeatures_management(point, 'in_memory\point')

0 Kudos
RichardFairhurst
MVP Honored Contributor

Sorry about my bad assumption.  The descriptions of some of the methods in the Geometry help suggest that they only return values in meters (getLength) and square meters (getArea) and the help document is far from clear about how any of the other functions behave with regard to units, so I thought this method might have a similar restriction.  Anyway, I grant that LR and the postionAlongLine geometry function are equal as far as unit handling.

Darren:  I am curious.  What is the performance of your code example?  How many points does it generate and how long does it take?

0 Kudos
DarrenWiens2
MVP Honored Contributor

The following runs in 44 seconds (12 of which are tied up in CopyFeatures), placing 100,000 points.

>>> import cProfile
... def drawPoints():
...    reps = 100000
...    points = []
...    with arcpy.da.SearchCursor("a_line",'SHAPE@') as cursor: # only one line
...        for row in cursor:
...            for i in range(reps):
...                points.append(row[0].positionAlongLine(1000))
...    arcpy.CopyFeatures_management(points, r'in_memory\points')
... cProfile.runctx('drawPoints()',None,locals())
DanPatterson_Retired
MVP Emeritus

Grief Richard....No the function isn't restricted on one planar measure.  It uses the coordinate system of the incoming shape. 


However, since you bring it up, It is common only to use projected data for such a function, since the position between two geodesic points (ie Long/Lat coordinates) need not be on the imaginary line connecting them but on the geodesic line. 

There are other examples for this, but Josh's main issue is getting off topic.

Also, in Canada, we use metres (Canadian and world-wide spelling) or meters (US spelling) and my examples for teaching purposes and serves as a gentle reminder to ensure to use planar coordinates when trying to determine geometric properties of spatial features.

Sorry Josh...back to  you

0 Kudos
MiniAgarwal
New Contributor

you acn use this python script to generate point along polyline  . here i have taken distance 50.

import arcpy, math, datetime, numpy

print ("starting")

start = datetime.datetime.now() # for calculating time of process

midpoint =  "E:/test/testShape.shp" 

polyline = "c:/arcgis/MyLR/baseroads.shp"

#housekeeping

  1. arcpy.DeleteFeatures_management(midpoint)
  2. arcpy.env.overwriteOutput = True

with arcpy.da.SearchCursor(polyline, "SHAPE@") as in_cursor, \

  1. arcpy.da.InsertCursor(midpoint, "SHAPE@") as out_cursor:

    for row in in_cursor:

                midpoint = row[0].positionAlongLine(50)

                out_cursor.insertRow([midpoint])

0 Kudos
ClaudiaEQuicenoR
New Contributor

You can use the geoprocessing tool Create RouteEvent layer

0 Kudos