I have a project where I am modifying over 1 million polygons (representing tracts of land) to make them line up with the PLSS land grid. My process works (mostly) by cutting up polygons based on a grid of the landgrid, determining whether to toss the split part or apply the grid polygon, the reassembles the shape to be inserted into the final dataset. Unfortunately this process over-modifies many irregular polygons, which I can identify by determining the result's percentage change in acreage, perimeter, and movement of the centroid.

In these instances (of over-modification) I would like to attempt to simply snap the original input polygon to the landgrid, so that at least the irregular polygons line up with their modified neighbors. Due to the nature of the process, I would have to apply this snap to the geometry object itself, not the entire dataset. The result of the snap will also be checked to determine whether the modification is too extreme.

My question: Can arcpy.Snap_edit be applied to a geometry object? Is there an alternative tool/process that could snap an input polygon to a line dataset?

I have tried using snap on the polygon shape object, with 0 results. I have also tried converting the vertices to point geometries (in the hopes that I could snap the points to the grid, then rebuild the polygon based on the points) but the resulting coordinates are the same.

Here's my attempt at getting this to work.

with arcpy.da.UpdateCursor(Polygons, [u'SHAPE@']) as cursor:
for row in cursor:
    if row[0].getArea('GEODESIC', 'ACRES') > 35.0:
        count +=1
        points = json.loads(row[0].JSON)["rings"][0]
        #print json.loads(row[0].JSON)["rings"][0]
        newPoints = arcpy.Array()
        for pt in points:
            print pt
            thePoint = arcpy.PointGeometry(arcpy.Point(pt[0], pt[1]), arcpy.SpatialReference(5070))
            print thePoint.JSON
            arcpy.Snap_edit(thePoint, [[grid, "VERTEX", "100 METERS"], [grid, 'EDGE', '100 METERS']])
            snappedXY = [json.loads(thePoint.JSON)["x"], json.loads(thePoint.JSON)["y"]]
            print snappedXY
            newPoints.append(arcpy.Point(snappedXY[0], snappedXY[1]))
        shape = row[0]
        NewShape = arcpy.Polygon(newPoints)
        #print NewShape[0].WKT == shape.WKT
        snap_env = [[grid, "VERTEX", "60 METERS"], [grid, 'EDGE', '50 METERS']]
        geom = arcpy.CopyFeatures_management(arcpy.Snap_edit(NewShape, snap_env), arcpy.Geometry())
        row[0] = NewShape
del cursor

UPDATE: Here's the working function:

def ShapeSnap(shape, grid):
    #Snaps input shape to grid, removes extra boundary lines
    if shape.getArea('GEODESIC', 'ACRES') > 29.0:

        points = json.loads(shape.JSON)["rings"][0]
        #print json.loads(row[0].JSON)["rings"][0]
        newPoints = arcpy.Array()
        for pt in points:
            pointFeature = "in_memory" + "//" + "point"
            if arcpy.Exists(pointFeature): arcpy.Delete_management(pointFeature)
            thePoint = arcpy.PointGeometry(arcpy.Point(pt[0], pt[1]), arcpy.SpatialReference(5070))
            arcpy.CopyFeatures_management(thePoint, pointFeature)
            arcpy.Snap_edit(pointFeature, [[grid, "VERTEX", "20 METERS"], [grid, 'EDGE', '20 METERS']])
            snappedXY = [json.loads(thePoint.JSON)["x"], json.loads(thePoint.JSON)["y"]]
            newPoints.append(arcpy.Point(snappedXY[0], snappedXY[1]))
        shapeobj = shape
        NewShape = arcpy.Polygon(newPoints)
        #print NewShape[0].WKT == shape.WKT
        newPolyFeature = 'in_memory' + '//' + 'newPolygon'
        arcpy.CopyFeatures_management(NewShape, newPolyFeature)
        snap_env = [[grid, "VERTEX", "40 METERS"], [grid, 'EDGE', '40 METERS']]
        arcpy.Snap_edit(newPolyFeature, snap_env)
        geom = arcpy.CopyFeatures_management(newPolyFeature, arcpy.Geometry())
        return geom[0]

        return shape
  • Snap tool honours selection, thus you can select row by row and modify them if necessary without update cursor. Even better use layer definition query to select one
    – FelixIP
    Mar 1, 2016 at 0:55
  • Just a thought, but as you're iterating over a geometry object you could create a temporary feature class in memory, add the geometry object, run the snap tool, then re-implement it in to the working feature class.
    – nwduncan
    Mar 1, 2016 at 0:56
  • @nwduncan We must have come up with the same idea at exactly the same time; looking through other parts of my script I realized that's actually how most of the process is working. I'll try it out tomorrow and let you know if it works
    – crld
    Mar 1, 2016 at 0:59
  • @FelixIP I'd like to be able to compare the before/after acreage, perimeter, centroid movement, etc to identify over-modifications; my goal is to not have any features make it into the result that make me say "whoops"
    – crld
    Mar 1, 2016 at 1:01
  • 1
    @nwduncan your idea was the solution; I created a temporary feature class in memory for the extracted point geometry and was able to snap that fc and get back the point location to rebuild the polygon. If you post an answer I'll mark it as the answer
    – crld
    Mar 9, 2016 at 17:21

1 Answer 1


As you're iterating over the geometry object you can create a temporary feature class in memory, add the geometry object, run the snap tool, then re-implement it in to the working feature class.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.