ArcGIS Pro Arcpy – Creating LRS Dataset from Line Feature Class with Route IDs and Measures

arcgis-proarcgis-roads-highwaysarcpylinear-referencing

I am using ArcGIS Pro 2.9.3 with the Location Referencing extension.

I am trying to create an LRS dataset so that I can start using the Location Referencing tab on the ribbon to edit routes. I have a line feature class (testFC) with fields for RouteID, FromMeasure and ToMeasure that I can easily create a route feature class from but that does not make the Location Referencing tab become available.

My test data is simple – see picture below:

enter image description here

I use the code below to create the test data above (testFC), an empty LRS dataset (testLRS), and an intermediate feature dataset (testFD) into which I've copied testFC as intermediateFC as well as the empty Calibration_Point and Redline feature classes from testLRS because they need to be there to use the Create LRS From Existing Dataset tool.

import arcpy

arcpy.env.overwriteOutput = True

# Create empty feature class and its schema
sr = arcpy.SpatialReference("GCS_WGS_1984")
arcpy.management.CreateFileGDB(r"C:\temp","test")
arcpy.management.CreateFeatureclass(r"C:\temp\test.gdb","testFC","POLYLINE")
arcpy.management.DefineProjection(r"C:\temp\test.gdb\testFC",sr)
arcpy.management.AddField(r"C:\temp\test.gdb\testFC","RouteID","LONG")
arcpy.management.AddField(r"C:\temp\test.gdb\testFC","FromMeasure","DOUBLE")
arcpy.management.AddField(r"C:\temp\test.gdb\testFC","ToMeasure","DOUBLE")

# Write two lines and their attributes to the feature class
cursor = arcpy.da.InsertCursor(r"C:\temp\test.gdb\testFC",["SHAPE@","RouteID","FromMeasure","ToMeasure"])
array = arcpy.Array([arcpy.Point(0.0,0.0),
                     arcpy.Point(0.0,1.0)])
polyline = arcpy.Polyline(array,sr)
cursor.insertRow([polyline,1,0.0,1.0])
array = arcpy.Array([arcpy.Point(0.0,1.0),
                     arcpy.Point(1.0,1.0)])
polyline = arcpy.Polyline(array,sr)
cursor.insertRow([polyline,2,1.0,2.0])
del cursor

# Create empty TestLRS dataset and TestLRSNetwork for testing, and copying schema from
# Create empty LRS dataset (TestLRS), with default names for three feature classes (Calibration_Point,Centerline,
# Redline) and an LRS Hierarchy (TestLRS) within it, and three tables (Centerline_Sequence, Lrs_Edit_Log,Lrs_Locks)
gdb = r"C:\temp\test.gdb"
if arcpy.Exists(r"{0}\{1}".format(gdb,"TestLRS")):
    arcpy.management.Delete(r"{0}\{1}".format(gdb,"TestLRS"))
if arcpy.Exists(r"{0}\{1}".format(gdb,"Centerline_Sequence")):
    arcpy.management.Delete(r"{0}\{1}".format(gdb,"Centerline_Sequence"))
if arcpy.Exists(r"{0}\{1}".format(gdb,"Lrs_Edit_Log")):
    arcpy.management.Delete(r"{0}\{1}".format(gdb,"Lrs_Edit_Log"))
if arcpy.Exists(r"{0}\{1}".format(gdb,"Lrs_Locks")):
    arcpy.management.Delete(r"{0}\{1}".format(gdb,"Lrs_Locks"))
if arcpy.Exists(r"{0}\{1}".format(gdb,"TestLRS")):
    arcpy.management.Delete(r"{0}\{1}".format(gdb,"TestLRS"))
print("Creating LRS dataset named {0}".format("TestLRS"))
arcpy.locref.CreateLRS(gdb,"TestLRS","Centerline","Calibration_Point","Redline","Centerline_Sequence",sr,
                       "8.98315284119521E-09 DecimalDegrees","0.001 Meters",
                       "0.000000001 DecimalDegrees","0.0001 Meters")
