Random Shapes?

489
6
07-15-2019 10:58 AM
ThomasColson
MVP Frequent Contributor

I'm well aware of the random point tool....I have many points for which I need to create an irregular, random-shaped buffer around each point. No requirements on the buffer other than it can't be a perfect geometric shape (square, circle, rectangle, etc...). More like a mutated starfish. 

Tags (1)
0 Kudos
6 Replies
JoshuaBixby
MVP Esteemed Contributor

Although I don't think this directly applies to your need, the discussion is good and might give you some thoughts on coming up with a solution:  arcgis desktop - How to create an oriented buffer using arcpy? - Geographic Information Systems Stac... 

JoshuaBixby
MVP Esteemed Contributor

This was a fun question.  Below is something I just ginned up.  It effectively makes a radar/spider plot around the point:

import arcpy
import random

def radarBufferPoint(in_point, num_vertices, distance, spread=0.3, seed=None, srid=None):
random.seed(seed)
if num_vertices > 360: num_vertices = 360
if not isinstance(in_point, arcpy.PointGeometry):
in_point = arcpy.PointGeometry(in_point, arcpy.SpatialReference(srid))

pts = [
in_point.pointFromAngleAndDistance(
angle,
random.uniform((1-spread)*distance, (1+spread)*distance)
)
for angle
in range(0, 360, 360/num_vertices)
]

pg = arcpy.Polygon(
arcpy.Array([pt.firstPoint for pt in pts]),
in_point.spatialReference
)

return pg

The preferred input is a point geometry, but if you pass a point with a spatial reference, it will make the point geometry.

ThomasColson
MVP Frequent Contributor

I might be missing the Captain Obvious here...I did:

import arcpy
import random
in_point = arcpy.GetParameterAsText(0)

def radarBufferPoint(in_point, num_vertices, distance, spread=0.3, seed=None, srid=None):
random.seed(seed)
if num_vertices > 360: num_vertices = 360
if not isinstance(in_point, arcpy.PointGeometry):
in_point = arcpy.PointGeometry(in_point, arcpy.SpatialReference(srid))

pts = [
in_point.pointFromAngleAndDistance(
angle,
random.uniform((1-spread)*distance, (1+spread)*distance)
)
for angle
in range(0, 360, 360/num_vertices)
]

pg = arcpy.Polygon(
arcpy.Array([pt.firstPoint for pt in pts]),
in_point.spatialReference
)

return pg

and...nothing..

I suspect I need a few more code blocks, but I can't even write a python print statement without help from Dan Patterson

0 Kudos
JoshuaBixby
MVP Esteemed Contributor

(Time to learn more Python!  )

The code i provided isn't written for a feature class, just a single ArcPy geometry.  You would need to use cursors to iterate over a point feature class and populate a new polygon feature class.  I can look into expanding on the code. 

0 Kudos
DanPatterson_Retired
MVP Esteemed Contributor
0 Kudos
JoshuaBixby
MVP Esteemed Contributor

I haven't tried the following as a script tool, but it should be straightforward to package up that way:

import arcpy
import os
import random

def radarBufferPointFeatures(
in_features,
out_feature_class,
num_vertices,
distance,
spread=0.3,
seed=None
):
# Check for valid input
desc = arcpy.Describe(in_features)
if hasattr(desc, 'shapeType') and desc.shapeType == 'Point':
pass
else:
raise arcpy.ExecuteError("Failed to execute. Parameters are not valid. "
"Input Features: Dataset not point features")

# Create output feature class
out_fc = arcpy.CreateFeatureclass_management(
*os.path.split(out_feature_class),
geometry_type = 'Polygon',
spatial_reference = desc.spatialReference
)
arcpy.AddField_management(out_fc, "PT_OID", "LONG")

# Iterate over input features and perform radar buffer
random.seed(seed)
if num_vertices > 360: num_vertices = 360
with arcpy.da.SearchCursor(in_features, ["OID@", "SHAPE@"]) as scur:
with arcpy.da.InsertCursor(out_fc, ["PT_OID", "SHAPE@"]) as icur:
for oid, point in scur:
pts = [
point.pointFromAngleAndDistance(
angle,
random.uniform((1-spread)*distance, (1+spread)*distance)
)
for angle
in range(0, 360, 360/num_vertices)
]

pg = arcpy.Polygon(
arcpy.Array([pt.firstPoint for pt in pts]),
point.spatialReference
)

icur.insertRow([oid, pg])

del icur, scur