I am writing a python script for ArcGIS 10.3. I know about Scale tool
in ArcGIS interface but I can't find such arcpy command. It exists?
As you can see on the picture the Scale tool
works different than Buffer tool
- it changes the form of original polygon. So the question is:
Can I use Scale tool
(available from ArcGIS interface) using arcpy?
Answer
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:
Also tested with multi-ring polygons (holes)!
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.'
No comments:
Post a Comment