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>
|
||||
void render_polygon_symbolizer(polygon_symbolizer const &sym,
|
||||
mapnik::feature_impl &feature,
|
||||
proj_transform const &prj_trans,
|
||||
renderer_common &common,
|
||||
box2d<double> const &clip_box,
|
||||
rasterizer_type &ras,
|
||||
mapnik::feature_impl & feature,
|
||||
proj_transform const& prj_trans,
|
||||
renderer_common & common,
|
||||
box2d<double> const& clip_box,
|
||||
rasterizer_type & ras,
|
||||
F fill_func)
|
||||
{
|
||||
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/proj_transform.hpp>
|
||||
#include <mapnik/ctrans.hpp>
|
||||
#include <mapnik/vertex_converters.hpp>
|
||||
|
||||
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
|
||||
{
|
||||
public:
|
||||
|
@ -116,10 +144,8 @@ protected:
|
|||
bool next_line_placement(bool clipped);
|
||||
|
||||
placement_finder finder_;
|
||||
|
||||
// Place text at points on a line instead of following the line (used for ShieldSymbolizer)
|
||||
bool points_on_line_;
|
||||
|
||||
placement_finder_adapter<placement_finder> adapter_;
|
||||
vertex_converter_type converter_;
|
||||
//ShieldSymbolizer only
|
||||
void init_marker();
|
||||
};
|
||||
|
|
|
@ -121,8 +121,8 @@ public:
|
|||
bool next_subpath();
|
||||
|
||||
// Compatibility with standard path interface
|
||||
void rewind(unsigned) const;
|
||||
unsigned vertex(double *x, double *y) const;
|
||||
void rewind(unsigned);
|
||||
unsigned vertex(double *x, double *y);
|
||||
|
||||
// State
|
||||
state save_state() const;
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#include <mapnik/label_collision_detector.hpp>
|
||||
#include <mapnik/ctrans.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_properties.hpp>
|
||||
#include <mapnik/text/placements_list.hpp>
|
||||
|
@ -169,71 +169,6 @@ bool placement_finder::find_point_placement(pixel_position const& pos)
|
|||
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)
|
||||
{
|
||||
//
|
||||
|
@ -502,12 +437,4 @@ pixel_position const& glyph_positions::marker_pos() const
|
|||
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
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
#include <mapnik/debug.hpp>
|
||||
#include <mapnik/symbolizer.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/dummy.hpp>
|
||||
|
||||
|
@ -72,7 +72,6 @@ struct largest_bbox_first
|
|||
box2d<double> b1 = g1->envelope();
|
||||
return b0.width()*b0.height() > b1.width()*b1.height();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
void base_symbolizer_helper::initialize_geometries()
|
||||
|
@ -182,8 +181,21 @@ text_symbolizer_helper::text_symbolizer_helper(
|
|||
DetectorT &detector, box2d<double> const& 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),
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -212,31 +224,15 @@ bool text_symbolizer_helper::next_line_placement(bool clipped)
|
|||
geo_itr_ = geometries_to_process_.begin();
|
||||
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_);
|
||||
clipped.clip_box(query_extent_.minx(), query_extent_.miny(),
|
||||
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)
|
||||
converter_.apply(**geo_itr_);
|
||||
if (adapter_.status())
|
||||
{
|
||||
//Found a placement
|
||||
geo_itr_ = geometries_to_process_.erase(geo_itr_);
|
||||
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_;
|
||||
}
|
||||
return false;
|
||||
|
@ -266,8 +262,6 @@ bool text_symbolizer_helper::next_point_placement()
|
|||
return false;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
template <typename FaceManagerT, typename DetectorT>
|
||||
text_symbolizer_helper::text_symbolizer_helper(
|
||||
shield_symbolizer const& sym,
|
||||
|
@ -276,11 +270,22 @@ text_symbolizer_helper::text_symbolizer_helper(
|
|||
proj_transform const& prj_trans,
|
||||
unsigned width, unsigned height, double scale_factor,
|
||||
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),
|
||||
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())
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
template text_symbolizer_helper::text_symbolizer_helper(
|
||||
text_symbolizer const& sym,
|
||||
|
|
Loading…
Reference in a new issue