Use vertex_converters in text placement
This commit is contained in:
parent
ec97b8b744
commit
9835057b0f
6 changed files with 177 additions and 112 deletions
|
@ -27,11 +27,11 @@ namespace mapnik {
|
||||||
|
|
||||||
template <typename vertex_converter_type, typename rasterizer_type, typename F>
|
template <typename vertex_converter_type, typename rasterizer_type, typename F>
|
||||||
void render_polygon_symbolizer(polygon_symbolizer const &sym,
|
void render_polygon_symbolizer(polygon_symbolizer const &sym,
|
||||||
mapnik::feature_impl &feature,
|
mapnik::feature_impl & feature,
|
||||||
proj_transform const &prj_trans,
|
proj_transform const& prj_trans,
|
||||||
renderer_common &common,
|
renderer_common & common,
|
||||||
box2d<double> const &clip_box,
|
box2d<double> const& clip_box,
|
||||||
rasterizer_type &ras,
|
rasterizer_type & ras,
|
||||||
F fill_func)
|
F fill_func)
|
||||||
{
|
{
|
||||||
agg::trans_affine tr;
|
agg::trans_affine tr;
|
||||||
|
|
108
include/mapnik/text/placement_finder_impl.hpp
Normal file
108
include/mapnik/text/placement_finder_impl.hpp
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
*
|
||||||
|
* This file is part of Mapnik (c++ mapping toolkit)
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014 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/debug.hpp>
|
||||||
|
#include <mapnik/label_collision_detector.hpp>
|
||||||
|
#include <mapnik/ctrans.hpp>
|
||||||
|
#include <mapnik/expression_evaluator.hpp>
|
||||||
|
#include <mapnik/text/placement_finder.hpp>
|
||||||
|
#include <mapnik/text/text_layout.hpp>
|
||||||
|
#include <mapnik/text/text_properties.hpp>
|
||||||
|
#include <mapnik/text/placements_list.hpp>
|
||||||
|
#include <mapnik/text/vertex_cache.hpp>
|
||||||
|
#include <mapnik/text/tolerance_iterator.hpp>
|
||||||
|
|
||||||
|
// agg
|
||||||
|
#include "agg_conv_clip_polyline.h"
|
||||||
|
|
||||||
|
// stl
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace mapnik
|
||||||
|
{
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool placement_finder::find_line_placements(T & path, bool points)
|
||||||
|
{
|
||||||
|
if (!layouts_.line_count()) return true; //TODO
|
||||||
|
vertex_cache pp(path);
|
||||||
|
|
||||||
|
bool success = false;
|
||||||
|
while (pp.next_subpath())
|
||||||
|
{
|
||||||
|
if (points)
|
||||||
|
{
|
||||||
|
if (pp.length() <= 0.001)
|
||||||
|
{
|
||||||
|
success = find_point_placement(pp.current_position()) || success;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((pp.length() < info_.properties.minimum_path_length * scale_factor_)
|
||||||
|
||
|
||||||
|
(pp.length() <= 0.001) // Clipping removed whole geometry
|
||||||
|
||
|
||||||
|
(pp.length() < layouts_.width()))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double spacing = get_spacing(pp.length(), points ? 0. : layouts_.width());
|
||||||
|
|
||||||
|
//horizontal_alignment_e halign = layouts_.back()->horizontal_alignment();
|
||||||
|
|
||||||
|
// halign == H_LEFT -> don't move
|
||||||
|
if (horizontal_alignment_ == H_MIDDLE || horizontal_alignment_ == H_AUTO)
|
||||||
|
{
|
||||||
|
pp.forward(spacing/2.0);
|
||||||
|
}
|
||||||
|
else if (horizontal_alignment_ == H_RIGHT)
|
||||||
|
{
|
||||||
|
pp.forward(pp.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (move_dx_ != 0.0) path_move_dx(pp, move_dx_);
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
tolerance_iterator tolerance_offset(info_.properties.label_position_tolerance * scale_factor_, spacing); //TODO: Handle halign
|
||||||
|
while (tolerance_offset.next())
|
||||||
|
{
|
||||||
|
vertex_cache::scoped_state state(pp);
|
||||||
|
if (pp.move(tolerance_offset.get())
|
||||||
|
&& (
|
||||||
|
(points && find_point_placement(pp.current_position()))
|
||||||
|
|| (!points && single_line_placement(pp, info_.properties.upright))))
|
||||||
|
{
|
||||||
|
success = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (pp.forward(spacing));
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
}// ns mapnik
|
|
@ -30,9 +30,37 @@
|
||||||
#include <mapnik/text/placement_finder.hpp>
|
#include <mapnik/text/placement_finder.hpp>
|
||||||
#include <mapnik/proj_transform.hpp>
|
#include <mapnik/proj_transform.hpp>
|
||||||
#include <mapnik/ctrans.hpp>
|
#include <mapnik/ctrans.hpp>
|
||||||
|
#include <mapnik/vertex_converters.hpp>
|
||||||
|
|
||||||
namespace mapnik {
|
namespace mapnik {
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct placement_finder_adapter
|
||||||
|
{
|
||||||
|
using placement_finder_type = T;
|
||||||
|
placement_finder_adapter(T & finder, bool points_on_line)
|
||||||
|
: finder_(finder),
|
||||||
|
points_on_line_(points_on_line) {}
|
||||||
|
|
||||||
|
template <typename PathT>
|
||||||
|
void add_path(PathT & path)
|
||||||
|
{
|
||||||
|
status_ = finder_.find_line_placements(path, points_on_line_);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool status() const { return status_;}
|
||||||
|
// Place text at points on a line instead of following the line (used for ShieldSymbolizer)
|
||||||
|
placement_finder_type & finder_;
|
||||||
|
bool points_on_line_;
|
||||||
|
mutable bool status_ = false;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
using conv_types = boost::mpl::vector<clip_line_tag , transform_tag, simplify_tag, smooth_tag>;
|
||||||
|
using vertex_converter_type = vertex_converter<box2d<double>, placement_finder_adapter<placement_finder> , symbolizer_base,
|
||||||
|
CoordTransform, proj_transform, agg::trans_affine,
|
||||||
|
conv_types, feature_impl>;
|
||||||
|
|
||||||
class base_symbolizer_helper
|
class base_symbolizer_helper
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -116,10 +144,8 @@ protected:
|
||||||
bool next_line_placement(bool clipped);
|
bool next_line_placement(bool clipped);
|
||||||
|
|
||||||
placement_finder finder_;
|
placement_finder finder_;
|
||||||
|
placement_finder_adapter<placement_finder> adapter_;
|
||||||
// Place text at points on a line instead of following the line (used for ShieldSymbolizer)
|
vertex_converter_type converter_;
|
||||||
bool points_on_line_;
|
|
||||||
|
|
||||||
//ShieldSymbolizer only
|
//ShieldSymbolizer only
|
||||||
void init_marker();
|
void init_marker();
|
||||||
};
|
};
|
||||||
|
|
|
@ -121,8 +121,8 @@ public:
|
||||||
bool next_subpath();
|
bool next_subpath();
|
||||||
|
|
||||||
// Compatibility with standard path interface
|
// Compatibility with standard path interface
|
||||||
void rewind(unsigned) const;
|
void rewind(unsigned);
|
||||||
unsigned vertex(double *x, double *y) const;
|
unsigned vertex(double *x, double *y);
|
||||||
|
|
||||||
// State
|
// State
|
||||||
state save_state() const;
|
state save_state() const;
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
#include <mapnik/label_collision_detector.hpp>
|
#include <mapnik/label_collision_detector.hpp>
|
||||||
#include <mapnik/ctrans.hpp>
|
#include <mapnik/ctrans.hpp>
|
||||||
#include <mapnik/expression_evaluator.hpp>
|
#include <mapnik/expression_evaluator.hpp>
|
||||||
#include <mapnik/text/placement_finder.hpp>
|
#include <mapnik/text/placement_finder_impl.hpp>
|
||||||
#include <mapnik/text/text_layout.hpp>
|
#include <mapnik/text/text_layout.hpp>
|
||||||
#include <mapnik/text/text_properties.hpp>
|
#include <mapnik/text/text_properties.hpp>
|
||||||
#include <mapnik/text/placements_list.hpp>
|
#include <mapnik/text/placements_list.hpp>
|
||||||
|
@ -169,71 +169,6 @@ bool placement_finder::find_point_placement(pixel_position const& pos)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
bool placement_finder::find_line_placements(T & path, bool points)
|
|
||||||
{
|
|
||||||
if (!layouts_.line_count()) return true; //TODO
|
|
||||||
vertex_cache pp(path);
|
|
||||||
|
|
||||||
bool success = false;
|
|
||||||
while (pp.next_subpath())
|
|
||||||
{
|
|
||||||
if (points)
|
|
||||||
{
|
|
||||||
if (pp.length() <= 0.001)
|
|
||||||
{
|
|
||||||
success = find_point_placement(pp.current_position()) || success;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ((pp.length() < info_.properties.minimum_path_length * scale_factor_)
|
|
||||||
||
|
|
||||||
(pp.length() <= 0.001) // Clipping removed whole geometry
|
|
||||||
||
|
|
||||||
(pp.length() < layouts_.width()))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
double spacing = get_spacing(pp.length(), points ? 0. : layouts_.width());
|
|
||||||
|
|
||||||
//horizontal_alignment_e halign = layouts_.back()->horizontal_alignment();
|
|
||||||
|
|
||||||
// halign == H_LEFT -> don't move
|
|
||||||
if (horizontal_alignment_ == H_MIDDLE || horizontal_alignment_ == H_AUTO)
|
|
||||||
{
|
|
||||||
pp.forward(spacing/2.0);
|
|
||||||
}
|
|
||||||
else if (horizontal_alignment_ == H_RIGHT)
|
|
||||||
{
|
|
||||||
pp.forward(pp.length());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (move_dx_ != 0.0) path_move_dx(pp, move_dx_);
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
tolerance_iterator tolerance_offset(info_.properties.label_position_tolerance * scale_factor_, spacing); //TODO: Handle halign
|
|
||||||
while (tolerance_offset.next())
|
|
||||||
{
|
|
||||||
vertex_cache::scoped_state state(pp);
|
|
||||||
if (pp.move(tolerance_offset.get())
|
|
||||||
&& (
|
|
||||||
(points && find_point_placement(pp.current_position()))
|
|
||||||
|| (!points && single_line_placement(pp, info_.properties.upright))))
|
|
||||||
{
|
|
||||||
success = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (pp.forward(spacing));
|
|
||||||
}
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool placement_finder::single_line_placement(vertex_cache &pp, text_upright_e orientation)
|
bool placement_finder::single_line_placement(vertex_cache &pp, text_upright_e orientation)
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
|
@ -502,12 +437,4 @@ pixel_position const& glyph_positions::marker_pos() const
|
||||||
return marker_pos_;
|
return marker_pos_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
using clipped_geometry_type = agg::conv_clip_polyline<geometry_type>;
|
|
||||||
using ClippedPathType = coord_transform<CoordTransform,clipped_geometry_type>;
|
|
||||||
using PathType = coord_transform<CoordTransform,geometry_type>;
|
|
||||||
template bool placement_finder::find_line_placements<ClippedPathType>(ClippedPathType &, bool);
|
|
||||||
template bool placement_finder::find_line_placements<PathType>(PathType &, bool);
|
|
||||||
|
|
||||||
|
|
||||||
}// ns mapnik
|
}// ns mapnik
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
#include <mapnik/debug.hpp>
|
#include <mapnik/debug.hpp>
|
||||||
#include <mapnik/symbolizer.hpp>
|
#include <mapnik/symbolizer.hpp>
|
||||||
#include <mapnik/value_types.hpp>
|
#include <mapnik/value_types.hpp>
|
||||||
#include <mapnik/text/placement_finder.hpp>
|
#include <mapnik/text/placement_finder_impl.hpp>
|
||||||
#include <mapnik/text/placements/base.hpp>
|
#include <mapnik/text/placements/base.hpp>
|
||||||
#include <mapnik/text/placements/dummy.hpp>
|
#include <mapnik/text/placements/dummy.hpp>
|
||||||
|
|
||||||
|
@ -72,7 +72,6 @@ struct largest_bbox_first
|
||||||
box2d<double> b1 = g1->envelope();
|
box2d<double> b1 = g1->envelope();
|
||||||
return b0.width()*b0.height() > b1.width()*b1.height();
|
return b0.width()*b0.height() > b1.width()*b1.height();
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void base_symbolizer_helper::initialize_geometries()
|
void base_symbolizer_helper::initialize_geometries()
|
||||||
|
@ -182,8 +181,21 @@ text_symbolizer_helper::text_symbolizer_helper(
|
||||||
DetectorT &detector, box2d<double> const& query_extent)
|
DetectorT &detector, box2d<double> const& query_extent)
|
||||||
: base_symbolizer_helper(sym, feature, vars, prj_trans, width, height, scale_factor, t, query_extent),
|
: base_symbolizer_helper(sym, feature, vars, prj_trans, width, height, scale_factor, t, query_extent),
|
||||||
finder_(feature, vars, detector, dims_, *placement_, font_manager, scale_factor),
|
finder_(feature, vars, detector, dims_, *placement_, font_manager, scale_factor),
|
||||||
points_on_line_(false)
|
adapter_(finder_,false),
|
||||||
|
converter_(query_extent_, adapter_, sym_, t, prj_trans, agg::trans_affine(), feature, vars, scale_factor)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
// setup vertex converter
|
||||||
|
bool clip = mapnik::get<bool>(sym_, keys::clip, feature_, vars_, false);
|
||||||
|
double simplify_tolerance = mapnik::get<double>(sym_, keys::simplify_tolerance, feature_, vars_, 0.0);
|
||||||
|
double smooth = mapnik::get<double>(sym_, keys::smooth, feature_, vars_, 0.0);
|
||||||
|
|
||||||
|
if (clip) converter_.template set<clip_line_tag>(); //optional clip (default: true)
|
||||||
|
converter_.template set<transform_tag>(); //always transform
|
||||||
|
converter_.template set<affine_transform_tag>();
|
||||||
|
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 (geometries_to_process_.size()) finder_.next_position();
|
if (geometries_to_process_.size()) finder_.next_position();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,31 +224,15 @@ bool text_symbolizer_helper::next_line_placement(bool clipped)
|
||||||
geo_itr_ = geometries_to_process_.begin();
|
geo_itr_ = geometries_to_process_.begin();
|
||||||
continue; //Reexecute size check
|
continue; //Reexecute size check
|
||||||
}
|
}
|
||||||
bool success = false;
|
|
||||||
if (clipped)
|
|
||||||
{
|
|
||||||
using clipped_geometry_type = agg::conv_clip_polyline<geometry_type>;
|
|
||||||
using path_type = coord_transform<CoordTransform,clipped_geometry_type>;
|
|
||||||
|
|
||||||
clipped_geometry_type clipped(**geo_itr_);
|
converter_.apply(**geo_itr_);
|
||||||
clipped.clip_box(query_extent_.minx(), query_extent_.miny(),
|
if (adapter_.status())
|
||||||
query_extent_.maxx(), query_extent_.maxy());
|
|
||||||
path_type path(t_, clipped, prj_trans_);
|
|
||||||
success = finder_.find_line_placements(path, points_on_line_);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
using path_type = coord_transform<CoordTransform,geometry_type>;
|
|
||||||
path_type path(t_, **geo_itr_, prj_trans_);
|
|
||||||
success = finder_.find_line_placements(path, points_on_line_);
|
|
||||||
}
|
|
||||||
if (success)
|
|
||||||
{
|
{
|
||||||
//Found a placement
|
//Found a placement
|
||||||
geo_itr_ = geometries_to_process_.erase(geo_itr_);
|
geo_itr_ = geometries_to_process_.erase(geo_itr_);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
//No placement for this geometry. Keep it in geometries_to_process_ for next try.
|
// No placement for this geometry. Keep it in geometries_to_process_ for next try.
|
||||||
++geo_itr_;
|
++geo_itr_;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -266,8 +262,6 @@ bool text_symbolizer_helper::next_point_placement()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
|
||||||
|
|
||||||
template <typename FaceManagerT, typename DetectorT>
|
template <typename FaceManagerT, typename DetectorT>
|
||||||
text_symbolizer_helper::text_symbolizer_helper(
|
text_symbolizer_helper::text_symbolizer_helper(
|
||||||
shield_symbolizer const& sym,
|
shield_symbolizer const& sym,
|
||||||
|
@ -276,11 +270,22 @@ text_symbolizer_helper::text_symbolizer_helper(
|
||||||
proj_transform const& prj_trans,
|
proj_transform const& prj_trans,
|
||||||
unsigned width, unsigned height, double scale_factor,
|
unsigned width, unsigned height, double scale_factor,
|
||||||
CoordTransform const& t, FaceManagerT & font_manager,
|
CoordTransform const& t, FaceManagerT & font_manager,
|
||||||
DetectorT &detector, const box2d<double> &query_extent)
|
DetectorT & detector, box2d<double> const& query_extent)
|
||||||
: base_symbolizer_helper(sym, feature, vars, prj_trans, width, height, scale_factor, t, query_extent),
|
: base_symbolizer_helper(sym, feature, vars, prj_trans, width, height, scale_factor, t, query_extent),
|
||||||
finder_(feature, vars, detector, dims_, *placement_, font_manager, scale_factor),
|
finder_(feature, vars, detector, dims_, *placement_, font_manager, scale_factor),
|
||||||
points_on_line_(true)
|
adapter_(finder_,true),
|
||||||
|
converter_(query_extent_, adapter_, sym_, t, prj_trans, agg::trans_affine(), feature, vars, scale_factor)
|
||||||
{
|
{
|
||||||
|
// setup vertex converter
|
||||||
|
bool clip = mapnik::get<bool>(sym_, keys::clip, feature_, vars_, false);
|
||||||
|
double simplify_tolerance = mapnik::get<double>(sym_, keys::simplify_tolerance, feature_, vars_, 0.0);
|
||||||
|
double smooth = mapnik::get<double>(sym_, keys::smooth, feature_, vars_, 0.0);
|
||||||
|
|
||||||
|
if (clip) converter_.template set<clip_line_tag>(); //optional clip (default: true)
|
||||||
|
converter_.template set<transform_tag>(); //always transform
|
||||||
|
converter_.template set<affine_transform_tag>();
|
||||||
|
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 (geometries_to_process_.size())
|
if (geometries_to_process_.size())
|
||||||
{
|
{
|
||||||
init_marker();
|
init_marker();
|
||||||
|
@ -325,7 +330,6 @@ void text_symbolizer_helper::init_marker()
|
||||||
finder_.set_marker(std::make_shared<marker_info>(*marker, trans), bbox, unlock_image, marker_displacement);
|
finder_.set_marker(std::make_shared<marker_info>(*marker, trans), bbox, unlock_image, marker_displacement);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
|
||||||
|
|
||||||
template text_symbolizer_helper::text_symbolizer_helper(
|
template text_symbolizer_helper::text_symbolizer_helper(
|
||||||
text_symbolizer const& sym,
|
text_symbolizer const& sym,
|
||||||
|
|
Loading…
Reference in a new issue