Skip to main content
added 2431 characters in body
Source Link
FelixIP
  • 23.3k
  • 3
  • 31
  • 62

I think the most robust way is deriving medial axis of line buffer:

enter image description here

Vector solution is hard, perhaps consider raster based solution explained here.

Workflow (tools) for raster solution:

arcpy.Buffer_analysis(in_features="ORIGINAL", out_feature_class="in_memory/BUFFER", buffer_distance_or_field="20 Meters", line_side="FULL", line_end_type="FLAT", dissolve_option="NONE", dissolve_field="", method="PLANAR")
arcpy.PolygonToLine_management(in_features="buffer", out_feature_class="in_memory/BORDER", neighbor_option="IDENTIFY_NEIGHBORS")
arcpy.Merge_management(inputs="BORDER;ORIGINAL", output="in_memory/MERGED", field_mappings='LEFT_FID "LEFT_FID" true true false 0 Long 0 0 ,First,#,BORDER,LEFT_FID,-1,-1')
arcpy.Dissolve_management(in_features="MERGED", out_feature_class="in_memory/THREE_LINES", dissolve_field="", statistics_fields="", multi_part="SINGLE_PART", unsplit_lines="DISSOLVE_LINES")
arcpy.SelectLayerByLocation_management(in_layer="THREE_LINES", overlap_type="SHARE_A_LINE_SEGMENT_WITH", select_features="ORIGINAL", search_distance="", selection_type="NEW_SELECTION", invert_spatial_relationship="INVERT")
arcpy.PolygonToRaster_conversion(in_features="buffer", value_field="OBJECTID", out_rasterdataset="in_memory/cost_3", cell_assignment="CELL_CENTER", priority_field="NONE", cellsize="F:\SCRATCH\SCRATCH.gdb\MASK")
arcpy.gp.CostAllocation_sa("THREE_LINES", "cost_3", "F:/SCRATCH/SCRATCH.gdb/ALLOCATION", "", "", "OID", "", "", "", "", "", "", "")

Output of above:

enter image description here

As one can see result is highly dependent on a quality of flat end buffer I used at the beginning - see artefact at eastern end. Perhaps smooth original first. Note it can be done with round buffer, but it is more tricky.

Convert allocation raster to polygons and delete lines on the sides:

RasterToPolygon_conversion(in_raster="ALLOCATION", out_polygon_features="in_memory/POLYGONS", simplify="NO_SIMPLIFY", raster_field="Value", create_multipart_features="SINGLE_OUTER_PART", max_vertices_per_feature="")
PolygonToLine_management(in_features="POLYGONS", out_feature_class="in_memory/LINES", neighbor_option="IDENTIFY_NEIGHBORS")
SelectLayerByAttribute_management(in_layer_or_view="LINES", selection_type="NEW_SELECTION", where_clause='"LEFT_FID" =-1')
DeleteFeatures_management(in_features="LINES")

Output shows original smoothed result line.

enter image description here

I think the most robust way is deriving medial axis of line buffer:

enter image description here

Vector solution is hard, perhaps consider raster based solution explained here.

I think the most robust way is deriving medial axis of line buffer:

enter image description here

Vector solution is hard, perhaps consider raster based solution explained here.

Workflow (tools) for raster solution:

arcpy.Buffer_analysis(in_features="ORIGINAL", out_feature_class="in_memory/BUFFER", buffer_distance_or_field="20 Meters", line_side="FULL", line_end_type="FLAT", dissolve_option="NONE", dissolve_field="", method="PLANAR")
arcpy.PolygonToLine_management(in_features="buffer", out_feature_class="in_memory/BORDER", neighbor_option="IDENTIFY_NEIGHBORS")
arcpy.Merge_management(inputs="BORDER;ORIGINAL", output="in_memory/MERGED", field_mappings='LEFT_FID "LEFT_FID" true true false 0 Long 0 0 ,First,#,BORDER,LEFT_FID,-1,-1')
arcpy.Dissolve_management(in_features="MERGED", out_feature_class="in_memory/THREE_LINES", dissolve_field="", statistics_fields="", multi_part="SINGLE_PART", unsplit_lines="DISSOLVE_LINES")
arcpy.SelectLayerByLocation_management(in_layer="THREE_LINES", overlap_type="SHARE_A_LINE_SEGMENT_WITH", select_features="ORIGINAL", search_distance="", selection_type="NEW_SELECTION", invert_spatial_relationship="INVERT")
arcpy.PolygonToRaster_conversion(in_features="buffer", value_field="OBJECTID", out_rasterdataset="in_memory/cost_3", cell_assignment="CELL_CENTER", priority_field="NONE", cellsize="F:\SCRATCH\SCRATCH.gdb\MASK")
arcpy.gp.CostAllocation_sa("THREE_LINES", "cost_3", "F:/SCRATCH/SCRATCH.gdb/ALLOCATION", "", "", "OID", "", "", "", "", "", "", "")

Output of above:

enter image description here

As one can see result is highly dependent on a quality of flat end buffer I used at the beginning - see artefact at eastern end. Perhaps smooth original first. Note it can be done with round buffer, but it is more tricky.

Convert allocation raster to polygons and delete lines on the sides:

RasterToPolygon_conversion(in_raster="ALLOCATION", out_polygon_features="in_memory/POLYGONS", simplify="NO_SIMPLIFY", raster_field="Value", create_multipart_features="SINGLE_OUTER_PART", max_vertices_per_feature="")
PolygonToLine_management(in_features="POLYGONS", out_feature_class="in_memory/LINES", neighbor_option="IDENTIFY_NEIGHBORS")
SelectLayerByAttribute_management(in_layer_or_view="LINES", selection_type="NEW_SELECTION", where_clause='"LEFT_FID" =-1')
DeleteFeatures_management(in_features="LINES")

Output shows original smoothed result line.

enter image description here

Source Link
FelixIP
  • 23.3k
  • 3
  • 31
  • 62

I think the most robust way is deriving medial axis of line buffer:

enter image description here

Vector solution is hard, perhaps consider raster based solution explained here.