From 7fbc254673e9e401d1e05df9360f94c54ffe4941 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Wed, 11 Feb 2015 15:52:36 -0800 Subject: [PATCH 01/14] fix polygon_clipper to work with vertex_adapter --- include/mapnik/polygon_clipper.hpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/include/mapnik/polygon_clipper.hpp b/include/mapnik/polygon_clipper.hpp index 91f467051..9ef2f01a7 100644 --- a/include/mapnik/polygon_clipper.hpp +++ b/include/mapnik/polygon_clipper.hpp @@ -67,7 +67,9 @@ struct polygon_clipper polygon_clipper(box2d const& clip_box, Geometry & geom) :state_(clip), clip_box_(clip_box), - geom_(geom) + geom_(geom), + output_(), + output_adapter_(output_) { init(); } @@ -86,7 +88,7 @@ struct polygon_clipper void rewind(unsigned path_id) { - if (state_ == clip) output_.rewind(path_id); + if (state_ == clip) output_adapter_.rewind(path_id); else geom_.rewind(path_id); } @@ -95,7 +97,7 @@ struct polygon_clipper switch (state_) { case clip: - return output_.vertex(x,y); + return output_adapter_.vertex(x,y); case no_clip: return geom_.vertex(x,y); case ignore: @@ -230,6 +232,7 @@ private: box2d clip_box_; Geometry & geom_; mapnik::geometry_type output_; + mapnik::vertex_adapter output_adapter_; }; From 216d1e9324c02ea7626bd19e79c65cb01dd61a2b Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Wed, 11 Feb 2015 15:53:09 -0800 Subject: [PATCH 02/14] adapt clipping benchmark to vertex_adapter interface - refs #2688 --- benchmark/build.py | 2 +- benchmark/data/polygon_clipping_agg.png | Bin 4991 -> 8884 bytes benchmark/data/polygon_clipping_boost.png | Bin 4991 -> 8884 bytes benchmark/data/polygon_clipping_clipper.png | Bin 5029 -> 8803 bytes benchmark/test_polygon_clipping.cpp | 67 +++++++++++--------- 5 files changed, 39 insertions(+), 30 deletions(-) diff --git a/benchmark/build.py b/benchmark/build.py index 3b5ff20da..4c62f1825 100644 --- a/benchmark/build.py +++ b/benchmark/build.py @@ -34,7 +34,7 @@ benchmarks = [ #"test_to_double.cpp", #"test_to_int.cpp", #"test_utf_encoding.cpp" - #"test_polygon_clipping.cpp", + "test_polygon_clipping.cpp", #"test_polygon_clipping_rendering.cpp", "test_proj_transform1.cpp", "test_expression_parse.cpp", diff --git a/benchmark/data/polygon_clipping_agg.png b/benchmark/data/polygon_clipping_agg.png index 34709aba37981e0827a34d10abd298f49e09ac04..6c38b39f7a1d6eed6b906006bed527f63ae39a02 100644 GIT binary patch literal 8884 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 literal 4991 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 diff --git a/benchmark/data/polygon_clipping_boost.png b/benchmark/data/polygon_clipping_boost.png index 34709aba37981e0827a34d10abd298f49e09ac04..6c38b39f7a1d6eed6b906006bed527f63ae39a02 100644 GIT binary patch literal 8884 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 literal 4991 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 diff --git a/benchmark/data/polygon_clipping_clipper.png b/benchmark/data/polygon_clipping_clipper.png index a52fd50d93fad3f3c7e11980785f299e7a5c8672..8d1b11e9c28de5c8539e3617c58cbb49ec41a051 100644 GIT binary patch literal 8803 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 iBpMrx_t@>n0|ss=vrjR>z| literal 5029 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

