I am trying to update Z values of polygon shape with ArcPy. This script is working without error but increasing the first (0 position vertex) vertex twice. I want to update only once. How can I avoid it?
import arcpy
feature = r"D:\acrpy\VV_test\scripts\map1\ZM_KAD_00.shp" #polygon shape
fields = ["ESRI_OID", "SHAPE@Z"]
whereclause = """{0} = 7""".format(arcpy.AddFieldDelimiters(feature, fields[0]))
z_increase = 2
with arcpy.da.UpdateCursor(feature, fields, whereclause, explode_to_points=True) as cursor:
for row in cursor:
print row[1]
cursor.updateRow([row[0],row[1] + z_increase])
Answer
I wanted to insert a new answer rather than editing my previous one as this comes with a new solution that should handle the problematic of updating the geometries of polygons with more than one inner ring as well.
The OP in the comments pointed out that my other answer didn't work for the case "two donuts in one polygon".
Trying myself I was susprised but today I realized this problem has already come up previously in this other question where a solution is also provided.
I'll highlight the key part that makes the code you are about to see working with all types of polygons (single-to-multipart, zero-to-many inner rings):
- an
arcpy.Polygon()
is made up of one or morearcpy.Array()
s - each
arcpy.Array()
is constructed with at least threearcpy.Point()
s (although they require four per definition, as pointed out by @Vince in the comments; yes, in ArcGIS a "Point" means a "Vertex", quite confusing...) - a single
arcpy.Polygon()
with more than onearcpy.Array()
inside is a multipart polygon - a single
arcpy.Polygon()
with one or more interior rings (alias "donuts"), is NOT a multipart polygon but a singlepart polygon with interior ring(s) (quoting this) a single part
arcpy.Polygon()
with one or more interior rings is composed by a singlearcpy.Array()
with aNone
value where the inner ring(s) begin(s), for example:[[x1, y1], [x2, y2], [x3, y3], [x4, y4], None, # start of the inner ring coordinatres [x5, y5], [x6, y6], [x7, y7], [x8, y8]]
Last but not least,
arcpy.cursors
list per each ring (not part, here I mean ring), a starting vertex and an end vertex which are equivalent in terms of coorindates.As per the previous assessment, one needs to sikp updating (shifting) either the first or last point otherwise the coincident point is shifted twice.
The modified working code of my previous original answer is shown below:
fields = ["OID@", "SHAPE@"]
feature = r"D:\acrpy\VV_test\scripts\map1\ZM_KAD_00.shp" #polygon shape
fields = ["ESRI_OID", "SHAPE@"]
whereclause = """{0} = 7""".format(arcpy.AddFieldDelimiters(feature, fields[0]))
z_increase = 2
desc = arcpy.Describe(feature)
sr = desc.spatialReference
with arcpy.da.UpdateCursor(feature, fields, whereclause) as cursor:
for row in cursor:
print("Feature {}:".format(row[0]))
partnum = 0
# create an array for the updated feature
arr_feat = arcpy.Array()
for part in row[1]:
# create an array for the part
arr_part = arcpy.Array()
print("Part {}:".format(partnum))
i = 0
for pnt in part:
if i == 0:
print("SKIPPING FIRST VERTEX")
arr_part.add(arcpy.Point(pnt.X, pnt.Y, pnt.Z))
i += 1
continue
if pnt:
print("OLD: {}, {}, {}".format(pnt.X, pnt.Y, pnt.Z))
new_z = pnt.Z
new_z += z_increase
i += 1
print("NEW: {}, {}, {}".format(pnt.X, pnt.Y, new_z))
arr_part.add(arcpy.Point(pnt.X, pnt.Y, new_z))
else:
print("Interior Ring:")
null_point = None
arr_part.add(null_point) # MUST DO THIS WHEN INSERTING INTERIOR RING!!!
i = 0
# add part to feature array
arr_feat.add(arr_part)
partnum += 1
polygon = arcpy.Polygon(arr_feat, sr, True)
row[1] = polygon
cursor.updateRow(row)
No comments:
Post a Comment