print("Creating LRS Network ({0}) in LRS dataset ({1}".format("TestLRSNetwork","TestLRS"))
arcpy.locref.CreateLRSNetwork(gdb, "TestLRS", "TestLRSNetwork",
                              "RouteId", "RouteName", "FromDate", "ToDate", "DO_NOT_DERIVE", '',
                              "DO_NOT_INCLUDE", "LineId", "LineName", "LineOrder", "KILOMETERS")

print("Creating intermediate feature dataset")
arcpy.management.CreateFeatureDataset(gdb,"IntermediateFD")
arcpy.management.DefineProjection(r"{0}\{1}".format(gdb,"IntermediateFD"),sr)
print("Copying testFC into IntermediateFD as IntermediateCL")
arcpy.management.CopyFeatures(r"C:\temp\test.gdb\testFC",r"C:\temp\test.gdb\IntermediateFD\IntermediateFC")
emptyCalibrationFC = r"{0}\{1}\Calibration_Point".format(gdb,"TestLRS")
intermediateCalibrationFC = r"{0}\{1}\IntermediateCalibration".format(gdb,"IntermediateFD")
arcpy.management.CopyFeatures(emptyCalibrationFC,intermediateCalibrationFC)
emptyRoutelineFC = r"{0}\{1}\Redline".format(gdb,"TestLRS")
intermediateRoutelineFC = r"{0}\{1}\IntermediateRedline".format(gdb,"IntermediateFD")
arcpy.management.CopyFeatures(emptyRoutelineFC,intermediateRoutelineFC)

After running the code above my test.gdb looks like this:

enter image description here

I think I now have what is needed to create a FinalLRS using the Create LRS From Existing Dataset tool but when I start to use them to populate its parameters I get three warnings:

enter image description here

  • WARNING 130172 which I suspect will be easy to address by making testFC (and therefore IntermediateFC) z-aware.
  • WARNING 130010 telling me "The field has not been mapped" which I do not yet know how to address.
  • WARNING 130018 telling me "The chosen dataset is already being used with another LRS" which I suspect is correct but I do not yet know how to address it.

When I try to Run the tool it bails out because I've not addressed the first warning.

Before I expend more effort trying to address each of the three warnings, is there another (hopefully much simpler) way to create an LRS dataset from a "route-ready" line feature class (like my testFC with fields for RouteID, FromMeasure and ToMeasure)?

I am trying separately to find additional documentation/help via the Esri Community at Creating LRS Dataset from existing line/route feature class.

Best Answer

It took more effort than I originally anticipated but I ended up getting measured routes in an LRS dataset and network, as seen below, from test data generated and processed using the code and output that follows.

enter image description here

# This script is intended to create an empty LRS dataset and load
# the geometries of a test polyline feature class with route IDs (TEXT),
# Route Names (TEXT) and from/to measures (DOUBLE) into it so that an
# LRS Network with those routes can be created
import arcpy

arcpy.env.overwriteOutput = True

