2

Is it possible to scale each polygon by a numeric value in an attribute table field using arcpy. I have updated the code from some previous excellent work done by Evil Genius

import arcpy
import math

def scale_geom(geom, scale, reference=None):
   """Returns geom scaled to scale %"""
   if geom is None: return None
   if reference is None:
    # we'll use the centroid if no reference point is given
    reference = geom.centroid

refgeom = arcpy.PointGeometry(reference)
newparts = []
for pind in range(geom.partCount):
    part = geom.getPart(pind)
    newpart = []
    for ptind in range(part.count):
        apnt = part.getObject(ptind)
        if apnt is None:
            # polygon boundaries and holes are all returned in the same part.
            # A null point separates each ring, so just pass it on to
            # preserve the holes.
            newpart.append(apnt)
            continue
        bdist = refgeom.distanceTo(apnt)

        bpnt = arcpy.Point(reference.X + bdist, reference.Y)
        adist = refgeom.distanceTo(bpnt)
        cdist = arcpy.PointGeometry(apnt).distanceTo(bpnt)

        # Law of Cosines, angle of C given lengths of a, b and c
        angle = math.acos((adist**2 + bdist**2 - cdist**2) / (2 * adist * bdist))

        scaledist = bdist * scale

        # If the point is below the reference point then our angle
        # is actually negative
        if apnt.Y < reference.Y: angle = angle * -1

        # Create a new point that is scaledist from the origin
        # along the x axis. Rotate that point the same amount
        # as the original then translate it to the reference point
        scalex = scaledist * math.cos(angle) + reference.X
        scaley = scaledist * math.sin(angle) + reference.Y

        newpart.append(arcpy.Point(scalex, scaley))
    newparts.append(newpart)

return arcpy.Geometry(geom.type, arcpy.Array(newparts), geom.spatialReference)

incur = arcpy.da.SearchCursor(r'D:\ZOC\POLYPGDIS_MASTER.shp', ['OID@','SHAPE@'])
outcur = arcpy.da.InsertCursor(r'D:\ZOC\POLYPGDIS_MASTER_1.shp', ['SHAPE@'])

for row in incur:
    # Scale each feature by 0.5 and insert into dest_fc
    outcur.insertRow([scale_geom(row[1], arcpy.da.SearchCursor(r'D:\ZOC\POLYPGDIS_MASTER.shp', ['Scale_Fact']))])
del incur
del outcur
  • What do you mean by "scale"? Can you provide a more specific example of what you're trying to do? – Andy Bradford Mar 15 '16 at 16:06
  • Of course it's possible, but not without code. In addition to scale, you'll need to have some way to choose the origin (basis of scaling), and then extract, alter, and either update or insert the resulting geometry. – Vince Mar 15 '16 at 16:09
  • I have numerous polygons in one shapefile that I need to scale up or down. Each row in the attribute table contains the numeric value by how much to scale the polygon. Hope this makes sense? – user1655130 Mar 15 '16 at 16:12
  • I seen this, which nearly does it for me: gis.stackexchange.com/questions/169694/… – user1655130 Mar 15 '16 at 16:14
  • 1
    So take the source from the other script, try modifying it to read both geometry and scale, and if it fails to work as intended, post the entire content here, with a link to the original in the body, then ask your question about the code you've modified, with details about the problem. Coding questions here in GIS SE are expected to have code. – Vince Mar 15 '16 at 16:25
2

Going back to the referenced code that you say in the comments nearly does it for you, I think all you need to do is add your scale column to the input cursor.

incur = arcpy.da.SearchCursor('some_folder/a_fgdb.gdb/orig_fc', ['OID@','SHAPE@', 'Scale'])
outcur = arcpy.da.InsertCursor('some_folder/a_fgdb.gdb/dest_fc', ['SHAPE@'])

for row in incur:
    # Scale each feature by 0.5 and insert into dest_fc
    outcur.insertRow([scale_geom(row[1], row[2])])
del incur
del outcur
  • Thank you so much for this. I was getting completely bogged down. I cannot fully understand how arcpy.da.SearchCursor works with insertRow. But this is great. Thanks again – user1655130 Mar 16 '16 at 8:54
  • Think of the insert cursor as nesting inside the search cursor. As you iterate through each row of the search cursor, you insert a row into the output table based on the values from the search cursor row. – RHB Mar 16 '16 at 14:35
  • This is great, is it possible for the code to insert the new rows and populate the news rows with the old values from the attribute table. Currently, it inserts the new rows, but all values are 0. Thanks again – user1655130 Mar 23 '16 at 15:49
  • Yes, just add the columns you want to include the same way I added the Scale column, then add the corresponding row[x] to your insertRow statement. X = the column position of the column in the search cursor. As in my example, the Scale column is row[2]. – RHB Mar 23 '16 at 16:34
  • Ok, so I do this: incur = arcpy.da.SearchCursor(r'D:\ZOC\POLYPGDIS_MASTER.shp', ['OID@','SHAPE@','Scale_Fact','LOCX']) outcur = arcpy.da.InsertCursor(r'D:\ZOC\POLYPGDIS_MASTER_1.shp', ['SHAPE@']) for row in incur: # Scale each feature by 0.5 and insert into dest_fc outcur.insertRow([scale_geom(row[1], row[2]), row[3]]) and I get the error: sequence size must match size of the row – user1655130 Mar 23 '16 at 16:42

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.