diff --git a/include/mapnik/marker_helpers.hpp b/include/mapnik/marker_helpers.hpp index 1f03b117b..96f857a8b 100644 --- a/include/mapnik/marker_helpers.hpp +++ b/include/mapnik/marker_helpers.hpp @@ -90,7 +90,8 @@ struct vector_markers_dispatch : util::noncopyable coord2d center = src_->bounding_box().center(); agg::trans_affine_translation recenter(-center.x, -center.y); agg::trans_affine tr = recenter * marker_trans_; - markers_placement_params params { src_->bounding_box(), tr, spacing * scale_factor_, max_error, allow_overlap, avoid_edges }; + direction_enum direction = get(sym_, feature_, vars_); + markers_placement_params params { src_->bounding_box(), tr, spacing * scale_factor_, max_error, allow_overlap, avoid_edges, direction }; markers_placement_finder placement_finder( placement_method, path, detector_, params); double x, y, angle = .0; @@ -147,7 +148,8 @@ struct raster_markers_dispatch : util::noncopyable value_double spacing = get(sym_, feature_, vars_); value_double max_error = get(sym_, feature_, vars_); box2d bbox(0,0, src_.width(),src_.height()); - markers_placement_params params { bbox, marker_trans_, spacing * scale_factor_, max_error, allow_overlap, avoid_edges }; + direction_enum direction = get(sym_, feature_, vars_); + markers_placement_params params { bbox, marker_trans_, spacing * scale_factor_, max_error, allow_overlap, avoid_edges, direction }; markers_placement_finder placement_finder( placement_method, path, detector_, params); double x, y, angle = .0; diff --git a/include/mapnik/markers_placements/line.hpp b/include/mapnik/markers_placements/line.hpp index 24bb229ec..9b9035e5c 100644 --- a/include/mapnik/markers_placements/line.hpp +++ b/include/mapnik/markers_placements/line.hpp @@ -97,6 +97,10 @@ public: x = pos.x; y = pos.y; angle = path_.current_segment_angle(); + if (!this->set_direction(angle)) + { + continue; + } box2d box = this->perform_transform(angle, x, y); if ((this->params_.avoid_edges && !this->detector_.extent().contains(box)) || (!this->params_.allow_overlap && !this->detector_.has_placement(box))) diff --git a/include/mapnik/markers_placements/point.hpp b/include/mapnik/markers_placements/point.hpp index 3ca1ce5c8..89bc005e5 100644 --- a/include/mapnik/markers_placements/point.hpp +++ b/include/mapnik/markers_placements/point.hpp @@ -24,6 +24,7 @@ #define MAPNIK_MARKERS_PLACEMENTS_POINT_HPP #include +#include #include "agg_basics.h" #include "agg_trans_affine.h" @@ -38,6 +39,7 @@ struct markers_placement_params double max_error; bool allow_overlap; bool avoid_edges; + direction_enum direction; }; template @@ -141,6 +143,36 @@ protected: result.expand_to_include(xD, yD); return result; } + + bool set_direction(double & angle) + { + switch (params_.direction) + { + case DIRECTION_UP: + angle = .0; + return true; + case DIRECTION_DOWN: + angle = M_PI; + return true; + case DIRECTION_AUTO: + angle = (std::fabs(util::normalize_angle(angle)) > 0.5 * M_PI) ? (angle + M_PI) : angle; + return true; + case DIRECTION_AUTO_DOWN: + angle = (std::fabs(util::normalize_angle(angle)) < 0.5 * M_PI) ? (angle + M_PI) : angle; + return true; + case DIRECTION_LEFT: + angle += M_PI; + return true; + case DIRECTION_LEFT_ONLY: + angle += M_PI; + return std::fabs(util::normalize_angle(angle)) < 0.5 * M_PI; + case DIRECTION_RIGHT_ONLY: + return std::fabs(util::normalize_angle(angle)) < 0.5 * M_PI; + case DIRECTION_RIGHT: + default: + return true; + } + } }; } diff --git a/include/mapnik/markers_placements/vertext_first.hpp b/include/mapnik/markers_placements/vertext_first.hpp index 9f142e160..7f6fada94 100644 --- a/include/mapnik/markers_placements/vertext_first.hpp +++ b/include/mapnik/markers_placements/vertext_first.hpp @@ -69,6 +69,10 @@ public: if (agg::is_line_to(this->locator_.vertex(&x1, &y1))) { angle = std::atan2(y1 - y0, x1 - x0); + if (!this->set_direction(angle)) + { + return false; + } } box2d box = this->perform_transform(angle, x, y); diff --git a/include/mapnik/markers_placements/vertext_last.hpp b/include/mapnik/markers_placements/vertext_last.hpp index 456687003..1c85c95b3 100644 --- a/include/mapnik/markers_placements/vertext_last.hpp +++ b/include/mapnik/markers_placements/vertext_last.hpp @@ -74,6 +74,10 @@ public: if (agg::is_line_to(command1)) { angle = std::atan2(y0 - y1, x0 - x1); + if (!this->set_direction(angle)) + { + return false; + } } box2d box = this->perform_transform(angle, x, y); diff --git a/include/mapnik/symbolizer.hpp b/include/mapnik/symbolizer.hpp index d15c1e10e..8a4745acd 100644 --- a/include/mapnik/symbolizer.hpp +++ b/include/mapnik/symbolizer.hpp @@ -91,6 +91,7 @@ enum class property_types : std::uint8_t target_justify_alignment, target_vertical_alignment, target_upright, + target_direction, target_font_feature_settings }; @@ -184,6 +185,7 @@ ENUM_FROM_STRING( horizontal_alignment_enum ) ENUM_FROM_STRING( justify_alignment_enum ) ENUM_FROM_STRING( text_transform_enum ) ENUM_FROM_STRING( text_upright_enum ) +ENUM_FROM_STRING( direction_enum ) ENUM_FROM_STRING( gamma_method_enum ) // enum diff --git a/include/mapnik/symbolizer_default_values.hpp b/include/mapnik/symbolizer_default_values.hpp index 8816d7c18..c793acbde 100644 --- a/include/mapnik/symbolizer_default_values.hpp +++ b/include/mapnik/symbolizer_default_values.hpp @@ -329,6 +329,13 @@ struct symbolizer_default static marker_multi_policy_enum value() { return MARKER_EACH_MULTI; } }; +// direction +template <> +struct symbolizer_default +{ + static direction_enum value() { return DIRECTION_RIGHT; } +}; + // placement // colorizer diff --git a/include/mapnik/symbolizer_enumerations.hpp b/include/mapnik/symbolizer_enumerations.hpp index 7f1c556c4..beca46835 100644 --- a/include/mapnik/symbolizer_enumerations.hpp +++ b/include/mapnik/symbolizer_enumerations.hpp @@ -189,6 +189,21 @@ enum text_upright_enum : std::uint8_t DEFINE_ENUM(text_upright_e, text_upright_enum); +enum direction_enum : std::uint8_t +{ + DIRECTION_LEFT, + DIRECTION_RIGHT, + DIRECTION_LEFT_ONLY, + DIRECTION_RIGHT_ONLY, + DIRECTION_AUTO, + DIRECTION_AUTO_DOWN, + DIRECTION_UP, + DIRECTION_DOWN, + direction_enum_MAX +}; + +DEFINE_ENUM(direction_e, direction_enum); + enum gamma_method_enum : std::uint8_t { GAMMA_POWER, //agg::gamma_power diff --git a/include/mapnik/symbolizer_keys.hpp b/include/mapnik/symbolizer_keys.hpp index 4867d3764..ec8649da5 100644 --- a/include/mapnik/symbolizer_keys.hpp +++ b/include/mapnik/symbolizer_keys.hpp @@ -89,6 +89,7 @@ enum class keys : std::uint8_t justify_alignment, vertical_alignment, upright, + direction, avoid_edges, ff_settings, MAX_SYMBOLIZER_KEY diff --git a/include/mapnik/util/math.hpp b/include/mapnik/util/math.hpp new file mode 100644 index 000000000..4b24893b1 --- /dev/null +++ b/include/mapnik/util/math.hpp @@ -0,0 +1,35 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2015 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 MAPNIK_MATH_HPP +#define MAPNIK_MATH_HPP + +#include + +namespace mapnik { namespace util { + +MAPNIK_DECL double normalize_angle(double angle); + +}} + +#endif + diff --git a/src/build.py b/src/build.py index 5311d6068..865293711 100644 --- a/src/build.py +++ b/src/build.py @@ -243,6 +243,7 @@ source = Split( renderer_common.cpp renderer_common/render_pattern.cpp renderer_common/process_group_symbolizer.cpp + math.cpp """ ) diff --git a/src/load_map.cpp b/src/load_map.cpp index 25cf3f34b..f6cce8a43 100644 --- a/src/load_map.cpp +++ b/src/load_map.cpp @@ -995,6 +995,7 @@ void map_parser::parse_markers_symbolizer(rule & rule, xml_node const& node) set_symbolizer_property(sym, keys::image_transform, node); set_symbolizer_property(sym, keys::markers_placement_type, node); set_symbolizer_property(sym, keys::markers_multipolicy, node); + set_symbolizer_property(sym, keys::direction, node); parse_stroke(sym,node); rule.append(std::move(sym)); } diff --git a/src/math.cpp b/src/math.cpp new file mode 100644 index 000000000..b27431343 --- /dev/null +++ b/src/math.cpp @@ -0,0 +1,48 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2015 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 + +// stl +#include + +namespace mapnik { + +namespace util { + + double normalize_angle(double angle) + { + while (angle >= M_PI) + { + angle -= 2.0 * M_PI; + } + while (angle < -M_PI) + { + angle += 2.0 * M_PI; + } + return angle; + } + +} // end namespace util + +} // end namespace mapnik diff --git a/src/symbolizer_enumerations.cpp b/src/symbolizer_enumerations.cpp index dfa91860d..f2a580237 100644 --- a/src/symbolizer_enumerations.cpp +++ b/src/symbolizer_enumerations.cpp @@ -177,6 +177,19 @@ static const char * text_upright_strings[] = { }; IMPLEMENT_ENUM(text_upright_e, text_upright_strings) +static const char * direction_strings[] = { + "left", + "right", + "left-only", + "right-only", + "auto", + "auto-down", + "up", + "down", + "" +}; +IMPLEMENT_ENUM(direction_e, direction_strings) + static const char * gamma_method_strings[] = { "power", //agg::gamma_power "linear", //agg::gamma_linear diff --git a/src/symbolizer_keys.cpp b/src/symbolizer_keys.cpp index ac974a34b..099832df9 100644 --- a/src/symbolizer_keys.cpp +++ b/src/symbolizer_keys.cpp @@ -153,6 +153,9 @@ static const property_meta_type key_meta[const_max_key] = property_meta_type{ "upright", [](enumeration_wrapper e) {return enumeration(text_upright_enum(e.value)).as_string();}, property_types::target_upright}, + property_meta_type{ "direction", [](enumeration_wrapper e) + {return enumeration(direction_enum(e.value)).as_string();}, + property_types::target_direction}, property_meta_type{ "avoid-edges",nullptr, property_types::target_bool }, property_meta_type{ "font-feature-settings", nullptr, property_types::target_font_feature_settings }, diff --git a/src/text/placement_finder.cpp b/src/text/placement_finder.cpp index 2c3b5a806..4a85bba1d 100644 --- a/src/text/placement_finder.cpp +++ b/src/text/placement_finder.cpp @@ -30,6 +30,7 @@ #include #include #include +#include // agg #include "agg_conv_clip_polyline.h" @@ -95,11 +96,11 @@ text_upright_e placement_finder::simplify_upright(text_upright_e upright, double { if (upright == UPRIGHT_AUTO) { - return (std::fabs(normalize_angle(angle)) > 0.5*M_PI) ? UPRIGHT_LEFT : UPRIGHT_RIGHT; + return (std::fabs(util::normalize_angle(angle)) > 0.5*M_PI) ? UPRIGHT_LEFT : UPRIGHT_RIGHT; } if (upright == UPRIGHT_AUTO_DOWN) { - return (std::fabs(normalize_angle(angle)) < 0.5*M_PI) ? UPRIGHT_LEFT : UPRIGHT_RIGHT; + return (std::fabs(util::normalize_angle(angle)) < 0.5*M_PI) ? UPRIGHT_LEFT : UPRIGHT_RIGHT; } if (upright == UPRIGHT_LEFT_ONLY) { @@ -260,10 +261,12 @@ bool placement_finder::single_line_placement(vertex_cache &pp, text_upright_e or } current_cluster = glyph.char_index; // Only calculate new angle at the start of each cluster! - angle = normalize_angle(off_pp.angle(sign * layout.cluster_width(current_cluster))); + // Y axis is inverted. + // See note about coordinate systems in placement_finder::find_point_placement(). + angle = -util::normalize_angle(off_pp.angle(sign * layout.cluster_width(current_cluster))); rot.init(angle); if ((text_props_->max_char_angle_delta > 0) && (last_cluster_angle != 999) && - std::fabs(normalize_angle(angle-last_cluster_angle)) > text_props_->max_char_angle_delta) + std::fabs(util::normalize_angle(angle - last_cluster_angle)) > text_props_->max_char_angle_delta) { return false; } @@ -328,21 +331,6 @@ void placement_finder::path_move_dx(vertex_cache & pp, double dx) if (!pp.move(dx)) pp.restore_state(state); } -double placement_finder::normalize_angle(double angle) -{ - while (angle >= M_PI) - { - angle -= 2.0 * M_PI; - } - while (angle < -M_PI) - { - angle += 2.0 * M_PI; - } - // y axis is inverted. - // See note about coordinate systems in placement_finder::find_point_placement(). - return -angle; -} - double placement_finder::get_spacing(double path_length, double layout_width) const { int num_labels = 1; diff --git a/src/xml_tree.cpp b/src/xml_tree.cpp index e46f6a4f2..410a2bcf0 100644 --- a/src/xml_tree.cpp +++ b/src/xml_tree.cpp @@ -427,6 +427,7 @@ compile_get_opt_attr(vertical_alignment_e); compile_get_opt_attr(horizontal_alignment_e); compile_get_opt_attr(justify_alignment_e); compile_get_opt_attr(text_upright_e); +compile_get_opt_attr(direction_e); compile_get_opt_attr(halo_rasterizer_e); compile_get_opt_attr(expression_ptr); compile_get_opt_attr(font_feature_settings); diff --git a/tests/visual_tests/grids/marker-direction-1152-384-1.0-grid-reference.json b/tests/visual_tests/grids/marker-direction-1152-384-1.0-grid-reference.json new file mode 100644 index 000000000..c9ec04180 --- /dev/null +++ b/tests/visual_tests/grids/marker-direction-1152-384-1.0-grid-reference.json @@ -0,0 +1,131 @@ +{ + "keys": [ + "", + "4", + "1", + "2", + "3", + "5", + "6", + "7", + "8", + "9", + "10", + "11", + "12", + "13", + "14", + "15", + "16", + "17", + "18", + "19", + "20", + "21", + "22", + "23", + "24", + "25", + "26", + "27" + ], + "data": {}, + "grid": [ + " ", + " ", + " ", + " ", + " !!! ", + " # $ % !!! & ' ( ) * ", + " # # # # $ $$$ % % !!! & &&& ' ' ' ' ( (( ((( )))) ))) * *** ", + " #### #### $$$ $$$$ % % ! !!! &&& &&&& '''' '''' ((( ((( )) )) *** **** ", + " ##### ### $$$ $$$$ % % ! ! &&& &&&& ''''' ''' (((( ((( ))) ))))) *** **** ", + " ### #### $$$$ $$ $ % % ! ! !!! &&&& && & ''' '''' (( ((( ))) )))) **** ** * ", + " # # # $ $ $ % % !!!! !!!! & & & ' ' ' (((( ( )))) ) * * * ", + " # # # $ $ $ % % !!!! !!!! & & & ' ' ' ( ((( ) ))) * * * ", + " #### #### $$$ $$$ % % !!!! ! ! &&& &&& '''' '''' ((( ((( ))) )) *** *** ", + " #### #### $$$ $$$ % % ! ! &&& &&& '''' '''' ((((( (( )) )) ) *** *** ", + " #### #### $$$$ $$ $ % % ! ! ! &&&& && & '''' '''' (( ((( ))) ))) **** ** * ", + " # # # # # $ $$ $ $ $ % % % !!!! ! ! & && & & ' ' ' ' ' (((( (( ( )))) ) ) * ** * * * * ", + " # ### # $ $$$$ $ % %%% % %% % % !!!! !!!! !!!! ! & &&& & ' ''' ''' '' ' ' ( (( ( ) )))) ) * ** ** * ", + " #### ### $ $ $ $ $ %%%% %%% !!! ! ! &&&& &&& ' ' ' ' ' ' (((( ( ((( )))) ) ))) * * * * *** * * * ", + " #### ### $$$$ $$$$ %%%% %%% !! ! &&&& &&& '''' '''' ((( ((( ))) )) **** **** ", + " #### #### $$$$ $$$$ %%%% %%%% ! ! &&&& &&&& '''' '''' (( (( ))))) )))) **** **** ", + " # # ## # $$$ $$$$ % % %% % ! ! & & && & ''' '''' ((( (((( ))) )))) *** **** ", + " # # $ $ % % ! ! & & ' ' ( ( ) ) * * ", + " ## # # # $ $ $ $ %% % % % ! ! && & & & ' ' ' ' (((( ((( )))) ))) * * * * ", + " #### ### $ $$ $$$$ %%%% %%% ! ! &&&& &&& ' '' '''' ((( ((( ))) )) * ** **** ", + " #### ### $$$ $$$ %%%% %%% ! ! &&&& &&& ''' ''' ((( ((( )))) ))))) *** *** ", + " #### #### $$$ $$$$ %%%% %%%% ! ! &&&& &&&& ''' '''' (( ((( ))) )))) *** **** ", + " # ## # $ $$ $ % %% % !! & && & ' '' ' (((( (( ))) * ** * ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " + , - . / 0 1 2 3 ", + " + + , , - - . . / / 0 0 1 1 2 2 3 3 ", + " + + , , - - . . / / 0 0 1 1 2 2 3 3 ", + " + + , , - - . . / / 0 0 1 1 2 2 3 3 ", + " + + , , - - . . / / 0 0 1 1 2 2 3 3 ", + " + + , , - - . . / / 0 0 1 1 2 2 3 3 ", + " + + , , - - . . / / 0 0 1 1 2 2 3 3 ", + " + + , , - - . . / / 0 0 1 1 2 2 3 3 ", + " + + , , - - . . / / 0 0 1 1 2 2 3 3 ", + " + ++ + , ,, - -- - . . / // / 0 00 1 111 2 222 3 33 ", + " + + +++ , , ,, , - - --- . . . / /// 0 0 00 0 1 1111 2 22 3 3 3 33 3 ", + " + +++ +++ , ,,,, ,,, - --- - -- - --- . .... .... . / /// /// 0 000 000 00 0 000 1 11 111 2 2222 22222 3 33 33 333 ", + " + ++++ , , ,,,, - ---- . . . / //// 0 0 0 0000 1 1 111 2 2 2222 3 3 3 333 3 3333 ", + " + + + , , , - - - . . / / / 0 0 0 1 1 11 2 2 3 3 3 ", + " + + , , - - . . / / 0 0 1 1 2 2 3 3 ", + " + + , , - - . . / / 0 0 1 1 2 2 3 3 ", + " + + , , - - . . / / 0 0 1 1 2 2 3 3 ", + " + + , , - - . . / / 0 0 1 1 2 2 3 3 ", + " + + , , - - . . / / 0 0 1 1 2 2 3 3 ", + " + + , , - - . . / / 0 0 1 1 2 2 3 3 ", + " + + , , - - . . / / 0 0 1 1 2 2 3 3 ", + " ++ ,, -- .. // 00 11 22 33 ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " 4 5 6 7 8 9 : ; < ", + " 4 4 5 5 6 6 7 7 8 8 9 9 : : ; ; < < ", + " 4 4 5 5 6 6 7 7 8 8 9 9 : : ; ; < < ", + " 4 4 5 5 6 6 7 7 8 8 9 9 : : ; ; < < ", + " 4 4 5 5 6 6 7 7 8 8 9 9 : : ; ; < < ", + " 4 4 5 5 6 6 7 7 8 8 9 9 : : ; ; < < ", + " 4 4 5 5 6 6 7 7 8 8 9 9 : : ; ; < < ", + " 4 4 5 5 6 6 7 7 8 8 9 9 : : ; ; < < ", + " 4 4 5 5 6 6 7 7 8 8 9 9 : : ; ; < < ", + " 4 4 4 5 5 5 6 6 7 7 7 8 8 8 9 9 9 : ::: ; ;;; < < < ", + " 4 4 4444 5 5 555 6 6 6 7 7 777 8 888 9 9 9999 : :::: ; ;; < < < <<< ", + " 4 444 444 5 5555 5555 6 666 6 66 6 6 7 7777 7777 7777 8 888 8888 9 999 999 99 9 999 : :: ::: ; ;;;; ;;;;; < << << <<<< ", + " 4 444 5 5 55 5 6 6 7 7 77 7 8 88 8 9 9 9 999 : : ::: ; ; ;;;; < < < <<< < << < ", + " 4 4 4 5 5 5 6 6 7 7 7 8 8 8 9 9 9 : : :: ; ; < < < ", + " 4 4 5 5 6 6 7 7 8 8 9 9 : : ; ; < < ", + " 4 4 5 5 6 6 7 7 8 8 9 9 : : ; ; < < ", + " 4 4 5 5 6 6 7 7 8 8 9 9 : : ; ; < < ", + " 4 4 5 5 6 6 7 7 8 8 9 9 : : ; ; < < ", + " 4 4 5 5 6 6 7 7 8 8 9 9 : : ; ; < < ", + " 4 4 5 5 6 6 7 7 8 8 9 9 : : ; ; < < ", + " 4 4 5 5 6 6 7 7 8 8 9 9 : : ; ; < < ", + " 44 55 66 77 88 99 :: ;; << ", + " ", + " ", + " ", + " ", + " " + ] +} \ No newline at end of file diff --git a/tests/visual_tests/grids/marker-direction-1152-384-2.0-grid-reference.json b/tests/visual_tests/grids/marker-direction-1152-384-2.0-grid-reference.json new file mode 100644 index 000000000..f52a7ac11 --- /dev/null +++ b/tests/visual_tests/grids/marker-direction-1152-384-2.0-grid-reference.json @@ -0,0 +1,131 @@ +{ + "keys": [ + "", + "4", + "1", + "2", + "3", + "5", + "6", + "7", + "8", + "9", + "10", + "11", + "12", + "13", + "14", + "15", + "16", + "17", + "18", + "19", + "20", + "21", + "22", + "23", + "24", + "25", + "26", + "27" + ], + "data": {}, + "grid": [ + " ", + " ", + " !!! ! ", + " !!!!! ", + " !!!!!! ", + " # $ % !!!!! & ' ( ) * ", + " # # # $ $ $ % % !!!!!!!! & & & ' ' ' ( ( ) ) ) * * * ", + " ### # # ## $$ $$ $ $$$ % % !! !!!! && && & &&& ''' ' ' '' ((((( ( (((((( ))))) ) )))))) ** ** * *** ", + " ### #### ## ### $$$$$$ $$$$$$ % % !!!! !!! &&&&&& &&&&&& ''' '''' '' ''' (((((( ((((( )))))) )))) ****** ****** ", + " #### ## ####### $$$$$$ $$$$$$$ % % ! !!! ! &&&&&& &&&&&&& '''' '' ''''''' (((((( ((((( ))) )))) ****** ******* ", + " ######## ###### # $$$$$$ $$$$$$ % % ! ! &&&&&& &&&&&& '''''''' '''''' ' (((((((((( ( ((((( ( )) ) ))) ) ****** ****** ", + " ##### ####### $$$$$$ $ $$$$$$$$ % % ! ! &&&&&& & &&&&&&&& ''''' ''''''' (((( ( ((( )))))))))) ))))))))) ****** * ******** ", + " ####### ####### $$ $$$$ $$$$$ $ % % !! !! ! && &&&& &&&&& & ''''''' ''''''' (((( ((((( )))))) ))))) ** **** ***** * ", + " ###### ###### $$$$$$$$ $$$ $ % % !!!!!! ! &&&&&&&& &&& & '''''' '''''' ( (( (((((( )))))) )))))) ******** *** * ", + " ## ### # ## ## $ $$$ $$$ $ % % % % % !!!!!! ! ! ! & &&& && & & '' ''' '' '' ' ((((((( ((((( ( )))))) )))))) ) * *** ** * ", + " # # # # #### # $ $ $$$ $$ $$ $ % % % %%%% %% %% %%!%!!! !!! !! !! ! !! ! !!&! & && & &&&&&& ' ' '' ' ''' '' '' ' ' '' ''(( ( ((( ( ) )) ) ) ))) * * * * * * ", + " # ## # # # $ $ $$ $ $ $ % %% % % % %% %% !%!!!! ! !! ! ! ! ! !! ! && & && & & ' ' ' '' ' ' ' '' ''''' ' ( (( ( ( ) ) )) )))))) ) * * * ** ** ** * *", + " # # ## # # ## $ $$ $ $$$$ $$$ % % %% % % %% %% %% %!!!!!!! ! !! ! !! ! ! ! & && &&&& &&& ' '' ' '''' ''' ' '' ' ''' ' ( (( ( (( ) )) ) ))))))))) ) * ** * * ******* * *", + " ## ### #### ## $ $$$ $$$ $$ %% %%% %%%% %% % !!!!!! ! !! !&& &&& &&&& && ' ''' '' '' ' ' ( ((((( ((((((( ))))))) ))))))) * *** * ********** ***", + " ###### ####### $ $$$ $$$$$$$ %%%%%% %%%%%%% !!! !! &&&&&& &&&&&&& ' ''' ''''''' (((((( (((((( ) )) ))))) * *** ******* ", + " ####### ####### $$$$$$$ $$$$$$$$ %%%%%%% %%%%%%% ! ! !! &&&&&&& &&&&&&& ''''''' '''''''' (((((( (((((( ))))) )))) ******* ******** ", + " # ##### ##### $$$$$$ $ $$$$$$ % %%%%% %%%%% ! !! & &&&&& &&&&& '''''' ' '''''' (((((((( ( ( ((((( ( )))) )))) ****** * ****** ", + " ######## ######## $$$$$$$ $$$$$$ %%%%%%%% %%%%%%%% ! !! &&&&&&&& &&&&&&&& ''''''' '''''' ( (( (((( )))))))))) ))))))))) ******* ****** ", + " #### ## ####### $$$$$$$ $$$$$$ %%%% %% %%%%%%% ! !! &&&& && &&&&&&& ''''''' '''''' (((( (((( )))))) )))))) ******* ****** ", + " ### ## ## ### $$$$$$ $$$$$$ %%% %% %% %%% ! !! &&& && && &&& '''''' '''''' ((((( (((((( )))))) )))))) ****** ****** ", + " ## # ## ## $$$ $ $$ $$ %% % %% %% ! !! && & && && ''' ' '' '' (((((( ((((((( )))))) ))))))) *** * ** ** ", + " ### $$$ %%% !!! &&& ''' ((( ))) *** ", + " # $ % ! & ' ( ) * ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " + , - . / 0 1 2 3 ", + " + + , , - - . . / / 0 0 1 1 2 2 3 3 ", + " + + , , - - . . / / 0 0 1 1 2 2 3 3 ", + " + + , , - - . . / / 0 0 1 1 2 2 3 3 ", + " + + , , - - . . / / 0 0 1 1 2 2 3 3 ", + " + + , , - - . . / / 0 0 1 1 2 2 3 3 ", + " + + , , - - . . / / 0 0 1 1 2 2 3 3 ", + " + + ++ , , ,, - - -- . . / / // 0 0 00 1 111111 2 2 2222 3 3 33 ", + " + ++++ + , ,,, , , - ---- - . . / //// / 0 000 0 0 1 111111 2 222222 3 333 3 3 ", + " + + + +++++ , , ,,,,, , - - - ----- - . . . . / / ///// 0 00000 0 0 1 111111 2 2 222 3 33333 3 ", + " + + + +++++++++ , ,,, ,, ,,,,,,, - - - ----------- -- - . ... .. .. . .. . ../. // / //////// 0 00 0 00000000000 0 0 00 00 1 111 111111 2 22 2 2 222 2 3 3 3 3333333 ", + " + ++ + +++++++ , , ,, , ,,,,,,, - -- - -------- -- - . . .. . . . . .. . // / //////// 0 0 0 00 000000000 00000 0 1 11 1 1111 2 2 22 222222222 2 3 3 3 33 333333333", + " + ++ + +++++++ , , ,, , ,,,,,,,, - -- - --------- - . . .. . .. . . . // / // /////// 0 0 0 00 000000000 0 000 0 1 11 1 1111 2 2 22 2 2222222 3 3 3 333333333333", + " + +++++++ , , ,,,,,, - ------- - . . .. ./ /////// 0 0000000 0 1 1 1111 2 2 222222 3 3 33333333333333", + " + ++ +++ , ,, ,,, - -- --- . .. / // /// 0 00 000 1 1111111 2 2222222 3 33 333 ", + " + ++ ++ , ,, , - -- -- . .. / // // 0 00 0 1 11 1111 2 22 2 2 3 33 3 ", + " + ++ , ,, - -- . .. / // 0 00 1 11 2 22 3 33 ", + " + ++ , ,, - -- . .. / // 0 00 1 11 2 22 3 33 ", + " + ++ , ,, - -- . .. / // 0 00 1 11 2 22 3 33 ", + " + ++ , ,, - -- . .. / // 0 00 1 11 2 22 3 33 ", + " + ++ , ,, - -- . .. / // 0 00 1 11 2 22 3 33 ", + " +++ ,,, --- ... /// 000 111 222 333 ", + " + , - . / 0 1 2 3 ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " 4 5 6 7 8 9 : ; < ", + " 4 4 5 5 6 6 7 7 8 8 9 9 : : ; ; < < ", + " 4 4 5 5 6 6 7 7 8 8 9 9 : : ; ; < < ", + " 4 4 5 5 6 6 7 7 8 8 9 9 : : ; ; < < ", + " 4 4 5 5 6 6 7 7 8 8 9 9 : : ; ; < < ", + " 4 4 5 5 6 6 7 7 8 8 9 9 : : ; ; < < ", + " 4 4 5 5 6 6 7 7 8 8 9 9 : : ; ; < < ", + " 4 4 44 5 5 55 6 6 7 7 77 8 8 88 9 9 99 : :::::: ; ; ;;;; < < << ", + " 4 44 44 5 5 5555 6 6 7 7 7777 8 8 8888 9 99 99 : :::::: ; ;;;;;; < < <<<< ", + " 4 4 4 44 4444 5 5 5555555 6 6 6 6 6 7 7 7777777 7 8 8 8888888 9 99 99999 : :::::: ; ; ;;; < <<<<<<< ", + " 4 4 4 44444444444 5 555 55 55 55555 6 6 6 6666 66 66 66 6 7 777 77 77 777777 7 7787 88 8 8888888888 9 99 9 99999999999 9 9 99 99 : ::: :::::: ; ;; ; ; ;;; ; < < < < <<<<< ", + " 4 44 4 44444444 5 5 55 5 5555555 6 66 6 6 6 66 66 6 7 7 77 7 77777777 77 7 88 8 88 8888888 9 9 9 999999999 99 99999 9 : :: : :::: ; ; ;; ;;;;;;;;; ; < < < << <<<<<<<<<", + " 4 44 44444444 5 5 55 5 5555555 6 66 6 66 66 66 6 7 7 77 7 7777777 7 7 7 88 8 888888888 9 9 9 999999999 99 9 999 9 : :: : :::: ; ; ;; ; ;;;;;;; < < < <<<<<<<<<< <", + " 4 44444 5 5 5555 6 66 6 7 7 7777 78 8888 9 99999 9 9 : : :::: ; ; ;;;;;; < < <<<<<<<<<< <<<", + " 4 44444 4 5 5555 5 6 66 7 7777 7 8 8888 8 9 99999 9 : ::::::: ; ;;;;;;; < <<<< < ", + " 4 44 44 5 55 55 6 66 7 77 77 8 88 88 9 99 99 : :: :::: ; ;; ; ; < << << ", + " 4 44 5 55 6 66 7 77 8 88 9 99 : :: ; ;; < << ", + " 4 44 5 55 6 66 7 77 8 88 9 99 : :: ; ;; < << ", + " 4 44 5 55 6 66 7 77 8 88 9 99 : :: ; ;; < << ", + " 4 44 5 55 6 66 7 77 8 88 9 99 : :: ; ;; < << ", + " 4 44 5 55 6 66 7 77 8 88 9 99 : :: ; ;; < << ", + " 444 555 666 777 888 999 ::: ;;; <<< ", + " 4 5 6 7 8 9 : ; < ", + " ", + " ", + " ", + " " + ] +} \ No newline at end of file diff --git a/tests/visual_tests/images/marker-direction-1152-384-1.0-agg-reference.png b/tests/visual_tests/images/marker-direction-1152-384-1.0-agg-reference.png new file mode 100644 index 000000000..7303e4c8a Binary files /dev/null and b/tests/visual_tests/images/marker-direction-1152-384-1.0-agg-reference.png differ diff --git a/tests/visual_tests/images/marker-direction-1152-384-1.0-cairo-reference.png b/tests/visual_tests/images/marker-direction-1152-384-1.0-cairo-reference.png new file mode 100644 index 000000000..72624d289 Binary files /dev/null and b/tests/visual_tests/images/marker-direction-1152-384-1.0-cairo-reference.png differ diff --git a/tests/visual_tests/images/marker-direction-1152-384-2.0-agg-reference.png b/tests/visual_tests/images/marker-direction-1152-384-2.0-agg-reference.png new file mode 100644 index 000000000..dcd81dad3 Binary files /dev/null and b/tests/visual_tests/images/marker-direction-1152-384-2.0-agg-reference.png differ diff --git a/tests/visual_tests/images/marker-direction-1152-384-2.0-cairo-reference.png b/tests/visual_tests/images/marker-direction-1152-384-2.0-cairo-reference.png new file mode 100644 index 000000000..fc2f6cd90 Binary files /dev/null and b/tests/visual_tests/images/marker-direction-1152-384-2.0-cairo-reference.png differ diff --git a/tests/visual_tests/styles/marker-direction.xml b/tests/visual_tests/styles/marker-direction.xml new file mode 100644 index 000000000..8a70db890 --- /dev/null +++ b/tests/visual_tests/styles/marker-direction.xml @@ -0,0 +1,88 @@ + + + + + 1152,384 + + + + + + line + markers + text + + csv + -1.5, -7.5, 25.5, 1.5 + + id, wkt, placement, direction + 0, "LINESTRING( 1 0, 0 -1, -1 0, 0 1, 1 0)", "line", "left" + 1, "LINESTRING( 4 0, 3 -1, 2 0, 3 1, 4 0)", "line", "right" + 2, "LINESTRING( 7 0, 6 -1, 5 0, 6 1, 7 0)", "line", "left-only" + 3, "LINESTRING(10 0, 9 -1, 8 0, 9 1, 10 0)", "line", "right-only" + 4, "LINESTRING(13 0, 12 -1, 11 0, 12 1, 13 0)", "line", "auto" + 5, "LINESTRING(16 0, 15 -1, 14 0, 15 1, 16 0)", "line", "auto-down" + 6, "LINESTRING(19 0, 18 -1, 17 0, 18 1, 19 0)", "line", "up" + 7, "LINESTRING(22 0, 21 -1, 20 0, 21 1, 22 0)", "line", "down" + 8, "LINESTRING(25 0, 24 -1, 23 0, 24 1, 25 0)", "line", "[default]" + 9, "LINESTRING( 1 -3, 0 -4, -1 -3, 0 -2, 1 -3)", "vertex-first", "left" + 10, "LINESTRING( 4 -3, 3 -4, 2 -3, 3 -2, 4 -3)", "vertex-first", "right" + 11, "LINESTRING( 7 -3, 6 -4, 5 -3, 6 -2, 7 -3)", "vertex-first", "left-only" + 12, "LINESTRING(10 -3, 9 -4, 8 -3, 9 -2, 10 -3)", "vertex-first", "right-only" + 13, "LINESTRING(13 -3, 12 -4, 11 -3, 12 -2, 13 -3)", "vertex-first", "auto" + 14, "LINESTRING(16 -3, 15 -4, 14 -3, 15 -2, 16 -3)", "vertex-first", "auto-down" + 15, "LINESTRING(19 -3, 18 -4, 17 -3, 18 -2, 19 -3)", "vertex-first", "up" + 16, "LINESTRING(22 -3, 21 -4, 20 -3, 21 -2, 22 -3)", "vertex-first", "down" + 17, "LINESTRING(25 -3, 24 -4, 23 -3, 24 -2, 25 -3)", "vertex-first", "[default]" + 18, "LINESTRING( 1 -6, 0 -7, -1 -6, 0 -5, 1 -6)", "vertex-last", "left" + 19, "LINESTRING( 4 -6, 3 -7, 2 -6, 3 -5, 4 -6)", "vertex-last", "right" + 20, "LINESTRING( 7 -6, 6 -7, 5 -6, 6 -5, 7 -6)", "vertex-last", "left-only" + 21, "LINESTRING(10 -6, 9 -7, 8 -6, 9 -5, 10 -6)", "vertex-last", "right-only" + 22, "LINESTRING(13 -6, 12 -7, 11 -6, 12 -5, 13 -6)", "vertex-last", "auto" + 23, "LINESTRING(16 -6, 15 -7, 14 -6, 15 -5, 16 -6)", "vertex-last", "auto-down" + 24, "LINESTRING(19 -6, 18 -7, 17 -6, 18 -5, 19 -6)", "vertex-last", "up" + 25, "LINESTRING(22 -6, 21 -7, 20 -6, 21 -5, 22 -6)", "vertex-last", "down" + 26, "LINESTRING(25 -6, 24 -7, 23 -6, 24 -5, 25 -6)", "vertex-last", "[default]" + + + +