159 lines
5.4 KiB
Python
159 lines
5.4 KiB
Python
|
#!/usr/bin/env python
|
||
|
# -*- coding: utf-8 -*-
|
||
|
|
||
|
import os
|
||
|
import math
|
||
|
import mapnik
|
||
|
import sys
|
||
|
from utilities import execution_path
|
||
|
from nose.tools import *
|
||
|
|
||
|
try:
|
||
|
from shapely.geometry import Point
|
||
|
have_shapely = True
|
||
|
except ImportError:
|
||
|
print('Shapely is required for python data source test.')
|
||
|
have_shapely = False
|
||
|
|
||
|
def setup():
|
||
|
# All of the paths used are relative, if we run the tests
|
||
|
# from another directory we need to chdir()
|
||
|
os.chdir(execution_path('.'))
|
||
|
|
||
|
class PointDatasource(mapnik.PythonDatasource):
|
||
|
def __init__(self):
|
||
|
super(PointDatasource, self).__init__(
|
||
|
envelope = mapnik.Box2d(0,-10,100,110)
|
||
|
)
|
||
|
|
||
|
def features(self, query):
|
||
|
return mapnik.PythonDatasource.wkb_features(
|
||
|
keys = ('label',),
|
||
|
features = (
|
||
|
( Point(5,6).wkb, { 'label': 'foo-bar'} ),
|
||
|
( Point(60,50).wkb, { 'label': 'buzz-quux'} ),
|
||
|
)
|
||
|
)
|
||
|
|
||
|
def box2d_to_shapely(box):
|
||
|
import shapely.geometry
|
||
|
return shapely.geometry.box(box.minx, box.miny, box.maxx, box.maxy)
|
||
|
|
||
|
class ConcentricCircles(object):
|
||
|
def __init__(self, centre, bounds, step=1):
|
||
|
self.centre = centre
|
||
|
self.bounds = bounds
|
||
|
self.step = step
|
||
|
|
||
|
class Iterator(object):
|
||
|
def __init__(self, container):
|
||
|
self.container = container
|
||
|
|
||
|
centre = self.container.centre
|
||
|
bounds = self.container.bounds
|
||
|
step = self.container.step
|
||
|
|
||
|
if centre.within(bounds):
|
||
|
self.radius = step
|
||
|
else:
|
||
|
self.radius = math.ceil(centre.distance(bounds) / float(step)) * step
|
||
|
|
||
|
def next(self):
|
||
|
circle = self.container.centre.buffer(self.radius)
|
||
|
self.radius += self.container.step
|
||
|
|
||
|
# has the circle grown so large that the boundary is entirely within it?
|
||
|
if circle.contains(self.container.bounds):
|
||
|
raise StopIteration()
|
||
|
|
||
|
return ( circle.wkb, { } )
|
||
|
|
||
|
def __iter__(self):
|
||
|
return ConcentricCircles.Iterator(self)
|
||
|
|
||
|
class CirclesDatasource(mapnik.PythonDatasource):
|
||
|
def __init__(self, centre_x=-20, centre_y=0, step=10):
|
||
|
super(CirclesDatasource, self).__init__(
|
||
|
geometry_type=mapnik.DataGeometryType.Polygon
|
||
|
)
|
||
|
|
||
|
# note that the plugin loader will set all arguments to strings and will not try to parse them
|
||
|
centre_x = int(centre_x)
|
||
|
centre_y = int(centre_y)
|
||
|
step = int(step)
|
||
|
|
||
|
self.centre_x = centre_x
|
||
|
self.centre_y = centre_y
|
||
|
self.step = step
|
||
|
|
||
|
def features(self, query):
|
||
|
# Get the query bounding-box as a shapely bounding box
|
||
|
bounding_box = box2d_to_shapely(query.bbox)
|
||
|
centre = Point(self.centre_x, self.centre_y)
|
||
|
|
||
|
return mapnik.PythonDatasource.wkb_features(
|
||
|
keys = (),
|
||
|
features = ConcentricCircles(centre, bounding_box, self.step)
|
||
|
)
|
||
|
|
||
|
if 'python' in mapnik.DatasourceCache.instance().plugin_names() and have_shapely:
|
||
|
# make sure we can load from ourself as a module
|
||
|
sys.path.append(execution_path('.'))
|
||
|
|
||
|
def test_python_point_init():
|
||
|
ds = mapnik.Python(factory='python_plugin_test:PointDatasource')
|
||
|
e = ds.envelope()
|
||
|
|
||
|
assert_almost_equal(e.minx, 0, places=7)
|
||
|
assert_almost_equal(e.miny, -10, places=7)
|
||
|
assert_almost_equal(e.maxx, 100, places=7)
|
||
|
assert_almost_equal(e.maxy, 110, places=7)
|
||
|
|
||
|
def test_python_circle_init():
|
||
|
ds = mapnik.Python(factory='python_plugin_test:CirclesDatasource')
|
||
|
e = ds.envelope()
|
||
|
|
||
|
assert_almost_equal(e.minx, -180, places=7)
|
||
|
assert_almost_equal(e.miny, -90, places=7)
|
||
|
assert_almost_equal(e.maxx, 180, places=7)
|
||
|
assert_almost_equal(e.maxy, 90, places=7)
|
||
|
|
||
|
def test_python_circle_init_with_args():
|
||
|
ds = mapnik.Python(factory='python_plugin_test:CirclesDatasource', centre_x=40, centre_y=7)
|
||
|
e = ds.envelope()
|
||
|
|
||
|
assert_almost_equal(e.minx, -180, places=7)
|
||
|
assert_almost_equal(e.miny, -90, places=7)
|
||
|
assert_almost_equal(e.maxx, 180, places=7)
|
||
|
assert_almost_equal(e.maxy, 90, places=7)
|
||
|
|
||
|
def test_python_point_rendering():
|
||
|
m = mapnik.Map(512,512)
|
||
|
mapnik.load_map(m,'../data/good_maps/python_point_datasource.xml')
|
||
|
m.zoom_all()
|
||
|
im = mapnik.Image(512,512)
|
||
|
mapnik.render(m,im)
|
||
|
actual = '/tmp/mapnik-python-point-render1.png'
|
||
|
expected = 'images/support/mapnik-python-point-render1.png'
|
||
|
im.save(actual)
|
||
|
expected_im = mapnik.Image.open(expected)
|
||
|
eq_(im.tostring(),expected_im.tostring(),
|
||
|
'failed comparing actual (%s) and expected (%s)' % (actual,'tests/python_tests/'+ expected))
|
||
|
|
||
|
def test_python_circle_rendering():
|
||
|
m = mapnik.Map(512,512)
|
||
|
mapnik.load_map(m,'../data/good_maps/python_circle_datasource.xml')
|
||
|
m.zoom_all()
|
||
|
im = mapnik.Image(512,512)
|
||
|
mapnik.render(m,im)
|
||
|
actual = '/tmp/mapnik-python-circle-render1.png'
|
||
|
expected = 'images/support/mapnik-python-circle-render1.png'
|
||
|
im.save(actual)
|
||
|
expected_im = mapnik.Image.open(expected)
|
||
|
eq_(im.tostring(),expected_im.tostring(),
|
||
|
'failed comparing actual (%s) and expected (%s)' % (actual,'tests/python_tests/'+ expected))
|
||
|
|
||
|
if __name__ == "__main__":
|
||
|
setup()
|
||
|
[eval(run)() for run in dir() if 'test_' in run]
|