Skip to content

Instantly share code, notes, and snippets.

@ka7eh
Created June 2, 2017 00:04
Show Gist options
  • Save ka7eh/9e6d5b428b22aef2656350c1f41721e4 to your computer and use it in GitHub Desktop.
Save ka7eh/9e6d5b428b22aef2656350c1f41721e4 to your computer and use it in GitHub Desktop.
A factory for creating random polygons in a given extent
# requires pyproj and shapely
import collections
import functools
import math
import random
import pyproj
from shapely.geometry import box, point, polygon
from shapely.ops import transform
Extent = collections.namedtuple('Extent', ['x_min', 'y_min', 'x_max', 'y_max'])
class GeomFactory:
def __init__(self, max_area, min_area=0, extent=(-180, -90, 180, 90), geom_nums=1, max_polygon_sides=5):
"""Creates a collection of random polygons within the given extent. The collection can be retrieved through
`geoms` method. Returned geometries are in WKT format.
:param max_area: in acre
:param min_area: in acre
:param extent: an array of coordinates for SW and NE corners
:param geom_nums: number of geometries to create
:param max_polygon_sides: Max number of sides for created geometries
"""
self.extent = Extent(*extent)
self.max_area = max_area * 4046.86
self.min_area = min_area * 4046.86
self.geom_nums = geom_nums
self.max_polygon_sides = max(3, max_polygon_sides)
@property
def proj_wgs_to_cart(self):
return functools.partial(
pyproj.transform,
pyproj.Proj(init='epsg:4326'),
pyproj.Proj(init='epsg:26913')
)
@property
def proj_cart_to_wgs(self):
return functools.partial(
pyproj.transform,
pyproj.Proj(init='epsg:26913'),
pyproj.Proj(init='epsg:4326')
)
def generate_point_in(self, outer_extent, inner_extent=None):
if inner_extent:
ran = random.choice(['min', 'max'])
print(getattr(outer_extent, 'x_{}'.format(ran)), getattr(inner_extent, 'x_{}'.format(ran)))
x = random.uniform(getattr(outer_extent, 'x_{}'.format(ran)), getattr(inner_extent, 'x_{}'.format(ran)))
ran = random.choice(['min', 'max'])
print(getattr(outer_extent, 'y_{}'.format(ran)), getattr(inner_extent, 'y_{}'.format(ran)))
y = random.uniform(getattr(outer_extent, 'y_{}'.format(ran)), getattr(inner_extent, 'y_{}'.format(ran)))
else:
x = random.uniform(outer_extent.x_min, outer_extent.x_max)
y = random.uniform(outer_extent.y_min, outer_extent.y_max)
return x, y
def get_geom_max_bounds(self, center, max_buffer_length, min_buffer_length):
c = transform(self.proj_wgs_to_cart, point.Point(center))
outer_bound = transform(
self.proj_cart_to_wgs,
box(
c.x - max_buffer_length,
c.y - max_buffer_length,
c.x + max_buffer_length,
c.y + max_buffer_length,
False)
)
outer_ext = outer_bound.intersection(
box(self.extent.x_min, self.extent.y_min, self.extent.x_max, self.extent.y_max, False))
inner_bound = transform(
self.proj_cart_to_wgs,
box(
c.x - min_buffer_length,
c.y - min_buffer_length,
c.x + min_buffer_length,
c.y + min_buffer_length,
False
)
)
return Extent(*outer_ext.bounds), Extent(*inner_bound.bounds)
def calculate_area(self, geom):
return transform(self.proj_wgs_to_cart, geom).area
@property
def geoms(self):
geoms = []
for _ in range(self.geom_nums):
center = self.generate_point_in(self.extent)
geom_outer_bounds, geom_inner_bounds = self.get_geom_max_bounds(
center,
math.sqrt(self.max_area) / 2,
math.sqrt(self.min_area) / 2
)
coordinates = []
for __ in range(random.randint(3, self.max_polygon_sides)):
coordinates.append(self.generate_point_in(geom_outer_bounds, geom_inner_bounds))
coordinates.append(coordinates[0])
geoms.append(polygon.Polygon(coordinates).wkt)
return geoms
if __name__ == '__main__':
factory = GeomFactory(20000, 2000, extent=[-90.15, 25.25, -74.25, 29.89], geom_nums=100)
print(factory.geoms)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment