diff --git a/CHANGELOG.md b/CHANGELOG.md index 162d4901b..278204bb0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ For a complete change history, see the git log. ## Future +- Added to python bindings: `has_tiff`, `has_png`, `has_webp`, `has_proj4`, `has_svg_renderer`, and `has_grid_renderer` + +- Made it possible to disable compilation of `grid_renderer` with `./configure GRID_RENDERER=False` (#1962) + - Added `webp` image encoding and decoding support (#1955) - Added `premultiplied` property on mapnik::image_32 / mapnik.Image to enable knowledge of premultiplied status of image buffer. diff --git a/SConstruct b/SConstruct index cf8904425..40b9ff277 100644 --- a/SConstruct +++ b/SConstruct @@ -336,6 +336,7 @@ opts.AddVariables( # Variables affecting rendering back-ends + BoolVariable('GRID_RENDERER', 'build support for native grid renderer', 'True'), BoolVariable('SVG_RENDERER', 'build support for native svg renderer', 'False'), BoolVariable('CPP_TESTS', 'Compile the C++ tests', 'True'), BoolVariable('BENCHMARK', 'Compile the C++ benchmark scripts', 'False'), @@ -447,6 +448,7 @@ pickle_store = [# Scons internal variables 'CAIRO_LIBPATHS', 'CAIRO_ALL_LIBS', 'CAIRO_CPPPATHS', + 'GRID_RENDERER', 'SVG_RENDERER', 'SQLITE_LINKFLAGS', 'BOOST_LIB_VERSION_FROM_HEADER', diff --git a/bindings/python/mapnik_grid.cpp b/bindings/python/mapnik_grid.cpp index 1118d3b4b..09b21ee3d 100644 --- a/bindings/python/mapnik_grid.cpp +++ b/bindings/python/mapnik_grid.cpp @@ -20,6 +20,8 @@ * *****************************************************************************/ +#if defined(GRID_RENDERER) + // boost #include #include @@ -80,3 +82,5 @@ void export_grid() ; } + +#endif diff --git a/bindings/python/mapnik_grid_view.cpp b/bindings/python/mapnik_grid_view.cpp index aa29dda78..5e9d2745f 100644 --- a/bindings/python/mapnik_grid_view.cpp +++ b/bindings/python/mapnik_grid_view.cpp @@ -20,6 +20,8 @@ * *****************************************************************************/ +#if defined(GRID_RENDERER) + // boost #include #include @@ -49,3 +51,5 @@ void export_grid_view() ) ; } + +#endif diff --git a/bindings/python/mapnik_python.cpp b/bindings/python/mapnik_python.cpp index 81ee0661e..1e0db91a9 100644 --- a/bindings/python/mapnik_python.cpp +++ b/bindings/python/mapnik_python.cpp @@ -41,8 +41,10 @@ void export_image(); void export_image_view(); void export_gamma_method(); void export_scaling_method(); +#if defined(GRID_RENDERER) void export_grid(); void export_grid_view(); +#endif void export_map(); void export_python(); void export_expression(); @@ -92,7 +94,9 @@ void export_logger(); #include #include #include +#if defined(GRID_RENDERER) #include "python_grid_utils.hpp" +#endif #include "mapnik_value_converter.hpp" #include "mapnik_threads.hpp" #include "python_optional.hpp" @@ -366,7 +370,33 @@ std::string mapnik_version_string() return MAPNIK_VERSION_STRING; } -// indicator for jpeg read/write support within libmapnik +bool has_proj4() +{ +#if defined(MAPNIK_USE_PROJ4) + return true; +#else + return false; +#endif +} + +bool has_svg_renderer() +{ +#if defined(SVG_RENDERER) + return true; +#else + return false; +#endif +} + +bool has_grid_renderer() +{ +#if defined(GRID_RENDERER) + return true; +#else + return false; +#endif +} + bool has_jpeg() { #if defined(HAVE_JPEG) @@ -376,6 +406,33 @@ bool has_jpeg() #endif } +bool has_png() +{ +#if defined(HAVE_PNG) + return true; +#else + return false; +#endif +} + +bool has_tiff() +{ +#if defined(HAVE_TIFF) + return true; +#else + return false; +#endif +} + +bool has_webp() +{ +#if defined(HAVE_WEBP) + return true; +#else + return false; +#endif +} + // indicator for cairo rendering support inside libmapnik bool has_cairo() { @@ -427,7 +484,6 @@ BOOST_PYTHON_MODULE(_mapnik) using mapnik::load_map_string; using mapnik::save_map; using mapnik::save_map_to_string; - using mapnik::render_grid; register_exception_translator(&standard_error_translator); register_exception_translator(&out_of_range_error_translator); @@ -448,8 +504,10 @@ BOOST_PYTHON_MODULE(_mapnik) export_image_view(); export_gamma_method(); export_scaling_method(); +#if defined(GRID_RENDERER) export_grid(); export_grid_view(); +#endif export_expression(); export_rule(); export_style(); @@ -487,7 +545,8 @@ BOOST_PYTHON_MODULE(_mapnik) ">>> clear_cache()\n" ); - def("render_grid",&render_grid, +#if defined(GRID_RENDERER) + def("render_grid",&mapnik::render_grid, ( arg("map"), arg("layer"), args("key")="__id__", @@ -495,6 +554,7 @@ BOOST_PYTHON_MODULE(_mapnik) arg("fields")=boost::python::list() ) ); +#endif def("render_to_file",&render_to_file1, "\n" @@ -579,9 +639,11 @@ BOOST_PYTHON_MODULE(_mapnik) (arg("map"),arg("image"),args("layer")) ); +#if defined(GRID_RENDERER) def("render_layer", &mapnik::render_layer_for_grid, (arg("map"),arg("grid"),args("layer"),arg("fields")=boost::python::list()) ); +#endif #if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO) def("render",&render3, @@ -739,7 +801,12 @@ BOOST_PYTHON_MODULE(_mapnik) def("save_map_to_string", &save_map_to_string, save_map_to_string_overloads()); def("mapnik_version", &mapnik_version,"Get the Mapnik version number"); def("mapnik_version_string", &mapnik_version_string,"Get the Mapnik version string"); + def("has_proj4", &has_proj4, "Get proj4 status"); def("has_jpeg", &has_jpeg, "Get jpeg read/write support status"); + def("has_png", &has_png, "Get png read/write support status"); + def("has_tiff", &has_jpeg, "Get tiff read/write support status"); + def("has_webp", &has_jpeg, "Get webp read/write support status"); + def("has_grid_renderer", &has_grid_renderer, "Get grid_renderer status"); def("has_cairo", &has_cairo, "Get cairo library status"); def("has_pycairo", &has_pycairo, "Get pycairo module status"); diff --git a/bindings/python/python_grid_utils.cpp b/bindings/python/python_grid_utils.cpp index e5bd5103e..7e9e1e52f 100644 --- a/bindings/python/python_grid_utils.cpp +++ b/bindings/python/python_grid_utils.cpp @@ -20,6 +20,8 @@ * *****************************************************************************/ +#if defined(GRID_RENDERER) + // boost #include #include @@ -472,3 +474,5 @@ boost::python::dict render_grid(mapnik::Map const& map, } } + +#endif diff --git a/include/build.py b/include/build.py index 02d3d0032..6fed90d9b 100644 --- a/include/build.py +++ b/include/build.py @@ -9,6 +9,9 @@ subdirs = ['','svg','wkt','grid','json','util','text_placements','formatting'] if env['SVG_RENDERER']: subdirs.append('svg/output') +if env['GRID_RENDERER']: + subdirs.append('grid') + if 'install' in COMMAND_LINE_TARGETS: for subdir in subdirs: pathdir = os.path.join(base,subdir,'*.hpp') diff --git a/include/mapnik/svg/svg_renderer_agg.hpp b/include/mapnik/svg/svg_renderer_agg.hpp index 326edebe0..cf76e0a99 100644 --- a/include/mapnik/svg/svg_renderer_agg.hpp +++ b/include/mapnik/svg/svg_renderer_agg.hpp @@ -27,7 +27,11 @@ #include #include #include + +#if defined(GRID_RENDERER) #include +#endif + #include // boost @@ -334,6 +338,7 @@ public: } } +#if defined(GRID_RENDERER) template void render_id(Rasterizer& ras, Scanline& sl, @@ -416,6 +421,7 @@ public: } } } +#endif private: diff --git a/src/build.py b/src/build.py index 7ffa2df54..0c91cba7f 100644 --- a/src/build.py +++ b/src/build.py @@ -292,21 +292,24 @@ if env['RUNTIME_LINK'] == "static": source += glob.glob('../deps/agg/src/' + '*.cpp') # grid backend -source += Split( - """ - grid/grid.cpp - grid/grid_renderer.cpp - grid/process_building_symbolizer.cpp - grid/process_line_pattern_symbolizer.cpp - grid/process_line_symbolizer.cpp - grid/process_markers_symbolizer.cpp - grid/process_point_symbolizer.cpp - grid/process_polygon_pattern_symbolizer.cpp - grid/process_polygon_symbolizer.cpp - grid/process_raster_symbolizer.cpp - grid/process_shield_symbolizer.cpp - grid/process_text_symbolizer.cpp - """) +if env['GRID_RENDERER']: # svg backend + source += Split( + """ + grid/grid.cpp + grid/grid_renderer.cpp + grid/process_building_symbolizer.cpp + grid/process_line_pattern_symbolizer.cpp + grid/process_line_symbolizer.cpp + grid/process_markers_symbolizer.cpp + grid/process_point_symbolizer.cpp + grid/process_polygon_pattern_symbolizer.cpp + grid/process_polygon_symbolizer.cpp + grid/process_raster_symbolizer.cpp + grid/process_shield_symbolizer.cpp + grid/process_text_symbolizer.cpp + """) + lib_env.Append(CPPDEFINES = '-DGRID_RENDERER') + libmapnik_defines.append('-DGRID_RENDERER') # https://github.com/mapnik/mapnik/issues/1438 if env['SVG_RENDERER']: # svg backend diff --git a/src/feature_style_processor.cpp b/src/feature_style_processor.cpp index 9deb275ab..fd79e13a7 100644 --- a/src/feature_style_processor.cpp +++ b/src/feature_style_processor.cpp @@ -24,8 +24,11 @@ #include #include #include + +#if defined(GRID_RENDERER) #include #include +#endif #if defined(HAVE_CAIRO) #include @@ -48,7 +51,10 @@ template class feature_style_processor >; template class feature_style_processor > >; #endif +#if defined(GRID_RENDERER) template class feature_style_processor >; +#endif + template class feature_style_processor >; } diff --git a/src/font_engine_freetype.cpp b/src/font_engine_freetype.cpp index 78db9f24a..f9b2f84e0 100644 --- a/src/font_engine_freetype.cpp +++ b/src/font_engine_freetype.cpp @@ -25,7 +25,11 @@ #include #include #include + +#if defined(GRID_RENDERER) #include +#endif + #include #include #include @@ -686,6 +690,7 @@ void text_renderer::render(pixel_position const& pos) } } +#if defined(GRID_RENDERER) template void text_renderer::render_id(mapnik::value_integer feature_id, pixel_position const& pos) @@ -715,6 +720,7 @@ void text_renderer::render_id(mapnik::value_integer feature_id, } } } +#endif #ifdef MAPNIK_THREADSAFE boost::mutex freetype_engine::mutex_; @@ -729,6 +735,7 @@ template text_renderer::text_renderer(image_32&, double); template box2dtext_renderer::prepare_glyphs(text_path const&); template void text_renderer::render(pixel_position const&); +#if defined(GRID_RENDERER) template void text_renderer::render_id(mapnik::value_integer, pixel_position const&); template text_renderer::text_renderer(grid&, @@ -736,4 +743,5 @@ template text_renderer::text_renderer(grid&, halo_rasterizer_e, composite_mode_e, double); template box2dtext_renderer::prepare_glyphs(text_path const& ); +#endif } diff --git a/tests/python_tests/buffer_clear_test.py b/tests/python_tests/buffer_clear_test.py index 2119d6d63..7a828f8ca 100644 --- a/tests/python_tests/buffer_clear_test.py +++ b/tests/python_tests/buffer_clear_test.py @@ -45,18 +45,18 @@ def make_map(): m.zoom_all() return m -def test_clearing_grid_data(): - g = mapnik.Grid(256,256) - utf = g.encode() - # make sure it equals itself - eq_(g.encode(),utf) - m = make_map() - mapnik.render_layer(m,g,layer=0,fields=['__id__','Name']) - eq_(g.encode()!=utf,True) - # clear grid, should now match original - g.clear() - eq_(g.encode(),utf) - +if mapnik.has_grid_renderer(): + def test_clearing_grid_data(): + g = mapnik.Grid(256,256) + utf = g.encode() + # make sure it equals itself + eq_(g.encode(),utf) + m = make_map() + mapnik.render_layer(m,g,layer=0,fields=['__id__','Name']) + eq_(g.encode()!=utf,True) + # clear grid, should now match original + g.clear() + eq_(g.encode(),utf) if __name__ == "__main__": setup() diff --git a/tests/python_tests/render_grid_test.py b/tests/python_tests/render_grid_test.py index f998735c0..ca0996707 100644 --- a/tests/python_tests/render_grid_test.py +++ b/tests/python_tests/render_grid_test.py @@ -15,370 +15,371 @@ def setup(): # from another directory we need to chdir() os.chdir(execution_path('.')) -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 - -# first pass impl where resolution is passed as render -# time rather than encoding time, likely will be deprecated soon -grid_correct_old = {"keys": ["", "North West", "North East", "South West", "South East"], "data": {"South East": {"Name": "South East"}, "North East": {"Name": "North East"}, "North West": {"Name": "North West"}, "South West": {"Name": "South West"}}, "grid": [" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " !!! ### ", " !!!!! ##### ", " !!!!! ##### ", " !!! ### ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " $$$$ %%%% ", " $$$$$ %%%%% ", " $$$$$ %%%%% ", " $$$ %%% ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "]} - -# now using svg rendering -grid_correct_old2 = {"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_old3 = {"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"]} - -# 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_old(): - """ test old method """ - width,height = 256,256 - symb = mapnik.PointSymbolizer(mapnik.PathExpression('../data/images/dummy.png')) - sym = mapnik.MarkersSymbolizer() - sym.width = mapnik.Expression('10') - sym.height = mapnik.Expression('10') - m = create_grid_map(width,height,sym) - #print mapnik.save_map_to_string(m) - 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.render_grid(m,0,key='Name',resolution=4,fields=['Name']) - eq_(grid,grid_correct_old3,show_grids('old-markers',grid,grid_correct_old3)) - eq_(resolve(grid,0,0),None) - - # check every pixel of the nw symbol - expected = {"Name": "North West"} - - # top row - eq_(resolve(grid,23,9),expected) - eq_(resolve(grid,23,10),expected) - eq_(resolve(grid,23,11),expected) - -def test_render_grid_new(): - """ test old against new""" - 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(mapnik.PathExpression('../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']) - utf1 = grid.encode() +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 + + # first pass impl where resolution is passed as render + # time rather than encoding time, likely will be deprecated soon + grid_correct_old = {"keys": ["", "North West", "North East", "South West", "South East"], "data": {"South East": {"Name": "South East"}, "North East": {"Name": "North East"}, "North West": {"Name": "North West"}, "South West": {"Name": "South West"}}, "grid": [" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " !!! ### ", " !!!!! ##### ", " !!!!! ##### ", " !!! ### ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " $$$$ %%%% ", " $$$$$ %%%%% ", " $$$$$ %%%%% ", " $$$ %%% ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "]} + + # now using svg rendering + grid_correct_old2 = {"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_old3 = {"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"]} + + # 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_old(): + """ test old method """ + width,height = 256,256 + symb = mapnik.PointSymbolizer(mapnik.PathExpression('../data/images/dummy.png')) + sym = mapnik.MarkersSymbolizer() + sym.width = mapnik.Expression('10') + sym.height = mapnik.Expression('10') + m = create_grid_map(width,height,sym) + #print mapnik.save_map_to_string(m) + 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.render_grid(m,0,key='Name',resolution=4,fields=['Name']) + eq_(grid,grid_correct_old3,show_grids('old-markers',grid,grid_correct_old3)) + eq_(resolve(grid,0,0),None) + + # check every pixel of the nw symbol + expected = {"Name": "North West"} + + # top row + eq_(resolve(grid,23,9),expected) + eq_(resolve(grid,23,10),expected) + eq_(resolve(grid,23,11),expected) + + def test_render_grid_new(): + """ test old against new""" + 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(mapnik.PathExpression('../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']) + utf1 = grid.encode() if __name__ == "__main__": setup() diff --git a/tests/visual_tests/test.py b/tests/visual_tests/test.py index 2be5c0bca..31072c4f1 100755 --- a/tests/visual_tests/test.py +++ b/tests/visual_tests/test.py @@ -21,7 +21,7 @@ defaults = { 'scales':[1.0,2.0], 'agg': True, 'cairo': mapnik.has_cairo(), - 'grid': True + 'grid': mapnik.has_grid_renderer() } cairo_threshold = 10