# Establish coordinate system and geodatabase to be used
srWGS84 = arcpy.SpatialReference("GCS_WGS_1984")
workingFolder = r"C:\temp"
gdbName = "test"
gdb = r"{0}\{1}.gdb".format(workingFolder,gdbName)
lrsName = "TestLRS"
lrsFD = r"{0}\{1}".format(gdb,lrsName)
testFCName = "testFC"
testFC = r"{0}\{1}".format(lrsFD,testFCName)
testStatsTableName = "testStats"
testStatsTable = r"{0}\{1}".format(gdb,testStatsTableName)
testDissolvedFC = r"{0}{1}".format(testFC,"_Dissolve")
calibrationFC = r"{0}\{1}".format(lrsFD,"Calibration_Point")
centerlineFC = r"{0}\{1}".format(lrsFD,"Centerline")
lrsNetworkName = "testLRSNetwork"
lrsNetworkFC = r"{0}\{1}".format(lrsFD,lrsNetworkName)
redlineFC = r"{0}\{1}".format(lrsFD,"Redline")
centerlineSequenceTable = r"{0}\{1}".format(gdb,"Centerline_Sequence")
newCalibrationPointsFCName = "NewCalibrationPoints"
newCalibrationPointsFC = r"{0}\{1}".format(lrsFD,newCalibrationPointsFCName)
newCalibrationPointsFCTempName = newCalibrationPointsFCName+"Temp"
newCalibrationPointsFCtemp = r"{0}\{1}".format(lrsFD,newCalibrationPointsFCTempName)
uniqueCalibrationPointsFCName = "UniqueCalibrationPoints"
uniqueCalibrationPointsFC = r"{0}\{1}".format(lrsFD,uniqueCalibrationPointsFCName)

# Create empty geodatabase for testing
arcpy.management.CreateFileGDB(workingFolder,gdbName)

# Create empty TestLRS dataset with default names for three feature classes
# (Calibration_Point,Centerline,Redline) and an LRS Hierarchy (TestLRS)
# within it, and three tables (Centerline_Sequence, Lrs_Edit_Log,Lrs_Locks)        
print("Creating LRS dataset named {0} in {1}".format(lrsName,gdb))
arcpy.locref.CreateLRS(gdb,lrsName,"Centerline","Calibration_Point",
                       "Redline","Centerline_Sequence",srWGS84)

# Prepare feature class from which routes will be appended into the LRS Network later
# Create empty feature class and its schema
print('Creating "route-ready" polyline feature class ({0}) in LRS dataset ({1})'.format(testFC,lrsFD))
arcpy.management.CreateFeatureclass(lrsFD,"testFC","POLYLINE")
arcpy.management.AddField(testFC,"RouteID","TEXT", None, None, 10)
arcpy.management.AddField(testFC,"RouteName","TEXT", None, None, 10)
arcpy.management.AddField(testFC,"FromMeasure","DOUBLE")
arcpy.management.AddField(testFC,"ToMeasure","DOUBLE")
arcpy.management.AddField(testFC,"FromDate","DATE")
arcpy.management.AddField(testFC,"ToDate","DATE")
# Write three polylines and their route attributes to the feature class
cursor = arcpy.da.InsertCursor(testFC,["SHAPE@","RouteID","RouteName","FromMeasure","ToMeasure"])
array = arcpy.Array([arcpy.Point(0.0,0.0),
                     arcpy.Point(0.0,1.0)])
polyline = arcpy.Polyline(array,srWGS84)
cursor.insertRow([polyline,"Route1","Route 1",0.0,750.0])
array = arcpy.Array([arcpy.Point(0.0,1.0),
                     arcpy.Point(1.0,1.0)])
polyline = arcpy.Polyline(array,srWGS84)
cursor.insertRow([polyline,"Route1","Route 1",750.0,2000.0])
array = arcpy.Array([arcpy.Point(1.0,1.0),
                     arcpy.Point(1.0,0.0)])
polyline = arcpy.Polyline(array,srWGS84)
cursor.insertRow([polyline,"Route2","Route 2",0.0,999.0])
del cursor
arcpy.management.CalculateField(testFC, "FromDate", "datetime.datetime.now()", "PYTHON3", '', "TEXT", "NO_ENFORCE_DOMAINS")
print('Writing statistics from polyline feature class ({0}) into table ({1})'.format(testFC,testStatsTable))
arcpy.analysis.Statistics(testFC,testStatsTable,"FromMeasure MIN;ToMeasure MAX","RouteID")

# Dissolve testFC so that there's only one polyline per route
print("Dissolving {0} primarily on RouteID to create {1}".format(testFC,testDissolvedFC))
arcpy.management.Dissolve(testFC,testDissolvedFC,
                          "RouteID;RouteName;FromDate;ToDate",
                          None, "SINGLE_PART", "UNSPLIT_LINES")
