Wednesday, 7 September 2016

Updating Z values with geometry of multipart and donut polygons with ArcPy?



I am trying to update Z values of polygon features with point features. The code is (found on GIS) working good if no 'interor ring' or 'multipart' features are present in the polygon features. The polygon is large data set with several 'interor rings' or 'multiparts'. I have no idea how to solve it. I have understood that 'NoneType' AttributeError refers to 'multipart' or 'inner rings' issue.


My code is :


import os
import arcpy

arcpy.env.workspace = r"D:\acrpy\VV_test\scripts\map1"
point_fc = r"D:\acrpy\VV_test\scripts\map1\VRTX_ZM_KAD_test.shp"
polygon_fc = r"\acrpy\VV_test\scripts\map1\ZM_KAD__test.shp"
my_field = "SHAPE@"
my_field_pnt = "SHAPE@XYZ"



with arcpy.da.UpdateCursor(polygon_fc, my_field) as myUpdtCur:
for row in myUpdtCur:
geom = row[0]
arr_pol = arcpy.Array()
for part in geom:
arr_part = arcpy.Array()
pnt_count = 0
for pnt in part:

with arcpy.da.SearchCursor(point_fc, my_field_pnt) as mySrcCur:
for srcPnt in mySrcCur:
if int(pnt.X) == int(srcPnt[0][0]) and int(pnt.Y) == int(srcPnt[0][1]):
updZpnt=srcPnt[0][2]
del mySrcCur
pnt_count += 1
print pnt_count
myXYZPoint = arcpy.Point(pnt.X, pnt.Y, updZpnt)
arr_part.add(myXYZPoint)
arr_pol.add(arr_part)

polygon = arcpy.Polygon(arr_pol,None, True)
row[0] = polygon
myUpdtCur.updateRow(row)
del myUpdtCur



got the error:
76
77

78
79
80
81
82

Traceback (most recent call last):
File "D:\acrpy\VV_test\scripts_OK\GIS_stackexcahnge\test_update Z values from point vertices to polygon vertices .py", line 21, in
if int(pnt.X) == int(srcPnt[0][0]) and int(pnt.Y) == int(srcPnt[0][1]):
AttributeError: 'NoneType' object has no attribute 'X'

>>>

Answer



The Reading geometries documentation shows the proper processing procedure for sub-parts in polygons:


for row in arcpy.da.SearchCursor(infc, ["OID@", "SHAPE@"]):
# Print the current multipoint's ID
#
print("Feature {}:".format(row[0]))
partnum = 0

# Step through each part of the feature

#
for part in row[1]:
# Print the part number
#
print("Part {}:".format(partnum))

# Step through each vertex in the feature
#
for pnt in part:
if pnt:

# Print x,y coordinates of current point
#
print("{}, {}".format(pnt.X, pnt.Y))
else:
# If pnt is None, this represents an interior ring
#
print("Interior Ring:")
partnum += 1

Note the if pnt test, with the comment




If pnt is None, this represents an interior ring



Some comments:




  • Your inner loop is so inefficient, I can't copy it in good conscience. This should be a simple matrix or sparse dictionary of arrays, populated once above the top of the code.




  • It should be a crime (misdemeanor data abuse) to not use the spatial_reference parameter in the arcpy.Polygon constructor -- failure to do so will truncate your coordinates to the third decimal place.





  • The with construct deletes variables, so your del statements were no-op.




And the corrected code block:


desc = arcpy.Describe(polygon_fc)
sr = desc.spatialReference
with arcpy.da.UpdateCursor(polygon_fc, my_field) as myUpdtCur:
for row in myUpdtCur:

geom = row[0]
arr_pol = arcpy.Array()
for part in geom:
arr_part = arcpy.Array()
pnt_count = 0
for pnt in part:
if not pnt:
arr_part.add(None) # Close previous subpart
continue # <-- Skips hole markers
## assign updZpnt here

pnt_count += 1
print pnt_count
myXYZPoint = arcpy.Point(pnt.X, pnt.Y, updZpnt)
arr_part.add(myXYZPoint)
arr_pol.add(arr_part)

row[0] = arcpy.Polygon(arr_pol,sr, True)
myUpdtCur.updateRow(row)

No comments:

Post a Comment

arcpy - Changing output name when exporting data driven pages to JPG?

Is there a way to save the output JPG, changing the output file name to the page name, instead of page number? I mean changing the script fo...