Merge branch 'text-extend' of https://github.com/mapycz/mapnik into mapycz-text-extend
This commit is contained in:
commit
c1053181f5
12 changed files with 490 additions and 100 deletions
232
include/mapnik/extend_converter.hpp
Normal file
232
include/mapnik/extend_converter.hpp
Normal file
|
@ -0,0 +1,232 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
*
|
||||||
|
* This file is part of Mapnik (c++ mapping toolkit)
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015 Artem Pavlenko
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef MAPNIK_EXTEND_CONVERTER_HPP
|
||||||
|
#define MAPNIK_EXTEND_CONVERTER_HPP
|
||||||
|
|
||||||
|
#include <mapnik/vertex.hpp>
|
||||||
|
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#include <mapnik/warning_ignore.hpp>
|
||||||
|
#include <boost/optional.hpp>
|
||||||
|
#include <boost/msm/back/state_machine.hpp>
|
||||||
|
#include <boost/msm/front/state_machine_def.hpp>
|
||||||
|
#include <boost/msm/front/functor_row.hpp>
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
|
||||||
|
// stl
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
namespace mapnik
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace msm = boost::msm;
|
||||||
|
namespace mpl = boost::mpl;
|
||||||
|
using namespace msm::front;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T extend(T const & v1, T const & v2, double length)
|
||||||
|
{
|
||||||
|
double dx = v2.x - v1.x;
|
||||||
|
double dy = v2.y - v1.y;
|
||||||
|
double l12 = std::sqrt(dx * dx + dy * dy);
|
||||||
|
double coef = 1.0 + length / l12;
|
||||||
|
return vertex2d(v1.x + dx * coef,
|
||||||
|
v1.y + dy * coef, v2.cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace events
|
||||||
|
{
|
||||||
|
struct vertex_event
|
||||||
|
{
|
||||||
|
vertex_event(vertex2d const & vertex) : vertex(vertex) { }
|
||||||
|
vertex2d const & vertex;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct move_to : vertex_event { using vertex_event::vertex_event; };
|
||||||
|
struct line_to : vertex_event { using vertex_event::vertex_event; };
|
||||||
|
struct close : vertex_event { using vertex_event::vertex_event; };
|
||||||
|
struct end : vertex_event { using vertex_event::vertex_event; };
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace actions
|
||||||
|
{
|
||||||
|
struct store
|
||||||
|
{
|
||||||
|
template <class FSM, class EVT, class SourceState, class TargetState>
|
||||||
|
void operator()(EVT const & e, FSM & m, SourceState&, TargetState&)
|
||||||
|
{
|
||||||
|
m.v2 = m.v1;
|
||||||
|
m.v1 = e.vertex;
|
||||||
|
m.output = boost::none;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct output
|
||||||
|
{
|
||||||
|
template <class FSM, class EVT, class SourceState, class TargetState>
|
||||||
|
void operator()(EVT const & e, FSM & m, SourceState&, TargetState&)
|
||||||
|
{
|
||||||
|
m.output = e.vertex;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct store_and_output
|
||||||
|
{
|
||||||
|
template <class FSM, class EVT, class SourceState, class TargetState>
|
||||||
|
void operator()(EVT const & e, FSM & m, SourceState&, TargetState&)
|
||||||
|
{
|
||||||
|
m.v2 = m.v1;
|
||||||
|
m.v1 = e.vertex;
|
||||||
|
m.output = m.v2;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct output_begin
|
||||||
|
{
|
||||||
|
template <class FSM, class EVT, class SourceState, class TargetState>
|
||||||
|
void operator()(EVT const & e, FSM & m, SourceState&, TargetState&)
|
||||||
|
{
|
||||||
|
m.v2 = m.v1;
|
||||||
|
m.v1 = e.vertex;
|
||||||
|
m.output = extend(m.v1, m.v2, m.extend_length);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct output_end
|
||||||
|
{
|
||||||
|
template <class FSM, class EVT, class SourceState, class TargetState>
|
||||||
|
void operator()(EVT const & e, FSM & m, SourceState&, TargetState&)
|
||||||
|
{
|
||||||
|
m.output = extend(m.v2, m.v1, m.extend_length);
|
||||||
|
m.v1 = e.vertex;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
struct extender_def : public msm::front::state_machine_def<extender_def>
|
||||||
|
{
|
||||||
|
using no_exception_thrown = int;
|
||||||
|
using no_message_queue = int;
|
||||||
|
|
||||||
|
struct initial : public msm::front::state<> { };
|
||||||
|
struct vertex_one : public msm::front::state<> { };
|
||||||
|
struct vertex_two : public msm::front::state<> { };
|
||||||
|
struct end : public msm::front::state<> { };
|
||||||
|
|
||||||
|
using initial_state = initial;
|
||||||
|
|
||||||
|
struct transition_table : mpl::vector<
|
||||||
|
// Start Event Next Action Guard
|
||||||
|
// +------------+-----------------+------------+--------------------+------+
|
||||||
|
Row < initial , events::move_to , vertex_one , actions::store >,
|
||||||
|
Row < initial , events::line_to , vertex_one , actions::store >,
|
||||||
|
Row < initial , events::close , initial >,
|
||||||
|
Row < initial , events::end , end , actions::output >,
|
||||||
|
Row < vertex_one , events::move_to , vertex_one , actions::store_and_output >,
|
||||||
|
Row < vertex_one , events::line_to , vertex_two , actions::output_begin >,
|
||||||
|
Row < vertex_one , events::close , initial , actions::store_and_output >,
|
||||||
|
Row < vertex_one , events::end , end , actions::store_and_output >,
|
||||||
|
Row < vertex_two , events::move_to , vertex_one , actions::output_end >,
|
||||||
|
Row < vertex_two , events::line_to , vertex_two , actions::store_and_output >,
|
||||||
|
Row < vertex_two , events::close , initial , actions::output_end >,
|
||||||
|
Row < vertex_two , events::end , end , actions::output_end >,
|
||||||
|
Row < end , events::end , end , actions::output >
|
||||||
|
> {};
|
||||||
|
|
||||||
|
extender_def(double extend_length)
|
||||||
|
: extend_length(extend_length)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::optional<vertex2d> output;
|
||||||
|
vertex2d v1, v2;
|
||||||
|
double extend_length;
|
||||||
|
};
|
||||||
|
|
||||||
|
using extender = msm::back::state_machine<extender_def>;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Geometry>
|
||||||
|
struct extend_converter
|
||||||
|
{
|
||||||
|
extend_converter(Geometry & geom)
|
||||||
|
: extend_converter(geom, 0)
|
||||||
|
{}
|
||||||
|
|
||||||
|
extend_converter(Geometry & geom, double extend)
|
||||||
|
: geom_(geom), extender_(extend)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void set_extend(double extend)
|
||||||
|
{
|
||||||
|
extender_.extend_length = extend;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned vertex(double * x, double * y)
|
||||||
|
{
|
||||||
|
using namespace detail;
|
||||||
|
vertex2d v;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
v.cmd = geom_.vertex(&v.x, &v.y);
|
||||||
|
switch (v.cmd)
|
||||||
|
{
|
||||||
|
case SEG_MOVETO:
|
||||||
|
extender_.process_event(events::move_to(v));
|
||||||
|
break;
|
||||||
|
case SEG_LINETO:
|
||||||
|
extender_.process_event(events::line_to(v));
|
||||||
|
break;
|
||||||
|
case SEG_CLOSE:
|
||||||
|
extender_.process_event(events::close(v));
|
||||||
|
break;
|
||||||
|
case SEG_END:
|
||||||
|
extender_.process_event(events::end(v));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while(!extender_.output);
|
||||||
|
|
||||||
|
vertex2d const & output = *extender_.output;
|
||||||
|
*x = output.x;
|
||||||
|
*y = output.y;
|
||||||
|
return output.cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rewind(unsigned)
|
||||||
|
{
|
||||||
|
geom_.rewind(0);
|
||||||
|
extender_.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Geometry & geom_;
|
||||||
|
detail::extender extender_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // MAPNIK_EXTEND_CONVERTER_HPP
|
|
@ -369,6 +369,13 @@ struct symbolizer_default<value_bool, keys::avoid_edges>
|
||||||
|
|
||||||
// font-feature-settings
|
// font-feature-settings
|
||||||
|
|
||||||
|
// extend
|
||||||
|
template <>
|
||||||
|
struct symbolizer_default<value_double, keys::extend>
|
||||||
|
{
|
||||||
|
static value_double value() { return 0.0; }
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace mapnik
|
} // namespace mapnik
|
||||||
|
|
||||||
#endif // MAPNIK_SYMBOLIZER_DEFAULT_VALUES_HPP
|
#endif // MAPNIK_SYMBOLIZER_DEFAULT_VALUES_HPP
|
||||||
|
|
|
@ -92,6 +92,7 @@ enum class keys : std::uint8_t
|
||||||
direction,
|
direction,
|
||||||
avoid_edges,
|
avoid_edges,
|
||||||
ff_settings,
|
ff_settings,
|
||||||
|
extend,
|
||||||
MAX_SYMBOLIZER_KEY
|
MAX_SYMBOLIZER_KEY
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,7 @@ struct placement_finder_adapter
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
using vertex_converter_type = vertex_converter<clip_line_tag, transform_tag, affine_transform_tag, simplify_tag, smooth_tag>;
|
using vertex_converter_type = vertex_converter<clip_line_tag, transform_tag, affine_transform_tag, extend_tag, simplify_tag, smooth_tag>;
|
||||||
|
|
||||||
class base_symbolizer_helper
|
class base_symbolizer_helper
|
||||||
{
|
{
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
#include <mapnik/symbolizer_enumerations.hpp>
|
#include <mapnik/symbolizer_enumerations.hpp>
|
||||||
#include <mapnik/symbolizer_keys.hpp>
|
#include <mapnik/symbolizer_keys.hpp>
|
||||||
#include <mapnik/symbolizer.hpp>
|
#include <mapnik/symbolizer.hpp>
|
||||||
|
#include <mapnik/extend_converter.hpp>
|
||||||
|
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
#include <mapnik/warning_ignore_agg.hpp>
|
#include <mapnik/warning_ignore_agg.hpp>
|
||||||
|
@ -65,6 +66,7 @@ struct stroke_tag {};
|
||||||
struct dash_tag {};
|
struct dash_tag {};
|
||||||
struct affine_transform_tag {};
|
struct affine_transform_tag {};
|
||||||
struct offset_transform_tag {};
|
struct offset_transform_tag {};
|
||||||
|
struct extend_tag {};
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
|
@ -254,6 +256,23 @@ struct converter_traits<T,mapnik::offset_transform_tag>
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct converter_traits<T, mapnik::extend_tag>
|
||||||
|
{
|
||||||
|
using geometry_type = T;
|
||||||
|
using conv_type = extend_converter<geometry_type>;
|
||||||
|
|
||||||
|
template <typename Args>
|
||||||
|
static void setup(geometry_type & geom, Args const& args)
|
||||||
|
{
|
||||||
|
auto const& sym = args.sym;
|
||||||
|
auto const& feat = args.feature;
|
||||||
|
auto const& vars = args.vars;
|
||||||
|
double extend = get<value_double, keys::extend>(sym, feat, vars);
|
||||||
|
geom.set_extend(extend * args.scale_factor);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
template <typename T0, typename T1>
|
template <typename T0, typename T1>
|
||||||
struct is_switchable
|
struct is_switchable
|
||||||
|
|
|
@ -895,6 +895,7 @@ void map_parser::parse_symbolizer_base(symbolizer_base &sym, xml_node const& nod
|
||||||
set_symbolizer_property<symbolizer_base,composite_mode_e>(sym, keys::comp_op, node);
|
set_symbolizer_property<symbolizer_base,composite_mode_e>(sym, keys::comp_op, node);
|
||||||
set_symbolizer_property<symbolizer_base,transform_type>(sym, keys::geometry_transform, node);
|
set_symbolizer_property<symbolizer_base,transform_type>(sym, keys::geometry_transform, node);
|
||||||
set_symbolizer_property<symbolizer_base,simplify_algorithm_e>(sym, keys::simplify_algorithm, node);
|
set_symbolizer_property<symbolizer_base,simplify_algorithm_e>(sym, keys::simplify_algorithm, node);
|
||||||
|
set_symbolizer_property<symbolizer_base,double>(sym, keys::extend, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
void map_parser::parse_point_symbolizer(rule & rule, xml_node const & node)
|
void map_parser::parse_point_symbolizer(rule & rule, xml_node const & node)
|
||||||
|
|
|
@ -158,6 +158,7 @@ static const property_meta_type key_meta[const_max_key] =
|
||||||
property_types::target_direction},
|
property_types::target_direction},
|
||||||
property_meta_type{ "avoid-edges",nullptr, property_types::target_bool },
|
property_meta_type{ "avoid-edges",nullptr, property_types::target_bool },
|
||||||
property_meta_type{ "font-feature-settings", nullptr, property_types::target_font_feature_settings },
|
property_meta_type{ "font-feature-settings", nullptr, property_types::target_font_feature_settings },
|
||||||
|
property_meta_type{ "extend", nullptr, property_types::target_double},
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -327,10 +327,12 @@ text_symbolizer_helper::text_symbolizer_helper(
|
||||||
value_bool clip = mapnik::get<value_bool, keys::clip>(sym_, feature_, vars_);
|
value_bool clip = mapnik::get<value_bool, keys::clip>(sym_, feature_, vars_);
|
||||||
value_double simplify_tolerance = mapnik::get<value_double, keys::simplify_tolerance>(sym_, feature_, vars_);
|
value_double simplify_tolerance = mapnik::get<value_double, keys::simplify_tolerance>(sym_, feature_, vars_);
|
||||||
value_double smooth = mapnik::get<value_double, keys::smooth>(sym_, feature_, vars_);
|
value_double smooth = mapnik::get<value_double, keys::smooth>(sym_, feature_, vars_);
|
||||||
|
value_double extend = mapnik::get<value_double, keys::extend>(sym_, feature_, vars_);
|
||||||
|
|
||||||
if (clip) converter_.template set<clip_line_tag>();
|
if (clip) converter_.template set<clip_line_tag>();
|
||||||
converter_.template set<transform_tag>(); //always transform
|
converter_.template set<transform_tag>(); //always transform
|
||||||
converter_.template set<affine_transform_tag>();
|
converter_.template set<affine_transform_tag>();
|
||||||
|
if (extend > 0.0) converter_.template set<extend_tag>();
|
||||||
if (simplify_tolerance > 0.0) converter_.template set<simplify_tag>(); // optional simplify converter
|
if (simplify_tolerance > 0.0) converter_.template set<simplify_tag>(); // optional simplify converter
|
||||||
if (smooth > 0.0) converter_.template set<smooth_tag>(); // optional smooth converter
|
if (smooth > 0.0) converter_.template set<smooth_tag>(); // optional smooth converter
|
||||||
|
|
||||||
|
@ -452,12 +454,15 @@ text_symbolizer_helper::text_symbolizer_helper(
|
||||||
value_bool clip = mapnik::get<value_bool, keys::clip>(sym_, feature_, vars_);
|
value_bool clip = mapnik::get<value_bool, keys::clip>(sym_, feature_, vars_);
|
||||||
value_double simplify_tolerance = mapnik::get<value_double, keys::simplify_tolerance>(sym_, feature_, vars_);
|
value_double simplify_tolerance = mapnik::get<value_double, keys::simplify_tolerance>(sym_, feature_, vars_);
|
||||||
value_double smooth = mapnik::get<value_double, keys::smooth>(sym_, feature_, vars_);
|
value_double smooth = mapnik::get<value_double, keys::smooth>(sym_, feature_, vars_);
|
||||||
|
value_double extend = mapnik::get<value_double, keys::extend>(sym_, feature_, vars_);
|
||||||
|
|
||||||
if (clip) converter_.template set<clip_line_tag>();
|
if (clip) converter_.template set<clip_line_tag>();
|
||||||
converter_.template set<transform_tag>(); //always transform
|
converter_.template set<transform_tag>(); //always transform
|
||||||
converter_.template set<affine_transform_tag>();
|
converter_.template set<affine_transform_tag>();
|
||||||
|
if (extend > 0.0) converter_.template set<extend_tag>();
|
||||||
if (simplify_tolerance > 0.0) converter_.template set<simplify_tag>(); // optional simplify converter
|
if (simplify_tolerance > 0.0) converter_.template set<simplify_tag>(); // optional simplify converter
|
||||||
if (smooth > 0.0) converter_.template set<smooth_tag>(); // optional smooth converter
|
if (smooth > 0.0) converter_.template set<smooth_tag>(); // optional smooth converter
|
||||||
|
|
||||||
if (geometries_to_process_.size())
|
if (geometries_to_process_.size())
|
||||||
{
|
{
|
||||||
init_marker();
|
init_marker();
|
||||||
|
|
128
test/unit/vertex_adapter/extend_converter.cpp
Normal file
128
test/unit/vertex_adapter/extend_converter.cpp
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
#include "catch.hpp"
|
||||||
|
#include "fake_path.hpp"
|
||||||
|
|
||||||
|
// mapnik
|
||||||
|
#include <mapnik/extend_converter.hpp>
|
||||||
|
|
||||||
|
// stl
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace offset_test {
|
||||||
|
|
||||||
|
TEST_CASE("extend converter") {
|
||||||
|
|
||||||
|
SECTION("empty") {
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fake_path path = {};
|
||||||
|
mapnik::extend_converter<fake_path> c(path, 1000);
|
||||||
|
double x, y;
|
||||||
|
REQUIRE(c.vertex(&x, &y) == mapnik::SEG_END);
|
||||||
|
}
|
||||||
|
catch (std::exception const& ex)
|
||||||
|
{
|
||||||
|
std::cerr << ex.what() << "\n";
|
||||||
|
REQUIRE(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("one point") {
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fake_path path = { 0, 0 };
|
||||||
|
mapnik::extend_converter<fake_path> c(path, 1000);
|
||||||
|
double x, y;
|
||||||
|
REQUIRE(c.vertex(&x, &y) == mapnik::SEG_MOVETO);
|
||||||
|
REQUIRE(x == 0);
|
||||||
|
REQUIRE(y == 0);
|
||||||
|
REQUIRE(c.vertex(&x, &y) == mapnik::SEG_END);
|
||||||
|
REQUIRE(c.vertex(&x, &y) == mapnik::SEG_END);
|
||||||
|
}
|
||||||
|
catch (std::exception const& ex)
|
||||||
|
{
|
||||||
|
std::cerr << ex.what() << "\n";
|
||||||
|
REQUIRE(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("two points") {
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fake_path path = { 0, 0 , 1, 0};
|
||||||
|
mapnik::extend_converter<fake_path> c(path, 1000);
|
||||||
|
double x, y;
|
||||||
|
REQUIRE(c.vertex(&x, &y) == mapnik::SEG_MOVETO);
|
||||||
|
REQUIRE(x == -1000);
|
||||||
|
REQUIRE(y == 0);
|
||||||
|
REQUIRE(c.vertex(&x, &y) == mapnik::SEG_LINETO);
|
||||||
|
REQUIRE(x == 1001);
|
||||||
|
REQUIRE(y == 0);
|
||||||
|
REQUIRE(c.vertex(&x, &y) == mapnik::SEG_END);
|
||||||
|
}
|
||||||
|
catch (std::exception const& ex)
|
||||||
|
{
|
||||||
|
std::cerr << ex.what() << "\n";
|
||||||
|
REQUIRE(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("three points") {
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fake_path path = { 0, 0, 1, 0, 2, 0 };
|
||||||
|
mapnik::extend_converter<fake_path> c(path, 1000);
|
||||||
|
double x, y;
|
||||||
|
REQUIRE(c.vertex(&x, &y) == mapnik::SEG_MOVETO);
|
||||||
|
REQUIRE(x == -1000);
|
||||||
|
REQUIRE(y == 0);
|
||||||
|
REQUIRE(c.vertex(&x, &y) == mapnik::SEG_LINETO);
|
||||||
|
REQUIRE(x == 1);
|
||||||
|
REQUIRE(y == 0);
|
||||||
|
REQUIRE(c.vertex(&x, &y) == mapnik::SEG_LINETO);
|
||||||
|
REQUIRE(x == 1002);
|
||||||
|
REQUIRE(y == 0);
|
||||||
|
REQUIRE(c.vertex(&x, &y) == mapnik::SEG_END);
|
||||||
|
}
|
||||||
|
catch (std::exception const& ex)
|
||||||
|
{
|
||||||
|
std::cerr << ex.what() << "\n";
|
||||||
|
REQUIRE(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("more points") {
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fake_path path = { 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0 };
|
||||||
|
mapnik::extend_converter<fake_path> c(path, 1000);
|
||||||
|
double x, y;
|
||||||
|
REQUIRE(c.vertex(&x, &y) == mapnik::SEG_MOVETO);
|
||||||
|
REQUIRE(x == -1000);
|
||||||
|
REQUIRE(y == 0);
|
||||||
|
REQUIRE(c.vertex(&x, &y) == mapnik::SEG_LINETO);
|
||||||
|
REQUIRE(x == 1);
|
||||||
|
REQUIRE(y == 0);
|
||||||
|
REQUIRE(c.vertex(&x, &y) == mapnik::SEG_LINETO);
|
||||||
|
REQUIRE(x == 2);
|
||||||
|
REQUIRE(y == 0);
|
||||||
|
REQUIRE(c.vertex(&x, &y) == mapnik::SEG_LINETO);
|
||||||
|
REQUIRE(x == 3);
|
||||||
|
REQUIRE(y == 0);
|
||||||
|
REQUIRE(c.vertex(&x, &y) == mapnik::SEG_LINETO);
|
||||||
|
REQUIRE(x == 4);
|
||||||
|
REQUIRE(y == 0);
|
||||||
|
REQUIRE(c.vertex(&x, &y) == mapnik::SEG_LINETO);
|
||||||
|
REQUIRE(x == 1005);
|
||||||
|
REQUIRE(y == 0);
|
||||||
|
REQUIRE(c.vertex(&x, &y) == mapnik::SEG_END);
|
||||||
|
}
|
||||||
|
catch (std::exception const& ex)
|
||||||
|
{
|
||||||
|
std::cerr << ex.what() << "\n";
|
||||||
|
REQUIRE(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
93
test/unit/vertex_adapter/fake_path.hpp
Normal file
93
test/unit/vertex_adapter/fake_path.hpp
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
*
|
||||||
|
* This file is part of Mapnik (c++ mapping toolkit)
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015 Artem Pavlenko
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
// mapnik
|
||||||
|
#include <mapnik/vertex.hpp>
|
||||||
|
|
||||||
|
// stl
|
||||||
|
#include <vector>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct fake_path
|
||||||
|
{
|
||||||
|
using coord_type = std::tuple<T, T, unsigned>;
|
||||||
|
using cont_type = std::vector<coord_type>;
|
||||||
|
cont_type vertices_;
|
||||||
|
typename cont_type::iterator itr_;
|
||||||
|
|
||||||
|
fake_path(std::initializer_list<T> l)
|
||||||
|
: fake_path(l.begin(), l.size())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
fake_path(std::vector<T> const &v, bool make_invalid = false)
|
||||||
|
: fake_path(v.begin(), v.size(), make_invalid)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Itr>
|
||||||
|
fake_path(Itr itr, size_t sz, bool make_invalid = false)
|
||||||
|
{
|
||||||
|
size_t num_coords = sz >> 1;
|
||||||
|
vertices_.reserve(num_coords + (make_invalid ? 1 : 0));
|
||||||
|
if (make_invalid)
|
||||||
|
{
|
||||||
|
vertices_.push_back(std::make_tuple(0,0,mapnik::SEG_END));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < num_coords; ++i)
|
||||||
|
{
|
||||||
|
T x = *itr++;
|
||||||
|
T y = *itr++;
|
||||||
|
unsigned cmd = (i == 0) ? mapnik::SEG_MOVETO : mapnik::SEG_LINETO;
|
||||||
|
vertices_.push_back(std::make_tuple(x, y, cmd));
|
||||||
|
}
|
||||||
|
itr_ = vertices_.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned vertex(T *x, T *y)
|
||||||
|
{
|
||||||
|
if (itr_ == vertices_.end())
|
||||||
|
{
|
||||||
|
return mapnik::SEG_END;
|
||||||
|
}
|
||||||
|
*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();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
using fake_path = detail::fake_path<double>;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
|
||||||
#include "catch.hpp"
|
#include "catch.hpp"
|
||||||
|
#include "fake_path.hpp"
|
||||||
|
|
||||||
// mapnik
|
// mapnik
|
||||||
#include <mapnik/vertex_cache.hpp>
|
#include <mapnik/vertex_cache.hpp>
|
||||||
|
@ -7,53 +8,6 @@
|
||||||
|
|
||||||
// stl
|
// stl
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <vector>
|
|
||||||
#include <tuple>
|
|
||||||
|
|
||||||
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,
|
double dist(mapnik::pixel_position const &a,
|
||||||
mapnik::pixel_position const &b)
|
mapnik::pixel_position const &b)
|
||||||
|
|
|
@ -1,66 +1,15 @@
|
||||||
|
|
||||||
#include "catch.hpp"
|
#include "catch.hpp"
|
||||||
|
#include "fake_path.hpp"
|
||||||
|
|
||||||
// mapnik
|
// mapnik
|
||||||
#include <mapnik/vertex.hpp>
|
|
||||||
#include <mapnik/offset_converter.hpp>
|
#include <mapnik/offset_converter.hpp>
|
||||||
|
|
||||||
// stl
|
// stl
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <vector>
|
|
||||||
#include <tuple>
|
|
||||||
|
|
||||||
namespace offset_test {
|
namespace offset_test {
|
||||||
|
|
||||||
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, bool make_invalid = false)
|
|
||||||
: fake_path(v.begin(), v.size(), make_invalid) {
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Itr>
|
|
||||||
fake_path(Itr itr, size_t sz, bool make_invalid = false) {
|
|
||||||
size_t num_coords = sz >> 1;
|
|
||||||
vertices_.reserve(num_coords + (make_invalid ? 1 : 0));
|
|
||||||
if (make_invalid)
|
|
||||||
{
|
|
||||||
vertices_.push_back(std::make_tuple(0,0,mapnik::SEG_END));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < num_coords; ++i) {
|
|
||||||
double x = *itr++;
|
|
||||||
double y = *itr++;
|
|
||||||
unsigned cmd = (i == 0) ? mapnik::SEG_MOVETO : mapnik::SEG_LINETO;
|
|
||||||
vertices_.push_back(std::make_tuple(x, y, cmd));
|
|
||||||
}
|
|
||||||
itr_ = vertices_.begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned vertex(double *x, double *y) {
|
|
||||||
if (itr_ == vertices_.end()) {
|
|
||||||
return mapnik::SEG_END;
|
|
||||||
}
|
|
||||||
*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();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static double DELTA_BUFF = 0.5;
|
static double DELTA_BUFF = 0.5;
|
||||||
|
|
||||||
double dist(double x0, double y0, double x1, double y1)
|
double dist(double x0, double y0, double x1, double y1)
|
||||||
|
|
Loading…
Reference in a new issue