Skip to content

Commit

Permalink
Merge a6e363b into e1a9594
Browse files Browse the repository at this point in the history
  • Loading branch information
fitodic committed Sep 9, 2018
2 parents e1a9594 + a6e363b commit 4d441b8
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 32 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).

## 0.5 - 2018-09-09

### Added

- `MultiPolygon` support

## 0.4.2 - 2018-08-22

### Added
Expand Down
2 changes: 1 addition & 1 deletion centerline/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from __future__ import unicode_literals

__title__ = 'centerline'
__version__ = '0.4.2'
__version__ = '0.5'
__author__ = 'Filip Todic'
__license__ = 'MIT'
__copyright__ = 'Copyright (c) 2014-present Filip Todic'
Expand Down
6 changes: 3 additions & 3 deletions centerline/io.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from shapely.geometry import mapping, shape

from .main import Centerline
from .utils import get_ogr_driver, is_polygon
from .utils import get_ogr_driver, is_valid_geometry


def create_centerlines(src, dst, density=0.5):
Expand Down Expand Up @@ -50,11 +50,11 @@ def create_centerlines(src, dst, density=0.5):
encoding=source.encoding) as destination:
for record in source:
geom = record.get('geometry')
input_geom = shape(geom)

if not is_polygon(geometry_type=geom.get('type')):
if not is_valid_geometry(geometry=input_geom):
continue

input_geom = shape(geom)
attributes = record.get('properties')
try:
centerline_obj = Centerline(
Expand Down
34 changes: 22 additions & 12 deletions centerline/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@

from numpy import array
from scipy.spatial import Voronoi
from shapely.geometry import LineString, MultiLineString, Polygon
from shapely.geometry import LineString, MultiLineString, MultiPolygon
from shapely.ops import unary_union

from .utils import is_valid_geometry


class Centerline(MultiLineString):
"""
Expand Down Expand Up @@ -40,9 +42,10 @@ def __init__(self, input_geom, interpolation_dist=0.5, **attributes):
ValueError: invalid input geometry
"""
if not isinstance(input_geom, Polygon):
if not is_valid_geometry(input_geom):
raise ValueError(
'Input geometry must be of type shapely.geometry.Polygon!'
'Input geometry must be of type shapely.geometry.Polygon '
'or shapely.geometry.MultiPolygon!'
)

self._input_geom = input_geom
Expand Down Expand Up @@ -112,17 +115,24 @@ def __densify_border(self):
[[X1, Y1], [X2, Y2], ..., [Xn, Yn]
"""
if len(self._input_geom.interiors) == 0:
exterIN = LineString(self._input_geom.exterior)
points = self.__fixed_interpolation(exterIN)

if isinstance(self._input_geom, MultiPolygon):
polygons = [polygon for polygon in self._input_geom]
else:
exterIN = LineString(self._input_geom.exterior)
points = self.__fixed_interpolation(exterIN)
polygons = [self._input_geom]

points = []
for polygon in polygons:
if len(polygon.interiors) == 0:
exterior = LineString(polygon.exterior)
points += self.__fixed_interpolation(exterior)

else:
exterior = LineString(polygon.exterior)
points += self.__fixed_interpolation(exterior)

for j in range(len(self._input_geom.interiors)):
interIN = LineString(self._input_geom.interiors[j])
points += self.__fixed_interpolation(interIN)
for j in range(len(polygon.interiors)):
interior = LineString(polygon.interiors[j])
points += self.__fixed_interpolation(interior)

return points

Expand Down
11 changes: 6 additions & 5 deletions centerline/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,27 @@
import os

from osgeo import gdal, ogr
from shapely.geometry import MultiPolygon, Polygon

# Enable GDAL/OGR exceptions
gdal.UseExceptions()


ALLOWED_INPUT_GEOMETRY = 'Polygon'
ALLOWED_INPUT_GEOMETRIES = ('Polygon', 'MultiPolygon')


def is_polygon(geometry_type):
def is_valid_geometry(geometry):
"""
Confirm that the geometry type is of type Polygon.
Confirm that the geometry type is of type Polygon or MultiPolygon.
Args:
geometry_type (str): geometry type
geometry (BaseGeometry): BaseGeometry instance (e.g. Polygon)
Returns:
bool
"""
if geometry_type == ALLOWED_INPUT_GEOMETRY:
if isinstance(geometry, Polygon) or isinstance(geometry, MultiPolygon):
return True
else:
return False
Expand Down
13 changes: 8 additions & 5 deletions tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

class TestCenterlineSupportedGeometryTypes(TestCase):
"""
Only Polygons should be supported.
Only Polygons and MultiPolygons should be supported.
For more information about creating the geometry objects (like the
ones used below) see The Shapely User Manual:
Expand All @@ -39,11 +39,14 @@ def test__polygon_with_interior_ring__returns_multilinestring(self):
self.assertIsInstance(centerline, MultiLineString)

def test__multipolygon__raises_valueerror(self):
POLYGONS = [Point(i, 0).buffer(0.1) for i in range(2)]
MULTIPOLYGON = MultiPolygon(POLYGONS)
POLYGON_1 = Polygon([[0, 0], [0, 4], [4, 4], [4, 0]])
POLYGON_2 = Polygon([[5, 5], [5, 9], [9, 9], [9, 5]])

with self.assertRaises(ValueError):
Centerline(MULTIPOLYGON)
MULTIPOLYGON = MultiPolygon([POLYGON_1, POLYGON_2])

centerline = Centerline(MULTIPOLYGON)

self.assertIsInstance(centerline, MultiLineString)

def test__point__raises_valueerror(self):
POINT = Point(0, 0)
Expand Down
29 changes: 23 additions & 6 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,37 @@
import os
from unittest import TestCase

from centerline.utils import get_ogr_driver, is_polygon
from shapely import geometry

from centerline.utils import get_ogr_driver, is_valid_geometry

TESTS_DIR = os.path.dirname(os.path.abspath(__file__))
SHP_DIR = os.path.join(TESTS_DIR, 'data', 'shp')
GEOJSON_DIR = os.path.join(TESTS_DIR, 'data', 'geojson')


class TestIsPolygon(TestCase):
class TestIsValidGeometry(TestCase):

def test_point_returns_false(self):
self.assertFalse(is_valid_geometry(geometry.Point()))

def test_multipoint_returns_false(self):
self.assertFalse(is_valid_geometry(geometry.MultiPoint()))

def test_linestring_returns_false(self):
self.assertFalse(is_valid_geometry(geometry.LineString()))

def test_multilinestring_returns_false(self):
self.assertFalse(is_valid_geometry(geometry.MultiLineString()))

def test_linearring_returns_false(self):
self.assertFalse(is_valid_geometry(geometry.LinearRing()))

def test__returns_true(self):
self.assertTrue(is_polygon('Polygon'))
def test_polygon_returns_true(self):
self.assertTrue(is_valid_geometry(geometry.Polygon()))

def test__returns_false_for_multipolygon(self):
self.assertFalse(is_polygon('MultiPolygon'))
def test_multipolygon_returns_true(self):
self.assertTrue(is_valid_geometry(geometry.MultiPolygon()))


class TestGetOgrDriver(TestCase):
Expand Down

0 comments on commit 4d441b8

Please sign in to comment.