diff --git a/include/mapnik/markers_placement.hpp b/include/mapnik/markers_placement.hpp index 6a784a790..ca7cf967a 100644 --- a/include/mapnik/markers_placement.hpp +++ b/include/mapnik/markers_placement.hpp @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include #include @@ -41,7 +43,9 @@ class markers_placement_finder : mapnik::noncopyable public: using markers_placement = boost::variant, markers_line_placement, - markers_interior_placement>; + markers_interior_placement, + markers_vertex_first_placement, + markers_vertex_last_placement>; class get_point_visitor : public boost::static_visitor { @@ -74,22 +78,14 @@ public: { } - /** Get a point where the marker should be placed. - * Each time this function is called a new point is returned. - * \param x Return value for x position - * \param y Return value for x position - * \param angle Return value for rotation angle - * \param ignore_placement Whether to add selected position to detector - * \return True if a place is found, false if none is found. - */ + // Get next point where the marker should be placed. Returns true if a place is found, false if none is found. bool get_point(double &x, double &y, double &angle, bool ignore_placement) { return boost::apply_visitor(get_point_visitor(x, y, angle, ignore_placement), placement_); } private: - /** Factory function for particular placement implementations. - */ + // Factory function for particular placement implementations. static markers_placement create(marker_placement_e placement_type, Locator &locator, box2d const& size, @@ -110,7 +106,9 @@ private: { { MARKER_POINT_PLACEMENT, boost::value_factory>() }, { MARKER_INTERIOR_PLACEMENT, boost::value_factory>() }, - { MARKER_LINE_PLACEMENT, boost::value_factory>() } + { MARKER_LINE_PLACEMENT, boost::value_factory>() }, + { MARKER_VERTEX_FIRST_PLACEMENT, boost::value_factory>() }, + { MARKER_VERTEX_LAST_PLACEMENT, boost::value_factory>() } }; return factories.at(placement_type)(locator, size, tr, detector, spacing, max_error, allow_overlap); } diff --git a/include/mapnik/markers_placements/line.hpp b/include/mapnik/markers_placements/line.hpp index 3244ede79..782a4a04e 100644 --- a/include/mapnik/markers_placements/line.hpp +++ b/include/mapnik/markers_placements/line.hpp @@ -206,13 +206,13 @@ private: double last_y; double next_x; double next_y; - /** If a marker could not be placed at the exact point where it should - * go the next marker's distance will be a bit lower. */ + // If a marker could not be placed at the exact point where it should + // go the next marker's distance will be a bit lower. double error_; double spacing_left_; unsigned marker_nr_; - /** Set spacing_left_, adjusts error_ and performs sanity checks. */ + // Set spacing_left_, adjusts error_ and performs sanity checks. void set_spacing_left(double sl, bool allow_negative=false) { double delta_error = sl - spacing_left_; diff --git a/include/mapnik/markers_placements/point.hpp b/include/mapnik/markers_placements/point.hpp index 4329761c2..60ec39320 100644 --- a/include/mapnik/markers_placements/point.hpp +++ b/include/mapnik/markers_placements/point.hpp @@ -55,27 +55,16 @@ public: { rewind(); } - virtual ~markers_point_placement() {} - /** Start again at first marker. - * \note Returns the same list of markers only works when they were NOT added - * to the detector. - */ - virtual void rewind() + // Start again at first marker. Returns the same list of markers only works when they were NOT added to the detector. + void rewind() { locator_.rewind(0); done_ = false; } - /** Get a point where the marker should be placed. - * Each time this function is called a new point is returned. - * \param x Return value for x position - * \param y Return value for x position - * \param angle Return value for rotation angle - * \param ignore_placement Whether to add selected position to detector - * \return True if a place is found, false if none is found. - */ - virtual bool get_point(double &x, double &y, double &angle, bool ignore_placement) + // Get next point where the marker should be placed. Returns true if a place is found, false if none is found. + bool get_point(double &x, double &y, double &angle, bool ignore_placement) { if (done_) { @@ -129,7 +118,7 @@ protected: double marker_width_; bool done_; - /** Rotates the size_ box and translates the position. */ + // Rotates the size_ box and translates the position. box2d perform_transform(double angle, double dx, double dy) { double x1 = size_.minx(); @@ -156,4 +145,3 @@ protected: } #endif // MAPNIK_MARKERS_PLACEMENTS_POINT_HPP - diff --git a/include/mapnik/markers_placements/vertext_first.hpp b/include/mapnik/markers_placements/vertext_first.hpp new file mode 100644 index 000000000..57608fbdd --- /dev/null +++ b/include/mapnik/markers_placements/vertext_first.hpp @@ -0,0 +1,98 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2014 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_MARKERS_PLACEMENTS_VERTEXT_FIRST_HPP +#define MAPNIK_MARKERS_PLACEMENTS_VERTEXT_FIRST_HPP + +#include + +namespace mapnik { + +template +class markers_vertex_first_placement : public markers_point_placement +{ +public: + markers_vertex_first_placement( + Locator &locator, + box2d const& size, + agg::trans_affine const& tr, + Detector &detector, + double spacing, + double max_error, + bool allow_overlap) + : markers_point_placement( + locator, size, tr, detector, + spacing, max_error, allow_overlap) + { + } + + bool get_point(double &x, double &y, double &angle, bool ignore_placement) + { + if (this->done_) + { + return false; + } + + if (this->locator_.type() == mapnik::geometry_type::types::Point) + { + return markers_point_placement::get_point(x, y, angle, ignore_placement); + } + + double x0, y0; + + if (agg::is_stop(this->locator_.vertex(&x0, &y0))) + { + this->done_ = true; + return false; + } + + x = x0; + y = y0; + angle = 0; + + double x1, y1; + + if (agg::is_line_to(this->locator_.vertex(&x1, &y1))) + { + angle = std::atan2(y1 - y0, x1 - x0); + } + + box2d box = this->perform_transform(angle, x, y); + + if (!this->allow_overlap_ && !this->detector_.has_placement(box)) + { + return false; + } + + if (!ignore_placement) + { + this->detector_.insert(box); + } + + this->done_ = true; + return true; + } +}; + +} + +#endif // MAPNIK_MARKERS_PLACEMENTS_VERTEXT_FIRST_HPP diff --git a/include/mapnik/markers_placements/vertext_last.hpp b/include/mapnik/markers_placements/vertext_last.hpp new file mode 100644 index 000000000..2ff1f740a --- /dev/null +++ b/include/mapnik/markers_placements/vertext_last.hpp @@ -0,0 +1,103 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2014 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_MARKERS_PLACEMENTS_VERTEXT_LAST_HPP +#define MAPNIK_MARKERS_PLACEMENTS_VERTEXT_LAST_HPP + +#include + +namespace mapnik { + +template +class markers_vertex_last_placement : public markers_point_placement +{ +public: + markers_vertex_last_placement( + Locator &locator, + box2d const& size, + agg::trans_affine const& tr, + Detector &detector, + double spacing, + double max_error, + bool allow_overlap) + : markers_point_placement( + locator, size, tr, detector, + spacing, max_error, allow_overlap) + { + } + + bool get_point(double &x, double &y, double &angle, bool ignore_placement) + { + if (this->done_) + { + return false; + } + + double next_x, next_y; + double x0, y0; + double x1, y1; + unsigned command0, command1 = agg::path_cmd_stop; + + while (!agg::is_stop(command0 = this->locator_.vertex(&next_x, &next_y))) + { + command1 = command0; + x1 = x0; + y1 = y0; + x0 = next_x; + y0 = next_y; + } + + // If path stopped on the very firts vertex. + if (agg::is_stop(command1)) + { + this->done_ = true; + return false; + } + + x = x0; + y = y0; + + if (agg::is_line_to(command1)) + { + angle = std::atan2(y0 - y1, x0 - x1); + } + + box2d box = this->perform_transform(angle, x, y); + + if (!this->allow_overlap_ && !this->detector_.has_placement(box)) + { + return false; + } + + if (!ignore_placement) + { + this->detector_.insert(box); + } + + this->done_ = true; + return true; + } +}; + +} + +#endif // MAPNIK_MARKERS_PLACEMENTS_VERTEXT_LAST_HPP diff --git a/include/mapnik/symbolizer_enumerations.hpp b/include/mapnik/symbolizer_enumerations.hpp index 0b3179815..b4b81c1de 100644 --- a/include/mapnik/symbolizer_enumerations.hpp +++ b/include/mapnik/symbolizer_enumerations.hpp @@ -102,6 +102,8 @@ enum marker_placement_enum MARKER_POINT_PLACEMENT, MARKER_INTERIOR_PLACEMENT, MARKER_LINE_PLACEMENT, + MARKER_VERTEX_FIRST_PLACEMENT, + MARKER_VERTEX_LAST_PLACEMENT, marker_placement_enum_MAX }; diff --git a/src/symbolizer_enumerations.cpp b/src/symbolizer_enumerations.cpp index 27e3f9b14..257de804d 100644 --- a/src/symbolizer_enumerations.cpp +++ b/src/symbolizer_enumerations.cpp @@ -65,6 +65,8 @@ static const char * marker_placement_strings[] = { "point", "interior", "line", + "vertex-first", + "vertex-last", "" }; diff --git a/tests/visual_tests/grids/marker-on-line-and-vertex-first-placement-600-400-1.0-grid-reference.json b/tests/visual_tests/grids/marker-on-line-and-vertex-first-placement-600-400-1.0-grid-reference.json new file mode 100644 index 000000000..84f2841b3 --- /dev/null +++ b/tests/visual_tests/grids/marker-on-line-and-vertex-first-placement-600-400-1.0-grid-reference.json @@ -0,0 +1,111 @@ +{ + "keys": [ + "", + "3", + "2", + "1" + ], + "data": {}, + "grid": [ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ! ! ! ", + " !! ! !! ! !! ", + " !! ! !! ! !! ", + " !! ! !! ! !! ", + " !! ! !! ! !! ", + " !! ! !! ! !! ", + " !! ! !! ! !! ", + " !! ! !! ! !! ", + " !! ! !! ! !! ", + " !! ! !! ! !! ", + " !! ! !! ! !! ", + " !! ! !! ! !! ", + " !!! ! !! ! !! ", + " !!! ", + " ! ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ## ", + " ############################################################################################################################### ", + " ## ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " $$ ", + " $$$ ", + " $ ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + ] +} \ No newline at end of file diff --git a/tests/visual_tests/grids/marker-on-line-and-vertex-last-placement-600-400-1.0-grid-reference.json b/tests/visual_tests/grids/marker-on-line-and-vertex-last-placement-600-400-1.0-grid-reference.json new file mode 100644 index 000000000..8f0444cb9 --- /dev/null +++ b/tests/visual_tests/grids/marker-on-line-and-vertex-last-placement-600-400-1.0-grid-reference.json @@ -0,0 +1,111 @@ +{ + "keys": [ + "", + "3", + "2", + "1" + ], + "data": {}, + "grid": [ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " !! ", + " ! ! !!! ", + " !! ! !! ! !!!! ", + " !! ! !! ! !! ", + " !! ! !! ! !! ", + " !! ! !! ! !! ", + " !! ! !! ! !! ", + " !! ! !! ! !! ", + " !! ! !! ! !! ", + " !! ! !! ! !! ", + " !! ! !! ! !! ", + " !! ! !! ! !! ", + " !! ! !! ! !! ", + " !! ! !! ! !! ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ## ", + " ############################################################################################################################## ", + " ## ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " $$ ", + " $$$ ", + " $ ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + ] +} \ No newline at end of file diff --git a/tests/visual_tests/images/marker-on-line-and-vertex-first-placement-600-400-1.0-agg-reference.png b/tests/visual_tests/images/marker-on-line-and-vertex-first-placement-600-400-1.0-agg-reference.png new file mode 100644 index 000000000..cf1c4e936 Binary files /dev/null and b/tests/visual_tests/images/marker-on-line-and-vertex-first-placement-600-400-1.0-agg-reference.png differ diff --git a/tests/visual_tests/images/marker-on-line-and-vertex-first-placement-600-400-1.0-cairo-reference.png b/tests/visual_tests/images/marker-on-line-and-vertex-first-placement-600-400-1.0-cairo-reference.png new file mode 100644 index 000000000..1d862a942 Binary files /dev/null and b/tests/visual_tests/images/marker-on-line-and-vertex-first-placement-600-400-1.0-cairo-reference.png differ diff --git a/tests/visual_tests/images/marker-on-line-and-vertex-first-placement-600-400-2.0-agg-reference.png b/tests/visual_tests/images/marker-on-line-and-vertex-first-placement-600-400-2.0-agg-reference.png new file mode 100644 index 000000000..f558b77b7 Binary files /dev/null and b/tests/visual_tests/images/marker-on-line-and-vertex-first-placement-600-400-2.0-agg-reference.png differ diff --git a/tests/visual_tests/images/marker-on-line-and-vertex-first-placement-600-400-2.0-cairo-reference.png b/tests/visual_tests/images/marker-on-line-and-vertex-first-placement-600-400-2.0-cairo-reference.png new file mode 100644 index 000000000..4af718a64 Binary files /dev/null and b/tests/visual_tests/images/marker-on-line-and-vertex-first-placement-600-400-2.0-cairo-reference.png differ diff --git a/tests/visual_tests/images/marker-on-line-and-vertex-last-placement-600-400-1.0-agg-reference.png b/tests/visual_tests/images/marker-on-line-and-vertex-last-placement-600-400-1.0-agg-reference.png new file mode 100644 index 000000000..f892d137f Binary files /dev/null and b/tests/visual_tests/images/marker-on-line-and-vertex-last-placement-600-400-1.0-agg-reference.png differ diff --git a/tests/visual_tests/images/marker-on-line-and-vertex-last-placement-600-400-1.0-cairo-reference.png b/tests/visual_tests/images/marker-on-line-and-vertex-last-placement-600-400-1.0-cairo-reference.png new file mode 100644 index 000000000..5f8bd3565 Binary files /dev/null and b/tests/visual_tests/images/marker-on-line-and-vertex-last-placement-600-400-1.0-cairo-reference.png differ diff --git a/tests/visual_tests/images/marker-on-line-and-vertex-last-placement-600-400-2.0-agg-reference.png b/tests/visual_tests/images/marker-on-line-and-vertex-last-placement-600-400-2.0-agg-reference.png new file mode 100644 index 000000000..69045d7a5 Binary files /dev/null and b/tests/visual_tests/images/marker-on-line-and-vertex-last-placement-600-400-2.0-agg-reference.png differ diff --git a/tests/visual_tests/images/marker-on-line-and-vertex-last-placement-600-400-2.0-cairo-reference.png b/tests/visual_tests/images/marker-on-line-and-vertex-last-placement-600-400-2.0-cairo-reference.png new file mode 100644 index 000000000..3e1c3cffe Binary files /dev/null and b/tests/visual_tests/images/marker-on-line-and-vertex-last-placement-600-400-2.0-cairo-reference.png differ diff --git a/tests/visual_tests/styles/marker-on-line-and-vertex-first-placement.xml b/tests/visual_tests/styles/marker-on-line-and-vertex-first-placement.xml new file mode 100644 index 000000000..e001cd4d2 --- /dev/null +++ b/tests/visual_tests/styles/marker-on-line-and-vertex-first-placement.xml @@ -0,0 +1,28 @@ + + + + + + + lines + markers + + csv + + wkt, placement + "LINESTRING(0 0)", "vertex-first" + "LINESTRING(0 1, 10 1)", "vertex-first" + "LINESTRING(0 2, 2 3, 4 2, 6 3, 8 2, 10 3)", "vertex-first" + + + + diff --git a/tests/visual_tests/styles/marker-on-line-and-vertex-last-placement.xml b/tests/visual_tests/styles/marker-on-line-and-vertex-last-placement.xml new file mode 100644 index 000000000..b35a65d1a --- /dev/null +++ b/tests/visual_tests/styles/marker-on-line-and-vertex-last-placement.xml @@ -0,0 +1,28 @@ + + + + + + + lines + markers + + csv + + wkt, placement + "LINESTRING(0 0)", "vertex-last" + "LINESTRING(0 1, 10 1)", "vertex-last" + "LINESTRING(0 2, 2 3, 4 2, 6 3, 8 2, 10 3)", "vertex-last" + + + + diff --git a/tests/visual_tests/test.py b/tests/visual_tests/test.py index 4e1324e53..da095b1b8 100755 --- a/tests/visual_tests/test.py +++ b/tests/visual_tests/test.py @@ -6,7 +6,6 @@ import mapnik #mapnik.logger.set_severity(mapnik.severity_type.None) #mapnik.logger.set_severity(mapnik.severity_type.Debug) import shutil -import sys import os.path from compare import compare, compare_grids @@ -121,6 +120,10 @@ files = { 'marker-on-line-spacing-eq-width': {'sizes':[(600,400)]}, 'marker-on-line-spacing-eq-width-overlap': {'sizes':[(600,400)]}, 'marker_line_placement_on_points':{}, + 'marker-on-line-and-vertex-first-placement':{'sizes':[(600,400)], + 'bbox': mapnik.Box2d(-1, -1, 11, 4)}, + 'marker-on-line-and-vertex-last-placement':{'sizes':[(600,400)], + 'bbox': mapnik.Box2d(-1, -1, 11, 4)}, 'marker-with-background-image-linear-comp-op': {}, 'marker-with-background-image': {'sizes':[(600,400),(400,600),(257,256)]}, 'marker-with-background-image-and-hsla-transform': {'sizes':[(600,400),(400,600),(257,256)]},