# Problems updating geometry of multipart and donut polygons with Arcpy

I am trying to update the geometry of some features (polygons) to allow stretching / shrinking in the X and Y planes, but am struggling to get this to work for multipart polygons and for those with an inner ring (donut polygons). I am struggling to find a solution online and with weak Python skills and suspect something simple is wrong in my code - possibly indentation in the final part of the program?

Two issues arise in this code- 1.) multipart polygons are only updated for their first part and therefore become single part, and 2.) the inner ring is lost in the donut polygon.

Attaching a before processing and after image to show the issue, shapefile and code. Looking at the after image (cyan polygons), my blue (multipart) polygons are not replicated properly, and my donut polygon (red) becomes a single area with no inner gap.

Is this just indentation, or do I need more looping to deal with the multipart & inner ring logic correctly?

Code:

import arcpy

def stretch_features(in_features, x_stretch=None, y_stretch=None):

with arcpy.da.UpdateCursor(in_features, ['OID@', 'SHAPE@XY', 'SHAPE@']) as cursor:
for row in cursor:

Xc = row[1][0]
Yc = row[1][1]

print("Feature {}, at {}, {}".format(row[0] ,Xc, Yc))

geometry = row[2]

partnum = 0

for part in geometry:

print("Part {}:".format(partnum))
pts = geometry.getPart(partnum)

pt_array = arcpy.Array()

for pnt in pts:
if pnt:
#print("old {}, {}, new {}, {}".format(pnt.X, pnt.Y, Xc-((Xc-pnt.X) * x_stretch or 1), Yc-((Yc-pnt.Y) * y_stretch or 1)))
pnt.X = Xc-((Xc-pnt.X) * x_stretch or 1)
pnt.Y = Yc-((Yc-pnt.Y) * y_stretch or 1)
else:
print("interior ring")
print("old inner {}".format(pnt))

partnum += 1

new_polygon_geometry = arcpy.Polygon(pt_array)

row[2] = new_polygon_geometry

cursor.updateRow(row)
return

in_features = r"D:\ReShapeFeatures\TestPolygons.shp"

stretch_features(in_features, x_stretch=.75, y_stretch=.75)


I figured this out now - it was my own weaknesses with Python. In case it is of any use, here is the working code. Main changes being the addition of an array for the parts and moving the declaration of it and the point array outside the loop through the parts.

import arcpy

def stretch_features(in_features, x_stretch=None, y_stretch=None):

with arcpy.da.UpdateCursor(in_features, ['OID@', 'SHAPE@XY', 'SHAPE@']) as cursor:
for row in cursor:

Xc = row[1][0]
Yc = row[1][1]

print("Feature {}, at {}, {}".format(row[0] ,Xc, Yc))

geometry = row[2]

pnt_array = arcpy.Array()
part_array = arcpy.Array()

partnum = 0

for part in geometry:

print("Part {}:".format(partnum))
pts = geometry.getPart(partnum)

for pnt in pts:
if pnt:
#print("old {}, {}, new {}, {}".format(pnt.X, pnt.Y, Xc-((Xc-pnt.X) * x_stretch or 1), Yc-((Yc-pnt.Y) * y_stretch or 1)))
pnt.X = Xc-((Xc-pnt.X) * x_stretch or 1)
pnt.Y = Yc-((Yc-pnt.Y) * y_stretch or 1)
else:
print("interior ring")
print("old inner {}".format(pnt))

pnt_array.removeAll()
partnum += 1

new_polygon_geometry = arcpy.Polygon(part_array)
part_array.removeAll()

row[2] = new_polygon_geometry

cursor.updateRow(row)

return

in_features = r"D:\ReShapeFeatures\TestPolygons 6.shp"

stretch_features(in_features, x_stretch=.75, y_stretch=.75)


Resulting output now looks like this...