/***************************************************************************** * * This file is part of Mapnik (c++ mapping toolkit) * * Copyright (C) 2013 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 #include #include #include #include #include #include #include #include // boost #include 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), minimum_distance(0.0), minimum_padding(0.0), minimum_path_length(0.0), max_char_angle_delta(22.5 * M_PI/180.0), force_odd_labels(false), allow_overlap(false), largest_bbox_only(true), upright(UPRIGHT_AUTO), layout_defaults(), format(std::make_shared()), tree_() {} void text_symbolizer_properties::process(text_layout &output, feature_impl const& feature, attributes const& vars) const { output.clear(); if (tree_) { tree_->apply(format, feature, vars, output); } else { MAPNIK_LOG_WARN(text_properties) << "text_symbolizer_properties can't produce text: No formatting tree!"; } } void text_symbolizer_properties::set_format_tree(formatting::node_ptr tree) { tree_ = tree; } formatting::node_ptr text_symbolizer_properties::format_tree() const { return tree_; } void text_symbolizer_properties::placement_properties_from_xml(xml_node const &sym) { optional placement_ = sym.get_opt_attr("placement"); if (placement_) label_placement = *placement_; optional label_position_tolerance_ = sym.get_opt_attr("label-position-tolerance"); if (label_position_tolerance_) label_position_tolerance = *label_position_tolerance_; optional spacing_ = sym.get_opt_attr("spacing"); if (spacing_) label_spacing = *spacing_; else { // https://github.com/mapnik/mapnik/issues/1427 spacing_ = sym.get_opt_attr("label-spacing"); if (spacing_) label_spacing = *spacing_; } optional minimum_distance_ = sym.get_opt_attr("minimum-distance"); if (minimum_distance_) minimum_distance = *minimum_distance_; optional min_padding_ = sym.get_opt_attr("minimum-padding"); if (min_padding_) minimum_padding = *min_padding_; optional min_path_length_ = sym.get_opt_attr("minimum-path-length"); if (min_path_length_) minimum_path_length = *min_path_length_; optional avoid_edges_ = sym.get_opt_attr("avoid-edges"); if (avoid_edges_) avoid_edges = *avoid_edges_; optional allow_overlap_ = sym.get_opt_attr("allow-overlap"); if (allow_overlap_) allow_overlap = *allow_overlap_; optional largest_bbox_only_ = sym.get_opt_attr("largest-bbox-only"); if (largest_bbox_only_) largest_bbox_only = *largest_bbox_only_; } void text_symbolizer_properties::from_xml(xml_node const &sym, fontset_map const & fontsets) { placement_properties_from_xml(sym); optional max_char_angle_delta_ = sym.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_ = sym.get_opt_attr("upright"); if (upright_) upright = *upright_; layout_defaults.from_xml(sym); optional name_ = sym.get_opt_attr("name"); if (name_) { MAPNIK_LOG_WARN(text_placements) << "Using 'name' in TextSymbolizer/ShieldSymbolizer is deprecated!"; set_old_style_expression(*name_); } format->from_xml(sym, fontsets); formatting::node_ptr n(formatting::node::from_xml(sym)); if (n) set_format_tree(n); } 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) { set_attr(node, "placement", label_placement); } if (label_position_tolerance != dfl.label_position_tolerance || explicit_defaults) { set_attr(node, "label-position-tolerance", label_position_tolerance); } if (label_spacing != dfl.label_spacing || explicit_defaults) { set_attr(node, "spacing", label_spacing); } if (minimum_distance != dfl.minimum_distance || explicit_defaults) { set_attr(node, "minimum-distance", minimum_distance); } if (minimum_padding != dfl.minimum_padding || explicit_defaults) { set_attr(node, "minimum-padding", minimum_padding); } if (minimum_path_length != dfl.minimum_path_length || explicit_defaults) { set_attr(node, "minimum-path-length", minimum_path_length); } if (avoid_edges != dfl.avoid_edges || explicit_defaults) { set_attr(node, "avoid-edges", avoid_edges); } if (allow_overlap != dfl.allow_overlap || explicit_defaults) { set_attr(node, "allow-overlap", allow_overlap); } if (largest_bbox_only != dfl.largest_bbox_only || explicit_defaults) { set_attr(node, "largest-bbox-only", largest_bbox_only); } if (max_char_angle_delta != dfl.max_char_angle_delta || explicit_defaults) { set_attr(node, "max-char-angle-delta", max_char_angle_delta/(M_PI/180)); } if (upright != dfl.upright || explicit_defaults) { set_attr(node, "upright", upright); } layout_defaults.to_xml(node, explicit_defaults, dfl.layout_defaults); format->to_xml(node, explicit_defaults, *(dfl.format)); if (tree_) tree_->to_xml(node); } void text_symbolizer_properties::add_expressions(expression_set &output) const { layout_defaults.add_expressions(output); if (tree_) tree_->add_expressions(output); } void text_symbolizer_properties::set_old_style_expression(expression_ptr expr) { tree_ = std::make_shared(expr); } text_layout_properties::text_layout_properties() : orientation(), displacement(0.0,0.0), halign(H_AUTO), jalign(J_AUTO), valign(V_AUTO), text_ratio(0.0), wrap_width(0.0), wrap_before(false), rotate_displacement(false) {} void text_layout_properties::from_xml(xml_node const &sym) { optional dx = sym.get_opt_attr("dx"); if (dx) displacement.x = *dx; optional dy = sym.get_opt_attr("dy"); if (dy) displacement.y = *dy; optional valign_ = sym.get_opt_attr("vertical-alignment"); if (valign_) valign = *valign_; optional halign_ = sym.get_opt_attr("horizontal-alignment"); if (halign_) halign = *halign_; optional jalign_ = sym.get_opt_attr("justify-alignment"); if (jalign_) jalign = *jalign_; optional text_ratio_ = sym.get_opt_attr("text-ratio"); if (text_ratio_) text_ratio = *text_ratio_; optional wrap_width_ = sym.get_opt_attr("wrap-width"); if (wrap_width_) wrap_width = *wrap_width_; optional wrap_before_ = sym.get_opt_attr("wrap-before"); if (wrap_before_) wrap_before = *wrap_before_; optional rotate_displacement_ = sym.get_opt_attr("rotate-displacement"); if (rotate_displacement_) rotate_displacement = *rotate_displacement_; // TODO!! try { optional val = sym.get_opt_attr("orientation"); if (val) orientation = *val; } catch (config_error const& ex) { optional val = sym.get_opt_attr("orientation"); if (val) orientation = *val; else { ex.append_context(std::string("text_layout_properties::from_xml 'orientation'"), sym); } } //optional orientation_ = sym.get_opt_attr("orientation"); //if (orientation_) orientation = *orientation_; } void text_layout_properties::to_xml(boost::property_tree::ptree &node, bool explicit_defaults, text_layout_properties const& dfl) const { if (displacement.x != dfl.displacement.x || explicit_defaults) { set_attr(node, "dx", displacement.x); } if (displacement.y != dfl.displacement.y || explicit_defaults) { set_attr(node, "dy", displacement.y); } if (valign != dfl.valign || explicit_defaults) { set_attr(node, "vertical-alignment", valign); } if (halign != dfl.halign || explicit_defaults) { set_attr(node, "horizontal-alignment", halign); } if (jalign != dfl.jalign || explicit_defaults) { set_attr(node, "justify-alignment", jalign); } if (text_ratio != dfl.text_ratio || explicit_defaults) { set_attr(node, "text-ratio", text_ratio); } if (wrap_width != dfl.wrap_width || explicit_defaults) { set_attr(node, "wrap-width", wrap_width); } if (wrap_before != dfl.wrap_before || explicit_defaults) { set_attr(node, "wrap-before", wrap_before); } if (rotate_displacement != dfl.rotate_displacement || explicit_defaults) { set_attr(node, "rotate-displacement", rotate_displacement); } /// TODO //if (orientation) //{ // std::string const& orientationstr = to_expression_string(*orientation); // if (!dfl.orientation || orientationstr != to_expression_string(*(dfl.orientation)) || explicit_defaults) { // set_attr(node, "orientation", orientationstr); // } //} } void text_layout_properties::add_expressions(expression_set &output) const { //output.insert(orientation); } char_properties::char_properties() : face_name(), fontset(), text_size(10.0), character_spacing(0), line_spacing(0), text_opacity(1.0), halo_opacity(1.0), wrap_char(' '), text_transform(NONE), fill(color(0,0,0)), halo_fill(color(255,255,255)), halo_radius(0) { } void char_properties::from_xml(xml_node const& node, fontset_map const& fontsets) { optional text_size_ = node.get_opt_attr("size"); if (text_size_) text_size = *text_size_; optional character_spacing_ = node.get_opt_attr("character-spacing"); if (character_spacing_) character_spacing = *character_spacing_; optional fill_ = node.get_opt_attr("fill"); if (fill_) fill = *fill_; optional halo_fill_ = node.get_opt_attr("halo-fill"); if (halo_fill_) halo_fill = *halo_fill_; optional halo_radius_ = node.get_opt_attr("halo-radius"); if (halo_radius_) halo_radius = *halo_radius_; optional tconvert_ = node.get_opt_attr("text-transform"); if (tconvert_) text_transform = *tconvert_; optional line_spacing_ = node.get_opt_attr("line-spacing"); if (line_spacing_) line_spacing = *line_spacing_; optional opacity_ = node.get_opt_attr("opacity"); if (opacity_) text_opacity = *opacity_; optional halo_opacity_ = node.get_opt_attr("halo-opacity"); if (halo_opacity_) halo_opacity = *halo_opacity_; optional wrap_char_ = node.get_opt_attr("wrap-character"); if (wrap_char_ && (*wrap_char_).size() > 0) wrap_char = ((*wrap_char_)[0]); optional face_name_ = node.get_opt_attr("face-name"); if (face_name_) { face_name = *face_name_; } optional fontset_name_ = node.get_opt_attr("fontset-name"); if (fontset_name_) { std::map::const_iterator itr = fontsets.find(*fontset_name_); if (itr != fontsets.end()) { fontset = itr->second; } else { throw config_error("Unable to find any fontset named '" + *fontset_name_ + "'", node); } } if (!face_name.empty() && fontset) { throw config_error("Can't have both face-name and fontset-name", node); } if (face_name.empty() && !fontset) { throw config_error("Must have face-name or fontset-name", node); } } void char_properties::to_xml(boost::property_tree::ptree& node, bool explicit_defaults, char_properties const& dfl) const { if (fontset) { set_attr(node, "fontset-name", fontset->get_name()); } if (face_name != dfl.face_name || explicit_defaults) { set_attr(node, "face-name", face_name); } if (text_size != dfl.text_size || explicit_defaults) { set_attr(node, "size", text_size); } if (fill != dfl.fill || explicit_defaults) { set_attr(node, "fill", fill); } if (halo_radius != dfl.halo_radius || explicit_defaults) { set_attr(node, "halo-radius", halo_radius); } if (halo_fill != dfl.halo_fill || explicit_defaults) { set_attr(node, "halo-fill", halo_fill); } if (wrap_char != dfl.wrap_char || explicit_defaults) { set_attr(node, "wrap-character", std::string(1, wrap_char)); } if (text_transform != dfl.text_transform || explicit_defaults) { set_attr(node, "text-transform", text_transform); } if (line_spacing != dfl.line_spacing || explicit_defaults) { set_attr(node, "line-spacing", line_spacing); } if (character_spacing != dfl.character_spacing || explicit_defaults) { set_attr(node, "character-spacing", character_spacing); } // for shield_symbolizer this is later overridden if (text_opacity != dfl.text_opacity || explicit_defaults) { set_attr(node, "opacity", text_opacity); } // for shield_symbolizer this is later overridden if (halo_opacity != dfl.halo_opacity || explicit_defaults) { set_attr(node, "halo-opacity", halo_opacity); } } } //ns mapnik