j4!m`Kb_W4i~s@>6$|9LYxjtIo6pFC!QQ zUciAj_Sgr6vtRu~C^ieUB7Rb>NCN$)W4M)a^-1oJK5e^BnLxQbXec-d)D#j#5*al- zSJecGro#jT7&e+p#=VERssN5)%^4jX9UmVX zGbv_dtQnq}IbK>iIGCH;SzSFjnVGp$Wg~s<_0IkBdnck9LMcH%th5C8nM~6{PPoUY z8uzlq;jmD!IAFD9Ar)Ty2=c~B*+cToN5F4fT+P>w#+btJM|Um3ZET4lB|jWC1`=g- zA2nKAg0ECK)S7ya{82Z9rA&#~E%N%zu|BzP&%jug$G6W!MU=dTz4lSIyA7eQ`4bjt zO!Dj12E=_8J*>2Hb4S$xt9OJGrI`bY`5dnrF#b*%o8vO5NGtF;@#ZT_?vSoI5IfZJ zw!O+PpVw2eaI(^B2k~Y5%{T&@Fj~v}QS1ppB2o*dC>8X$T&bThr{?9^YQgit92yVW zqroxglu}b#`SYH#s&|N`&XM7=zM2JQIYx&3H z`_5HPTFJf7ynez%M-ielMFhwH>6q)U%pN(49zI^0TRpkcaA-LG5K>3`enMKA(?q&5 zbYk@CdESMumA>cW=O(tR;nG0O$kEc;59!k~6T@j#v`(nZvB2d2KV1C diff --git a/benchmark/test_polygon_clipping.cpp b/benchmark/test_polygon_clipping.cpp index 9b6184b0c..ac2f34094 100644 --- a/benchmark/test_polygon_clipping.cpp +++ b/benchmark/test_polygon_clipping.cpp @@ -29,14 +29,16 @@ // stl #include +#include -void render(mapnik::geometry_type & geom, +void render(mapnik::geometry_type const& geom, mapnik::box2d const& extent, std::string const& name) { - using path_type = mapnik::transform_path_adapter; + using path_type = mapnik::transform_path_adapter; using ren_base = agg::renderer_base; using renderer = agg::renderer_scanline_aa_solid; + mapnik::vertex_adapter va(geom); mapnik::image_32 im(256,256); im.set_background(mapnik::color("white")); mapnik::box2d padded_extent = extent; @@ -49,13 +51,11 @@ void render(mapnik::geometry_type & geom, ren.color(agg::rgba8(127,127,127,255)); agg::rasterizer_scanline_aa<> ras; mapnik::proj_transform prj_trans(mapnik::projection("+init=epsg:4326"),mapnik::projection("+init=epsg:4326")); - geom.rewind(0); - path_type path(tr,geom,prj_trans); + path_type path(tr,va,prj_trans); ras.add_path(path); agg::scanline_u8 sl; agg::render_scanlines(ras, sl, ren); mapnik::save_to_file(im.data(),name); - geom.rewind(0); } class test1 : public benchmark::test_case @@ -64,7 +64,7 @@ class test1 : public benchmark::test_case mapnik::box2d extent_; std::string expected_; public: - using conv_clip = agg::conv_clip_polygon; + using conv_clip = agg::conv_clip_polygon; test1(mapnik::parameters const& params, std::string const& wkt_in, mapnik::box2d const& extent) @@ -85,8 +85,9 @@ public: std::clog << "paths.size() != 1\n"; return false; } - mapnik::geometry_type & geom = paths[0]; - conv_clip clipped(geom); + mapnik::geometry_type const& geom = paths[0]; + mapnik::vertex_adapter va(geom); + conv_clip clipped(va); clipped.clip_box( extent_.minx(), extent_.miny(), @@ -100,12 +101,13 @@ public: } std::string expect = expected_+".png"; std::string actual = expected_+"_actual.png"; - if (!mapnik::util::exists(expect)) + auto env = mapnik::envelope(geom); + if (!mapnik::util::exists(expect) || (std::getenv("UPDATE") != nullptr)) { std::clog << "generating expected image: " << expect << "\n"; - render(geom2,geom.envelope(),expect); + render(geom2,env,expect); } - render(geom2,geom.envelope(),actual); + render(geom2,env,actual); return benchmark::compare_images(actual,expect); } bool operator()() const @@ -117,9 +119,10 @@ public: } for (unsigned i=0;i extent_; std::string expected_; public: - using poly_clipper = agg::conv_clipper; + using poly_clipper = agg::conv_clipper; test2(mapnik::parameters const& params, std::string const& wkt_in, mapnik::box2d const& extent) @@ -167,8 +170,9 @@ public: std::clog << "paths.size() != 1\n"; return false; } - mapnik::geometry_type & geom = paths[0]; - poly_clipper clipped(geom,ps, + mapnik::geometry_type const& geom = paths[0]; + mapnik::vertex_adapter va(geom); + poly_clipper clipped(va,ps, agg::clipper_and, agg::clipper_non_zero, agg::clipper_non_zero, @@ -182,12 +186,13 @@ public: } std::string expect = expected_+".png"; std::string actual = expected_+"_actual.png"; - if (!mapnik::util::exists(expect)) + auto env = mapnik::envelope(geom); + if (!mapnik::util::exists(expect) || (std::getenv("UPDATE") != nullptr)) { std::clog << "generating expected image: " << expect << "\n"; - render(geom2,geom.envelope(),expect); + render(geom2,env,expect); } - render(geom2,geom.envelope(),actual); + render(geom2,env,actual); return benchmark::compare_images(actual,expect); } bool operator()() const @@ -205,9 +210,10 @@ public: ps.close_polygon(); for (unsigned i=0;i extent_; std::string expected_; public: - using poly_clipper = mapnik::polygon_clipper; + using poly_clipper = mapnik::polygon_clipper; test3(mapnik::parameters const& params, std::string const& wkt_in, mapnik::box2d const& extent) @@ -249,8 +255,9 @@ public: std::clog << "paths.size() != 1\n"; return false; } - mapnik::geometry_type & geom = paths[0]; - poly_clipper clipped(extent_, geom); + mapnik::geometry_type const& geom = paths[0]; + mapnik::vertex_adapter va(geom); + poly_clipper clipped(extent_, va); unsigned cmd; double x,y; mapnik::geometry_type geom2(mapnik::geometry_type::types::Polygon); @@ -259,12 +266,13 @@ public: } std::string expect = expected_+".png"; std::string actual = expected_+"_actual.png"; - if (!mapnik::util::exists(expect)) + auto env = mapnik::envelope(geom); + if (!mapnik::util::exists(expect) || (std::getenv("UPDATE") != nullptr)) { std::clog << "generating expected image: " << expect << "\n"; - render(geom2,geom.envelope(),expect); + render(geom2,env,expect); } - render(geom2,geom.envelope(),actual); + render(geom2,env,actual); return benchmark::compare_images(actual,expect); } bool operator()() const @@ -276,9 +284,10 @@ public: } for (unsigned i=0;i Date: Wed, 11 Feb 2015 22:42:31 -0800 Subject: [PATCH 03/14] further validate results of clipping tests --- benchmark/test_polygon_clipping.cpp | 38 ++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/benchmark/test_polygon_clipping.cpp b/benchmark/test_polygon_clipping.cpp index ac2f34094..7c7626a0e 100644 --- a/benchmark/test_polygon_clipping.cpp +++ b/benchmark/test_polygon_clipping.cpp @@ -29,6 +29,7 @@ // stl #include +#include #include void render(mapnik::geometry_type const& geom, @@ -117,6 +118,7 @@ public: { throw std::runtime_error("Failed to parse WKT"); } + unsigned count = 0; for (unsigned i=0;i Date: Wed, 11 Feb 2015 23:13:59 -0800 Subject: [PATCH 04/14] json error handler: fix -Wunused-parameter warning --- include/mapnik/json/error_handler.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mapnik/json/error_handler.hpp b/include/mapnik/json/error_handler.hpp index 7432c10f0..74b0aa48d 100644 --- a/include/mapnik/json/error_handler.hpp +++ b/include/mapnik/json/error_handler.hpp @@ -34,7 +34,7 @@ struct error_handler { using result_type = void; void operator() ( - Iterator, Iterator last, + Iterator, Iterator, Iterator err_pos, boost::spirit::info const& what) const { std::stringstream s; From 81ef45b06c31e27d8a23d72a3af1df92da0a6c81 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Wed, 11 Feb 2015 23:47:26 -0800 Subject: [PATCH 05/14] fixup polygon clipping test build --- benchmark/build.py | 1 + benchmark/test_polygon_clipping.cpp | 3 --- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/benchmark/build.py b/benchmark/build.py index 4c62f1825..9b41cc748 100644 --- a/benchmark/build.py +++ b/benchmark/build.py @@ -8,6 +8,7 @@ test_env = env.Clone() test_env['LIBS'] = [env['MAPNIK_NAME']] test_env.AppendUnique(LIBS=copy(env['LIBMAPNIK_LIBS'])) +test_env.AppendUnique(LIBS='mapnik-wkt') if env['PLATFORM'] == 'Linux': test_env.AppendUnique(LIBS='dl') test_env.AppendUnique(LIBS='rt') diff --git a/benchmark/test_polygon_clipping.cpp b/benchmark/test_polygon_clipping.cpp index 7c7626a0e..0c0639f6e 100644 --- a/benchmark/test_polygon_clipping.cpp +++ b/benchmark/test_polygon_clipping.cpp @@ -1,14 +1,11 @@ #include "bench_framework.hpp" #include "compare_images.hpp" -#include "agg_conv_clip_polygon.h" #include #include #include #include #include #include -#include -#include #include #include #include From e8f397c41cb217170f333a9b2b3b0d5f72e85f2b Mon Sep 17 00:00:00 2001 From: artemp Date: Thu, 12 Feb 2015 11:51:11 +0100 Subject: [PATCH 06/14] instantiate geojson grammar using chr_iterator_type = char const* - via #2700 --- plugins/input/geojson/large_geojson_featureset.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/plugins/input/geojson/large_geojson_featureset.cpp b/plugins/input/geojson/large_geojson_featureset.cpp index 043d3fe5a..795d61944 100644 --- a/plugins/input/geojson/large_geojson_featureset.cpp +++ b/plugins/input/geojson/large_geojson_featureset.cpp @@ -23,8 +23,8 @@ // mapnik #include #include -#include -#include +#include +#include #include // stl #include @@ -62,9 +62,10 @@ mapnik::feature_ptr large_geojson_featureset::next() std::vector json; json.resize(size); std::fread(json.data(), size, 1, file_.get()); - using chr_iterator_type = std::vector::const_iterator; - chr_iterator_type start = json.begin(); - chr_iterator_type end = json.end(); + + using chr_iterator_type = char const*; + chr_iterator_type start = json.data(); + chr_iterator_type end = start + json.size(); static const mapnik::transcoder tr("utf8"); static const mapnik::json::feature_grammar grammar(tr); From bb57ebd258ec7fd8588ef16f7f38348358e7197e Mon Sep 17 00:00:00 2001 From: artemp Date: Thu, 12 Feb 2015 15:50:13 +0100 Subject: [PATCH 07/14] implement get_geometry_type() for 'large json' strategy @springmeyer - we should talk re: validity of this approach. I know the baclground but still. --- plugins/input/geojson/geojson_datasource.cpp | 68 +++++++++++++++++--- 1 file changed, 59 insertions(+), 9 deletions(-) diff --git a/plugins/input/geojson/geojson_datasource.cpp b/plugins/input/geojson/geojson_datasource.cpp index b6c6fa609..0969834e2 100644 --- a/plugins/input/geojson/geojson_datasource.cpp +++ b/plugins/input/geojson/geojson_datasource.cpp @@ -292,19 +292,69 @@ boost::optional geojson_datasource::get_geometry { boost::optional result; int multi_type = 0; - unsigned num_features = features_.size(); - for (unsigned i = 0; i < num_features && i < 5; ++i) + if (cache_features_) { - mapnik::util::to_ds_type(features_[i]->paths(),result); - if (result) + unsigned num_features = features_.size(); + for (unsigned i = 0; i < num_features && i < 5; ++i) { - int type = static_cast(*result); - if (multi_type > 0 && multi_type != type) + mapnik::util::to_ds_type(features_[i]->paths(),result); + if (result) { - result.reset(mapnik::datasource::Collection); - return result; + int type = static_cast(*result); + if (multi_type > 0 && multi_type != type) + { + result.reset(mapnik::datasource::Collection); + return result; + } + multi_type = type; + } + } + } + else + { + mapnik::util::file file(filename_); + if (!file.open()) + { + throw mapnik::datasource_exception("GeoJSON Plugin: could not open: '" + filename_ + "'"); + } + auto itr = tree_->qbegin(boost::geometry::index::intersects(extent_)); + auto end = tree_->qend(); + mapnik::context_ptr ctx = std::make_shared(); + for (std::size_t count = 0; itr !=end && count < 5; ++itr,++count) + { + geojson_datasource::item_type const& item = *itr; + std::size_t file_offset = item.second.first; + std::size_t size = item.second.second; + + std::fseek(file.get(), file_offset, SEEK_SET); + std::vector json; + json.resize(size); + std::fread(json.data(), size, 1, file.get()); + + using chr_iterator_type = char const*; + chr_iterator_type start = json.data(); + chr_iterator_type end = start + json.size(); + + static const mapnik::transcoder tr("utf8"); + static const mapnik::json::feature_grammar grammar(tr); + using namespace boost::spirit; + ascii::space_type space; + mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx,1)); + if (!qi::phrase_parse(start, end, (grammar)(boost::phoenix::ref(*feature)), space)) + { + throw std::runtime_error("Failed to parse geojson feature"); + } + mapnik::util::to_ds_type(feature->paths(),result); + if (result) + { + int type = static_cast(*result); + if (multi_type > 0 && multi_type != type) + { + result.reset(mapnik::datasource::Collection); + return result; + } + multi_type = type; } - multi_type = type; } } return result; From 3aaac077cb21dcc040ef32c41f350e310c8a28a6 Mon Sep 17 00:00:00 2001 From: artemp Date: Thu, 12 Feb 2015 15:53:29 +0100 Subject: [PATCH 08/14] add test_large_geojson_properties --- tests/python_tests/geojson_plugin_test.py | 32 +++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/tests/python_tests/geojson_plugin_test.py b/tests/python_tests/geojson_plugin_test.py index 6609f082d..a2834fe93 100644 --- a/tests/python_tests/geojson_plugin_test.py +++ b/tests/python_tests/geojson_plugin_test.py @@ -52,6 +52,38 @@ if 'geojson' in mapnik.DatasourceCache.plugin_names(): eq_(f['NOM_FR'], u'Qu\xe9bec') eq_(f['NOM_FR'], u'Québec') + def test_large_geojson_properties(): + ds = mapnik.Datasource(type='geojson',file='../data/json/escaped.geojson',cache_features = False) + f = ds.features_at_point(ds.envelope().center()).features[0] + eq_(len(ds.fields()),9) + desc = ds.describe() + eq_(desc['geometry_type'],mapnik.DataGeometryType.Point) + + eq_(f['name'], u'Test') + eq_(f['int'], 1) + eq_(f['description'], u'Test: \u005C') + eq_(f['spaces'], u'this has spaces') + eq_(f['double'], 1.1) + eq_(f['boolean'], True) + eq_(f['NOM_FR'], u'Qu\xe9bec') + eq_(f['NOM_FR'], u'Québec') + + ds = mapnik.Datasource(type='geojson',file='../data/json/escaped.geojson') + f = ds.all_features()[0] + eq_(len(ds.fields()),9) + + desc = ds.describe() + eq_(desc['geometry_type'],mapnik.DataGeometryType.Point) + + eq_(f['name'], u'Test') + eq_(f['int'], 1) + eq_(f['description'], u'Test: \u005C') + eq_(f['spaces'], u'this has spaces') + eq_(f['double'], 1.1) + eq_(f['boolean'], True) + eq_(f['NOM_FR'], u'Qu\xe9bec') + eq_(f['NOM_FR'], u'Québec') + def test_geojson_from_in_memory_string(): # will silently fail since it is a geometry and needs to be a featurecollection. #ds = mapnik.Datasource(type='geojson',inline='{"type":"LineString","coordinates":[[0,0],[10,10]]}') From df60a2f37f1a052fef6672f20c629d5ae71262e8 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 12 Feb 2015 11:37:46 -0800 Subject: [PATCH 09/14] more tests for object stringify in geojson plugin - refs #2678 --- tests/python_tests/geojson_plugin_test.py | 28 +++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/python_tests/geojson_plugin_test.py b/tests/python_tests/geojson_plugin_test.py index a2834fe93..2732e3429 100644 --- a/tests/python_tests/geojson_plugin_test.py +++ b/tests/python_tests/geojson_plugin_test.py @@ -4,6 +4,10 @@ from nose.tools import eq_,assert_almost_equal 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 @@ -35,6 +39,12 @@ if 'geojson' in mapnik.DatasourceCache.plugin_names(): eq_(f['boolean'], True) eq_(f['NOM_FR'], u'Qu\xe9bec') eq_(f['NOM_FR'], u'Québec') + eq_(f['array'], u'[[[1],["deux"]],[["\\u0442\\u0440\\u0438","four","\\u4e94"]]]') + array = json.loads(f['array']) + eq_(array,[[[1], [u'deux']], [[u'\u0442\u0440\u0438', u'four', u'\u4e94']]]) + eq_(f['object'], u'{"value":{"type":"\\u041c\\u0430pni\\u043a","array":[3,0,"x"]}}') + object = json.loads(f['object']) + eq_(object,{u'value': {u'array': [3, 0, u'x'], u'type': u'\u041c\u0430pni\u043a'}}) ds = mapnik.Datasource(type='geojson',file='../data/json/escaped.geojson') f = ds.all_features()[0] @@ -51,6 +61,12 @@ if 'geojson' in mapnik.DatasourceCache.plugin_names(): eq_(f['boolean'], True) eq_(f['NOM_FR'], u'Qu\xe9bec') eq_(f['NOM_FR'], u'Québec') + eq_(f['array'], u'[[[1],["deux"]],[["\\u0442\\u0440\\u0438","four","\\u4e94"]]]') + array = json.loads(f['array']) + eq_(array,[[[1], [u'deux']], [[u'\u0442\u0440\u0438', u'four', u'\u4e94']]]) + eq_(f['object'], u'{"value":{"type":"\\u041c\\u0430pni\\u043a","array":[3,0,"x"]}}') + object = json.loads(f['object']) + eq_(object,{u'value': {u'array': [3, 0, u'x'], u'type': u'\u041c\u0430pni\u043a'}}) def test_large_geojson_properties(): ds = mapnik.Datasource(type='geojson',file='../data/json/escaped.geojson',cache_features = False) @@ -67,6 +83,12 @@ if 'geojson' in mapnik.DatasourceCache.plugin_names(): eq_(f['boolean'], True) eq_(f['NOM_FR'], u'Qu\xe9bec') eq_(f['NOM_FR'], u'Québec') + eq_(f['array'], u'[[[1],["deux"]],[["\\u0442\\u0440\\u0438","four","\\u4e94"]]]') + array = json.loads(f['array']) + eq_(array,[[[1], [u'deux']], [[u'\u0442\u0440\u0438', u'four', u'\u4e94']]]) + eq_(f['object'], u'{"value":{"type":"\\u041c\\u0430pni\\u043a","array":[3,0,"x"]}}') + object = json.loads(f['object']) + eq_(object,{u'value': {u'array': [3, 0, u'x'], u'type': u'\u041c\u0430pni\u043a'}}) ds = mapnik.Datasource(type='geojson',file='../data/json/escaped.geojson') f = ds.all_features()[0] @@ -83,6 +105,12 @@ if 'geojson' in mapnik.DatasourceCache.plugin_names(): eq_(f['boolean'], True) eq_(f['NOM_FR'], u'Qu\xe9bec') eq_(f['NOM_FR'], u'Québec') + eq_(f['array'], u'[[[1],["deux"]],[["\\u0442\\u0440\\u0438","four","\\u4e94"]]]') + array = json.loads(f['array']) + eq_(array,[[[1], [u'deux']], [[u'\u0442\u0440\u0438', u'four', u'\u4e94']]]) + eq_(f['object'], u'{"value":{"type":"\\u041c\\u0430pni\\u043a","array":[3,0,"x"]}}') + object = json.loads(f['object']) + eq_(object,{u'value': {u'array': [3, 0, u'x'], u'type': u'\u041c\u0430pni\u043a'}}) def test_geojson_from_in_memory_string(): # will silently fail since it is a geometry and needs to be a featurecollection. From 2aaaecbcaf2a69cbb5b11251541aa487230d2088 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 12 Feb 2015 11:38:31 -0800 Subject: [PATCH 10/14] initialize pos_ variable in path_iterator + fix spelling --- include/mapnik/util/path_iterator.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/mapnik/util/path_iterator.hpp b/include/mapnik/util/path_iterator.hpp index bddde5698..e805f3023 100644 --- a/include/mapnik/util/path_iterator.hpp +++ b/include/mapnik/util/path_iterator.hpp @@ -80,7 +80,7 @@ private: const path_type *vertices_; }; -// specialization for mapnik::geometry_type - vertex interfacce has been removed +// specialization for mapnik::geometry_type - vertex interface has been removed template <> class path_iterator : public boost::iterator_facade< path_iterator, @@ -95,7 +95,8 @@ public: using size_type = path_type::size_type; path_iterator() : v_(mapnik::SEG_END,0,0), - vertices_() + vertices_(), + pos_(0) {} explicit path_iterator(path_type const& vertices) From 884de5a0440d5521e4ca50177e10a6584610ffd6 Mon Sep 17 00:00:00 2001 From: artemp Date: Thu, 12 Feb 2015 22:16:04 +0100 Subject: [PATCH 11/14] fix condition for skipping M (measure) in PointZ --- utils/shapeindex/shapeindex.cpp | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/utils/shapeindex/shapeindex.cpp b/utils/shapeindex/shapeindex.cpp index 18b237a5a..dc7d79a22 100644 --- a/utils/shapeindex/shapeindex.cpp +++ b/utils/shapeindex/shapeindex.cpp @@ -192,31 +192,40 @@ int main (int argc,char** argv) double y=shp.read_double(); // skip z shp.read_double(); - //skip m if exists - if ( content_length == 8 + 36) + // According to ESRI shapefile doc + // A PointZ consists of a triplet of double-precision coordinates in the order X, Y, Z plus a + // measure. + // PointZ + // { + // Double X // X coordinate + // Double Y // Y coordinate + // Double Z // Z coordinate + // Double M // Measure + // } + // But OGR creates shapefiles with M missing so we need skip M only if present + // NOTE: content_length is in 16-bit words + if ( content_length == 18) { shp.read_double(); } item_ext=box2d(x,y,x,y); - } + } else { shp.read_envelope(item_ext); shp.skip(2*content_length-4*8-4); } - tree.insert(offset,item_ext); - if (verbose) { + if (verbose) + { clog << "record number " << record_number << " box=" << item_ext << endl; } pos+=4+content_length; ++count; - if (pos>=file_length) { - break; - } + if (pos >= file_length) break; } clog << " number shapes=" << count << endl; From 5424c350cd487fee24888093047ed5f73ee01d62 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Fri, 13 Feb 2015 00:04:09 -0800 Subject: [PATCH 12/14] avoid inf loop on empty point3d shapefile --- utils/shapeindex/shapeindex.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/utils/shapeindex/shapeindex.cpp b/utils/shapeindex/shapeindex.cpp index dc7d79a22..d92eba019 100644 --- a/utils/shapeindex/shapeindex.cpp +++ b/utils/shapeindex/shapeindex.cpp @@ -165,17 +165,23 @@ int main (int argc,char** argv) box2d item_ext; if (shape_type==shape_io::shape_null) { - // still need to increment pos, or the pos counter - // won't indicate EOF until too late. - pos+=4+content_length; - continue; + if (pos >= file_length) + { + break; + } + else + { + // still need to increment pos, or the pos counter + // won't indicate EOF until too late. + pos+=4+content_length; + continue; + } } else if (shape_type==shape_io::shape_point) { double x=shp.read_double(); double y=shp.read_double(); item_ext=box2d(x,y,x,y); - } else if (shape_type==shape_io::shape_pointm) { @@ -184,7 +190,6 @@ int main (int argc,char** argv) // skip m shp.read_double(); item_ext=box2d(x,y,x,y); - } else if (shape_type==shape_io::shape_pointz) { @@ -209,7 +214,6 @@ int main (int argc,char** argv) shp.read_double(); } item_ext=box2d(x,y,x,y); - } else { From 54dc9dd0f34a30e5a3b693af5ff02277c7f45147 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Fri, 13 Feb 2015 00:05:34 -0800 Subject: [PATCH 13/14] add shapeindex tests - refs #2703 --- tests/data/shp/3d_point_empty.dbf | Bin 0 -> 65 bytes tests/data/shp/3d_point_empty.prj | 1 + tests/data/shp/3d_point_empty.shp | Bin 0 -> 100 bytes tests/data/shp/3d_point_empty.shx | Bin 0 -> 100 bytes tests/python_tests/shapeindex_test.py | 51 ++++++++++++++++++++++++++ 5 files changed, 52 insertions(+) create mode 100644 tests/data/shp/3d_point_empty.dbf create mode 100644 tests/data/shp/3d_point_empty.prj create mode 100644 tests/data/shp/3d_point_empty.shp create mode 100644 tests/data/shp/3d_point_empty.shx create mode 100644 tests/python_tests/shapeindex_test.py diff --git a/tests/data/shp/3d_point_empty.dbf b/tests/data/shp/3d_point_empty.dbf new file mode 100644 index 0000000000000000000000000000000000000000..45d754f7b5cad2919c244b42d920376410fe6666 GIT binary patch literal 65 mcmZRMXP06C0!IcB5QPfD85sP7ed9e{z`}kYQW#YQ11|u8hXZ*4 literal 0 HcmV?d00001 diff --git a/tests/data/shp/3d_point_empty.prj b/tests/data/shp/3d_point_empty.prj new file mode 100644 index 000000000..6e3eaed5b --- /dev/null +++ b/tests/data/shp/3d_point_empty.prj @@ -0,0 +1 @@ +PROJCS["WGS_1984_Web_Mercator_Auxiliary_Sphere",GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.017453292519943295]],PROJECTION["Mercator_Auxiliary_Sphere"],PARAMETER["False_Easting",0.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",0.0],PARAMETER["Standard_Parallel_1",0.0],PARAMETER["Auxiliary_Sphere_Type",0.0],UNIT["Meter",1.0]] \ No newline at end of file diff --git a/tests/data/shp/3d_point_empty.shp b/tests/data/shp/3d_point_empty.shp new file mode 100644 index 0000000000000000000000000000000000000000..92815c2ece77fedf8ac258bf4f3fa1503999d56a GIT binary patch literal 100 YcmZQzQ0HR64vbzfGca&tmm^6O0A^nSS^xk5 literal 0 HcmV?d00001 diff --git a/tests/data/shp/3d_point_empty.shx b/tests/data/shp/3d_point_empty.shx new file mode 100644 index 0000000000000000000000000000000000000000..92815c2ece77fedf8ac258bf4f3fa1503999d56a GIT binary patch literal 100 YcmZQzQ0HR64vbzfGca&tmm^6O0A^nSS^xk5 literal 0 HcmV?d00001 diff --git a/tests/python_tests/shapeindex_test.py b/tests/python_tests/shapeindex_test.py new file mode 100644 index 000000000..4de19a593 --- /dev/null +++ b/tests/python_tests/shapeindex_test.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python + +from nose.tools import eq_ +from utilities import execution_path, run_all +from subprocess import Popen, PIPE +import shutil +import os +import fnmatch +import mapnik + +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('.')) + +def test_shapeindex(): + # first copy shapefiles to tmp directory + source_dir = '../data/shp/' + working_dir = '/tmp/mapnik-shp-tmp/' + if os.path.exists(working_dir): + shutil.rmtree(working_dir) + shutil.copytree(source_dir,working_dir) + matches = [] + for root, dirnames, filenames in os.walk('%s' % source_dir): + for filename in fnmatch.filter(filenames, '*.shp'): + matches.append(os.path.join(root, filename)) + for shp in matches: + source_file = os.path.join(source_dir,os.path.relpath(shp,source_dir)) + dest_file = os.path.join(working_dir,os.path.relpath(shp,source_dir)) + ds = mapnik.Shapefile(file=source_file) + count = 0; + fs = ds.featureset() + try: + while (fs.next()): + count = count+1 + except StopIteration: + pass + stdin, stderr = Popen('shapeindex %s' % dest_file, shell=True, stdout=PIPE, stderr=PIPE).communicate() + ds2 = mapnik.Shapefile(file=dest_file) + count2 = 0; + fs = ds.featureset() + try: + while (fs.next()): + count2 = count2+1 + except StopIteration: + pass + eq_(count,count2) + +if __name__ == "__main__": + setup() + exit(run_all(eval(x) for x in dir() if x.startswith("test_"))) From 1ebd6afd9cba1629261b7d7e06473f242b64819b Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Fri, 13 Feb 2015 01:26:19 -0800 Subject: [PATCH 14/14] improve sql subselect parsing + add tests - closes #2704 --- .gitignore | 1 + include/mapnik/sql_utils.hpp | 2 +- tests/cxx/sql_parse.cpp | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 tests/cxx/sql_parse.cpp diff --git a/.gitignore b/.gitignore index bbf225e80..eb3ccbd1a 100644 --- a/.gitignore +++ b/.gitignore @@ -44,3 +44,4 @@ demo/viewer/ui_about.h demo/viewer/ui_info.h demo/viewer/ui_layer_info.h tests/cpp_tests/*-bin +tests/cxx/run diff --git a/include/mapnik/sql_utils.hpp b/include/mapnik/sql_utils.hpp index ddadd21cb..f45af6ca8 100644 --- a/include/mapnik/sql_utils.hpp +++ b/include/mapnik/sql_utils.hpp @@ -73,7 +73,7 @@ namespace mapnik { namespace sql_utils { { table_name=table_name.substr(idx); } - idx = table_name.find_first_of(" )"); + idx = table_name.find_first_of(", )"); if (idx != std::string::npos) { table_name = table_name.substr(0,idx); diff --git a/tests/cxx/sql_parse.cpp b/tests/cxx/sql_parse.cpp new file mode 100644 index 000000000..43a6eb2d1 --- /dev/null +++ b/tests/cxx/sql_parse.cpp @@ -0,0 +1,33 @@ + +#include "catch.hpp" + +#include + +TEST_CASE("sql parse") { + +SECTION("table") { + std::string subquery("table"); + REQUIRE( subquery == mapnik::sql_utils::table_from_sql(subquery) ); +} + +SECTION("complex sql 1") { + std::string subquery("(select * FROM table1, table2) AS data"); + REQUIRE( "table1" == mapnik::sql_utils::table_from_sql(subquery) ); +} + +SECTION("complex sql 2") { + std::string subquery("(select * FROM table1 , table2) AS data"); + REQUIRE( "table1" == mapnik::sql_utils::table_from_sql(subquery) ); +} + +SECTION("complex sql 3") { + std::string subquery("(select * FROM table1,table2) AS data"); + REQUIRE( "table1" == mapnik::sql_utils::table_from_sql(subquery) ); +} + +SECTION("complex sql 4") { + std::string subquery("(select * FROM table1) AS data"); + REQUIRE( "table1" == mapnik::sql_utils::table_from_sql(subquery) ); +} + +}