avoid storing evaluated text properties in text_symbolizer_properties (all style related strucures must be read-only)

make process(..) method const
This commit is contained in:
artemp 2014-10-10 12:38:06 +01:00
parent c6ed108a72
commit 74e872c48b
9 changed files with 109 additions and 128 deletions

View file

@ -39,7 +39,7 @@ using DetectorType = label_collision_detector4;
using pixel_position_list = std::list<pixel_position>;
/** Helper object that does some of the GroupSymbolizer placement finding work. */
// Helper object that does some of the GroupSymbolizer placement finding work.
class group_symbolizer_helper : public base_symbolizer_helper
{
public:

View file

@ -85,6 +85,7 @@ private:
DetectorType & detector_;
box2d<double> const& extent_;
text_placement_info const& info_;
evaluated_text_properties_ptr text_props_;
layout_container layouts_;
double scale_factor_;

View file

@ -59,7 +59,7 @@ bool placement_finder::find_line_placements(T & path, bool points)
}
else
{
if ((pp.length() < info_.properties.minimum_path_length * scale_factor_)
if ((pp.length() < text_props_->minimum_path_length * scale_factor_)
||
(pp.length() <= 0.001) // Clipping removed whole geometry
||
@ -89,14 +89,13 @@ bool placement_finder::find_line_placements(T & path, bool points)
do
{
tolerance_iterator tolerance_offset(info_.properties.label_position_tolerance * scale_factor_, spacing); //TODO: Handle halign
tolerance_iterator tolerance_offset(text_props_->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))))
&& ((points && find_point_placement(pp.current_position()))
|| (!points && single_line_placement(pp, text_props_->upright))))
{
success = true;
break;

View file

@ -97,6 +97,7 @@ protected:
// Use point placement. Otherwise line placement is used.
mutable bool point_placement_;
text_placement_info_ptr placement_;
evaluated_text_properties_ptr text_props_;
};
// Helper object that does all the TextSymbolizer placement finding

View file

