Skip to content

Commit

Permalink
Merge pull request #368 from tilezen/zerebubuth/fix-boundaries-orient…
Browse files Browse the repository at this point in the history
…-multipolygon

Add utility function to orient MultiPolygons.
  • Loading branch information
zerebubuth authored Feb 4, 2019
2 parents 58f6398 + da716aa commit 7d47872
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 1 deletion.
42 changes: 42 additions & 0 deletions tests/test_query_rawr.py
Original file line number Diff line number Diff line change
Expand Up @@ -820,6 +820,48 @@ def _tile_triangle(bounds):
# check no area
self.assertIsNone(props.get('area'))

def test_boundaries_from_multipolygons(self):
# check that the boundary extraction code also works for multipolygons
from shapely.geometry import Polygon, MultiPolygon

def _tile_squares(bounds):
# maxy +----+
# | b |
# midy +----+----+
# | a |
# miny +----+
# minx midx maxx

minx, miny, maxx, maxy = bounds
midx = 0.5 * (minx + maxx)
midy = 0.5 * (miny + maxy)

a = Polygon([
[minx, miny],
[minx, midy],
[midx, midy],
[midx, miny],
[minx, miny],
])

b = Polygon([
[midx, midy],
[midx, maxy],
[maxx, maxy],
[maxx, midy],
[midy, midy],
])

return MultiPolygon([a, b])

read_rows = self._fetch_data(_tile_squares, 'planet_osm_polygon')

self.assertEqual(len(read_rows), 1)
props = read_rows[0]['__boundaries_properties__']
self.assertEqual(props.get('boundary'), 'administrative')
# check no area
self.assertIsNone(props.get('area'))


class TestBufferedLand(RawrTestCase):

Expand Down
22 changes: 21 additions & 1 deletion tilequeue/query/rawr.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from collections import namedtuple, defaultdict
from shapely.geometry import box
from shapely.geometry import MultiLineString
from shapely.geometry import MultiPolygon
from shapely.geometry.polygon import orient
from shapely.wkb import loads as wkb_loads
from tilequeue.query.common import layer_properties
Expand Down Expand Up @@ -612,6 +613,25 @@ def _lines_only(shape):
return MultiLineString(lines)


def _orient(shape):
"""
The Shapely version of the orient function appears to only work on
Polygons, and fails on MultiPolygons. This is a quick wrapper to allow
orienting of either.
"""

assert shape.geom_type in ('Polygon', 'MultiPolygon')

if shape.geom_type == 'Polygon':
return orient(shape)

else:
polys = []
for geom in shape.geoms:
polys.append(orient(geom))
return MultiPolygon(polys)


class RawrTile(object):

def __init__(self, layers, tables, tile_pyramid, label_placement_layers,
Expand Down Expand Up @@ -757,7 +777,7 @@ def _parse_row(self, zoom, unpadded_bounds, bbox, source, fid, shape,
# make sure boundary rings are oriented in the correct
# direction; anti-clockwise for outers and clockwise for
# inners, which means the interior should be on the left.
boundaries_shape = orient(shape).boundary
boundaries_shape = _orient(shape).boundary

# make sure it's only lines, post-intersection. a polygon-line
# intersection can return points as well as lines. however,
Expand Down

0 comments on commit 7d47872

Please sign in to comment.