ArcPy Optimization – Techniques for Optimizing ArcPy Code to Cut Polygon

arcpypolygonsplitting

There is a lot of nested loops and wondering of ways I could speed up this code? Any ideas?

Note: This requires ArcMap 10.2

def cut_geometry(to_cut, cutter):
    """
    Cut a feature by a line, splitting it into two geometries.
    :param to_cut: The feature to cut.
    :param cutter: The polyline to cut the feature by.
    :return: The feature with the split geometry added to it.
    """
    arcpy.AddField_management(to_cut, "SOURCE_OID", "LONG")
    geometries = None
    with arcpy.da.SearchCursor(cutter, "SHAPE@") as lines:
        for line in lines:
            with arcpy.da.UpdateCursor(to_cut, ["SHAPE@", "OID@"]) as polygons:
                for polygon in polygons:
                    if line[0].disjoint(polygon[0]) == False:
                        geometries = polygon[0].cut(line[0])
                        polygons.deleteRow()
                with arcpy.da.InsertCursor(to_cut, ["SHAPE@", "SOURCE_OID"]) as insert_cursor:
                    for geometry in geometries:
                        if geometry.area > 0:
                            insert_cursor.insertRow([geometry, polygon[1]])

UPDATE as per @MichaelMiles-Stimson

I was able to move out the insert_cursor, by adding in code for an edit session. However can't figure out how to pull out the UpdateCursor without losing the functionality, since it's deleting and inserting rows back into the original feature it needs to get a new UpdateCursor each time.

def cut_geometry(to_cut, cutter):
    """
    Cut a feature by a line, splitting it into its separate geometries.
    :param to_cut: The feature to cut.
    :param cutter: The polylines to cut the feature by.
    :return: The feature with the split geometry added to it.
    """
    arcpy.AddField_management(to_cut, "SOURCE_OID", "LONG")
    geometries = None
    polygon = None

    edit = arcpy.da.Editor(os.path.dirname(to_cut))
    edit.startEditing(False, False)

    insert_cursor = arcpy.da.InsertCursor(to_cut, ["SHAPE@", "SOURCE_OID"])

    with arcpy.da.SearchCursor(cutter, "SHAPE@") as lines:
        for line in lines:
            with arcpy.da.UpdateCursor(to_cut, ["SHAPE@", "OID@"]) as polygons:
                for polygon in polygons:
                    if line[0].disjoint(polygon[0]) == False:
                        geometries = polygon[0].cut(line[0])
                        polygons.deleteRow()
                for geometry in geometries:
                    if geometry.area > 0:
                        insert_cursor.insertRow([geometry, polygon[1]])

    edit.stopEditing(True)

Best Answer

[UPDATED TO HANDLE INTERSECTING LINES]

Can also be download as a toolbox here: https://github.com/tforward/CutPolygonByLines

Split Polygon on Lines

import os

def cut_geometry(to_cut, cutter):
    """
    Cut a feature by a line, splitting it into its separate geometries.
    :param to_cut: The feature to cut.
    :param cutter: The polylines to cut the feature by.
    :return: The feature with the split geometry added to it.
    """
    arcpy.AddField_management(to_cut, "SOURCE_OID", "LONG")
    geometries = []
    polygon = None

    edit = arcpy.da.Editor(os.path.dirname(to_cut))
    edit.startEditing(False, False)

    insert_cursor = arcpy.da.InsertCursor(to_cut, ["SHAPE@", "SOURCE_OID"])

    with arcpy.da.SearchCursor(cutter, "SHAPE@") as lines:
        for line in lines:
            with arcpy.da.UpdateCursor(to_cut, ["SHAPE@", "OID@", "SOURCE_OID"]) as polygons:
                for polygon in polygons:
                    if line[0].disjoint(polygon[0]) == False:
                        if polygon[2] == None:
                            id = polygon[1]
                        # Remove previous geom if additional cuts are needed for intersecting lines
                        if len(geometries) > 1:
                            del geometries[0] 
                        geometries.append([polygon[0].cut(line[0]), id])
                        polygons.deleteRow()
                for geometryList in geometries:
                    for geometry in geometryList[0]:
                        if geometry.area > 0:
                            insert_cursor.insertRow([geometry, geometryList[1]])

    edit.stopEditing(True)


cut_geometry(r"PATH_TO_POLY", r"PATH_TO_LINES")