Since celticflute did not post his code, I had to figure it out again.
Finally got a working sample. This seems to work pretty well.
The key thing is that you do not write polygon parts and holes differently!
Instead, you construct a polygon from nested arrays which represent parts made of up rings. When you write the geometry by writing it to a shape field or use it in a tool, behind the scenes arc objects planarizes the rings within in each polygon part and determines what's a hole and what isn't. And sorts the coordinates clockwise, and burns the xys into the coordinate system and domain of the geodatabase feature class.
#
# Write a polygon feature class
#
import os
import arcpy
from arcpy import env
def makepoly(coord_list, SR=None):
"""Convert a Python list of coordinates to an ArcPy polygon feature
Author: Curtis Price, USGS, cprice@usgs.gov
Examples, from Desktop Help 10.x: Reading Geometries
Feat0 = [
[[3.0, 8.0],
[1.0, 8.0],
[2.0, 10.0],
[3.0, 8.0]]
]
Feat1 = [
[[5.0, 3.0],
[3.0, 3.0],
[3.0, 5.0],
[5.0, 3.0]],
[[7.0, 5.0],
[5.0, 5.0],
[5.0, 7.0],
[7.0, 5.0]],
]
# this feature has an interior ring (donut)
Feat2 = [
[[9.0, 11.0],
[9.0, 8.0],
[6.0, 8.0],
[6.0, 11.0],
[9.0, 11.0],
None,
[7.0, 10.0],
[7.0, 9.0],
[8.0, 9.0],
[8.0, 10.0],
[7.0, 10.0]]
]
"""
parts = arcpy.Array()
rings = arcpy.Array()
ring = arcpy.Array()
for part in coord_list:
for pnt in part:
if pnt:
ring.add(arcpy.Point(pnt[0], pnt[1]))
else:
# null point - we are at the start of a new ring
rings.add(ring)
ring.removeAll()
# we have our last ring, add it
rings.add(ring)
ring.removeAll()
# if we only have one ring: remove nesting
if len(rings) == 1:
rings = rings.getObject(0)
parts.add(rings)
rings.removeAll()
# if single-part (only one part) remove nesting
if len(parts) == 1:
parts = parts.getObject(0)
return arcpy.Polygon(parts, SR)
# test data from:
# Desktop Help 10.0: Reading Geometries
Feat0 = [
[[3.0, 8.0],
[1.0, 8.0],
[2.0, 10.0],
[3.0, 8.0]]
]
Feat1 = [
[[5.0, 3.0],
[3.0, 3.0],
[3.0, 5.0],
[5.0, 3.0]],
[[7.0, 5.0],
[5.0, 5.0],
[5.0, 7.0],
[7.0, 5.0]],
]
# this last feature has an interior ring (donut)
Feat2 = [
[[9.0, 11.0],
[9.0, 8.0],
[6.0, 8.0],
[6.0, 11.0],
[9.0, 11.0],
None,
[7.0, 10.0],
[7.0, 9.0],
[8.0, 9.0],
[8.0, 10.0],
[7.0, 10.0]]
]
# test code
# create the empty feature class
# with real data, provide a SR code, name or dataset for SR
# SR = arcpy.SpatialReference(4326)
SR = None
env.workspace = env.scratchGDB
Data = arcpy.CreateScratchName("","","featureclass",env.workspace)
print "writing: " + Data
print
arcpy.CreateFeatureclass_management(os.path.dirname(Data),
os.path.basename(Data),"Polygon",
spatial_reference=SR)
# create the polygons and write them
Rows = arcpy.da.InsertCursor(Data, "SHAPE@")
for f in [Feat0, Feat1, Feat2]:
print "coords: " + repr(f)
p = makepoly(f)
print "feature: " + repr(p)
Rows.insertRow([p])
del Rows
Best Answer
While the buffer wizard is not exposed through ArcPy, geometries do expose the buffer method so the following works to create multiple ring buffers:
For each source feature, we create a dictionary to store each ring buffer. Each of these buffers is a dictionary with a few values - the source OID, the distance, and the buffer geometry. We then create an insert cursor and create features in the output table for each ring buffer of each input feature.
Edit: I have tested this and with 3 simple features, where the gp tool takes over a minute, this script takes ~1s once arcpy has finished importing.
Edit 2: Fixed a couple of bugs - firstly, the difference call was removing the previous ring rather than all previous rings. Secondly, I wasn't adding the ring to the currentBuffer so it wasn't getting added later...
Edit 3: Handled the shape field not being 'SHAPE' in the output featureclass. Added cleanup of cursor objects.