How can I create mileposts for roads and trails with ArcGIS 10.2?

9867
5
07-01-2015 04:30 PM
AmandaTaub
New Contributor II

We need to be able create milepost points from our shapefiles for road lines and trail lines . I have Advanced ArcGIS Desktop 10.2 and our transportation folks have Basic 10.2. Is there a python script or a geoprocessing tool available to do this?

0 Kudos
5 Replies
DanPatterson_Retired
MVP Emeritus

Some threads on the web cover several alternatives for your versions...check these options and depending upon your needs, one should suit

arcgis 10.1 - How to create a point file along a line (trail) at regular distances (0.20 miles)? - G...

PS searching for mileposts on the help (ie within linear referencing) basically assumes that they have already been created

AmandaTaub
New Contributor II

Thank you, Dan!  I will get this out and see if it works for us.

0 Kudos
XanderBakker
Esri Esteemed Contributor

You could create a script that creates a point for each milepost. A simple snippets is shown below:

def main():
    import arcpy
    fc = r"C:\Forum\RoadSlope\Road.shp"
    fc_out = r"C:\Forum\RoadSlope\Mileposts2.shp"
    interval = 1000 # adjust

    flds = ("SHAPE@")
    lst = []
    with arcpy.da.SearchCursor(fc, flds) as curs:
        for row in curs:
            line = row[0]
            dist = 0
            while dist <= line.length:
                pnt = line.positionAlongLine(dist, use_percentage = False)
                lst.append(pnt)
                dist += interval
    arcpy.CopyFeatures_management(lst, fc_out)

if __name__ == '__main__':
    main()

This however, only creates points and has no attributes, so you would not be able to label the mileposts. The alternative would be to create the empty output featureclass (with a field to store the mileage) and to use an arcpy.da.InsertCursor to fill it.

Be aware that this procedure only uses the length of the polyline and linear unit of the spatial reference into account. In case you have M-aware geometries you may have a line that starts at M=1.5 (miles) and end in M=10.27 (miles). This would require reading the M value to correctly place the mileposts.

As an alternative (if you are looking to locate and label mileposts) you could use Create Routes—Help | ArcGIS for Desktop if the lines aren't already routes, and use About hatching route feature classes—Help | ArcGIS for Desktop to do the job.

AmandaTaub
New Contributor II

Thank you, Xander. I will get this out and see if it works for us.

0 Kudos

I do it like this because I use LRS.  With this script I can use my routes with measures to create points at different increments for different LRS Reference Methods:

pydot/HatchFake.py at master · KDOTGIS/pydot · GitHub 

'''
Created on Jul 14, 2015
This script will create route events as points along the route features at specific increments
the points can be symbolically displayed as route hatches for web mapping
@author: Kyle Gonterwitz with, as always the amazing help from Dirk Talley
@contact: Kyleg@Ksdot.org
'''

#import arcpy
from arcpy import (AddField_management, MakeFeatureLayer_management, CreateTable_management,da, Exists, AddXY_management,
TruncateTable_management, Append_management, MakeRouteEventLayer_lr, Delete_management, FeatureClassToFeatureClass_conversion, env)
#set the geodatabase parameters for the input route data
env.overwriteOutput = True
wsPath = r"Database Connections\shared@SQLGIS_cansys_gis_dev.sde" #enter the workspace path that has the data owner login
StatefcRoutes = r"\\gisdata\arcgis\GISdata\Connection_files\RO@sqlgisprod_GIS_cansys.sde\GIS_CANSYS.SHARED.SMLRS"  # State Route feature class with begin/end attribs 
CountyfcRoutes = r"\\gisdata\arcgis\GISdata\Connection_files\RO@sqlgisprod_GIS_cansys.sde\GIS_CANSYS.SHARED.CMLRS"  #County Route Feature Class with begin/end attribs 
#State and County are the Two main Linear Referecing Methods used by KDOT which will be hatched
StateOutTable = "SMHatch"
CountyOutTable=  "CMHatch"
StateFields = ["LRS_Route", "BEG_STATE_LOGMILE", "END_STATE_LOGMILE"]
CountyFields = ["LRS_KEY", "BEG_CNTY_LOGMILE", "END_CNTY_LOGMILE"]
#this field sets the hatch separation/spacing.  For a hatch point every 1/10 of a mile, enter 0.1.  For a hatch every 1/100th of a mile, choose 0.01.  
#for mapping in KanPlan 1/10 mile seems plenty sufficient, and will create about 108,000 points for each LRM.  
#1/100 would create 1,080,000 points which might suffer from use of in-memory processing, already this script takes a few minutes to run for each LRM 
HatchSep = 0.1
countyLRM = [CountyfcRoutes, CountyOutTable, CountyFields]
stateLRM = [StatefcRoutes, StateOutTable, StateFields]
LRMethod = [countyLRM, stateLRM]

