diff --git a/include/mapnik/evaluate_global_attributes.hpp b/include/mapnik/evaluate_global_attributes.hpp index 3df6772be..c2f6a75f2 100644 --- a/include/mapnik/evaluate_global_attributes.hpp +++ b/include/mapnik/evaluate_global_attributes.hpp @@ -24,6 +24,7 @@ #define MAPNIK_EVALUATE_GLOBAL_ATTRIBUTES_HPP #include +#include #include #include #include diff --git a/include/mapnik/symbolizer.hpp b/include/mapnik/symbolizer.hpp index 14472484a..32c7b9c7b 100644 --- a/include/mapnik/symbolizer.hpp +++ b/include/mapnik/symbolizer.hpp @@ -146,7 +146,8 @@ enum class property_types : std::uint8_t target_text_transform, target_horizontal_alignment, target_justify_alignment, - target_vertical_alignment + target_vertical_alignment, + target_upright }; inline bool operator==(symbolizer_base const& lhs, symbolizer_base const& rhs) diff --git a/include/mapnik/symbolizer_enumerations.hpp b/include/mapnik/symbolizer_enumerations.hpp index adb4cc24a..11ec98df4 100644 --- a/include/mapnik/symbolizer_enumerations.hpp +++ b/include/mapnik/symbolizer_enumerations.hpp @@ -172,17 +172,17 @@ enum justify_alignment_enum DEFINE_ENUM(justify_alignment_e, justify_alignment_enum); -enum text_upright +enum text_upright_enum { UPRIGHT_AUTO, UPRIGHT_LEFT, UPRIGHT_RIGHT, UPRIGHT_LEFT_ONLY, UPRIGHT_RIGHT_ONLY, - text_upright_MAX + text_upright_enum_MAX }; -DEFINE_ENUM(text_upright_e, text_upright); +DEFINE_ENUM(text_upright_e, text_upright_enum); } diff --git a/include/mapnik/symbolizer_keys.hpp b/include/mapnik/symbolizer_keys.hpp index c8ba04a46..27b9bd0dd 100644 --- a/include/mapnik/symbolizer_keys.hpp +++ b/include/mapnik/symbolizer_keys.hpp @@ -72,6 +72,7 @@ enum class keys : std::uint8_t simplify_tolerance, halo_rasterizer, text_placements_, + label_placement, markers_placement_type, markers_multipolicy, point_placement_type, @@ -88,6 +89,7 @@ enum class keys : std::uint8_t horizontal_alignment, justify_alignment, vertical_alignment, + upright, MAX_SYMBOLIZER_KEY }; diff --git a/include/mapnik/text/text_properties.hpp b/include/mapnik/text/text_properties.hpp index eb218019d..a1d673887 100644 --- a/include/mapnik/text/text_properties.hpp +++ b/include/mapnik/text/text_properties.hpp @@ -122,7 +122,21 @@ struct MAPNIK_DECL text_layout_properties class text_layout; -struct text_properties_expressions : symbolizer_base {}; +struct text_properties_expressions +{ + symbolizer_base::value_type label_placement = enumeration_wrapper(POINT_PLACEMENT); + symbolizer_base::value_type label_spacing = 0.0; + symbolizer_base::value_type label_position_tolerance = 0.0; + symbolizer_base::value_type avoid_edges = false; + symbolizer_base::value_type minimum_distance = 0.0; + symbolizer_base::value_type minimum_padding = 0.0; + symbolizer_base::value_type minimum_path_length = 0.0; + symbolizer_base::value_type max_char_angle_delta = 22.5; + symbolizer_base::value_type force_odd_labels = false; + symbolizer_base::value_type allow_overlap = false; + symbolizer_base::value_type largest_bbox_only = true; + symbolizer_base::value_type upright = enumeration_wrapper(UPRIGHT_AUTO); +}; // Contains all text symbolizer properties which are not directly related to text formatting and layout. struct MAPNIK_DECL text_symbolizer_properties @@ -138,7 +152,8 @@ struct MAPNIK_DECL text_symbolizer_properties // Takes a feature and produces formated 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) const; + void process(text_layout &output, feature_impl const& feature, attributes const& vars); + void evaluate_text_properties(feature_impl const& feature, attributes const& attrs); // Automatically create processing instructions for a single expression. void set_old_style_expression(expression_ptr expr); // Sets new format tree. diff --git a/src/symbolizer_keys.cpp b/src/symbolizer_keys.cpp index a61b418f4..6756c5052 100644 --- a/src/symbolizer_keys.cpp +++ b/src/symbolizer_keys.cpp @@ -83,11 +83,14 @@ static const property_meta_type key_meta[to_integral(keys::MAX_SYMBOLIZER_KEY)] property_meta_type{ "halo-rasterizer", enumeration_wrapper(HALO_RASTERIZER_FULL), [](enumeration_wrapper e) { return enumeration(halo_rasterizer_enum(e.value)).as_string();}, property_types::target_halo_rasterizer }, property_meta_type{ "text-placements", false, nullptr, property_types::target_double }, - property_meta_type{ "placement", enumeration_wrapper(MARKER_POINT_PLACEMENT), - [](enumeration_wrapper e) { return enumeration(marker_placement_enum(e.value)).as_string();}, property_types::target_markers_placement }, // FIXME - rename to "markers-placement-type" + property_meta_type{ "placement", enumeration_wrapper(POINT_PLACEMENT), + [](enumeration_wrapper e) + { return enumeration(label_placement_enum(e.value)).as_string();}, property_types::target_placement }, + property_meta_type{ "placement", enumeration_wrapper(MARKER_POINT_PLACEMENT), // FIXME - change property name + [](enumeration_wrapper e) { return enumeration(marker_placement_enum(e.value)).as_string();}, property_types::target_markers_placement }, property_meta_type{ "multi-policy", enumeration_wrapper(MARKER_EACH_MULTI), [](enumeration_wrapper e) { return enumeration(marker_multi_policy_enum(e.value)).as_string();}, property_types::target_markers_multipolicy }, - property_meta_type{ "placement", enumeration_wrapper(CENTROID_POINT_PLACEMENT), + property_meta_type{ "placement", enumeration_wrapper(CENTROID_POINT_PLACEMENT), // FIXME - change property name [](enumeration_wrapper e) { return enumeration(point_placement_enum(e.value)).as_string();}, property_types::target_double }, property_meta_type{ "colorizer", nullptr, nullptr, property_types::target_colorizer}, property_meta_type{ "halo-transform", false, nullptr, property_types::target_transform }, @@ -109,7 +112,10 @@ static const property_meta_type key_meta[to_integral(keys::MAX_SYMBOLIZER_KEY)] property_types::target_justify_alignment}, property_meta_type{ "vertical-alignment", enumeration_wrapper(V_TOP), [](enumeration_wrapper e) {return enumeration(vertical_alignment_enum(e.value)).as_string();}, - property_types::target_vertical_alignment} + property_types::target_vertical_alignment}, + property_meta_type{ "upright", enumeration_wrapper(UPRIGHT_AUTO), [](enumeration_wrapper e) + {return enumeration(text_upright_enum(e.value)).as_string();}, + property_types::target_upright} }; diff --git a/src/text/symbolizer_helpers.cpp b/src/text/symbolizer_helpers.cpp index 81afe6a6a..860a65ada 100644 --- a/src/text/symbolizer_helpers.cpp +++ b/src/text/symbolizer_helpers.cpp @@ -58,6 +58,7 @@ base_symbolizer_helper::base_symbolizer_helper( clipped_(get(sym_, keys::clip, feature_, vars_, false)), placement_(get(sym_, keys::text_placements_)->get_placement_info(scale_factor)) { + placement_->properties.evaluate_text_properties(feature_, vars_); initialize_geometries(); if (!geometries_to_process_.size()) return; // FIXME - bad practise initialize_points(); diff --git a/src/text/text_properties.cpp b/src/text/text_properties.cpp index cd1b7618b..c6f1af561 100644 --- a/src/text/text_properties.cpp +++ b/src/text/text_properties.cpp @@ -53,14 +53,33 @@ text_symbolizer_properties::text_symbolizer_properties() largest_bbox_only(true), upright(UPRIGHT_AUTO), layout_defaults(), - format_defaults(),//std::make_shared()), + format_defaults(), tree_() {} -void text_symbolizer_properties::process(text_layout & output, feature_impl const& feature, attributes const& attrs) const + +void text_symbolizer_properties::evaluate_text_properties(feature_impl const& feature, attributes const& attrs) +{ + label_placement = boost::apply_visitor(extract_value(feature,attrs), expressions.label_placement); + label_spacing = boost::apply_visitor(extract_value(feature,attrs), expressions.label_spacing); + label_position_tolerance = boost::apply_visitor(extract_value(feature,attrs), expressions.label_position_tolerance); + avoid_edges = boost::apply_visitor(extract_value(feature,attrs), expressions.avoid_edges); + minimum_distance = boost::apply_visitor(extract_value(feature,attrs), expressions.minimum_distance); + minimum_padding = boost::apply_visitor(extract_value(feature,attrs), expressions.minimum_padding); + minimum_path_length = boost::apply_visitor(extract_value(feature,attrs), expressions.minimum_path_length); + max_char_angle_delta = boost::apply_visitor(extract_value(feature,attrs), expressions.max_char_angle_delta) * M_PI/180; + force_odd_labels = boost::apply_visitor(extract_value(feature,attrs), expressions.force_odd_labels); + allow_overlap = boost::apply_visitor(extract_value(feature,attrs), expressions.allow_overlap); + largest_bbox_only = boost::apply_visitor(extract_value(feature,attrs), expressions.largest_bbox_only); + upright = boost::apply_visitor(extract_value(feature,attrs), expressions.upright); +} + +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(); @@ -97,33 +116,18 @@ formatting::node_ptr text_symbolizer_properties::format_tree() const void text_symbolizer_properties::text_properties_from_xml(xml_node const& node) { - optional placement_ = node.get_opt_attr("placement"); - if (placement_) label_placement = *placement_; - optional label_position_tolerance_ = node.get_opt_attr("label-position-tolerance"); - if (label_position_tolerance_) label_position_tolerance = *label_position_tolerance_; - optional spacing_ = node.get_opt_attr("spacing"); - if (spacing_) label_spacing = *spacing_; - else { - // https://github.com/mapnik/mapnik/issues/1427 - spacing_ = node.get_opt_attr("label-spacing"); - if (spacing_) label_spacing = *spacing_; - } - optional minimum_distance_ = node.get_opt_attr("minimum-distance"); - if (minimum_distance_) minimum_distance = *minimum_distance_; - optional min_padding_ = node.get_opt_attr("minimum-padding"); - if (min_padding_) minimum_padding = *min_padding_; - optional min_path_length_ = node.get_opt_attr("minimum-path-length"); - if (min_path_length_) minimum_path_length = *min_path_length_; - optional avoid_edges_ = node.get_opt_attr("avoid-edges"); - if (avoid_edges_) avoid_edges = *avoid_edges_; - optional allow_overlap_ = node.get_opt_attr("allow-overlap"); - if (allow_overlap_) allow_overlap = *allow_overlap_; - optional largest_bbox_only_ = node.get_opt_attr("largest-bbox-only"); - if (largest_bbox_only_) largest_bbox_only = *largest_bbox_only_; - optional max_char_angle_delta_ = node.get_opt_attr("max-char-angle-delta"); - if (max_char_angle_delta_) max_char_angle_delta=(*max_char_angle_delta_)*(M_PI/180); - optional upright_ = node.get_opt_attr("upright"); - if (upright_) upright = *upright_; + set_property_from_xml(expressions.label_placement, "placement", node); + set_property_from_xml(expressions.label_spacing, "spacing", node); + set_property_from_xml(expressions.label_position_tolerance, "label-position-tolerance", node); + set_property_from_xml(expressions.minimum_distance, "minimum-distance", node); + set_property_from_xml(expressions.minimum_padding, "minimum-padding", node); + set_property_from_xml(expressions.minimum_path_length, "minimum-path-length", node); + set_property_from_xml(expressions.avoid_edges, "avoid-edges", node); + set_property_from_xml(expressions.allow_overlap, "allow-overlap", node); + set_property_from_xml(expressions.largest_bbox_only, "largest-bbox-only", node); + set_property_from_xml(expressions.force_odd_labels, "force-odd-labels", node); + set_property_from_xml(expressions.max_char_angle_delta, "max-char-angle-delta", node); + set_property_from_xml(expressions.upright, "upright", node); } void text_symbolizer_properties::from_xml(xml_node const& node, fontset_map const& fontsets) @@ -146,49 +150,49 @@ void text_symbolizer_properties::to_xml(boost::property_tree::ptree &node, bool explicit_defaults, text_symbolizer_properties const& dfl) const { - if (label_placement != dfl.label_placement || explicit_defaults) + if (!(expressions.label_placement == dfl.expressions.label_placement) || explicit_defaults) { - set_attr(node, "placement", label_placement); + serialize_property("placement", expressions.label_placement, node); } - if (label_position_tolerance != dfl.label_position_tolerance || explicit_defaults) + if (!(expressions.label_position_tolerance == dfl.expressions.label_position_tolerance) || explicit_defaults) { - set_attr(node, "label-position-tolerance", label_position_tolerance); + serialize_property("label-position-tolerance", expressions.label_position_tolerance,node); } - if (label_spacing != dfl.label_spacing || explicit_defaults) + if (!(expressions.label_spacing == dfl.expressions.label_spacing) || explicit_defaults) { - set_attr(node, "spacing", label_spacing); + serialize_property("spacing", expressions.label_spacing, node); } - if (minimum_distance != dfl.minimum_distance || explicit_defaults) + if (!(expressions.minimum_distance == dfl.expressions.minimum_distance) || explicit_defaults) { - set_attr(node, "minimum-distance", minimum_distance); + serialize_property("minimum-distance", expressions.minimum_distance, node); } - if (minimum_padding != dfl.minimum_padding || explicit_defaults) + if (!(expressions.minimum_padding == dfl.expressions.minimum_padding) || explicit_defaults) { - set_attr(node, "minimum-padding", minimum_padding); + serialize_property("minimum-padding", expressions.minimum_padding, node); } - if (minimum_path_length != dfl.minimum_path_length || explicit_defaults) + if (!(expressions.minimum_path_length == dfl.expressions.minimum_path_length) || explicit_defaults) { - set_attr(node, "minimum-path-length", minimum_path_length); + serialize_property("minimum-path-length", expressions.minimum_path_length, node); } - if (avoid_edges != dfl.avoid_edges || explicit_defaults) + if (!(expressions.avoid_edges == dfl.expressions.avoid_edges) || explicit_defaults) { - set_attr(node, "avoid-edges", avoid_edges); + serialize_property("avoid-edges", expressions.avoid_edges, node); } - if (allow_overlap != dfl.allow_overlap || explicit_defaults) + if (!(expressions.allow_overlap == dfl.expressions.allow_overlap) || explicit_defaults) { - set_attr(node, "allow-overlap", allow_overlap); + serialize_property("allow-overlap", expressions.allow_overlap, node); } - if (largest_bbox_only != dfl.largest_bbox_only || explicit_defaults) + if (!(expressions.largest_bbox_only == dfl.expressions.largest_bbox_only) || explicit_defaults) { - set_attr(node, "largest-bbox-only", largest_bbox_only); + serialize_property("largest-bbox-only", expressions.largest_bbox_only, node); } - if (max_char_angle_delta != dfl.max_char_angle_delta || explicit_defaults) + if (!(expressions.max_char_angle_delta == dfl.expressions.max_char_angle_delta) || explicit_defaults) { - set_attr(node, "max-char-angle-delta", max_char_angle_delta/(M_PI/180)); + serialize_property("max-char-angle-delta", expressions.max_char_angle_delta, node); } - if (upright != dfl.upright || explicit_defaults) + if (!(expressions.upright == dfl.expressions.upright) || explicit_defaults) { - set_attr(node, "upright", upright); + serialize_property("upright", expressions.upright, node); } layout_defaults.to_xml(node, explicit_defaults, dfl.layout_defaults); @@ -199,6 +203,19 @@ void text_symbolizer_properties::to_xml(boost::property_tree::ptree &node, void text_symbolizer_properties::add_expressions(expression_set & output) const { + if (is_expression(expressions.label_placement)) output.insert(boost::get(expressions.label_placement)); + if (is_expression(expressions.label_spacing)) output.insert(boost::get(expressions.label_spacing)); + if (is_expression(expressions.label_position_tolerance)) output.insert(boost::get(expressions.label_position_tolerance)); + if (is_expression(expressions.avoid_edges)) output.insert(boost::get(expressions.avoid_edges)); + if (is_expression(expressions.minimum_distance)) output.insert(boost::get(expressions.minimum_distance)); + if (is_expression(expressions.minimum_padding)) output.insert(boost::get(expressions.minimum_padding)); + if (is_expression(expressions.minimum_path_length)) output.insert(boost::get(expressions.minimum_path_length)); + if (is_expression(expressions.max_char_angle_delta)) output.insert(boost::get(expressions.max_char_angle_delta)); + if (is_expression(expressions.force_odd_labels)) output.insert(boost::get(expressions.force_odd_labels)); + if (is_expression(expressions.allow_overlap)) output.insert(boost::get(expressions.allow_overlap)); + if (is_expression(expressions.largest_bbox_only)) output.insert(boost::get(expressions.largest_bbox_only)); + if (is_expression(expressions.upright)) output.insert(boost::get(expressions.upright)); + layout_defaults.add_expressions(output); format_defaults.add_expressions(output); if (tree_) tree_->add_expressions(output); @@ -220,8 +237,8 @@ void text_layout_properties::from_xml(xml_node const &node) set_property_from_xml(dy, "dy", node); set_property_from_xml(text_ratio, "text-ratio", node); set_property_from_xml(wrap_width, "wrap-width", node); - set_property_from_xml(wrap_before, "wrap-before", node); - set_property_from_xml(rotate_displacement, "rotate-displacement", node); + set_property_from_xml(wrap_before, "wrap-before", node); + set_property_from_xml(rotate_displacement, "rotate-displacement", node); set_property_from_xml(orientation, "orientation", node); set_property_from_xml(valign, "vertical-alignment", node); set_property_from_xml(halign, "horizontal-alignment", node); @@ -260,7 +277,6 @@ void text_layout_properties::add_expressions(expression_set & output) const } // text format properties - format_properties::format_properties() : face_name(), fontset(),