// mapnik #include <mapnik/geometry.hpp> #include <mapnik/util/conversions.hpp> #include <mapnik/util/trim.hpp> // boost #include <boost/detail/lightweight_test.hpp> #include <boost/algorithm/string.hpp> // stl #include <stdexcept> #include <iostream> #include <sstream> #include <fstream> #include <vector> #include <algorithm> // agg #include "agg_conv_clip_polygon.h" #include "agg_conv_clip_polyline.h" //#include "agg_path_storage.h" //#include "agg_conv_clipper.h" #include "utils.hpp" template <typename T> std::string dump_path(T & path) { unsigned cmd = 1; double x = 0; double y = 0; unsigned idx = 0; std::ostringstream s; path.rewind(0); while ((cmd = path.vertex(&x, &y)) != mapnik::SEG_END) { if (idx > 0) s << ","; s << x << " " << y << " " << cmd; idx++; } return s.str(); } std::string clip_line(mapnik::box2d<double> const& bbox, mapnik::geometry_type & geom) { using line_clipper = agg::conv_clip_polyline<mapnik::geometry_type>; line_clipper clipped(geom); clipped.clip_box(bbox.minx(),bbox.miny(),bbox.maxx(),bbox.maxy()); return dump_path(clipped); } void parse_geom(mapnik::geometry_type & geom, std::string const& geom_string) { std::vector<std::string> vertices; boost::split(vertices, geom_string, boost::is_any_of(",")); for (std::string const& vert : vertices) { std::vector<std::string> commands; boost::split(commands, vert, boost::is_any_of(" ")); if (commands.size() != 3) { throw std::runtime_error(std::string("could not parse geometry '") + geom_string + "'"); } double x = 0; double y = 0; int c = 0; if (mapnik::util::string2double(commands[0],x) && mapnik::util::string2double(commands[1],y) && mapnik::util::string2int(commands[2],c)) { geom.push_vertex(x,y,(mapnik::CommandType)c); } else { throw std::runtime_error(std::string("could not parse geometry '") + geom_string + "'"); } } } int main(int argc, char** argv) { 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(); try { BOOST_TEST(set_working_dir(args)); std::string filename("tests/cpp_tests/data/cases.txt"); std::ifstream stream(filename.c_str(),std::ios_base::in | std::ios_base::binary); if (!stream.is_open()) throw std::runtime_error("could not open: '" + filename + "'"); std::string csv_line; while(std::getline(stream,csv_line,'\n')) { if (csv_line.empty() || csv_line[0] == '#') continue; std::vector<std::string> parts; boost::split(parts, csv_line, boost::is_any_of(";")); // first part is clipping box mapnik::box2d<double> bbox; if (!bbox.from_string(parts[0])) { throw std::runtime_error(std::string("could not parse bbox '") + parts[0] + "'"); } // second part is input geometry mapnik::geometry_type geom; parse_geom(geom,parts[1]); //std::clog << dump_path(geom) << "\n"; // third part is expected, clipped geometry BOOST_TEST_EQ(clip_line(bbox,geom),mapnik::util::trim_copy(parts[2])); } stream.close(); } catch (std::exception const& ex) { std::cerr << ex.what() << "\n"; } if (!::boost::detail::test_errors()) { if (quiet) std::clog << "\x1b[1;32m.\x1b[0m"; else std::clog << "C++ clipping: \x1b[1;32m✓ \x1b[0m\n"; ::boost::detail::report_errors_remind().called_report_errors_function = true; } else { return ::boost::report_errors(); } }