getPart() method returns incorrect geometry from buffer in ArcGIS
This is not an answer but some extra info for this question. The sinister behaviour is not occurring at arcpy.Polygon
as suggested by @FelixIP, it is occuring at the getPart() bit of code. I tweaked your code and ran it on a dataset with just a triangle. I had set the coordinate system to be British National Grid when I had created it.
import arcpy
arcpy.env.addOutputsToMap = True
infc = "tri"
outBuffer=r'c:\scratch\OUT_BUFFER.shp'
outPart=r'c:\scratch\OUT_PART.shp'
d=arcpy.Describe(infc)
SR=d.spatialReference
with arcpy.da.SearchCursor(infc, ("SHAPE@","LABEL")) as rows:
for shp,label in rows:
buf=shp.buffer(5)
arcpy.CopyFeatures_management(buf, outBuffer)
n=buf.partCount
for i in xrange (n):
prt=buf.getPart(i)
# Print out sequence of XY points
print(prt)
for p in prt:
print str(p.X ) + "," + str(p.Y)
pgon=arcpy.Polygon(prt,SR)
arcpy.CopyFeatures_management(pgon, outPart)
break
Zooming into one corner of the buffer of the triangle in edit mode we can see many vertices:
Infact there are 42 vertices for the whole geometry. My adjusted code reading the output of the getPart() returns only 11.
So the bug is occuring when the getPart() is called to return the Array of Points.
Instead of using getPart()
, you can use WKT
on the buffered polygon itself. It's not the exact shape of the buffer (due to approximating the 3 true curves on the triangle with 15 vertices each), but it's quite close.
From the help:
Any true curves in the geometry will be densified into approximate curves in the WKT string.
import json
from pandas import DataFrame
import arcpy
header = ("type", "area", "vertices")
sr = arcpy.SpatialReference(3857) #WMAS
coords = [(-10136090, 3460507),
(-10135313, 3461773),
(-10134909, 3460488),
(-10136090, 3460507)]
poly = arcpy.Polygon(arcpy.Array(arcpy.Point(x,y) for x,y in coords), sr)
buffer = poly.buffer(5)
part = arcpy.Polygon(buffer.getPart(0), sr)
wkt = arcpy.FromWKT(buffer.WKT, sr)
wkb = arcpy.FromWKB(buffer.WKB)
densify = arcpy.Polygon(buffer.densify("DISTANCE", 1, .00001).getPart(0), sr)
esriJSON = arcpy.AsShape(json.loads(buffer.JSON), True)
print(DataFrame([("buffer", buffer.area, buffer.pointCount)], columns=header))
df = DataFrame([("getPart", part.area, part.pointCount),
("WKT", wkt.area, wkt.pointCount),
("WKB", wkb.area, wkb.pointCount),
("densify", densify.area, densify.pointCount),
("JSON", esriJSON.area, esriJSON.pointCount)],
columns=header)
df["delta"] = [v - buffer.area for v in df["area"]]
print(df.sort(columns='delta',ascending=False))
And here's the output:
type area vertices
0 buffer 775085.643363 9
type area vertices delta
4 JSON 775085.643363 9 1.641456e-08
3 densify 775085.633439 4235 -9.923947e-03
1 WKT 775085.297882 43 -3.454809e-01
0 getPart 775041.921399 9 -4.372196e+01
2 WKB 775041.921399 9 -4.372196e+01
Based on comment below from @faith_dur, the way to go is esri JSON!