Use vertex_converters in text placement

This commit is contained in:
artemp 2014-08-06 13:10:24 +01:00
parent ec97b8b744
commit 9835057b0f
6 changed files with 177 additions and 112 deletions

View file

@ -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;

View 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

View file

@ -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();
}; };

View file

@ -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;

View file

@ -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

View file

@ -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,