[Git][debian-gis-team/mapnik][upstream] New upstream version 3.0.19~rc1+ds
Bas Couwenberg
gitlab at salsa.debian.org
Mon Mar 5 15:23:23 UTC 2018
Bas Couwenberg pushed to branch upstream at Debian GIS Project / mapnik
Commits:
07e55bf9 by Bas Couwenberg at 2018-03-05T15:37:28+01:00
New upstream version 3.0.19~rc1+ds
- - - - -
16 changed files:
- CHANGELOG.md
- SConstruct
- deps/agg/include/agg_rendering_buffer.h
- + include/mapnik/grid_vertex_converter.hpp
- include/mapnik/symbolizer_enumerations.hpp
- include/mapnik/text/placements/list.hpp
- include/mapnik/text/placements/simple.hpp
- include/mapnik/text/symbolizer_helpers.hpp
- include/mapnik/text/text_properties.hpp
- include/mapnik/version.hpp
- src/geometry/interior.cpp
- src/load_map.cpp
- src/symbolizer_enumerations.cpp
- src/text/symbolizer_helpers.cpp
- src/text/text_properties.cpp
- + test/unit/geometry/grid_vertex_converter.cpp
Changes:
=====================================
CHANGELOG.md
=====================================
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,20 @@ Developers: Please commit along with changes.
For a complete change history, see the git log.
+## 3.0.19
+
+Released: March XX, 2018
+
+(Packaged from xxxxxxxxx)
+
+ - Backported scaling of precision by polygon size (#3844)
+ - Backported GRID placement (#3847, #3854, #3855)
+ - Added missing `MAPNIK_DECL` to all `text_placement_` types (7ce142a5aa8e9da5ddd11266a054c1e69052230d)
+ - Fixed invalid memory access if input_buffer size is zero (a602c65354a4b595821d2300f38ebc107d07e2a9)
+ - Fixed handling of an empty polygon in grid_vertex_converter (2f2dcf1eeae71aaa7878f4bc9a39741321f07e68)
+ - Fixed PROJ_LIB detection logic (44f1ae3a6e9e9979d1a93343f40db6cd7dbf51d5)
+ - Default to `icu-config` for obtaining `ICU_DATA` if `u_getDataDirectory fails (2cef98d7f76cdd302afcf15f1c585379537e8f1d)
+
## 3.0.18
Released: January 26, 2018
=====================================
SConstruct
=====================================
--- a/SConstruct
+++ b/SConstruct
@@ -830,9 +830,16 @@ int main() {
context.did_show_result=1
if ret[0]:
context.Result('u_getDataDirectory returned %s' % ret[1])
+ return ret[1].strip()
else:
- context.Result('Failed to detect (mapnik-config will have null value)')
- return ret[1].strip()
+ ret = call("icu-config --icudatadir", silent=True)
+ if ret:
+ context.Result('icu-config returned %s' % ret)
+ return ret
+ else:
+ context.Result('Failed to detect (mapnik-config will have null value)')
+ return ''
+
def CheckGdalData(context, silent=False):
@@ -866,6 +873,7 @@ def CheckProjData(context, silent=False):
// This is narly, could eventually be replaced using https://github.com/OSGeo/proj.4/pull/551]
#include <proj_api.h>
#include <iostream>
+#include <cstring>
static void my_proj4_logger(void * user_data, int /*level*/, const char * msg)
{
=====================================
deps/agg/include/agg_rendering_buffer.h
=====================================
--- a/deps/agg/include/agg_rendering_buffer.h
+++ b/deps/agg/include/agg_rendering_buffer.h
@@ -176,6 +176,10 @@ namespace agg
{
m_rows.resize(height);
}
+ else if(height == 0)
+ {
+ return;
+ }
T* row_ptr = m_buf;
=====================================
include/mapnik/grid_vertex_converter.hpp
=====================================
--- /dev/null
+++ b/include/mapnik/grid_vertex_converter.hpp
@@ -0,0 +1,257 @@
+/*****************************************************************************
+ *
+ * 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_GRID_ADAPTERS_HPP
+#define MAPNIK_GRID_ADAPTERS_HPP
+
+// mapnik
+#include <mapnik/vertex.hpp>
+#include <mapnik/image.hpp>
+#include <mapnik/image_util.hpp>
+#include <mapnik/geom_util.hpp>
+#include <mapnik/geometry/polygon_vertex_processor.hpp>
+#include <mapnik/geometry_envelope.hpp>
+#include <mapnik/geometry/interior.hpp>
+#include <mapnik/view_strategy.hpp>
+#include <mapnik/vertex_adapters.hpp>
+
+// agg
+#include "agg_rendering_buffer.h"
+#include "agg_pixfmt_gray.h"
+#include "agg_renderer_base.h"
+#include "agg_renderer_scanline.h"
+#include "agg_rasterizer_scanline_aa.h"
+#include "agg_scanline_bin.h"
+#include "agg_conv_transform.h"
+
+namespace mapnik { namespace geometry {
+
+// Generates integer coordinates of a spiral similar to the Ulam spiral
+// around [0, 0], bounded by size.
+class spiral_iterator
+{
+public:
+ spiral_iterator(unsigned size)
+ : end_(size * size),
+ i_(0),
+ x_(0), y_(0)
+ {
+ }
+
+ bool vertex(int * x, int * y)
+ {
+ if (i_ < end_)
+ {
+ *x = x_;
+ *y = y_;
+
+ if (std::abs(x_) <= std::abs(y_) && (x_ != y_ || x_ >= 0))
+ {
+ x_ += ((y_ >= 0) ? 1 : -1);
+ }
+ else
+ {
+ y_ += ((x_ >= 0) ? -1 : 1);
+ }
+
+ ++i_;
+
+ return true;
+ }
+ return false;
+ }
+
+ void rewind()
+ {
+ i_ = x_ = y_ = 0;
+ }
+
+private:
+ const unsigned end_;
+ unsigned i_;
+ int x_, y_;
+};
+
+struct view_transform_agg_adapter
+{
+ void transform(double * x, double * y) const
+ {
+ vt.forward(x, y);
+ }
+
+ view_transform const& vt;
+};
+
+// Generates grid of points laying inside a polygon.
+template <typename PathType, typename T, bool Alternating = false>
+struct grid_vertex_converter
+{
+ grid_vertex_converter(PathType & path, T dx, T dy, double scale_factor)
+ : grid_vertex_converter(cache_path(path), dx, dy, scale_factor)
+ {
+ }
+
+ void rewind(unsigned)
+ {
+ si_.rewind();
+ }
+
+ unsigned vertex(T * x, T * y)
+ {
+ int spiral_x, spiral_y;
+ while (si_.vertex(&spiral_x, &spiral_y))
+ {
+ T pix_x = interior_.x + spiral_x * dx_;
+ T pix_y = interior_.y + spiral_y * dy_;
+
+ if (Alternating && spiral_y % 2 != 0)
+ {
+ // Every odd line is shifted by dx/2.
+ pix_x += this->dx_ / 2.0;
+ }
+
+ if (pix_x >= 0 && static_cast<std::size_t>(pix_x) < hit_bitmap_.width() &&
+ pix_y >= 0 && static_cast<std::size_t>(pix_y) < hit_bitmap_.height() &&
+ get_pixel<image_gray8::pixel_type>(hit_bitmap_, pix_x, pix_y))
+ {
+ *x = pix_x;
+ *y = pix_y;
+ vt_.backward(x, y);
+ return mapnik::SEG_MOVETO;
+ }
+ }
+ return mapnik::SEG_END;
+ }
+
+ geometry_types type() const
+ {
+ return geometry_types::MultiPoint;
+ }
+
+private:
+ grid_vertex_converter(polygon<T> const& poly, T dx, T dy, double scale_factor)
+ : grid_vertex_converter(poly, dx, dy, scale_factor, mapnik::geometry::envelope(poly))
+ {
+ }
+
+ grid_vertex_converter(polygon<T> const& poly, T dx, T dy, double scale_factor, box2d<T> const& envelope)
+ : hit_bitmap_scale_(get_hit_bitmap_scale(envelope)),
+ dx_(dx * hit_bitmap_scale_),
+ dy_(dy * hit_bitmap_scale_),
+ vt_(envelope.valid() ? (envelope.width() * hit_bitmap_scale_) : 0,
+ envelope.valid() ? (envelope.height() * hit_bitmap_scale_) : 0, envelope),
+ hit_bitmap_(create_hit_bitmap(poly)),
+ interior_(interior(poly, envelope, scale_factor)),
+ si_(std::max(std::ceil((hit_bitmap_.width() + std::abs((hit_bitmap_.width() / 2.0) - interior_.x) * 2.0) / dx_),
+ std::ceil((hit_bitmap_.height() + std::abs((hit_bitmap_.height() / 2.0) - interior_.y) * 2.0) / dy_)))
+ {
+ }
+
+ double get_hit_bitmap_scale(box2d<T> const& envelope) const
+ {
+ if (envelope.valid())
+ {
+ T size = envelope.width() * envelope.height();
+ // Polygon with huge area can lead to excessive memory allocation.
+ // This is more or less arbitrarily chosen limit for the maximum bitmap resolution.
+ // Bitmap bigger than this limit is scaled down to fit into this resolution.
+ const std::size_t max_size = 8192 * 8192;
+ if (size > max_size)
+ {
+ return std::sqrt(max_size / size);
+ }
+ }
+ return 1;
+ }
+
+ // The polygon is rendered to a bitmap for fast hit-testing.
+ image_gray8 create_hit_bitmap(polygon<T> const& poly) const
+ {
+ polygon_vertex_adapter<T> va(poly);
+ view_transform_agg_adapter vta{ vt_ };
+ agg::conv_transform<polygon_vertex_adapter<T>, view_transform_agg_adapter> tp(va, vta);
+ tp.rewind(0);
+ agg::rasterizer_scanline_aa<> ras;
+ ras.add_path(tp);
+
+ image_gray8 hit_bitmap(vt_.width(), vt_.height());
+ agg::rendering_buffer buf(hit_bitmap.data(),
+ hit_bitmap.width(),
+ hit_bitmap.height(),
+ hit_bitmap.row_size());
+ agg::pixfmt_gray8 pixfmt(buf);
+ using renderer_base = agg::renderer_base<agg::pixfmt_gray8>;
+ using renderer_bin = agg::renderer_scanline_bin_solid<renderer_base>;
+ renderer_base rb(pixfmt);
+ renderer_bin ren_bin(rb);
+ ren_bin.color(agg::gray8(1));
+ agg::scanline_bin sl_bin;
+ agg::render_scanlines(ras, sl_bin, ren_bin);
+
+ return hit_bitmap;
+ }
+
+ mapnik::geometry::point<T> interior(polygon<T> const& poly,
+ box2d<T> const& envelope,
+ double scale_factor) const
+ {
+ mapnik::geometry::point<T> interior;
+ if (envelope.valid())
+ {
+ if (!mapnik::geometry::interior(poly, scale_factor, interior))
+ {
+ auto center = envelope.center();
+ interior.x = center.x;
+ interior.y = center.y;
+ }
+
+ vt_.forward(&interior.x, &interior.y);
+ }
+ return interior;
+ }
+
+ polygon<T> cache_path(PathType & path) const
+ {
+ mapnik::geometry::polygon_vertex_processor<T> vertex_processor;
+ path.rewind(0);
+ vertex_processor.add_path(path);
+ return vertex_processor.polygon_;
+ }
+
+ const double hit_bitmap_scale_;
+ const T dx_, dy_;
+ const view_transform vt_;
+ const image_gray8 hit_bitmap_;
+ const mapnik::geometry::point<T> interior_;
+ spiral_iterator si_;
+};
+
+template <typename PathType, typename T>
+using regular_grid_vertex_converter = grid_vertex_converter<PathType, T, false>;
+
+template <typename PathType, typename T>
+using alternating_grid_vertex_converter = grid_vertex_converter<PathType, T, true>;
+
+}
+}
+
+#endif //MAPNIK_GRID_ADAPTERS_HPP
=====================================
include/mapnik/symbolizer_enumerations.hpp
=====================================
--- a/include/mapnik/symbolizer_enumerations.hpp
+++ b/include/mapnik/symbolizer_enumerations.hpp
@@ -138,6 +138,8 @@ enum label_placement_enum : std::uint8_t
LINE_PLACEMENT,
VERTEX_PLACEMENT,
INTERIOR_PLACEMENT,
+ GRID_PLACEMENT,
+ ALTERNATING_GRID_PLACEMENT,
label_placement_enum_MAX
};
=====================================
include/mapnik/text/placements/list.hpp
=====================================
--- a/include/mapnik/text/placements/list.hpp
+++ b/include/mapnik/text/placements/list.hpp
@@ -30,7 +30,7 @@ class feature_impl;
struct attribute;
// Tries a list of placements.
-class text_placements_list: public text_placements
+class MAPNIK_DECL text_placements_list: public text_placements
{
public:
text_placements_list();
@@ -47,7 +47,7 @@ private:
// List placement strategy.
// See parent class for documentation of each function.
-class text_placement_info_list : public text_placement_info
+class MAPNIK_DECL text_placement_info_list : public text_placement_info
{
public:
text_placement_info_list(text_placements_list const* parent, double scale_factor) :
=====================================
include/mapnik/text/placements/simple.hpp
=====================================
--- a/include/mapnik/text/placements/simple.hpp
+++ b/include/mapnik/text/placements/simple.hpp
@@ -33,7 +33,7 @@ class feature_impl;
struct attribute;
// Automatically generates placement options from a user selected list of directions and text sizes.
-class text_placements_simple: public text_placements
+class MAPNIK_DECL text_placements_simple: public text_placements
{
public:
text_placements_simple(symbolizer_base::value_type const& positions);
@@ -53,7 +53,7 @@ private:
// Simple placement strategy.
// See parent class for documentation of each function.
-class text_placement_info_simple : public text_placement_info
+class MAPNIK_DECL text_placement_info_simple : public text_placement_info
{
public:
text_placement_info_simple(text_placements_simple const* parent,
=====================================
include/mapnik/text/symbolizer_helpers.hpp
=====================================
--- a/include/mapnik/text/symbolizer_helpers.hpp
+++ b/include/mapnik/text/symbolizer_helpers.hpp
@@ -59,7 +59,13 @@ struct placement_finder_adapter
};
-using vertex_converter_type = vertex_converter<clip_line_tag, transform_tag, affine_transform_tag, simplify_tag, smooth_tag>;
+using vertex_converter_type = vertex_converter<clip_line_tag,
+ clip_poly_tag,
+ transform_tag,
+ affine_transform_tag,
+ simplify_tag,
+ smooth_tag,
+ offset_transform_tag>;
class base_symbolizer_helper
{
@@ -147,6 +153,10 @@ public:
// Return all placements.
placements_list const& get() const;
protected:
+ void init_converters();
+ void initialize_points() const;
+ template <template <typename, typename> typename GridAdapter>
+ void initialize_grid_points() const;
bool next_point_placement() const;
bool next_line_placement() const;
=====================================
include/mapnik/text/text_properties.hpp
=====================================
--- a/include/mapnik/text/text_properties.hpp
+++ b/include/mapnik/text/text_properties.hpp
@@ -80,6 +80,8 @@ struct evaluated_text_properties : util::noncopyable
bool allow_overlap;
bool largest_bbox_only;
text_upright_e upright;
+ double grid_cell_width;
+ double grid_cell_height;
};
}
@@ -172,6 +174,8 @@ struct text_properties_expressions
symbolizer_base::value_type allow_overlap = false;
symbolizer_base::value_type largest_bbox_only = true;
symbolizer_base::value_type upright = enumeration_wrapper(UPRIGHT_AUTO);
+ symbolizer_base::value_type grid_cell_width = 0.0;
+ symbolizer_base::value_type grid_cell_height = 0.0;
};
// Contains all text symbolizer properties which are not directly related to text formatting and layout.
=====================================
include/mapnik/version.hpp
=====================================
--- a/include/mapnik/version.hpp
+++ b/include/mapnik/version.hpp
@@ -27,7 +27,7 @@
#define MAPNIK_MAJOR_VERSION 3
#define MAPNIK_MINOR_VERSION 0
-#define MAPNIK_PATCH_VERSION 18
+#define MAPNIK_PATCH_VERSION 19
#define MAPNIK_VERSION (MAPNIK_MAJOR_VERSION*100000) + (MAPNIK_MINOR_VERSION*100) + (MAPNIK_PATCH_VERSION)
=====================================
src/geometry/interior.cpp
=====================================
--- a/src/geometry/interior.cpp
+++ b/src/geometry/interior.cpp
@@ -153,15 +153,8 @@ struct cell
};
template <class T>
-boost::optional<point<T>> polylabel(polygon<T> const& polygon, T precision = 1)
+point<T> polylabel(polygon<T> const& polygon, box2d<T> const& bbox , T precision = 1)
{
- if (polygon.exterior_ring.empty())
- {
- return boost::none;
- }
-
- // find the bounding box of the outer ring
- const box2d<T> bbox = envelope(polygon.exterior_ring);
const point<T> size { bbox.width(), bbox.height() };
const T cell_size = std::min(size.x, size.y);
@@ -177,14 +170,14 @@ boost::optional<point<T>> polylabel(polygon<T> const& polygon, T precision = 1)
if (cell_size == 0)
{
- return point<T>{ bbox.minx(), bbox.miny() };
+ return { bbox.minx(), bbox.miny() };
}
point<T> centroid;
if (!mapnik::geometry::centroid(polygon, centroid))
{
auto center = bbox.center();
- return point<T>{ center.x, center.y };
+ return { center.x, center.y };
}
fitness_functor<T> fitness_func(centroid, size);
@@ -232,15 +225,18 @@ boost::optional<point<T>> polylabel(polygon<T> const& polygon, T precision = 1)
template <class T>
bool interior(polygon<T> const& polygon, double scale_factor, point<T> & pt)
{
- // This precision has been chosen to work well in the map (viewport) coordinates.
- double precision = 10.0 * scale_factor;
- if (boost::optional<point<T>> opt = detail::polylabel(polygon, precision))
+ if (polygon.exterior_ring.empty())
{
- pt = *opt;
- return true;
+ return false;
}
- return false;
+ const box2d<T> bbox = envelope(polygon.exterior_ring);
+
+ // Let the precision be 1% of the polygon size to be independent to map scale.
+ double precision = (std::max(bbox.width(), bbox.height()) / 100.0) * scale_factor;
+
+ pt = detail::polylabel(polygon, bbox, precision);
+ return true;
}
template
=====================================
src/load_map.cpp
=====================================
--- a/src/load_map.cpp
+++ b/src/load_map.cpp
@@ -1134,6 +1134,7 @@ void map_parser::parse_text_symbolizer(rule & rule, xml_node const& node)
set_symbolizer_property<symbolizer_base,composite_mode_e>(sym, keys::halo_comp_op, node);
set_symbolizer_property<symbolizer_base,halo_rasterizer_enum>(sym, keys::halo_rasterizer, node);
set_symbolizer_property<symbolizer_base,transform_type>(sym, keys::halo_transform, node);
+ set_symbolizer_property<symbolizer_base,value_double>(sym, keys::offset, node);
rule.append(std::move(sym));
}
}
@@ -1175,6 +1176,7 @@ void map_parser::parse_shield_symbolizer(rule & rule, xml_node const& node)
set_symbolizer_property<symbolizer_base,double>(sym, keys::shield_dy, node);
set_symbolizer_property<symbolizer_base,double>(sym, keys::opacity, node);
set_symbolizer_property<symbolizer_base,value_bool>(sym, keys::unlock_image, node);
+ set_symbolizer_property<symbolizer_base,value_double>(sym, keys::offset, node);
std::string file = node.get_attr<std::string>("file");
if (file.empty())
=====================================
src/symbolizer_enumerations.cpp
=====================================
--- a/src/symbolizer_enumerations.cpp
+++ b/src/symbolizer_enumerations.cpp
@@ -116,6 +116,8 @@ static const char * label_placement_strings[] = {
"line",
"vertex",
"interior",
+ "grid",
+ "alternating-grid",
""
};
=====================================
src/text/symbolizer_helpers.cpp
=====================================
--- a/src/text/symbolizer_helpers.cpp
+++ b/src/text/symbolizer_helpers.cpp
@@ -33,7 +33,6 @@
#include <mapnik/geometry_centroid.hpp>
#include <mapnik/geometry/interior.hpp>
#include <mapnik/vertex_processor.hpp>
-#include <mapnik/geom_util.hpp>
#include <mapnik/parse_path.hpp>
#include <mapnik/debug.hpp>
#include <mapnik/symbolizer.hpp>
@@ -43,6 +42,7 @@
#include <mapnik/text/placements/dummy.hpp>
#include <mapnik/geometry_transform.hpp>
#include <mapnik/geometry_strategy.hpp>
+#include <mapnik/grid_vertex_converter.hpp>
#include <mapnik/proj_strategy.hpp>
#include <mapnik/view_strategy.hpp>
@@ -108,6 +108,31 @@ struct apply_vertex_placement
proj_transform const& prj_trans_;
};
+template <template <typename, typename> typename GridAdapter, typename T, typename Points>
+struct grid_placement_finder_adapter
+{
+ grid_placement_finder_adapter(T dx, T dy, Points & points, double scale_factor)
+ : dx_(dx), dy_(dy),
+ points_(points),
+ scale_factor_(scale_factor) {}
+
+ template <typename PathT>
+ void add_path(PathT & path) const
+ {
+ GridAdapter<PathT, T> gpa(path, dx_, dy_, scale_factor_);
+ gpa.rewind(0);
+ double label_x, label_y;
+ for (unsigned cmd; (cmd = gpa.vertex(&label_x, &label_y)) != SEG_END; )
+ {
+ points_.emplace_back(label_x, label_y);
+ }
+ }
+
+ T dx_, dy_;
+ Points & points_;
+ double scale_factor_;
+};
+
template <typename T>
struct split_multi_geometries
{
@@ -244,14 +269,20 @@ void base_symbolizer_helper::initialize_geometries() const
void base_symbolizer_helper::initialize_points() const
{
label_placement_enum how_placed = text_props_->label_placement;
- if (how_placed == LINE_PLACEMENT)
- {
- point_placement_ = false;
- return;
- }
- else
+
+ switch (how_placed)
{
- point_placement_ = true;
+ case LINE_PLACEMENT:
+ point_placement_ = false;
+ return;
+ case GRID_PLACEMENT:
+ case ALTERNATING_GRID_PLACEMENT:
+ point_placement_ = true;
+ // Points for grid placement are generated in text_symbolizer_helper
+ // because base_symbolizer_helper doesn't have the vertex converter.
+ return;
+ default:
+ point_placement_ = true;
}
double label_x=0.0;
@@ -337,19 +368,40 @@ text_symbolizer_helper::text_symbolizer_helper(
adapter_(finder_,false),
converter_(query_extent_, sym_, t, prj_trans, affine_trans, feature, vars, scale_factor)
{
+ init_converters();
+ if (geometries_to_process_.size())
+ {
+ text_symbolizer_helper::initialize_points();
+ finder_.next_position();
+ }
+}
+
+void text_symbolizer_helper::init_converters()
+{
// setup vertex converter
value_bool clip = mapnik::get<value_bool, keys::clip>(sym_, feature_, vars_);
value_double simplify_tolerance = mapnik::get<value_double, keys::simplify_tolerance>(sym_, feature_, vars_);
value_double smooth = mapnik::get<value_double, keys::smooth>(sym_, feature_, vars_);
+ boost::optional<value_double> offset = get_optional<value_double>(sym_, keys::offset, feature_, vars_);
- if (clip) converter_.template set<clip_line_tag>();
+ if (clip)
+ {
+ label_placement_enum how_placed = text_props_->label_placement;
+ if (how_placed == GRID_PLACEMENT || how_placed == ALTERNATING_GRID_PLACEMENT)
+ {
+ converter_.template set<clip_poly_tag>();
+ }
+ else
+ {
+ converter_.template set<clip_line_tag>();
+ }
+ }
converter_.template set<transform_tag>(); //always transform
converter_.template set<affine_transform_tag>();
if (simplify_tolerance > 0.0) converter_.template set<simplify_tag>(); // optional simplify converter
if (smooth > 0.0) converter_.template set<smooth_tag>(); // optional smooth converter
-
- if (geometries_to_process_.size()) finder_.next_position();
+ if (offset) converter_.template set<offset_transform_tag>(); // optional offset converter
}
placements_list const& text_symbolizer_helper::get() const
@@ -463,18 +515,11 @@ text_symbolizer_helper::text_symbolizer_helper(
adapter_(finder_,true),
converter_(query_extent_, sym_, t, prj_trans, affine_trans, feature, vars, scale_factor)
{
- // setup vertex converter
- value_bool clip = mapnik::get<value_bool, keys::clip>(sym_, feature_, vars_);
- value_double simplify_tolerance = mapnik::get<value_double, keys::simplify_tolerance>(sym_, feature_, vars_);
- value_double smooth = mapnik::get<value_double, keys::smooth>(sym_, feature_, vars_);
+ init_converters();
- if (clip) converter_.template set<clip_line_tag>();
- converter_.template set<transform_tag>(); //always transform
- converter_.template set<affine_transform_tag>();
- if (simplify_tolerance > 0.0) converter_.template set<simplify_tag>(); // optional simplify converter
- if (smooth > 0.0) converter_.template set<smooth_tag>(); // optional smooth converter
if (geometries_to_process_.size())
{
+ text_symbolizer_helper::initialize_points();
init_marker();
finder_.next_position();
}
@@ -515,6 +560,44 @@ void text_symbolizer_helper::init_marker() const
finder_.set_marker(std::make_shared<marker_info>(marker, trans), bbox, unlock_image, marker_displacement);
}
+template <template <typename, typename> typename GridAdapter>
+void text_symbolizer_helper::initialize_grid_points() const
+{
+ for (auto const& geom : geometries_to_process_)
+ {
+ auto type = geometry::geometry_type(geom);
+ if (type != geometry::geometry_types::Polygon)
+ {
+ continue;
+ }
+
+ using adapter_type = detail::grid_placement_finder_adapter<
+ GridAdapter, double, std::list<pixel_position>>;
+ adapter_type ga(text_props_->grid_cell_width,
+ text_props_->grid_cell_height,
+ points_,
+ scale_factor_);
+ auto const& poly = mapnik::util::get<geometry::polygon<double>>(geom);
+ geometry::polygon_vertex_adapter<double> va(poly);
+ converter_.apply(va, ga);
+ }
+}
+
+void text_symbolizer_helper::initialize_points() const
+{
+ label_placement_enum how_placed = text_props_->label_placement;
+
+ if (how_placed == GRID_PLACEMENT)
+ {
+ initialize_grid_points<geometry::regular_grid_vertex_converter>();
+ }
+ else if (how_placed == ALTERNATING_GRID_PLACEMENT)
+ {
+ initialize_grid_points<geometry::alternating_grid_vertex_converter>();
+ }
+ point_itr_ = points_.begin();
+}
+
template text_symbolizer_helper::text_symbolizer_helper(
text_symbolizer const& sym,
feature_impl const& feature,
=====================================
src/text/text_properties.cpp
=====================================
--- a/src/text/text_properties.cpp
+++ b/src/text/text_properties.cpp
@@ -61,6 +61,8 @@ evaluated_text_properties_ptr evaluate_text_properties(text_symbolizer_propertie
prop->allow_overlap = util::apply_visitor(extract_value<value_bool>(feature,attrs), text_prop.expressions.allow_overlap);
prop->largest_bbox_only = util::apply_visitor(extract_value<value_bool>(feature,attrs), text_prop.expressions.largest_bbox_only);
prop->upright = util::apply_visitor(extract_value<text_upright_enum>(feature,attrs), text_prop.expressions.upright);
+ prop->grid_cell_width = util::apply_visitor(extract_value<value_double>(feature,attrs), text_prop.expressions.grid_cell_width);
+ prop->grid_cell_height = util::apply_visitor(extract_value<value_double>(feature,attrs), text_prop.expressions.grid_cell_height);
return prop;
}
@@ -108,6 +110,8 @@ void text_symbolizer_properties::text_properties_from_xml(xml_node const& node)
set_property_from_xml<value_bool>(expressions.largest_bbox_only, "largest-bbox-only", node);
set_property_from_xml<value_double>(expressions.max_char_angle_delta, "max-char-angle-delta", node);
set_property_from_xml<text_upright_e>(expressions.upright, "upright", node);
+ set_property_from_xml<value_double>(expressions.grid_cell_width, "grid-cell-width", node);
+ set_property_from_xml<value_double>(expressions.grid_cell_height, "grid-cell-height", node);
}
void text_symbolizer_properties::from_xml(xml_node const& node, fontset_map const& fontsets, bool is_shield)
@@ -175,6 +179,14 @@ void text_symbolizer_properties::to_xml(boost::property_tree::ptree &node,
{
serialize_property("upright", expressions.upright, node);
}
+ if (!(expressions.grid_cell_width == dfl.expressions.grid_cell_width) || explicit_defaults)
+ {
+ serialize_property("grid-cell-width", expressions.grid_cell_width, node);
+ }
+ if (!(expressions.grid_cell_height == dfl.expressions.grid_cell_height) || explicit_defaults)
+ {
+ serialize_property("grid-cell-height", expressions.grid_cell_height, node);
+ }
layout_defaults.to_xml(node, explicit_defaults, dfl.layout_defaults);
format_defaults.to_xml(node, explicit_defaults, dfl.format_defaults);
@@ -197,6 +209,8 @@ void text_symbolizer_properties::add_expressions(expression_set & output) const
if (is_expression(expressions.allow_overlap)) output.insert(util::get<expression_ptr>(expressions.allow_overlap));
if (is_expression(expressions.largest_bbox_only)) output.insert(util::get<expression_ptr>(expressions.largest_bbox_only));
if (is_expression(expressions.upright)) output.insert(util::get<expression_ptr>(expressions.upright));
+ if (is_expression(expressions.grid_cell_width)) output.insert(util::get<expression_ptr>(expressions.grid_cell_width));
+ if (is_expression(expressions.grid_cell_height)) output.insert(util::get<expression_ptr>(expressions.grid_cell_height));
layout_defaults.add_expressions(output);
format_defaults.add_expressions(output);
=====================================
test/unit/geometry/grid_vertex_converter.cpp
=====================================
--- /dev/null
+++ b/test/unit/geometry/grid_vertex_converter.cpp
@@ -0,0 +1,103 @@
+#include "catch.hpp"
+
+#include <mapnik/grid_vertex_converter.hpp>
+
+TEST_CASE("spiral_iterator") {
+
+SECTION("sprial 3x3") {
+
+ mapnik::geometry::spiral_iterator si(3);
+ const mapnik::geometry::point<int> points[] = {
+ { 0, 0 }, { 1, 0 }, { 1, -1 },
+ { 0, -1 }, { -1, -1 }, { -1, 0 },
+ { -1, 1 }, { 0, 1 }, { 1, 1 } };
+
+ const std::size_t points_size = std::extent<decltype(points)>::value;
+
+ int x, y;
+ std::size_t index = 0;
+
+ while (si.vertex(&x, &y))
+ {
+ REQUIRE(index < points_size);
+
+ CHECK(x == points[index].x);
+ CHECK(y == points[index].y);
+
+ index++;
+ }
+
+ CHECK(index == points_size);
+}
+
+}
+
+TEST_CASE("grid_vertex_converter") {
+
+SECTION("empty polygon") {
+
+ mapnik::geometry::polygon<double> poly;
+ using path_type = mapnik::geometry::polygon_vertex_adapter<double>;
+ path_type path(poly);
+ using converter_type = mapnik::geometry::grid_vertex_converter<path_type, double>;
+ converter_type gvc(path, 10.0, 10.0, 1.0);
+
+ double x, y;
+ unsigned cmd = gvc.vertex(&x, &y);
+
+ CHECK(cmd == mapnik::SEG_END);
+
+}
+
+SECTION("grid of a square") {
+
+ mapnik::geometry::polygon<double> poly;
+ auto & exterior_ring = poly.exterior_ring;
+ exterior_ring.emplace_back(-10, -10);
+ exterior_ring.emplace_back( 10, -10);
+ exterior_ring.emplace_back( 10, 10);
+ exterior_ring.emplace_back(-10, 10);
+ exterior_ring.emplace_back(-10, -10);
+
+ using path_type = mapnik::geometry::polygon_vertex_adapter<double>;
+ path_type path(poly);
+ using converter_type = mapnik::geometry::grid_vertex_converter<path_type, double>;
+ converter_type gvc(path, 3.0, 3.0, 1.0);
+
+ const mapnik::geometry::point<double> points[] = {
+ { 0, 0 }, { 3, 0 }, { 3, 3 }, { 0, 3 },
+ { -3, 3 }, { -3, 0 }, { -3, -3 }, { 0, -3 },
+ { 3, -3 }, { 6, -3 }, { 6, 0 }, { 6, 3 },
+ { 6, 6 }, { 3, 6 }, { 0, 6 }, { -3, 6 },
+ { -6, 6 }, { -6, 3 }, { -6, 0 }, { -6, -3 },
+ { -6, -6 }, { -3, -6 }, { 0, -6 }, { 3, -6 },
+ { 6, -6 }, { 9, -6 }, { 9, -3 }, { 9, 0 },
+ { 9, 3 }, { 9, 6 }, { 9, 9 }, { 6, 9 },
+ { 3, 9 }, { 0, 9 }, { -3, 9 }, { -6, 9 },
+ { -9, 9 }, { -9, 6 }, { -9, 3 }, { -9, 0 },
+ { -9, -3 }, { -9, -6 }, { -9, -9 }, { -6, -9 },
+ { -3, -9 }, { 0, -9 }, { 3, -9 }, { 6, -9 },
+ { 9, -9 } };
+ const std::size_t points_size = std::extent<decltype(points)>::value;
+
+ double x, y;
+ unsigned cmd = mapnik::SEG_END;
+ std::size_t index = 0;
+
+ while ((cmd = gvc.vertex(&x, &y)) != mapnik::SEG_END)
+ {
+ REQUIRE(index < points_size);
+
+ CHECK(cmd == mapnik::SEG_MOVETO);
+ CHECK(x == Approx(points[index].x));
+ CHECK(y == Approx(points[index].y));
+
+ index++;
+ }
+
+ CHECK(index == points_size);
+ CHECK(cmd == mapnik::SEG_END);
+}
+
+}
+
View it on GitLab: https://salsa.debian.org/debian-gis-team/mapnik/commit/07e55bf93952a69e768b531f655e1e07ac7652b2
---
View it on GitLab: https://salsa.debian.org/debian-gis-team/mapnik/commit/07e55bf93952a69e768b531f655e1e07ac7652b2
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.alioth.debian.org/pipermail/pkg-grass-devel/attachments/20180305/874893d0/attachment-0001.html>
More information about the Pkg-grass-devel
mailing list