Hello,
I want to create multiple ring buffer starting with 0.5 m, 1 m, 1.5 m, 2 m,..... up to 500 m around point object. I try to do it by Arcpy - 'MultipleRingBuffer_analysis', unfortunately, it takes very long time and end up with displaying an error.
(But I try it 10 m buffer interval 10 m, 20 m, 30 m, .....500 m, it nicely works)
Does anyone have experience of creating a large number of buffers around single point object....?
Since I'm working with Python (Arcpy), It could be the great help for me to have suggestions in python platform.
Thank you very much for kind attention.
I can't say I understand your approach, but I can say it is technically possible to get what you are after. Although ArcPy's Geometry classes don't do a good job of supporting arcs and curves, one can work with arcs and curves indirectly. For situations such as this, you definitely want to be working with arcs and curves and not approximated arcs and curves.
Below is some code that builds an Esri JSON-compliant Python dictionary containing either circle or ring buffers:
def concentricBuffers(point_geometry, distance, interval, rings=False):
x = point_geometry.firstPoint.X
y = point_geometry.firstPoint.Y
WKID = point_geometry.spatialReference.PCSCode
esri_json = {
"displayFieldName" : "",
"geometryType" : "esriGeometryPolygon",
"spatialReference" : {
"wkid" : WKID
},
"fields" : [
{
"name" : "OUTER_DIST",
"type" : "esriFieldTypeDouble"
},{
"name" : "INNER_DIST",
"type" : "esriFieldTypeDouble"
}
],
"features" : [
]
}
steps = range(int(distance/interval))
prev_step = 0
for step in steps:
step = (step + 1) * interval
esri_feature = {
"attributes" : {
"OUTER_DIST" : step,
"INNER_DIST" : 0
},
"geometry" : {
"curveRings": [
[
[x, y+step],
{"a": [[x, y+step], [x, y], 0, 1]}
]
]
}
}
if rings:
esri_feature["attributes"]["INNER_DIST"] = prev_step
esri_feature["geometry"]["curveRings"].append(
[
[x, y+prev_step],
{"a": [[x, y+prev_step], [x, y], 0, 0]}
]
)
esri_json["features"].append(esri_feature)
prev_step = step
esri_json["features"].reverse()
return esri_json
The code takes an ArcPy PointGeometry, a maximum distance to buffer out, an interval for buffering, and a Boolean indicating circles or rings. The default is Circles, so make sure to set True for rings. The Geometry objects section of the ArcGIS REST API explains why I structured the Python dictionary the way I did.
NOTE: This is designed for projected data, not geographic coordinate system data. Adding geographic support can be done, but it requires additional code.
The code returns a Python dictionary, which can be passed to ArcPy's AsShape to return a RecordSet that can be exported to a feature class using Copy Features.
>>> pt = arcpy.FromWKT('POINT(10 10)',arcpy.SpatialReference(3857))
>>> arcpy.CopyFeatures_management(pt,'in_memory/pt')
<Result 'in_memory\\pt'>
>>> rings = concentricBuffers(pt, 10, 3, True)
>>> arcpy.CopyFeatures_management(arcpy.AsShape(rings, True), "in_memory/rings")
<Result 'in_memory\\rings'>
The code can generate thousands of rings in a second or less, and it takes a second or two to dump a 1,000 ring record set to disk.
>>> top = _arc(radius=10, start=0, stop=1, step=0.2, xc=0.0, yc=0.0)
>>> top.reverse()
>>> bott = _arc(radius=9.5, start=0, stop=1, step=0.2, xc=0.0, yc=0.0)
>>> top = np.array(top)
>>> bott = np.array(bott)
>>> close = top[0]
>>> arc = np.asarray([i for i in [*top, *bott, close]])
>>> pnts = arc.tolist()
>>> pnts
[[9.99902524, 0.1396218], [9.99945169, 0.10471784], [9.99975631, 0.0698126],
[9.99993908, 0.03490651], [10.0, 0.0], [9.5, 0.0], [9.49994212, 0.03316119],
[9.49976849, 0.06632197], [9.49947911, 0.09948195], [9.49907398, 0.13264071],
[9.99902524, 0.1396218]]
If someone wants to check that this forms a valid polygon (on the iThing, so I can't check)
I have some code that performs arc calculations.
If it does... or needs fixing,
It is designed initially to create the cirular arc from a circle radius, a start and stop angle, then a densification step, centered about an origin (xc, yc). In this example, I just calculated the top and bottom segments. tried to make sure that the arc formed a closed circular arc.
The code is
def _arc(radius=100, start=0, stop=1, step=0.1, xc=0.0, yc=0.0):
"""
:Requires:
:---------
: radius = cirle radius from which the arc is obtained
: start, stop, incr = angles in degrees
: xc, yc - center coordinates in projected units
:
:Returns:
:--------
: points on the arc
"""
start, stop = sorted([start, stop])
angle = np.deg2rad(np.arange(start, stop, step))
Xs = radius*np.cos(angle) # X values
Ys = radius*np.sin(angle) # Y values
pnts = np.array(list(zip(Xs, Ys)))
pnts = np.round(pnts + [xc, yc], 8)
p_lst = pnts.tolist()
return p_lst
You can then generate each sector singly to do the sampling .... I would NOT recommend making a sampling framework in this manner...
here is what the sector are of 1/2 degree with a 50 cm separation looks like between 9.5 and 10 meters out from a point. notice, that the circular arc points are not even noticeable, but they are there. You would be better off simplifying the whole analysis using a fishnet or using the code as a sampling tool
here is what 5 degrees looks like
Well it can be done, by using the arc code and cycling through inner and outer radii.
If that is what you want... the example is for 5 degree sector widths and each sectors points are densified.
I cut out the buffer from 0 to 5 m since the points would be too dense.
Here is 1/4 of a circle with 1 meter buffer/sector widths by 1 degree
As you can see, the sectors are quite thin and I suspect sampling your raster will have several sectors recording the same values
Perhaps you can re-examine the sizes you want in both the x and y direction since you will notice that the sample space changes with the angle, preferring a different axis as the sectors get rotated.
of course if you generate your own multiring buffer code, you can vary the density of the points used to create the rings, effective, moving from a dense ngon (360+ points) down to triangles.
Or add in a rotation and scaling factor to the circle and generate ellipse rings.
Dan, can you post the code you used for these? Cool!
I'll throw it in a blog and github it if that is ok... just trying to get some stuff ready for classes before next week... so maybe tonight...
Dan, you're a maniac. My classes start next week too and have no idea how you do it all!
Sleep is inconvenient and repetitive ... GitHub link plus the images will appear on my blog ... tomorrow 10:00 am Ottawa, Canada... Take a look at some of the other geometry stuff... like the Julia set demo files... It's how I am introducing programming... cool before the cursors...
Curtis... here is the link /blogs/dan_patterson/2017/01/04/circles-sectors-rings-buffers-and-the-n-gons