Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add RAWR data fetcher #244

Merged
merged 19 commits into from
Oct 4, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@ wsgiref==0.1.2
zope.dottedname==4.1.0
edtf==0.9.3
mapbox-vector-tile==1.2.0
git+https://github.com/tilezen/raw_tiles@master#egg=raw_tiles
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
'pyproj',
'python-dateutil',
'PyYAML',
'raw_tiles',
'redis',
'requests',
'Shapely',
Expand Down
183 changes: 179 additions & 4 deletions tests/test_query_fixture.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
import unittest


class TestQueryFixture(unittest.TestCase):
class FixtureTestCase(unittest.TestCase):

def _make(self, rows, min_zoom_fn, props_fn, relations=[],
layer_name='testlayer'):
from tilequeue.query.fixture import LayerInfo
layer_name='testlayer', label_placement_layers={}):
from tilequeue.query.common import LayerInfo
from tilequeue.query.fixture import make_fixture_data_fetcher
layers = {layer_name: LayerInfo(min_zoom_fn, props_fn)}
return make_fixture_data_fetcher(layers, rows, relations=relations)
return make_fixture_data_fetcher(
layers, rows, label_placement_layers=label_placement_layers,
relations=relations)


class TestQueryFixture(FixtureTestCase):

def test_query_simple(self):
from shapely.geometry import Point
Expand Down Expand Up @@ -141,3 +146,173 @@ def _rel(id, nodes=None, ways=None, rels=None):
_rel(4, rels=[3]),
_rel(5, rels=[2, 4]),
], 5)


class TestLabelPlacement(FixtureTestCase):

def _test(self, layer_name, props):
from ModestMaps.Core import Coordinate
from tilequeue.tile import coord_to_mercator_bounds
from shapely.geometry import box

def min_zoom_fn(shape, props, fid, meta):
return 0

tile = Coordinate(zoom=15, column=0, row=0)
bounds = coord_to_mercator_bounds(tile)
shape = box(*bounds)

rows = [
(1, shape, props),
]

label_placement_layers = {
'polygon': set([layer_name]),
}
fetch = self._make(
rows, min_zoom_fn, None, relations=[], layer_name=layer_name,
label_placement_layers=label_placement_layers)

read_rows = fetch(16, bounds)
return read_rows

def test_named_item(self):
from shapely import wkb

layer_name = 'testlayer'
read_rows = self._test(layer_name, {'name': 'Foo'})

self.assertEquals(1, len(read_rows))

label_prop = '__label__'
self.assertTrue(label_prop in read_rows[0])
point = wkb.loads(read_rows[0][label_prop])
self.assertEqual(point.geom_type, 'Point')


class TestGeometryClipping(FixtureTestCase):

def _test(self, layer_name, bounds, factor):
from shapely.geometry import box

def min_zoom_fn(shape, props, fid, meta):
return 0

boxwidth = bounds[2] - bounds[0]
boxheight = bounds[3] - bounds[1]
# make shape overlap the edges of the bounds. that way we can check to
# see if the shape gets clipped.
shape = box(bounds[0] - factor * boxwidth,
bounds[1] - factor * boxheight,
bounds[2] + factor * boxwidth,
bounds[3] + factor * boxheight)

props = {'name': 'Foo'}

rows = [
(1, shape, props),
]

fetch = self._make(
rows, min_zoom_fn, None, relations=[], layer_name=layer_name)

read_rows = fetch(16, bounds)
self.assertEqual(1, len(read_rows))
return read_rows[0]

def test_normal_layer(self):
from ModestMaps.Core import Coordinate
from tilequeue.tile import coord_to_mercator_bounds
from shapely import wkb

tile = Coordinate(zoom=15, column=10, row=10)
bounds = coord_to_mercator_bounds(tile)

read_row = self._test('testlayer', bounds, 1.0)
clipped_shape = wkb.loads(read_row['__geometry__'])
# for normal layers, clipped shape is inside the bounds of the tile.
x_factor = ((clipped_shape.bounds[2] - clipped_shape.bounds[0]) /
(bounds[2] - bounds[0]))
y_factor = ((clipped_shape.bounds[2] - clipped_shape.bounds[0]) /
(bounds[2] - bounds[0]))
self.assertAlmostEqual(1.0, x_factor)
self.assertAlmostEqual(1.0, y_factor)

def test_water_layer(self):
# water layer should be expanded by 10% on each side.
from ModestMaps.Core import Coordinate
from tilequeue.tile import coord_to_mercator_bounds
from shapely import wkb

tile = Coordinate(zoom=15, column=10, row=10)
bounds = coord_to_mercator_bounds(tile)

read_row = self._test('water', bounds, 1.0)
clipped_shape = wkb.loads(read_row['__geometry__'])
# for water layer, the geometry should be 10% larger than the tile
# bounds.
x_factor = ((clipped_shape.bounds[2] - clipped_shape.bounds[0]) /
(bounds[2] - bounds[0]))
y_factor = ((clipped_shape.bounds[2] - clipped_shape.bounds[0]) /
(bounds[2] - bounds[0]))
self.assertAlmostEqual(1.1, x_factor)
self.assertAlmostEqual(1.1, y_factor)


class TestNameHandling(FixtureTestCase):

def _test(self, input_layer_names, expected_layer_names):
from shapely.geometry import Point
from tilequeue.query.common import LayerInfo
from tilequeue.query.fixture import make_fixture_data_fetcher
from tilequeue.tile import coord_to_mercator_bounds
from tilequeue.tile import mercator_point_to_coord

def min_zoom_fn(shape, props, fid, meta):
return 0

def props_fn(shape, props, fid, meta):
return {}

shape = Point(0, 0)
props = {'name': 'Foo'}

rows = [
(1, shape, props),
]

layers = {}
for name in input_layer_names:
layers[name] = LayerInfo(min_zoom_fn, props_fn)
fetch = make_fixture_data_fetcher(layers, rows)

feature_coord = mercator_point_to_coord(16, shape.x, shape.y)
read_rows = fetch(16, coord_to_mercator_bounds(feature_coord))
self.assertEqual(1, len(read_rows))

all_names = set(expected_layer_names) | set(input_layer_names)
for name in all_names:
properties_name = '__%s_properties__' % name
self.assertTrue(properties_name in read_rows[0])
actual_name = read_rows[0][properties_name].get('name')
if name in expected_layer_names:
expected_name = props.get('name')
self.assertEquals(expected_name, actual_name)
else:
# check the name doesn't appear anywhere else
self.assertEquals(None, actual_name)

def test_name_single_layer(self):
# in any oone of the pois, landuse or buildings layers, a name
# by itself will be output in the same layer.
for layer_name in ('pois', 'landuse', 'buildings'):
self._test([layer_name], [layer_name])

def test_precedence(self):
# if the feature is in the pois layer, then that should get the name
# and the other layers should not.
self._test(['pois', 'landuse'], ['pois'])
self._test(['pois', 'buildings'], ['pois'])
self._test(['pois', 'landuse', 'buildings'], ['pois'])
# otherwise, landuse should take precedence over buildings.
self._test(['landuse', 'buildings'], ['landuse'])
Loading