diff --git a/bindings/python/mapnik_text_placement.cpp b/bindings/python/mapnik_text_placement.cpp index a8e684a3c..c0e4d412b 100644 --- a/bindings/python/mapnik_text_placement.cpp +++ b/bindings/python/mapnik_text_placement.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -97,12 +98,12 @@ public: } }; -boost::python::tuple get_displacement(text_symbolizer_properties const& t) +boost::python::tuple get_displacement(text_layout_properties const& t) { return boost::python::make_tuple(t.displacement.x, t.displacement.y); } -void set_displacement(text_symbolizer_properties &t, boost::python::tuple arg) +void set_displacement(text_layout_properties &t, boost::python::tuple arg) { if (len(arg) != 2) { @@ -118,7 +119,6 @@ void set_displacement(text_symbolizer_properties &t, boost::python::tuple arg) t.displacement.set(x, y); } - struct NodeWrap: formatting::node, wrapper { NodeWrap() : formatting::node(), wrapper() @@ -225,6 +225,27 @@ struct ExprFormatWrap: formatting::expression_format, wrapper +{ + virtual void apply(char_properties_ptr p, feature_impl const& feature, text_layout &output) const + { + if(override o = this->get_override("apply")) + { + python_block_auto_unblock b; + o(ptr(&p), ptr(&feature), ptr(&output)); + } + else + { + formatting::layout_node::apply(p, feature, output); + } + } + + void default_apply(char_properties_ptr p, feature_impl const& feature, text_layout &output) const + { + formatting::layout_node::apply(p, feature, output); + } +}; + struct ListNodeWrap: formatting::list_node, wrapper { //Default constructor @@ -399,13 +420,7 @@ void export_text_placement() class_with_converter ("TextSymbolizerProperties") .def_readwrite_convert("label_placement", &text_symbolizer_properties::label_placement) - .def_readwrite_convert("horizontal_alignment", &text_symbolizer_properties::halign) - .def_readwrite_convert("justify_alignment", &text_symbolizer_properties::jalign) - .def_readwrite_convert("vertical_alignment", &text_symbolizer_properties::valign) - .def_readwrite("orientation", &text_symbolizer_properties::orientation) - .add_property("displacement", - &get_displacement, - &set_displacement) + .def_readwrite_convert("upright", &text_symbolizer_properties::upright) .def_readwrite("label_spacing", &text_symbolizer_properties::label_spacing) .def_readwrite("label_position_tolerance", &text_symbolizer_properties::label_position_tolerance) .def_readwrite("avoid_edges", &text_symbolizer_properties::avoid_edges) @@ -416,9 +431,7 @@ void export_text_placement() .def_readwrite("force_odd_labels", &text_symbolizer_properties::force_odd_labels) .def_readwrite("allow_overlap", &text_symbolizer_properties::allow_overlap) .def_readwrite("largest_bbox_only", &text_symbolizer_properties::largest_bbox_only) - .def_readwrite("text_ratio", &text_symbolizer_properties::text_ratio) - .def_readwrite("wrap_width", &text_symbolizer_properties::wrap_width) - .def_readwrite("wrap_before", &text_symbolizer_properties::wrap_before) + .def_readwrite("layout_defaults", &text_symbolizer_properties::layout_defaults) .def_readwrite("format", &text_symbolizer_properties::format) .add_property ("format_tree", &text_symbolizer_properties::format_tree, @@ -430,6 +443,17 @@ void export_text_placement() set_old_style expression is just a compatibility wrapper and doesn't need to be exposed in python. */ ; + class_with_converter + ("TextLayoutProperties") + .def_readwrite_convert("horizontal_alignment", &text_layout_properties::halign) + .def_readwrite_convert("justify_alignment", &text_layout_properties::jalign) + .def_readwrite_convert("vertical_alignment", &text_layout_properties::valign) + .def_readwrite("text_ratio", &text_layout_properties::text_ratio) + .def_readwrite("wrap_width", &text_layout_properties::wrap_width) + .def_readwrite("wrap_before", &text_layout_properties::wrap_before) + .def_readwrite("orientation", &text_layout_properties::orientation) + .def_readwrite("rotate_displacement", &text_layout_properties::rotate_displacement) + .add_property("displacement", &get_displacement, &set_displacement); class_with_converter ("CharProperties") diff --git a/include/mapnik/text/formatting/layout.hpp b/include/mapnik/text/formatting/layout.hpp new file mode 100644 index 000000000..fe94c1434 --- /dev/null +++ b/include/mapnik/text/formatting/layout.hpp @@ -0,0 +1,59 @@ +/***************************************************************************** + * + * 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 + * + *****************************************************************************/ + +#ifndef FORMATTING_OFFSET_HPP +#define FORMATTING_OFFSET_HPP + +#include +#include + +#include + +namespace mapnik { +namespace formatting { +class MAPNIK_DECL layout_node: public node { +public: + void to_xml(boost::property_tree::ptree &xml) const; + static node_ptr from_xml(xml_node const& xml); + virtual void apply(char_properties_ptr p, feature_impl const& feature, text_layout &output) const; + virtual void add_expressions(expression_set &output) const; + void set_child(node_ptr child); + node_ptr get_child() const; + + boost::optional dx; + boost::optional dy; + boost::optional halign; + boost::optional valign; + boost::optional jalign; + boost::optional text_ratio; + boost::optional wrap_width; + boost::optional wrap_before; + boost::optional rotate_displacement; + boost::optional orientation; + +private: + node_ptr child_; +}; +} //ns formatting +} //ns mapnik + +#endif // FORMATTING_OFFSET_HPP diff --git a/include/mapnik/text/layout.hpp b/include/mapnik/text/layout.hpp index 9c3eb19e7..916c3e4f2 100644 --- a/include/mapnik/text/layout.hpp +++ b/include/mapnik/text/layout.hpp @@ -30,6 +30,7 @@ #include #include #include +#include //stl #include @@ -38,13 +39,17 @@ namespace mapnik { +typedef std::shared_ptr text_layout_ptr; +typedef std::vector text_layout_vector; + class text_layout { public: typedef std::vector line_vector; typedef line_vector::const_iterator const_iterator; + typedef text_layout_vector::const_iterator child_iterator; typedef harfbuzz_shaper shaper_type; - text_layout(face_manager_freetype & font_manager, double scale_factor); + text_layout(face_manager_freetype & font_manager, double scale_factor, text_layout_properties_ptr properties); /** Adds a new text part. Call this function repeatedly to build the complete text. */ void add_text(mapnik::value_unicode_string const& str, char_properties_ptr format); @@ -53,7 +58,7 @@ public: mapnik::value_unicode_string const& text() const; /** Processes the text into a list of glyphs, performing RTL/LTR handling, shaping and line breaking. */ - void layout(double wrap_width, unsigned text_ratio, bool wrap_before); + void layout(); /** Clear all data stored in this object. The object's state is the same as directly after construction. */ void clear(); @@ -81,11 +86,29 @@ public: // Returns the number of glyphs so memory can be preallocated. inline unsigned glyphs_count() const { return glyphs_count_;} + void add_child(text_layout_ptr child_layout); + + inline const text_layout_vector &get_child_layouts() const { return child_layout_list_; } + + inline face_manager &get_font_manager() const { return font_manager_; } + inline double get_scale_factor() const { return scale_factor_; } + inline text_layout_properties_ptr get_layout_properties() const { return properties_; } + + inline rotation const& orientation() const { return orientation_; } + inline pixel_position const& displacement() const { return displacement_; } + inline box2d const& bounds() const { return bounds_; } + + pixel_position alignment_offset() const; + double jalign_offset(double line_width) const; + + void init_orientation(feature_impl const& feature); + private: void break_line(text_line & line, double wrap_width, unsigned text_ratio, bool wrap_before); void shape_text(text_line & line); void add_line(text_line & line); void clear_cluster_widths(unsigned first, unsigned last); + void init_alignment(); //input face_manager_freetype &font_manager_; @@ -103,7 +126,60 @@ private: //output line_vector lines_; + + //text layout properties + text_layout_properties_ptr properties_; + + //alignments + vertical_alignment_e valign_; + horizontal_alignment_e halign_; + justify_alignment_e jalign_; + + // Precalculated values for maximum performance + rotation orientation_; + pixel_position displacement_; + box2d bounds_; + + //children + text_layout_vector child_layout_list_; }; + +class layout_container +{ +public: + layout_container() : glyphs_count_(0), line_count_(0) {} + + void add(text_layout_ptr layout); + void clear(); + + void layout(); + + inline size_t size() const { return layouts_.size(); } + + inline text_layout_vector::const_iterator begin() const { return layouts_.begin(); } + inline text_layout_vector::const_iterator end() const { return layouts_.end(); } + + inline mapnik::value_unicode_string const& text() const { return text_; } + + inline unsigned glyphs_count() const { return glyphs_count_; } + inline unsigned line_count() const { return line_count_; } + + inline box2d const& bounds() const { return bounds_; } + + inline double width() const { return bounds_.width(); } + inline double height() const { return bounds_.height(); } + +private: + text_layout_vector layouts_; + + mapnik::value_unicode_string text_; + + unsigned glyphs_count_; + unsigned line_count_; + + box2d bounds_; +}; + } #endif // TEXT_LAYOUT_HPP diff --git a/include/mapnik/text/placement_finder.hpp b/include/mapnik/text/placement_finder.hpp index 92660e7c6..9bb42f250 100644 --- a/include/mapnik/text/placement_finder.hpp +++ b/include/mapnik/text/placement_finder.hpp @@ -29,6 +29,7 @@ #include #include #include +#include #include namespace mapnik @@ -62,10 +63,6 @@ public: void set_marker(marker_info_ptr m, box2d box, bool marker_unlocked, pixel_position const& marker_displacement); private: - void init_alignment(); - pixel_position alignment_offset() const; - double jalign_offset(double line_width) const; - bool single_line_placement(vertex_cache &pp, text_upright_e orientation); /** Moves dx pixels but makes sure not to fall of the end. */ void path_move_dx(vertex_cache &pp); @@ -80,23 +77,16 @@ private: /** Maps upright==auto, left_only and right_only to left,right to simplify processing. angle = angle of at start of line (to estimate best option for upright==auto) */ text_upright_e simplify_upright(text_upright_e upright, double angle) const; - box2d get_bbox(glyph_info const& glyph, pixel_position const& pos, rotation const& rot); + box2d get_bbox(text_layout const& layout, glyph_info const& glyph, pixel_position const& pos, rotation const& rot); feature_impl const& feature_; DetectorType &detector_; box2d const& extent_; - // Precalculated values for maximum performance - rotation orientation_; - text_layout layout_; text_placement_info_ptr info_; + layout_container layouts_; bool valid_; - vertical_alignment_e valign_; - /** Horizontal alignment for point placements. */ - horizontal_alignment_e halign_point_; - /** Horizontal alignment for line placements. */ - horizontal_alignment_e halign_line_; - justify_alignment_e jalign_; double scale_factor_; + face_manager_freetype &font_manager_; placements_list placements_; diff --git a/include/mapnik/text/rotation.hpp b/include/mapnik/text/rotation.hpp index d7a0fdd1f..294eed05a 100644 --- a/include/mapnik/text/rotation.hpp +++ b/include/mapnik/text/rotation.hpp @@ -15,8 +15,8 @@ struct rotation void init(double angle) { sin = std::sin(angle); cos = std::cos(angle); } double sin; double cos; - rotation operator~() { return rotation(sin, -cos); } - rotation operator!() { return rotation(-sin, cos); } + rotation operator~() const { return rotation(sin, -cos); } + rotation operator!() const { return rotation(-sin, cos); } }; } diff --git a/include/mapnik/text/text_properties.hpp b/include/mapnik/text/text_properties.hpp index 55d7ddec8..a7d20bf37 100644 --- a/include/mapnik/text/text_properties.hpp +++ b/include/mapnik/text/text_properties.hpp @@ -132,10 +132,36 @@ enum text_upright DEFINE_ENUM(text_upright_e, text_upright); +/** Properties for building the layout of a single text placement */ +struct MAPNIK_DECL text_layout_properties +{ + text_layout_properties(); + + /** Load all values from XML ptree. */ + void from_xml(xml_node const &sym); + /** Save all values to XML ptree (but does not create a new parent node!). */ + void to_xml(boost::property_tree::ptree &node, bool explicit_defaults, text_layout_properties const &dfl=text_layout_properties()) const; + + /** Get a list of all expressions used in any placement. + * This function is used to collect attributes. */ + void add_expressions(expression_set &output) const; + + //Per layout options + expression_ptr orientation; + pixel_position displacement; + horizontal_alignment_e halign; + justify_alignment_e jalign; + vertical_alignment_e valign; + double text_ratio; + double wrap_width; + bool wrap_before; + bool rotate_displacement; +}; +typedef std::shared_ptr text_layout_properties_ptr; + class text_layout; - -/** Contains all text symbolizer properties which are not directly related to text formatting. */ +/** Contains all text symbolizer properties which are not directly related to text formatting and layout. */ struct MAPNIK_DECL text_symbolizer_properties { text_symbolizer_properties(); @@ -159,12 +185,7 @@ struct MAPNIK_DECL text_symbolizer_properties void add_expressions(expression_set &output) const; //Per symbolizer options - expression_ptr orientation; - pixel_position displacement; label_placement_e label_placement; - horizontal_alignment_e halign; - justify_alignment_e jalign; - vertical_alignment_e valign; /** 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 */ @@ -179,11 +200,11 @@ struct MAPNIK_DECL text_symbolizer_properties bool allow_overlap; /** Only consider geometry with largest bbox (polygons) */ bool largest_bbox_only; - double text_ratio; - double wrap_width; - bool wrap_before; - bool rotate_displacement; text_upright_e upright; + + /** Default values for text layouts */ + text_layout_properties_ptr layout_defaults; + /** Default values for char_properties. */ char_properties_ptr format; private: diff --git a/src/build.py b/src/build.py index 8a4dc0ebe..86eeb73dd 100644 --- a/src/build.py +++ b/src/build.py @@ -226,6 +226,7 @@ source = Split( text/formatting/list.cpp text/formatting/text.cpp text/formatting/format.cpp + text/formatting/layout.cpp text/formatting/registry.cpp text/placements/registry.cpp text/placements/base.cpp diff --git a/src/text/formatting/layout.cpp b/src/text/formatting/layout.cpp new file mode 100644 index 000000000..d21550d9f --- /dev/null +++ b/src/text/formatting/layout.cpp @@ -0,0 +1,125 @@ +/***************************************************************************** + * + * 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 +#include +#include +#include +#include + +// boost +#include + +namespace mapnik { +namespace formatting { + +using boost::property_tree::ptree; + +void layout_node::to_xml(ptree &xml) const +{ + ptree &new_node = xml.push_back(ptree::value_type("Layout", ptree()))->second; + + if (dx) set_attr(new_node, "dx", *dx); + if (dy) set_attr(new_node, "dy", *dy); + if (halign) set_attr(new_node, "horizontal-alignment", *halign); + if (valign) set_attr(new_node, "vertical-alignment", *valign); + if (jalign) set_attr(new_node, "justify-alignment", *jalign); + if (text_ratio) set_attr(new_node, "text-ratio", *text_ratio); + if (wrap_width) set_attr(new_node, "wrap-width", *wrap_width); + if (wrap_before) set_attr(new_node, "wrap-before", *wrap_before); + if (rotate_displacement) set_attr(new_node, "rotate-displacement", *rotate_displacement); + if (orientation) set_attr(new_node, "orientation", to_expression_string(**orientation)); + + if (child_) child_->to_xml(new_node); +} + +node_ptr layout_node::from_xml(xml_node const& xml) +{ + std::shared_ptr n = std::make_shared(); + + node_ptr child = node::from_xml(xml); + n->set_child(child); + + n->dx = xml.get_opt_attr("dx"); + n->dy = xml.get_opt_attr("dy"); + n->halign = xml.get_opt_attr("horizontal-alignment"); + n->valign = xml.get_opt_attr("vertical-alignment"); + n->jalign = xml.get_opt_attr("justify-alignment"); + n->text_ratio = xml.get_opt_attr("text-ratio"); + n->wrap_width = xml.get_opt_attr("wrap-width"); + n->wrap_before = xml.get_opt_attr("wrap-before"); + n->rotate_displacement = xml.get_opt_attr("rotate-displacement"); + n->orientation = xml.get_opt_attr("orientation"); + + return n; +} + +void layout_node::apply(char_properties_ptr p, feature_impl const& feature, text_layout &output) const +{ + text_layout_properties_ptr new_properties = std::make_shared(*output.get_layout_properties()); + if (dx) new_properties->displacement.x = *dx; + if (dy) new_properties->displacement.y = *dy; + if (halign) new_properties->halign = *halign; + if (valign) new_properties->valign = *valign; + if (jalign) new_properties->jalign = *jalign; + if (text_ratio) new_properties->text_ratio = *text_ratio; + if (wrap_width) new_properties->wrap_width = *wrap_width; + if (wrap_before) new_properties->wrap_before = *wrap_before; + if (rotate_displacement) new_properties->rotate_displacement = *rotate_displacement; + if (orientation) new_properties->orientation = *orientation; + + // starting a new offset child with the new displacement value + text_layout_ptr child_layout = std::make_shared(output.get_font_manager(), output.get_scale_factor(), new_properties); + child_layout->init_orientation(feature); + + // process contained format tree into the child node + if (child_) { + child_->apply(p, feature, *child_layout); + } else { + MAPNIK_LOG_WARN(format) << "Useless layout node: Contains no text"; + } + output.add_child(child_layout); +} + +void layout_node::set_child(node_ptr child) +{ + child_ = child; +} + +node_ptr layout_node::get_child() const +{ + return child_; +} + +void layout_node::add_expressions(expression_set &output) const +{ + if (child_) child_->add_expressions(output); +} + +} //ns formatting +} //ns mapnik diff --git a/src/text/formatting/registry.cpp b/src/text/formatting/registry.cpp index 442743fe0..e3edd10d0 100644 --- a/src/text/formatting/registry.cpp +++ b/src/text/formatting/registry.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -37,6 +38,7 @@ registry::registry() register_name("", &text_node::from_xml); register_name("Format", &format_node::from_xml); register_name("ExpressionFormat", &expression_format::from_xml); + register_name("Layout", &layout_node::from_xml); } void registry::register_name(std::string const& name, from_xml_function_ptr ptr, bool overwrite) diff --git a/src/text/layout.cpp b/src/text/layout.cpp index 6dded99b3..770bea7e9 100644 --- a/src/text/layout.cpp +++ b/src/text/layout.cpp @@ -22,6 +22,7 @@ #include #include +#include #include // ICU @@ -30,7 +31,29 @@ namespace mapnik { -text_layout::text_layout(face_manager_freetype & font_manager, double scale_factor) +// Output is centered around (0,0) +static void rotated_box2d(box2d & box, rotation const& rot, pixel_position const& center, double width, double height) +{ + double half_width, half_height; + if (rot.sin == 0 && rot.cos == 1.) + { + half_width = width / 2.; + half_height = height / 2.; + } + else + { + half_width = (width * rot.cos + height * rot.sin) /2.; + half_height = (width * rot.sin + height * rot.cos) /2.; + } + box.init(center.x - half_width, center.y - half_height, center.x + half_width, center.y + half_height); +} + +pixel_position pixel_position::rotate(rotation const& rot) const +{ + return pixel_position(x * rot.cos - y * rot.sin, x * rot.sin + y * rot.cos); +} + +text_layout::text_layout(face_manager_freetype & font_manager, double scale_factor, text_layout_properties_ptr properties) : font_manager_(font_manager), scale_factor_(scale_factor), itemizer_(), @@ -38,7 +61,8 @@ text_layout::text_layout(face_manager_freetype & font_manager, double scale_fact width_(0.0), height_(0.0), glyphs_count_(0), - lines_() + lines_(), + properties_(properties) { } @@ -47,20 +71,34 @@ void text_layout::add_text(mapnik::value_unicode_string const& str, char_propert itemizer_.add_text(str, format); } +void text_layout::add_child(text_layout_ptr child_layout) +{ + child_layout_list_.push_back(child_layout); +} + mapnik::value_unicode_string const& text_layout::text() const { return itemizer_.text(); } -void text_layout::layout(double wrap_width, unsigned text_ratio, bool wrap_before) +void text_layout::layout() { unsigned num_lines = itemizer_.num_lines(); for (unsigned i = 0; i < num_lines; ++i) { std::pair line_limits = itemizer_.line(i); text_line line(line_limits.first, line_limits.second); - break_line(line, wrap_width, text_ratio, wrap_before); //Break line if neccessary + //Break line if neccessary + break_line(line, properties_->wrap_width * scale_factor_, properties_->text_ratio, properties_->wrap_before); } + init_alignment(); + + /* Find text origin. */ + displacement_ = scale_factor_ * properties_->displacement + alignment_offset(); + if (properties_->rotate_displacement) displacement_ = displacement_.rotate(!orientation_); + + /* Find layout bounds, expanded for rotation */ + rotated_box2d(bounds_, orientation_, displacement_, width_, height_); } /* In the Unicode string characters are always stored in logical order. @@ -189,6 +227,7 @@ void text_layout::clear() width_map_.clear(); width_ = 0.; height_ = 0.; + child_layout_list_.clear(); } void text_layout::shape_text(text_line & line) @@ -196,5 +235,155 @@ void text_layout::shape_text(text_line & line) shaper_type::shape_text(line, itemizer_, width_map_, font_manager_, scale_factor_); } +void text_layout::init_orientation(feature_impl const& feature) +{ + if (properties_->orientation) + { + // https://github.com/mapnik/mapnik/issues/1352 + mapnik::evaluate evaluator(feature); + orientation_.init( + boost::apply_visitor( + evaluator, + *(properties_->orientation)).to_double() * M_PI / 180.0); + } + else + { + orientation_.reset(); + } +} + +void text_layout::init_alignment() +{ + text_layout_properties const& p = *(properties_); + valign_ = p.valign; + if (valign_ == V_AUTO) + { + if (p.displacement.y > 0.0) + { + valign_ = V_BOTTOM; + } + else if (p.displacement.y < 0.0) + { + valign_ = V_TOP; + } + else + { + valign_ = V_MIDDLE; + } + } + + halign_ = p.halign; + if (halign_ == H_AUTO) + { + if (p.displacement.x > 0.0) + { + halign_ = H_RIGHT; + } + else if (p.displacement.x < 0.0) + { + halign_ = H_LEFT; + } + else + { + halign_ = H_MIDDLE; + } + } + + jalign_ = p.jalign; + if (jalign_ == J_AUTO) + { + if (p.displacement.x > 0.0) + { + jalign_ = J_LEFT; + } + else if (p.displacement.x < 0.0) + { + jalign_ = J_RIGHT; + } + else + { + jalign_ = J_MIDDLE; + } + } +} + +pixel_position text_layout::alignment_offset() const +{ + pixel_position result(0,0); + // if needed, adjust for desired vertical alignment + if (valign_ == V_TOP) + { + result.y = -0.5 * height(); // move center up by 1/2 the total height + } + else if (valign_ == V_BOTTOM) + { + result.y = 0.5 * height(); // move center down by the 1/2 the total height + } + // set horizontal position to middle of text + if (halign_ == H_LEFT) + { + result.x = -0.5 * width(); // move center left by 1/2 the string width + } + else if (halign_ == H_RIGHT) + { + result.x = 0.5 * width(); // move center right by 1/2 the string width + } + return result; +} + +double text_layout::jalign_offset(double line_width) const +{ + if (jalign_ == J_MIDDLE) return -(line_width / 2.0); + if (jalign_ == J_LEFT) return -(width() / 2.0); + if (jalign_ == J_RIGHT) return (width() / 2.0) - line_width; + return 0; +} + +void layout_container::add(text_layout_ptr layout) +{ + text_ += layout->text(); + layouts_.push_back(layout); + + for (text_layout_ptr const& child_layout : layout->get_child_layouts()) + { + add(child_layout); + } +} + +void layout_container::layout() +{ + bounds_.init(0,0,0,0); + glyphs_count_ = 0; + line_count_ = 0; + + bool first = true; + for (text_layout_ptr const& layout : layouts_) + { + layout->layout(); + + glyphs_count_ += layout->glyphs_count(); + line_count_ += layout->num_lines(); + + if (first) + { + bounds_ = layout->bounds(); + first = false; + } + else + { + bounds_.expand_to_include(layout->bounds()); + } + } +} + +void layout_container::clear() +{ + layouts_.clear(); + text_.remove(); + bounds_.init(0,0,0,0); + glyphs_count_ = 0; + line_count_ = 0; +} + } //ns mapnik diff --git a/src/text/placement_finder.cpp b/src/text/placement_finder.cpp index da65ad4c0..e176c9a71 100644 --- a/src/text/placement_finder.cpp +++ b/src/text/placement_finder.cpp @@ -107,19 +107,6 @@ private: }; -// Output is centered around (0,0) -static void rotated_box2d(box2d & box, rotation const& rot, double width, double height) -{ - double new_width = width * rot.cos + height * rot.sin; - double new_height = width * rot.sin + height * rot.cos; - box.init(-new_width/2., -new_height/2., new_width/2., new_height/2.); -} - -pixel_position pixel_position::rotate(rotation const& rot) const -{ - return pixel_position(x * rot.cos - y * rot.sin, x * rot.sin + y * rot.cos); -} - placement_finder::placement_finder(feature_impl const& feature, DetectorType &detector, box2d const& extent, @@ -129,10 +116,10 @@ placement_finder::placement_finder(feature_impl const& feature, : feature_(feature), detector_(detector), extent_(extent), - layout_(font_manager, scale_factor), info_(placement_info), valid_(true), scale_factor_(scale_factor), + font_manager_(font_manager), placements_(), has_marker_(false), marker_(), @@ -153,173 +140,113 @@ bool placement_finder::next_position() return false; } - info_->properties.process(layout_, feature_); - layout_.layout(info_->properties.wrap_width * scale_factor_, info_->properties.text_ratio, info_->properties.wrap_before); + text_layout_ptr layout = std::make_shared(font_manager_, scale_factor_, info_->properties.layout_defaults); + layout->init_orientation(feature_); + info_->properties.process(*layout, feature_); + + layouts_.clear(); + layouts_.add(layout); + layouts_.layout(); - if (info_->properties.orientation) - { - // https://github.com/mapnik/mapnik/issues/1352 - mapnik::evaluate evaluator(feature_); - orientation_.init( - boost::apply_visitor( - evaluator, - *(info_->properties.orientation)).to_double() * M_PI / 180.0); - } - else - { - orientation_.reset(); - } - init_alignment(); return true; } -void placement_finder::init_alignment() +text_upright_e placement_finder::simplify_upright(text_upright_e upright, double angle) const { - text_symbolizer_properties const& p = info_->properties; - valign_ = p.valign; - if (valign_ == V_AUTO) + if (upright == UPRIGHT_AUTO) { - if (p.displacement.y > 0.0) - { - valign_ = V_BOTTOM; - } - else if (p.displacement.y < 0.0) - { - valign_ = V_TOP; - } - else - { - valign_ = V_MIDDLE; - } + return (std::fabs(normalize_angle(angle)) > 0.5*M_PI) ? UPRIGHT_LEFT : UPRIGHT_RIGHT; } - - halign_point_ = p.halign; - halign_line_ = p.halign; - if (halign_point_ == H_AUTO) + if (upright == UPRIGHT_LEFT_ONLY) { - if (p.displacement.x > 0.0) - { - halign_point_ = H_RIGHT; - halign_line_ = H_LEFT; - } - else if (p.displacement.x < 0.0) - { - halign_point_ = H_LEFT; - halign_line_= H_RIGHT; - } - else - { - halign_point_ = H_MIDDLE; - halign_line_ = H_MIDDLE; - } + return UPRIGHT_LEFT; } - - jalign_ = p.jalign; - if (jalign_ == J_AUTO) + if (upright == UPRIGHT_RIGHT_ONLY) { - if (p.displacement.x > 0.0) - { - jalign_ = J_LEFT; - } - else if (p.displacement.x < 0.0) - { - jalign_ = J_RIGHT; - } - else - { - jalign_ = J_MIDDLE; - } + return UPRIGHT_RIGHT; } -} - - -pixel_position placement_finder::alignment_offset() const //TODO -{ - pixel_position result(0,0); - // if needed, adjust for desired vertical alignment - if (valign_ == V_TOP) - { - result.y = -0.5 * layout_.height(); // move center up by 1/2 the total height - } - else if (valign_ == V_BOTTOM) - { - result.y = 0.5 * layout_.height(); // move center down by the 1/2 the total height - } - - // set horizontal position to middle of text - if (halign_point_ == H_LEFT) - { - result.x = -0.5 * layout_.width(); // move center left by 1/2 the string width - } - else if (halign_point_ == H_RIGHT) - { - result.x = 0.5 * layout_.width(); // move center right by 1/2 the string width - } - return result; -} - -double placement_finder::jalign_offset(double line_width) const //TODO -{ - if (jalign_ == J_MIDDLE) return -(line_width / 2.0); - if (jalign_ == J_LEFT) return -(layout_.width() / 2.0); - if (jalign_ == J_RIGHT) return (layout_.width() / 2.0) - line_width; - return 0; + return upright; } bool placement_finder::find_point_placement(pixel_position const& pos) { glyph_positions_ptr glyphs = std::make_shared(); + std::vector > bboxes; - /* Find text origin. */ - pixel_position displacement = scale_factor_ * info_->properties.displacement + alignment_offset(); - if (info_->properties.rotate_displacement) displacement = displacement.rotate(!orientation_); - glyphs->set_base_point(pos + displacement); - box2d bbox; - rotated_box2d(bbox, orientation_, layout_.width(), layout_.height()); - bbox.re_center(glyphs->get_base_point().x, glyphs->get_base_point().y); + glyphs->reserve(layouts_.glyphs_count()); + bboxes.reserve(layouts_.size()); - /* For point placements it is faster to just check the bounding box. */ - if (collision(bbox)) return false; - /* add_marker first checks for collision and then updates the detector.*/ - if (has_marker_ && !add_marker(glyphs, pos)) return false; - if (layout_.num_lines()) detector_.insert(bbox, layout_.text()); - - /* IMPORTANT NOTE: - x and y are relative to the center of the text - coordinate system: - x: grows from left to right - y: grows from bottom to top (opposite of normal computer graphics) - */ - double x, y; - - // set for upper left corner of text envelope for the first line, top left of first character - y = layout_.height() / 2.0; - glyphs->reserve(layout_.glyphs_count()); - - for ( auto const& line : layout_) + bool base_point_set = false; + for (auto const& layout_ptr : layouts_) { - y -= line.height(); //Automatically handles first line differently - x = jalign_offset(line.width()); + text_layout const& layout = *layout_ptr; + rotation const& orientation = layout.orientation(); - for (auto const& glyph : line) + /* Find text origin. */ + pixel_position layout_center = pos + layout.displacement(); + + if (!base_point_set) { - // place the character relative to the center of the string envelope - glyphs->push_back(glyph, pixel_position(x, y).rotate(orientation_), orientation_); - if (glyph.width) + glyphs->set_base_point(layout_center); + base_point_set = true; + } + + box2d bbox = layout.bounds(); + bbox.re_center(layout_center.x, layout_center.y); + + /* For point placements it is faster to just check the bounding box. */ + if (collision(bbox)) return false; + + if (layout.num_lines()) bboxes.push_back(std::move(bbox)); + + pixel_position layout_offset = layout_center - glyphs->get_base_point(); + layout_offset.y = -layout_offset.y; + + /* IMPORTANT NOTE: + x and y are relative to the center of the text + coordinate system: + x: grows from left to right + y: grows from bottom to top (opposite of normal computer graphics) + */ + double x, y; + + // set for upper left corner of text envelope for the first line, top left of first character + y = layout.height() / 2.0; + + for ( auto const& line : layout) + { + y -= line.height(); //Automatically handles first line differently + x = layout.jalign_offset(line.width()); + + for (auto const& glyph : line) { - //Only advance if glyph is not part of a multiple glyph sequence - x += glyph.width + glyph.format->character_spacing * scale_factor_; + // place the character relative to the center of the string envelope + glyphs->push_back(glyph, (pixel_position(x, y).rotate(orientation)) + layout_offset, orientation); + if (glyph.width) + { + //Only advance if glyph is not part of a multiple glyph sequence + x += glyph.width + glyph.format->character_spacing * scale_factor_; + } } } } + + /* add_marker first checks for collision and then updates the detector.*/ + if (has_marker_ && !add_marker(glyphs, pos)) return false; + + for (box2d const& bbox : bboxes) + { + detector_.insert(bbox, layouts_.text()); + } placements_.push_back(glyphs); + return true; } template bool placement_finder::find_line_placements(T & path, bool points) { - if (!layout_.num_lines()) return true; //TODO + if (!layouts_.line_count()) return true; //TODO vertex_cache pp(path); bool success = false; @@ -339,15 +266,15 @@ bool placement_finder::find_line_placements(T & path, bool points) || (pp.length() <= 0.001) /* Clipping removed whole geometry */ || - (pp.length() < layout_.width())) + (pp.length() < layouts_.width())) { continue; } } - double spacing = get_spacing(pp.length(), points ? 0. : layout_.width()); + double spacing = get_spacing(pp.length(), points ? 0. : layouts_.width()); - horizontal_alignment_e halign = info_->properties.halign; + horizontal_alignment_e halign = info_->properties.layout_defaults->halign; if (halign == H_LEFT) { // Don't move @@ -381,125 +308,116 @@ bool placement_finder::find_line_placements(T & path, bool points) return success; } -text_upright_e placement_finder::simplify_upright(text_upright_e upright, double angle) const -{ - if (upright == UPRIGHT_AUTO) - { - return (std::fabs(normalize_angle(angle)) > 0.5*M_PI) ? UPRIGHT_LEFT : UPRIGHT_RIGHT; - } - if (upright == UPRIGHT_LEFT_ONLY) - { - return UPRIGHT_LEFT; - } - if (upright == UPRIGHT_RIGHT_ONLY) - { - return UPRIGHT_RIGHT; - } - return upright; -} - - bool placement_finder::single_line_placement(vertex_cache &pp, text_upright_e orientation) { /******************************************************************************** * IMPORTANT NOTE: See note about coordinate systems in find_point_placement()! * ********************************************************************************/ - vertex_cache::scoped_state s(pp); + vertex_cache::scoped_state begin(pp); + text_upright_e real_orientation = simplify_upright(orientation, pp.angle()); glyph_positions_ptr glyphs = std::make_shared(); std::vector > bboxes; - bboxes.reserve(layout_.text().length()); - int upside_down_glyph_count = 0; + glyphs->reserve(layouts_.glyphs_count()); + bboxes.reserve(layouts_.glyphs_count()); - text_upright_e real_orientation = simplify_upright(orientation, pp.angle()); + unsigned upside_down_glyph_count = 0; - double sign = (real_orientation == UPRIGHT_LEFT) ? -1 : 1; - double offset = alignment_offset().y + info_->properties.displacement.y * scale_factor_ + sign * layout_.height()/2.; - - glyphs->reserve(layout_.glyphs_count()); - - for (auto const& line : layout_) + for (auto const& layout_ptr : layouts_) { - //Only subtract half the line height here and half at the end because text is automatically - //centered on the line - offset -= sign * line.height()/2; - vertex_cache & off_pp = pp.get_offseted(offset, sign*layout_.width()); - vertex_cache::scoped_state off_state(off_pp); //TODO: Remove this when a clean implementation in vertex_cache::get_offseted was done + text_layout const& layout = *layout_ptr; + pixel_position align_offset = layout.alignment_offset(); + pixel_position const& layout_displacement = layout.get_layout_properties()->displacement; + double sign = (real_orientation == UPRIGHT_LEFT) ? -1 : 1; + double offset = align_offset.y + layout_displacement.y * scale_factor_ + sign * layout.height()/2.; - if (!off_pp.move(sign * jalign_offset(line.width()) - alignment_offset().x)) return false; - - double last_cluster_angle = 999; - int current_cluster = -1; - pixel_position cluster_offset; - double angle; - rotation rot; - double last_glyph_spacing = 0.; - - for (auto const& glyph : line) + for (auto const& line : layout) { - if (current_cluster != static_cast(glyph.char_index)) + //Only subtract half the line height here and half at the end because text is automatically + //centered on the line + offset -= sign * line.height()/2; + vertex_cache & off_pp = pp.get_offseted(offset, sign*layout.width()); + vertex_cache::scoped_state off_state(off_pp); //TODO: Remove this when a clean implementation in vertex_cache::get_offseted was done + + if (!off_pp.move(sign * layout.jalign_offset(line.width()) - align_offset.x)) return false; + + double last_cluster_angle = 999; + int current_cluster = -1; + pixel_position cluster_offset; + double angle; + rotation rot; + double last_glyph_spacing = 0.; + + for (auto const& glyph : line) { - if (!off_pp.move(sign * (layout_.cluster_width(current_cluster) + last_glyph_spacing))) + if (current_cluster != static_cast(glyph.char_index)) { - return false; + if (!off_pp.move(sign * (layout.cluster_width(current_cluster) + last_glyph_spacing))) + { + return false; + } + current_cluster = glyph.char_index; + last_glyph_spacing = glyph.format->character_spacing * scale_factor_; + //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) + { + return false; + } + cluster_offset.clear(); + last_cluster_angle = angle; } - current_cluster = glyph.char_index; - last_glyph_spacing = glyph.format->character_spacing * scale_factor_; - //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) - { - return false; - } - cluster_offset.clear(); - last_cluster_angle = angle; + + if (std::abs(angle) > M_PI/2) ++upside_down_glyph_count; + + pixel_position pos = off_pp.current_position() + cluster_offset; + //Center the text on the line + double char_height = line.max_char_height(); + pos.y = -pos.y - char_height/2.0*rot.cos; + pos.x = pos.x + char_height/2.0*rot.sin; + + cluster_offset.x += rot.cos * glyph.width; + cluster_offset.y -= rot.sin * glyph.width; + + box2d bbox = get_bbox(layout, glyph, pos, rot); + if (collision(bbox)) return false; + bboxes.push_back(std::move(bbox)); + glyphs->push_back(glyph, pos, rot); } - if (std::abs(angle) > M_PI/2) ++upside_down_glyph_count; - - pixel_position pos = off_pp.current_position() + cluster_offset; - //Center the text on the line - double char_height = line.max_char_height(); - pos.y = -pos.y - char_height/2.0*rot.cos; - pos.x = pos.x + char_height/2.0*rot.sin; - - cluster_offset.x += rot.cos * glyph.width; - cluster_offset.y -= rot.sin * glyph.width; - - box2d bbox = get_bbox(glyph, pos, rot); - if (collision(bbox)) return false; - bboxes.push_back(bbox); - glyphs->push_back(glyph, pos, rot); + //See comment above + offset -= sign * line.height()/2; } - //See comment above - offset -= sign * line.height()/2; } - if (upside_down_glyph_count > (layout_.text().length()/2)) + + if (upside_down_glyph_count > (layouts_.text().length() / 2)) { if (orientation == UPRIGHT_AUTO) { //Try again with oposite orientation - s.restore(); + begin.restore(); return single_line_placement(pp, real_orientation == UPRIGHT_RIGHT ? UPRIGHT_LEFT : UPRIGHT_RIGHT); } //upright==left_only or right_only and more than 50% of characters upside down => no placement - if (orientation == UPRIGHT_LEFT_ONLY || orientation == UPRIGHT_RIGHT_ONLY) + else if (orientation == UPRIGHT_LEFT_ONLY || orientation == UPRIGHT_RIGHT_ONLY) { return false; } } - for (box2d const& bbox : bboxes) + + for (box2d const& box : bboxes) { - detector_.insert(bbox, layout_.text()); + detector_.insert(box, layouts_.text()); } placements_.push_back(glyphs); + return true; } void placement_finder::path_move_dx(vertex_cache &pp) { - double dx = info_->properties.displacement.x * scale_factor_; + double dx = info_->properties.layout_defaults->displacement.x * scale_factor_; if (dx != 0.0) { vertex_cache::state state = pp.save_state(); @@ -579,7 +497,7 @@ bool placement_finder::add_marker(glyph_positions_ptr glyphs, pixel_position con return true; } -box2d placement_finder::get_bbox(glyph_info const& glyph, pixel_position const& pos, rotation const& rot) +box2d placement_finder::get_bbox(text_layout const& layout, glyph_info const& glyph, pixel_position const& pos, rotation const& rot) { /* @@ -592,7 +510,7 @@ box2d placement_finder::get_bbox(glyph_info const& glyph, pixel_position (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); + double width = layout.cluster_width(glyph.char_index); if (glyph.width <= 0) width = -width; pixel_position tmp, tmp2; tmp.set(0, glyph.ymax); diff --git a/src/text/placements/base.cpp b/src/text/placements/base.cpp index faa9e02f2..4b7d5a672 100644 --- a/src/text/placements/base.cpp +++ b/src/text/placements/base.cpp @@ -42,6 +42,7 @@ text_placement_info::text_placement_info(text_placements const* parent, scale_factor(scale_factor_) { properties.format = std::make_shared(*(properties.format)); + properties.layout_defaults = std::make_shared(*(properties.layout_defaults)); } } //ns mapnik diff --git a/src/text/placements/list.cpp b/src/text/placements/list.cpp index 1bfdb191c..ad16b0900 100644 --- a/src/text/placements/list.cpp +++ b/src/text/placements/list.cpp @@ -99,6 +99,7 @@ text_placements_ptr text_placements_list::from_xml(xml_node const &xml, fontset_ if (itr->is_text() || !itr->is("Placement")) continue; text_symbolizer_properties &p = list->add(); p.format = std::make_shared(*(p.format)); //Make a deep copy + p.layout_defaults = std::make_shared(*(p.layout_defaults)); //TODO: This needs a real copy constructor for text_symbolizer_properties p.from_xml(*itr, fontsets); //TODO: if (strict_ && diff --git a/src/text/placements/simple.cpp b/src/text/placements/simple.cpp index 02218b248..e20f34ad2 100644 --- a/src/text/placements/simple.cpp +++ b/src/text/placements/simple.cpp @@ -61,8 +61,8 @@ bool text_placement_info_simple::next() bool text_placement_info_simple::next_position_only() { - pixel_position const& pdisp = parent_->defaults.displacement; - pixel_position &displacement = properties.displacement; + pixel_position const& pdisp = parent_->defaults.layout_defaults->displacement; + pixel_position &displacement = properties.layout_defaults->displacement; if (position_state >= parent_->direction_.size()) return false; directions_t dir = parent_->direction_[position_state]; switch (dir) { diff --git a/src/text/text_properties.cpp b/src/text/text_properties.cpp index 5839a69c6..dfa793698 100644 --- a/src/text/text_properties.cpp +++ b/src/text/text_properties.cpp @@ -99,12 +99,7 @@ IMPLEMENT_ENUM(text_upright_e, text_upright_strings) */ text_symbolizer_properties::text_symbolizer_properties() : - orientation(), - displacement(0.0,0.0), label_placement(POINT_PLACEMENT), - halign(H_AUTO), - jalign(J_AUTO), - valign(V_AUTO), label_spacing(0.0), label_position_tolerance(0.0), avoid_edges(false), @@ -115,11 +110,8 @@ text_symbolizer_properties::text_symbolizer_properties() : force_odd_labels(false), allow_overlap(false), largest_bbox_only(true), - text_ratio(0.0), - wrap_width(0.0), - wrap_before(false), - rotate_displacement(false), upright(UPRIGHT_AUTO), + layout_defaults(std::make_shared()), format(std::make_shared()), tree_() { @@ -150,14 +142,6 @@ void text_symbolizer_properties::from_xml(xml_node const &sym, fontset_map const { optional placement_ = sym.get_opt_attr("placement"); if (placement_) label_placement = *placement_; - optional valign_ = sym.get_opt_attr("vertical-alignment"); - if (valign_) valign = *valign_; - 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 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"); @@ -179,22 +163,12 @@ void text_symbolizer_properties::from_xml(xml_node const &sym, fontset_map const 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_; - 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 orientation_ = sym.get_opt_attr("orientation"); - if (orientation_) orientation = *orientation_; - optional rotate_displacement_ = sym.get_opt_attr("rotate-displacement"); - if (rotate_displacement_) rotate_displacement = *rotate_displacement_; - optional upright_ = sym.get_opt_attr("upright"); - if (upright_) upright = *upright_; - 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 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_) @@ -213,42 +187,10 @@ void text_symbolizer_properties::to_xml(boost::property_tree::ptree &node, bool explicit_defaults, text_symbolizer_properties const& dfl) const { - 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); - } - } - - 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 (label_placement != dfl.label_placement || explicit_defaults) { set_attr(node, "placement", label_placement); } - if (valign != dfl.valign || explicit_defaults) - { - set_attr(node, "vertical-alignment", valign); - } - 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 (label_position_tolerance != dfl.label_position_tolerance || explicit_defaults) { set_attr(node, "label-position-tolerance", label_position_tolerance); @@ -269,22 +211,98 @@ void text_symbolizer_properties::to_xml(boost::property_tree::ptree &node, { set_attr(node, "minimum-path-length", minimum_path_length); } - if (allow_overlap != dfl.allow_overlap || explicit_defaults) - { - set_attr(node, "allow-overlap", allow_overlap); - } if (avoid_edges != dfl.avoid_edges || explicit_defaults) { set_attr(node, "avoid-edges", avoid_edges); } - if (largest_bbox_only != dfl.largest_bbox_only|| explicit_defaults) + if (allow_overlap != dfl.allow_overlap || explicit_defaults) { - set_attr(node, "largest-bbox_only", largest_bbox_only); + 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 +{ + if (layout_defaults) 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_; + 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); @@ -293,32 +311,34 @@ void text_symbolizer_properties::to_xml(boost::property_tree::ptree &node, { set_attr(node, "justify-alignment", jalign); } - if (valign != dfl.valign || explicit_defaults) + if (text_ratio != dfl.text_ratio || explicit_defaults) { - set_attr(node, "vertical-alignment", valign); + 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); } - if (upright != dfl.upright || explicit_defaults) + if (orientation) { - set_attr(node, "upright", upright); + std::string const& orientationstr = to_expression_string(*orientation); + if (!dfl.orientation || orientationstr != to_expression_string(*(dfl.orientation)) || explicit_defaults) { + set_attr(node, "orientation", orientationstr); + } } - format->to_xml(node, explicit_defaults, *(dfl.format)); - if (tree_) tree_->to_xml(node); } - -void text_symbolizer_properties::add_expressions(expression_set &output) const +void text_layout_properties::add_expressions(expression_set &output) const { output.insert(orientation); - if (tree_) tree_->add_expressions(output); -} - -void text_symbolizer_properties::set_old_style_expression(expression_ptr expr) -{ - tree_ = std::make_shared(expr); } char_properties::char_properties() : diff --git a/tests/visual_tests/grids/lines-multi-layout-1-800-800-1.0-grid-reference.json b/tests/visual_tests/grids/lines-multi-layout-1-800-800-1.0-grid-reference.json new file mode 100644 index 000000000..a34444598 --- /dev/null +++ b/tests/visual_tests/grids/lines-multi-layout-1-800-800-1.0-grid-reference.json @@ -0,0 +1,224 @@ +{ + "keys": [ + "", + "9", + "8", + "4", + "5", + "7", + "16", + "6", + "10", + "2", + "12", + "13", + "14", + "11", + "3", + "15", + "1" + ], + "data": {}, + "grid": [ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " !! ", + " !!! !!!! !!!!! ", + " !! !! ! !!!! ! ! !!!!! ", + " !!!! !! !!!!!! !! ! !! !!! !!!!! ! ", + " !!!! !! !!!!!!! !!!! !! !!!!!!! !!!!!! ! ", + " !!!!! !! !!!! !!!! !!!! !! !! !!!! !!!! !!!!!!! ! !! ", + " !!!!! !! !!!! ! !!!! !!!!!! !!!!!! !!!!! !!!!!! !! !!! !! ", + " !!!!! !! !! !!! !!!!!! !! ! !! !!!!!!!!! !!!!!!!!!!! !! !!!! ! ", + " !!!!! !!!!!! !!!!!!!!!!! !!!!!! !! !!!!!! !!!! !!!!!!!! ! !! ! !!!! ", + " !!! !! !!!! !!! !!!!!!! !!!!!!! !!! !!! ! !!! ! !!!!!!! !! !!! !!!! !! ", + " !!!!!!!! !! !!!!! ! !!!! !!!!!! !!!!!!!!!!! !! !! !!!! !!!!!! !!!! ! ! ", + " !! !!!!!!!! !! !! !!!!!!!!!!! !!! !!!!!!!! !! !!!!!!! !!!! !!!!!! ", + " !! ! !!! !! !!!!!!!!!!! !!!!!!! !! !! !! !! !!!! !!!! !!!!!! ", + " !! ! !! !! !! !! !!! !!! ! !! ! !!!! !! !!!!!!!!!! !!!!!!!!! !! ", + " !! !!! !! !! !! ! !! !!!! !!!! !! !!!!!!!!!! !!!!!!!!!!! ", + " !!!!!! !!!!! !! !!!!!!! ! !!!! !!!!!! !!!! !! !!!!!!! ", + " !!!!!!!!!!!!! ! !!!!!! !! !!!!!! !!!!! !! !!! ", + " ! !!!!! !! !!!!!! ! !! !!! !!! !! ! !! ", + " !!!! ! !! !! !!!!!! !!!!!! !! ! ", + " !!! !! !! !!!!!!!! !!! ! ", + " !!!!!!! !!!!!!!! ", + " ## !!!!!!!! !!!!!!!!! # $ ", + " ### # # !!!!!!!! # !!!!!! ### $ ", + " ##### ## # ### !!!!!!! ## ### ### !! #### $ ", + " ###### ## ## #### !!! #### ## ## ##### #### # $$ $ ", + " ######### ## ## #### ! #### ## ## ##### ######## #### ## # $$ $ ", + " ######### ## ### ###### ###### # # ## ####### ####### ## ## #### ## $$ $ ", + " ### ## #### ### # ######## ########### ## ### ##### ## ## ##### ### # ## #### ## $$ $$$ ", + " ## ##### #### ######## ###### ###### ####### ### # #### ##### ## #### #### ## ## $$ $$$ $$ ", + " ## ##### #### ## ## #### #### #### # # ######### ## #### ######## ## # $$ $$$ $$ ", + " ## ##### ### # ## #### #### ## # #### ## ##### ## ###### ### $$ $$$ $$ ", + " ## #### ### ## ## #### ####### ## #### # ## ######## ## ## #### $$ $$$$$$ ", + " ## ##### #### ## ## ##### #### ## # ####### ###### ####### ## # ## $$ $$$$ $ ", + " # ### ### ## ## ## #### ### ## ### ## ## #### ##### ##### # ## #### $$ $$$ $ ", + " % # ### # ### ### ## #### ### ## ######## ## # #### #### ## #### $$ $$$ ", + " % ## ## ####### ## ## ## ## ###### ## ####### # #### $$ $ ", + " % ## ##### ## # ## ## ##### ## ## #### $$ $ ", + " %%%% ## ## ## ## ## ## # # ## ## ## ### $$ $ ", + " %%%% ## ##### ## ## ####### #### #### $ ", + " %%%% ####### # ## # ## ### ### # $ ", + " %%%%%%% ## ## ### # ####### # $ ", + " %%%%%%%%% # # ####### # ## #### $ ", + " %%%%%% %% ### # ##### ### ### $ ", + " %%%%%%%%% #### ### ######## $ ", + " %%%%%%%%% ####### &&&&& #### &&&&& $$ $ ", + " %%%%%%% % &&&&& ### &&&&&& &&&&&&& &&& &&&& $$ $ ", + " %%% %%%%% &&&&&& &&&&&&&&& &&&& & &&&&&& &&&&& $$ $$$ ", + " %%%%%%% &&&&&&&& &&&&& &&&& &&&&& &&&&&&& &&&&&&&&& & $$ $$$ ", + " %%%% &&&&&& &&&&&& &&&&& &&& && &&&&& &&& & & &&&&&&&&&&&& && $ $$$ $$ ", + " %%%% &&&&&&&&&&& && &&&& && &&& && &&&&&& &&&&& & && && &&&&& & && $$ $$$ $$ ", + " % % &&& &&&&&&& && &&&&& &&&&&& && && & &&&&&&&& & &&& &&&&&&&& & &&& $$ $$$ $$ ", + " % &&&&&&&&&& && && &&&&&&&& & &&& &&&&&&& && &&&&& && &&&&&&&& &&&& $$ $$$$$$ ", + " % &&&&&&& && & &&& & &&&& &&& &&&& && &&&&&&& &&&& && && &&&&& &&&&& & $$ $$$$$$ ", + " % & &&&&&&&& &&&& & &&&&&&& &&&& & && &&&& & &&&& && && && & &&& &&&& & $$ $$$ ", + " % & &&& &&&&&& && && &&& &&&&&& &&&&& && & &&&&&&&&&&& && &&&&&&&&& && $$ $$$ ", + " % & && & &&&&&&&&& && & &&&&&&&& & & &&& &&&&& &&&&&&& && && $$ $ ", + " % & &&&&&&& && &&&&&&& &&&& &&&&& & &&& &&&&&&& && $$ $ ", + " % &&&& & & && &&&&&& &&& &&&&&&&&&& &&&&& && $ ", + " % %% &&&&&&&&&& &&&& &&&& &&&&& & &&&&&&& $ ", + " % %% &&&&& &&&&&&& &&&&&&& & && &&& $ ", + " %%% %% &&&&&&& &&&&&&& &&& &&& &&&& $ ", + " %%% %% &&& &&& &&&&& & &&&&& &&& $ ", + " %%%%%% %% &&&&& &&& && $ ", + " %%%%%% %% &&& & ''''''''' $$ $ ", + " %% %%% %% '''''''' ''''''' $$ $ ", + " %% %%% %% ''''''''' ' $$ $ ", + " %% %%% % (( ((( ''''' ' $$ $$$ ", + " %%% %% ( ( (( ((((( (((((( ''''' ' $ $$$ $$ ", + " % %% ((( ((((( ((((((( (((((( '''''''''''''''''''''''' $$ $$$ $$ ", + " % %% ((((((( ((((((( ((((( ( (((( ((( $$ $$$ $$ ", + " % %% (((((( ( (((( (( (((((((( ((((((( ''''''''''''' $$ $$$$$$ ", + " % ((((((( (((((((( ( (((( ((((( ((( (((((((( '''''''' '''' $$ $$$$$$ ", + " % ( ((((( ((((( ((( ((((((( ((((( (( (( ( (( '''''''' '''' $$ $$$ ", + " % (( ((( (( ( ((( (( (( (( ((((( (( ( (( (((((( (( ((( $$ $$$ ", + " % (( (((( (( ((( (( ((((((( ( (( (( ((( (((( (( (( (( (((((((( (( ((( ( $$ $ ", + " % (( (((((((( (( ((( (( ((( (((( (( (((( ( (((((( (( (( ((( (( (( (((( ( ((((((( $$ $ ", + " % (( ((((( (( (((( ((( (( ((((( (( ((((((( (( ((((( ( (((((( (( (((( ( ((((((( $ ", + " % ( ((((( (((((( ((((((( ( ((((( ( (((((( (( (((( ( ((((((( (( (((( ( (((((( $ ", + " % %% ( (((( ((( ( ((((((( ( (((( ( ((((( (( ((( (( ((( (( ((( (((((((((( (( $ ", + " % %% ( ((( ((( ((((( (( (( ((( (((( (( (((((((((( ( ((( (( ((( (( $ ", + " %%% %% ( (((((((( (( (( (( (((( ( ((( (( ((( (( ((( (( ( ((( $ ", + " %%% %% ((( ((( (( ((( (( (( (( ((( ((( (( ((((( ((((( $ ", + " %%%%%% %% (((( (( ((( ((( ((((( ((((( (( (((((( $$ $ ", + " %%%%%% %% ( (( ((( ((((( ((((((((( ))) ((( (((( $$ $ ", + " %% %%% %% ((((( ** + (((((((( ((( (((( ))))))))))))) (((((( $$ $ ", + " %% %% %% ((( * ** + ((((((( ((( )))))))) )))) ))))))) $$ $$$ ", + " %% %%% % **** ** + ))))))))) ) ))))))))) $$ $$$ $ ", + " %%% %% **** ** + , ) )))))))))))))))))))) ))) )) $$ $$$ $$ ", + " %%% %% ****** * + , ------ --- )))))))) )))))))) )))) $$ $$$ $$ ", + " % %% **** ****** ** + , -------- ---- )))))))) ))))))))))) $$ $$$$$$ ", + " % %% ****** ****** + , -- ------ ---- )) )))))))))))) $ $$$$ $ ", + " % * ** * **** ++++ , ---------------------------- ))))) )) )))) ) $$ $$$$$ ", + " % ** **** + ++ , ---- - - ))))) ))) )) )) $$ $$$ ", + " % ** **** + ++ , -------- ))))) ) $$ $ ", + " % * ***** +++++++ , -------- ) ) $$ $ ", + " % ** **** ++++++ , . ----- .. . .. ..... )) $$ $ ", + " % ** **** ++++ ++++ , . ..........----- ....... ..... ) $ ", + " % * ** +++++++++ , ,, ........ .... ............. ) $ ", + " % %% ** ++++++ ++ , , ,,, ...... ................................ ) $ ", + " % %% ** ++ +++ ++ ,, , ,, ......... .... . . ) $ ", + " %%%% * * ++ +++++++,, ,,, ,, .. ......... ........ ) )) $ ", + " %% %%% **** ** ++ +++,,,,,,, , . . ....... ........ ) )) $ ", + " % %%%%%% **** ** ///// +++,,,,, ,,,, .. .... ..... )) ) )) $$ $ ", + " %%%%% %%% ******* * ////////// ++++,,,, , ,, . ...... ..... )) ))) )) $$ $ ", + " %%%%% %%%% **** *** ** ** /////////// + ,,,,,,,,,, . ...... ))))))) $$ $$$ ", + " %%%%% %%% ******* ** *** //// ////// / + ,, , ,, . 0 0 0 0 )))) )))) $$ $$$ ", + " %%%%%%%%% * *** * ***** // ////// ////// /// ++ ,, , ,, . 00000000 ))))) ) )) $ $$$ $$ ", + " %% %% %%%% ** **** ///////// ///////// + ,,,, . 00000000 ))))) )))) $$ $$$ $$ ", + " %% %%%% ** *** ////////// ///// + ,,,, . . 00000 ))))) )))) $$ $$$$$$ ", + " %%% * ***** / /////// // /// + ,,,, ... 00000 ))) )))) $$$ $$$$$$ ", + " %%% ** **** // /////// //// // + , ... 00000 ) ))) $$ $$$$$$ ", + " %%% ******* // // /// //// + , ..... . 00000000000000000000000000000 ) )) $$ $$$ ", + " % * *** // /////// / , .. .... 0 0 00 ) )) $$$ $$$ ", + " % ** * // /////// /// , . ... .. 00000000 0000 ) $$ $ ", + " % * // // ////// / // , .. ... .. 00000000 0000 ) $$ $ ", + " % /// ////// //// , .. ... .. )))))))) )) )) $ ", + " % //// // / //// , .. ...... ))))))))) )))))))) ) $ ", + " % /////// / , .. ...... ))))))) )))))))) ) $ ", + " % / /// / .. ... ))))) )))) )) $ ", + " %%%% // /// // // .. ... ))))) )))))) ) $ ", + " %%%% // /// // // .... ))))))))))))) ))))) ) $ ", + " %%%%%% /// ///// / .... ))))))))))))))))))))))))))))) $$$ ", + " %%%%%%% ///////// / . )))))))))) )) $$$ ", + " %%%%%%%% ///////// // . )))))))) )))) )))))))) )))) $$$ ", + " %%%% %%%% /////// / . )))) )))) )))))))) )))) $$$ $$ ", + " %%%% %%% // / / .. .. $$$ $$ $$ ", + " %%%%%%%%% // / / . ... . $$$$$$$$$ ", + " %%%% % % / / . ....... ........ $$$ $$$$$ ", + " %%%%%%% / / . ...... ........ $$$$ $$$$$ ", + " %%% / / .. .. ..... $$$$$$$$$ ", + " %%% / / .. ..... ..... $$$ $$ ", + " %%% / / .. ... ..... $$$ $$ ", + " % // / .. ..................................... $$$$ ", + " % // / ..... . . .. $$$ ", + " % / / ............ ............. $ ", + " % / / ..... .... ............. $ ", + " // // $ ", + " / / $ ", + " / / ", + " / // ", + " // // 1 1 1 ", + " / // 11111111 111111111 ", + " / // 11111111 111111111 ", + " / // 1 11 11111 ", + " /// // 11111 11111 ", + " /////// // 11111 111 1 ", + " /////// // 11111111111111111111111111111111111111111111111 ", + " /// 111 1 1 1111 ", + " 1111111111111 11111111 1111 ", + " 11111111 1111 11111111 1111 ", + " 1 1 ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + ] +} \ No newline at end of file diff --git a/tests/visual_tests/grids/lines-multi-layout-2-800-800-1.0-grid-reference.json b/tests/visual_tests/grids/lines-multi-layout-2-800-800-1.0-grid-reference.json new file mode 100644 index 000000000..96a1f2fbe --- /dev/null +++ b/tests/visual_tests/grids/lines-multi-layout-2-800-800-1.0-grid-reference.json @@ -0,0 +1,209 @@ +{ + "keys": [ + "", + "1" + ], + "data": {}, + "grid": [ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ! ", + " ! ", + " ! !!!!! ", + " !!! ! ", + " !!!!!!!! ! ! ! ", + " ! !! ! ! ", + " !! ! !! ! ", + " !! !!! !! ! ", + " ! ! !!! ! ! ", + " ! ! ! ! !! ", + " ! ! ! ! ", + " !! ! ! ! ", + " ! ! ! !! ! !! ", + " ! !!! !! ! ! ! ", + " ! ! !! ! ! !!! ", + " ! !! !!! !! ! ", + " ! !!! ! ! ! ! ", + " ! ! ! !!!! ! ! !! ", + " ! !! ! ! !! ! ", + " ! ! ! ! ! !! ", + " ! !! ! ! !! ", + " !! ! ! ! ! ! !!! ", + " ! !! !!! !! ! !!! ", + " ! ! ! ! ! ! ! !! ", + " !! ! ! !!! ! ! ! ", + " ! !! !! ! !!! ! ", + " !!! ! !!! !! ! ! ! ", + " !! ! ! ! !!! ", + " ! ! ! ! ! ", + " !! ! ! !! ", + " !! ! ! ", + " ! ! ! !! ! ", + " ! ! ! ! ", + " !!! !! !! ! ", + " !!!! ! !! !!! ", + " !! ! ! ! !! ! ", + " ! !!! !!!! !!!! ", + " !! ! ! ! !! ! ", + " !!! ! !!! !! ! ", + " ! ! ! !! ! ", + " !! ! !! ! ", + " ! ! ! ! ", + " ! ! ! ", + " ! !!!!! ! ", + " ! ! ! ! ", + " ! ! !! ! ", + " ! ! !! ! ", + " ! ! ! ", + " ! ! ! ", + " ! !!! ! ! ", + " ! ! ! !!!!! ", + " ! ! !!!!! ! !! ", + " ! ! !! ! ! !!! ", + " ! ! ! ! ! ! !! ", + " ! !!! !!! ! ! !! ", + " ! ! ! ! !! ", + " !!!! ! ! ! ! ", + " ! !!! !! ! !!!! ", + " ! !! !! ! ! ", + " ! ! ! ! ! ", + " ! !! !! ! ! !! ", + " ! ! !!!! ! ! ! ! ", + " ! !! !! !! ! ! ", + " ! !! !!! ! !! ! ", + " ! !!! !!! ! ! ! ", + " ! ! !! ! ! ", + " !!!! ! !!!! ! ", + " !!!! !! ! !! ! ", + " !! ! !! ! ! ", + " ! ! ! !! ! ", + " !! ! ! ! ! ", + " ! ! !! !!!! ", + " !!! ! ! ", + " ! ! !! ! ! ", + " ! ! !! ! ! ! ", + " !! ! ! !!! ! !! ", + " !!! ! ! !!!!! ", + " !!!! !!! ! !! ! ", + " !! ! ! !! !!! ", + " !!! ! ! !! ! ", + " !! ! ! !! ", + " ! ! !! ! ", + " ! ! ! ! ", + " ! !!!! ! ", + " ! ! !! !! ", + " ! ! ! ! ! ", + " ! !! ! ", + " ! ! ! ", + " ! ! ! ", + " ! !! ! ! ", + " ! ! ! ! ! ", + " ! !!! ! ! ! ! ", + " ! ! ! !! ! ! ! ", + " ! !! !!! ! ! ! ", + " !!! !!! ! ! !! ", + " ! !! !! ! ! ! ! ", + " ! !! ! ! ! !!! ", + " ! !!! ! ! ! !!! ", + " ! !!! ! ! ! ! !! ", + " ! ! !! ! ! ", + " ! ! ! ! ! !! ", + " !! !! !!!! ! !! ! ", + " ! ! ! ! !! ", + " ! !! !!! ! ! !! ", + " ! ! ! ! !!! ", + " ! !!! ! ! ! ", + " ! ! ! !!!! ", + " !!!! ! !!!! ! ", + " !! !! ! !! ! ", + " ! ! ! ! ! ", + " !! ! ! !! ! ", + " ! ! ! ! ! ", + " ! ! !!! !!! ", + " !!! ! ! !! ! ", + " ! ! !!! ! ! ", + " !!! ! !! ! ! ", + " !!!! ! ! !!! ", + " !!!! !!!! ! ! ", + " !! ! !!! ! !! ! ", + " !! ! ! ! !! ! ", + " ! ! !! ! ! ", + " ! ! !! !!! ", + " !! ! !! ! ", + " ! ! !! ! ", + " ! ! !!! ! ", + " ! ! ! !! ", + " ! !! ! ", + " ! ! ! ", + " ! !!! ! ! ", + " ! ! !! !! ", + " ! !!! ! ! ", + " ! !!! ! ! ", + " ! ! ! ! ! ! ", + " ! ! !!! ! ! !! ", + " ! !! ! !! ! ", + " ! ! ! ! ! ", + " ! ! ! ! ! ! ! ", + " ! ! ! ! ! ! !!!! ", + " ! !!!! !! ! ! ! ! ", + " ! ! ! !! !! ! ! ", + " ! !! !!!! ! !! ", + " ! ! ! ! ! ! ! ", + " ! ! ! ! ! ! ", + " ! ! ! ! ! !! ", + " ! ! ! ! ! ", + " ! ! ! ! !! ", + " ! ! ! !! ! !! ", + " ! !!! ! !! !! ! ! ", + " ! !! !! ! ! ! ", + " ! ! !! ! !! ! ", + " !!! ! ! !!!!! !!! ", + " !! ! ! !! ! ! ", + " ! !!!!!! !!! ", + " !! ! ! !! ! ! ", + " !! !!! ! ! ", + " !! !! ! ! !! ", + " ! !! ! !!!! ", + " ! ! ! ! ! ! ! ", + " ! ! ! ! ! ", + " ! !! !!!!! !! ! ", + " ! !!! ! !!! ! ! ", + " !!! ! ! ! ! ! ", + " !!!! !! ! ", + " !! ! ! ! ", + " !! ! ! ", + " ! ! !! ", + " ! !! ! ! ", + " ! !!! !! ! ", + " ! !!! !! !! ", + " ! !! ! !! !! ", + " ! !!!! !!!!!! ", + " ! !!! ", + " !!!! !!! ", + " !! ! ", + " !! ! ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + ] +} \ No newline at end of file diff --git a/tests/visual_tests/grids/lines-multi-layout-shield-800-800-1.0-grid-reference.json b/tests/visual_tests/grids/lines-multi-layout-shield-800-800-1.0-grid-reference.json new file mode 100644 index 000000000..e4ae90b58 --- /dev/null +++ b/tests/visual_tests/grids/lines-multi-layout-shield-800-800-1.0-grid-reference.json @@ -0,0 +1,217 @@ +{ + "keys": [ + "", + "8", + "7", + "6", + "5", + "9", + "4", + "2", + "1", + "3" + ], + "data": {}, + "grid": [ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! ", + " !!!!!!!!! !!!!!!!!! !!!!!!!!! !!!!!!!!! !!!!!!!!! !!!!!!!!! !!!!!!!!! !!!!!!!!! !!!!!!!!! !!!!!!!!! !!!!!!!!! !!!!!!!!! ", + " !!!!! !!!!! !!!!! !!!!! !!!!! !!!!! !!!!! !!!!! !!!!! !!!!! !!!!! !!!!! ", + " !!!!! !!!!! !!!!! !!!!! !!!!! !!!!! !!!!! !!!!! !!!!! !!!!! !!!!! !!!!! ", + " !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ", + " !!!!! !!!!! !!!!! !!!!! !!!!! !!!!! !!!!! !!!!! !!!!! !!!!! !!!!! !!!!! ", + " ", + " !!!!! !!!!! !!!!! !!!!! !!!!! !!!!! !!!!! !!!!! !!!!! !!!!! !!!!! !!!!! ", + " !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! ", + " ", + " ", + " ", + " ", + " ", + " ", + " ######### ######### ######### ######### ######### ######### ######### ######### ######### ######### ######### ######### ", + " ######### ######### ######### ######### ######### ######### ######### ######### ######### ######### ######### ######### ", + " ######### ######### ######### ######### ######### ######### ######### ######### ######### ######### ######### ######### ", + " ##### ##### ##### ##### ##### ##### ##### ##### ##### ##### ##### ##### ", + " #################################################################################################################################################################################### ", + " ##### ##### ##### ##### ##### ##### ##### ##### ##### ##### ##### ##### ", + " ##### ##### ##### ##### ##### ##### ##### ##### ##### ##### ##### ##### ", + " #### #### #### #### #### #### #### #### #### #### #### #### ", + " #### #### #### #### #### #### #### #### #### #### #### #### ", + " # ## # ## # ## # ## # ## # ## # ## # ## # ## # ## # ## # ## ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " $$$$$$$$$ $$$$$$$$$ $$$$$$$$$ $$$$$$$$$ $$$$$$$$$ $$$$$$$$$ $$$$$$$$$ $$$$$$$$$ $$$$$$$$$ $$$$$$$$$ $$$$$$$$$ $$$$$$$$$ ", + " $$$$$$ $$ $$$$$$ $$ $$$$$$ $$ $$$$$$ $$ $$$$$$ $$ $$$$$$ $$ $$$$$$ $$ $$$$$$ $$ $$$$$$ $$ $$$$$$ $$ $$$$$$ $$ $$$$$$ $$ ", + " $$$$$$ $$ $$$$$$ $$ $$$$$$ $$ $$$$$$ $$ $$$$$$ $$ $$$$$$ $$ $$$$$$ $$ $$$$$$ $$ $$$$$$ $$ $$$$$$ $$ $$$$$$ $$ $$$$$$ $$ ", + " $$$$$ $$$$$ $$$$$ $$$$$ $$$$$ $$$$$ $$$$$ $$$$$ $$$$$ $$$$$ $$$$$ $$$$$ ", + " $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ ", + " $$$$$ $$$$$ $$$$$ $$$$$ $$$$$ $$$$$ $$$$$ $$$$$ $$$$$ $$$$$ $$$$$ $$$$$ ", + " $$$$$ $$$$$ $$$$$ $$$$$ $$$$$ $$$$$ $$$$$ $$$$$ $$$$$ $$$$$ $$$$$ $$$$$ ", + " $$$$ $$$$ $$$$ $$$$ $$$$ $$$$ $$$$ $$$$ $$$$ $$$$ $$$$ $$$$ ", + " $$$$ $$$$ $$$$ $$$$ $$$$ $$$$ $$$$ $$$$ $$$$ $$$$ $$$$ $$$$ ", + " $$$$ $$$$ $$$$ $$$$ $$$$ $$$$ $$$$ $$$$ $$$$ $$$$ $$$$ $$$$ ", + " ", + " ", + " ", + " ", + " ", + " %%%%%%%% %%%%%%%% %%%%%%%% %%%%%%%% %%%%%%%% %%%%%%%% %%%%%%%% %%%%%%%% %%%%%%%% %%%%%%%% %%%%%%%% %%%%%%%% ", + " %%%%%%%% %%%%%%%% %%%%%%%% %%%%%%%% %%%%%%%% %%%%%%%% %%%%%%%% %%%%%%%% %%%%%%%% %%%%%%%% %%%%%%%% %%%%%%%% ", + " %%%%%% %%%%%% %%%%%% %%%%%% %%%%%% %%%%%% %%%%%% %%%%%% %%%%%% %%%%%% %%%%%% %%%%%% ", + " %%%%%% %%%%%% %%%%%% %%%%%% %%%%%% %%%%%% %%%%%% %%%%%% %%%%%% %%%%%% %%%%%% %%%%%% ", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " %%%%%% %%%%%% %%%%%% %%%%%% %%%%%% %%%%%% %%%%%% %%%%%% %%%%%% %%%%%% %%%%%% %%%%%% ", + " ", + " %%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% ", + " %%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% %%%% ", + " ", + " ", + " ", + " ", + " ", + " &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ''''''' ' '''''''' (((((((( ", + " '' '''''' '' ''''' (((((((( ( ((((((((( ", + " )))) )))) ''''''' ' '''''''' (((((((( ((( ((( (((((( (( ", + " )))) )))) ) ))))))))) '''''' '''''' ((((((((( (((((((( (( ", + " ))))))))) )))))) ))))))))) '''''''''''''''''''''''''''''''''''''' (((((( ((((((( ", + " )))))))) )))))))))) '''''' '''''' (((((( ((((( ", + " )))))) ))))))) '''''' '''''' (((((( ((((( ", + " ))))) )))))) ''''' ''''' (((( ((((( ", + " ))))) )))))) '''' '' ' (( ( (((( ", + " )))) )))))) '''' '''' ((((( (((( ", + " )))) )))) ( ((((( ", + " )))) )) ) (( ( ", + " ) ) ))) ( ( ", + " ) ) ( ( ", + " )) ) ( ( ", + " ) ) ( (( ", + " ) ) ( ( ", + " ) ) ( ( ", + " ) )) ((((((((( (((( (((( ", + " ) ) ((((((( ( (((( (((( ", + " ))))))))) )))))))) (((((( ((((((((( ", + " ))))))))) )))))))) (((((( ((((( ", + " ))))) )))))))) (((((( ((((( ", + " ))))) )))))) ((((((( ((((( ", + " ))))) )))))) ******** ******** (( (((((((( ", + " )))))) )))))) ******* ******** ((((( (( ((( (((( ", + " ))) )))))))) ****** ****** (((( (( (((( ", + " )))) ))) ))) )))) ****** ****** (((( ", + " )))) )) )) ) ************************************** ", + " )))) ****** ****** ", + " ****** ****** ", + " ***** **** ", + " **** **** ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + ] +} \ No newline at end of file diff --git a/tests/visual_tests/grids/text-multi-layout-1-512-512-1.0-grid-reference.json b/tests/visual_tests/grids/text-multi-layout-1-512-512-1.0-grid-reference.json new file mode 100644 index 000000000..5bdb416b7 --- /dev/null +++ b/tests/visual_tests/grids/text-multi-layout-1-512-512-1.0-grid-reference.json @@ -0,0 +1,142 @@ +{ + "keys": [ + "", + "2", + "3", + "5", + "6", + "4", + "1" + ], + "data": {}, + "grid": [ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ! # ", + " !! ## ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " $ ", + " $ ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " % ", + " %% ", + " % ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " & ' ", + " && '' ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + ] +} \ No newline at end of file diff --git a/tests/visual_tests/grids/text-multi-layout-2-512-512-1.0-grid-reference.json b/tests/visual_tests/grids/text-multi-layout-2-512-512-1.0-grid-reference.json new file mode 100644 index 000000000..fa899d3ad --- /dev/null +++ b/tests/visual_tests/grids/text-multi-layout-2-512-512-1.0-grid-reference.json @@ -0,0 +1,137 @@ +{ + "keys": [ + "", + "1" + ], + "data": {}, + "grid": [ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ! ", + " !!! ", + " ! !! ", + " ! ! !!! ", + " !! ! ! ", + " !!! !!! ", + " ! ! !!! ", + " ! ! !! ! ", + " ! ! !! !!! ", + " !! !!! !!! ", + " ! ! !!! ! ! ", + " !! ! ! !!!! !! ! ", + " ! ! !! !!! !!! !! ", + " !! !!! ! ! !! ", + " !! !! !! ! ! ", + " !! !!!! !!! !! ", + " !! ! !! !! !!! ! ! ! ", + " !! !!!!!!!!!!! !!!!! !!! ! !!!! ! ! !!! ", + " !! ! !! !!!!!! !!! ! !! !!! !! ! ", + " ! !!! !! !! ! ", + " ! !! ! ! !!! ", + " !! !!! ! !! !!! ! ", + " !! !!!!!!! !!!!! ! !! !!! !!! ", + " !!!!!!!!!! !!! !!!! ! ! ! !! ", + " !!! !!! ! ! ", + " ! !!! !! ", + " ! !!! !!! ", + " ! !!!! ", + " !!! ", + " ! ! ", + " ! ", + " ", + " ", + " ! !! ! !! ! ", + " !!!!!!!!!!!!!!!!!! !!!!!!!! !!!!!!!! !!!!!!!! ", + " !!!!!!!!!!!!!!!!!! !!!!!!!! !!!!!!!! !!!!!!!!! ", + " ! !!! ! ! ! !!! ! ! ! ! ! !! ", + " ! ! !!! !! ! !! ! ", + " ! !!!!!!!! !!!!!!!!!!!!!!!!! !!!!!!!!! ", + " !!!!!!!!!! !!!!!!!!!!!!!!!!! !!!!!!!!! ", + " !! ! ! ! ! ! ", + " !!!!!!!!!!!! !!!!!!! ", + " !!!!!!!!!!!! !!!!!!! ", + " ! ! ! ! ! !! ! ", + " ! ! ", + " !!!!!!!!! ", + " !!!!!!!!!! ", + " ! ! ! ", + " !!!!!!! ", + " !!!!!! ", + " !! ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + ] +} \ No newline at end of file diff --git a/tests/visual_tests/images/lines-multi-layout-1-800-800-1.0-agg-reference.png b/tests/visual_tests/images/lines-multi-layout-1-800-800-1.0-agg-reference.png new file mode 100644 index 000000000..b404d18ee Binary files /dev/null and b/tests/visual_tests/images/lines-multi-layout-1-800-800-1.0-agg-reference.png differ diff --git a/tests/visual_tests/images/lines-multi-layout-1-800-800-1.0-cairo-reference.png b/tests/visual_tests/images/lines-multi-layout-1-800-800-1.0-cairo-reference.png new file mode 100644 index 000000000..f67aff893 Binary files /dev/null and b/tests/visual_tests/images/lines-multi-layout-1-800-800-1.0-cairo-reference.png differ diff --git a/tests/visual_tests/images/lines-multi-layout-1-800-800-2.0-agg-reference.png b/tests/visual_tests/images/lines-multi-layout-1-800-800-2.0-agg-reference.png new file mode 100644 index 000000000..f11fa790d Binary files /dev/null and b/tests/visual_tests/images/lines-multi-layout-1-800-800-2.0-agg-reference.png differ diff --git a/tests/visual_tests/images/lines-multi-layout-1-800-800-2.0-cairo-reference.png b/tests/visual_tests/images/lines-multi-layout-1-800-800-2.0-cairo-reference.png new file mode 100644 index 000000000..4972c4031 Binary files /dev/null and b/tests/visual_tests/images/lines-multi-layout-1-800-800-2.0-cairo-reference.png differ diff --git a/tests/visual_tests/images/lines-multi-layout-2-800-800-1.0-agg-reference.png b/tests/visual_tests/images/lines-multi-layout-2-800-800-1.0-agg-reference.png new file mode 100644 index 000000000..f31122187 Binary files /dev/null and b/tests/visual_tests/images/lines-multi-layout-2-800-800-1.0-agg-reference.png differ diff --git a/tests/visual_tests/images/lines-multi-layout-2-800-800-1.0-cairo-reference.png b/tests/visual_tests/images/lines-multi-layout-2-800-800-1.0-cairo-reference.png new file mode 100644 index 000000000..16561ac94 Binary files /dev/null and b/tests/visual_tests/images/lines-multi-layout-2-800-800-1.0-cairo-reference.png differ diff --git a/tests/visual_tests/images/lines-multi-layout-2-800-800-2.0-agg-reference.png b/tests/visual_tests/images/lines-multi-layout-2-800-800-2.0-agg-reference.png new file mode 100644 index 000000000..ab7588155 Binary files /dev/null and b/tests/visual_tests/images/lines-multi-layout-2-800-800-2.0-agg-reference.png differ diff --git a/tests/visual_tests/images/lines-multi-layout-2-800-800-2.0-cairo-reference.png b/tests/visual_tests/images/lines-multi-layout-2-800-800-2.0-cairo-reference.png new file mode 100644 index 000000000..643ca1384 Binary files /dev/null and b/tests/visual_tests/images/lines-multi-layout-2-800-800-2.0-cairo-reference.png differ diff --git a/tests/visual_tests/images/lines-multi-layout-shield-800-800-1.0-agg-reference.png b/tests/visual_tests/images/lines-multi-layout-shield-800-800-1.0-agg-reference.png new file mode 100644 index 000000000..dc5a1af04 Binary files /dev/null and b/tests/visual_tests/images/lines-multi-layout-shield-800-800-1.0-agg-reference.png differ diff --git a/tests/visual_tests/images/lines-multi-layout-shield-800-800-1.0-cairo-reference.png b/tests/visual_tests/images/lines-multi-layout-shield-800-800-1.0-cairo-reference.png new file mode 100644 index 000000000..3ae3eb173 Binary files /dev/null and b/tests/visual_tests/images/lines-multi-layout-shield-800-800-1.0-cairo-reference.png differ diff --git a/tests/visual_tests/images/lines-multi-layout-shield-800-800-2.0-agg-reference.png b/tests/visual_tests/images/lines-multi-layout-shield-800-800-2.0-agg-reference.png new file mode 100644 index 000000000..7e2b733a0 Binary files /dev/null and b/tests/visual_tests/images/lines-multi-layout-shield-800-800-2.0-agg-reference.png differ diff --git a/tests/visual_tests/images/lines-multi-layout-shield-800-800-2.0-cairo-reference.png b/tests/visual_tests/images/lines-multi-layout-shield-800-800-2.0-cairo-reference.png new file mode 100644 index 000000000..ae89b493d Binary files /dev/null and b/tests/visual_tests/images/lines-multi-layout-shield-800-800-2.0-cairo-reference.png differ diff --git a/tests/visual_tests/images/text-multi-layout-1-512-512-1.0-agg-reference.png b/tests/visual_tests/images/text-multi-layout-1-512-512-1.0-agg-reference.png new file mode 100644 index 000000000..302e87fdc Binary files /dev/null and b/tests/visual_tests/images/text-multi-layout-1-512-512-1.0-agg-reference.png differ diff --git a/tests/visual_tests/images/text-multi-layout-1-512-512-1.0-cairo-reference.png b/tests/visual_tests/images/text-multi-layout-1-512-512-1.0-cairo-reference.png new file mode 100644 index 000000000..8f863d1c5 Binary files /dev/null and b/tests/visual_tests/images/text-multi-layout-1-512-512-1.0-cairo-reference.png differ diff --git a/tests/visual_tests/images/text-multi-layout-1-512-512-2.0-agg-reference.png b/tests/visual_tests/images/text-multi-layout-1-512-512-2.0-agg-reference.png new file mode 100644 index 000000000..ff3e98be4 Binary files /dev/null and b/tests/visual_tests/images/text-multi-layout-1-512-512-2.0-agg-reference.png differ diff --git a/tests/visual_tests/images/text-multi-layout-1-512-512-2.0-cairo-reference.png b/tests/visual_tests/images/text-multi-layout-1-512-512-2.0-cairo-reference.png new file mode 100644 index 000000000..883b19fc2 Binary files /dev/null and b/tests/visual_tests/images/text-multi-layout-1-512-512-2.0-cairo-reference.png differ diff --git a/tests/visual_tests/images/text-multi-layout-2-512-512-1.0-agg-reference.png b/tests/visual_tests/images/text-multi-layout-2-512-512-1.0-agg-reference.png new file mode 100644 index 000000000..d7e748485 Binary files /dev/null and b/tests/visual_tests/images/text-multi-layout-2-512-512-1.0-agg-reference.png differ diff --git a/tests/visual_tests/images/text-multi-layout-2-512-512-1.0-cairo-reference.png b/tests/visual_tests/images/text-multi-layout-2-512-512-1.0-cairo-reference.png new file mode 100644 index 000000000..b4a157794 Binary files /dev/null and b/tests/visual_tests/images/text-multi-layout-2-512-512-1.0-cairo-reference.png differ diff --git a/tests/visual_tests/images/text-multi-layout-2-512-512-2.0-agg-reference.png b/tests/visual_tests/images/text-multi-layout-2-512-512-2.0-agg-reference.png new file mode 100644 index 000000000..721d71715 Binary files /dev/null and b/tests/visual_tests/images/text-multi-layout-2-512-512-2.0-agg-reference.png differ diff --git a/tests/visual_tests/images/text-multi-layout-2-512-512-2.0-cairo-reference.png b/tests/visual_tests/images/text-multi-layout-2-512-512-2.0-cairo-reference.png new file mode 100644 index 000000000..05cb2de56 Binary files /dev/null and b/tests/visual_tests/images/text-multi-layout-2-512-512-2.0-cairo-reference.png differ diff --git a/tests/visual_tests/styles/lines-multi-layout-1.xml b/tests/visual_tests/styles/lines-multi-layout-1.xml new file mode 100644 index 000000000..7a8f8d890 --- /dev/null +++ b/tests/visual_tests/styles/lines-multi-layout-1.xml @@ -0,0 +1,34 @@ + + + + + + + lines + text + + csv + ../data/lines2.csv + + + + + + + + diff --git a/tests/visual_tests/styles/lines-multi-layout-2.xml b/tests/visual_tests/styles/lines-multi-layout-2.xml new file mode 100644 index 000000000..c09445744 --- /dev/null +++ b/tests/visual_tests/styles/lines-multi-layout-2.xml @@ -0,0 +1,33 @@ + + + + + + + lines + text + + csv + +wkt,nr +"LINESTRING(1.000 1.000, 0.958 0.646, 0.917 0.331, 0.875 0.055, 0.833 -0.185, 0.792 -0.390, 0.750 -0.562, 0.708 -0.703, 0.667 -0.815, 0.625 -0.898, 0.583 -0.956, 0.542 -0.989, 0.500 -1.000, 0.458 -0.990, 0.417 -0.961, 0.375 -0.914, 0.333 -0.852, 0.292 -0.776, 0.250 -0.688, 0.208 -0.589, 0.167 -0.481, 0.125 -0.367, 0.083 -0.248, 0.042 -0.125, 0.000 0.000, -0.042 0.125, -0.083 0.248, -0.125 0.367, -0.167 0.481, -0.208 0.589, -0.250 0.688, -0.292 0.776, -0.333 0.852, -0.375 0.914, -0.417 0.961, -0.458 0.990, -0.500 1.000, -0.542 0.989, -0.583 0.956, -0.625 0.898, -0.667 0.815, -0.708 0.703, -0.750 0.562, -0.792 0.390, -0.833 0.185, -0.875 -0.055, -0.917 -0.331, -0.958 -0.646, -1.000 -1.000)",1 + + + + + + + + + diff --git a/tests/visual_tests/styles/lines-multi-layout-shield.xml b/tests/visual_tests/styles/lines-multi-layout-shield.xml new file mode 100644 index 000000000..708cac234 --- /dev/null +++ b/tests/visual_tests/styles/lines-multi-layout-shield.xml @@ -0,0 +1,33 @@ + + + + + + + lines + text + + csv + ../data/lines.csv + + + + + + + + diff --git a/tests/visual_tests/styles/text-multi-layout-1.xml b/tests/visual_tests/styles/text-multi-layout-1.xml new file mode 100644 index 000000000..46cb7db7c --- /dev/null +++ b/tests/visual_tests/styles/text-multi-layout-1.xml @@ -0,0 +1,65 @@ + + + + + + obstacle + + csv + +lat,long,nr +-0.5,0.5,0 +0.5,-0.5,1 +0.5,0.5,2 +-0.5,-0.5,3 +0.08,0,4 +-0.08,0,5 + + + + + + + + points + + csv + +lat,long,nr,ref +-0.45,-0.45,0,first +0.45,-0.45,1,second +0.45,0.45,2,third +-0.45,0.45,3,fourth +0,0,4,fifth + + + + + + + + diff --git a/tests/visual_tests/styles/text-multi-layout-2.xml b/tests/visual_tests/styles/text-multi-layout-2.xml new file mode 100644 index 000000000..513dd729b --- /dev/null +++ b/tests/visual_tests/styles/text-multi-layout-2.xml @@ -0,0 +1,48 @@ + + + + + + points + + csv + +lat,long +0,0 + + + + + + + + diff --git a/tests/visual_tests/test.py b/tests/visual_tests/test.py index 7a984a463..4b1255580 100755 --- a/tests/visual_tests/test.py +++ b/tests/visual_tests/test.py @@ -3,6 +3,7 @@ import mapnik mapnik.logger.set_severity(mapnik.severity_type.None) +#mapnik.logger.set_severity(mapnik.severity_type.Debug) import shutil import sys @@ -96,6 +97,9 @@ files = { 'lines-5': {'sizes': sizes_few_square,'bbox':default_text_box}, 'lines-6': {'sizes': sizes_few_square,'bbox':default_text_box}, 'lines-7': {'sizes': sizes_few_square,'bbox':mapnik.Box2d(-1.2, -1.2, 1.2, 1.2)}, + 'lines-multi-layout-1': {'sizes': [(800,800)],'bbox':default_text_box}, + 'lines-multi-layout-2': {'sizes': [(800,800)],'bbox':mapnik.Box2d(-1.2, -1.2, 1.2, 1.2)}, + 'lines-multi-layout-shield': {'sizes': [(800,800)],'bbox':default_text_box}, 'lines-shield': {'sizes': sizes_few_square,'bbox':default_text_box}, 'collision': {'sizes':[(600,400)]}, 'shield-on-polygon': {'sizes':[(600,400)]}, @@ -156,6 +160,8 @@ files = { 'text-halign': {'sizes': [(800,800)], 'bbox': default_text_box}, 'text-malayalam': {'sizes': [(800, 100)], 'bbox': default_text_box}, 'text-bengali': {'sizes': [(800, 100)], 'bbox': default_text_box}, + 'text-multi-layout-1': {'sizes': [(512,512)], 'bbox':mapnik.Box2d(-1, -1, 1, 1)}, + 'text-multi-layout-2': {'sizes': [(512,512)], 'bbox':mapnik.Box2d(-1, -1, 1, 1)}, 'line-pattern-symbolizer': {'sizes':[(900, 250)],'bbox': mapnik.Box2d(-5.192, 50.189, -5.174, 50.195)}, 'tiff-alpha-gdal': {'sizes':[(600,400)]}, 'tiff-alpha-broken-assoc-alpha-gdal': {'sizes':[(600,400)]},