@ -49,34 +49,41 @@ namespace detail {
struct evaluated_format_properties
{
evaluated_format_properties() :
face_name(),
text_size(0.0),
character_spacing(0.0),
line_spacing(0.0),
text_opacity(1.0),
halo_opacity(1.0),
text_transform(NONE),
fill(0,0,0),
halo_fill(0,0,0),
halo_radius(0.0),
font_feature_settings(std::make_shared<mapnik::font_feature_settings>()) {}
std::string face_name;
std::string face_name = "";
boost::optional<font_set> fontset;
double text_size;
double character_spacing;
double line_spacing;
double text_opacity;
double halo_opacity;
text_transform_e text_transform;
color fill;
color halo_fill;
double halo_radius;
font_feature_settings_ptr font_feature_settings;
double text_size = 0.0;
double character_spacing = 0.0;
double line_spacing = 0.0;
double text_opacity = 1.0;
double halo_opacity = 1.0;
text_transform_e text_transform = NONE;
color fill = color(0,0,0);
color halo_fill = color(255,255,255);
double halo_radius = 0.0;
font_feature_settings_ptr font_feature_settings = std::make_shared<mapnik::font_feature_settings>();
};
struct evaluated_text_properties
{
label_placement_e label_placement = POINT_PLACEMENT;
double label_spacing = 0.0; // distance between repeated labels on a single geometry
double label_position_tolerance = 0.0; // distance the label can be moved on the line to fit, if 0 the default is used
bool avoid_edges = false;
double margin = 0.0;
double repeat_distance = 0.0;
double minimum_distance = 0.0;
double minimum_padding = 0.0;
double minimum_path_length = 0.0;
double max_char_angle_delta = 22.5 * M_PI/180.0;
bool allow_overlap = false;
bool largest_bbox_only = true; // Only consider geometry with largest bbox (polygons)
text_upright_e upright = UPRIGHT_AUTO;
};
}
using evaluated_text_properties_ptr = std::unique_ptr<detail::evaluated_text_properties>;
enum directions_e
{
NORTH,
@ -179,8 +186,8 @@ struct MAPNIK_DECL text_symbolizer_properties
// Takes a feature and produces formatted text as output.
// The output object has to be created by the caller and passed in for thread safety.
void process(text_layout &output, feature_impl const& feature, attributes const& vars);
void evaluate_text_properties(feature_impl const& feature, attributes const& attrs);
void process(text_layout & output, feature_impl const& feature, attributes const& vars) const;
evaluated_text_properties_ptr evaluate_text_properties(feature_impl const& feature, attributes const& attrs) const;
// Sets new format tree.
void set_format_tree(formatting::node_ptr tree);
// Get a list of all expressions used in any placement.
@ -188,23 +195,6 @@ struct MAPNIK_DECL text_symbolizer_properties
void add_expressions(expression_set & output) const;
// Per symbolizer options
label_placement_e label_placement;
// distance between repeated labels on a single geometry
double label_spacing;
// distance the label can be moved on the line to fit, if 0 the default is used
double label_position_tolerance;
bool avoid_edges;
double margin;
double repeat_distance;
double minimum_distance;
double minimum_padding;
double minimum_path_length;
double max_char_angle_delta;
bool allow_overlap;
// Only consider geometry with largest bbox (polygons)
bool largest_bbox_only;
text_upright_e upright;
// Expressions
text_properties_expressions expressions;
// Default values for text layouts

View file

@ -95,7 +95,7 @@ bool group_symbolizer_helper::find_line_placements(T & path)
pp.forward(spacing/2.0);
do
{
tolerance_iterator tolerance_offset(placement_->properties.label_position_tolerance * scale_factor_, spacing); //TODO: Handle halign
tolerance_iterator tolerance_offset(text_props_->label_position_tolerance * scale_factor_, spacing); //TODO: Handle halign
while (tolerance_offset.next())
{
vertex_cache::scoped_state state(pp);
@ -146,16 +146,16 @@ bool group_symbolizer_helper::collision(box2d<double> const& box, value_unicode_
{
if (!detector_.extent().intersects(box)
||
(placement_->properties.avoid_edges && !query_extent_.contains(box))
(text_props_->avoid_edges && !query_extent_.contains(box))
||
(placement_->properties.minimum_padding > 0 &&
!query_extent_.contains(box + (scale_factor_ * placement_->properties.minimum_padding)))
(text_props_->minimum_padding > 0 &&
!query_extent_.contains(box + (scale_factor_ * text_props_->minimum_padding)))
||
(!placement_->properties.allow_overlap &&
((repeat_key.length() == 0 && !detector_.has_placement(box, placement_->properties.margin * scale_factor_))
(!text_props_->allow_overlap &&
((repeat_key.length() == 0 && !detector_.has_placement(box, text_props_->margin * scale_factor_))
||
(repeat_key.length() > 0 && !detector_.has_placement(box, placement_->properties.margin * scale_factor_,
repeat_key, placement_->properties.repeat_distance * scale_factor_))))
(repeat_key.length() > 0 && !detector_.has_placement(box, text_props_->margin * scale_factor_,
repeat_key, text_props_->repeat_distance * scale_factor_))))
)
{
return true;
@ -166,10 +166,10 @@ bool group_symbolizer_helper::collision(box2d<double> const& box, value_unicode_
double group_symbolizer_helper::get_spacing(double path_length) const
{
int num_labels = 1;
if (placement_->properties.label_spacing > 0)
if (text_props_->label_spacing > 0)
{
num_labels = static_cast<int>(std::floor(
path_length / (placement_->properties.label_spacing * scale_factor_)));
path_length / (text_props_->label_spacing * scale_factor_)));
}
if (num_labels <= 0)
{

View file

@ -51,13 +51,14 @@ placement_finder::placement_finder(feature_impl const& feature,
attr_(attr),
detector_(detector),
extent_(extent),
info_(placement_info),
scale_factor_(scale_factor),
font_manager_(font_manager),
placements_(),
has_marker_(false),
marker_(),
marker_box_() {}
info_(placement_info),
text_props_(info_.properties.evaluate_text_properties(feature_,attr_)),
scale_factor_(scale_factor),
font_manager_(font_manager),
placements_(),
has_marker_(false),
marker_(),
marker_box_() {}
bool placement_finder::next_position()
{
@ -66,6 +67,7 @@ bool placement_finder::next_position()
text_layout_ptr layout = std::make_shared<text_layout>(font_manager_, scale_factor_, info_.properties.layout_defaults);
layout->evaluate_properties(feature_, attr_);
move_dx_ = layout->displacement().x;
text_props_ = info_.properties.evaluate_text_properties(feature_,attr_); // this call is needed (text-bug1533) ??
info_.properties.process(*layout, feature_, attr_);
layouts_.clear(); // FIXME !!!!
layouts_.add(layout);
@ -231,8 +233,8 @@ bool placement_finder::single_line_placement(vertex_cache &pp, text_upright_e or
// Only calculate new angle at the start of each cluster!
angle = normalize_angle(off_pp.angle(sign * layout.cluster_width(current_cluster)));
rot.init(angle);
if ((info_.properties.max_char_angle_delta > 0) && (last_cluster_angle != 999) &&
std::fabs(normalize_angle(angle-last_cluster_angle)) > info_.properties.max_char_angle_delta)
if ((text_props_->max_char_angle_delta > 0) && (last_cluster_angle != 999) &&
std::fabs(normalize_angle(angle-last_cluster_angle)) > text_props_->max_char_angle_delta)
{
return false;
}
@ -307,10 +309,10 @@ double placement_finder::normalize_angle(double angle)
double placement_finder::get_spacing(double path_length, double layout_width) const
{
int num_labels = 1;
if (info_.properties.label_spacing > 0)
if (text_props_->label_spacing > 0)
{
num_labels = static_cast<int>(std::floor(
path_length / (info_.properties.label_spacing * scale_factor_ + layout_width)));
path_length / (text_props_->label_spacing * scale_factor_ + layout_width)));
}
if (num_labels <= 0)
{
@ -324,25 +326,25 @@ bool placement_finder::collision(const box2d<double> &box, const value_unicode_s
double margin, repeat_distance;
if (line_placement)
{
margin = info_.properties.margin * scale_factor_;
repeat_distance = (info_.properties.repeat_distance != 0 ? info_.properties.repeat_distance : info_.properties.minimum_distance) * scale_factor_;
margin = text_props_->margin * scale_factor_;
repeat_distance = (text_props_->repeat_distance != 0 ? text_props_->repeat_distance : text_props_->minimum_distance) * scale_factor_;
}
else
{
margin = (info_.properties.margin != 0 ? info_.properties.margin : info_.properties.minimum_distance) * scale_factor_;
repeat_distance = info_.properties.repeat_distance * scale_factor_;
margin = (text_props_->margin != 0 ? text_props_->margin : text_props_->minimum_distance) * scale_factor_;
repeat_distance = text_props_->repeat_distance * scale_factor_;
}
return !detector_.extent().intersects(box)
||
(info_.properties.avoid_edges && !extent_.contains(box))
||
(info_.properties.minimum_padding > 0 &&
!extent_.contains(box + (scale_factor_ * info_.properties.minimum_padding)))
||
(!info_.properties.allow_overlap &&
((repeat_key.length() == 0 && !detector_.has_placement(box, margin))
||
(repeat_key.length() > 0 && !detector_.has_placement(box, margin, repeat_key, repeat_distance))));
||
(text_props_->avoid_edges && !extent_.contains(box))
||
(text_props_->minimum_padding > 0 &&
!extent_.contains(box + (scale_factor_ * text_props_->minimum_padding)))
||
(!text_props_->allow_overlap &&
((repeat_key.length() == 0 && !detector_.has_placement(box, margin))
||
(repeat_key.length() > 0 && !detector_.has_placement(box, margin, repeat_key, repeat_distance))));
}
void placement_finder::set_marker(marker_info_ptr m, box2d<double> box, bool marker_unlocked, pixel_position const& marker_displacement)
@ -370,14 +372,14 @@ box2d<double> placement_finder::get_bbox(text_layout const& layout, glyph_info c
{
/*
(0/ymax) (width/ymax)
***************
* *
(0/0)* *
* *
***************
(0/ymin) (width/ymin)
Add glyph offset in y direction, but not in x direction (as we use the full cluster width anyways)!
(0/ymax) (width/ymax)
***************
* *
(0/0)* *
* *
***************
(0/ymin) (width/ymin)
Add glyph offset in y direction, but not in x direction (as we use the full cluster width anyways)!
*/
double width = layout.cluster_width(glyph.char_index);
if (glyph.advance() <= 0) width = -width;

View file

@ -58,9 +58,9 @@ base_symbolizer_helper::base_symbolizer_helper(
dims_(0, 0, width, height),
query_extent_(query_extent),
scale_factor_(scale_factor),
placement_(get<text_placements_ptr>(sym_, keys::text_placements_)->get_placement_info(scale_factor))
placement_(get<text_placements_ptr>(sym_, keys::text_placements_)->get_placement_info(scale_factor)),
text_props_(placement_->properties.evaluate_text_properties(feature_,vars_))
{
placement_->properties.evaluate_text_properties(feature_, vars_);
initialize_geometries();
if (!geometries_to_process_.size()) return; // FIXME - bad practise
initialize_points();
@ -78,8 +78,8 @@ struct largest_bbox_first
void base_symbolizer_helper::initialize_geometries() const
{
bool largest_box_only = placement_->properties.largest_bbox_only;
double minimum_path_length = placement_->properties.minimum_path_length;
bool largest_box_only = text_props_->largest_bbox_only;
double minimum_path_length = text_props_->minimum_path_length;
for ( auto const& geom : feature_.paths())
{
// don't bother with empty geometries
@ -111,7 +111,7 @@ void base_symbolizer_helper::initialize_geometries() const
void base_symbolizer_helper::initialize_points() const
{
label_placement_enum how_placed = placement_->properties.label_placement;
label_placement_enum how_placed = text_props_->label_placement;
if (how_placed == LINE_PLACEMENT)
{
point_placement_ = false;

View file

@ -32,7 +32,7 @@
#include <mapnik/config_error.hpp>
#include <mapnik/text/properties_util.hpp>
#include <mapnik/boolean.hpp>
#include <mapnik/make_unique.hpp>
// boost
#include <boost/property_tree/ptree.hpp>
@ -41,51 +41,39 @@ namespace mapnik
using boost::optional;
text_symbolizer_properties::text_symbolizer_properties()
: label_placement(POINT_PLACEMENT),
label_spacing(0.0),
label_position_tolerance(0.0),
avoid_edges(false),
margin(0.0),
repeat_distance(0.0),
minimum_distance(0.0),
minimum_padding(0.0),
minimum_path_length(0.0),
max_char_angle_delta(22.5 * M_PI/180.0),
allow_overlap(false),
largest_bbox_only(true),
upright(UPRIGHT_AUTO),
layout_defaults(),
: layout_defaults(),
format_defaults(),
tree_() {}
void text_symbolizer_properties::evaluate_text_properties(feature_impl const& feature, attributes const& attrs) //const
evaluated_text_properties_ptr text_symbolizer_properties::evaluate_text_properties(feature_impl const& feature, attributes const& attrs) const
{
label_placement = util::apply_visitor(extract_value<label_placement_enum>(feature,attrs), expressions.label_placement);
label_spacing = util::apply_visitor(extract_value<value_double>(feature,attrs), expressions.label_spacing);
label_position_tolerance = util::apply_visitor(extract_value<value_double>(feature,attrs), expressions.label_position_tolerance);
avoid_edges = util::apply_visitor(extract_value<value_bool>(feature,attrs), expressions.avoid_edges);
margin = util::apply_visitor(extract_value<value_double>(feature,attrs), expressions.margin);
repeat_distance = util::apply_visitor(extract_value<value_double>(feature,attrs), expressions.repeat_distance);
minimum_distance = util::apply_visitor(extract_value<value_double>(feature,attrs), expressions.minimum_distance);
minimum_padding = util::apply_visitor(extract_value<value_double>(feature,attrs), expressions.minimum_padding);
minimum_path_length = util::apply_visitor(extract_value<value_double>(feature,attrs), expressions.minimum_path_length);
max_char_angle_delta = util::apply_visitor(extract_value<value_double>(feature,attrs), expressions.max_char_angle_delta) * M_PI/180;
allow_overlap = util::apply_visitor(extract_value<value_bool>(feature,attrs), expressions.allow_overlap);
largest_bbox_only = util::apply_visitor(extract_value<value_bool>(feature,attrs), expressions.largest_bbox_only);
upright = util::apply_visitor(extract_value<text_upright_enum>(feature,attrs), expressions.upright);
// evaluate text properties
evaluated_text_properties_ptr prop = std::make_unique<detail::evaluated_text_properties>();
prop->label_placement = util::apply_visitor(extract_value<label_placement_enum>(feature,attrs), expressions.label_placement);
prop->label_spacing = util::apply_visitor(extract_value<value_double>(feature,attrs), expressions.label_spacing);
prop->label_position_tolerance = util::apply_visitor(extract_value<value_double>(feature,attrs), expressions.label_position_tolerance);
prop->avoid_edges = util::apply_visitor(extract_value<value_bool>(feature,attrs), expressions.avoid_edges);
prop->margin = util::apply_visitor(extract_value<value_double>(feature,attrs), expressions.margin);
prop->repeat_distance = util::apply_visitor(extract_value<value_double>(feature,attrs), expressions.repeat_distance);
prop->minimum_distance = util::apply_visitor(extract_value<value_double>(feature,attrs), expressions.minimum_distance);
prop->minimum_padding = util::apply_visitor(extract_value<value_double>(feature,attrs), expressions.minimum_padding);
prop->minimum_path_length = util::apply_visitor(extract_value<value_double>(feature,attrs), expressions.minimum_path_length);
prop->max_char_angle_delta = util::apply_visitor(extract_value<value_double>(feature,attrs), expressions.max_char_angle_delta) * M_PI/180;
prop->allow_overlap = util::apply_visitor(extract_value<value_bool>(feature,attrs), expressions.allow_overlap);
prop->largest_bbox_only = util::apply_visitor(extract_value<value_bool>(feature,attrs), expressions.largest_bbox_only);
prop->upright = util::apply_visitor(extract_value<text_upright_enum>(feature,attrs), expressions.upright);
return prop;
}
void text_symbolizer_properties::process(text_layout & output, feature_impl const& feature, attributes const& attrs) //const
void text_symbolizer_properties::process(text_layout & output, feature_impl const& feature, attributes const& attrs) const
{
output.clear();
if (tree_)
{
evaluate_text_properties(feature, attrs);
//evaluate format properties
evaluated_format_properties_ptr format = std::make_shared<detail::evaluated_format_properties>();
format->text_size = util::apply_visitor(extract_value<value_double>(feature,attrs), format_defaults.text_size);
format->character_spacing = util::apply_visitor(extract_value<value_double>(feature,attrs), format_defaults.character_spacing);
format->line_spacing = util::apply_visitor(extract_value<value_double>(feature,attrs), format_defaults.line_spacing);