4

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)
                        pt_array.add(pnt) 
                    else:
                        print("interior ring")
                        print("old inner {}".format(pnt))
                        pt_array.add(pnt) 
                        #pt_array.add(None) 

                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)

enter image description here

enter image description here

2

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)
                        pnt_array.add(pnt) 
                    else:
                        print("interior ring")
                        print("old inner {}".format(pnt))
                        pnt_array.add(pnt) 

                part_array.add(pnt_array)
                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... enter image description here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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