[mapnik] 01/04: Imported Upstream version 3.0.9~rc3+ds
Sebastiaan Couwenberg
sebastic at moszumanska.debian.org
Tue Nov 24 23:42:44 UTC 2015
This is an automated email from the git hooks/post-receive script.
sebastic pushed a commit to branch master
in repository mapnik.
commit 991733b5b18d411a7c87ed94a1310ec6e325e2e9
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date: Tue Nov 24 23:54:06 2015 +0100
Imported Upstream version 3.0.9~rc3+ds
---
CHANGELOG.md | 14 +-
deps/agg/src/agg_pixfmt_rgba.cpp | 8 +-
deps/boost/gil/extension/toolbox/hsl.hpp | 4 +-
deps/boost/gil/extension/toolbox/hsv.hpp | 4 +-
include/mapnik/geometry_centroid.hpp | 50 +++--
include/mapnik/geometry_is_empty.hpp | 83 ++++++++-
include/mapnik/geometry_remove_empty.hpp | 77 ++++++++
include/mapnik/image_scaling.hpp | 17 +-
include/mapnik/image_scaling_traits.hpp | 25 +--
.../json/feature_collection_grammar_impl.hpp | 13 +-
.../renderer_common/process_raster_symbolizer.hpp | 8 +-
include/mapnik/simplify_converter.hpp | 32 ++--
include/mapnik/span_image_filter.h | 178 ++++++++++++++++++
include/mapnik/warp.hpp | 11 +-
plugins/input/csv/build.py | 2 +-
plugins/input/csv/csv_utils.hpp | 26 +--
plugins/input/geojson/geojson_datasource.cpp | 46 +++--
plugins/input/postgis/connection_manager.hpp | 2 +-
src/box2d.cpp | 14 +-
src/grid/grid_renderer.cpp | 3 +-
src/image_scaling.cpp | 34 ++--
src/map.cpp | 2 +-
src/warp.cpp | 47 +++--
test/unit/datasource/geojson.cpp | 45 ++++-
test/unit/datasource/shapeindex.cpp | 120 ++++++++++++
test/unit/geometry/centroid.cpp | 205 +++++++++++++++++++++
test/unit/geometry/has_empty.cpp | 150 +++++++++++++++
test/unit/geometry/is_empty.cpp | 117 ++++++++++++
test/unit/geometry/label_algo_test.cpp | 33 ----
test/unit/geometry/remove_empty.cpp | 53 ++++++
utils/mapnik-index/build.py | 2 +-
utils/mapnik-index/mapnik-index.cpp | 14 +-
utils/mapnik-index/process_geojson_file.cpp | 41 ++++-
utils/mapnik-index/process_geojson_file.hpp | 2 +-
utils/shapefile/shapefile_reader.py | 14 +-
utils/shapeindex/shapeindex.cpp | 44 +++--
36 files changed, 1343 insertions(+), 197 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 933a72b..d33353a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,11 +10,21 @@ For a complete change history, see the git log.
Released:
-(Packaged from )
+(Work-in-progress)
#### Summary
- - Fixed offsetting of complex paths and sharp angles (https://github.com/mapnik/mapnik/pull/3160)
+ - Fixed offsetting of complex paths and sharp angles (https://github.com/mapnik/mapnik/pull/3160) (via @winni159)
+ - Fixed mapnik.util.variant issue when compiling with gcc-5.x and SSO enabled by default (https://github.com/mapnik/mapnik/issues/3103) (via @nkovacs)
+ - Fixed issue with complex scripts where some character sequences weren't rendered correctly (https://github.com/mapnik/mapnik/issues/3050) (via @jkroll20)
+ - Revived postgis.input tests
+ - JSON: geometry grammar has been refactored and optimized to have expectation points
+ - Filled missing specializations for value_bool in `mapnik::value` comparison operators
+ - `mapnik.Image` - fixed copy semantics implementation for internal buffer
+ - JSON parsing: unified error_handler across all grammars
+ - Improved unit test coverage
+ - Raster scaling: fixed nodata handling, acurracy when working with small floats and clipping floats by \[0; 255\] (https://github.com/mapnik/mapnik/pull/3147)
+ - Centroid algorithm: fixed invalid input handling, particularly empty geometries (https://github.com/mapnik/mapnik/pull/3185)
## 3.0.8
diff --git a/deps/agg/src/agg_pixfmt_rgba.cpp b/deps/agg/src/agg_pixfmt_rgba.cpp
index 45e0b19..c19e9d6 100644
--- a/deps/agg/src/agg_pixfmt_rgba.cpp
+++ b/deps/agg/src/agg_pixfmt_rgba.cpp
@@ -1,14 +1,8 @@
#include "agg_pixfmt_rgba.h"
-// boost
#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wunused-parameter"
-#pragma GCC diagnostic ignored "-Wc++11-narrowing"
-#pragma GCC diagnostic ignored "-Wunused-local-typedef"
-#pragma GCC diagnostic ignored "-Wshadow"
-#pragma GCC diagnostic ignored "-Wsign-conversion"
-#pragma GCC diagnostic ignored "-Wconversion"
+#include <mapnik/warning_ignore.hpp>
#include <boost/gil/gil_all.hpp>
#include <boost/gil/extension/toolbox/hsv.hpp>
#include <boost/gil/extension/toolbox/hsl.hpp>
diff --git a/deps/boost/gil/extension/toolbox/hsl.hpp b/deps/boost/gil/extension/toolbox/hsl.hpp
index c77dd72..b1b9c1b 100644
--- a/deps/boost/gil/extension/toolbox/hsl.hpp
+++ b/deps/boost/gil/extension/toolbox/hsl.hpp
@@ -15,9 +15,7 @@
////////////////////////////////////////////////////////////////////////////////////////
#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wunused-parameter"
-#pragma GCC diagnostic ignored "-Wc++11-narrowing"
-#pragma GCC diagnostic ignored "-Wunused-local-typedef"
+#include <mapnik/warning_ignore.hpp>
#include <boost/gil/gil_all.hpp>
#pragma GCC diagnostic pop
diff --git a/deps/boost/gil/extension/toolbox/hsv.hpp b/deps/boost/gil/extension/toolbox/hsv.hpp
index 5195cc2..dc6e14e 100644
--- a/deps/boost/gil/extension/toolbox/hsv.hpp
+++ b/deps/boost/gil/extension/toolbox/hsv.hpp
@@ -15,9 +15,7 @@
////////////////////////////////////////////////////////////////////////////////////////
#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wunused-parameter"
-#pragma GCC diagnostic ignored "-Wc++11-narrowing"
-#pragma GCC diagnostic ignored "-Wunused-local-typedef"
+#include <mapnik/warning_ignore.hpp>
#include <boost/gil/gil_all.hpp>
#pragma GCC diagnostic pop
diff --git a/include/mapnik/geometry_centroid.hpp b/include/mapnik/geometry_centroid.hpp
index 71d0c07..590ba48 100644
--- a/include/mapnik/geometry_centroid.hpp
+++ b/include/mapnik/geometry_centroid.hpp
@@ -26,6 +26,8 @@
#include <mapnik/geometry.hpp>
#include <mapnik/geometry_adapters.hpp>
#include <boost/geometry/algorithms/centroid.hpp>
+#include <mapnik/geometry_is_empty.hpp>
+#include <mapnik/geometry_remove_empty.hpp>
namespace mapnik { namespace geometry {
@@ -57,40 +59,64 @@ struct geometry_centroid
result_type operator() (point<T> const& geom) const
{
- boost::geometry::centroid(geom, pt_);
- return true;
+ return centroid_simple(geom);
}
result_type operator() (line_string<T> const& geom) const
{
- boost::geometry::centroid(geom, pt_);
- return true;
+ return centroid_simple(geom);
}
result_type operator() (polygon<T> const& geom) const
{
- boost::geometry::centroid(geom, pt_);
- return true;
+ return centroid_simple(geom);
}
result_type operator() (multi_point<T> const& geom) const
{
- boost::geometry::centroid(geom, pt_);
- return true;
+ return centroid_simple(geom);
}
result_type operator() (multi_line_string<T> const& geom) const
{
- boost::geometry::centroid(geom, pt_);
- return true;
+ return centroid_multi(geom);
}
result_type operator() (multi_polygon<T> const& geom) const
{
- boost::geometry::centroid(geom, pt_);
- return true;
+ return centroid_multi(geom);
}
+
point<T> & pt_;
+
+private:
+ template <typename Geom>
+ result_type centroid_simple(Geom const & geom) const
+ {
+ try
+ {
+ boost::geometry::centroid(geom, pt_);
+ return true;
+ }
+ catch (boost::geometry::centroid_exception const & e)
+ {
+ return false;
+ }
+ }
+
+ template <typename Geom>
+ result_type centroid_multi(Geom const & geom) const
+ {
+// https://github.com/mapnik/mapnik/issues/3169
+#if BOOST_VERSION <= 105900
+ if (mapnik::geometry::has_empty(geom))
+ {
+ Geom stripped = mapnik::geometry::remove_empty(geom);
+ return centroid_simple(stripped);
+ }
+#endif
+ return centroid_simple(geom);
+ }
};
}
diff --git a/include/mapnik/geometry_is_empty.hpp b/include/mapnik/geometry_is_empty.hpp
index 5d017aa..953bddc 100644
--- a/include/mapnik/geometry_is_empty.hpp
+++ b/include/mapnik/geometry_is_empty.hpp
@@ -72,13 +72,88 @@ struct geometry_is_empty
}
template <typename T>
- bool operator() (T const& geom) const
+ bool operator() (T const&) const
{
return true;
}
};
+struct geometry_has_empty
+{
+ bool operator() (mapnik::geometry::geometry<double> const& geom) const
+ {
+ return mapnik::util::apply_visitor(*this, geom);
+ }
+
+ bool operator() (mapnik::geometry::geometry_empty const&) const
+ {
+ return false;
+ }
+
+ bool operator() (mapnik::geometry::point<double> const&) const
+ {
+ return false;
+ }
+
+ bool operator() (mapnik::geometry::line_string<double> const&) const
+ {
+ return false;
+ }
+
+ bool operator() (mapnik::geometry::polygon<double> const&) const
+ {
+ return false;
+ }
+
+ bool operator() (mapnik::geometry::multi_point<double> const&) const
+ {
+ return false;
+ }
+
+ bool operator() (mapnik::geometry::multi_line_string<double> const& geom) const
+ {
+ return test_multigeometry(geom);
+ }
+
+ bool operator() (mapnik::geometry::multi_polygon<double> const& geom) const
+ {
+ return test_multigeometry(geom);
+ }
+
+ bool operator() (mapnik::geometry::geometry_collection<double> const& geom) const
+ {
+ for (auto const & item : geom)
+ {
+ if (geometry_is_empty()(item) || (*this)(item))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ template <typename T>
+ bool operator() (T const&) const
+ {
+ return true;
+ }
+
+private:
+ template <typename T>
+ bool test_multigeometry(T const & geom) const
+ {
+ for (auto const & item : geom)
+ {
+ if (item.empty())
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+};
+
}
template <typename GeomType>
@@ -87,6 +162,12 @@ inline bool is_empty(GeomType const& geom)
return detail::geometry_is_empty()(geom);
}
+template <typename GeomType>
+inline bool has_empty(GeomType const& geom)
+{
+ return detail::geometry_has_empty()(geom);
+}
+
}}
#endif // MAPNIK_GEOMETRY_IS_EMPTY_HPP
diff --git a/include/mapnik/geometry_remove_empty.hpp b/include/mapnik/geometry_remove_empty.hpp
new file mode 100644
index 0000000..9838b5a
--- /dev/null
+++ b/include/mapnik/geometry_remove_empty.hpp
@@ -0,0 +1,77 @@
+/*****************************************************************************
+ *
+ * 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_GEOMETRY_REMOVE_EMPTY_HPP
+#define MAPNIK_GEOMETRY_REMOVE_EMPTY_HPP
+
+#include <mapnik/geometry.hpp>
+#include <mapnik/geometry_is_empty.hpp>
+
+namespace mapnik { namespace geometry {
+
+namespace detail {
+
+struct geometry_remove_empty
+{
+ mapnik::geometry::multi_line_string<double> operator() (mapnik::geometry::multi_line_string<double> const & geom) const
+ {
+ return remove_empty(geom);
+ }
+
+ mapnik::geometry::multi_polygon<double> operator() (mapnik::geometry::multi_polygon<double> const & geom) const
+ {
+ return remove_empty(geom);
+ }
+
+ template <typename T>
+ T operator() (T const & geom) const
+ {
+ return geom;
+ }
+
+private:
+ template <typename T>
+ T remove_empty(T const & geom) const
+ {
+ T new_geom;
+ for (auto const & g : geom)
+ {
+ if (!g.empty())
+ {
+ new_geom.emplace_back(g);
+ }
+ }
+ return new_geom;
+ }
+};
+
+}
+
+template <typename GeomType>
+inline GeomType remove_empty(GeomType const& geom)
+{
+ return detail::geometry_remove_empty()(geom);
+}
+
+}}
+
+#endif // MAPNIK_GEOMETRY_REMOVE_EMPTY_HPP
diff --git a/include/mapnik/image_scaling.hpp b/include/mapnik/image_scaling.hpp
index ad4954e..ddae368 100644
--- a/include/mapnik/image_scaling.hpp
+++ b/include/mapnik/image_scaling.hpp
@@ -67,7 +67,22 @@ MAPNIK_DECL void scale_image_agg(T & target, T const& source,
double image_ratio_y,
double x_off_f,
double y_off_f,
- double filter_factor);
+ double filter_factor,
+ boost::optional<double> const & nodata_value);
+template <typename T>
+inline void scale_image_agg(T & target, T const& source,
+ scaling_method_e scaling_method,
+ double image_ratio_x,
+ double image_ratio_y,
+ double x_off_f,
+ double y_off_f,
+ double filter_factor)
+{
+ scale_image_agg(target, source, scaling_method,
+ image_ratio_x,image_ratio_y,
+ x_off_f, y_off_f, filter_factor,
+ boost::optional<double>());
+}
}
#endif // MAPNIK_IMAGE_SCALING_HPP
diff --git a/include/mapnik/image_scaling_traits.hpp b/include/mapnik/image_scaling_traits.hpp
index e2d0220..69eec5a 100644
--- a/include/mapnik/image_scaling_traits.hpp
+++ b/include/mapnik/image_scaling_traits.hpp
@@ -23,6 +23,9 @@
#ifndef MAPNIK_IMAGE_SCALING_TRAITS_HPP
#define MAPNIK_IMAGE_SCALING_TRAITS_HPP
+// mapnik
+#include <mapnik/span_image_filter.h>
+
// agg
#include "agg_image_accessors.h"
#include "agg_pixfmt_rgba.h"
@@ -45,7 +48,7 @@ struct agg_scaling_traits<image_rgba8>
using interpolator_type = agg::span_interpolator_linear<>;
using img_src_type = agg::image_accessor_clone<pixfmt_pre>;
using span_image_filter = agg::span_image_filter_rgba_nn<img_src_type,interpolator_type>;
- using span_image_resample_affine = agg::span_image_resample_rgba_affine<img_src_type>;
+ using span_image_resample_affine = span_image_resample_rgba_affine<img_src_type>;
};
@@ -57,7 +60,7 @@ struct agg_scaling_traits<image_gray8>
using interpolator_type = agg::span_interpolator_linear<>;
using img_src_type = agg::image_accessor_clone<pixfmt_pre>;
using span_image_filter = agg::span_image_filter_gray_nn<img_src_type,interpolator_type>;
- using span_image_resample_affine = agg::span_image_resample_gray_affine<img_src_type>;
+ using span_image_resample_affine = span_image_resample_gray_affine<img_src_type>;
};
template <>
@@ -68,7 +71,7 @@ struct agg_scaling_traits<image_gray8s>
using interpolator_type = agg::span_interpolator_linear<>;
using img_src_type = agg::image_accessor_clone<pixfmt_pre>;
using span_image_filter = agg::span_image_filter_gray_nn<img_src_type,interpolator_type>;
- using span_image_resample_affine = agg::span_image_resample_gray_affine<img_src_type>;
+ using span_image_resample_affine = span_image_resample_gray_affine<img_src_type>;
};
template <>
@@ -79,7 +82,7 @@ struct agg_scaling_traits<image_gray16>
using interpolator_type = agg::span_interpolator_linear<>;
using img_src_type = agg::image_accessor_clone<pixfmt_pre>;
using span_image_filter = agg::span_image_filter_gray_nn<img_src_type,interpolator_type>;
- using span_image_resample_affine = agg::span_image_resample_gray_affine<img_src_type>;
+ using span_image_resample_affine = span_image_resample_gray_affine<img_src_type>;
};
template <>
@@ -90,7 +93,7 @@ struct agg_scaling_traits<image_gray16s>
using interpolator_type = agg::span_interpolator_linear<>;
using img_src_type = agg::image_accessor_clone<pixfmt_pre>;
using span_image_filter = agg::span_image_filter_gray_nn<img_src_type,interpolator_type>;
- using span_image_resample_affine = agg::span_image_resample_gray_affine<img_src_type>;
+ using span_image_resample_affine = span_image_resample_gray_affine<img_src_type>;
};
template <>
@@ -101,7 +104,7 @@ struct agg_scaling_traits<image_gray32>
using interpolator_type = agg::span_interpolator_linear<>;
using img_src_type = agg::image_accessor_clone<pixfmt_pre>;
using span_image_filter = agg::span_image_filter_gray_nn<img_src_type,interpolator_type>;
- using span_image_resample_affine = agg::span_image_resample_gray_affine<img_src_type>;
+ using span_image_resample_affine = span_image_resample_gray_affine<img_src_type>;
};
template <>
@@ -112,7 +115,7 @@ struct agg_scaling_traits<image_gray32s>
using interpolator_type = agg::span_interpolator_linear<>;
using img_src_type = agg::image_accessor_clone<pixfmt_pre>;
using span_image_filter = agg::span_image_filter_gray_nn<img_src_type,interpolator_type>;
- using span_image_resample_affine = agg::span_image_resample_gray_affine<img_src_type>;
+ using span_image_resample_affine = span_image_resample_gray_affine<img_src_type>;
};
template <>
@@ -123,7 +126,7 @@ struct agg_scaling_traits<image_gray32f>
using interpolator_type = agg::span_interpolator_linear<>;
using img_src_type = agg::image_accessor_clone<pixfmt_pre>;
using span_image_filter = agg::span_image_filter_gray_nn<img_src_type,interpolator_type>;
- using span_image_resample_affine = agg::span_image_resample_gray_affine<img_src_type>;
+ using span_image_resample_affine = span_image_resample_gray_affine<img_src_type>;
};
template <>
@@ -134,7 +137,7 @@ struct agg_scaling_traits<image_gray64>
using interpolator_type = agg::span_interpolator_linear<>;
using img_src_type = agg::image_accessor_clone<pixfmt_pre>;
using span_image_filter = agg::span_image_filter_gray_nn<img_src_type,interpolator_type>;
- using span_image_resample_affine = agg::span_image_resample_gray_affine<img_src_type>;
+ using span_image_resample_affine = span_image_resample_gray_affine<img_src_type>;
};
template <>
@@ -145,7 +148,7 @@ struct agg_scaling_traits<image_gray64s>
using interpolator_type = agg::span_interpolator_linear<>;
using img_src_type = agg::image_accessor_clone<pixfmt_pre>;
using span_image_filter = agg::span_image_filter_gray_nn<img_src_type,interpolator_type>;
- using span_image_resample_affine = agg::span_image_resample_gray_affine<img_src_type>;
+ using span_image_resample_affine = span_image_resample_gray_affine<img_src_type>;
};
template <>
@@ -156,7 +159,7 @@ struct agg_scaling_traits<image_gray64f>
using interpolator_type = agg::span_interpolator_linear<>;
using img_src_type = agg::image_accessor_clone<pixfmt_pre>;
using span_image_filter = agg::span_image_filter_gray_nn<img_src_type,interpolator_type>;
- using span_image_resample_affine = agg::span_image_resample_gray_affine<img_src_type>;
+ using span_image_resample_affine = span_image_resample_gray_affine<img_src_type>;
};
template <typename Filter>
diff --git a/include/mapnik/json/feature_collection_grammar_impl.hpp b/include/mapnik/json/feature_collection_grammar_impl.hpp
index 49ee249..b2836af 100644
--- a/include/mapnik/json/feature_collection_grammar_impl.hpp
+++ b/include/mapnik/json/feature_collection_grammar_impl.hpp
@@ -54,24 +54,23 @@ feature_collection_grammar<Iterator,FeatureType, FeatureCallback,ErrorHandler>::
start = feature_collection(_r1, _r2, _r3)
;
- feature_collection = lit('{') >> (type | features(_r1, _r2, _r3) | feature_g.json_.key_value) % lit(',') >> lit('}')
+ feature_collection = lit('{') > (type | features(_r1, _r2, _r3) | feature_g.json_.key_value) % lit(',') > lit('}')
;
- type = lit("\"type\"") >> lit(':') >> lit("\"FeatureCollection\"")
+ type = lit("\"type\"") > lit(':') > lit("\"FeatureCollection\"")
;
features = lit("\"features\"")
- >> lit(':')
- >> lit('[')
- >> -(feature(_r1, _r2, _r3) [_r2 +=1] % lit(','))
- >> lit(']')
+ > lit(':') > lit('[') >
+ ( lit(']') | ((feature(_r1, _r2, _r3) [_r2 +=1] % lit(',')) > lit(']')))
;
feature = eps[_a = phoenix::construct<mapnik::feature_ptr>(new_<mapnik::feature_impl>(_r1, _r2))]
- >> feature_g(*_a)[on_feature(_r3,_a)]
+ > feature_g(*_a)[on_feature(_r3,_a)]
;
start.name("start");
+ feature_collection.name("FeatureCollection");
type.name("type");
features.name("features");
feature.name("feature");
diff --git a/include/mapnik/renderer_common/process_raster_symbolizer.hpp b/include/mapnik/renderer_common/process_raster_symbolizer.hpp
index 5646785..f8ce32d 100644
--- a/include/mapnik/renderer_common/process_raster_symbolizer.hpp
+++ b/include/mapnik/renderer_common/process_raster_symbolizer.hpp
@@ -77,7 +77,7 @@ struct image_dispatcher
if (need_scaling_)
{
image_rgba8 data_out(width_, height_, true, true);
- scale_image_agg(data_out, data_in, method_, scale_x_, scale_y_, 0.0, 0.0, filter_factor_);
+ scale_image_agg(data_out, data_in, method_, scale_x_, scale_y_, 0.0, 0.0, filter_factor_, nodata_);
composite_(data_out, comp_op_, opacity_, start_x_, start_y_);
}
else
@@ -95,7 +95,7 @@ struct image_dispatcher
if (need_scaling_)
{
image_type data_out(width_, height_);
- scale_image_agg(data_out, data_in, method_, scale_x_, scale_y_, 0.0, 0.0, filter_factor_);
+ scale_image_agg(data_out, data_in, method_, scale_x_, scale_y_, 0.0, 0.0, filter_factor_, nodata_);
if (colorizer) colorizer->colorize(dst, data_out, nodata_, feature_);
}
else
@@ -157,7 +157,7 @@ struct image_warp_dispatcher
void operator() (image_rgba8 const& data_in) const
{
image_rgba8 data_out(width_, height_, true, true);
- warp_image(data_out, data_in, prj_trans_, target_ext_, source_ext_, offset_x_, offset_y_, mesh_size_, scaling_method_, filter_factor_);
+ warp_image(data_out, data_in, prj_trans_, target_ext_, source_ext_, offset_x_, offset_y_, mesh_size_, scaling_method_, filter_factor_, nodata_);
composite_(data_out, comp_op_, opacity_, start_x_, start_y_);
}
@@ -167,7 +167,7 @@ struct image_warp_dispatcher
using image_type = T;
image_type data_out(width_, height_);
if (nodata_) data_out.set(*nodata_);
- warp_image(data_out, data_in, prj_trans_, target_ext_, source_ext_, offset_x_, offset_y_, mesh_size_, scaling_method_, filter_factor_);
+ warp_image(data_out, data_in, prj_trans_, target_ext_, source_ext_, offset_x_, offset_y_, mesh_size_, scaling_method_, filter_factor_, nodata_);
image_rgba8 dst(width_, height_);
raster_colorizer_ptr colorizer = get<raster_colorizer_ptr>(sym_, keys::colorizer);
if (colorizer) colorizer->colorize(dst, data_out, nodata_, feature_);
diff --git a/include/mapnik/simplify_converter.hpp b/include/mapnik/simplify_converter.hpp
index f107a8d..77d3674 100644
--- a/include/mapnik/simplify_converter.hpp
+++ b/include/mapnik/simplify_converter.hpp
@@ -106,7 +106,7 @@ public:
initial,
process,
closing,
- end,
+ done,
cache
};
@@ -210,7 +210,7 @@ private:
if (status_ == closing)
{
*x = *y = 0.0;
- status_ = end;
+ status_ = done;
return SEG_CLOSE;
}
@@ -237,7 +237,7 @@ private:
{
// The previous vertex was already output in the previous call.
// We can now safely output SEG_CLOSE.
- status_ = end;
+ status_ = done;
}
else
{
@@ -268,11 +268,11 @@ private:
}
template <typename Iterator>
- bool fit_sleeve(Iterator itr, Iterator itr_end, vertex2d const& v)
+ bool fit_sleeve(Iterator itr, Iterator end, vertex2d const& v)
{
sleeve s(*itr,v,tolerance_);
++itr; // skip first vertex
- for (; itr!=itr_end; ++itr)
+ for (; itr != end; ++itr)
{
if (!s.inside(*itr))
{
@@ -486,14 +486,14 @@ private:
return status_ = process;
}
- void RDP(std::vector<vertex2d>& vertices, const size_t start, const size_t end)
+ void RDP(std::vector<vertex2d>& vertices, const size_t first, const size_t last)
{
// Squared length of a vector
auto sqlen = [] (vertex2d const& vec) { return vec.x*vec.x + vec.y*vec.y; };
// Compute square distance of p to a line segment
auto segment_distance = [&sqlen] (vertex2d const& p, vertex2d const& a, vertex2d const& b, vertex2d const& dir, double dir_sq_len)
{
- // Special case where segment has same start and end point at which point we are just doing a radius check
+ // Special case where segment has same first and last point at which point we are just doing a radius check
if (dir_sq_len == 0)
{
return sqlen(vertex2d(p.x - b.x, p.y - b.y, SEG_END));
@@ -525,15 +525,15 @@ private:
};
// Compute the directional vector along the segment
- vertex2d dir = vertex2d(vertices[end].x - vertices[start].x, vertices[end].y - vertices[start].y, SEG_END);
+ vertex2d dir = vertex2d(vertices[last].x - vertices[first].x, vertices[last].y - vertices[first].y, SEG_END);
double dir_sq_len = sqlen(dir);
// Find the point with the maximum distance from this line segment
double max = std::numeric_limits<double>::min();
size_t keeper = 0;
- for (size_t i = start + 1; i < end; ++i)
+ for (size_t i = first + 1; i < last; ++i)
{
- double d = segment_distance(vertices[i], vertices[start], vertices[end], dir, dir_sq_len);
+ double d = segment_distance(vertices[i], vertices[first], vertices[last], dir, dir_sq_len);
if (d > max)
{
keeper = i;
@@ -546,19 +546,19 @@ private:
if (max > tolerance_ * tolerance_)
{
// Make sure not to smooth out the biggest outlier (keeper)
- if (keeper - start != 1)
+ if (keeper - first != 1)
{
- RDP(vertices, start, keeper);
+ RDP(vertices, first, keeper);
}
- if (end - keeper != 1)
+ if (last - keeper != 1)
{
- RDP(vertices, keeper, end);
+ RDP(vertices, keeper, last);
}
- }// Everyone between the start and the end was close enough to the line
+ }// Everyone between the first and the last was close enough to the line
else
{
// Mark each of them as discarded
- for (size_t i = start + 1; i < end; ++i)
+ for (size_t i = first + 1; i < last; ++i)
{
vertices[i].cmd = SEG_END;
}
diff --git a/include/mapnik/span_image_filter.h b/include/mapnik/span_image_filter.h
new file mode 100644
index 0000000..cd84301
--- /dev/null
+++ b/include/mapnik/span_image_filter.h
@@ -0,0 +1,178 @@
+/*****************************************************************************
+ *
+ * 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_SPAN_IMAGE_FILTER_INCLUDED
+#define MAPNIK_SPAN_IMAGE_FILTER_INCLUDED
+
+#include "agg_span_image_filter_gray.h"
+#include "agg_span_image_filter_rgba.h"
+
+#include <limits>
+
+namespace mapnik
+{
+
+template<class Source>
+class span_image_resample_gray_affine : public agg::span_image_resample_affine<Source>
+{
+public:
+ using source_type = Source;
+ using color_type = typename source_type::color_type;
+ using base_type = agg::span_image_resample_affine<source_type>;
+ using interpolator_type = typename base_type::interpolator_type;
+ using value_type = typename color_type::value_type;
+ using long_type = typename color_type::long_type;
+
+ enum base_scale_e
+ {
+ downscale_shift = agg::image_filter_shift,
+ base_mask = color_type::base_mask
+ };
+
+ span_image_resample_gray_affine(source_type & src,
+ interpolator_type & inter,
+ agg::image_filter_lut const & filter,
+ boost::optional<value_type> const & nodata_value) :
+ base_type(src, inter, filter),
+ nodata_value_(nodata_value)
+ { }
+
+ void generate(color_type* span, int x, int y, unsigned len)
+ {
+ base_type::interpolator().begin(x + base_type::filter_dx_dbl(),
+ y + base_type::filter_dy_dbl(), len);
+
+ long_type fg;
+
+ int diameter = base_type::filter().diameter();
+ int filter_scale = diameter << agg::image_subpixel_shift;
+ int radius_x = (diameter * base_type::m_rx) >> 1;
+ int radius_y = (diameter * base_type::m_ry) >> 1;
+ int len_x_lr =
+ (diameter * base_type::m_rx + agg::image_subpixel_mask) >>
+ agg::image_subpixel_shift;
+
+ const agg::int16* weight_array = base_type::filter().weight_array();
+
+ do
+ {
+ base_type::interpolator().coordinates(&x, &y);
+
+ int src_x = x >> agg::image_subpixel_shift;
+ int src_y = y >> agg::image_subpixel_shift;
+ const value_type* pix = reinterpret_cast<const value_type*>(base_type::source().span(src_x, src_y, 0));
+ if (nodata_value_ && *nodata_value_ == *pix)
+ {
+ span->v = *nodata_value_;
+ span->a = base_mask;
+ ++span;
+ ++base_type::interpolator();
+ continue;
+ }
+
+ x += base_type::filter_dx_int() - radius_x;
+ y += base_type::filter_dy_int() - radius_y;
+
+ fg = 0;
+
+ int y_lr = y >> agg::image_subpixel_shift;
+ int y_hr = ((agg::image_subpixel_mask - (y & agg::image_subpixel_mask)) *
+ base_type::m_ry_inv) >>
+ agg::image_subpixel_shift;
+ int total_weight = 0;
+ int x_lr = x >> agg::image_subpixel_shift;
+ int x_hr = ((agg::image_subpixel_mask - (x & agg::image_subpixel_mask)) *
+ base_type::m_rx_inv) >>
+ agg::image_subpixel_shift;
+
+ int x_hr2 = x_hr;
+ const value_type* fg_ptr = reinterpret_cast<const value_type*>(base_type::source().span(x_lr, y_lr, len_x_lr));
+ for(;;)
+ {
+ int weight_y = weight_array[y_hr];
+ x_hr = x_hr2;
+ for(;;)
+ {
+ int weight = (weight_y * weight_array[x_hr] +
+ agg::image_filter_scale) >>
+ downscale_shift;
+ if (!nodata_value_ || *nodata_value_ != *fg_ptr)
+ {
+ fg += *fg_ptr * weight;
+ total_weight += weight;
+ }
+ x_hr += base_type::m_rx_inv;
+ if (x_hr >= filter_scale) break;
+ fg_ptr = reinterpret_cast<const value_type*>(base_type::source().next_x());
+ }
+ y_hr += base_type::m_ry_inv;
+ if (y_hr >= filter_scale) break;
+ fg_ptr = reinterpret_cast<const value_type*>(base_type::source().next_y());
+ }
+
+ fg /= total_weight;
+ if (fg < std::numeric_limits<value_type>::min())
+ {
+ span->v = std::numeric_limits<value_type>::min();
+ }
+ else if (fg > std::numeric_limits<value_type>::max())
+ {
+ span->v = std::numeric_limits<value_type>::max();
+ }
+ else
+ {
+ span->v = static_cast<value_type>(fg);
+ }
+ span->a = base_mask;
+
+ ++span;
+ ++base_type::interpolator();
+ } while(--len);
+ }
+
+private:
+ boost::optional<value_type> nodata_value_;
+};
+
+template<class Source>
+class span_image_resample_rgba_affine : public agg::span_image_resample_rgba_affine<Source>
+{
+public:
+ using source_type = Source;
+ using color_type = typename source_type::color_type;
+ using order_type = typename source_type::order_type;
+ using base_type = agg::span_image_resample_rgba_affine<source_type>;
+ using interpolator_type = typename base_type::interpolator_type;
+ using value_type = typename color_type::value_type;
+ using long_type = typename color_type::long_type;
+
+ span_image_resample_rgba_affine(source_type & src,
+ interpolator_type & inter,
+ agg::image_filter_lut const & filter,
+ boost::optional<value_type> const & nodata_value) :
+ agg::span_image_resample_rgba_affine<Source>(src, inter, filter)
+ { }
+};
+
+}
+
+#endif
diff --git a/include/mapnik/warp.hpp b/include/mapnik/warp.hpp
index 0bf3332..abf0108 100644
--- a/include/mapnik/warp.hpp
+++ b/include/mapnik/warp.hpp
@@ -38,13 +38,20 @@ MAPNIK_DECL void reproject_and_scale_raster(raster & target,
proj_transform const& prj_trans,
double offset_x, double offset_y,
unsigned mesh_size,
- scaling_method_e scaling_method);
+ scaling_method_e scaling_method,
+ boost::optional<double> const & nodata_value);
+MAPNIK_DECL void reproject_and_scale_raster(raster & target, raster const& source,
+ proj_transform const& prj_trans,
+ double offset_x, double offset_y,
+ unsigned mesh_size,
+ scaling_method_e scaling_method);
template <typename T>
MAPNIK_DECL void warp_image (T & target, T const& source, proj_transform const& prj_trans,
box2d<double> const& target_ext, box2d<double> const& source_ext,
- double offset_x, double offset_y, unsigned mesh_size, scaling_method_e scaling_method, double filter_factor);
+ double offset_x, double offset_y, unsigned mesh_size, scaling_method_e scaling_method, double filter_factor,
+ boost::optional<double> const & nodata_value);
}
#endif // MAPNIK_WARP_HPP
diff --git a/plugins/input/csv/build.py b/plugins/input/csv/build.py
index f21c93f..edc3ae0 100644
--- a/plugins/input/csv/build.py
+++ b/plugins/input/csv/build.py
@@ -29,7 +29,7 @@ if env.get('BOOST_LIB_VERSION_FROM_HEADER'):
can_build = True
if not can_build:
- print 'WARNING: skipping building the optional topojson datasource plugin which requires boost >= 1.56'
+ print 'WARNING: skipping building the optional CSV datasource plugin which requires boost >= 1.56'
else:
Import ('plugin_base')
diff --git a/plugins/input/csv/csv_utils.hpp b/plugins/input/csv/csv_utils.hpp
index 43da304..b820773 100644
--- a/plugins/input/csv/csv_utils.hpp
+++ b/plugins/input/csv/csv_utils.hpp
@@ -177,28 +177,30 @@ std::tuple<char,bool,char> autodect_newline_and_quote(T & stream, std::size_t fi
// autodetect newlines
char newline = '\n';
bool has_newline = false;
- char quote = '"';
bool has_quote = false;
+ char quote = '"';
static std::size_t const max_size = 4000;
std::size_t size = std::min(file_length, max_size);
for (std::size_t lidx = 0; lidx < size; ++lidx)
{
char c = static_cast<char>(stream.get());
- if (c == '\r')
+ switch (c)
{
+ case '\r':
newline = '\r';
has_newline = true;
- //break;
- }
- if (c == '\n')
- {
+ break;
+ case '\n':
has_newline = true;
- //break;
- }
- else if (!has_quote && c == '\'')
- {
- quote = '\'';
- has_quote = true;
+ break;
+ case '\'':
+ case '"':
+ if (!has_quote)
+ {
+ quote = c;
+ has_quote = true;
+ }
+ break;
}
}
return std::make_tuple(newline, has_newline, quote);
diff --git a/plugins/input/geojson/geojson_datasource.cpp b/plugins/input/geojson/geojson_datasource.cpp
index b46bf5b..dbb80f9 100644
--- a/plugins/input/geojson/geojson_datasource.cpp
+++ b/plugins/input/geojson/geojson_datasource.cpp
@@ -345,28 +345,40 @@ void geojson_datasource::initialise_index(Iterator start, Iterator end)
template <typename Iterator>
void geojson_datasource::parse_geojson(Iterator start, Iterator end)
{
+ using boost::spirit::qi::expectation_failure;
boost::spirit::standard::space_type space;
mapnik::context_ptr ctx = std::make_shared<mapnik::context_type>();
std::size_t start_id = 1;
mapnik::json::default_feature_callback callback(features_);
Iterator itr = start;
- bool result = boost::spirit::qi::phrase_parse(itr, end, (geojson_datasource_static_fc_grammar)
- (boost::phoenix::ref(ctx),boost::phoenix::ref(start_id), boost::phoenix::ref(callback)),
- space);
- if (!result || itr != end)
+
+ try
{
- if (!inline_string_.empty()) throw mapnik::datasource_exception("geojson_datasource: Failed to parse GeoJSON file from in-memory string");
- else throw mapnik::datasource_exception("geojson_datasource: Failed to parse GeoJSON file '" + filename_ + "'");
+ bool result = boost::spirit::qi::phrase_parse(itr, end, (geojson_datasource_static_fc_grammar)
+ (boost::phoenix::ref(ctx),boost::phoenix::ref(start_id), boost::phoenix::ref(callback)),
+ space);
+ if (!result || itr != end)
+ {
+ itr = start;
+ // try parsing as single Feature or single Geometry JSON
+ result = boost::spirit::qi::phrase_parse(itr, end, (geojson_datasource_static_feature_callback_grammar)
+ (boost::phoenix::ref(ctx),boost::phoenix::ref(start_id), boost::phoenix::ref(callback)),
+ space);
+ if (!result || itr != end)
+ {
+ if (!inline_string_.empty()) throw mapnik::datasource_exception("geojson_datasource: Failed parse GeoJSON file from in-memory string");
+ else throw mapnik::datasource_exception("geojson_datasource: Failed parse GeoJSON file '" + filename_ + "'");
+ }
+ }
}
-
- if (features_.size() == 0)
+ catch (expectation_failure<char const*> const& ex)
{
itr = start;
// try parsing as single Feature or single Geometry JSON
- result = boost::spirit::qi::phrase_parse(itr, end, (geojson_datasource_static_feature_callback_grammar)
- (boost::phoenix::ref(ctx),boost::phoenix::ref(start_id), boost::phoenix::ref(callback)),
- space);
+ bool result = boost::spirit::qi::phrase_parse(itr, end, (geojson_datasource_static_feature_callback_grammar)
+ (boost::phoenix::ref(ctx),boost::phoenix::ref(start_id), boost::phoenix::ref(callback)),
+ space);
if (!result || itr != end)
{
if (!inline_string_.empty()) throw mapnik::datasource_exception("geojson_datasource: Failed parse GeoJSON file from in-memory string");
@@ -555,18 +567,18 @@ mapnik::featureset_ptr geojson_datasource::features(mapnik::query const& q) cons
if (tree_)
{
tree_->query(boost::geometry::index::intersects(box),std::back_inserter(index_array));
-
+ // sort index array to preserve original feature ordering in GeoJSON
+ std::sort(index_array.begin(),index_array.end(),
+ [] (item_type const& item0, item_type const& item1)
+ {
+ return item0.second.first < item1.second.first;
+ });
if (cache_features_)
{
return std::make_shared<geojson_featureset>(features_, std::move(index_array));
}
else
{
- std::sort(index_array.begin(),index_array.end(),
- [] (item_type const& item0, item_type const& item1)
- {
- return item0.second.first < item1.second.first;
- });
return std::make_shared<geojson_memory_index_featureset>(filename_, std::move(index_array));
}
}
diff --git a/plugins/input/postgis/connection_manager.hpp b/plugins/input/postgis/connection_manager.hpp
index 37c547f..73656cb 100644
--- a/plugins/input/postgis/connection_manager.hpp
+++ b/plugins/input/postgis/connection_manager.hpp
@@ -113,7 +113,7 @@ private:
public:
- bool registerPool(const ConnectionCreator<Connection>& creator,unsigned initialSize,unsigned maxSize)
+ bool registerPool(ConnectionCreator<Connection> const& creator,unsigned initialSize,unsigned maxSize)
{
ContType::const_iterator itr = pools_.find(creator.id());
diff --git a/src/box2d.cpp b/src/box2d.cpp
index 0e60a38..26e6929 100644
--- a/src/box2d.cpp
+++ b/src/box2d.cpp
@@ -53,7 +53,10 @@ namespace mapnik
{
template <typename T>
box2d<T>::box2d()
- :minx_(0),miny_(0),maxx_(-1),maxy_(-1) {}
+ :minx_( std::numeric_limits<T>::max()),
+ miny_( std::numeric_limits<T>::max()),
+ maxx_(-std::numeric_limits<T>::max()),
+ maxy_(-std::numeric_limits<T>::max()) {}
template <typename T>
box2d<T>::box2d(T minx,T miny,T maxx,T maxy)
@@ -264,15 +267,16 @@ bool box2d<T>::intersects(box2d<T> const& other) const
template <typename T>
box2d<T> box2d<T>::intersect(box2d_type const& other) const
{
- if (intersects(other)) {
+ if (intersects(other))
+ {
T x0=std::max(minx_,other.minx_);
T y0=std::max(miny_,other.miny_);
-
T x1=std::min(maxx_,other.maxx_);
T y1=std::min(maxy_,other.maxy_);
-
return box2d<T>(x0,y0,x1,y1);
- } else {
+ }
+ else
+ {
return box2d<T>();
}
}
diff --git a/src/grid/grid_renderer.cpp b/src/grid/grid_renderer.cpp
index 93afb5b..33d10ee 100644
--- a/src/grid/grid_renderer.cpp
+++ b/src/grid/grid_renderer.cpp
@@ -197,12 +197,13 @@ struct grid_render_marker_visitor
else
{
image_rgba8 target(data.width(), data.height());
+ boost::optional<double> nodata;
mapnik::scale_image_agg(target,
data,
SCALING_NEAR,
1,
1,
- 0.0, 0.0, 1.0); // TODO: is 1.0 a valid default here, and do we even care in grid_renderer what the image looks like?
+ 0.0, 0.0, 1.0, nodata); // TODO: is 1.0 a valid default here, and do we even care in grid_renderer what the image looks like?
pixmap_.set_rectangle(feature_.id(), target,
boost::math::iround(pos_.x - cx),
boost::math::iround(pos_.y - cy));
diff --git a/src/image_scaling.cpp b/src/image_scaling.cpp
index 63bb88c..f0cc450 100644
--- a/src/image_scaling.cpp
+++ b/src/image_scaling.cpp
@@ -24,8 +24,6 @@
#include <mapnik/image.hpp>
#include <mapnik/image_scaling.hpp>
#include <mapnik/image_scaling_traits.hpp>
-// does not handle alpha correctly
-//#include <mapnik/span_image_filter.hpp>
// boost
#pragma GCC diagnostic push
@@ -100,7 +98,7 @@ boost::optional<std::string> scaling_method_to_string(scaling_method_e scaling_m
template <typename T>
void scale_image_agg(T & target, T const& source, scaling_method_e scaling_method,
double image_ratio_x, double image_ratio_y, double x_off_f, double y_off_f,
- double filter_factor)
+ double filter_factor, boost::optional<double> const & nodata_value)
{
// "the image filters should work namely in the premultiplied color space"
// http://old.nabble.com/Re:--AGG--Basic-image-transformations-p1110665.html
@@ -158,42 +156,46 @@ void scale_image_agg(T & target, T const& source, scaling_method_e scaling_metho
using span_gen_type = typename detail::agg_scaling_traits<image_type>::span_image_resample_affine;
agg::image_filter_lut filter;
detail::set_scaling_method(filter, scaling_method, filter_factor);
- span_gen_type sg(img_src, interpolator, filter);
+ boost::optional<typename span_gen_type::value_type> nodata;
+ if (nodata_value)
+ {
+ nodata = nodata_value;
+ }
+ span_gen_type sg(img_src, interpolator, filter, nodata);
agg::render_scanlines_aa(ras, sl, rb_dst_pre, sa, sg);
}
-
}
template MAPNIK_DECL void scale_image_agg(image_rgba8 &, image_rgba8 const&, scaling_method_e,
- double, double , double, double , double);
+ double, double , double, double , double, boost::optional<double> const &);
template MAPNIK_DECL void scale_image_agg(image_gray8 &, image_gray8 const&, scaling_method_e,
- double, double , double, double , double);
+ double, double , double, double , double, boost::optional<double> const &);
template MAPNIK_DECL void scale_image_agg(image_gray8s &, image_gray8s const&, scaling_method_e,
- double, double , double, double , double);
+ double, double , double, double , double, boost::optional<double> const &);
template MAPNIK_DECL void scale_image_agg(image_gray16 &, image_gray16 const&, scaling_method_e,
- double, double , double, double , double);
+ double, double , double, double , double, boost::optional<double> const &);
template MAPNIK_DECL void scale_image_agg(image_gray16s &, image_gray16s const&, scaling_method_e,
- double, double , double, double , double);
+ double, double , double, double , double, boost::optional<double> const &);
template MAPNIK_DECL void scale_image_agg(image_gray32 &, image_gray32 const&, scaling_method_e,
- double, double , double, double , double);
+ double, double , double, double , double, boost::optional<double> const &);
template MAPNIK_DECL void scale_image_agg(image_gray32s &, image_gray32s const&, scaling_method_e,
- double, double , double, double , double);
+ double, double , double, double , double, boost::optional<double> const &);
template MAPNIK_DECL void scale_image_agg(image_gray32f &, image_gray32f const&, scaling_method_e,
- double, double , double, double , double);
+ double, double , double, double , double, boost::optional<double> const &);
template MAPNIK_DECL void scale_image_agg(image_gray64 &, image_gray64 const&, scaling_method_e,
- double, double , double, double , double);
+ double, double , double, double , double, boost::optional<double> const &);
template MAPNIK_DECL void scale_image_agg(image_gray64s &, image_gray64s const&, scaling_method_e,
- double, double , double, double , double);
+ double, double , double, double , double, boost::optional<double> const &);
template MAPNIK_DECL void scale_image_agg(image_gray64f &, image_gray64f const&, scaling_method_e,
- double, double , double, double , double);
+ double, double , double, double , double, boost::optional<double> const &);
}
diff --git a/src/map.cpp b/src/map.cpp
index 81ad147..c44735c 100644
--- a/src/map.cpp
+++ b/src/map.cpp
@@ -580,7 +580,7 @@ void Map::zoom_all()
void Map::zoom_to_box(box2d<double> const& box)
{
- current_extent_=box;
+ current_extent_= box;
fixAspectRatio();
}
diff --git a/src/warp.cpp b/src/warp.cpp
index 5729748..b250d6e 100644
--- a/src/warp.cpp
+++ b/src/warp.cpp
@@ -51,7 +51,8 @@ namespace mapnik {
template <typename T>
MAPNIK_DECL void warp_image (T & target, T const& source, proj_transform const& prj_trans,
box2d<double> const& target_ext, box2d<double> const& source_ext,
- double offset_x, double offset_y, unsigned mesh_size, scaling_method_e scaling_method, double filter_factor)
+ double offset_x, double offset_y, unsigned mesh_size, scaling_method_e scaling_method, double filter_factor,
+ boost::optional<double> const & nodata_value)
{
using image_type = T;
using pixel_type = typename image_type::pixel_type;
@@ -147,7 +148,12 @@ MAPNIK_DECL void warp_image (T & target, T const& source, proj_transform const&
using span_gen_type = typename detail::agg_scaling_traits<image_type>::span_image_resample_affine;
agg::image_filter_lut filter;
detail::set_scaling_method(filter, scaling_method, filter_factor);
- span_gen_type sg(ia, interpolator, filter);
+ boost::optional<typename span_gen_type::value_type> nodata;
+ if (nodata_value)
+ {
+ nodata = nodata_value;
+ }
+ span_gen_type sg(ia, interpolator, filter, nodata);
agg::render_scanlines_bin(rasterizer, scanline, rb, sa, sg);
}
}
@@ -162,7 +168,8 @@ struct warp_image_visitor
{
warp_image_visitor (raster & target_raster, proj_transform const& prj_trans, box2d<double> const& source_ext,
double offset_x, double offset_y, unsigned mesh_size,
- scaling_method_e scaling_method, double filter_factor)
+ scaling_method_e scaling_method, double filter_factor,
+ boost::optional<double> const & nodata_value)
: target_raster_(target_raster),
prj_trans_(prj_trans),
source_ext_(source_ext),
@@ -170,7 +177,9 @@ struct warp_image_visitor
offset_y_(offset_y),
mesh_size_(mesh_size),
scaling_method_(scaling_method),
- filter_factor_(filter_factor) {}
+ filter_factor_(filter_factor),
+ nodata_value_(nodata_value)
+ {}
void operator() (image_null const&) {}
@@ -183,7 +192,7 @@ struct warp_image_visitor
{
image_type & target = util::get<image_type>(target_raster_.data_);
warp_image (target, source, prj_trans_, target_raster_.ext_, source_ext_,
- offset_x_, offset_y_, mesh_size_, scaling_method_, filter_factor_);
+ offset_x_, offset_y_, mesh_size_, scaling_method_, filter_factor_, nodata_value_);
}
}
@@ -195,6 +204,7 @@ struct warp_image_visitor
unsigned mesh_size_;
scaling_method_e scaling_method_;
double filter_factor_;
+ boost::optional<double> const & nodata_value_;
};
}
@@ -203,24 +213,39 @@ void reproject_and_scale_raster(raster & target, raster const& source,
proj_transform const& prj_trans,
double offset_x, double offset_y,
unsigned mesh_size,
- scaling_method_e scaling_method)
+ scaling_method_e scaling_method,
+ boost::optional<double> const & nodata_value)
{
detail::warp_image_visitor warper(target, prj_trans, source.ext_, offset_x, offset_y, mesh_size,
- scaling_method, source.get_filter_factor());
+ scaling_method, source.get_filter_factor(), nodata_value);
util::apply_visitor(warper, source.data_);
}
+void reproject_and_scale_raster(raster & target, raster const& source,
+ proj_transform const& prj_trans,
+ double offset_x, double offset_y,
+ unsigned mesh_size,
+ scaling_method_e scaling_method)
+{
+ reproject_and_scale_raster(target, source, prj_trans,
+ offset_x, offset_y,
+ mesh_size,
+ scaling_method,
+ boost::optional<double>());
+}
+
+
template MAPNIK_DECL void warp_image (image_rgba8&, image_rgba8 const&, proj_transform const&,
- box2d<double> const&, box2d<double> const&, double, double, unsigned, scaling_method_e, double);
+ box2d<double> const&, box2d<double> const&, double, double, unsigned, scaling_method_e, double, boost::optional<double> const &);
template MAPNIK_DECL void warp_image (image_gray8&, image_gray8 const&, proj_transform const&,
- box2d<double> const&, box2d<double> const&, double, double, unsigned, scaling_method_e, double);
+ box2d<double> const&, box2d<double> const&, double, double, unsigned, scaling_method_e, double, boost::optional<double> const &);
template MAPNIK_DECL void warp_image (image_gray16&, image_gray16 const&, proj_transform const&,
- box2d<double> const&, box2d<double> const&, double, double, unsigned, scaling_method_e, double);
+ box2d<double> const&, box2d<double> const&, double, double, unsigned, scaling_method_e, double, boost::optional<double> const &);
template MAPNIK_DECL void warp_image (image_gray32f&, image_gray32f const&, proj_transform const&,
- box2d<double> const&, box2d<double> const&, double, double, unsigned, scaling_method_e, double);
+ box2d<double> const&, box2d<double> const&, double, double, unsigned, scaling_method_e, double, boost::optional<double> const &);
}// namespace mapnik
diff --git a/test/unit/datasource/geojson.cpp b/test/unit/datasource/geojson.cpp
index 785d669..ad1f2d9 100644
--- a/test/unit/datasource/geojson.cpp
+++ b/test/unit/datasource/geojson.cpp
@@ -446,7 +446,7 @@ TEST_CASE("geojson") {
"./test/data/json/feature-malformed-3.geojson"})
{
std::string filename(c_str);
- params["file"] = filename; // mismatched parentheses
+ params["file"] = filename;
// cleanup in the case of a failed previous run
if (mapnik::util::exists(filename + ".index"))
@@ -468,6 +468,7 @@ TEST_CASE("geojson") {
for (auto cache_features : {true, false})
{
+ params["cache_features"] = cache_features;
CHECK_THROWS(mapnik::datasource_cache::instance().create(params));
}
@@ -480,6 +481,48 @@ TEST_CASE("geojson") {
}
}
+ SECTION("GeoJSON ensure mapnik::featureset::next() throws on malformed input")
+ {
+ std::string filename{"./test/data/json/featurecollection-malformed.json"};
+ mapnik::parameters params;
+ params["type"] = "geojson";
+ params["file"] = filename;
+
+ // cleanup in the case of a failed previous run
+ if (mapnik::util::exists(filename + ".index"))
+ {
+ mapnik::util::remove(filename + ".index");
+ }
+
+ CHECK(!mapnik::util::exists(filename + ".index"));
+ int ret = create_disk_index(filename);
+ int ret_posix = (ret >> 8) & 0x000000ff;
+ INFO(ret);
+ INFO(ret_posix);
+ CHECK(mapnik::util::exists(filename + ".index"));
+
+ for (auto cache_features : {true,false})
+ {
+ params["cache_features"] = false;
+ auto ds = mapnik::datasource_cache::instance().create(params);
+ auto fields = ds->get_descriptor().get_descriptors();
+ mapnik::query query(ds->envelope());
+ auto features = ds->features(query);
+ REQUIRE_THROWS(
+ auto feature = features->next();
+ while (feature != nullptr)
+ {
+ feature = features->next();
+ });
+ }
+
+ // cleanup
+ if (mapnik::util::exists(filename + ".index"))
+ {
+ mapnik::util::remove(filename + ".index");
+ }
+ }
+
SECTION("GeoJSON ensure input fully consumed and throw exception otherwise")
{
mapnik::parameters params;
diff --git a/test/unit/datasource/shapeindex.cpp b/test/unit/datasource/shapeindex.cpp
new file mode 100644
index 0000000..e169678
--- /dev/null
+++ b/test/unit/datasource/shapeindex.cpp
@@ -0,0 +1,120 @@
+/*****************************************************************************
+ *
+ * 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
+ *
+ *****************************************************************************/
+
+#include "catch.hpp"
+
+#include <mapnik/datasource.hpp>
+#include <mapnik/datasource_cache.hpp>
+#include <mapnik/util/fs.hpp>
+#include <cstdlib>
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
+#include <boost/algorithm/string.hpp>
+#pragma GCC diagnostic pop
+
+namespace {
+
+std::size_t count_shapefile_features(std::string const& filename)
+{
+ mapnik::parameters params;
+ params["type"] = "shape";
+ params["file"] = filename;
+ auto ds = mapnik::datasource_cache::instance().create(params);
+ CHECK(ds->type() == mapnik::datasource::datasource_t::Vector);
+ auto fields = ds->get_descriptor().get_descriptors();
+ mapnik::query query(ds->envelope());
+ for (auto const& field : fields)
+ {
+ query.add_property_name(field.get_name());
+ }
+ auto features = ds->features(query);
+
+ std::size_t feature_count = 0;
+ auto feature = features->next();
+ while (feature)
+ {
+ ++feature_count;
+ feature = features->next();
+ }
+ return feature_count;
+}
+
+int create_shapefile_index(std::string const& filename, bool silent = true)
+{
+ std::string cmd;
+ if (std::getenv("DYLD_LIBRARY_PATH") != nullptr)
+ {
+ cmd += std::string("export DYLD_LIBRARY_PATH=") + std::getenv("DYLD_LIBRARY_PATH") + " && ";
+ }
+ cmd += "shapeindex " + filename;
+ if (silent)
+ {
+#ifndef _WINDOWS
+ cmd += " 2>/dev/null";
+#else
+ cmd += " 2> nul";
+#endif
+ }
+ return std::system(cmd.c_str());
+}
+
+}
+
+TEST_CASE("shapeindex")
+{
+ std::string shape_plugin("./plugins/input/shape.input");
+ if (mapnik::util::exists(shape_plugin))
+ {
+ SECTION("Shapefile index")
+ {
+ for (auto const& path : mapnik::util::list_directory("test/data/shp/"))
+ {
+ if (boost::iends_with(path,".shp"))
+ {
+ std::string index_path = path.substr(0, path.rfind(".")) + ".index";
+ // remove *.index if present
+ if (mapnik::util::exists(index_path))
+ {
+ mapnik::util::remove(index_path);
+ }
+ // count features
+ std::size_t feature_count = count_shapefile_features(path);
+ // create *.index
+ create_shapefile_index(path);
+ if (feature_count == 0)
+ {
+ REQUIRE(!mapnik::util::exists(index_path)); // index won't be created if there's no features
+ }
+ // count features
+ std::size_t feature_count_indexed = count_shapefile_features(path);
+ // ensure number of features are the same
+ REQUIRE(feature_count == feature_count_indexed);
+ // remove *.index if present
+ if (mapnik::util::exists(index_path))
+ {
+ mapnik::util::remove(index_path);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/test/unit/geometry/centroid.cpp b/test/unit/geometry/centroid.cpp
new file mode 100644
index 0000000..1e58aad
--- /dev/null
+++ b/test/unit/geometry/centroid.cpp
@@ -0,0 +1,205 @@
+#include "catch.hpp"
+
+#include <mapnik/geometry_centroid.hpp>
+
+TEST_CASE("geometry centroid") {
+
+SECTION("empty geometry") {
+
+ mapnik::geometry::geometry_empty geom;
+ mapnik::geometry::point<double> centroid;
+ REQUIRE(!mapnik::geometry::centroid(geom, centroid));
+}
+
+SECTION("geometry collection") {
+
+ mapnik::geometry::geometry_collection<double> geom;
+ mapnik::geometry::point<double> centroid;
+ REQUIRE(!mapnik::geometry::centroid(geom, centroid));
+}
+
+SECTION("point") {
+
+ mapnik::geometry::point<double> pt(10, 10);
+ mapnik::geometry::point<double> centroid;
+ REQUIRE(mapnik::geometry::centroid(pt, centroid));
+ REQUIRE(pt.x == centroid.x);
+ REQUIRE(pt.y == centroid.y);
+}
+
+SECTION("linestring") {
+
+ mapnik::geometry::line_string<double> line;
+ line.add_coord(0, 0);
+ line.add_coord(25, 25);
+ line.add_coord(50, 50);
+ mapnik::geometry::point<double> centroid;
+ REQUIRE(mapnik::geometry::centroid(line, centroid));
+ REQUIRE(centroid.x == 25);
+ REQUIRE(centroid.y == 25);
+}
+
+SECTION("empty linestring") {
+
+ mapnik::geometry::line_string<double> line;
+ mapnik::geometry::point<double> centroid;
+ REQUIRE(!mapnik::geometry::centroid(line, centroid));
+}
+
+SECTION("polygon") {
+
+ mapnik::geometry::polygon<double> poly;
+ mapnik::geometry::linear_ring<double> ring;
+ ring.add_coord(0, 0);
+ ring.add_coord(1, 0);
+ ring.add_coord(1, 1);
+ ring.add_coord(0, 1);
+ ring.add_coord(0, 0);
+ poly.set_exterior_ring(std::move(ring));
+
+ mapnik::geometry::point<double> centroid;
+ REQUIRE(mapnik::geometry::centroid(poly, centroid));
+ REQUIRE(centroid.x == 0.5);
+ REQUIRE(centroid.y == 0.5);
+}
+
+SECTION("polygon with empty exterior ring") {
+
+ mapnik::geometry::polygon<double> poly;
+ mapnik::geometry::linear_ring<double> ring;
+ poly.set_exterior_ring(std::move(ring));
+
+ mapnik::geometry::point<double> centroid;
+ REQUIRE(!mapnik::geometry::centroid(poly, centroid));
+}
+
+SECTION("empty polygon") {
+
+ mapnik::geometry::polygon<double> poly;
+ mapnik::geometry::point<double> centroid;
+ REQUIRE(!mapnik::geometry::centroid(poly, centroid));
+}
+
+SECTION("multi-point") {
+
+ mapnik::geometry::multi_point<double> geom;
+ geom.add_coord(0, 0);
+ geom.add_coord(25, 25);
+ geom.add_coord(50, 50);
+ mapnik::geometry::point<double> centroid;
+ REQUIRE(mapnik::geometry::centroid(geom, centroid));
+ REQUIRE(centroid.x == 25);
+ REQUIRE(centroid.y == 25);
+}
+
+SECTION("empty multi-point") {
+
+ mapnik::geometry::multi_point<double> geom;
+ mapnik::geometry::point<double> centroid;
+ REQUIRE(!mapnik::geometry::centroid(geom, centroid));
+}
+
+SECTION("multi-linestring") {
+
+ mapnik::geometry::multi_line_string<double> geom;
+ {
+ mapnik::geometry::line_string<double> line;
+ line.add_coord(0, 0);
+ line.add_coord(0, 25);
+ line.add_coord(0, 50);
+ geom.emplace_back(std::move(line));
+ }
+ {
+ mapnik::geometry::line_string<double> line;
+ line.add_coord(0, 0);
+ line.add_coord(25, 0);
+ line.add_coord(50, 0);
+ geom.emplace_back(std::move(line));
+ }
+ mapnik::geometry::point<double> centroid;
+ REQUIRE(mapnik::geometry::centroid(geom, centroid));
+ REQUIRE(centroid.x == 12.5);
+ REQUIRE(centroid.y == 12.5);
+}
+
+SECTION("multi-linestring: one component empty") {
+
+ mapnik::geometry::multi_line_string<double> geom;
+ mapnik::geometry::line_string<double> line;
+ line.add_coord(0, 0);
+ line.add_coord(0, 25);
+ line.add_coord(0, 50);
+ geom.emplace_back(std::move(line));
+ geom.emplace_back();
+ mapnik::geometry::point<double> centroid;
+ REQUIRE(mapnik::geometry::centroid(geom, centroid));
+ REQUIRE(centroid.x == 0);
+ REQUIRE(centroid.y == 25);
+}
+
+SECTION("empty multi-linestring") {
+
+ mapnik::geometry::multi_line_string<double> geom;
+ mapnik::geometry::point<double> centroid;
+ REQUIRE(!mapnik::geometry::centroid(geom, centroid));
+}
+
+SECTION("multi-polygon") {
+
+ mapnik::geometry::multi_polygon<double> geom;
+ {
+ mapnik::geometry::polygon<double> poly;
+ mapnik::geometry::linear_ring<double> ring;
+ ring.add_coord(0, 0);
+ ring.add_coord(1, 0);
+ ring.add_coord(1, 1);
+ ring.add_coord(0, 1);
+ ring.add_coord(0, 0);
+ poly.set_exterior_ring(std::move(ring));
+ geom.emplace_back(std::move(poly));
+ }
+ {
+ mapnik::geometry::polygon<double> poly;
+ mapnik::geometry::linear_ring<double> ring;
+ ring.add_coord(1, 1);
+ ring.add_coord(2, 1);
+ ring.add_coord(2, 2);
+ ring.add_coord(1, 2);
+ ring.add_coord(1, 1);
+ poly.set_exterior_ring(std::move(ring));
+ geom.emplace_back(std::move(poly));
+ }
+
+ mapnik::geometry::point<double> centroid;
+ REQUIRE(mapnik::geometry::centroid(geom, centroid));
+ REQUIRE(centroid.x == 1);
+ REQUIRE(centroid.y == 1);
+}
+
+SECTION("multi-polygon: one component empty") {
+
+ mapnik::geometry::multi_polygon<double> geom;
+ mapnik::geometry::polygon<double> poly;
+ mapnik::geometry::linear_ring<double> ring;
+ ring.add_coord(0, 0);
+ ring.add_coord(1, 0);
+ ring.add_coord(1, 1);
+ ring.add_coord(0, 1);
+ ring.add_coord(0, 0);
+ poly.set_exterior_ring(std::move(ring));
+ geom.emplace_back(std::move(poly));
+ geom.emplace_back();
+
+ mapnik::geometry::point<double> centroid;
+ REQUIRE(mapnik::geometry::centroid(geom, centroid));
+ REQUIRE(centroid.x == 0.5);
+ REQUIRE(centroid.y == 0.5);
+}
+
+SECTION("empty multi-polygon") {
+
+ mapnik::geometry::multi_polygon<double> geom;
+ mapnik::geometry::point<double> centroid;
+ REQUIRE(!mapnik::geometry::centroid(geom, centroid));
+}
+}
diff --git a/test/unit/geometry/has_empty.cpp b/test/unit/geometry/has_empty.cpp
new file mode 100644
index 0000000..a240c6f
--- /dev/null
+++ b/test/unit/geometry/has_empty.cpp
@@ -0,0 +1,150 @@
+#include "catch.hpp"
+
+#include <mapnik/geometry_is_empty.hpp>
+
+TEST_CASE("geometry has_empty") {
+
+SECTION("empty geometry") {
+
+ mapnik::geometry::geometry_empty geom;
+ REQUIRE(!mapnik::geometry::has_empty(geom));
+}
+
+SECTION("geometry collection") {
+
+ {
+ mapnik::geometry::geometry_collection<double> geom;
+ REQUIRE(!mapnik::geometry::has_empty(geom));
+ }
+ {
+ mapnik::geometry::geometry_collection<double> geom;
+ mapnik::geometry::geometry_empty geom1;
+ geom.emplace_back(std::move(geom1));
+ REQUIRE(mapnik::geometry::has_empty(geom));
+ }
+ {
+ mapnik::geometry::geometry_collection<double> geom;
+ mapnik::geometry::multi_line_string<double> mls;
+ mapnik::geometry::line_string<double> line;
+ mls.emplace_back(std::move(line));
+ geom.emplace_back(std::move(mls));
+ REQUIRE(mapnik::geometry::has_empty(geom));
+ }
+ {
+ mapnik::geometry::geometry_collection<double> geom;
+ mapnik::geometry::multi_line_string<double> mls;
+ mapnik::geometry::line_string<double> line;
+ line.add_coord(0, 0);
+ mls.emplace_back(std::move(line));
+ geom.emplace_back(std::move(mls));
+ REQUIRE(!mapnik::geometry::has_empty(geom));
+ }
+}
+
+SECTION("point") {
+
+ mapnik::geometry::point<double> pt(10, 10);
+ REQUIRE(!mapnik::geometry::has_empty(pt));
+}
+
+SECTION("linestring") {
+
+ {
+ mapnik::geometry::line_string<double> line;
+ REQUIRE(!mapnik::geometry::has_empty(line));
+ }
+ {
+ mapnik::geometry::line_string<double> line;
+ line.add_coord(0, 0);
+ line.add_coord(25, 25);
+ line.add_coord(50, 50);
+ REQUIRE(!mapnik::geometry::has_empty(line));
+ }
+}
+
+SECTION("polygon") {
+
+ {
+ mapnik::geometry::polygon<double> poly;
+ REQUIRE(!mapnik::geometry::has_empty(poly));
+ }
+ {
+ mapnik::geometry::polygon<double> poly;
+ mapnik::geometry::linear_ring<double> ring;
+ poly.set_exterior_ring(std::move(ring));
+ REQUIRE(!mapnik::geometry::has_empty(poly));
+ }
+ {
+ mapnik::geometry::polygon<double> poly;
+ mapnik::geometry::linear_ring<double> ring;
+ ring.add_coord(0, 0);
+ ring.add_coord(1, 0);
+ ring.add_coord(1, 1);
+ ring.add_coord(0, 1);
+ ring.add_coord(0, 0);
+ poly.set_exterior_ring(std::move(ring));
+ REQUIRE(!mapnik::geometry::has_empty(poly));
+ }
+}
+
+SECTION("multi-point") {
+
+ {
+ mapnik::geometry::multi_point<double> geom;
+ REQUIRE(!mapnik::geometry::has_empty(geom));
+ }
+ {
+ mapnik::geometry::multi_point<double> geom;
+ geom.add_coord(0, 0);
+ geom.add_coord(25, 25);
+ geom.add_coord(50, 50);
+ REQUIRE(!mapnik::geometry::has_empty(geom));
+ }
+}
+
+SECTION("multi-linestring") {
+
+ {
+ mapnik::geometry::multi_line_string<double> geom;
+ REQUIRE(!mapnik::geometry::has_empty(geom));
+ }
+ {
+ mapnik::geometry::multi_line_string<double> geom;
+ mapnik::geometry::line_string<double> line;
+ geom.emplace_back(std::move(line));
+ REQUIRE(mapnik::geometry::has_empty(geom));
+ }
+ {
+ mapnik::geometry::multi_line_string<double> geom;
+ mapnik::geometry::line_string<double> line;
+ line.add_coord(0, 0);
+ geom.emplace_back(std::move(line));
+ REQUIRE(!mapnik::geometry::has_empty(geom));
+ }
+}
+
+SECTION("multi-polygon") {
+
+ {
+ mapnik::geometry::multi_polygon<double> geom;
+ REQUIRE(!mapnik::geometry::has_empty(geom));
+ }
+ {
+ mapnik::geometry::multi_polygon<double> geom;
+ mapnik::geometry::polygon<double> poly;
+ mapnik::geometry::linear_ring<double> ring;
+ poly.set_exterior_ring(std::move(ring));
+ geom.emplace_back(std::move(poly));
+ REQUIRE(mapnik::geometry::has_empty(geom));
+ }
+ {
+ mapnik::geometry::multi_polygon<double> geom;
+ mapnik::geometry::polygon<double> poly;
+ mapnik::geometry::linear_ring<double> ring;
+ ring.add_coord(0, 0);
+ poly.set_exterior_ring(std::move(ring));
+ geom.emplace_back(std::move(poly));
+ REQUIRE(!mapnik::geometry::has_empty(geom));
+ }
+}
+}
diff --git a/test/unit/geometry/is_empty.cpp b/test/unit/geometry/is_empty.cpp
new file mode 100644
index 0000000..bb6a634
--- /dev/null
+++ b/test/unit/geometry/is_empty.cpp
@@ -0,0 +1,117 @@
+#include "catch.hpp"
+
+#include <mapnik/geometry_is_empty.hpp>
+
+TEST_CASE("geometry is_empty") {
+
+SECTION("empty geometry") {
+
+ mapnik::geometry::geometry_empty geom;
+ REQUIRE(mapnik::geometry::is_empty(geom));
+}
+
+SECTION("geometry collection") {
+
+ {
+ mapnik::geometry::geometry_collection<double> geom;
+ REQUIRE(mapnik::geometry::is_empty(geom));
+ }
+ {
+ mapnik::geometry::geometry_collection<double> geom;
+ mapnik::geometry::geometry_empty geom1;
+ geom.emplace_back(std::move(geom1));
+ REQUIRE(!mapnik::geometry::is_empty(geom));
+ }
+}
+
+SECTION("point") {
+
+ mapnik::geometry::point<double> pt(10, 10);
+ REQUIRE(!mapnik::geometry::is_empty(pt));
+}
+
+SECTION("linestring") {
+
+ {
+ mapnik::geometry::line_string<double> line;
+ REQUIRE(mapnik::geometry::is_empty(line));
+ }
+ {
+ mapnik::geometry::line_string<double> line;
+ line.add_coord(0, 0);
+ line.add_coord(25, 25);
+ line.add_coord(50, 50);
+ REQUIRE(!mapnik::geometry::is_empty(line));
+ }
+}
+
+SECTION("polygon") {
+
+ {
+ mapnik::geometry::polygon<double> poly;
+ REQUIRE(mapnik::geometry::is_empty(poly));
+ }
+ {
+ mapnik::geometry::polygon<double> poly;
+ mapnik::geometry::linear_ring<double> ring;
+ poly.set_exterior_ring(std::move(ring));
+ REQUIRE(mapnik::geometry::is_empty(poly));
+ }
+ {
+ mapnik::geometry::polygon<double> poly;
+ mapnik::geometry::linear_ring<double> ring;
+ ring.add_coord(0, 0);
+ ring.add_coord(1, 0);
+ ring.add_coord(1, 1);
+ ring.add_coord(0, 1);
+ ring.add_coord(0, 0);
+ poly.set_exterior_ring(std::move(ring));
+ REQUIRE(!mapnik::geometry::is_empty(poly));
+ }
+}
+
+SECTION("multi-point") {
+
+ {
+ mapnik::geometry::multi_point<double> geom;
+ REQUIRE(mapnik::geometry::is_empty(geom));
+ }
+ {
+ mapnik::geometry::multi_point<double> geom;
+ geom.add_coord(0, 0);
+ geom.add_coord(25, 25);
+ geom.add_coord(50, 50);
+ REQUIRE(!mapnik::geometry::is_empty(geom));
+ }
+}
+
+SECTION("multi-linestring") {
+
+ {
+ mapnik::geometry::multi_line_string<double> geom;
+ REQUIRE(mapnik::geometry::is_empty(geom));
+ }
+ {
+ mapnik::geometry::multi_line_string<double> geom;
+ mapnik::geometry::line_string<double> line;
+ geom.emplace_back(std::move(line));
+ REQUIRE(!mapnik::geometry::is_empty(geom));
+ }
+}
+
+SECTION("multi-polygon") {
+
+ {
+ mapnik::geometry::multi_polygon<double> geom;
+ REQUIRE(mapnik::geometry::is_empty(geom));
+ }
+ {
+ mapnik::geometry::multi_polygon<double> geom;
+ mapnik::geometry::polygon<double> poly;
+ mapnik::geometry::linear_ring<double> ring;
+ poly.set_exterior_ring(std::move(ring));
+ geom.emplace_back(std::move(poly));
+ REQUIRE(!mapnik::geometry::is_empty(geom));
+ }
+}
+}
diff --git a/test/unit/geometry/label_algo_test.cpp b/test/unit/geometry/label_algo_test.cpp
deleted file mode 100644
index 1c315ca..0000000
--- a/test/unit/geometry/label_algo_test.cpp
+++ /dev/null
@@ -1,33 +0,0 @@
-#include "catch.hpp"
-
-#include <iostream>
-#include <mapnik/geometry.hpp>
-#include <mapnik/geometry_centroid.hpp>
-#include <algorithm>
-
-TEST_CASE("labeling") {
-
-SECTION("algorithms") {
-
- // reused these for simplicity
- mapnik::geometry::point<double> centroid;
- {
- // single point
- mapnik::geometry::point<double> pt(10,10);
- REQUIRE( mapnik::geometry::centroid(pt, centroid));
- REQUIRE( pt.x == centroid.x);
- REQUIRE( pt.y == centroid.y);
- }
-
- // linestring with three consecutive verticies
- {
- mapnik::geometry::line_string<double> line;
- line.add_coord(0, 0);
- line.add_coord(25, 25);
- line.add_coord(50, 50);
- REQUIRE(mapnik::geometry::centroid(line, centroid));
- REQUIRE( centroid.x == 25 );
- REQUIRE( centroid.y == 25 );
- }
-}
-}
diff --git a/test/unit/geometry/remove_empty.cpp b/test/unit/geometry/remove_empty.cpp
new file mode 100644
index 0000000..1523754
--- /dev/null
+++ b/test/unit/geometry/remove_empty.cpp
@@ -0,0 +1,53 @@
+#include "catch.hpp"
+
+#include <mapnik/geometry_remove_empty.hpp>
+
+TEST_CASE("geometry remove_empty") {
+
+SECTION("point") {
+
+ using geom_type = mapnik::geometry::point<double>;
+ geom_type pt(10, 10);
+ geom_type pt2 = mapnik::geometry::remove_empty(pt);
+ REQUIRE(pt.x == pt2.x);
+ REQUIRE(pt.y == pt2.y);
+}
+
+SECTION("multi-linestring") {
+
+ using geom_type = mapnik::geometry::multi_line_string<double>;
+ geom_type geom;
+ mapnik::geometry::line_string<double> line;
+ line.add_coord(0, 0);
+ line.add_coord(0, 25);
+ line.add_coord(0, 50);
+ geom.emplace_back(std::move(line));
+ geom.emplace_back();
+
+ REQUIRE(geom.size() == 2);
+ geom_type geom2 = mapnik::geometry::remove_empty(geom);
+ REQUIRE(geom2.size() == 1);
+ REQUIRE(geom2[0].size() == 3);
+}
+
+SECTION("multi-polygon") {
+
+ using geom_type = mapnik::geometry::multi_polygon<double>;
+ geom_type geom;
+ mapnik::geometry::polygon<double> poly;
+ mapnik::geometry::linear_ring<double> ring;
+ ring.add_coord(0, 0);
+ ring.add_coord(1, 0);
+ ring.add_coord(1, 1);
+ ring.add_coord(0, 1);
+ ring.add_coord(0, 0);
+ poly.set_exterior_ring(std::move(ring));
+ geom.emplace_back(std::move(poly));
+ geom.emplace_back();
+
+ REQUIRE(geom.size() == 2);
+ geom_type geom2 = mapnik::geometry::remove_empty(geom);
+ REQUIRE(geom2.size() == 1);
+ REQUIRE(geom2[0].exterior_ring.size() == 5);
+}
+}
diff --git a/utils/mapnik-index/build.py b/utils/mapnik-index/build.py
index 341c4b8..5bb1770 100644
--- a/utils/mapnik-index/build.py
+++ b/utils/mapnik-index/build.py
@@ -42,9 +42,9 @@ boost_program_options = 'boost_program_options%s' % env['BOOST_APPEND']
boost_system = 'boost_system%s' % env['BOOST_APPEND']
libraries = [env['MAPNIK_NAME'], boost_program_options, boost_system]
# need on linux: https://github.com/mapnik/mapnik/issues/3145
-libraries.append(env['ICU_LIB_NAME'])
libraries.append('mapnik-json')
libraries.append('mapnik-wkt')
+libraries.append(env['ICU_LIB_NAME'])
if env['RUNTIME_LINK'] == 'static':
libraries.extend(copy(env['LIBMAPNIK_LIBS']))
diff --git a/utils/mapnik-index/mapnik-index.cpp b/utils/mapnik-index/mapnik-index.cpp
index a19b1f1..7361c05 100644
--- a/utils/mapnik-index/mapnik-index.cpp
+++ b/utils/mapnik-index/mapnik-index.cpp
@@ -61,6 +61,7 @@ int main (int argc, char** argv)
//using namespace mapnik;
namespace po = boost::program_options;
bool verbose = false;
+ bool validate_features = false;
unsigned int depth = DEFAULT_DEPTH;
double ratio = DEFAULT_RATIO;
std::vector<std::string> files;
@@ -80,6 +81,7 @@ int main (int argc, char** argv)
("quote,q", po::value<char>(), "CSV columns quote")
("manual-headers,H", po::value<std::string>(), "CSV manual headers string")
("files",po::value<std::vector<std::string> >(),"Files to index: file1 file2 ...fileN")
+ ("validate-features", "Validate GeoJSON features")
;
po::positional_options_description p;
@@ -102,6 +104,10 @@ int main (int argc, char** argv)
{
verbose = true;
}
+ if (vm.count("validate-features"))
+ {
+ validate_features = true;
+ }
if (vm.count("depth"))
{
depth = vm["depth"].as<unsigned int>();
@@ -180,8 +186,12 @@ int main (int argc, char** argv)
else if (mapnik::detail::is_geojson(filename))
{
std::clog << "processing '" << filename << "' as GeoJSON\n";
- auto result = mapnik::detail::process_geojson_file(boxes, filename);
- if (!result.first) continue;
+ auto result = mapnik::detail::process_geojson_file(boxes, filename, validate_features);
+ if (!result.first)
+ {
+ std::clog << "Error: failed to process " << filename << std::endl;
+ continue;
+ }
extent = result.second;
}
diff --git a/utils/mapnik-index/process_geojson_file.cpp b/utils/mapnik-index/process_geojson_file.cpp
index 1ca0be7..af9656b 100644
--- a/utils/mapnik-index/process_geojson_file.cpp
+++ b/utils/mapnik-index/process_geojson_file.cpp
@@ -39,16 +39,34 @@
#include <mapnik/json/positions_grammar.hpp>
#include <mapnik/json/extract_bounding_box_grammar_impl.hpp>
+#include <mapnik/json/feature_collection_grammar_impl.hpp>
namespace {
+struct feature_validate_callback
+{
+ feature_validate_callback(mapnik::box2d<double> const& box)
+ : box_(box) {}
+
+ void operator() (mapnik::feature_ptr const& f) const
+ {
+ if (box_ != f->envelope())
+ {
+ throw std::runtime_error("Bounding boxes mismatch validation feature");
+ }
+ }
+ mapnik::box2d<double> const& box_;
+};
+
using base_iterator_type = char const*;
const mapnik::json::extract_bounding_box_grammar<base_iterator_type> geojson_datasource_static_bbox_grammar;
+const mapnik::transcoder tr("utf8");
+const mapnik::json::feature_grammar_callback<base_iterator_type, mapnik::feature_impl, feature_validate_callback> fc_grammar(tr);
}
namespace mapnik { namespace detail {
template <typename T>
-std::pair<bool,box2d<double>> process_geojson_file(T & boxes, std::string const& filename)
+std::pair<bool,box2d<double>> process_geojson_file(T & boxes, std::string const& filename, bool validate_features)
{
mapnik::box2d<double> extent;
#if defined(MAPNIK_MEMORY_MAPPED_FILE)
@@ -81,9 +99,10 @@ std::pair<bool,box2d<double>> process_geojson_file(T & boxes, std::string const&
#endif
boost::spirit::standard::space_type space;
+ auto const* itr = start;
try
{
- if (!boost::spirit::qi::phrase_parse(start, end, (geojson_datasource_static_bbox_grammar)(boost::phoenix::ref(boxes)) , space))
+ if (!boost::spirit::qi::phrase_parse(itr, end, (geojson_datasource_static_bbox_grammar)(boost::phoenix::ref(boxes)) , space))
{
std::clog << "mapnik-index (GeoJSON) : could not extract bounding boxes from : '" << filename << "'" << std::endl;
return std::make_pair(false, extent);
@@ -93,12 +112,28 @@ std::pair<bool,box2d<double>> process_geojson_file(T & boxes, std::string const&
{
std::clog << "mapnik-index (GeoJSON): " << ex.what() << std::endl;
}
+ mapnik::context_ptr ctx = std::make_shared<mapnik::context_type>();
+ std::size_t start_id = 1;
for (auto const& item : boxes)
{
if (item.first.valid())
{
if (!extent.valid()) extent = item.first;
else extent.expand_to_include(item.first);
+
+ if (validate_features)
+ {
+ base_iterator_type feat_itr = start + item.second.first;
+ base_iterator_type feat_end = feat_itr + item.second.second;
+ feature_validate_callback callback(item.first);
+ bool result = boost::spirit::qi::phrase_parse(feat_itr, feat_end, (fc_grammar)
+ (boost::phoenix::ref(ctx), boost::phoenix::ref(start_id), boost::phoenix::ref(callback)),
+ space);
+ if (!result || feat_itr != feat_end)
+ {
+ return std::make_pair(false, extent);
+ }
+ }
}
}
return std::make_pair(true, extent);
@@ -107,6 +142,6 @@ std::pair<bool,box2d<double>> process_geojson_file(T & boxes, std::string const&
using box_type = mapnik::box2d<double>;
using item_type = std::pair<box_type, std::pair<std::size_t, std::size_t>>;
using boxes_type = std::vector<item_type>;
-template std::pair<bool,box2d<double>> process_geojson_file(boxes_type&, std::string const&);
+template std::pair<bool,box2d<double>> process_geojson_file(boxes_type&, std::string const&, bool);
}}
diff --git a/utils/mapnik-index/process_geojson_file.hpp b/utils/mapnik-index/process_geojson_file.hpp
index d7ccd63..a4d468a 100644
--- a/utils/mapnik-index/process_geojson_file.hpp
+++ b/utils/mapnik-index/process_geojson_file.hpp
@@ -29,7 +29,7 @@
namespace mapnik { namespace detail {
template <typename T>
-std::pair<bool, box2d<double>> process_geojson_file(T & boxes, std::string const& filename);
+std::pair<bool, box2d<double>> process_geojson_file(T & boxes, std::string const& filename, bool validate_features);
}}
diff --git a/utils/shapefile/shapefile_reader.py b/utils/shapefile/shapefile_reader.py
index 1519c67..a57d516 100755
--- a/utils/shapefile/shapefile_reader.py
+++ b/utils/shapefile/shapefile_reader.py
@@ -29,16 +29,24 @@ def test_record(_type, record) :
test_polygon(record)
def test_pointz(record):
+ _type, = struct.unpack("<i", record[0:4])
+ if _type == 0:
+ print "NULL shape"
+ return
if len(record) != 36 :
print>>sys.stderr,"BAD SHAPE FILE: expected 36 bytes got",len(record)
sys.exit(1)
- _type,x,y,z,m = struct.unpack("<idddd",record)
+ x,y,z,m = struct.unpack("<dddd",record[4:36])
if _type != 11:
print>>sys.stderr,"BAD SHAPE FILE: expected PointZ or NullShape got",_type
sys.exit(1)
def test_polygon(record):
- _type, x0, y0, x1, y0, num_parts, num_points = struct.unpack("<iddddii", record[0:44])
+ _type, = struct.unpack("<i", record[0:4])
+ if _type == 0:
+ print "NULL shape"
+ return
+ x0, y0, x1, y0, num_parts, num_points = struct.unpack("<ddddii", record[4:44])
if _type != 5:
print>>sys.stderr, "BAD SHAPE FILE: expected Polygon or NullShape got", _type
sys.exit(1)
@@ -85,7 +93,7 @@ if __name__ == "__main__" :
record = struct.Struct(">II")
calc_total_size = 50
count = 0
- while shx.tell() < shx_file_length * 2 :
+ while shx.tell() <= shx_file_length * 2 - 4 * 2 :
offset,shx_content_length = record.unpack_from(shx.read(8))
shp.seek(offset*2, os.SEEK_SET)
record_number,content_length = record_header.unpack_from(shp.read(8))
diff --git a/utils/shapeindex/shapeindex.cpp b/utils/shapeindex/shapeindex.cpp
index 5555c20..a9c5242 100644
--- a/utils/shapeindex/shapeindex.cpp
+++ b/utils/shapeindex/shapeindex.cpp
@@ -162,7 +162,7 @@ int main (int argc,char** argv)
mapnik::quad_tree<int> tree(extent, depth, ratio);
int count = 0;
- while (true)
+ while (shx.is_good() && pos <= file_length - 4)
{
int offset = shx.read_xdr_integer();
int content_length = shx.read_xdr_integer();
@@ -189,34 +189,40 @@ int main (int argc,char** argv)
{
shp.read_envelope(item_ext);
}
-
- tree.insert(offset * 2,item_ext);
-
if (verbose)
{
std::clog << "record number " << record_number << " box=" << item_ext << std::endl;
}
- ++count;
- if (pos >= file_length) break;
+ if (item_ext.valid())
+ {
+ tree.insert(offset * 2,item_ext);
+ ++count;
+ }
}
- std::clog << " number shapes=" << count << std::endl;
-
- std::fstream file((shapename+".index").c_str(),
- std::ios::in | std::ios::out | std::ios::trunc | std::ios::binary);
- if (!file)
+ if (count > 0)
{
- std::clog << "cannot open index file for writing file \""
- << (shapename+".index") << "\"" << std::endl;
+ std::clog << " number shapes=" << count << std::endl;
+ std::fstream file((shapename+".index").c_str(),
+ std::ios::in | std::ios::out | std::ios::trunc | std::ios::binary);
+ if (!file)
+ {
+ std::clog << "cannot open index file for writing file \""
+ << (shapename+".index") << "\"" << std::endl;
+ }
+ else
+ {
+ tree.trim();
+ std::clog << " number nodes=" << tree.count() << std::endl;
+ file.exceptions(std::ios::failbit | std::ios::badbit);
+ tree.write(file);
+ file.flush();
+ file.close();
+ }
}
else
{
- tree.trim();
- std::clog << " number nodes=" << tree.count() << std::endl;
- file.exceptions(std::ios::failbit | std::ios::badbit);
- tree.write(file);
- file.flush();
- file.close();
+ std::clog << "No non-empty geometries in shapefile" << std::endl;
}
}
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/mapnik.git
More information about the Pkg-grass-devel
mailing list