for method in LRMethod:
    print "creating hatches for " + str(method[1])
    #add route table as feature layer
    if Exists("RouteLyr"):
        Delete_management("RouteLyr")
    else:
        pass
    MakeFeatureLayer_management(method[0], "RouteLyr", "DIRECTION in (  1 ,  2 )")
    #create event table in memory
    mem_table = "HatchEvents"
    if Exists(r"in_memory\\"+mem_table):
        print str(mem_table) +"already existed, deleting"
        Delete_management(r"in_memory\\"+mem_table)
    else:
        print "Creating table for processing route increments of " + str(HatchSep)
        
    CreateTable_management("in_memory", mem_table)
    mem_table = r"in_memory\\"+mem_table
    AddField_management(mem_table, "RouteID", "TEXT")
    AddField_management(mem_table, "LogMile", "Double")
    
    for row in sorted(da.SearchCursor("RouteLyr", (method[2]))): # @UndefinedVariable
        LRSKEY = row[0]
        if LRSKEY == (LRSKEY):  
            # use this loop to test the script against a single route
            iter0 = row[1]
            #print row[0]+ ' from '+str(row[1])+' to '+str(row[2])  #print the current LRS Key
            #set the begin and end parameters from which to create incremental values
            if HatchSep == 0.1:
                round_dec = 1
            elif HatchSep == 0.01:
                round_dec = 2
            else:    
                round_dec = 0
                print "check hatch separation value"
            minlog = round(row[1], round_dec)
            if minlog > row[1]:
                minlog = minlog - HatchSep
            else:
                pass
            maxlog = round(row[2], round_dec)
            if maxlog < row[2]:
                maxlog = maxlog + HatchSep
            else:
                pass
            #set the starting point for the route segment
            itermile = minlog 
            #now loop between the start and end logmiles for each route segment, and insert the step increment into the event table in memory
            while itermile <= maxlog and itermile >= minlog:
                #print str(itermile) 
                with da.InsertCursor(mem_table, ("RouteID", "LogMile")) as insert:# @UndefinedVariable
                    insertfields = [LRSKEY, itermile]
                    insert.insertRow(insertfields)
                itermile = itermile + HatchSep
            del minlog
            del maxlog
        
    MakeRouteEventLayer_lr("RouteLyr", method[2][0], mem_table, "RouteID POINT LogMile", "HatchPoints_events", "", "ERROR_FIELD", "ANGLE_FIELD", "NORMAL", "COMPLEMENT", "LEFT", "POINT")
    #add XY points, later on these coordinates can be used to hyperlink to google street view, bing maps, etc.  Make sure we are in NAD83 Lat/Long CRS here.
    AddXY_management("HatchPoints_events")
    try:
        Delete_management(wsPath+'//'+method[1])
        FeatureClassToFeatureClass_conversion("HatchPoints_events", wsPath, method[1], "LOC_ERROR = 'NO ERROR'")
    except:
        TruncateTable_management(wsPath+'//'+method[1])
        Append_management("HatchPoints_events", wsPath+'//'+method[1])
    cleanup = [mem_table, "RouteLyr", "HatchPoints_events"]
    for layer in cleanup:
        Delete_management(layer)