Created
June 2, 2017 00:04
-
-
Save ka7eh/9e6d5b428b22aef2656350c1f41721e4 to your computer and use it in GitHub Desktop.
A factory for creating random polygons in a given extent
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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