2013-06-02 23:54:27 +02:00
|
|
|
#include <boost/detail/lightweight_test.hpp>
|
|
|
|
#include <iostream>
|
|
|
|
#include <vector>
|
|
|
|
#include <algorithm>
|
|
|
|
#include "utils.hpp"
|
2013-01-24 14:34:00 +01:00
|
|
|
|
|
|
|
#include <mapnik/layer.hpp>
|
|
|
|
#include <mapnik/feature_type_style.hpp>
|
2014-07-23 23:02:36 +02:00
|
|
|
#include <mapnik/rule.hpp>
|
2013-01-24 14:34:00 +01:00
|
|
|
#include <mapnik/debug.hpp>
|
2014-08-28 11:29:04 +02:00
|
|
|
#include <mapnik/view_transform.hpp>
|
2014-02-09 07:10:14 +01:00
|
|
|
#include <mapnik/feature.hpp>
|
2013-01-24 14:34:00 +01:00
|
|
|
#include <mapnik/vertex_converters.hpp>
|
|
|
|
#include <mapnik/geometry.hpp>
|
|
|
|
#include <mapnik/wkt/wkt_factory.hpp>
|
2013-02-20 19:47:55 +01:00
|
|
|
#include <mapnik/well_known_srs.hpp>
|
2014-07-24 23:31:59 +02:00
|
|
|
#include <mapnik/wkt/wkt_generator_grammar.hpp>
|
2014-07-23 07:40:39 +02:00
|
|
|
#include <mapnik/projection.hpp>
|
|
|
|
#include <mapnik/proj_transform.hpp>
|
2013-05-26 03:16:18 +02:00
|
|
|
|
2013-06-03 05:19:33 +02:00
|
|
|
// stl
|
|
|
|
#include <stdexcept>
|
|
|
|
|
2013-01-24 14:34:00 +01:00
|
|
|
struct output_geometry_backend
|
|
|
|
{
|
2014-07-24 23:31:59 +02:00
|
|
|
output_geometry_backend(mapnik::geometry_container & paths, mapnik::geometry_type::types type)
|
2013-01-24 14:34:00 +01:00
|
|
|
: paths_(paths),
|
|
|
|
type_(type) {}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
void add_path(T & path)
|
|
|
|
{
|
|
|
|
mapnik::vertex2d vtx(mapnik::vertex2d::no_init);
|
|
|
|
path.rewind(0);
|
2013-09-20 05:19:01 +02:00
|
|
|
std::unique_ptr<mapnik::geometry_type> geom_ptr(new mapnik::geometry_type(type_));
|
2013-01-24 14:34:00 +01:00
|
|
|
|
|
|
|
while ((vtx.cmd = path.vertex(&vtx.x, &vtx.y)) != mapnik::SEG_END)
|
|
|
|
{
|
|
|
|
//std::cerr << vtx.x << "," << vtx.y << " cmd=" << vtx.cmd << std::endl;
|
|
|
|
geom_ptr->push_vertex(vtx.x, vtx.y, (mapnik::CommandType)vtx.cmd);
|
|
|
|
}
|
2013-09-20 05:19:01 +02:00
|
|
|
paths_.push_back(geom_ptr.release());
|
2013-01-24 14:34:00 +01:00
|
|
|
}
|
2014-07-24 23:31:59 +02:00
|
|
|
mapnik::geometry_container & paths_;
|
2013-09-20 05:19:01 +02:00
|
|
|
mapnik::geometry_type::types type_;
|
2013-01-24 14:34:00 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
boost::optional<std::string> linestring_bbox_clipping(mapnik::box2d<double> bbox,
|
|
|
|
std::string wkt_in)
|
|
|
|
{
|
|
|
|
using namespace mapnik;
|
|
|
|
agg::trans_affine tr;
|
2013-02-20 19:47:55 +01:00
|
|
|
projection src(MAPNIK_LONGLAT_PROJ);
|
|
|
|
projection dst(MAPNIK_LONGLAT_PROJ);
|
2013-01-24 14:34:00 +01:00
|
|
|
proj_transform prj_trans(src,dst);
|
|
|
|
line_symbolizer sym;
|
2014-08-28 11:17:15 +02:00
|
|
|
view_transform t(bbox.width(),bbox.height(), bbox);
|
2014-07-24 23:31:59 +02:00
|
|
|
mapnik::geometry_container output_paths;
|
2013-09-20 05:19:01 +02:00
|
|
|
output_geometry_backend backend(output_paths, mapnik::geometry_type::types::LineString);
|
2013-01-24 14:34:00 +01:00
|
|
|
|
2014-02-09 07:10:14 +01:00
|
|
|
mapnik::context_ptr ctx = std::make_shared<mapnik::context_type>();
|
|
|
|
mapnik::feature_impl f(ctx,0);
|
2014-09-29 12:57:47 +02:00
|
|
|
vertex_converter<output_geometry_backend,clip_line_tag>
|
2014-05-11 22:08:24 +02:00
|
|
|
converter(bbox, backend, sym, t, prj_trans, tr, f, attributes(), 1.0);
|
2013-01-24 14:34:00 +01:00
|
|
|
|
2013-01-24 18:28:32 +01:00
|
|
|
converter.set<clip_line_tag>();
|
2013-01-24 14:34:00 +01:00
|
|
|
|
2014-07-24 23:31:59 +02:00
|
|
|
mapnik::geometry_container p;
|
2013-01-24 14:34:00 +01:00
|
|
|
if (!mapnik::from_wkt(wkt_in , p))
|
|
|
|
{
|
|
|
|
throw std::runtime_error("Failed to parse WKT");
|
|
|
|
}
|
|
|
|
|
2015-02-06 16:45:51 +01:00
|
|
|
for (geometry_type const& geom : p)
|
2013-01-24 14:34:00 +01:00
|
|
|
{
|
2015-02-06 16:45:51 +01:00
|
|
|
vertex_adapter va(geom);
|
|
|
|
converter.apply(va);
|
2013-01-24 14:34:00 +01:00
|
|
|
}
|
|
|
|
|
2014-07-24 23:31:59 +02:00
|
|
|
using sink_type = std::back_insert_iterator<std::string>;
|
2015-02-15 23:00:20 +01:00
|
|
|
std::string wkt;
|
2014-07-24 23:31:59 +02:00
|
|
|
sink_type sink(wkt);
|
|
|
|
static const mapnik::wkt::wkt_multi_generator<sink_type, mapnik::geometry_container> generator;
|
|
|
|
if (boost::spirit::karma::generate(sink, generator, output_paths))
|
2013-01-24 14:34:00 +01:00
|
|
|
{
|
2014-07-24 23:31:59 +02:00
|
|
|
return boost::optional<std::string>(wkt);
|
2013-01-24 14:34:00 +01:00
|
|
|
}
|
|
|
|
return boost::optional<std::string>();
|
|
|
|
}
|
|
|
|
|
|
|
|
boost::optional<std::string> polygon_bbox_clipping(mapnik::box2d<double> bbox,
|
|
|
|
std::string wkt_in)
|
|
|
|
{
|
|
|
|
using namespace mapnik;
|
|
|
|
agg::trans_affine tr;
|
2013-02-20 19:47:55 +01:00
|
|
|
projection src(MAPNIK_LONGLAT_PROJ);
|
|
|
|
projection dst(MAPNIK_LONGLAT_PROJ);
|
2013-01-24 14:34:00 +01:00
|
|
|
proj_transform prj_trans(src,dst);
|
|
|
|
polygon_symbolizer sym;
|
2014-08-28 11:17:15 +02:00
|
|
|
view_transform t(bbox.width(),bbox.height(), bbox);
|
2014-07-24 23:31:59 +02:00
|
|
|
mapnik::geometry_container output_paths;
|
2013-09-20 05:19:01 +02:00
|
|
|
output_geometry_backend backend(output_paths, mapnik::geometry_type::types::Polygon);
|
2013-01-24 14:34:00 +01:00
|
|
|
|
2014-02-09 07:10:14 +01:00
|
|
|
mapnik::context_ptr ctx = std::make_shared<mapnik::context_type>();
|
|
|
|
mapnik::feature_impl f(ctx,0);
|
2014-09-29 12:57:47 +02:00
|
|
|
vertex_converter<output_geometry_backend, clip_poly_tag>
|
2014-05-11 22:08:24 +02:00
|
|
|
converter(bbox, backend, sym, t, prj_trans, tr, f, attributes(), 1.0);
|
2013-01-24 14:34:00 +01:00
|
|
|
|
2013-01-24 18:28:32 +01:00
|
|
|
converter.set<clip_poly_tag>();
|
2013-01-24 14:34:00 +01:00
|
|
|
|
2014-07-24 23:31:59 +02:00
|
|
|
mapnik::geometry_container p;
|
2013-01-24 14:34:00 +01:00
|
|
|
if (!mapnik::from_wkt(wkt_in , p))
|
|
|
|
{
|
|
|
|
throw std::runtime_error("Failed to parse WKT");
|
|
|
|
}
|
|
|
|
|
2015-02-06 16:45:51 +01:00
|
|
|
for (geometry_type const& geom : p)
|
2013-01-24 14:34:00 +01:00
|
|
|
{
|
2015-02-06 16:45:51 +01:00
|
|
|
vertex_adapter va(geom);
|
|
|
|
converter.apply(va);
|
2013-01-24 14:34:00 +01:00
|
|
|
}
|
|
|
|
|
2014-07-24 23:31:59 +02:00
|
|
|
using sink_type = std::back_insert_iterator<std::string>;
|
|
|
|
std::string wkt; // Use Python String directly ?
|
|
|
|
sink_type sink(wkt);
|
|
|
|
static const mapnik::wkt::wkt_multi_generator<sink_type, mapnik::geometry_container> generator;
|
|
|
|
if (boost::spirit::karma::generate(sink, generator, output_paths))
|
2013-01-24 14:34:00 +01:00
|
|
|
{
|
2014-07-24 23:31:59 +02:00
|
|
|
return boost::optional<std::string>(wkt);
|
2013-01-24 14:34:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return boost::optional<std::string>();
|
|
|
|
}
|
|
|
|
|
2013-05-25 02:21:55 +02:00
|
|
|
int main(int argc, char** argv)
|
2013-01-24 14:34:00 +01:00
|
|
|
{
|
2013-05-25 02:21:55 +02:00
|
|
|
std::vector<std::string> args;
|
|
|
|
for (int i=1;i<argc;++i)
|
|
|
|
{
|
|
|
|
args.push_back(argv[i]);
|
|
|
|
}
|
|
|
|
bool quiet = std::find(args.begin(), args.end(), "-q")!=args.end();
|
|
|
|
|
2013-05-26 03:16:18 +02:00
|
|
|
BOOST_TEST(set_working_dir(args));
|
|
|
|
|
2014-10-21 04:55:11 +02:00
|
|
|
try
|
2013-01-24 14:34:00 +01:00
|
|
|
{
|
2014-10-21 04:55:11 +02:00
|
|
|
// LineString/bbox clipping
|
|
|
|
{
|
|
|
|
std::string wkt_in("LineString(0 0,200 200)");
|
|
|
|
boost::optional<std::string> result = linestring_bbox_clipping(mapnik::box2d<double>(50,50,150,150),wkt_in);
|
|
|
|
BOOST_TEST(result);
|
|
|
|
BOOST_TEST_EQ(*result,std::string("LineString(50 50,150 150)"));
|
|
|
|
}
|
|
|
|
// Polygon/bbox clipping
|
|
|
|
{
|
|
|
|
std::string wkt_in("Polygon((50 50,150 50,150 150,50 150,50 50))");
|
|
|
|
boost::optional<std::string> result = polygon_bbox_clipping(mapnik::box2d<double>(50,50,150,150),wkt_in);
|
|
|
|
BOOST_TEST(result);
|
2015-02-15 23:00:20 +01:00
|
|
|
// TODO - the extra 50 50 is not ideal, but we enforce this result for now to prevent
|
|
|
|
// regressions and because we don't have actionable solution to drop extra 50 50
|
|
|
|
BOOST_TEST_EQ(*result,std::string("Polygon((50 50,150 50,150 150,50 150,50 50,50 50))"));
|
|
|
|
// below is ideal, but not current result
|
|
|
|
//BOOST_TEST_EQ(*result,std::string("Polygon((50 50,150 50,150 150,50 150,50 50))"));
|
2014-10-21 04:55:11 +02:00
|
|
|
}
|
2015-02-15 23:00:20 +01:00
|
|
|
|
2014-10-21 04:55:11 +02:00
|
|
|
{
|
|
|
|
std::string wkt_in("Polygon((60 60,140 60,140 160,60 140,60 60))");
|
|
|
|
boost::optional<std::string> result = polygon_bbox_clipping(mapnik::box2d<double>(50,50,150,150),wkt_in);
|
|
|
|
BOOST_TEST(result);
|
2015-02-15 23:00:20 +01:00
|
|
|
BOOST_TEST_EQ(*result,std::string("Polygon((60 60,140 60,140 150,100 150,60 140,60 60,60 60))"));
|
|
|
|
//BOOST_TEST_EQ(*result,std::string("Polygon((60 60,140 60,140 160,60 140,60 60))"));
|
2014-10-21 04:55:11 +02:00
|
|
|
}
|
2013-01-24 14:34:00 +01:00
|
|
|
|
2014-10-21 04:55:11 +02:00
|
|
|
{
|
|
|
|
std::string wkt_in("Polygon((0 0,10 0,10 10,0 10,0 0))");
|
|
|
|
boost::optional<std::string> result = polygon_bbox_clipping(mapnik::box2d<double>(50,50,150,150),wkt_in);
|
|
|
|
BOOST_TEST(result);
|
2015-02-15 23:00:20 +01:00
|
|
|
// TODO - this is completely wrong: should not have )) and ideally should be EMPTY
|
|
|
|
BOOST_TEST_EQ(*result, std::string("Polygon())"));
|
2014-10-21 04:55:11 +02:00
|
|
|
}
|
|
|
|
{
|
|
|
|
std::string wkt_in("Polygon((0 0,100 200,200 0,0 0 ))");
|
|
|
|
boost::optional<std::string> result = polygon_bbox_clipping(mapnik::box2d<double>(50,50,150,150),wkt_in);
|
|
|
|
BOOST_TEST(result);
|
2015-02-15 23:00:20 +01:00
|
|
|
BOOST_TEST_EQ(*result, std::string("Polygon((50 50,50 100,75 150,125 150,150 100,150 50))"));
|
|
|
|
//BOOST_TEST_EQ(*result,std::string("Polygon((50 50,50 100,75 150,125 150,150 100,150 50,50 50))"));
|
2014-10-21 04:55:11 +02:00
|
|
|
}
|
2015-02-15 23:00:20 +01:00
|
|
|
|
2013-01-24 14:34:00 +01:00
|
|
|
}
|
2014-10-21 04:55:11 +02:00
|
|
|
catch (std::exception const & ex)
|
2013-01-24 14:34:00 +01:00
|
|
|
{
|
2014-10-21 04:55:11 +02:00
|
|
|
std::clog << ex.what() << "\n";
|
|
|
|
BOOST_TEST(false);
|
2013-01-24 14:34:00 +01:00
|
|
|
}
|
2014-10-21 04:55:11 +02:00
|
|
|
|
2013-06-02 23:54:27 +02:00
|
|
|
|
2013-01-24 14:34:00 +01:00
|
|
|
if (!::boost::detail::test_errors())
|
|
|
|
{
|
2013-05-25 02:21:55 +02:00
|
|
|
if (quiet) std::clog << "\x1b[1;32m.\x1b[0m";
|
|
|
|
else std::clog << "C++ geometry conversions: \x1b[1;32m✓ \x1b[0m\n";
|
2013-01-24 14:34:00 +01:00
|
|
|
::boost::detail::report_errors_remind().called_report_errors_function = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return ::boost::report_errors();
|
|
|
|
}
|
|
|
|
}
|