Disperse overlapping points

A user recently asked if a geoprocessing tool existed to randomly disperse overlapping points inside an area or polygon. There is no specific tool, however, with a little Python code and the use of a geometry operator, this can be accomplished very quickly.

Here’s an illustration and the code recipe.

dispersepoints

import random
import arcpy

def point_in_poly(poly, x, y):
    """Returns if the point is inside the polygon.

    Parameters:
        poly: arcpy.Polygon() geometry
        x:    x coordinate (float)
        y:    y coordinate (float)

    """
    pg = arcpy.PointGeometry(arcpy.Point(x, y), poly.spatialReference)
    return poly.contains(pg)

def disperse_points(in_points, polygon):
    """Randomly disperse points inside a polygon.

    Parameters:
        in_points:  Point feature class/layer (with or without selection)
        polygon:    arcpy.Polygon() geometry

    """

    lenx = polygon.extent.width
    leny = polygon.extent.height

    with arcpy.da.UpdateCursor(in_points, "shape@xy") as points:
        for p in points:
            x = (random.random() * lenx) + polygon.extent.XMin
            y = (random.random() * leny) + polygon.extent.YMin
            inside = point_in_poly(polygon, x, y)
            while not inside:
                x = (random.random() * lenx) + polygon.extent.XMin
                y = (random.random() * leny) + polygon.extent.YMin
                inside = point_in_poly(polygon, x, y)
            points.updateRow([(x, y)])
Advertisements

Find overlapping features

In ArcGIS 10, additional functions for performing relational operations was added to the geometry object. The following code uses the overlaps function to find overlapping features and prints out the ObjectID pairs. For a complete list of relational operators, see the Geometry class.

This code is supported in ArcGIS 10.0.

def find_overlaps(input_features):
    '''Find and print OID value pairs for overlapping features.'''
    oid_field = arcpy.ListFields(input_features, '*', 'OID')[0]
    for row in arcpy.SearchCursor(input_features, '', '', 'Shape;{0}'.format(oid_field.name)):
        for row2 in arcpy.SearchCursor(input_features, '', '', 'Shape;{0}'.format(oid_field.name)):
            if row2.Shape.overlaps(row.Shape):
                print '{0} overlaps {1}'.format(str(row2.getValue(oid_field.name)), str(row.getValue(oid_field.name)))

ArcGIS 10.1 introduces a new data access module, arcpy.da, for working with data. It includes cursor functions which provide improved cursor support and faster performance. The following code can replace the previous sample code and provide improved performance.

From more information about arcpy.da, see the data access module.

def find_overlaps(input_features):                
    '''Find and print OID value pairs for overlapping features.'''
    for row in arcpy.da.SearchCursor(input_features, ('OID@', 'SHAPE@')):
        for row2 in arcpy.da.SearchCursor(input_features, ('OID@', 'SHAPE@')):
            if row2[1].overlaps(row[1]):
                print '{0} overlaps {1}'.format(str(row2[0]), str(row[0]))