diff --git a/src/build.py b/src/build.py index 567d32e73..e12ec4d33 100644 --- a/src/build.py +++ b/src/build.py @@ -152,7 +152,6 @@ source = Split( metawriter.cpp raster_colorizer.cpp text_placements.cpp - text_processing.cpp wkt/wkt_factory.cpp metawriter_inmem.cpp metawriter_factory.cpp @@ -165,7 +164,12 @@ source = Split( warp.cpp json/feature_collection_parser.cpp markers_placement.cpp + processed_text.cpp + formatting/base.cpp formatting/expression.cpp + formatting/list.cpp + formatting/text.cpp + formatting/format.cpp """ ) diff --git a/src/formatting/base.cpp b/src/formatting/base.cpp new file mode 100644 index 000000000..2cf76a24d --- /dev/null +++ b/src/formatting/base.cpp @@ -0,0 +1,77 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2012 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 + +// boost +#include + +namespace mapnik { +namespace formatting { + +void node::to_xml(boost::property_tree::ptree &xml) const +{ + //TODO: Should this throw a config_error? +#ifdef MAPNIK_DEBUG + std::cerr << "Error: Trying to write unsupported node type to XML.\n"; +#endif +} + +node_ptr node::from_xml(boost::property_tree::ptree const& xml) +{ + list_node *list = new list_node(); + node_ptr list_ptr(list); + boost::property_tree::ptree::const_iterator itr = xml.begin(); + boost::property_tree::ptree::const_iterator end = xml.end(); + for (; itr != end; ++itr) { + node_ptr n; + if (itr->first == "") { + n = text_node::from_xml(itr->second); + } else if (itr->first == "Format") { + n = format_node::from_xml(itr->second); + } else if (itr->first == "ExpressionFormat") { + n = expression_format::from_xml(itr->second); + } else if (itr->first != "" && itr->first != "" && itr->first != "Placement") { + throw config_error("Unknown item " + itr->first); + } + if (n) list->push_back(n); + } + if (list->get_children().size() == 1) { + return list->get_children()[0]; + } else if (list->get_children().size() > 1) { + return list_ptr; + } else { + return node_ptr(); + } +} + +void node::add_expressions(expression_set &output) const +{ + //Do nothing by default +} + +} //ns formatting +} //ns mapnik diff --git a/src/formatting/format.cpp b/src/formatting/format.cpp new file mode 100644 index 000000000..860896dce --- /dev/null +++ b/src/formatting/format.cpp @@ -0,0 +1,114 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2012 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 + * + *****************************************************************************/ +#include +#include + +namespace mapnik { +using boost::property_tree::ptree; + +namespace formatting { +void format_node::to_xml(ptree &xml) const +{ + ptree &new_node = xml.push_back(ptree::value_type("Format", ptree()))->second; + if (face_name) set_attr(new_node, "face-name", *face_name); + if (text_size) set_attr(new_node, "size", *text_size); + if (character_spacing) set_attr(new_node, "character-spacing", *character_spacing); + if (line_spacing) set_attr(new_node, "line-spacing", *line_spacing); + if (text_opacity) set_attr(new_node, "opacity", *text_opacity); + if (wrap_before) set_attr(new_node, "wrap-before", *wrap_before); + if (wrap_char) set_attr(new_node, "wrap-character", *wrap_char); + if (text_transform) set_attr(new_node, "text-transform", *text_transform); + if (fill) set_attr(new_node, "fill", *fill); + if (halo_fill) set_attr(new_node, "halo-fill", *halo_fill); + if (halo_radius) set_attr(new_node, "halo-radius", *halo_radius); + if (child_) child_->to_xml(new_node); +} + + +node_ptr format_node::from_xml(ptree const& xml) +{ + format_node *n = new format_node(); + node_ptr np(n); + + node_ptr child = node::from_xml(xml); + n->set_child(child); + + n->face_name = get_opt_attr(xml, "face-name"); + /*TODO: Fontset is problematic. We don't have the fontsets pointer here... */ + n->text_size = get_opt_attr(xml, "size"); + n->character_spacing = get_opt_attr(xml, "character-spacing"); + n->line_spacing = get_opt_attr(xml, "line-spacing"); + n->text_opacity = get_opt_attr(xml, "opactity"); + boost::optional wrap = get_opt_attr(xml, "wrap-before"); + if (wrap) n->wrap_before = *wrap; + n->wrap_char = get_opt_attr(xml, "wrap-character"); + n->text_transform = get_opt_attr(xml, "text-transform"); + n->fill = get_opt_attr(xml, "fill"); + n->halo_fill = get_opt_attr(xml, "halo-fill"); + n->halo_radius = get_opt_attr(xml, "halo-radius"); + return np; +} + + +void format_node::apply(char_properties const& p, const Feature &feature, processed_text &output) const +{ + char_properties new_properties = p; + if (face_name) new_properties.face_name = *face_name; + if (text_size) new_properties.text_size = *text_size; + if (character_spacing) new_properties.character_spacing = *character_spacing; + if (line_spacing) new_properties.line_spacing = *line_spacing; + if (text_opacity) new_properties.text_opacity = *text_opacity; + if (wrap_before) new_properties.wrap_before = *wrap_before; + if (wrap_char) new_properties.wrap_char = *wrap_char; + if (text_transform) new_properties.text_transform = *text_transform; + if (fill) new_properties.fill = *fill; + if (halo_fill) new_properties.halo_fill = *halo_fill; + if (halo_radius) new_properties.halo_radius = *halo_radius; + + if (child_) { + child_->apply(new_properties, feature, output); + } else { +#ifdef MAPNIK_DEBUG + std::cerr << "Warning: Useless format: No text to format\n"; +#endif + } +} + + +void format_node::set_child(node_ptr child) +{ + child_ = child; +} + + +node_ptr format_node::get_child() const +{ + return child_; +} + +void format_node::add_expressions(expression_set &output) const +{ + if (child_) child_->add_expressions(output); +} + +} //ns formatting +} //ns mapnik diff --git a/src/formatting/list.cpp b/src/formatting/list.cpp new file mode 100644 index 000000000..e5044cf7d --- /dev/null +++ b/src/formatting/list.cpp @@ -0,0 +1,85 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2012 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 + * + *****************************************************************************/ +#include + +namespace mapnik { +using boost::property_tree::ptree; + +namespace formatting { +/************************************************************/ + +void list_node::to_xml(boost::property_tree::ptree &xml) const +{ + std::vector::const_iterator itr = children_.begin(); + std::vector::const_iterator end = children_.end(); + for (;itr != end; itr++) + { + (*itr)->to_xml(xml); + } +} + + +void list_node::apply(char_properties const& p, Feature const& feature, processed_text &output) const +{ + std::vector::const_iterator itr = children_.begin(); + std::vector::const_iterator end = children_.end(); + for (;itr != end; itr++) + { + (*itr)->apply(p, feature, output); + } +} + + +void list_node::add_expressions(expression_set &output) const +{ + std::vector::const_iterator itr = children_.begin(); + std::vector::const_iterator end = children_.end(); + for (;itr != end; itr++) + { + (*itr)->add_expressions(output); + } +} + + +void list_node::push_back(node_ptr n) +{ + children_.push_back(n); +} + + +void list_node::clear() +{ + children_.clear(); +} + +void list_node::set_children(std::vector const& children) +{ + children_ = children; +} + +std::vector const& list_node::get_children() const +{ + return children_; +} +} // ns mapnik +} // ns formatting + diff --git a/src/formatting/text.cpp b/src/formatting/text.cpp new file mode 100644 index 000000000..fc4e85e83 --- /dev/null +++ b/src/formatting/text.cpp @@ -0,0 +1,99 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2012 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 + +// boost +#include + +namespace mapnik +{ +namespace formatting +{ +using boost::property_tree::ptree; + + +void text_node::to_xml(ptree &xml) const +{ + ptree &new_node = xml.push_back(ptree::value_type( + "", ptree()))->second; + new_node.put_value(to_expression_string(*text_)); +} + + +node_ptr text_node::from_xml(boost::property_tree::ptree const& xml) +{ + std::string data = xml.data(); + boost::trim(data); + if (data.empty()) return node_ptr(); //No text + return node_ptr(new text_node(parse_expression(data, "utf8"))); +} + +void text_node::apply(char_properties const& p, Feature const& feature, processed_text &output) const +{ + UnicodeString text_str = boost::apply_visitor(evaluate(feature), *text_).to_unicode(); + if (p.text_transform == UPPERCASE) + { + text_str = text_str.toUpper(); + } + else if (p.text_transform == LOWERCASE) + { + text_str = text_str.toLower(); + } + else if (p.text_transform == CAPITALIZE) + { + text_str = text_str.toTitle(NULL); + } + if (text_str.length() > 0) { + output.push_back(p, text_str); + } else { +#ifdef MAPNIK_DEBUG + std::cerr << "Warning: Empty expression.\n"; +#endif + } +} + + +void text_node::add_expressions(expression_set &output) const +{ + if (text_) output.insert(text_); +} + + +void text_node::set_text(expression_ptr text) +{ + text_ = text; +} + + +expression_ptr text_node::get_text() const +{ + return text_; +} + +} //ns formatting +} //ns mapnik diff --git a/src/processed_text.cpp b/src/processed_text.cpp new file mode 100644 index 000000000..35109a724 --- /dev/null +++ b/src/processed_text.cpp @@ -0,0 +1,53 @@ +#include +namespace mapnik +{ + +void processed_text::push_back(char_properties const& properties, UnicodeString const& text) +{ + expr_list_.push_back(processed_expression(properties, text)); +} + +processed_text::expression_list::const_iterator processed_text::begin() const +{ + return expr_list_.begin(); +} + +processed_text::expression_list::const_iterator processed_text::end() const +{ + return expr_list_.end(); +} + +processed_text::processed_text(face_manager & font_manager, double scale_factor) + : font_manager_(font_manager), scale_factor_(scale_factor) +{ + +} + +void processed_text::clear() +{ + info_.clear(); + expr_list_.clear(); +} + + +string_info &processed_text::get_string_info() +{ + info_.clear(); //if this function is called twice invalid results are returned, so clear string_info first + expression_list::iterator itr = expr_list_.begin(); + expression_list::iterator end = expr_list_.end(); + for (; itr != end; ++itr) + { + char_properties const &p = itr->p; + face_set_ptr faces = font_manager_.get_face_set(p.face_name, p.fontset); + if (faces->size() <= 0) + { + throw config_error("Unable to find specified font face '" + p.face_name + "'"); + } + faces->set_character_sizes(p.text_size * scale_factor_); + faces->get_string_info(info_, itr->str, &(itr->p)); + info_.add_text(itr->str); + } + return info_; +} + +} //ns mapnik diff --git a/src/text_processing.cpp b/src/text_processing.cpp deleted file mode 100644 index f9f018846..000000000 --- a/src/text_processing.cpp +++ /dev/null @@ -1,343 +0,0 @@ -/***************************************************************************** - * - * This file is part of Mapnik (c++ mapping toolkit) - * - * Copyright (C) 2011 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 - * - *****************************************************************************/ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -namespace mapnik { -using boost::property_tree::ptree; -using boost::optional; - -namespace formatting { - -void node::to_xml(boost::property_tree::ptree &xml) const -{ - //TODO: Should this throw a config_error? -#ifdef MAPNIK_DEBUG - std::cerr << "Error: Trying to write unsupported node type to XML.\n"; -#endif -} - -node_ptr node::from_xml(boost::property_tree::ptree const& xml) -{ - list_node *list = new list_node(); - node_ptr list_ptr(list); - ptree::const_iterator itr = xml.begin(); - ptree::const_iterator end = xml.end(); - for (; itr != end; ++itr) { - node_ptr n; - if (itr->first == "") { - n = text_node::from_xml(itr->second); - } else if (itr->first == "Format") { - n = format_node::from_xml(itr->second); - } else if (itr->first == "ExpressionFormat") { - n = expression_format::from_xml(itr->second); - } else if (itr->first != "" && itr->first != "" && itr->first != "Placement") { - throw config_error("Unknown item " + itr->first); - } - if (n) list->push_back(n); - } - if (list->get_children().size() == 1) { - return list->get_children()[0]; - } else if (list->get_children().size() > 1) { - return list_ptr; - } else { - return node_ptr(); - } -} - -void node::add_expressions(expression_set &output) const -{ - //Do nothing by default -} - -/************************************************************/ - -void list_node::to_xml(boost::property_tree::ptree &xml) const -{ - std::vector::const_iterator itr = children_.begin(); - std::vector::const_iterator end = children_.end(); - for (;itr != end; itr++) - { - (*itr)->to_xml(xml); - } -} - - -void list_node::apply(char_properties const& p, Feature const& feature, processed_text &output) const -{ - std::vector::const_iterator itr = children_.begin(); - std::vector::const_iterator end = children_.end(); - for (;itr != end; itr++) - { - (*itr)->apply(p, feature, output); - } -} - - -void list_node::add_expressions(expression_set &output) const -{ - std::vector::const_iterator itr = children_.begin(); - std::vector::const_iterator end = children_.end(); - for (;itr != end; itr++) - { - (*itr)->add_expressions(output); - } -} - - -void list_node::push_back(node_ptr n) -{ - children_.push_back(n); -} - - -void list_node::clear() -{ - children_.clear(); -} - -void list_node::set_children(std::vector const& children) -{ - children_ = children; -} - -std::vector const& list_node::get_children() const -{ - return children_; -} - -/************************************************************/ - -void text_node::to_xml(ptree &xml) const -{ - ptree &new_node = xml.push_back(ptree::value_type( - "", ptree()))->second; - new_node.put_value(to_expression_string(*text_)); -} - - -node_ptr text_node::from_xml(boost::property_tree::ptree const& xml) -{ - std::string data = xml.data(); - boost::trim(data); - if (data.empty()) return node_ptr(); //No text - return node_ptr(new text_node(parse_expression(data, "utf8"))); -} - -void text_node::apply(char_properties const& p, Feature const& feature, processed_text &output) const -{ - UnicodeString text_str = boost::apply_visitor(evaluate(feature), *text_).to_unicode(); - if (p.text_transform == UPPERCASE) - { - text_str = text_str.toUpper(); - } - else if (p.text_transform == LOWERCASE) - { - text_str = text_str.toLower(); - } - else if (p.text_transform == CAPITALIZE) - { - text_str = text_str.toTitle(NULL); - } - if (text_str.length() > 0) { - output.push_back(p, text_str); - } else { -#ifdef MAPNIK_DEBUG - std::cerr << "Warning: Empty expression.\n"; -#endif - } -} - - -void text_node::add_expressions(expression_set &output) const -{ - if (text_) output.insert(text_); -} - - -void text_node::set_text(expression_ptr text) -{ - text_ = text; -} - - -expression_ptr text_node::get_text() const -{ - return text_; -} - -/************************************************************/ - -void format_node::to_xml(ptree &xml) const -{ - ptree &new_node = xml.push_back(ptree::value_type("Format", ptree()))->second; - if (face_name) set_attr(new_node, "face-name", *face_name); - if (text_size) set_attr(new_node, "size", *text_size); - if (character_spacing) set_attr(new_node, "character-spacing", *character_spacing); - if (line_spacing) set_attr(new_node, "line-spacing", *line_spacing); - if (text_opacity) set_attr(new_node, "opacity", *text_opacity); - if (wrap_before) set_attr(new_node, "wrap-before", *wrap_before); - if (wrap_char) set_attr(new_node, "wrap-character", *wrap_char); - if (text_transform) set_attr(new_node, "text-transform", *text_transform); - if (fill) set_attr(new_node, "fill", *fill); - if (halo_fill) set_attr(new_node, "halo-fill", *halo_fill); - if (halo_radius) set_attr(new_node, "halo-radius", *halo_radius); - if (child_) child_->to_xml(new_node); -} - - -node_ptr format_node::from_xml(ptree const& xml) -{ - format_node *n = new format_node(); - node_ptr np(n); - - node_ptr child = node::from_xml(xml); - n->set_child(child); - - n->face_name = get_opt_attr(xml, "face-name"); - /*TODO: Fontset is problematic. We don't have the fontsets pointer here... */ - n->text_size = get_opt_attr(xml, "size"); - n->character_spacing = get_opt_attr(xml, "character-spacing"); - n->line_spacing = get_opt_attr(xml, "line-spacing"); - n->text_opacity = get_opt_attr(xml, "opactity"); - boost::optional wrap = get_opt_attr(xml, "wrap-before"); - if (wrap) n->wrap_before = *wrap; - n->wrap_char = get_opt_attr(xml, "wrap-character"); - n->text_transform = get_opt_attr(xml, "text-transform"); - n->fill = get_opt_attr(xml, "fill"); - n->halo_fill = get_opt_attr(xml, "halo-fill"); - n->halo_radius = get_opt_attr(xml, "halo-radius"); - return np; -} - - -void format_node::apply(char_properties const& p, const Feature &feature, processed_text &output) const -{ - char_properties new_properties = p; - if (face_name) new_properties.face_name = *face_name; - if (text_size) new_properties.text_size = *text_size; - if (character_spacing) new_properties.character_spacing = *character_spacing; - if (line_spacing) new_properties.line_spacing = *line_spacing; - if (text_opacity) new_properties.text_opacity = *text_opacity; - if (wrap_before) new_properties.wrap_before = *wrap_before; - if (wrap_char) new_properties.wrap_char = *wrap_char; - if (text_transform) new_properties.text_transform = *text_transform; - if (fill) new_properties.fill = *fill; - if (halo_fill) new_properties.halo_fill = *halo_fill; - if (halo_radius) new_properties.halo_radius = *halo_radius; - - if (child_) { - child_->apply(new_properties, feature, output); - } else { -#ifdef MAPNIK_DEBUG - std::cerr << "Warning: Useless format: No text to format\n"; -#endif - } -} - - -void format_node::set_child(node_ptr child) -{ - child_ = child; -} - - -node_ptr format_node::get_child() const -{ - return child_; -} - -void format_node::add_expressions(expression_set &output) const -{ - if (child_) child_->add_expressions(output); -} - -} //namespace formatting - -/************************************************************/ - -void processed_text::push_back(char_properties const& properties, UnicodeString const& text) -{ - expr_list_.push_back(processed_expression(properties, text)); -} - -processed_text::expression_list::const_iterator processed_text::begin() const -{ - return expr_list_.begin(); -} - -processed_text::expression_list::const_iterator processed_text::end() const -{ - return expr_list_.end(); -} - -processed_text::processed_text(face_manager & font_manager, double scale_factor) - : font_manager_(font_manager), scale_factor_(scale_factor) -{ - -} - -void processed_text::clear() -{ - info_.clear(); - expr_list_.clear(); -} - - -string_info &processed_text::get_string_info() -{ - info_.clear(); //if this function is called twice invalid results are returned, so clear string_info first - expression_list::iterator itr = expr_list_.begin(); - expression_list::iterator end = expr_list_.end(); - for (; itr != end; ++itr) - { - char_properties const &p = itr->p; - face_set_ptr faces = font_manager_.get_face_set(p.face_name, p.fontset); - if (faces->size() <= 0) - { - throw config_error("Unable to find specified font face '" + p.face_name + "'"); - } - faces->set_character_sizes(p.text_size * scale_factor_); - faces->get_string_info(info_, itr->str, &(itr->p)); - info_.add_text(itr->str); - } - return info_; -} - - - -} /* namespace */