Random Shapes?

1073
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 Emeritus
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