arcpy.management.JoinField(testDissolvedFC,"RouteID",testStatsTable,"RouteID","MIN_FromMeasure;MAX_ToMeasure")

# Create empty TestLRSNetwork in TestLRS dataset 
print("Creating LRS Network ({0}) in LRS dataset ({1})".format("TestLRSNetwork","TestLRS"))
arcpy.locref.CreateLRSNetwork(gdb, "TestLRS", "TestLRSNetwork",
                              "RouteID", "RouteName", "FromDate", "ToDate", "DO_NOT_DERIVE", '',
                              "DO_NOT_INCLUDE",None,None,None,"METERS")
lrsNetworkFC = r"{0}\{1}".format(lrsFD,"TestLRSNetwork")

# Append routes from testFC into TestLRSNetwork which should append them into Centerline feature class at the same time
routeCount = arcpy.management.GetCount(testDissolvedFC)[0]
print("Appending {0} Routes from {1}\n into LRS Network ({2}) in LRS dataset ({3})".format(routeCount,testDissolvedFC,"TestLRSNetwork","TestLRS"))
arcpy.locref.AppendRoutes(testDissolvedFC,lrsNetworkFC, "RouteID", "RouteName", "FromDate", "ToDate",
                          None,None,None, None, "ADD")

# Generating calibration points and calibrating routes using them
arcpy.locref.GenerateCalibrationPoints(testDissolvedFC,"RouteID","FromDate","ToDate",calibrationFC,
                                       lrsNetworkName, "DIGITIZED_DIRECTION","ATTRIBUTE_FIELDS","MIN_FromMeasure","MAX_ToMeasure")
calPointCount = arcpy.management.GetCount(calibrationFC)[0]
print("Using {0} calibration points to generate measures on routes in LRS Network".format(calPointCount))
arcpy.locref.GenerateRoutes(lrsNetworkFC,"NO_RECORD_CALIBRATION_CHANGES")

# Clean up intermediate data
print(r"Deleting intermediate data")
for itm in [testStatsTableName]:
    if arcpy.Exists(r"{0}\{1}".format(gdb,itm)):
        print(r"Deleting {0}\{1}".format(gdb,itm))
        arcpy.management.Delete(r"{0}\{1}".format(gdb,itm))
for itm in [testFC,testDissolvedFC]:
    if arcpy.Exists(itm):
        print(r"Deleting {0}".format(itm))
        arcpy.management.Delete(r"{0}".format(itm))

Start Time: Tuesday, 5 July 2022 9:45:33 AM
Creating LRS dataset named TestLRS in C:\temp\test.gdb
Creating "route-ready" polyline feature class (C:\temp\test.gdb\TestLRS\testFC) in LRS dataset (C:\temp\test.gdb\TestLRS)
Writing statistics from polyline feature class (C:\temp\test.gdb\TestLRS\testFC) into table (C:\temp\test.gdb\testStats)
Dissolving C:\temp\test.gdb\TestLRS\testFC primarily on RouteID to create C:\temp\test.gdb\TestLRS\testFC_Dissolve
Creating LRS Network (TestLRSNetwork) in LRS dataset (TestLRS)
Appending 2 Routes from C:\temp\test.gdb\TestLRS\testFC_Dissolve
 into LRS Network (TestLRSNetwork) in LRS dataset (TestLRS)
Using 4 calibration points to generate measures on routes in LRS Network
Deleting intermediate data
Deleting C:\temp\test.gdb\testStats
Deleting C:\temp\test.gdb\TestLRS\testFC
Deleting C:\temp\test.gdb\TestLRS\testFC_Dissolve
Succeeded at Tuesday, 5 July 2022 9:47:08 AM (Elapsed Time: 1 minutes 34 seconds)