port old c++ tests to catch.hpp
This commit is contained in:
parent
0170ba1ae3
commit
d40fb04284
17 changed files with 2249 additions and 0 deletions
209
tests/cxx/agg_blend_src_over_test.cpp
Normal file
209
tests/cxx/agg_blend_src_over_test.cpp
Normal file
|
@ -0,0 +1,209 @@
|
|||
#include "catch.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include "agg_color_rgba.h"
|
||||
#include "agg_pixfmt_rgba.h"
|
||||
#include "agg_rendering_buffer.h"
|
||||
#include "agg_renderer_base.h"
|
||||
|
||||
using color = agg::rgba8;
|
||||
using order = agg::order_rgba;
|
||||
|
||||
std::string to_string(color const& c)
|
||||
{
|
||||
std::ostringstream s;
|
||||
s << "rgba(" << (unsigned)c.r << "," << (unsigned)c.g << "," << (unsigned)c.b << "," << (unsigned)c.a << ")";
|
||||
return s.str();
|
||||
}
|
||||
|
||||
template<typename blender>
|
||||
color blend(color const& source, color const& dest, unsigned cover=255)
|
||||
{
|
||||
unsigned stride = 4;
|
||||
unsigned size = 1;
|
||||
|
||||
color source_pre = source;
|
||||
source_pre.premultiply();
|
||||
color dest_pre = dest;
|
||||
dest_pre.premultiply();
|
||||
|
||||
unsigned char* buffer = new unsigned char[size*size*stride];
|
||||
std::memset(buffer, 0, size*size*stride);
|
||||
buffer[0] = dest_pre.r;
|
||||
buffer[1] = dest_pre.g;
|
||||
buffer[2] = dest_pre.b;
|
||||
buffer[3] = dest_pre.a;
|
||||
// http://www.antigrain.com/doc/basic_renderers/basic_renderers.agdoc.html
|
||||
agg::rendering_buffer rbuf(buffer,
|
||||
size,
|
||||
size,
|
||||
size * stride);
|
||||
color::value_type* psource = (color::value_type*)rbuf.row_ptr(0,0,1);
|
||||
blender::blend_pix(psource,source_pre.r,source_pre.g,source_pre.b,source_pre.a,cover);
|
||||
color color_result(psource[0],psource[1],psource[2],psource[3]);
|
||||
color_result.demultiply();
|
||||
delete [] buffer;
|
||||
return color_result;
|
||||
}
|
||||
|
||||
// agg::pixfmt_alpha_blend_rgba
|
||||
color normal_blend(color const& source, color const& dest, unsigned cover=255)
|
||||
{
|
||||
using renderer_type = agg::renderer_base<agg::pixfmt_rgba32_pre>;
|
||||
unsigned stride = 4;
|
||||
unsigned size = 1;
|
||||
color source_pre = source;
|
||||
source_pre.premultiply();
|
||||
color dest_pre = dest;
|
||||
dest_pre.premultiply();
|
||||
// source buffer
|
||||
unsigned char* source_buffer = new unsigned char[size*size*stride];
|
||||
std::memset(source_buffer, 0, size*size*stride);
|
||||
source_buffer[0] = source_pre.r;
|
||||
source_buffer[1] = source_pre.g;
|
||||
source_buffer[2] = source_pre.b;
|
||||
source_buffer[3] = source_pre.a;
|
||||
agg::rendering_buffer source_rbuffer(source_buffer,size,size,size * 4);
|
||||
agg::pixfmt_rgba32_pre pixf_source(source_rbuffer);
|
||||
|
||||
// destination buffer
|
||||
unsigned char* dest_buffer = new unsigned char[size*size*stride];
|
||||
std::memset(dest_buffer, 0, size*size*stride);
|
||||
dest_buffer[0] = dest_pre.r;
|
||||
dest_buffer[1] = dest_pre.g;
|
||||
dest_buffer[2] = dest_pre.b;
|
||||
dest_buffer[3] = dest_pre.a;
|
||||
agg::rendering_buffer dest_rbuffer(dest_buffer,size,size,size * 4);
|
||||
agg::pixfmt_rgba32_pre pixf_dest(dest_rbuffer);
|
||||
|
||||
// renderer: blends source into destination
|
||||
renderer_type ren(pixf_dest);
|
||||
ren.blend_from(pixf_source,0,0,0,cover);
|
||||
color color_result(dest_buffer[0],dest_buffer[1],dest_buffer[2],dest_buffer[3]);
|
||||
color_result.demultiply();
|
||||
delete [] source_buffer;
|
||||
delete [] dest_buffer;
|
||||
return color_result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
namespace agg {
|
||||
|
||||
// the original agg template code for src_over
|
||||
// before we changed A as per https://github.com/mapnik/mapnik/issues/1452
|
||||
template<class ColorT, class Order> struct comp_op_rgba_src_over2
|
||||
{
|
||||
using color_type = ColorT;
|
||||
using order_type = Order;
|
||||
using value_type = typename color_type::value_type;
|
||||
using calc_type = typename color_type::calc_type;
|
||||
enum base_scale_e
|
||||
{
|
||||
base_shift = color_type::base_shift,
|
||||
base_mask = color_type::base_mask
|
||||
};
|
||||
|
||||
// Dca' = Sca + Dca.(1 - Sa)
|
||||
// Da' = Sa + Da - Sa.Da
|
||||
static void blend_pix(value_type* p,
|
||||
unsigned sr, unsigned sg, unsigned sb,
|
||||
unsigned sa, unsigned cover)
|
||||
{
|
||||
if(cover < 255)
|
||||
{
|
||||
sr = (sr * cover + 255) >> 8;
|
||||
sg = (sg * cover + 255) >> 8;
|
||||
sb = (sb * cover + 255) >> 8;
|
||||
sa = (sa * cover + 255) >> 8;
|
||||
}
|
||||
calc_type s1a = base_mask - sa;
|
||||
p[Order::R] = (value_type)(sr + ((p[Order::R] * s1a + base_mask) >> base_shift));
|
||||
p[Order::G] = (value_type)(sg + ((p[Order::G] * s1a + base_mask) >> base_shift));
|
||||
p[Order::B] = (value_type)(sb + ((p[Order::B] * s1a + base_mask) >> base_shift));
|
||||
p[Order::A] = (value_type)(sa + p[Order::A] - ((sa * p[Order::A] + base_mask) >> base_shift));
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE("blending") {
|
||||
|
||||
SECTION("src over") {
|
||||
|
||||
using source_over_old_agg = agg::comp_op_rgba_src_over2<color, agg::order_rgba>;
|
||||
using source_over = agg::comp_op_rgba_src_over<color, agg::order_rgba>;
|
||||
|
||||
try
|
||||
{
|
||||
color white(255,255,255,255);
|
||||
color black(0,0,0,255);
|
||||
|
||||
REQUIRE( to_string(blend<source_over>(white,white)) == to_string(white) );
|
||||
REQUIRE( to_string(blend<source_over>(white,black)) == to_string(white) );
|
||||
REQUIRE( to_string(blend<source_over>(black,white)) == to_string(black) );
|
||||
|
||||
color near_white(254,254,254,254); // Source
|
||||
color near_trans(1,1,1,1); // Dest
|
||||
color expected_color(253,253,253,255); // expected result
|
||||
REQUIRE( to_string(blend<source_over_old_agg>(near_white,near_trans)) == to_string(color(253,253,253,254)) );
|
||||
REQUIRE( to_string(blend<source_over>(near_white,near_trans)) == to_string(expected_color) );
|
||||
REQUIRE( to_string(normal_blend(near_white,near_trans)) == to_string(expected_color) );
|
||||
|
||||
// using normal_blend as expected, compare a variety of other colors
|
||||
|
||||
{
|
||||
color source(128,128,128,255);
|
||||
color dest(128,128,128,255);
|
||||
unsigned cover = 128;
|
||||
std::string expected_str = to_string(normal_blend(source,dest,cover));
|
||||
REQUIRE( to_string(blend<source_over>(source,dest,cover)) == expected_str );
|
||||
REQUIRE( to_string(blend<source_over_old_agg>(source,dest,cover)) == expected_str );
|
||||
}
|
||||
|
||||
{
|
||||
color source(128,128,128,255);
|
||||
color dest(128,128,128,255);
|
||||
unsigned cover = 245;
|
||||
std::string expected_str = to_string(normal_blend(source,dest,cover));
|
||||
REQUIRE( to_string(blend<source_over>(source,dest,cover)) == expected_str );
|
||||
REQUIRE( to_string(blend<source_over_old_agg>(source,dest,cover)) == expected_str );
|
||||
}
|
||||
|
||||
// commenting until I study these failures more (dane)
|
||||
/*
|
||||
{
|
||||
// fails, why?
|
||||
color source(127,127,127,127);
|
||||
color dest(127,127,127,127);
|
||||
unsigned cover = 255;
|
||||
std::string expected_str = to_string(normal_blend(source,dest,cover));
|
||||
REQUIRE( to_string(blend<source_over>(source,dest,cover)) == expected_str );
|
||||
REQUIRE( to_string(blend<source_over_old_agg>(source,dest,cover)) == expected_str );
|
||||
}
|
||||
|
||||
{
|
||||
// fails, why?
|
||||
color source(128,128,128,128);
|
||||
color dest(128,128,128,128);
|
||||
unsigned cover = 128;
|
||||
std::string expected_str = to_string(normal_blend(source,dest,cover));
|
||||
REQUIRE( to_string(blend<source_over>(source,dest,cover)) == expected_str );
|
||||
REQUIRE( to_string(blend<source_over_old_agg>(source,dest,cover)) == expected_str );
|
||||
}
|
||||
*/
|
||||
}
|
||||
catch (std::exception const & ex)
|
||||
{
|
||||
std::clog << ex.what() << "\n";
|
||||
REQUIRE(false);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
120
tests/cxx/clipping_test.cpp
Normal file
120
tests/cxx/clipping_test.cpp
Normal file
|
@ -0,0 +1,120 @@
|
|||
#include "catch.hpp"
|
||||
|
||||
// mapnik
|
||||
#include <mapnik/util/conversions.hpp>
|
||||
#include <mapnik/util/trim.hpp>
|
||||
#include <mapnik/path.hpp>
|
||||
// boost
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||
#pragma GCC diagnostic ignored "-Wunused-local-typedef"
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
// 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"
|
||||
|
||||
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::path_type const& path)
|
||||
{
|
||||
using line_clipper = agg::conv_clip_polyline<mapnik::vertex_adapter>;
|
||||
mapnik::vertex_adapter va(path);
|
||||
line_clipper clipped(va);
|
||||
clipped.clip_box(bbox.minx(),bbox.miny(),bbox.maxx(),bbox.maxy());
|
||||
return dump_path(clipped);
|
||||
}
|
||||
|
||||
void parse_geom(mapnik::path_type & path,
|
||||
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))
|
||||
{
|
||||
path.push_vertex(x,y,(mapnik::CommandType)c);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error(std::string("could not parse geometry '") + geom_string + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("clipping") {
|
||||
|
||||
SECTION("lines") {
|
||||
|
||||
try {
|
||||
|
||||
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::path_type path;
|
||||
parse_geom(path, parts[1]);
|
||||
//std::clog << dump_path(path) << "\n";
|
||||
// third part is expected, clipped geometry
|
||||
REQUIRE(clip_line(bbox, path) == mapnik::util::trim_copy(parts[2]));
|
||||
}
|
||||
stream.close();
|
||||
}
|
||||
catch (std::exception const& ex)
|
||||
{
|
||||
std::cerr << ex.what() << "\n";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
300
tests/cxx/conversions_test.cpp
Normal file
300
tests/cxx/conversions_test.cpp
Normal file
|
@ -0,0 +1,300 @@
|
|||
#include "catch.hpp"
|
||||
|
||||
#include <mapnik/value_types.hpp>
|
||||
#include <mapnik/value.hpp>
|
||||
#include <mapnik/util/conversions.hpp>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
#include <cstdio>
|
||||
#endif
|
||||
|
||||
TEST_CASE("conversions") {
|
||||
|
||||
SECTION("to string") {
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
unsigned int old = _set_output_format(_TWO_DIGIT_EXPONENT);
|
||||
#endif
|
||||
|
||||
using mapnik::util::to_string;
|
||||
using mapnik::util::string2bool;
|
||||
|
||||
try
|
||||
{
|
||||
std::string out;
|
||||
|
||||
// Test double
|
||||
to_string(out, double(0));
|
||||
REQUIRE( out == "0" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(1));
|
||||
REQUIRE( out == "1" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(-1));
|
||||
REQUIRE( out == "-1" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(0.1));
|
||||
REQUIRE( out == "0.1" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(-0.1));
|
||||
REQUIRE( out == "-0.1" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(0.123));
|
||||
REQUIRE( out == "0.123" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(-0.123));
|
||||
REQUIRE( out == "-0.123" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(1e-06));
|
||||
REQUIRE( out == "1e-06" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(-1e-06));
|
||||
REQUIRE( out == "-1e-06" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(1e-05));
|
||||
REQUIRE( out == "1e-05" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(-1e-05));
|
||||
REQUIRE( out == "-1e-05" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(0.0001));
|
||||
REQUIRE( out == "0.0001" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(-0.0001));
|
||||
REQUIRE( out == "-0.0001" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(0.0001));
|
||||
REQUIRE( out == "0.0001" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(0.00001));
|
||||
REQUIRE( out == "1e-05" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(0.000001));
|
||||
REQUIRE( out == "1e-06" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(0.0000001));
|
||||
REQUIRE( out == "1e-07" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(0.00000001));
|
||||
REQUIRE( out == "1e-08" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(0.000000001));
|
||||
REQUIRE( out == "1e-09" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(0.0000000001));
|
||||
REQUIRE( out == "1e-10" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(-1.234e+16));
|
||||
REQUIRE( out == "-1.234e+16" );
|
||||
out.clear();
|
||||
|
||||
// critical failure when karam is used
|
||||
// https://github.com/mapnik/mapnik/issues/1741
|
||||
// https://github.com/mapbox/tilemill/issues/1456
|
||||
to_string(out, double(8.3));
|
||||
REQUIRE( out == "8.3" );
|
||||
out.clear();
|
||||
|
||||
// non-critical failures if karma is used
|
||||
to_string(out, double(0.0001234567890123456));
|
||||
// TODO: https://github.com/mapnik/mapnik/issues/1676
|
||||
REQUIRE( out == "0.000123457" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(0.00000000001));
|
||||
REQUIRE( out == "1e-11" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(0.000000000001));
|
||||
REQUIRE( out == "1e-12" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(0.0000000000001));
|
||||
REQUIRE( out == "1e-13" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(0.00000000000001));
|
||||
REQUIRE( out == "1e-14" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(0.000000000000001));
|
||||
REQUIRE( out == "1e-15" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(100000));
|
||||
REQUIRE( out == "100000" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(1000000));
|
||||
REQUIRE( out == "1e+06" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(10000000));
|
||||
REQUIRE( out == "1e+07" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(100000000));
|
||||
REQUIRE( out == "1e+08" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(1000000000));
|
||||
REQUIRE( out == "1e+09" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(10000000000));
|
||||
REQUIRE( out == "1e+10" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(100000000000));
|
||||
REQUIRE( out == "1e+11" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(1000000000000));
|
||||
REQUIRE( out == "1e+12" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(10000000000000));
|
||||
REQUIRE( out == "1e+13" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(100000000000000));
|
||||
REQUIRE( out == "1e+14" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(1000000000000005));
|
||||
REQUIRE( out == "1e+15" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(-1000000000000000));
|
||||
REQUIRE( out == "-1e+15" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(100000000000000.1));
|
||||
REQUIRE( out == "1e+14" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(1.00001));
|
||||
REQUIRE( out == "1.00001" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(67.65));
|
||||
REQUIRE( out == "67.65" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(67.35));
|
||||
REQUIRE( out == "67.35" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(1234000000000000));
|
||||
REQUIRE( out == "1.234e+15" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(1e+16));
|
||||
REQUIRE( out == "1e+16" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(1.234e+16));
|
||||
REQUIRE( out == "1.234e+16" );
|
||||
out.clear();
|
||||
|
||||
// int
|
||||
to_string(out, int(2));
|
||||
REQUIRE( out == "2" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, int(0));
|
||||
REQUIRE( out == "0" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, int(-2));
|
||||
REQUIRE( out == "-2" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, int(2147483647));
|
||||
REQUIRE( out == "2147483647" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, int(-2147483648));
|
||||
REQUIRE( out == "-2147483648" );
|
||||
out.clear();
|
||||
|
||||
// unsigned
|
||||
to_string(out, unsigned(4294967295));
|
||||
REQUIRE( out == "4294967295" );
|
||||
out.clear();
|
||||
|
||||
#ifdef BIGINT
|
||||
// long long
|
||||
to_string(out,mapnik::value_integer(-0));
|
||||
REQUIRE( out == "0" );
|
||||
out.clear();
|
||||
|
||||
to_string(out,mapnik::value_integer(-2));
|
||||
REQUIRE( out == "-2" );
|
||||
out.clear();
|
||||
|
||||
to_string(out,mapnik::value_integer(9223372036854775807));
|
||||
REQUIRE( out == "9223372036854775807" );
|
||||
out.clear();
|
||||
#else
|
||||
#ifdef _MSC_VER
|
||||
#pragma NOTE("BIGINT not defined so skipping large number conversion tests")
|
||||
#else
|
||||
#warning BIGINT not defined so skipping large number conversion tests
|
||||
#endif
|
||||
#endif
|
||||
// bool
|
||||
to_string(out, true);
|
||||
REQUIRE( out == "true" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, false);
|
||||
REQUIRE( out == "false" );
|
||||
out.clear();
|
||||
|
||||
bool val = false;
|
||||
REQUIRE( !string2bool("this is invalid",val) );
|
||||
REQUIRE( val == false );
|
||||
REQUIRE( string2bool("true",val) );
|
||||
REQUIRE( val == true );
|
||||
|
||||
// mapnik::value hashability
|
||||
using values_container = boost::unordered_map<mapnik::value, unsigned>;
|
||||
values_container vc;
|
||||
mapnik::value val2(1);
|
||||
vc[val2] = 1;
|
||||
REQUIRE( vc[1] == static_cast<int>(1) );
|
||||
|
||||
}
|
||||
catch (std::exception const & ex)
|
||||
{
|
||||
std::clog << ex.what() << "\n";
|
||||
REQUIRE(false);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
83
tests/cxx/copy_move_test.cpp
Normal file
83
tests/cxx/copy_move_test.cpp
Normal file
|
@ -0,0 +1,83 @@
|
|||
|
||||
#include <mapnik/layer.hpp>
|
||||
#include <mapnik/map.hpp>
|
||||
#include <mapnik/color.hpp>
|
||||
#include <mapnik/datasource.hpp>
|
||||
#include <mapnik/datasource_cache.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#include "catch.hpp"
|
||||
|
||||
|
||||
TEST_CASE("copy") {
|
||||
|
||||
SECTION("layers") {
|
||||
|
||||
try
|
||||
{
|
||||
mapnik::Map m0(100,100);
|
||||
mapnik::Map m2(200,100);
|
||||
// FIXME: not compiling when ported to catch.hpp
|
||||
// due to some conflict: 'include/mapnik/value.hpp:832:11: error: no matching constructor for initialization of 'value_base''
|
||||
/*
|
||||
|
||||
// mapnik::datasource
|
||||
mapnik::datasource_cache::instance().register_datasources("plugins/input/shape.input");
|
||||
mapnik::parameters p;
|
||||
p["type"]="shape";
|
||||
p["file"]="demo/data/boundaries";
|
||||
p["encoding"]="latin1";
|
||||
auto ds0 = mapnik::datasource_cache::instance().create(p);
|
||||
|
||||
auto ds1 = ds0; // shared ptr copy
|
||||
REQUIRE(ds1 == ds0);
|
||||
//REQUIRE(*ds1 == *ds0);
|
||||
ds1 = mapnik::datasource_cache::instance().create(p); // new with the same parameters
|
||||
REQUIRE(ds1 != ds0);
|
||||
REQUIRE(*ds1 == *ds0);
|
||||
auto ds2 = std::move(ds1);
|
||||
REQUIRE(ds2 != ds0);
|
||||
REQUIRE(*ds2 == *ds0);
|
||||
|
||||
// mapnik::layer
|
||||
mapnik::layer l0("test-layer");
|
||||
l0.set_datasource(ds0);
|
||||
|
||||
mapnik::layer l1 = l0; // copy assignment
|
||||
REQUIRE(l1 == l0);
|
||||
mapnik::layer l2(l0); // copy ctor
|
||||
REQUIRE(l2 == l0);
|
||||
mapnik::layer l3(mapnik::layer("test-layer")); // move ctor
|
||||
l3.set_datasource(ds2);
|
||||
|
||||
REQUIRE(l3 == l0);
|
||||
mapnik::layer l4 = std::move(l3);
|
||||
REQUIRE(l4 == l0); // move assignment
|
||||
|
||||
m0.add_layer(l4);
|
||||
m0.set_background(mapnik::color("skyblue"));
|
||||
m2.set_background(mapnik::color("skyblue"));
|
||||
|
||||
auto m1 = m0; //copy
|
||||
|
||||
REQUIRE(m0 == m1);
|
||||
REQUIRE(m0 != m2);
|
||||
|
||||
m2 = m1; // copy
|
||||
REQUIRE(m2 == m1);
|
||||
m2 = std::move(m1);
|
||||
REQUIRE(m2 == m0);
|
||||
REQUIRE(m1 != m0);
|
||||
|
||||
REQUIRE(m0 == m2);
|
||||
*/
|
||||
}
|
||||
catch (std::exception const & ex)
|
||||
{
|
||||
std::clog << ex.what() << "\n";
|
||||
REQUIRE(false);
|
||||
}
|
||||
}
|
||||
}
|
103
tests/cxx/exceptions_test.cpp
Normal file
103
tests/cxx/exceptions_test.cpp
Normal file
|
@ -0,0 +1,103 @@
|
|||
#include "catch.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <mapnik/projection.hpp>
|
||||
#include <mapnik/unicode.hpp>
|
||||
#include <mapnik/map.hpp>
|
||||
#include <mapnik/save_map.hpp>
|
||||
#include <mapnik/feature.hpp>
|
||||
#include <mapnik/memory_datasource.hpp>
|
||||
#include <mapnik/feature_type_style.hpp>
|
||||
#include <mapnik/feature_factory.hpp>
|
||||
#include <mapnik/rule.hpp>
|
||||
#include <mapnik/expression.hpp>
|
||||
#include <mapnik/layer.hpp>
|
||||
#include <mapnik/agg_renderer.hpp>
|
||||
#include <mapnik/config_error.hpp>
|
||||
#include <mapnik/datasource_cache.hpp>
|
||||
#include <mapnik/params.hpp>
|
||||
#include <mapnik/util/fs.hpp>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
TEST_CASE("exceptions") {
|
||||
|
||||
SECTION("handling") {
|
||||
try {
|
||||
mapnik::projection srs("foo");
|
||||
// to avoid unused variable warning
|
||||
srs.params();
|
||||
REQUIRE(false);
|
||||
} catch (...) {
|
||||
REQUIRE(true);
|
||||
}
|
||||
|
||||
// https://github.com/mapnik/mapnik/issues/2170
|
||||
try {
|
||||
mapnik::projection srs("+proj=longlat foo",true);
|
||||
REQUIRE(srs.is_geographic());
|
||||
REQUIRE(true);
|
||||
srs.init_proj4();
|
||||
// oddly init_proj4 does not throw with old proj/ubuntu precise
|
||||
//REQUIRE(false);
|
||||
} catch (...) {
|
||||
REQUIRE(true);
|
||||
}
|
||||
|
||||
try {
|
||||
mapnik::transcoder tr("bogus encoding");
|
||||
REQUIRE(false);
|
||||
} catch (...) {
|
||||
REQUIRE(true);
|
||||
}
|
||||
|
||||
mapnik::Map map(256,256);
|
||||
mapnik::rule r;
|
||||
r.set_filter(mapnik::parse_expression("[foo]='bar'"));
|
||||
r.append(std::move(mapnik::markers_symbolizer()));
|
||||
mapnik::feature_type_style style;
|
||||
style.add_rule(std::move(r));
|
||||
map.insert_style("style", std::move(style));
|
||||
|
||||
std::string csv_plugin("./plugins/input/csv.input");
|
||||
if (mapnik::util::exists(csv_plugin)) {
|
||||
try {
|
||||
mapnik::datasource_cache::instance().register_datasource(csv_plugin);
|
||||
mapnik::parameters p;
|
||||
p["type"]="csv";
|
||||
p["inline"]="x,y\n0,0";
|
||||
mapnik::datasource_ptr ds = mapnik::datasource_cache::instance().create(p);
|
||||
mapnik::layer l("layer");
|
||||
l.set_datasource(ds);
|
||||
l.add_style("style");
|
||||
mapnik::Map m = map;
|
||||
m.add_layer(l);
|
||||
m.zoom_all();
|
||||
mapnik::image_rgba8 im(m.width(),m.height());
|
||||
mapnik::agg_renderer<mapnik::image_rgba8> ren(m,im);
|
||||
//std::clog << mapnik::save_map_to_string(m) << "\n";
|
||||
REQUIRE(true);
|
||||
// should throw here with "CSV Plugin: no attribute 'foo'. Valid attributes are: x,y."
|
||||
ren.apply();
|
||||
REQUIRE(false);
|
||||
} catch (...) {
|
||||
REQUIRE(true);
|
||||
}
|
||||
}
|
||||
|
||||
std::string shape_plugin("./plugins/input/shape.input");
|
||||
if (mapnik::util::exists(shape_plugin)) {
|
||||
try {
|
||||
mapnik::datasource_cache::instance().register_datasource(shape_plugin);
|
||||
mapnik::parameters p2;
|
||||
p2["type"]="shape";
|
||||
p2["file"]="foo";
|
||||
mapnik::datasource_cache::instance().create(p2);
|
||||
REQUIRE(false);
|
||||
} catch (...) {
|
||||
REQUIRE(true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
192
tests/cxx/font_registration_test.cpp
Normal file
192
tests/cxx/font_registration_test.cpp
Normal file
|
@ -0,0 +1,192 @@
|
|||
#include "catch.hpp"
|
||||
|
||||
#include <mapnik/font_engine_freetype.hpp>
|
||||
#include <mapnik/util/fs.hpp>
|
||||
#include <mapnik/map.hpp>
|
||||
#include <mapnik/load_map.hpp>
|
||||
#include <mapnik/debug.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
TEST_CASE("font") {
|
||||
|
||||
SECTION("registration") {
|
||||
try
|
||||
{
|
||||
mapnik::logger logger;
|
||||
mapnik::logger::severity_type original_severity = logger.get_severity();
|
||||
|
||||
|
||||
|
||||
// grab references to global statics of registered/cached fonts
|
||||
auto const& global_mapping = mapnik::freetype_engine::get_mapping();
|
||||
auto const& global_cache = mapnik::freetype_engine::get_cache();
|
||||
|
||||
// mapnik.Map object has parallel structure for localized fonts
|
||||
mapnik::Map m(1,1);
|
||||
auto const& local_mapping = m.get_font_file_mapping();
|
||||
auto const& local_cache = m.get_font_memory_cache();
|
||||
|
||||
// should be empty to start
|
||||
REQUIRE( global_mapping.empty() );
|
||||
REQUIRE( global_cache.empty() );
|
||||
REQUIRE( local_mapping.empty() );
|
||||
REQUIRE( local_cache.empty() );
|
||||
|
||||
std::string fontdir("fonts/");
|
||||
|
||||
REQUIRE( mapnik::util::exists( fontdir ) );
|
||||
REQUIRE( mapnik::util::is_directory( fontdir ) );
|
||||
|
||||
// test map cached fonts
|
||||
REQUIRE( m.register_fonts(fontdir , false ) );
|
||||
REQUIRE( m.get_font_memory_cache().size() == 0 );
|
||||
REQUIRE( m.get_font_file_mapping().size() == 1 );
|
||||
REQUIRE( m.load_fonts() );
|
||||
REQUIRE( m.get_font_memory_cache().size() == 1 );
|
||||
REQUIRE( m.register_fonts(fontdir , true ) );
|
||||
REQUIRE( m.get_font_file_mapping().size() == 22 );
|
||||
REQUIRE( m.load_fonts() );
|
||||
REQUIRE( m.get_font_memory_cache().size() == 22 );
|
||||
|
||||
// copy discards memory cache but not file mapping
|
||||
mapnik::Map m2(m);
|
||||
REQUIRE( m2.get_font_memory_cache().size() == 0 );
|
||||
REQUIRE( m2.get_font_file_mapping().size() == 22 );
|
||||
REQUIRE( m2.load_fonts() );
|
||||
REQUIRE( m2.get_font_memory_cache().size() == 22 );
|
||||
|
||||
// test font-directory from XML
|
||||
mapnik::Map m3(1,1);
|
||||
mapnik::load_map_string(m3,"<Map font-directory=\"fonts/\"></Map>");
|
||||
REQUIRE( m3.get_font_memory_cache().size() == 0 );
|
||||
REQUIRE( m3.load_fonts() );
|
||||
REQUIRE( m3.get_font_memory_cache().size() == 1 );
|
||||
|
||||
std::vector<std::string> face_names;
|
||||
std::string foo("foo");
|
||||
// fake directories
|
||||
REQUIRE( !mapnik::freetype_engine::register_fonts(foo , true ) );
|
||||
face_names = mapnik::freetype_engine::face_names();
|
||||
REQUIRE( face_names.size() == 0 );
|
||||
REQUIRE( !mapnik::freetype_engine::register_fonts(foo) );
|
||||
face_names = mapnik::freetype_engine::face_names();
|
||||
REQUIRE( face_names.size() == 0 );
|
||||
|
||||
// directories without fonts
|
||||
// silence warnings here by altering the logging severity
|
||||
logger.set_severity(mapnik::logger::none);
|
||||
std::string src("src");
|
||||
// an empty directory will not return true
|
||||
// we need to register at least one font and not fail on any
|
||||
// to return true
|
||||
REQUIRE( mapnik::freetype_engine::register_font(src) == false );
|
||||
REQUIRE( mapnik::freetype_engine::register_fonts(src, true) == false );
|
||||
REQUIRE( mapnik::freetype_engine::face_names().size() == 0 );
|
||||
|
||||
// bogus, emtpy file that looks like font
|
||||
REQUIRE( mapnik::freetype_engine::register_font("tests/data/fonts/fake.ttf") == false );
|
||||
REQUIRE( mapnik::freetype_engine::register_fonts("tests/data/fonts/fake.ttf") == false );
|
||||
REQUIRE( mapnik::freetype_engine::face_names().size() == 0 );
|
||||
|
||||
REQUIRE( mapnik::freetype_engine::register_font("tests/data/fonts/intentionally-broken.ttf") == false );
|
||||
REQUIRE( mapnik::freetype_engine::register_fonts("tests/data/fonts/intentionally-broken.ttf") == false );
|
||||
REQUIRE( mapnik::freetype_engine::face_names().size() == 0 );
|
||||
|
||||
// now restore the original severity
|
||||
logger.set_severity(original_severity);
|
||||
|
||||
// register unifont, since we know it sits in the root fonts/ dir
|
||||
REQUIRE( mapnik::freetype_engine::register_fonts(fontdir) );
|
||||
face_names = mapnik::freetype_engine::face_names();
|
||||
REQUIRE( face_names.size() > 0 );
|
||||
REQUIRE( face_names.size() == 1 );
|
||||
|
||||
// re-register unifont, should not have any affect
|
||||
REQUIRE( mapnik::freetype_engine::register_fonts(fontdir, false) );
|
||||
face_names = mapnik::freetype_engine::face_names();
|
||||
REQUIRE( face_names.size() == 1 );
|
||||
|
||||
// single dejavu font in separate location
|
||||
std::string dejavu_bold_oblique("tests/data/fonts/DejaVuSansMono-BoldOblique.ttf");
|
||||
REQUIRE( mapnik::freetype_engine::register_font(dejavu_bold_oblique) );
|
||||
face_names = mapnik::freetype_engine::face_names();
|
||||
REQUIRE( face_names.size() == 2 );
|
||||
|
||||
// now, inspect font mapping and confirm the correct 'DejaVu Sans Mono Bold Oblique' is registered
|
||||
using font_file_mapping = std::map<std::string, std::pair<int,std::string> >;
|
||||
font_file_mapping const& name2file = mapnik::freetype_engine::get_mapping();
|
||||
bool found_dejavu = false;
|
||||
for (auto const& item : name2file)
|
||||
{
|
||||
if (item.first == "DejaVu Sans Mono Bold Oblique")
|
||||
{
|
||||
found_dejavu = true;
|
||||
REQUIRE( item.second.first == 0 );
|
||||
REQUIRE( item.second.second == dejavu_bold_oblique );
|
||||
}
|
||||
}
|
||||
REQUIRE( found_dejavu );
|
||||
|
||||
// recurse to find all dejavu fonts
|
||||
REQUIRE( mapnik::freetype_engine::register_fonts(fontdir, true) );
|
||||
face_names = mapnik::freetype_engine::face_names();
|
||||
REQUIRE( face_names.size() == 22 );
|
||||
|
||||
// we should have re-registered 'DejaVu Sans Mono Bold Oblique' again,
|
||||
// but now at a new path
|
||||
bool found_dejavu2 = false;
|
||||
for (auto const& item : name2file)
|
||||
{
|
||||
if (item.first == "DejaVu Sans Mono Bold Oblique")
|
||||
{
|
||||
found_dejavu2 = true;
|
||||
REQUIRE( item.second.first == 0 );
|
||||
// path should be different
|
||||
REQUIRE( item.second.second != dejavu_bold_oblique );
|
||||
}
|
||||
}
|
||||
REQUIRE( found_dejavu2 );
|
||||
|
||||
// now that global registry is populated
|
||||
// now test that a map only loads new fonts
|
||||
mapnik::Map m4(1,1);
|
||||
REQUIRE( m4.register_fonts(fontdir , true ) );
|
||||
REQUIRE( m4.get_font_memory_cache().size() == 0 );
|
||||
REQUIRE( m4.get_font_file_mapping().size() == 22 );
|
||||
REQUIRE( !m4.load_fonts() );
|
||||
REQUIRE( m4.get_font_memory_cache().size() == 0 );
|
||||
REQUIRE( m4.register_fonts(dejavu_bold_oblique, false) );
|
||||
REQUIRE( m4.load_fonts() );
|
||||
REQUIRE( m4.get_font_memory_cache().size() == 1 );
|
||||
|
||||
// check that we can correctly read a .ttc containing
|
||||
// multiple valid faces
|
||||
// https://github.com/mapnik/mapnik/issues/2274
|
||||
REQUIRE( mapnik::freetype_engine::register_font("tests/data/fonts/NotoSans-Regular.ttc") );
|
||||
face_names = mapnik::freetype_engine::face_names();
|
||||
REQUIRE( face_names.size() == 24 );
|
||||
|
||||
// now blindly register as many system fonts as possible
|
||||
// the goal here to make sure we don't crash
|
||||
// linux
|
||||
mapnik::freetype_engine::register_fonts("/usr/share/fonts/", true);
|
||||
mapnik::freetype_engine::register_fonts("/usr/local/share/fonts/", true);
|
||||
// osx
|
||||
mapnik::freetype_engine::register_fonts("/Library/Fonts/", true);
|
||||
mapnik::freetype_engine::register_fonts("/System/Library/Fonts/", true);
|
||||
// windows
|
||||
mapnik::freetype_engine::register_fonts("C:\\Windows\\Fonts", true);
|
||||
face_names = mapnik::freetype_engine::face_names();
|
||||
REQUIRE( face_names.size() > 22 );
|
||||
}
|
||||
catch (std::exception const & ex)
|
||||
{
|
||||
std::clog << ex.what() << "\n";
|
||||
REQUIRE(false);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
85
tests/cxx/fontset_runtime_test.cpp
Normal file
85
tests/cxx/fontset_runtime_test.cpp
Normal file
|
@ -0,0 +1,85 @@
|
|||
#include "catch.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <mapnik/memory_datasource.hpp>
|
||||
#include <mapnik/datasource_cache.hpp>
|
||||
#include <mapnik/feature.hpp>
|
||||
#include <mapnik/feature_factory.hpp>
|
||||
#include <mapnik/unicode.hpp>
|
||||
#include <mapnik/map.hpp>
|
||||
#include <mapnik/params.hpp>
|
||||
#include <mapnik/expression.hpp>
|
||||
#include <mapnik/layer.hpp>
|
||||
#include <mapnik/rule.hpp>
|
||||
#include <mapnik/feature_type_style.hpp>
|
||||
#include <mapnik/agg_renderer.hpp>
|
||||
#include <mapnik/image_util.hpp>
|
||||
#include <mapnik/color_factory.hpp>
|
||||
#include <mapnik/save_map.hpp>
|
||||
#include <mapnik/value_types.hpp>
|
||||
#include <mapnik/symbolizer.hpp>
|
||||
#include <mapnik/text/placements/dummy.hpp>
|
||||
#include <mapnik/text/formatting/text.hpp>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <mapnik/make_unique.hpp>
|
||||
|
||||
// icu - for memory cleanup (to make valgrind happy)
|
||||
#include "unicode/uclean.h"
|
||||
|
||||
TEST_CASE("fontset") {
|
||||
|
||||
SECTION("error") {
|
||||
|
||||
try {
|
||||
|
||||
// create a renderable map with a fontset and a text symbolizer
|
||||
// and do not register any fonts, to ensure the error thrown is reasonable
|
||||
mapnik::context_ptr ctx = std::make_shared<mapnik::context_type>();
|
||||
ctx->push("name");
|
||||
mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx,1));
|
||||
mapnik::transcoder tr("utf-8");
|
||||
mapnik::value_unicode_string ustr = tr.transcode("hello world!");
|
||||
feature->put("name",ustr);
|
||||
//auto pt = std::make_unique<mapnik::geometry_type>(mapnik::geometry::geometry_types::Point);
|
||||
//pt->move_to(128,128);
|
||||
mapnik::geometry::point<double> pt(128,128);
|
||||
feature->set_geometry(std::move(pt));
|
||||
|
||||
mapnik::parameters params;
|
||||
params["type"]="memory";
|
||||
auto ds = std::make_shared<mapnik::memory_datasource>(params);
|
||||
ds->push(feature);
|
||||
mapnik::Map m(256,256);
|
||||
mapnik::font_set fontset("fontset");
|
||||
// NOTE: this is a valid font, but will fail because none are registered
|
||||
fontset.add_face_name("DejaVu Sans Book");
|
||||
m.insert_fontset("fontset", fontset);
|
||||
mapnik::layer lyr("layer");
|
||||
lyr.set_datasource(ds);
|
||||
lyr.add_style("style");
|
||||
m.add_layer(lyr);
|
||||
mapnik::feature_type_style the_style;
|
||||
mapnik::rule r;
|
||||
mapnik::text_symbolizer text_sym;
|
||||
mapnik::text_placements_ptr placement_finder = std::make_shared<mapnik::text_placements_dummy>();
|
||||
placement_finder->defaults.format_defaults.face_name = "DejaVu Sans Book";
|
||||
placement_finder->defaults.format_defaults.text_size = 10.0;
|
||||
placement_finder->defaults.format_defaults.fill = mapnik::color(0,0,0);
|
||||
placement_finder->defaults.format_defaults.fontset = fontset;
|
||||
placement_finder->defaults.set_format_tree(std::make_shared<mapnik::formatting::text_node>(mapnik::parse_expression("[name]")));
|
||||
mapnik::put<mapnik::text_placements_ptr>(text_sym, mapnik::keys::text_placements_, placement_finder);
|
||||
r.append(std::move(text_sym));
|
||||
the_style.add_rule(std::move(r));
|
||||
m.insert_style("style", std::move(the_style) );
|
||||
m.zoom_to_box(mapnik::box2d<double>(-256,-256,
|
||||
256,256));
|
||||
mapnik::image_rgba8 buf(m.width(),m.height());
|
||||
mapnik::agg_renderer<mapnik::image_rgba8> ren(m,buf);
|
||||
ren.apply();
|
||||
} catch (std::exception const& ex) {
|
||||
REQUIRE(std::string(ex.what()) == std::string("Unable to find specified font face 'DejaVu Sans Book' in font set: 'fontset'"));
|
||||
}
|
||||
u_cleanup();
|
||||
}
|
||||
}
|
192
tests/cxx/geometry_converters_test.cpp
Normal file
192
tests/cxx/geometry_converters_test.cpp
Normal file
|
@ -0,0 +1,192 @@
|
|||
#include "catch.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#include <mapnik/layer.hpp>
|
||||
#include <mapnik/feature_type_style.hpp>
|
||||
#include <mapnik/rule.hpp>
|
||||
#include <mapnik/debug.hpp>
|
||||
#include <mapnik/view_transform.hpp>
|
||||
#include <mapnik/feature.hpp>
|
||||
#include <mapnik/vertex_converters.hpp>
|
||||
#include <mapnik/wkt/wkt_factory.hpp>
|
||||
#include <mapnik/well_known_srs.hpp>
|
||||
#include <mapnik/wkt/wkt_generator_grammar.hpp>
|
||||
#include <mapnik/projection.hpp>
|
||||
#include <mapnik/proj_transform.hpp>
|
||||
|
||||
// stl
|
||||
#include <stdexcept>
|
||||
#if 0 // FIXME
|
||||
struct output_geometry_backend
|
||||
{
|
||||
output_geometry_backend(mapnik::geometry_container & paths, mapnik::geometry_type::types type)
|
||||
: paths_(paths),
|
||||
type_(type) {}
|
||||
|
||||
template <typename T>
|
||||
void add_path(T & path)
|
||||
{
|
||||
mapnik::vertex2d vtx(mapnik::vertex2d::no_init);
|
||||
path.rewind(0);
|
||||
std::unique_ptr<mapnik::geometry_type> geom_ptr(new mapnik::geometry_type(type_));
|
||||
|
||||
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);
|
||||
}
|
||||
paths_.push_back(geom_ptr.release());
|
||||
}
|
||||
mapnik::geometry_container & paths_;
|
||||
mapnik::geometry_type::types type_;
|
||||
};
|
||||
|
||||
boost::optional<std::string> linestring_bbox_clipping(mapnik::box2d<double> bbox,
|
||||
std::string wkt_in)
|
||||
{
|
||||
using namespace mapnik;
|
||||
agg::trans_affine tr;
|
||||
projection src(MAPNIK_LONGLAT_PROJ);
|
||||
projection dst(MAPNIK_LONGLAT_PROJ);
|
||||
proj_transform prj_trans(src,dst);
|
||||
line_symbolizer sym;
|
||||
view_transform t(bbox.width(),bbox.height(), bbox);
|
||||
mapnik::geometry_container output_paths;
|
||||
output_geometry_backend backend(output_paths, mapnik::geometry::geometry_types::LineString);
|
||||
|
||||
mapnik::context_ptr ctx = std::make_shared<mapnik::context_type>();
|
||||
mapnik::feature_impl f(ctx,0);
|
||||
vertex_converter<output_geometry_backend,clip_line_tag>
|
||||
converter(bbox, backend, sym, t, prj_trans, tr, f, attributes(), 1.0);
|
||||
|
||||
converter.set<clip_line_tag>();
|
||||
|
||||
mapnik::geometry_container p;
|
||||
if (!mapnik::from_wkt(wkt_in , p))
|
||||
{
|
||||
throw std::runtime_error("Failed to parse WKT");
|
||||
}
|
||||
|
||||
for (geometry_type const& geom : p)
|
||||
{
|
||||
vertex_adapter va(geom);
|
||||
converter.apply(va);
|
||||
}
|
||||
|
||||
using sink_type = std::back_insert_iterator<std::string>;
|
||||
std::string wkt;
|
||||
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))
|
||||
{
|
||||
return boost::optional<std::string>(wkt);
|
||||
}
|
||||
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;
|
||||
projection src(MAPNIK_LONGLAT_PROJ);
|
||||
projection dst(MAPNIK_LONGLAT_PROJ);
|
||||
proj_transform prj_trans(src,dst);
|
||||
polygon_symbolizer sym;
|
||||
view_transform t(bbox.width(),bbox.height(), bbox);
|
||||
mapnik::geometry_container output_paths;
|
||||
output_geometry_backend backend(output_paths, mapnik::geometry::geometry_types::Polygon);
|
||||
|
||||
mapnik::context_ptr ctx = std::make_shared<mapnik::context_type>();
|
||||
mapnik::feature_impl f(ctx,0);
|
||||
vertex_converter<output_geometry_backend, clip_poly_tag>
|
||||
converter(bbox, backend, sym, t, prj_trans, tr, f, attributes(), 1.0);
|
||||
|
||||
converter.set<clip_poly_tag>();
|
||||
|
||||
mapnik::geometry_container p;
|
||||
if (!mapnik::from_wkt(wkt_in , p))
|
||||
{
|
||||
throw std::runtime_error("Failed to parse WKT");
|
||||
}
|
||||
|
||||
for (geometry_type const& geom : p)
|
||||
{
|
||||
vertex_adapter va(geom);
|
||||
converter.apply(va);
|
||||
}
|
||||
|
||||
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))
|
||||
{
|
||||
return boost::optional<std::string>(wkt);
|
||||
}
|
||||
|
||||
return boost::optional<std::string>();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
TEST_CASE("geometry converters") {
|
||||
|
||||
SECTION("TODO") {
|
||||
|
||||
try
|
||||
{
|
||||
#if 0
|
||||
// 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);
|
||||
REQUIRE(result);
|
||||
REQUIRE(*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);
|
||||
REQUIRE(result);
|
||||
// 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
|
||||
REQUIRE(*result == std::string("Polygon((50 50,150 50,150 150,50 150,50 50,50 50))"));
|
||||
// below is ideal, but not current result
|
||||
//REQUIRE(*result == std::string("Polygon((50 50,150 50,150 150,50 150,50 50))"));
|
||||
}
|
||||
|
||||
{
|
||||
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);
|
||||
REQUIRE(result);
|
||||
REQUIRE(*result == std::string("Polygon((60 60,140 60,140 150,100 150,60 140,60 60,60 60))"));
|
||||
//REQUIRE(*result == std::string("Polygon((60 60,140 60,140 160,60 140,60 60))"));
|
||||
}
|
||||
|
||||
{
|
||||
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);
|
||||
REQUIRE(result);
|
||||
// TODO - this is completely wrong: should not have )) and ideally should be EMPTY
|
||||
REQUIRE(*result == std::string("Polygon())"));
|
||||
}
|
||||
{
|
||||
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);
|
||||
REQUIRE(result);
|
||||
REQUIRE(*result == std::string("Polygon((50 50,50 100,75 150,125 150,150 100,150 50))"));
|
||||
//REQUIRE(*result == std::string("Polygon((50 50,50 100,75 150,125 150,150 100,150 50,50 50))"));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
catch (std::exception const & ex)
|
||||
{
|
||||
std::clog << ex.what() << "\n";
|
||||
REQUIRE(false);
|
||||
}
|
||||
}
|
||||
}
|
130
tests/cxx/image_io_test.cpp
Normal file
130
tests/cxx/image_io_test.cpp
Normal file
|
@ -0,0 +1,130 @@
|
|||
#include "catch.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <mapnik/image.hpp>
|
||||
#include <mapnik/image_reader.hpp>
|
||||
#include <mapnik/image_util.hpp>
|
||||
#include <mapnik/util/fs.hpp>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#if defined(HAVE_CAIRO)
|
||||
#include <mapnik/cairo/cairo_context.hpp>
|
||||
#include <mapnik/cairo/cairo_image_util.hpp>
|
||||
#endif
|
||||
|
||||
TEST_CASE("image io") {
|
||||
|
||||
SECTION("readers") {
|
||||
|
||||
std::string should_throw;
|
||||
boost::optional<std::string> type;
|
||||
try
|
||||
{
|
||||
#if defined(HAVE_JPEG)
|
||||
should_throw = "./tests/cpp_tests/data/blank.jpg";
|
||||
REQUIRE( mapnik::util::exists( should_throw ) );
|
||||
type = mapnik::type_from_filename(should_throw);
|
||||
REQUIRE( type );
|
||||
try
|
||||
{
|
||||
std::unique_ptr<mapnik::image_reader> reader(mapnik::get_image_reader(should_throw,*type));
|
||||
REQUIRE( false );
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
REQUIRE( true );
|
||||
}
|
||||
#endif
|
||||
|
||||
try
|
||||
{
|
||||
mapnik::image_rgba8 im(-10,-10); // should throw rather than overflow
|
||||
REQUIRE( im.width() < 10 ); // should not get here, but if we did this test should fail
|
||||
}
|
||||
catch (std::exception const& ex)
|
||||
{
|
||||
REQUIRE( true ); // should hit bad alloc here
|
||||
}
|
||||
|
||||
#if defined(HAVE_CAIRO)
|
||||
mapnik::cairo_surface_ptr image_surface(
|
||||
cairo_image_surface_create(CAIRO_FORMAT_ARGB32,256,257),
|
||||
mapnik::cairo_surface_closer());
|
||||
mapnik::image_rgba8 im_data(cairo_image_surface_get_width(&*image_surface), cairo_image_surface_get_height(&*image_surface));
|
||||
im_data.set(1);
|
||||
REQUIRE( (unsigned)im_data(0,0) == unsigned(1) );
|
||||
// Should set back to fully transparent
|
||||
mapnik::cairo_image_to_rgba8(im_data, image_surface);
|
||||
REQUIRE( (unsigned)im_data(0,0) == unsigned(0) );
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_PNG)
|
||||
should_throw = "./tests/cpp_tests/data/blank.png";
|
||||
REQUIRE( mapnik::util::exists( should_throw ) );
|
||||
type = mapnik::type_from_filename(should_throw);
|
||||
REQUIRE( type );
|
||||
try
|
||||
{
|
||||
std::unique_ptr<mapnik::image_reader> reader(mapnik::get_image_reader(should_throw,*type));
|
||||
REQUIRE( false );
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
REQUIRE( true );
|
||||
}
|
||||
|
||||
should_throw = "./tests/data/images/xcode-CgBI.png";
|
||||
REQUIRE( mapnik::util::exists( should_throw ) );
|
||||
type = mapnik::type_from_filename(should_throw);
|
||||
REQUIRE( type );
|
||||
try
|
||||
{
|
||||
std::unique_ptr<mapnik::image_reader> reader(mapnik::get_image_reader(should_throw,*type));
|
||||
REQUIRE( false );
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
REQUIRE( true );
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_TIFF)
|
||||
should_throw = "./tests/cpp_tests/data/blank.tiff";
|
||||
REQUIRE( mapnik::util::exists( should_throw ) );
|
||||
type = mapnik::type_from_filename(should_throw);
|
||||
REQUIRE( type );
|
||||
try
|
||||
{
|
||||
std::unique_ptr<mapnik::image_reader> reader(mapnik::get_image_reader(should_throw,*type));
|
||||
REQUIRE( false );
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
REQUIRE( true );
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_WEBP)
|
||||
should_throw = "./tests/cpp_tests/data/blank.webp";
|
||||
REQUIRE( mapnik::util::exists( should_throw ) );
|
||||
type = mapnik::type_from_filename(should_throw);
|
||||
REQUIRE( type );
|
||||
try
|
||||
{
|
||||
std::unique_ptr<mapnik::image_reader> reader(mapnik::get_image_reader(should_throw,*type));
|
||||
REQUIRE( false );
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
REQUIRE( true );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
catch (std::exception const & ex)
|
||||
{
|
||||
std::clog << ex.what() << "\n";
|
||||
REQUIRE(false);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
69
tests/cxx/image_painted_test.cpp
Normal file
69
tests/cxx/image_painted_test.cpp
Normal file
|
@ -0,0 +1,69 @@
|
|||
#include "catch.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <mapnik/map.hpp>
|
||||
#include <mapnik/layer.hpp>
|
||||
#include <mapnik/rule.hpp>
|
||||
#include <mapnik/feature_type_style.hpp>
|
||||
#include <mapnik/datasource_cache.hpp>
|
||||
#include <mapnik/agg_renderer.hpp>
|
||||
#include <mapnik/expression.hpp>
|
||||
|
||||
TEST_CASE("image") {
|
||||
|
||||
SECTION("painting") {
|
||||
|
||||
using namespace mapnik;
|
||||
|
||||
try
|
||||
{
|
||||
datasource_cache::instance().register_datasources("plugins/input/csv.input");
|
||||
|
||||
Map m(256, 256);
|
||||
|
||||
feature_type_style lines_style;
|
||||
{
|
||||
rule r;
|
||||
line_symbolizer line_sym;
|
||||
r.append(std::move(line_sym));
|
||||
lines_style.add_rule(std::move(r));
|
||||
}
|
||||
m.insert_style("lines", std::move(lines_style));
|
||||
|
||||
feature_type_style markers_style;
|
||||
{
|
||||
rule r;
|
||||
r.set_filter(parse_expression("False"));
|
||||
markers_symbolizer mark_sym;
|
||||
r.append(std::move(mark_sym));
|
||||
markers_style.add_rule(std::move(r));
|
||||
}
|
||||
m.insert_style("markers", std::move(markers_style));
|
||||
|
||||
parameters p;
|
||||
p["type"] = "csv";
|
||||
p["separator"] = "|";
|
||||
p["inline"] = "wkt\nLINESTRING(-10 0, 0 20, 10 0, 15 5)";
|
||||
|
||||
layer lyr("layer");
|
||||
lyr.set_datasource(datasource_cache::instance().create(p));
|
||||
lyr.add_style("lines");
|
||||
lyr.add_style("markers");
|
||||
m.add_layer(lyr);
|
||||
|
||||
m.zoom_all();
|
||||
|
||||
image_rgba8 image(m.width(), m.height());
|
||||
agg_renderer<image_rgba8> ren(m, image);
|
||||
ren.apply();
|
||||
|
||||
REQUIRE(image.painted() == true);
|
||||
}
|
||||
catch (std::exception const & ex)
|
||||
{
|
||||
std::clog << ex.what() << std::endl;
|
||||
REQUIRE(false);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
65
tests/cxx/label_algo_test.cpp
Normal file
65
tests/cxx/label_algo_test.cpp
Normal file
|
@ -0,0 +1,65 @@
|
|||
#include "catch.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <mapnik/geometry.hpp>
|
||||
#include <mapnik/geometry_adapters.hpp>
|
||||
#include <mapnik/geometry_centroid.hpp>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
TEST_CASE("labeling") {
|
||||
|
||||
SECTION("algorithms") {
|
||||
|
||||
try
|
||||
{
|
||||
// reused these for simplicity
|
||||
mapnik::geometry::point<double> centroid;
|
||||
{
|
||||
// single point
|
||||
mapnik::geometry::point<double> pt(10,10);
|
||||
REQUIRE( mapnik::geometry::centroid(pt, centroid));
|
||||
REQUIRE( pt.x == centroid.x);
|
||||
REQUIRE( pt.y == centroid.y);
|
||||
}
|
||||
|
||||
// linestring with three consecutive verticies
|
||||
{
|
||||
mapnik::geometry::line_string<double> line;
|
||||
line.add_coord(0, 0);
|
||||
line.add_coord(25, 25);
|
||||
line.add_coord(50, 50);
|
||||
REQUIRE(mapnik::geometry::centroid(line, centroid));
|
||||
REQUIRE( centroid.x == 25 );
|
||||
REQUIRE( centroid.y == 25 );
|
||||
}
|
||||
// TODO - centroid and interior should be equal but they appear not to be (check largest)
|
||||
// MULTIPOLYGON(((-52 40,-60 32,-68 40,-60 48,-52 40)),((-60 50,-80 30,-100 49.9999999999999,-80.0000000000001 70,-60 50)),((-52 60,-60 52,-68 60,-60 68,-52 60)))
|
||||
#if 0
|
||||
// hit tests
|
||||
{
|
||||
mapnik::geometry_type pt_hit(mapnik::geometry::geometry_types::Point);
|
||||
pt_hit.move_to(10,10);
|
||||
mapnik::vertex_adapter va(pt_hit);
|
||||
REQUIRE( mapnik::label::hit_test(va, 10, 10, 0.1) );
|
||||
REQUIRE( !mapnik::label::hit_test(va, 9, 9, 0) );
|
||||
REQUIRE( mapnik::label::hit_test(va, 9, 9, 1.5) );
|
||||
}
|
||||
{
|
||||
mapnik::geometry_type line_hit(mapnik::geometry::geometry_types::LineString);
|
||||
line_hit.move_to(0,0);
|
||||
line_hit.line_to(50,50);
|
||||
mapnik::vertex_adapter va(line_hit);
|
||||
REQUIRE( mapnik::label::hit_test(va, 0, 0, 0.001) );
|
||||
REQUIRE( !mapnik::label::hit_test(va, 1, 1, 0) );
|
||||
REQUIRE( mapnik::label::hit_test(va, 1, 1, 1.001) );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
catch (std::exception const & ex)
|
||||
{
|
||||
std::clog << ex.what() << "\n";
|
||||
REQUIRE(false);
|
||||
}
|
||||
}
|
||||
}
|
195
tests/cxx/line_offset_test.cpp
Normal file
195
tests/cxx/line_offset_test.cpp
Normal file
|
@ -0,0 +1,195 @@
|
|||
#include "catch.hpp"
|
||||
|
||||
// mapnik
|
||||
#include <mapnik/coord.hpp>
|
||||
#include <mapnik/vertex_cache.hpp>
|
||||
|
||||
// stl
|
||||
#include <stdexcept>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
#include <algorithm>
|
||||
|
||||
struct fake_path
|
||||
{
|
||||
using coord_type = std::tuple<double, double, unsigned>;
|
||||
using cont_type = std::vector<coord_type>;
|
||||
cont_type vertices_;
|
||||
cont_type::iterator itr_;
|
||||
|
||||
fake_path(std::initializer_list<double> l)
|
||||
: fake_path(l.begin(), l.size()) {
|
||||
}
|
||||
|
||||
fake_path(std::vector<double> const &v)
|
||||
: fake_path(v.begin(), v.size()) {
|
||||
}
|
||||
|
||||
template <typename Itr>
|
||||
fake_path(Itr itr, size_t sz) {
|
||||
size_t num_coords = sz >> 1;
|
||||
vertices_.reserve(num_coords);
|
||||
|
||||
for (size_t i = 0; i < num_coords; ++i) {
|
||||
double x = *itr++;
|
||||
double y = *itr++;
|
||||
unsigned cmd = (i == 0) ? agg::path_cmd_move_to : agg::path_cmd_line_to;
|
||||
vertices_.push_back(std::make_tuple(x, y, cmd));
|
||||
}
|
||||
itr_ = vertices_.begin();
|
||||
}
|
||||
|
||||
unsigned vertex(double *x, double *y) {
|
||||
if (itr_ == vertices_.end()) {
|
||||
return agg::path_cmd_stop;
|
||||
}
|
||||
*x = std::get<0>(*itr_);
|
||||
*y = std::get<1>(*itr_);
|
||||
unsigned cmd = std::get<2>(*itr_);
|
||||
++itr_;
|
||||
return cmd;
|
||||
}
|
||||
|
||||
void rewind(unsigned) {
|
||||
itr_ = vertices_.begin();
|
||||
}
|
||||
};
|
||||
|
||||
double dist(mapnik::pixel_position const &a,
|
||||
mapnik::pixel_position const &b)
|
||||
{
|
||||
mapnik::pixel_position d = a - b;
|
||||
return std::sqrt(d.x*d.x + d.y*d.y);
|
||||
}
|
||||
|
||||
void test_simple_segment(double const &offset)
|
||||
{
|
||||
const double dx = 0.01;
|
||||
fake_path path = {0, 0, 1, 0}, off_path = {0, offset, 1, offset};
|
||||
mapnik::vertex_cache vc(path), off_vc(off_path);
|
||||
|
||||
vc.reset(); vc.next_subpath();
|
||||
off_vc.reset(); off_vc.next_subpath();
|
||||
|
||||
while (vc.move(dx)) {
|
||||
double pos = vc.linear_position();
|
||||
double off_pos = off_vc.position_closest_to(vc.current_position());
|
||||
REQUIRE(std::abs(pos - off_pos) < 1.0e-6);
|
||||
}
|
||||
}
|
||||
|
||||
void test_straight_line(double const &offset) {
|
||||
const double dx = 0.01;
|
||||
fake_path path = {0, 0, 0.1, 0, 0.9, 0, 1, 0},
|
||||
off_path = {0, offset, 0.4, offset, 0.6, offset, 1, offset};
|
||||
mapnik::vertex_cache vc(path), off_vc(off_path);
|
||||
|
||||
vc.reset(); vc.next_subpath();
|
||||
off_vc.reset(); off_vc.next_subpath();
|
||||
|
||||
while (vc.move(dx)) {
|
||||
double pos = vc.linear_position();
|
||||
double off_pos = off_vc.position_closest_to(vc.current_position());
|
||||
REQUIRE(std::abs(pos - off_pos) < 1.0e-6);
|
||||
}
|
||||
}
|
||||
|
||||
void test_offset_curve(double const &offset) {
|
||||
const double dx = 0.01;
|
||||
const double r = (1.0 + offset);
|
||||
|
||||
std::vector<double> pos, off_pos;
|
||||
const size_t max_i = 1000;
|
||||
for (size_t i = 0; i <= max_i; ++i) {
|
||||
double x = M_PI * double(i) / max_i;
|
||||
pos.push_back(-std::cos(x)); pos.push_back(std::sin(x));
|
||||
off_pos.push_back(-r * std::cos(x)); off_pos.push_back(r * std::sin(x));
|
||||
}
|
||||
|
||||
fake_path path(pos), off_path(off_pos);
|
||||
mapnik::vertex_cache vc(path), off_vc(off_path);
|
||||
|
||||
vc.reset(); vc.next_subpath();
|
||||
off_vc.reset(); off_vc.next_subpath();
|
||||
|
||||
while (vc.move(dx)) {
|
||||
double pos = vc.linear_position();
|
||||
double off_pos = off_vc.position_closest_to(vc.current_position());
|
||||
{
|
||||
mapnik::vertex_cache::scoped_state s(off_vc);
|
||||
off_vc.move(off_pos);
|
||||
auto eps = (1.001 * offset);
|
||||
auto actual = dist(vc.current_position(), off_vc.current_position());
|
||||
REQUIRE(actual < eps);
|
||||
}
|
||||
REQUIRE(std::abs((pos / vc.length()) - (off_pos / off_vc.length())) < 1.0e-3);
|
||||
}
|
||||
}
|
||||
|
||||
void test_s_shaped_curve(double const &offset) {
|
||||
const double dx = 0.01;
|
||||
const double r = (1.0 + offset);
|
||||
const double r2 = (1.0 - offset);
|
||||
|
||||
std::vector<double> pos, off_pos;
|
||||
const size_t max_i = 1000;
|
||||
for (size_t i = 0; i <= max_i; ++i) {
|
||||
double x = M_PI * double(i) / max_i;
|
||||
pos.push_back(-std::cos(x) - 1); pos.push_back(std::sin(x));
|
||||
off_pos.push_back(-r * std::cos(x) - 1); off_pos.push_back(r * std::sin(x));
|
||||
}
|
||||
for (size_t i = 0; i <= max_i; ++i) {
|
||||
double x = M_PI * double(i) / max_i;
|
||||
pos.push_back(-std::cos(x) + 1); pos.push_back(-std::sin(x));
|
||||
off_pos.push_back(-r2 * std::cos(x) + 1); off_pos.push_back(-r2 * std::sin(x));
|
||||
}
|
||||
|
||||
fake_path path(pos), off_path(off_pos);
|
||||
mapnik::vertex_cache vc(path), off_vc(off_path);
|
||||
|
||||
vc.reset(); vc.next_subpath();
|
||||
off_vc.reset(); off_vc.next_subpath();
|
||||
|
||||
while (vc.move(dx)) {
|
||||
double off_pos = off_vc.position_closest_to(vc.current_position());
|
||||
{
|
||||
mapnik::vertex_cache::scoped_state s(off_vc);
|
||||
off_vc.move(off_pos);
|
||||
REQUIRE(dist(vc.current_position(), off_vc.current_position()) < (1.002 * offset));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("offsets") {
|
||||
|
||||
SECTION("line") {
|
||||
try {
|
||||
|
||||
std::vector<double> offsets = { 0.01, 0.02, 0.1, 0.2 };
|
||||
for (double offset : offsets) {
|
||||
// test simple straight line segment - should be easy to
|
||||
// find the correspondance here.
|
||||
test_simple_segment(offset);
|
||||
|
||||
// test straight line consisting of more than one segment.
|
||||
test_straight_line(offset);
|
||||
|
||||
// test an offset outer curve
|
||||
test_offset_curve(offset);
|
||||
|
||||
// test an offset along an S-shaped curve, which is harder
|
||||
// because the positions along the offset are no longer
|
||||
// linearly related to the positions along the original
|
||||
// curve.
|
||||
test_s_shaped_curve(offset);
|
||||
}
|
||||
}
|
||||
catch (std::exception const& ex)
|
||||
{
|
||||
std::cerr << ex.what() << "\n";
|
||||
REQUIRE(false);
|
||||
}
|
||||
}
|
||||
}
|
158
tests/cxx/map_request_test.cpp
Normal file
158
tests/cxx/map_request_test.cpp
Normal file
|
@ -0,0 +1,158 @@
|
|||
#include "catch.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <mapnik/map.hpp>
|
||||
#include <mapnik/load_map.hpp>
|
||||
#include <mapnik/agg_renderer.hpp>
|
||||
#if defined(HAVE_CAIRO)
|
||||
#include <mapnik/cairo/cairo_renderer.hpp>
|
||||
#endif
|
||||
#include <mapnik/image_util.hpp>
|
||||
#include <mapnik/datasource_cache.hpp>
|
||||
#include <mapnik/font_engine_freetype.hpp>
|
||||
#include <mapnik/image.hpp>
|
||||
#include <mapnik/image_reader.hpp>
|
||||
#include <mapnik/scale_denominator.hpp>
|
||||
#include <mapnik/feature_style_processor.hpp>
|
||||
#include <mapnik/projection.hpp>
|
||||
#include <mapnik/layer.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
bool compare_images(std::string const& src_fn,std::string const& dest_fn)
|
||||
{
|
||||
using namespace mapnik;
|
||||
std::unique_ptr<mapnik::image_reader> reader1(mapnik::get_image_reader(dest_fn,"png"));
|
||||
if (!reader1.get())
|
||||
{
|
||||
throw mapnik::image_reader_exception("Failed to load: " + dest_fn);
|
||||
}
|
||||
std::shared_ptr<image_rgba8> image_ptr1 = std::make_shared<image_rgba8>(reader1->width(),reader1->height());
|
||||
reader1->read(0,0,*image_ptr1);
|
||||
|
||||
std::unique_ptr<mapnik::image_reader> reader2(mapnik::get_image_reader(src_fn,"png"));
|
||||
if (!reader2.get())
|
||||
{
|
||||
throw mapnik::image_reader_exception("Failed to load: " + src_fn);
|
||||
}
|
||||
std::shared_ptr<image_rgba8> image_ptr2 = std::make_shared<image_rgba8>(reader2->width(),reader2->height());
|
||||
reader2->read(0,0,*image_ptr2);
|
||||
|
||||
image_rgba8 const& dest = *image_ptr1;
|
||||
image_rgba8 const& src = *image_ptr2;
|
||||
|
||||
unsigned int width = src.width();
|
||||
unsigned int height = src.height();
|
||||
if ((width != dest.width()) || height != dest.height()) return false;
|
||||
for (unsigned int y = 0; y < height; ++y)
|
||||
{
|
||||
const unsigned int* row_from = src.getRow(y);
|
||||
const unsigned int* row_to = dest.getRow(y);
|
||||
for (unsigned int x = 0; x < width; ++x)
|
||||
{
|
||||
if (row_from[x] != row_to[x]) return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
TEST_CASE("mapnik::request") {
|
||||
|
||||
SECTION("rendering") {
|
||||
|
||||
std::string expected("./tests/cpp_tests/support/map-request-marker-text-line-expected.png");
|
||||
std::string expected_cairo("./tests/cpp_tests/support/map-request-marker-text-line-expected-cairo.png");
|
||||
try {
|
||||
|
||||
mapnik::datasource_cache::instance().register_datasources("plugins/input/csv.input");
|
||||
mapnik::freetype_engine::register_fonts("./fonts", true );
|
||||
mapnik::Map m(256,256);
|
||||
mapnik::load_map(m,"./tests/data/good_maps/marker-text-line.xml",false);
|
||||
m.zoom_all();
|
||||
mapnik::image_rgba8 im(m.width(),m.height());
|
||||
double scale_factor = 1.2;
|
||||
|
||||
// render normally with apply() and just map and image
|
||||
mapnik::agg_renderer<mapnik::image_rgba8> renderer1(m,im,scale_factor);
|
||||
renderer1.apply();
|
||||
std::string actual1("/tmp/map-request-marker-text-line-actual1.png");
|
||||
//mapnik::save_to_file(im,expected);
|
||||
mapnik::save_to_file(im,actual1);
|
||||
// TODO - re-enable if we can control the freetype/cairo versions used
|
||||
// https://github.com/mapnik/mapnik/issues/1868
|
||||
//REQUIRE(compare_images(actual1,expected));
|
||||
|
||||
// reset image
|
||||
mapnik::fill(im, 0);
|
||||
|
||||
// set up a mapnik::request object
|
||||
mapnik::request req(m.width(),m.height(),m.get_current_extent());
|
||||
req.set_buffer_size(m.buffer_size());
|
||||
|
||||
// render using apply() and mapnik::request
|
||||
mapnik::attributes vars;
|
||||
mapnik::agg_renderer<mapnik::image_rgba8> renderer2(m,req,vars,im,scale_factor);
|
||||
renderer2.apply();
|
||||
std::string actual2("/tmp/map-request-marker-text-line-actual2.png");
|
||||
mapnik::save_to_file(im,actual2);
|
||||
// TODO - re-enable if we can control the freetype/cairo versions used
|
||||
// https://github.com/mapnik/mapnik/issues/1868
|
||||
//REQUIRE(compare_images(actual2,expected));
|
||||
|
||||
// reset image
|
||||
mapnik::fill(im, 0);
|
||||
|
||||
// render with apply_to_layer api and mapnik::request params passed to apply_to_layer
|
||||
mapnik::agg_renderer<mapnik::image_rgba8> renderer3(m,req,vars,im,scale_factor);
|
||||
renderer3.start_map_processing(m);
|
||||
mapnik::projection map_proj(m.srs(),true);
|
||||
double scale_denom = mapnik::scale_denominator(req.scale(),map_proj.is_geographic());
|
||||
scale_denom *= scale_factor;
|
||||
for (mapnik::layer const& lyr : m.layers() )
|
||||
{
|
||||
if (lyr.visible(scale_denom))
|
||||
{
|
||||
std::set<std::string> names;
|
||||
renderer3.apply_to_layer(lyr,
|
||||
renderer3,
|
||||
map_proj,
|
||||
req.scale(),
|
||||
scale_denom,
|
||||
req.width(),
|
||||
req.height(),
|
||||
req.extent(),
|
||||
req.buffer_size(),
|
||||
names);
|
||||
|
||||
}
|
||||
}
|
||||
renderer3.end_map_processing(m);
|
||||
std::string actual3("/tmp/map-request-marker-text-line-actual3.png");
|
||||
mapnik::save_to_file(im,actual3);
|
||||
// TODO - re-enable if we can control the freetype/cairo versions used
|
||||
// https://github.com/mapnik/mapnik/issues/1868
|
||||
//REQUIRE(compare_images(actual3,expected));
|
||||
|
||||
// also test cairo
|
||||
#if defined(HAVE_CAIRO)
|
||||
mapnik::cairo_surface_ptr image_surface(
|
||||
cairo_image_surface_create(CAIRO_FORMAT_ARGB32,req.width(),req.height()),
|
||||
mapnik::cairo_surface_closer());
|
||||
mapnik::cairo_ptr image_context = (mapnik::create_context(image_surface));
|
||||
mapnik::cairo_renderer<mapnik::cairo_ptr> png_render(m,req,vars,image_context,scale_factor);
|
||||
png_render.apply();
|
||||
//cairo_surface_write_to_png(&*image_surface, expected_cairo.c_str());
|
||||
std::string actual_cairo("/tmp/map-request-marker-text-line-actual4.png");
|
||||
cairo_surface_write_to_png(&*image_surface, actual_cairo.c_str());
|
||||
// TODO - re-enable if we can control the freetype/cairo versions used
|
||||
// https://github.com/mapnik/mapnik/issues/1868
|
||||
//REQUIRE(compare_images(actual_cairo,expected_cairo));
|
||||
#endif
|
||||
// TODO - test grid_renderer
|
||||
|
||||
} catch (std::exception const& ex) {
|
||||
std::clog << ex.what() << "\n";
|
||||
}
|
||||
}
|
||||
}
|
115
tests/cxx/params_test.cpp
Normal file
115
tests/cxx/params_test.cpp
Normal file
|
@ -0,0 +1,115 @@
|
|||
#include "catch.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <mapnik/value_types.hpp>
|
||||
#include <mapnik/params.hpp>
|
||||
#include <mapnik/boolean.hpp>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#include <ostream>
|
||||
|
||||
namespace detail {
|
||||
|
||||
class string_holder {
|
||||
public:
|
||||
string_holder() :
|
||||
member_("member") {}
|
||||
std::string const& get_string() const
|
||||
{
|
||||
return member_;
|
||||
}
|
||||
private:
|
||||
std::string member_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE("parameters") {
|
||||
|
||||
SECTION("get/set") {
|
||||
|
||||
try
|
||||
{
|
||||
mapnik::parameters params;
|
||||
|
||||
// true
|
||||
params["bool"] = mapnik::value_integer(true);
|
||||
REQUIRE( (params.get<mapnik::boolean_type>("bool") && *params.get<mapnik::boolean_type>("bool") == true));
|
||||
|
||||
params["bool"] = "true";
|
||||
REQUIRE( (params.get<mapnik::boolean_type>("bool") && *params.get<mapnik::boolean_type>("bool") == true));
|
||||
|
||||
params["bool"] = mapnik::value_integer(1);
|
||||
REQUIRE( (params.get<mapnik::boolean_type>("bool") && *params.get<mapnik::boolean_type>("bool") == true));
|
||||
|
||||
params["bool"] = "1";
|
||||
REQUIRE( (params.get<mapnik::boolean_type>("bool") && *params.get<mapnik::boolean_type>("bool") == true));
|
||||
|
||||
params["bool"] = "True";
|
||||
REQUIRE( (params.get<mapnik::boolean_type>("bool") && *params.get<mapnik::boolean_type>("bool") == true));
|
||||
|
||||
params["bool"] = "on";
|
||||
REQUIRE( (params.get<mapnik::boolean_type>("bool") && *params.get<mapnik::boolean_type>("bool") == true));
|
||||
|
||||
params["bool"] = "yes";
|
||||
REQUIRE( (params.get<mapnik::boolean_type>("bool") && *params.get<mapnik::boolean_type>("bool") == true));
|
||||
|
||||
// false
|
||||
params["bool"] = mapnik::value_integer(false);
|
||||
REQUIRE( (params.get<mapnik::boolean_type>("bool") && *params.get<mapnik::boolean_type>("bool") == false) );
|
||||
|
||||
params["bool"] = "false";
|
||||
REQUIRE( (params.get<mapnik::boolean_type>("bool") && *params.get<mapnik::boolean_type>("bool") == false) );
|
||||
|
||||
params["bool"] = mapnik::value_integer(0);
|
||||
REQUIRE( (params.get<mapnik::boolean_type>("bool") && *params.get<mapnik::boolean_type>("bool") == false));
|
||||
|
||||
params["bool"] = "0";
|
||||
REQUIRE( (params.get<mapnik::boolean_type>("bool") && *params.get<mapnik::boolean_type>("bool") == false));
|
||||
|
||||
params["bool"] = "False";
|
||||
REQUIRE( (params.get<mapnik::boolean_type>("bool") && *params.get<mapnik::boolean_type>("bool") == false));
|
||||
|
||||
params["bool"] = "off";
|
||||
REQUIRE( (params.get<mapnik::boolean_type>("bool") && *params.get<mapnik::boolean_type>("bool") == false));
|
||||
|
||||
params["bool"] = "no";
|
||||
REQUIRE( (params.get<mapnik::boolean_type>("bool") && *params.get<mapnik::boolean_type>("bool") == false));
|
||||
|
||||
// strings
|
||||
params["string"] = "hello";
|
||||
REQUIRE( (params.get<std::string>("string") && *params.get<std::string>("string") == "hello") );
|
||||
|
||||
// int
|
||||
params["int"] = mapnik::value_integer(1);
|
||||
REQUIRE( (params.get<mapnik::value_integer>("int") && *params.get<mapnik::value_integer>("int") == 1) );
|
||||
|
||||
// double
|
||||
params["double"] = 1.5;
|
||||
REQUIRE( (params.get<double>("double") && *params.get<double>("double") == 1.5) );
|
||||
// value_null
|
||||
params["null"] = mapnik::value_null();
|
||||
// https://github.com/mapnik/mapnik/issues/2471
|
||||
//REQUIRE( (params.get<mapnik::value_null>("null") && *params.get<mapnik::value_null>("null") == mapnik::value_null()) );
|
||||
|
||||
std::string value("value");
|
||||
params["value"] = value;
|
||||
REQUIRE( (params.get<std::string>("value") == std::string("value")) ) ;
|
||||
REQUIRE(value == std::string("value"));
|
||||
|
||||
// ensure that const member is not moved incorrectly when added to params
|
||||
detail::string_holder holder;
|
||||
std::string const& holder_member = holder.get_string();
|
||||
params["member"] = holder_member;
|
||||
REQUIRE( (params.get<std::string>("member") == std::string("member")) );
|
||||
REQUIRE( (holder_member == std::string("member")) );
|
||||
}
|
||||
catch (std::exception const& ex)
|
||||
{
|
||||
std::cerr << ex.what() << "\n";
|
||||
REQUIRE(false);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
82
tests/cxx/simplify_converters_test.cpp
Normal file
82
tests/cxx/simplify_converters_test.cpp
Normal file
|
@ -0,0 +1,82 @@
|
|||
#include "catch.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
#include <mapnik/layer.hpp>
|
||||
#include <mapnik/wkt/wkt_factory.hpp>
|
||||
#include <mapnik/wkt/wkt_generator_grammar.hpp>
|
||||
#include <mapnik/simplify.hpp>
|
||||
#include <mapnik/simplify_converter.hpp>
|
||||
|
||||
// stl
|
||||
#include <stdexcept>
|
||||
|
||||
// Convenience method for test cases
|
||||
void simplify(std::string const& wkt_in, double tolerance, std::string const& method, std::string const& expected)
|
||||
{
|
||||
#if 0 // FIXME
|
||||
//grab the geom
|
||||
mapnik::geometry_container multi_input;
|
||||
if (!mapnik::from_wkt(wkt_in , multi_input))
|
||||
{
|
||||
throw std::runtime_error("Failed to parse WKT");
|
||||
}
|
||||
//setup the generalization
|
||||
mapnik::vertex_adapter va(multi_input.front());
|
||||
mapnik::simplify_converter<mapnik::vertex_adapter> generalizer(va);
|
||||
generalizer.set_simplify_algorithm(mapnik::simplify_algorithm_from_string(method).get());
|
||||
generalizer.set_simplify_tolerance(tolerance);
|
||||
//suck the vertices back out of it
|
||||
mapnik::geometry_type* output = new mapnik::geometry_type(multi_input.front().type());
|
||||
mapnik::CommandType cmd;
|
||||
double x, y;
|
||||
while ((cmd = (mapnik::CommandType)generalizer.vertex(&x, &y)) != mapnik::SEG_END)
|
||||
{
|
||||
output->push_vertex(x, y, cmd);
|
||||
}
|
||||
//construct the answer
|
||||
mapnik::geometry_container multi_out;
|
||||
multi_out.push_back(output);
|
||||
std::string wkt_out;
|
||||
REQUIRE(mapnik::to_wkt(multi_out, wkt_out));
|
||||
REQUIRE(wkt_out == expected);
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("converters") {
|
||||
|
||||
SECTION("simplify") {
|
||||
|
||||
simplify( std::string("LineString(0 0,2 2,3 5,4 1,5 0,6 7,7 0)"),
|
||||
4, "douglas-peucker",
|
||||
std::string("LineString(0 0,6 7,7 0)"));
|
||||
|
||||
simplify( std::string("LineString(0 0,2 2,3 5,4 1,5 0,6 7,7 0)"),
|
||||
2, "douglas-peucker",
|
||||
std::string("LineString(0 0,3 5,5 0,6 7,7 0)"));
|
||||
|
||||
simplify( std::string("LineString(10 0,9 -4,7 -7,4 -9,0 -10,-4 -9,-7 -7,-9 -4,-10 0,-9 4,-7 7,-4 9,0 10,4 9,7 7,9 4)"),
|
||||
4, "douglas-peucker",
|
||||
std::string("LineString(10 0,0 -10,-10 0,0 10,9 4)"));
|
||||
|
||||
simplify( std::string("LineString(0 0,1 1,2 2,0 10,0 0)"),
|
||||
10, "douglas-peucker",
|
||||
std::string("LineString(0 0,0 0)"));
|
||||
|
||||
simplify( std::string("LineString(0 0,1 1,2 2,0 10,0 0)"),
|
||||
8, "douglas-peucker",
|
||||
std::string("LineString(0 0,0 10,0 0)"));
|
||||
|
||||
simplify( std::string("LineString(0 0,1 1,2 2,0 10,0 0)"),
|
||||
1, "douglas-peucker",
|
||||
std::string("LineString(0 0,2 2,0 10,0 0)"));
|
||||
|
||||
simplify( std::string("LineString(0 0, 1 -1, 2 2, 0 -10, 0 0, -5 7, 4 6)"),
|
||||
3, "douglas-peucker",
|
||||
std::string("LineString(0 0,0 -10,-5 7,4 6)"));
|
||||
|
||||
}
|
||||
}
|
30
tests/cxx/symbolizer_test.cpp
Normal file
30
tests/cxx/symbolizer_test.cpp
Normal file
|
@ -0,0 +1,30 @@
|
|||
#include "catch.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <mapnik/symbolizer.hpp>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace mapnik;
|
||||
|
||||
TEST_CASE("symbolizer") {
|
||||
|
||||
SECTION("enums") {
|
||||
|
||||
try {
|
||||
marker_multi_policy_enum policy_in = MARKER_WHOLE_MULTI;
|
||||
REQUIRE(policy_in == MARKER_WHOLE_MULTI);
|
||||
markers_symbolizer sym;
|
||||
put(sym, keys::markers_multipolicy, policy_in);
|
||||
REQUIRE(sym.properties.count(keys::markers_multipolicy) == static_cast<unsigned long>(1));
|
||||
marker_multi_policy_enum policy_out = get<mapnik::marker_multi_policy_enum>(sym, keys::markers_multipolicy);
|
||||
REQUIRE(policy_out == MARKER_WHOLE_MULTI);
|
||||
}
|
||||
catch (std::exception const & ex)
|
||||
{
|
||||
std::clog << ex.what() << std::endl;
|
||||
REQUIRE(false);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
121
tests/cxx/wkb_formats_test.cpp
Normal file
121
tests/cxx/wkb_formats_test.cpp
Normal file
|
@ -0,0 +1,121 @@
|
|||
#include "catch.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <mapnik/params.hpp>
|
||||
#include <mapnik/wkb.hpp>
|
||||
#include <mapnik/feature.hpp>
|
||||
#include <mapnik/geometry_is_valid.hpp>
|
||||
#include <mapnik/geometry_is_simple.hpp>
|
||||
#include <mapnik/geometry_correct.hpp>
|
||||
#include <mapnik/feature_factory.hpp>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <boost/version.hpp>
|
||||
|
||||
TEST_CASE("geometry formats") {
|
||||
|
||||
SECTION("wkb") {
|
||||
|
||||
unsigned char sp_valid_blob[] = {
|
||||
0x0, 0x1, 0xBC, 0xB, 0x0, 0x0, 0x1F, 0x12, 0xDB, 0xCF, 0xC3, 0xA2, 0x41, 0x41, 0x9D, 0x74, 0xB0, 0x31, 0xE6, 0x34, 0x53, 0x41, 0xDB,
|
||||
0x1B, 0xB6, 0x7C, 0xD9, 0xA2, 0x41, 0x41, 0x67, 0xA7, 0xB6, 0xF, 0xF6, 0x34, 0x53, 0x41, 0x7C, 0x6, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0,
|
||||
0x0, 0x69, 0x3, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x12, 0x0, 0x0, 0x0, 0xBB, 0x4B, 0x9C, 0x59, 0xD2, 0xA2, 0x41, 0x41, 0x3A, 0xAA,
|
||||
0x3F, 0xAE, 0xEB, 0x34, 0x53, 0x41, 0xA2, 0xC2, 0xE4, 0xC6, 0xD1, 0xA2, 0x41, 0x41, 0x4C, 0xFE, 0x6, 0x2B, 0xEC, 0x34, 0x53, 0x41,
|
||||
0xEC, 0x65, 0x5F, 0x6, 0xCE, 0xA2, 0x41, 0x41, 0xDD, 0x33, 0x7F, 0x24, 0xEF, 0x34, 0x53, 0x41, 0x2D, 0x35, 0x2D, 0x30, 0xCB, 0xA2,
|
||||
0x41, 0x41, 0x4E, 0xA7, 0x88, 0x9, 0xF1, 0x34, 0x53, 0x41, 0x58, 0x2F, 0x12, 0x96, 0xCA, 0xA2, 0x41, 0x41, 0x52, 0xD1, 0xBD, 0xDC,
|
||||
0xF0, 0x34, 0x53, 0x41, 0x1F, 0x12, 0xDB, 0xCF, 0xC3, 0xA2, 0x41, 0x41, 0xB9, 0x31, 0xA4, 0xE1, 0xF5, 0x34, 0x53, 0x41, 0x21, 0xBB,
|
||||
0x20, 0x6D, 0xC4, 0xA2, 0x41, 0x41, 0x67, 0xA7, 0xB6, 0xF, 0xF6, 0x34, 0x53, 0x41, 0x5A, 0x82, 0x4A, 0xD3, 0xCA, 0xA2, 0x41, 0x41,
|
||||
0xA7, 0x85, 0x3D, 0x58, 0xF1, 0x34, 0x53, 0x41, 0x22, 0xB8, 0x3A, 0x7D, 0xCB, 0xA2, 0x41, 0x41, 0x7D, 0x89, 0xA1, 0x8E, 0xF1, 0x34,
|
||||
0x53, 0x41, 0xD0, 0x77, 0x3F, 0x80, 0xCF, 0xA2, 0x41, 0x41, 0x57, 0x69, 0x83, 0xC4, 0xEE, 0x34, 0x53, 0x41, 0xA7, 0xF5, 0x8E, 0xF9,
|
||||
0xD1, 0xA2, 0x41, 0x41, 0x9A, 0xA2, 0x31, 0xEE, 0xEC, 0x34, 0x53, 0x41, 0x2A, 0xCD, 0xDE, 0x4C, 0xD4, 0xA2, 0x41, 0x41, 0x11, 0x43,
|
||||
0xE1, 0xF7, 0xEA, 0x34, 0x53, 0x41, 0xF, 0x89, 0xB1, 0x66, 0xD5, 0xA2, 0x41, 0x41, 0xC8, 0x5D, 0x86, 0xF1, 0xE9, 0x34, 0x53, 0x41,
|
||||
0x19, 0xF4, 0x73, 0x63, 0xD7, 0xA2, 0x41, 0x41, 0x7, 0xB1, 0x14, 0x36, 0xE8, 0x34, 0x53, 0x41, 0xDB, 0x1B, 0xB6, 0x7C, 0xD9, 0xA2,
|
||||
0x41, 0x41, 0x98, 0xB5, 0xE0, 0x74, 0xE6, 0x34, 0x53, 0x41, 0xC0, 0x3F, 0xC6, 0xAC, 0xD8, 0xA2, 0x41, 0x41, 0x9D, 0x74, 0xB0, 0x31,
|
||||
0xE6, 0x34, 0x53, 0x41, 0xF0, 0xB5, 0xB1, 0x53, 0xD5, 0xA2, 0x41, 0x41, 0x97, 0x47, 0xAD, 0x36, 0xE9, 0x34, 0x53, 0x41, 0xBB, 0x4B,
|
||||
0x9C, 0x59, 0xD2, 0xA2, 0x41, 0x41, 0x3A, 0xAA, 0x3F, 0xAE, 0xEB, 0x34, 0x53, 0x41, 0xFE };
|
||||
|
||||
unsigned char sp_invalid_blob[] = {
|
||||
0x0, 0x1, 0xBC, 0xB, 0x0, 0x0, 0x1F, 0x12, 0xDB, 0xCF, 0xC3, 0xA2, 0x41, 0x41, 0x9D, 0x74, 0xB0, 0x31, 0xE6, 0x34, 0x53, 0x41, 0xDB,
|
||||
0x1B, 0xB6, 0x7C, 0xD9, 0xA2, 0x41, 0x41, 0x67, 0xA7, 0xB6, 0xF, 0xF6, 0x34, 0x53, 0x41, 0x7C, 0x6, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0,
|
||||
0x0, 0x69, 0x3, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x12, 0x0, 0x0, 0x0, 0xBB, 0x4B, 0x9C, 0x59, 0xD2, 0xA2, 0x41, 0x41, 0x3A, 0xAA,
|
||||
0x3F, 0xAE, 0xEB, 0x34, 0x53, 0x41, 0xA2, 0xC2, 0xE4, 0xC6, 0xD1, 0xA2, 0x41, 0x41, 0x4C, 0xFE, 0x6, 0x2B, 0xEC, 0x34, 0x53, 0x41,
|
||||
0xEC, 0x65, 0x5F, 0x6, 0xCE, 0xA2, 0x41, 0x41, 0xDD, 0x33, 0x7F, 0x24, 0xEF, 0x34, 0x53, 0x41, 0x2D, 0x35, 0x2D, 0x30, 0xCB, 0xA2,
|
||||
0x41, 0x41, 0x4E, 0xA7, 0x88, 0x9, 0xF1, 0x34, 0x53, 0x41, 0x58, 0x2F, 0x12, 0x96, 0xCA, 0xA2, 0x41, 0x41, 0x52, 0xD1, 0xBD, 0xDC,
|
||||
0xF0, 0x34, 0x53, 0x41, 0x1F, 0x12, 0xDB, 0xCF, 0xC3, 0xA2, 0x41, 0x41, 0xB9, 0x31, 0xA4, 0xE1, 0xF5, 0x34, 0x53, 0x41, 0x21, 0xBB,
|
||||
0x20, 0x6D, 0xC4, 0xA2, 0x41, 0x41, 0x67, 0xA7, 0xB6, 0xF, 0xF6, 0x34, 0x53, 0x41, 0x5A, 0x82, 0x4A, 0xD3, 0xCA, 0xA2, 0x41, 0x41,
|
||||
0xA7, 0x85, 0x3D, 0x58, 0xF1, 0x34, 0x53, 0x41, 0x22, 0xB8, 0x3A, 0x7D, 0xCB, 0xA2, 0x41, 0x41, 0x7D, 0x89, 0xA1, 0x8E, 0xF1, 0x34,
|
||||
0x53, 0x41, 0xD0, 0x77, 0x3F, 0x80, 0xCF, 0xA2, 0x41, 0x41, 0x57, 0x69, 0x83, 0xC4, 0xEE, 0x34, 0x53, 0x41, 0xA7, 0xF5, 0x8E, 0xF9,
|
||||
0xD1, 0xA2, 0x41, 0x41, 0x9A, 0xA2, 0x31, 0xEE, 0xEC, 0x34, 0x53, 0x41, 0x2A, 0xCD, 0xDE, 0x4C, 0xD4, 0xA2, 0x41, 0x41, 0x11, 0x43,
|
||||
0xE1, 0xF7, 0xEA, 0x34, 0x53, 0x41, 0xF, 0x89, 0xB1, 0x66, 0xD5, 0xA2, 0x41, 0x41, 0xC8, 0x5D, 0x86, 0xF1, 0xE9, 0x34, 0x53, 0x41,
|
||||
0x19, 0xF4, 0x73, 0x63, 0xD7, 0xA2, 0x41, 0x41, 0x7, 0xB1, 0x14, 0x36, 0xE8, 0x34, 0x53, 0x41, 0xDB, 0x1B, 0xB6, 0x7C, 0xD9, 0xA2,
|
||||
0x41, 0x41, 0x98, 0xB5, 0xE0, 0x74, 0xE6, 0x34, 0x53, 0x41, 0xC0, 0x3F, 0xC6, 0xAC, 0xD8, 0xA2, 0x41, 0x41, 0x9D, 0x74, 0xB0, 0x31,
|
||||
0xE6, 0x34, 0x53, 0x41, 0xF0, 0xB5, 0xB1, 0x53, 0xD5, 0xA2, 0x41, 0x41, 0x97, 0x47, 0xAD, 0x36, 0xE9, 0x34, 0x53, 0x41, 0xBB, 0x4B,
|
||||
0x9C, 0x59, 0xD2, 0xA2, 0x41, 0x41, 0x3A, 0xAA, 0x3F, 0xAE, 0xEB, 0x34, 0x53, 0x41 };
|
||||
|
||||
unsigned char sq_valid_blob[] = {
|
||||
0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x40 };
|
||||
|
||||
unsigned char sq_invalid_blob[] = {
|
||||
0x23, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x40, 0x23 };
|
||||
|
||||
mapnik::context_ptr ctx(new mapnik::context_type);
|
||||
mapnik::feature_ptr feature = mapnik::feature_factory::create(ctx, 1);
|
||||
|
||||
// test of parsing wkb geometries
|
||||
try {
|
||||
|
||||
// spatialite blob
|
||||
mapnik::geometry::geometry<double> geom = mapnik::geometry_utils::from_wkb((const char*)sp_valid_blob,
|
||||
sizeof(sp_valid_blob) / sizeof(sp_valid_blob[0]),
|
||||
mapnik::wkbSpatiaLite);
|
||||
// winding order is not correct per OGC so we'll fix it
|
||||
mapnik::geometry::correct(geom);
|
||||
#if BOOST_VERSION >= 105600
|
||||
REQUIRE(mapnik::geometry::is_valid(geom));
|
||||
REQUIRE(mapnik::geometry::is_simple(geom));
|
||||
#endif
|
||||
|
||||
geom = mapnik::geometry_utils::from_wkb((const char*)sp_valid_blob,
|
||||
sizeof(sp_valid_blob) / sizeof(sp_valid_blob[0]),
|
||||
mapnik::wkbAuto);
|
||||
mapnik::geometry::correct(geom);
|
||||
#if BOOST_VERSION >= 105600
|
||||
REQUIRE(mapnik::geometry::is_valid(geom));
|
||||
REQUIRE(mapnik::geometry::is_simple(geom));
|
||||
#endif
|
||||
|
||||
geom = mapnik::geometry_utils::from_wkb((const char*)sp_invalid_blob,
|
||||
sizeof(sp_invalid_blob) / sizeof(sp_invalid_blob[0]),
|
||||
mapnik::wkbAuto);
|
||||
REQUIRE(geom.is<mapnik::geometry::geometry_empty>()); // returns geometry_empty
|
||||
|
||||
// sqlite generic wkb blob
|
||||
|
||||
geom = mapnik::geometry_utils::from_wkb((const char*)sq_valid_blob,
|
||||
sizeof(sq_valid_blob) / sizeof(sq_valid_blob[0]),
|
||||
mapnik::wkbGeneric);
|
||||
#if BOOST_VERSION >= 105600
|
||||
REQUIRE(mapnik::geometry::is_valid(geom));
|
||||
REQUIRE(mapnik::geometry::is_simple(geom));
|
||||
#endif
|
||||
|
||||
geom = mapnik::geometry_utils::from_wkb( (const char*)sq_valid_blob,
|
||||
sizeof(sq_valid_blob) / sizeof(sq_valid_blob[0]),
|
||||
mapnik::wkbAuto);
|
||||
|
||||
#if BOOST_VERSION >= 105600
|
||||
REQUIRE(mapnik::geometry::is_valid(geom));
|
||||
REQUIRE(mapnik::geometry::is_simple(geom));
|
||||
#endif
|
||||
|
||||
geom = mapnik::geometry_utils::from_wkb((const char*)sq_invalid_blob,
|
||||
sizeof(sq_invalid_blob) / sizeof(sq_invalid_blob[0]),
|
||||
mapnik::wkbGeneric);
|
||||
REQUIRE(geom.is<mapnik::geometry::geometry_empty>()); // returns geometry_empty
|
||||
|
||||
} catch (std::exception const& ex) {
|
||||
REQUIRE(false);
|
||||
std::clog << "threw: " << ex.what() << "\n";
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue