18

I am writing a python script for ArcMap 10.3. I know about the Scale tool in the ArcMap interface but I cannot find an equivalent ArcPy command.

As you can see on the picture the Scale tool works different than Buffer tool - it changes the form of original polygon.

Can I use the Scale tool (available from ArcMap interface) in ArcPy?

enter image description here

0

1 Answer 1

32
+200

I'm not aware of anything in the arcpy API that will do the scaling for you, but writing a function to do so would be relatively simple.

The code below does the scaling for 2D features, and doesn't take into account M or Z values:

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)

You can call it with a geometry object, a scale factor (1 = same size, 0.5 = half size, 5 = 5 times as large, etc.), and an optional reference point:

scale_geom(some_geom, 1.5)

Use this in conjunction with cursors to scale an entire feature class, assuming the destination feature class already exists:

incur = arcpy.da.SearchCursor('some_folder/a_fgdb.gdb/orig_fc', ['OID@','SHAPE@'])
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], 0.5)])
del incur
del outcur

edit: here's an example using an approximation of your test geometry, for 0.5 and 5 times: enter image description here

Also tested with multi-ring polygons (holes)! enter image description here

An explanation, as requested:

scale_geom takes a single polygon and loops through each vertex, measuring the distance from it to a reference point (by default, the centroid of the polygon).
That distance is then scaled by the scale given to create the new 'scaled' vertex.

The scaling is done by essentially drawing a line at the scaled length from the reference point through the original vertex, with the end of the line becoming the scaled vertex.
The angle and rotation stuff is there because it's more straight forward to calculate the position of the end of the line along a single axis and then rotate it 'into place.'

0

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.