Merge branch 'master' into release/image_data_Any
Conflicts: benchmark/test_polygon_clipping.cpp
This commit is contained in:
commit
b2c1c86d99
20 changed files with 321 additions and 74 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -45,3 +45,4 @@ demo/viewer/ui_about.h
|
||||||
demo/viewer/ui_info.h
|
demo/viewer/ui_info.h
|
||||||
demo/viewer/ui_layer_info.h
|
demo/viewer/ui_layer_info.h
|
||||||
tests/cpp_tests/*-bin
|
tests/cpp_tests/*-bin
|
||||||
|
tests/cxx/run
|
||||||
|
|
|
@ -8,6 +8,7 @@ test_env = env.Clone()
|
||||||
|
|
||||||
test_env['LIBS'] = [env['MAPNIK_NAME']]
|
test_env['LIBS'] = [env['MAPNIK_NAME']]
|
||||||
test_env.AppendUnique(LIBS=copy(env['LIBMAPNIK_LIBS']))
|
test_env.AppendUnique(LIBS=copy(env['LIBMAPNIK_LIBS']))
|
||||||
|
test_env.AppendUnique(LIBS='mapnik-wkt')
|
||||||
if env['PLATFORM'] == 'Linux':
|
if env['PLATFORM'] == 'Linux':
|
||||||
test_env.AppendUnique(LIBS='dl')
|
test_env.AppendUnique(LIBS='dl')
|
||||||
test_env.AppendUnique(LIBS='rt')
|
test_env.AppendUnique(LIBS='rt')
|
||||||
|
@ -34,7 +35,7 @@ benchmarks = [
|
||||||
#"test_to_double.cpp",
|
#"test_to_double.cpp",
|
||||||
#"test_to_int.cpp",
|
#"test_to_int.cpp",
|
||||||
#"test_utf_encoding.cpp"
|
#"test_utf_encoding.cpp"
|
||||||
#"test_polygon_clipping.cpp",
|
"test_polygon_clipping.cpp",
|
||||||
#"test_polygon_clipping_rendering.cpp",
|
#"test_polygon_clipping_rendering.cpp",
|
||||||
"test_proj_transform1.cpp",
|
"test_proj_transform1.cpp",
|
||||||
"test_expression_parse.cpp",
|
"test_expression_parse.cpp",
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 8.7 KiB |
Binary file not shown.
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 8.7 KiB |
Binary file not shown.
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 8.6 KiB |
|
@ -1,13 +1,10 @@
|
||||||
#include "bench_framework.hpp"
|
#include "bench_framework.hpp"
|
||||||
#include "compare_images.hpp"
|
#include "compare_images.hpp"
|
||||||
#include "agg_conv_clip_polygon.h"
|
|
||||||
#include <mapnik/geometry.hpp>
|
#include <mapnik/geometry.hpp>
|
||||||
#include <mapnik/vertex.hpp>
|
#include <mapnik/vertex.hpp>
|
||||||
#include <mapnik/transform_path_adapter.hpp>
|
#include <mapnik/transform_path_adapter.hpp>
|
||||||
#include <mapnik/view_transform.hpp>
|
#include <mapnik/view_transform.hpp>
|
||||||
#include <mapnik/wkt/wkt_factory.hpp>
|
#include <mapnik/wkt/wkt_factory.hpp>
|
||||||
#include <mapnik/wkt/wkt_grammar_impl.hpp>
|
|
||||||
#include <mapnik/geometry.hpp>
|
|
||||||
#include <mapnik/projection.hpp>
|
#include <mapnik/projection.hpp>
|
||||||
#include <mapnik/proj_transform.hpp>
|
#include <mapnik/proj_transform.hpp>
|
||||||
#include <mapnik/util/fs.hpp>
|
#include <mapnik/util/fs.hpp>
|
||||||
|
@ -28,14 +25,17 @@
|
||||||
|
|
||||||
// stl
|
// stl
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
void render(mapnik::geometry_type & geom,
|
void render(mapnik::geometry_type const& geom,
|
||||||
mapnik::box2d<double> const& extent,
|
mapnik::box2d<double> const& extent,
|
||||||
std::string const& name)
|
std::string const& name)
|
||||||
{
|
{
|
||||||
using path_type = mapnik::transform_path_adapter<mapnik::view_transform,mapnik::geometry_type>;
|
using path_type = mapnik::transform_path_adapter<mapnik::view_transform,mapnik::vertex_adapter>;
|
||||||
using ren_base = agg::renderer_base<agg::pixfmt_rgba32_plain>;
|
using ren_base = agg::renderer_base<agg::pixfmt_rgba32_plain>;
|
||||||
using renderer = agg::renderer_scanline_aa_solid<ren_base>;
|
using renderer = agg::renderer_scanline_aa_solid<ren_base>;
|
||||||
|
mapnik::vertex_adapter va(geom);
|
||||||
mapnik::image_rgba8 im(256,256);
|
mapnik::image_rgba8 im(256,256);
|
||||||
mapnik::fill(im, mapnik::color("white"));
|
mapnik::fill(im, mapnik::color("white"));
|
||||||
mapnik::box2d<double> padded_extent = extent;
|
mapnik::box2d<double> padded_extent = extent;
|
||||||
|
@ -48,13 +48,11 @@ void render(mapnik::geometry_type & geom,
|
||||||
ren.color(agg::rgba8(127,127,127,255));
|
ren.color(agg::rgba8(127,127,127,255));
|
||||||
agg::rasterizer_scanline_aa<> ras;
|
agg::rasterizer_scanline_aa<> ras;
|
||||||
mapnik::proj_transform prj_trans(mapnik::projection("+init=epsg:4326"),mapnik::projection("+init=epsg:4326"));
|
mapnik::proj_transform prj_trans(mapnik::projection("+init=epsg:4326"),mapnik::projection("+init=epsg:4326"));
|
||||||
geom.rewind(0);
|
path_type path(tr,va,prj_trans);
|
||||||
path_type path(tr,geom,prj_trans);
|
|
||||||
ras.add_path(path);
|
ras.add_path(path);
|
||||||
agg::scanline_u8 sl;
|
agg::scanline_u8 sl;
|
||||||
agg::render_scanlines(ras, sl, ren);
|
agg::render_scanlines(ras, sl, ren);
|
||||||
mapnik::save_to_file(im,name);
|
mapnik::save_to_file(im,name);
|
||||||
geom.rewind(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class test1 : public benchmark::test_case
|
class test1 : public benchmark::test_case
|
||||||
|
@ -63,7 +61,7 @@ class test1 : public benchmark::test_case
|
||||||
mapnik::box2d<double> extent_;
|
mapnik::box2d<double> extent_;
|
||||||
std::string expected_;
|
std::string expected_;
|
||||||
public:
|
public:
|
||||||
using conv_clip = agg::conv_clip_polygon<mapnik::geometry_type>;
|
using conv_clip = agg::conv_clip_polygon<mapnik::vertex_adapter>;
|
||||||
test1(mapnik::parameters const& params,
|
test1(mapnik::parameters const& params,
|
||||||
std::string const& wkt_in,
|
std::string const& wkt_in,
|
||||||
mapnik::box2d<double> const& extent)
|
mapnik::box2d<double> const& extent)
|
||||||
|
@ -84,8 +82,9 @@ public:
|
||||||
std::clog << "paths.size() != 1\n";
|
std::clog << "paths.size() != 1\n";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
mapnik::geometry_type & geom = paths[0];
|
mapnik::geometry_type const& geom = paths[0];
|
||||||
conv_clip clipped(geom);
|
mapnik::vertex_adapter va(geom);
|
||||||
|
conv_clip clipped(va);
|
||||||
clipped.clip_box(
|
clipped.clip_box(
|
||||||
extent_.minx(),
|
extent_.minx(),
|
||||||
extent_.miny(),
|
extent_.miny(),
|
||||||
|
@ -99,12 +98,13 @@ public:
|
||||||
}
|
}
|
||||||
std::string expect = expected_+".png";
|
std::string expect = expected_+".png";
|
||||||
std::string actual = expected_+"_actual.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";
|
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);
|
return benchmark::compare_images(actual,expect);
|
||||||
}
|
}
|
||||||
bool operator()() const
|
bool operator()() const
|
||||||
|
@ -114,11 +114,13 @@ public:
|
||||||
{
|
{
|
||||||
throw std::runtime_error("Failed to parse WKT");
|
throw std::runtime_error("Failed to parse WKT");
|
||||||
}
|
}
|
||||||
|
unsigned count = 0;
|
||||||
for (unsigned i=0;i<iterations_;++i)
|
for (unsigned i=0;i<iterations_;++i)
|
||||||
{
|
{
|
||||||
for (mapnik::geometry_type & geom : paths)
|
for (mapnik::geometry_type const& geom : paths)
|
||||||
{
|
{
|
||||||
conv_clip clipped(geom);
|
mapnik::vertex_adapter va(geom);
|
||||||
|
conv_clip clipped(va);
|
||||||
clipped.clip_box(
|
clipped.clip_box(
|
||||||
extent_.minx(),
|
extent_.minx(),
|
||||||
extent_.miny(),
|
extent_.miny(),
|
||||||
|
@ -126,10 +128,18 @@ public:
|
||||||
extent_.maxy());
|
extent_.maxy());
|
||||||
unsigned cmd;
|
unsigned cmd;
|
||||||
double x,y;
|
double x,y;
|
||||||
while ((cmd = clipped.vertex(&x, &y)) != mapnik::SEG_END) {}
|
while ((cmd = clipped.vertex(&x, &y)) != mapnik::SEG_END) {
|
||||||
|
count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
}
|
||||||
|
// TODO - sometimes this is 310001: what is causing that?
|
||||||
|
unsigned expected_count = 310002;
|
||||||
|
bool valid = (count == expected_count);
|
||||||
|
if (!valid) {
|
||||||
|
std::clog << "test1: clipping failed: processed " << count << " verticies but expected " << expected_count << "\n";
|
||||||
|
}
|
||||||
|
return valid;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -139,7 +149,7 @@ class test2 : public benchmark::test_case
|
||||||
mapnik::box2d<double> extent_;
|
mapnik::box2d<double> extent_;
|
||||||
std::string expected_;
|
std::string expected_;
|
||||||
public:
|
public:
|
||||||
using poly_clipper = agg::conv_clipper<mapnik::geometry_type, agg::path_storage>;
|
using poly_clipper = agg::conv_clipper<mapnik::vertex_adapter, agg::path_storage>;
|
||||||
test2(mapnik::parameters const& params,
|
test2(mapnik::parameters const& params,
|
||||||
std::string const& wkt_in,
|
std::string const& wkt_in,
|
||||||
mapnik::box2d<double> const& extent)
|
mapnik::box2d<double> const& extent)
|
||||||
|
@ -166,8 +176,9 @@ public:
|
||||||
std::clog << "paths.size() != 1\n";
|
std::clog << "paths.size() != 1\n";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
mapnik::geometry_type & geom = paths[0];
|
mapnik::geometry_type const& geom = paths[0];
|
||||||
poly_clipper clipped(geom,ps,
|
mapnik::vertex_adapter va(geom);
|
||||||
|
poly_clipper clipped(va,ps,
|
||||||
agg::clipper_and,
|
agg::clipper_and,
|
||||||
agg::clipper_non_zero,
|
agg::clipper_non_zero,
|
||||||
agg::clipper_non_zero,
|
agg::clipper_non_zero,
|
||||||
|
@ -181,12 +192,13 @@ public:
|
||||||
}
|
}
|
||||||
std::string expect = expected_+".png";
|
std::string expect = expected_+".png";
|
||||||
std::string actual = expected_+"_actual.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";
|
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);
|
return benchmark::compare_images(actual,expect);
|
||||||
}
|
}
|
||||||
bool operator()() const
|
bool operator()() const
|
||||||
|
@ -202,11 +214,13 @@ public:
|
||||||
ps.line_to(extent_.maxx(), extent_.maxy());
|
ps.line_to(extent_.maxx(), extent_.maxy());
|
||||||
ps.line_to(extent_.maxx(), extent_.miny());
|
ps.line_to(extent_.maxx(), extent_.miny());
|
||||||
ps.close_polygon();
|
ps.close_polygon();
|
||||||
|
unsigned count = 0;
|
||||||
for (unsigned i=0;i<iterations_;++i)
|
for (unsigned i=0;i<iterations_;++i)
|
||||||
{
|
{
|
||||||
for (mapnik::geometry_type & geom : paths)
|
for (mapnik::geometry_type const& geom : paths)
|
||||||
{
|
{
|
||||||
poly_clipper clipped(geom,ps,
|
mapnik::vertex_adapter va(geom);
|
||||||
|
poly_clipper clipped(va,ps,
|
||||||
agg::clipper_and,
|
agg::clipper_and,
|
||||||
agg::clipper_non_zero,
|
agg::clipper_non_zero,
|
||||||
agg::clipper_non_zero,
|
agg::clipper_non_zero,
|
||||||
|
@ -214,10 +228,17 @@ public:
|
||||||
clipped.rewind(0);
|
clipped.rewind(0);
|
||||||
unsigned cmd;
|
unsigned cmd;
|
||||||
double x,y;
|
double x,y;
|
||||||
while ((cmd = clipped.vertex(&x, &y)) != mapnik::SEG_END) {}
|
while ((cmd = clipped.vertex(&x, &y)) != mapnik::SEG_END) {
|
||||||
|
count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
}
|
||||||
|
unsigned expected_count = 290000;
|
||||||
|
bool valid = (count == expected_count);
|
||||||
|
if (!valid) {
|
||||||
|
std::clog << "test2: clipping failed: processed " << count << " verticies but expected " << expected_count << "\n";
|
||||||
|
}
|
||||||
|
return valid;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -227,7 +248,7 @@ class test3 : public benchmark::test_case
|
||||||
mapnik::box2d<double> extent_;
|
mapnik::box2d<double> extent_;
|
||||||
std::string expected_;
|
std::string expected_;
|
||||||
public:
|
public:
|
||||||
using poly_clipper = mapnik::polygon_clipper<mapnik::geometry_type>;
|
using poly_clipper = mapnik::polygon_clipper<mapnik::vertex_adapter>;
|
||||||
test3(mapnik::parameters const& params,
|
test3(mapnik::parameters const& params,
|
||||||
std::string const& wkt_in,
|
std::string const& wkt_in,
|
||||||
mapnik::box2d<double> const& extent)
|
mapnik::box2d<double> const& extent)
|
||||||
|
@ -248,8 +269,9 @@ public:
|
||||||
std::clog << "paths.size() != 1\n";
|
std::clog << "paths.size() != 1\n";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
mapnik::geometry_type & geom = paths[0];
|
mapnik::geometry_type const& geom = paths[0];
|
||||||
poly_clipper clipped(extent_, geom);
|
mapnik::vertex_adapter va(geom);
|
||||||
|
poly_clipper clipped(extent_, va);
|
||||||
unsigned cmd;
|
unsigned cmd;
|
||||||
double x,y;
|
double x,y;
|
||||||
mapnik::geometry_type geom2(mapnik::geometry_type::types::Polygon);
|
mapnik::geometry_type geom2(mapnik::geometry_type::types::Polygon);
|
||||||
|
@ -258,12 +280,13 @@ public:
|
||||||
}
|
}
|
||||||
std::string expect = expected_+".png";
|
std::string expect = expected_+".png";
|
||||||
std::string actual = expected_+"_actual.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";
|
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);
|
return benchmark::compare_images(actual,expect);
|
||||||
}
|
}
|
||||||
bool operator()() const
|
bool operator()() const
|
||||||
|
@ -273,17 +296,26 @@ public:
|
||||||
{
|
{
|
||||||
throw std::runtime_error("Failed to parse WKT");
|
throw std::runtime_error("Failed to parse WKT");
|
||||||
}
|
}
|
||||||
|
unsigned count = 0;
|
||||||
for (unsigned i=0;i<iterations_;++i)
|
for (unsigned i=0;i<iterations_;++i)
|
||||||
{
|
{
|
||||||
for ( mapnik::geometry_type & geom : paths)
|
for ( mapnik::geometry_type const& geom : paths)
|
||||||
{
|
{
|
||||||
poly_clipper clipped(extent_, geom);
|
mapnik::vertex_adapter va(geom);
|
||||||
|
poly_clipper clipped(extent_, va);
|
||||||
unsigned cmd;
|
unsigned cmd;
|
||||||
double x,y;
|
double x,y;
|
||||||
while ((cmd = clipped.vertex(&x, &y)) != mapnik::SEG_END) {}
|
while ((cmd = clipped.vertex(&x, &y)) != mapnik::SEG_END) {
|
||||||
|
count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
}
|
||||||
|
unsigned expected_count = 310000;
|
||||||
|
bool valid = (count == expected_count);
|
||||||
|
if (!valid) {
|
||||||
|
std::clog << "test3: clipping failed: processed " << count << " verticies but expected " << expected_count << "\n";
|
||||||
|
}
|
||||||
|
return valid;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ struct error_handler
|
||||||
{
|
{
|
||||||
using result_type = void;
|
using result_type = void;
|
||||||
void operator() (
|
void operator() (
|
||||||
Iterator, Iterator last,
|
Iterator, Iterator,
|
||||||
Iterator err_pos, boost::spirit::info const& what) const
|
Iterator err_pos, boost::spirit::info const& what) const
|
||||||
{
|
{
|
||||||
std::stringstream s;
|
std::stringstream s;
|
||||||
|
|
|
@ -67,7 +67,9 @@ struct polygon_clipper
|
||||||
polygon_clipper(box2d<double> const& clip_box, Geometry & geom)
|
polygon_clipper(box2d<double> const& clip_box, Geometry & geom)
|
||||||
:state_(clip),
|
:state_(clip),
|
||||||
clip_box_(clip_box),
|
clip_box_(clip_box),
|
||||||
geom_(geom)
|
geom_(geom),
|
||||||
|
output_(),
|
||||||
|
output_adapter_(output_)
|
||||||
{
|
{
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
@ -86,7 +88,7 @@ struct polygon_clipper
|
||||||
|
|
||||||
void rewind(unsigned path_id)
|
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);
|
else geom_.rewind(path_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,7 +97,7 @@ struct polygon_clipper
|
||||||
switch (state_)
|
switch (state_)
|
||||||
{
|
{
|
||||||
case clip:
|
case clip:
|
||||||
return output_.vertex(x,y);
|
return output_adapter_.vertex(x,y);
|
||||||
case no_clip:
|
case no_clip:
|
||||||
return geom_.vertex(x,y);
|
return geom_.vertex(x,y);
|
||||||
case ignore:
|
case ignore:
|
||||||
|
@ -230,6 +232,7 @@ private:
|
||||||
box2d<double> clip_box_;
|
box2d<double> clip_box_;
|
||||||
Geometry & geom_;
|
Geometry & geom_;
|
||||||
mapnik::geometry_type output_;
|
mapnik::geometry_type output_;
|
||||||
|
mapnik::vertex_adapter output_adapter_;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -73,7 +73,7 @@ namespace mapnik { namespace sql_utils {
|
||||||
{
|
{
|
||||||
table_name=table_name.substr(idx);
|
table_name=table_name.substr(idx);
|
||||||
}
|
}
|
||||||
idx = table_name.find_first_of(" )");
|
idx = table_name.find_first_of(", )");
|
||||||
if (idx != std::string::npos)
|
if (idx != std::string::npos)
|
||||||
{
|
{
|
||||||
table_name = table_name.substr(0,idx);
|
table_name = table_name.substr(0,idx);
|
||||||
|
|
|
@ -80,7 +80,7 @@ private:
|
||||||
const path_type *vertices_;
|
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 <>
|
template <>
|
||||||
class path_iterator<geometry_type>
|
class path_iterator<geometry_type>
|
||||||
: public boost::iterator_facade< path_iterator<geometry_type>,
|
: public boost::iterator_facade< path_iterator<geometry_type>,
|
||||||
|
@ -95,7 +95,8 @@ public:
|
||||||
using size_type = path_type::size_type;
|
using size_type = path_type::size_type;
|
||||||
path_iterator()
|
path_iterator()
|
||||||
: v_(mapnik::SEG_END,0,0),
|
: v_(mapnik::SEG_END,0,0),
|
||||||
vertices_()
|
vertices_(),
|
||||||
|
pos_(0)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
explicit path_iterator(path_type const& vertices)
|
explicit path_iterator(path_type const& vertices)
|
||||||
|
|
|
@ -292,6 +292,8 @@ boost::optional<mapnik::datasource::geometry_t> geojson_datasource::get_geometry
|
||||||
{
|
{
|
||||||
boost::optional<mapnik::datasource::geometry_t> result;
|
boost::optional<mapnik::datasource::geometry_t> result;
|
||||||
int multi_type = 0;
|
int multi_type = 0;
|
||||||
|
if (cache_features_)
|
||||||
|
{
|
||||||
unsigned num_features = features_.size();
|
unsigned num_features = features_.size();
|
||||||
for (unsigned i = 0; i < num_features && i < 5; ++i)
|
for (unsigned i = 0; i < num_features && i < 5; ++i)
|
||||||
{
|
{
|
||||||
|
@ -307,6 +309,54 @@ boost::optional<mapnik::datasource::geometry_t> geojson_datasource::get_geometry
|
||||||
multi_type = type;
|
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<mapnik::context_type>();
|
||||||
|
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<char> 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<chr_iterator_type,mapnik::feature_impl> 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<int>(*result);
|
||||||
|
if (multi_type > 0 && multi_type != type)
|
||||||
|
{
|
||||||
|
result.reset(mapnik::datasource::Collection);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
multi_type = type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,8 +23,8 @@
|
||||||
// mapnik
|
// mapnik
|
||||||
#include <mapnik/feature.hpp>
|
#include <mapnik/feature.hpp>
|
||||||
#include <mapnik/feature_factory.hpp>
|
#include <mapnik/feature_factory.hpp>
|
||||||
#include <mapnik/json/geometry_grammar_impl.hpp>
|
#include <mapnik/json/geometry_grammar.hpp>
|
||||||
#include <mapnik/json/feature_grammar_impl.hpp>
|
#include <mapnik/json/feature_grammar.hpp>
|
||||||
#include <mapnik/utils.hpp>
|
#include <mapnik/utils.hpp>
|
||||||
// stl
|
// stl
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -62,9 +62,10 @@ mapnik::feature_ptr large_geojson_featureset::next()
|
||||||
std::vector<char> json;
|
std::vector<char> json;
|
||||||
json.resize(size);
|
json.resize(size);
|
||||||
std::fread(json.data(), size, 1, file_.get());
|
std::fread(json.data(), size, 1, file_.get());
|
||||||
using chr_iterator_type = std::vector<char>::const_iterator;
|
|
||||||
chr_iterator_type start = json.begin();
|
using chr_iterator_type = char const*;
|
||||||
chr_iterator_type end = json.end();
|
chr_iterator_type start = json.data();
|
||||||
|
chr_iterator_type end = start + json.size();
|
||||||
|
|
||||||
static const mapnik::transcoder tr("utf8");
|
static const mapnik::transcoder tr("utf8");
|
||||||
static const mapnik::json::feature_grammar<chr_iterator_type,mapnik::feature_impl> grammar(tr);
|
static const mapnik::json::feature_grammar<chr_iterator_type,mapnik::feature_impl> grammar(tr);
|
||||||
|
|
33
tests/cxx/sql_parse.cpp
Normal file
33
tests/cxx/sql_parse.cpp
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
|
||||||
|
#include "catch.hpp"
|
||||||
|
|
||||||
|
#include <mapnik/sql_utils.hpp>
|
||||||
|
|
||||||
|
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) );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
BIN
tests/data/shp/3d_point_empty.dbf
Normal file
BIN
tests/data/shp/3d_point_empty.dbf
Normal file
Binary file not shown.
1
tests/data/shp/3d_point_empty.prj
Normal file
1
tests/data/shp/3d_point_empty.prj
Normal file
|
@ -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]]
|
BIN
tests/data/shp/3d_point_empty.shp
Normal file
BIN
tests/data/shp/3d_point_empty.shp
Normal file
Binary file not shown.
BIN
tests/data/shp/3d_point_empty.shx
Normal file
BIN
tests/data/shp/3d_point_empty.shx
Normal file
Binary file not shown.
|
@ -4,6 +4,10 @@
|
||||||
from nose.tools import eq_,assert_almost_equal
|
from nose.tools import eq_,assert_almost_equal
|
||||||
from utilities import execution_path, run_all
|
from utilities import execution_path, run_all
|
||||||
import os, mapnik
|
import os, mapnik
|
||||||
|
try:
|
||||||
|
import json
|
||||||
|
except ImportError:
|
||||||
|
import simplejson as json
|
||||||
|
|
||||||
def setup():
|
def setup():
|
||||||
# All of the paths used are relative, if we run the tests
|
# 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['boolean'], True)
|
||||||
eq_(f['NOM_FR'], u'Qu\xe9bec')
|
eq_(f['NOM_FR'], u'Qu\xe9bec')
|
||||||
eq_(f['NOM_FR'], u'Québec')
|
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')
|
ds = mapnik.Datasource(type='geojson',file='../data/json/escaped.geojson')
|
||||||
f = ds.all_features()[0]
|
f = ds.all_features()[0]
|
||||||
|
@ -51,6 +61,56 @@ if 'geojson' in mapnik.DatasourceCache.plugin_names():
|
||||||
eq_(f['boolean'], True)
|
eq_(f['boolean'], True)
|
||||||
eq_(f['NOM_FR'], u'Qu\xe9bec')
|
eq_(f['NOM_FR'], u'Qu\xe9bec')
|
||||||
eq_(f['NOM_FR'], u'Québec')
|
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)
|
||||||
|
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')
|
||||||
|
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]
|
||||||
|
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')
|
||||||
|
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():
|
def test_geojson_from_in_memory_string():
|
||||||
# will silently fail since it is a geometry and needs to be a featurecollection.
|
# will silently fail since it is a geometry and needs to be a featurecollection.
|
||||||
|
|
51
tests/python_tests/shapeindex_test.py
Normal file
51
tests/python_tests/shapeindex_test.py
Normal file
|
@ -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_")))
|
|
@ -164,18 +164,24 @@ int main (int argc,char** argv)
|
||||||
shape_type = shp.read_ndr_integer();
|
shape_type = shp.read_ndr_integer();
|
||||||
box2d<double> item_ext;
|
box2d<double> item_ext;
|
||||||
if (shape_type==shape_io::shape_null)
|
if (shape_type==shape_io::shape_null)
|
||||||
|
{
|
||||||
|
if (pos >= file_length)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
// still need to increment pos, or the pos counter
|
// still need to increment pos, or the pos counter
|
||||||
// won't indicate EOF until too late.
|
// won't indicate EOF until too late.
|
||||||
pos+=4+content_length;
|
pos+=4+content_length;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else if (shape_type==shape_io::shape_point)
|
else if (shape_type==shape_io::shape_point)
|
||||||
{
|
{
|
||||||
double x=shp.read_double();
|
double x=shp.read_double();
|
||||||
double y=shp.read_double();
|
double y=shp.read_double();
|
||||||
item_ext=box2d<double>(x,y,x,y);
|
item_ext=box2d<double>(x,y,x,y);
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (shape_type==shape_io::shape_pointm)
|
else if (shape_type==shape_io::shape_pointm)
|
||||||
{
|
{
|
||||||
|
@ -184,7 +190,6 @@ int main (int argc,char** argv)
|
||||||
// skip m
|
// skip m
|
||||||
shp.read_double();
|
shp.read_double();
|
||||||
item_ext=box2d<double>(x,y,x,y);
|
item_ext=box2d<double>(x,y,x,y);
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (shape_type==shape_io::shape_pointz)
|
else if (shape_type==shape_io::shape_pointz)
|
||||||
{
|
{
|
||||||
|
@ -192,31 +197,39 @@ int main (int argc,char** argv)
|
||||||
double y=shp.read_double();
|
double y=shp.read_double();
|
||||||
// skip z
|
// skip z
|
||||||
shp.read_double();
|
shp.read_double();
|
||||||
//skip m if exists
|
// According to ESRI shapefile doc
|
||||||
if ( content_length == 8 + 36)
|
// 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();
|
shp.read_double();
|
||||||
}
|
}
|
||||||
item_ext=box2d<double>(x,y,x,y);
|
item_ext=box2d<double>(x,y,x,y);
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
shp.read_envelope(item_ext);
|
shp.read_envelope(item_ext);
|
||||||
shp.skip(2*content_length-4*8-4);
|
shp.skip(2*content_length-4*8-4);
|
||||||
}
|
}
|
||||||
|
|
||||||
tree.insert(offset,item_ext);
|
tree.insert(offset,item_ext);
|
||||||
if (verbose) {
|
if (verbose)
|
||||||
|
{
|
||||||
clog << "record number " << record_number << " box=" << item_ext << endl;
|
clog << "record number " << record_number << " box=" << item_ext << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
pos+=4+content_length;
|
pos+=4+content_length;
|
||||||
++count;
|
++count;
|
||||||
|
|
||||||
if (pos>=file_length) {
|
if (pos >= file_length) break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
clog << " number shapes=" << count << endl;
|
clog << " number shapes=" << count << endl;
|
||||||
|
|
Loading…
Reference in a new issue