355 lines
48 KiB
Python
355 lines
48 KiB
Python
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
|
|
from nose.tools import eq_,raises
|
|
from utilities import execution_path, run_all
|
|
import os, mapnik
|
|
|
|
try:
|
|
import json
|
|
except ImportError:
|
|
import simplejson as json
|
|
|
|
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('.'))
|
|
|
|
if mapnik.has_grid_renderer():
|
|
def show_grids(name,g1,g2):
|
|
g1_file = '/tmp/mapnik-%s-actual.json' % name
|
|
open(g1_file,'w').write(json.dumps(g1,sort_keys=True))
|
|
g2_file = '/tmp/mapnik-%s-expected.json' % name
|
|
open(g2_file,'w').write(json.dumps(g2,sort_keys=True))
|
|
val = 'JSON does not match ->\n'
|
|
if g1['grid'] != g2['grid']:
|
|
val += ' X grid does not match\n'
|
|
else:
|
|
val += ' ✓ grid matches\n'
|
|
if g1['data'].keys() != g2['data'].keys():
|
|
val += ' X data does not match\n'
|
|
else:
|
|
val += ' ✓ data matches\n'
|
|
if g1['keys'] != g2['keys']:
|
|
val += ' X keys do not\n'
|
|
else:
|
|
val += ' ✓ keys match\n'
|
|
val += '\n\t%s\n\t%s' % (g1_file,g2_file)
|
|
return val
|
|
|
|
def show_grids2(name,g1,g2):
|
|
g2_expected = '../data/grids/mapnik-%s-actual.json' % name
|
|
if not os.path.exists(g2_expected):
|
|
# create test fixture based on actual results
|
|
open(g2_expected,'a+').write(json.dumps(g1,sort_keys=True))
|
|
return
|
|
g1_file = '/tmp/mapnik-%s-actual.json' % name
|
|
open(g1_file,'w').write(json.dumps(g1,sort_keys=True))
|
|
val = 'JSON does not match ->\n'
|
|
if g1['grid'] != g2['grid']:
|
|
val += ' X grid does not match\n'
|
|
else:
|
|
val += ' ✓ grid matches\n'
|
|
if g1['data'].keys() != g2['data'].keys():
|
|
val += ' X data does not match\n'
|
|
else:
|
|
val += ' ✓ data matches\n'
|
|
if g1['keys'] != g2['keys']:
|
|
val += ' X keys do not\n'
|
|
else:
|
|
val += ' ✓ keys match\n'
|
|
val += '\n\t%s\n\t%s' % (g1_file,g2_expected)
|
|
return val
|
|
|
|
# previous rendering using agg ellipse directly
|
|
grid_correct_new = {"data": {"North East": {"Name": "North East"}, "North West": {"Name": "North West"}, "South East": {"Name": "South East"}, "South West": {"Name": "South West"}}, "grid": [" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " !! ## ", " !!! ### ", " !! ## ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " $$ %% ", " $$$ %% ", " $$ %% ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "], "keys": ["", "North West", "North East", "South West", "South East"]}
|
|
|
|
# newer rendering using svg
|
|
grid_correct_new2 = {"data": {"North East": {"Name": "North East"}, "North West": {"Name": "North West"}, "South East": {"Name": "South East"}, "South West": {"Name": "South West"}}, "grid": [" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " !! ## ", " !!! ### ", " !! ## ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " $$ %% ", " $$$ %% ", " $$ %% ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "], "keys": ["", "North West", "North East", "South West", "South East"]}
|
|
|
|
grid_correct_new3 = {"data": {"North East": {"Name": "North East"}, "North West": {"Name": "North West"}, "South East": {"Name": "South East"}, "South West": {"Name": "South West"}}, "grid": [" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " !! ## ", " !!! ### ", " !! ## ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " $$ %% ", " $$$ %% ", " $ %% ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "], "keys": ["", "North West", "North East", "South West", "South East"]}
|
|
|
|
def resolve(grid,row,col):
|
|
""" Resolve the attributes for a given pixel in a grid.
|
|
"""
|
|
row = grid['grid'][row]
|
|
utf_val = row[col]
|
|
#http://docs.python.org/library/functions.html#ord
|
|
codepoint = ord(utf_val)
|
|
if (codepoint >= 93):
|
|
codepoint-=1
|
|
if (codepoint >= 35):
|
|
codepoint-=1
|
|
codepoint -= 32
|
|
key = grid['keys'][codepoint]
|
|
return grid['data'].get(key)
|
|
|
|
|
|
def create_grid_map(width,height,sym):
|
|
ds = mapnik.MemoryDatasource()
|
|
context = mapnik.Context()
|
|
context.push('Name')
|
|
f = mapnik.Feature(context,1)
|
|
f['Name'] = 'South East'
|
|
f.add_geometries_from_wkt('POINT (143.10 -38.60)')
|
|
ds.add_feature(f)
|
|
|
|
f = mapnik.Feature(context,2)
|
|
f['Name'] = 'South West'
|
|
f.add_geometries_from_wkt('POINT (142.48 -38.60)')
|
|
ds.add_feature(f)
|
|
|
|
f = mapnik.Feature(context,3)
|
|
f['Name'] = 'North West'
|
|
f.add_geometries_from_wkt('POINT (142.48 -38.38)')
|
|
ds.add_feature(f)
|
|
|
|
f = mapnik.Feature(context,4)
|
|
f['Name'] = 'North East'
|
|
f.add_geometries_from_wkt('POINT (143.10 -38.38)')
|
|
ds.add_feature(f)
|
|
s = mapnik.Style()
|
|
r = mapnik.Rule()
|
|
sym.allow_overlap = True
|
|
r.symbols.append(sym)
|
|
s.rules.append(r)
|
|
lyr = mapnik.Layer('Places')
|
|
lyr.datasource = ds
|
|
lyr.styles.append('places_labels')
|
|
m = mapnik.Map(width,height)
|
|
m.append_style('places_labels',s)
|
|
m.layers.append(lyr)
|
|
return m
|
|
|
|
|
|
def test_render_grid():
|
|
""" test render_grid method"""
|
|
width,height = 256,256
|
|
sym = mapnik.MarkersSymbolizer()
|
|
sym.width = mapnik.Expression('10')
|
|
sym.height = mapnik.Expression('10')
|
|
m = create_grid_map(width,height,sym)
|
|
ul_lonlat = mapnik.Coord(142.30,-38.20)
|
|
lr_lonlat = mapnik.Coord(143.40,-38.80)
|
|
m.zoom_to_box(mapnik.Box2d(ul_lonlat,lr_lonlat))
|
|
|
|
# new method
|
|
grid = mapnik.Grid(m.width,m.height,key='Name')
|
|
mapnik.render_layer(m,grid,layer=0,fields=['Name'])
|
|
utf1 = grid.encode('utf',resolution=4)
|
|
eq_(utf1,grid_correct_new3,show_grids('new-markers',utf1,grid_correct_new3))
|
|
|
|
# check a full view is the same as a full image
|
|
grid_view = grid.view(0,0,width,height)
|
|
# for kicks check at full res too
|
|
utf3 = grid.encode('utf',resolution=1)
|
|
utf4 = grid_view.encode('utf',resolution=1)
|
|
eq_(utf3['grid'],utf4['grid'])
|
|
eq_(utf3['keys'],utf4['keys'])
|
|
eq_(utf3['data'],utf4['data'])
|
|
|
|
eq_(resolve(utf4,0,0),None)
|
|
|
|
# resolve some center points in the
|
|
# resampled view
|
|
utf5 = grid_view.encode('utf',resolution=4)
|
|
eq_(resolve(utf5,25,10),{"Name": "North West"})
|
|
eq_(resolve(utf5,25,46),{"Name": "North East"})
|
|
eq_(resolve(utf5,38,10),{"Name": "South West"})
|
|
eq_(resolve(utf5,38,46),{"Name": "South East"})
|
|
|
|
|
|
grid_feat_id = {'keys': ['', '3', '4', '2', '1'], 'data': {'1': {'Name': 'South East'}, '3': {'Name': u'North West'}, '2': {'Name': 'South West'}, '4': {'Name': 'North East'}}, 'grid': [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' !! ## ', ' !!! ### ', ' !! ## ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' $$$ %% ', ' $$$ %%% ', ' $$ %% ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ']}
|
|
|
|
grid_feat_id2 = {"data": {"1": {"Name": "South East"}, "2": {"Name": "South West"}, "3": {"Name": "North West"}, "4": {"Name": "North East"}}, "grid": [" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " !! ## ", " !!! ### ", " !! ## ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " $$ %% ", " $$$ %% ", " $$ %% ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "], "keys": ["", "3", "4", "2", "1"]}
|
|
|
|
grid_feat_id3 = {"data": {"1": {"Name": "South East", "__id__": 1}, "2": {"Name": "South West", "__id__": 2}, "3": {"Name": "North West", "__id__": 3}, "4": {"Name": "North East", "__id__": 4}}, "grid": [" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " !! ## ", " !!! ### ", " !! ## ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " $$ %% ", " $$$ %% ", " $ %% ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "], "keys": ["", "3", "4", "2", "1"]}
|
|
|
|
def test_render_grid3():
|
|
""" test using feature id"""
|
|
width,height = 256,256
|
|
sym = mapnik.MarkersSymbolizer()
|
|
sym.width = mapnik.Expression('10')
|
|
sym.height = mapnik.Expression('10')
|
|
m = create_grid_map(width,height,sym)
|
|
ul_lonlat = mapnik.Coord(142.30,-38.20)
|
|
lr_lonlat = mapnik.Coord(143.40,-38.80)
|
|
m.zoom_to_box(mapnik.Box2d(ul_lonlat,lr_lonlat))
|
|
|
|
grid = mapnik.Grid(m.width,m.height,key='__id__')
|
|
mapnik.render_layer(m,grid,layer=0,fields=['__id__','Name'])
|
|
utf1 = grid.encode('utf',resolution=4)
|
|
eq_(utf1,grid_feat_id3,show_grids('id-markers',utf1,grid_feat_id3))
|
|
# check a full view is the same as a full image
|
|
grid_view = grid.view(0,0,width,height)
|
|
# for kicks check at full res too
|
|
utf3 = grid.encode('utf',resolution=1)
|
|
utf4 = grid_view.encode('utf',resolution=1)
|
|
eq_(utf3['grid'],utf4['grid'])
|
|
eq_(utf3['keys'],utf4['keys'])
|
|
eq_(utf3['data'],utf4['data'])
|
|
|
|
eq_(resolve(utf4,0,0),None)
|
|
|
|
# resolve some center points in the
|
|
# resampled view
|
|
utf5 = grid_view.encode('utf',resolution=4)
|
|
eq_(resolve(utf5,25,10),{"Name": "North West","__id__": 3})
|
|
eq_(resolve(utf5,25,46),{"Name": "North East","__id__": 4})
|
|
eq_(resolve(utf5,38,10),{"Name": "South West","__id__": 2})
|
|
eq_(resolve(utf5,38,46),{"Name": "South East","__id__": 1})
|
|
|
|
|
|
def gen_grid_for_id(pixel_key):
|
|
ds = mapnik.MemoryDatasource()
|
|
context = mapnik.Context()
|
|
context.push('Name')
|
|
f = mapnik.Feature(context,pixel_key)
|
|
f['Name'] = str(pixel_key)
|
|
f.add_geometries_from_wkt('POLYGON ((0 0, 0 256, 256 256, 256 0, 0 0))')
|
|
ds.add_feature(f)
|
|
s = mapnik.Style()
|
|
r = mapnik.Rule()
|
|
symb = mapnik.PolygonSymbolizer()
|
|
r.symbols.append(symb)
|
|
s.rules.append(r)
|
|
lyr = mapnik.Layer('Places')
|
|
lyr.datasource = ds
|
|
lyr.styles.append('places_labels')
|
|
width,height = 256,256
|
|
m = mapnik.Map(width,height)
|
|
m.append_style('places_labels',s)
|
|
m.layers.append(lyr)
|
|
m.zoom_all()
|
|
grid = mapnik.Grid(m.width,m.height,key='__id__')
|
|
mapnik.render_layer(m,grid,layer=0,fields=['__id__','Name'])
|
|
return grid
|
|
|
|
def test_negative_id():
|
|
grid = gen_grid_for_id(-1)
|
|
eq_(grid.get_pixel(128,128),-1)
|
|
utf1 = grid.encode('utf',resolution=4)
|
|
eq_(utf1['keys'],['-1'])
|
|
|
|
def test_32bit_int_id():
|
|
int32 = 2147483647
|
|
grid = gen_grid_for_id(int32)
|
|
eq_(grid.get_pixel(128,128),int32)
|
|
utf1 = grid.encode('utf',resolution=4)
|
|
eq_(utf1['keys'],[str(int32)])
|
|
max_neg = -(int32)
|
|
grid = gen_grid_for_id(max_neg)
|
|
eq_(grid.get_pixel(128,128),max_neg)
|
|
utf1 = grid.encode('utf',resolution=4)
|
|
eq_(utf1['keys'],[str(max_neg)])
|
|
|
|
def test_64bit_int_id():
|
|
int64 = 0x7FFFFFFFFFFFFFFF
|
|
grid = gen_grid_for_id(int64)
|
|
eq_(grid.get_pixel(128,128),int64)
|
|
utf1 = grid.encode('utf',resolution=4)
|
|
eq_(utf1['keys'],[str(int64)])
|
|
max_neg = -(int64)
|
|
grid = gen_grid_for_id(max_neg)
|
|
eq_(grid.get_pixel(128,128),max_neg)
|
|
utf1 = grid.encode('utf',resolution=4)
|
|
eq_(utf1['keys'],[str(max_neg)])
|
|
|
|
def test_id_zero():
|
|
grid = gen_grid_for_id(0)
|
|
eq_(grid.get_pixel(128,128),0)
|
|
utf1 = grid.encode('utf',resolution=4)
|
|
eq_(utf1['keys'],['0'])
|
|
|
|
line_expected = {"keys": ["", "1"], "data": {"1": {"Name": "1"}}, "grid": [" !", " !! ", " !! ", " !! ", " !! ", " !! ", " !! ", " !! ", " !! ", " !! ", " !! ", " !! ", " !! ", " !! ", " !! ", " !! ", " !! ", " !! ", " !! ", " !! ", " !! ", "!! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! "]}
|
|
|
|
def test_line_rendering():
|
|
ds = mapnik.MemoryDatasource()
|
|
context = mapnik.Context()
|
|
context.push('Name')
|
|
pixel_key = 1
|
|
f = mapnik.Feature(context,pixel_key)
|
|
f['Name'] = str(pixel_key)
|
|
f.add_geometries_from_wkt('LINESTRING (30 10, 10 30, 40 40)')
|
|
ds.add_feature(f)
|
|
s = mapnik.Style()
|
|
r = mapnik.Rule()
|
|
symb = mapnik.LineSymbolizer()
|
|
r.symbols.append(symb)
|
|
s.rules.append(r)
|
|
lyr = mapnik.Layer('Places')
|
|
lyr.datasource = ds
|
|
lyr.styles.append('places_labels')
|
|
width,height = 256,256
|
|
m = mapnik.Map(width,height)
|
|
m.append_style('places_labels',s)
|
|
m.layers.append(lyr)
|
|
m.zoom_all()
|
|
#mapnik.render_to_file(m,'test.png')
|
|
grid = mapnik.Grid(m.width,m.height,key='__id__')
|
|
mapnik.render_layer(m,grid,layer=0,fields=['Name'])
|
|
utf1 = grid.encode()
|
|
eq_(utf1,line_expected,show_grids('line',utf1,line_expected))
|
|
|
|
point_expected = {"data": {"1": {"Name": "South East"}, "2": {"Name": "South West"}, "3": {"Name": "North West"}, "4": {"Name": "North East"}}, "grid": [" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " !!!! #### ", " !!!! #### ", " !!!! #### ", " !!!! #### ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " $$$$ %%%% ", " $$$$ %%%% ", " $$$$ %%%% ", " $$$$ %%%% ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "], "keys": ["", "3", "4", "2", "1"]}
|
|
|
|
def test_point_symbolizer_grid():
|
|
width,height = 256,256
|
|
sym = mapnik.PointSymbolizer()
|
|
sym.file = '../data/images/dummy.png'
|
|
m = create_grid_map(width,height,sym)
|
|
ul_lonlat = mapnik.Coord(142.30,-38.20)
|
|
lr_lonlat = mapnik.Coord(143.40,-38.80)
|
|
m.zoom_to_box(mapnik.Box2d(ul_lonlat,lr_lonlat))
|
|
grid = mapnik.Grid(m.width,m.height)
|
|
mapnik.render_layer(m,grid,layer=0,fields=['Name'])
|
|
utf1 = grid.encode()
|
|
eq_(utf1,point_expected,show_grids('point-sym',utf1,point_expected))
|
|
|
|
|
|
# should throw because this is a mis-usage
|
|
# https://github.com/mapnik/mapnik/issues/1325
|
|
@raises(RuntimeError)
|
|
def test_render_to_grid_multiple_times():
|
|
# create map with two layers
|
|
m = mapnik.Map(256,256)
|
|
s = mapnik.Style()
|
|
r = mapnik.Rule()
|
|
sym = mapnik.MarkersSymbolizer()
|
|
sym.allow_overlap = True
|
|
r.symbols.append(sym)
|
|
s.rules.append(r)
|
|
m.append_style('points',s)
|
|
|
|
# NOTE: we use a csv datasource here
|
|
# because the memorydatasource fails silently for
|
|
# queries requesting fields that do not exist in the datasource
|
|
ds1 = mapnik.Datasource(**{"type":"csv","inline":'''
|
|
wkt,Name
|
|
"POINT (143.10 -38.60)",South East'''})
|
|
lyr1 = mapnik.Layer('One')
|
|
lyr1.datasource = ds1
|
|
lyr1.styles.append('points')
|
|
m.layers.append(lyr1)
|
|
|
|
ds2 = mapnik.Datasource(**{"type":"csv","inline":'''
|
|
wkt,Value
|
|
"POINT (142.48 -38.60)",South West'''})
|
|
lyr2 = mapnik.Layer('Two')
|
|
lyr2.datasource = ds2
|
|
lyr2.styles.append('points')
|
|
m.layers.append(lyr2)
|
|
|
|
ul_lonlat = mapnik.Coord(142.30,-38.20)
|
|
lr_lonlat = mapnik.Coord(143.40,-38.80)
|
|
m.zoom_to_box(mapnik.Box2d(ul_lonlat,lr_lonlat))
|
|
grid = mapnik.Grid(m.width,m.height)
|
|
mapnik.render_layer(m,grid,layer=0,fields=['Name'])
|
|
# should throw right here since Name will be a property now on the `grid` object
|
|
# and it is not found on the second layer
|
|
mapnik.render_layer(m,grid,layer=1,fields=['Value'])
|
|
grid.encode()
|
|
|
|
if __name__ == "__main__":
|
|
setup()
|
|
exit(run_all(eval(x) for x in dir() if x.startswith("test_")))
|