From 9b9bde7f34900cd8081a614720e6d30c195f80fb Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Fri, 10 Oct 2014 13:48:30 +0200 Subject: [PATCH 1/7] [test][centroid] Add test for big doubles. --- test/algorithms/centroid.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/algorithms/centroid.cpp b/test/algorithms/centroid.cpp index f3ef78688..d7a795f43 100644 --- a/test/algorithms/centroid.cpp +++ b/test/algorithms/centroid.cpp @@ -129,6 +129,19 @@ void test_large_integers() BOOST_CHECK_EQUAL(bg::get<1>(int_centroid), bg::get<1>(double_centroid_as_int)); } +void test_large_doubles() +{ + typedef bg::model::point point; + point pt; + bg::model::polygon poly; + + // related to ticket #10643 + bg::read_wkt("POLYGON((1074699.93 703064.65, 1074703.90 703064.58, 1074704.53 703061.40, 1074702.10 703054.62, 1074699.93 703064.65))", poly); + + bg::centroid(poly, pt); + + BOOST_CHECK(bg::within(pt, poly) == true); +} int test_main(int, char* []) { @@ -149,6 +162,9 @@ int test_main(int, char* []) // The test currently fails in release mode. TODO: fix this test_large_integers(); #endif + + test_large_doubles(); + test_exceptions >(); return 0; From d20bd1f0209b8f4e1f3d8a3e7580f898807820e6 Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Fri, 10 Oct 2014 22:29:16 +0200 Subject: [PATCH 2/7] [test][to_svg] Add geom_to_svg() helper function. --- test/to_svg.hpp | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/test/to_svg.hpp b/test/to_svg.hpp index da1fea778..e2eccd54f 100644 --- a/test/to_svg.hpp +++ b/test/to_svg.hpp @@ -187,6 +187,52 @@ inline void turns_to_svg(Turns const& turns, Mapper & mapper, bool /*enrich*/ = } } +template +inline void geom_to_svg(G1 const& g1, bg::svg_mapper

& mapper) +{ + mapper.add(g1); + + mapper.map(g1, "fill-opacity:0.5;fill:rgb(153,204,0);" + "stroke:rgb(153,204,0);stroke-width:3"); +} + +template +inline void geom_to_svg(G1 const& g1, G2 const& g2, bg::svg_mapper

& mapper) +{ + mapper.add(g1); + mapper.add(g2); + + mapper.map(g1, "fill-opacity:0.5;fill:rgb(153,204,0);" + "stroke:rgb(153,204,0);stroke-width:3"); + mapper.map(g2, "fill-opacity:0.3;fill:rgb(51,51,153);" + "stroke:rgb(51,51,153);stroke-width:3"); +} + +template +inline void geom_to_svg(G1 const& g1, std::string const& filename) +{ + namespace bg = boost::geometry; + typedef typename bg::point_type::type mapper_point_type; + + std::ofstream svg(filename.c_str(), std::ios::trunc); + bg::svg_mapper mapper(svg, 500, 500); + + geom_to_svg(g1, mapper); +} + +template +inline void geom_to_svg(G1 const& g1, G2 const& g2, std::string const& filename) +{ + namespace bg = boost::geometry; + typedef typename bg::point_type::type mapper_point_type; + + std::ofstream svg(filename.c_str(), std::ios::trunc); + bg::svg_mapper mapper(svg, 500, 500); + + geom_to_svg(g1, g2, mapper); +} + + struct to_svg_assign_policy : bg::detail::overlay::assign_null_policy { From 379c40ea2038dbc551538a5db64731dd99441698 Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Fri, 10 Oct 2014 22:30:08 +0200 Subject: [PATCH 3/7] [test][centroid] Improve the test for Polygon using big coordinates. --- test/algorithms/centroid.cpp | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/test/algorithms/centroid.cpp b/test/algorithms/centroid.cpp index d7a795f43..4c29b5dde 100644 --- a/test/algorithms/centroid.cpp +++ b/test/algorithms/centroid.cpp @@ -129,18 +129,33 @@ void test_large_integers() BOOST_CHECK_EQUAL(bg::get<1>(int_centroid), bg::get<1>(double_centroid_as_int)); } +//#include + void test_large_doubles() { typedef bg::model::point point; - point pt; - bg::model::polygon poly; + point pt_far, pt_near; + bg::model::polygon poly_far, poly_near; // related to ticket #10643 - bg::read_wkt("POLYGON((1074699.93 703064.65, 1074703.90 703064.58, 1074704.53 703061.40, 1074702.10 703054.62, 1074699.93 703064.65))", poly); + bg::read_wkt("POLYGON((1074699.93 703064.65, 1074703.90 703064.58, 1074704.53 703061.40, 1074702.10 703054.62, 1074699.93 703064.65))", poly_far); + bg::read_wkt("POLYGON((699.93 64.65, 703.90 64.58, 704.53 61.40, 702.10 54.62, 699.93 64.65))", poly_near); - bg::centroid(poly, pt); + bg::centroid(poly_far, pt_far); + bg::centroid(poly_near, pt_near); - BOOST_CHECK(bg::within(pt, poly) == true); + BOOST_CHECK(bg::within(pt_far, poly_far)); + BOOST_CHECK(bg::within(pt_near, poly_near)); + + point pt_near_moved; + bg::set<0>(pt_near_moved, bg::get<0>(pt_near) + 1074000.0); + bg::set<1>(pt_near_moved, bg::get<1>(pt_near) + 703000.0); + + //geom_to_svg(poly_far, pt_far, "far.svg"); + //geom_to_svg(poly_near, pt_near, "near.svg"); + + double d = bg::distance(pt_far, pt_near_moved); + BOOST_CHECK(d < 0.1); } int test_main(int, char* []) From d7722e190adb7927246d0b93f3e915a523a51357 Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Sat, 11 Oct 2014 00:14:36 +0200 Subject: [PATCH 4/7] [centroid] Reduce numerical errors by translating the Geometry closer to 0 and then the result back. The first Point of the Geometry is used as the new origin. During the centroid calculation each Point is translated by subtracting the origin. At the end the resulting point is translated back by adding the origin. --- .../boost/geometry/algorithms/centroid.hpp | 114 +++++++++++++++--- 1 file changed, 95 insertions(+), 19 deletions(-) diff --git a/include/boost/geometry/algorithms/centroid.hpp b/include/boost/geometry/algorithms/centroid.hpp index 2d8a737a1..3aa6bf88e 100644 --- a/include/boost/geometry/algorithms/centroid.hpp +++ b/include/boost/geometry/algorithms/centroid.hpp @@ -50,6 +50,8 @@ #include #include +#include + namespace boost { namespace geometry { @@ -188,6 +190,30 @@ inline bool range_ok(Range const& range, Point& centroid) return true; } +template +struct translating_transformer +{ + typedef Pt result_type; + + translating_transformer(Pt const& origin) + : m_origin(origin) + {} + + result_type apply(Pt const& pt) const + { + Pt res = pt; + geometry::subtract_point(res, m_origin); + return res; + } + + template + void apply_reverse(ResPt & res_pt) const + { + geometry::add_point(res_pt, m_origin); + } + + Pt const& m_origin; +}; /*! \brief Calculate the centroid of a ring. @@ -195,9 +221,11 @@ inline bool range_ok(Range const& range, Point& centroid) template struct centroid_range_state { - template + template static inline void apply(Ring const& ring, - Strategy const& strategy, typename Strategy::state_type& state) + PointTransformer const& transformer, + Strategy const& strategy, + typename Strategy::state_type& state) { typedef typename closeable_view::type view_type; @@ -207,11 +235,17 @@ struct centroid_range_state iterator_type it = boost::begin(view); iterator_type end = boost::end(view); - for (iterator_type previous = it++; - it != end; - ++previous, ++it) + typename PointTransformer::result_type + previous_pt = transformer.apply(*it); + + for ( ++it ; it != end ; ++it) { - strategy.apply(*previous, *it, state); + typename PointTransformer::result_type + pt = transformer.apply(*it); + + strategy.apply(previous_pt, pt, state); + + previous_pt = pt; } } }; @@ -221,13 +255,22 @@ struct centroid_range { template static inline void apply(Range const& range, Point& centroid, - Strategy const& strategy) + Strategy const& strategy) { if (range_ok(range, centroid)) { + // prepare translation transformer + typedef typename geometry::point_type::type point_type; + translating_transformer + transformer(*boost::begin(range)); + typename Strategy::state_type state; - centroid_range_state::apply(range, strategy, state); + centroid_range_state::apply(range, transformer, + strategy, state); strategy.result(state, centroid); + + // translate the result back + transformer.apply_reverse(centroid); } } }; @@ -240,14 +283,16 @@ struct centroid_range */ struct centroid_polygon_state { - template + template static inline void apply(Polygon const& poly, - Strategy const& strategy, typename Strategy::state_type& state) + PointTransformer const& transformer, + Strategy const& strategy, + typename Strategy::state_type& state) { typedef typename ring_type::type ring_type; typedef centroid_range_state::value> per_ring; - per_ring::apply(exterior_ring(poly), strategy, state); + per_ring::apply(exterior_ring(poly), transformer, strategy, state); typename interior_return_type::type rings = interior_rings(poly); @@ -255,7 +300,7 @@ struct centroid_polygon_state for (typename detail::interior_iterator::type it = boost::begin(rings); it != boost::end(rings); ++it) { - per_ring::apply(*it, strategy, state); + per_ring::apply(*it, transformer, strategy, state); } } }; @@ -268,9 +313,17 @@ struct centroid_polygon { if (range_ok(exterior_ring(poly), centroid)) { + // prepare translation transformer + typedef typename geometry::point_type::type point_type; + translating_transformer + transformer(*boost::begin(bg::exterior_ring(poly))); + typename Strategy::state_type state; - centroid_polygon_state::apply(poly, strategy, state); + centroid_polygon_state::apply(poly, transformer, strategy, state); strategy.result(state, centroid); + + // translate the result back + transformer.apply_reverse(centroid); } } }; @@ -282,11 +335,13 @@ struct centroid_polygon */ struct centroid_multi_point_state { - template + template static inline void apply(Point const& point, - Strategy const& strategy, typename Strategy::state_type& state) + PointTransformer const& transformer, + Strategy const& strategy, + typename Strategy::state_type& state) { - strategy.apply(point, state); + strategy.apply(transformer.apply(point), state); } }; @@ -303,8 +358,9 @@ template struct centroid_multi { template - static inline void apply(Multi const& multi, Point& centroid, - Strategy const& strategy) + static inline void apply(Multi const& multi, + Point& centroid, + Strategy const& strategy) { #if ! defined(BOOST_GEOMETRY_CENTROID_NO_THROW) // If there is nothing in any of the ranges, it is not possible @@ -315,6 +371,23 @@ struct centroid_multi } #endif + // prepare translation transformer + typedef typename geometry::point_type::type point_type; + point_type origin; + { + geometry::point_iterator + pt_it = geometry::points_begin(multi); + if ( pt_it != geometry::points_end(multi) ) + { + origin = *pt_it; + } + else + { + geometry::assign_zero(origin); + } + } + translating_transformer transformer(origin); + typename Strategy::state_type state; for (typename boost::range_iterator::type @@ -322,9 +395,12 @@ struct centroid_multi it != boost::end(multi); ++it) { - Policy::apply(*it, strategy, state); + Policy::apply(*it, transformer, strategy, state); } Strategy::result(state, centroid); + + // translate the result back + transformer.apply_reverse(centroid); } }; From 5e3656a09ac796de11c960d7880b3752d504428c Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Sat, 11 Oct 2014 01:42:20 +0200 Subject: [PATCH 5/7] [centroid] Disable error-reducing translation for other coordinate systems than cartesian. Remove undefined namespace. Add missing headers. Add a note about other coordinate systems. Add copyright info. --- .../boost/geometry/algorithms/centroid.hpp | 40 +++++++++++++++++-- test/algorithms/centroid.cpp | 5 +++ 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/include/boost/geometry/algorithms/centroid.hpp b/include/boost/geometry/algorithms/centroid.hpp index 3aa6bf88e..392fc437e 100644 --- a/include/boost/geometry/algorithms/centroid.hpp +++ b/include/boost/geometry/algorithms/centroid.hpp @@ -5,6 +5,11 @@ // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. // Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland. +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014 Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -18,6 +23,7 @@ #include +#include #include #include #include @@ -36,9 +42,11 @@ #include +#include #include #include #include +#include #include #include #include @@ -190,8 +198,28 @@ inline bool range_ok(Range const& range, Point& centroid) return true; } -template +// NOTE: There is no need to translate in other coordinate systems than +// cartesian. But if it was needed then one should translate using +// CS-specific technique, e.g. in spherical/geographic a translation +// vector should contain coordinates being multiplies of 2PI or 360 deg. +template ::type> struct translating_transformer +{ + typedef boost::reference_wrapper result_type; + + translating_transformer(Pt const&) {} + + result_type apply(Pt const& pt) const + { + return result_type(pt); + } + + template + void apply_reverse(ResPt & res_pt) const {} +}; + +template +struct translating_transformer { typedef Pt result_type; @@ -227,6 +255,7 @@ struct centroid_range_state Strategy const& strategy, typename Strategy::state_type& state) { + typedef typename geometry::point_type::type point_type; typedef typename closeable_view::type view_type; typedef typename boost::range_iterator::type iterator_type; @@ -243,7 +272,9 @@ struct centroid_range_state typename PointTransformer::result_type pt = transformer.apply(*it); - strategy.apply(previous_pt, pt, state); + strategy.apply(static_cast(previous_pt), + static_cast(pt), + state); previous_pt = pt; } @@ -316,7 +347,7 @@ struct centroid_polygon // prepare translation transformer typedef typename geometry::point_type::type point_type; translating_transformer - transformer(*boost::begin(bg::exterior_ring(poly))); + transformer(*boost::begin(exterior_ring(poly))); typename Strategy::state_type state; centroid_polygon_state::apply(poly, transformer, strategy, state); @@ -341,7 +372,8 @@ struct centroid_multi_point_state Strategy const& strategy, typename Strategy::state_type& state) { - strategy.apply(transformer.apply(point), state); + strategy.apply(static_cast(transformer.apply(point)), + state); } }; diff --git a/test/algorithms/centroid.cpp b/test/algorithms/centroid.cpp index 4c29b5dde..8e3af7f75 100644 --- a/test/algorithms/centroid.cpp +++ b/test/algorithms/centroid.cpp @@ -5,6 +5,11 @@ // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014 Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. From 95b3fb45d387de4a1887b4e417dafdae1af54969 Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Sat, 11 Oct 2014 11:57:49 +0200 Subject: [PATCH 6/7] [centroid] Disable translation for non-areal Geometries. --- .../boost/geometry/algorithms/centroid.hpp | 81 ++++++++++++------- 1 file changed, 50 insertions(+), 31 deletions(-) diff --git a/include/boost/geometry/algorithms/centroid.hpp b/include/boost/geometry/algorithms/centroid.hpp index 392fc437e..5d58fafb6 100644 --- a/include/boost/geometry/algorithms/centroid.hpp +++ b/include/boost/geometry/algorithms/centroid.hpp @@ -202,34 +202,42 @@ inline bool range_ok(Range const& range, Point& centroid) // cartesian. But if it was needed then one should translate using // CS-specific technique, e.g. in spherical/geographic a translation // vector should contain coordinates being multiplies of 2PI or 360 deg. -template ::type> +template ::type, + areal_tag + >::type, + typename CSTag = typename cs_tag::type> struct translating_transformer { - typedef boost::reference_wrapper result_type; + typedef typename geometry::point_type::type point_type; + typedef boost::reference_wrapper result_type; - translating_transformer(Pt const&) {} + translating_transformer(point_type const&) {} - result_type apply(Pt const& pt) const + result_type apply(point_type const& pt) const { return result_type(pt); } template - void apply_reverse(ResPt & res_pt) const {} + void apply_reverse(ResPt &) const {} }; -template -struct translating_transformer +template +struct translating_transformer { - typedef Pt result_type; + typedef typename geometry::point_type::type point_type; + typedef point_type result_type; - translating_transformer(Pt const& origin) + translating_transformer(point_type const& origin) : m_origin(origin) {} - result_type apply(Pt const& pt) const + result_type apply(point_type const& pt) const { - Pt res = pt; + point_type res = pt; geometry::subtract_point(res, m_origin); return res; } @@ -240,11 +248,36 @@ struct translating_transformer geometry::add_point(res_pt, m_origin); } - Pt const& m_origin; + point_type const& m_origin; }; +template +inline void assign_origin(Geometry const& geom, + typename geometry::point_type::type & origin) +{ + static const bool is_areal + = boost::is_same + < + typename tag_cast::type, areal_tag>::type, + areal_tag + >::value; + + if ( is_areal ) + { + geometry::point_iterator + pt_it = geometry::points_begin(geom); + if ( pt_it != geometry::points_end(geom) ) + { + origin = *pt_it; + return; + } + } + + geometry::assign_zero(origin); +} + /*! - \brief Calculate the centroid of a ring. + \brief Calculate the centroid of a Ring or a Linestring. */ template struct centroid_range_state @@ -291,9 +324,7 @@ struct centroid_range if (range_ok(range, centroid)) { // prepare translation transformer - typedef typename geometry::point_type::type point_type; - translating_transformer - transformer(*boost::begin(range)); + translating_transformer transformer(*boost::begin(range)); typename Strategy::state_type state; centroid_range_state::apply(range, transformer, @@ -345,8 +376,7 @@ struct centroid_polygon if (range_ok(exterior_ring(poly), centroid)) { // prepare translation transformer - typedef typename geometry::point_type::type point_type; - translating_transformer + translating_transformer transformer(*boost::begin(exterior_ring(poly))); typename Strategy::state_type state; @@ -406,19 +436,8 @@ struct centroid_multi // prepare translation transformer typedef typename geometry::point_type::type point_type; point_type origin; - { - geometry::point_iterator - pt_it = geometry::points_begin(multi); - if ( pt_it != geometry::points_end(multi) ) - { - origin = *pt_it; - } - else - { - geometry::assign_zero(origin); - } - } - translating_transformer transformer(origin); + assign_origin(multi, origin); + translating_transformer transformer(origin); typename Strategy::state_type state; From eee5b9e6ea03bf24ed26eb6e11c2ac7a326650da Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Sat, 18 Oct 2014 17:27:52 +0200 Subject: [PATCH 7/7] [centroid] Move translating_transformer to separate file. Add ctor taking Geometry to transformer. This allows to encapsulate the origin-retrieving-logic inside the transformer. Remove assign_origin() function. --- .../boost/geometry/algorithms/centroid.hpp | 88 +------------ .../centroid/translating_transformer.hpp | 119 ++++++++++++++++++ 2 files changed, 121 insertions(+), 86 deletions(-) create mode 100644 include/boost/geometry/algorithms/detail/centroid/translating_transformer.hpp diff --git a/include/boost/geometry/algorithms/centroid.hpp b/include/boost/geometry/algorithms/centroid.hpp index 5d58fafb6..65dc9c375 100644 --- a/include/boost/geometry/algorithms/centroid.hpp +++ b/include/boost/geometry/algorithms/centroid.hpp @@ -23,9 +23,7 @@ #include -#include #include -#include #include #include #include @@ -46,7 +44,6 @@ #include #include #include -#include #include #include #include @@ -58,7 +55,7 @@ #include #include -#include +#include namespace boost { namespace geometry @@ -198,84 +195,6 @@ inline bool range_ok(Range const& range, Point& centroid) return true; } -// NOTE: There is no need to translate in other coordinate systems than -// cartesian. But if it was needed then one should translate using -// CS-specific technique, e.g. in spherical/geographic a translation -// vector should contain coordinates being multiplies of 2PI or 360 deg. -template ::type, - areal_tag - >::type, - typename CSTag = typename cs_tag::type> -struct translating_transformer -{ - typedef typename geometry::point_type::type point_type; - typedef boost::reference_wrapper result_type; - - translating_transformer(point_type const&) {} - - result_type apply(point_type const& pt) const - { - return result_type(pt); - } - - template - void apply_reverse(ResPt &) const {} -}; - -template -struct translating_transformer -{ - typedef typename geometry::point_type::type point_type; - typedef point_type result_type; - - translating_transformer(point_type const& origin) - : m_origin(origin) - {} - - result_type apply(point_type const& pt) const - { - point_type res = pt; - geometry::subtract_point(res, m_origin); - return res; - } - - template - void apply_reverse(ResPt & res_pt) const - { - geometry::add_point(res_pt, m_origin); - } - - point_type const& m_origin; -}; - -template -inline void assign_origin(Geometry const& geom, - typename geometry::point_type::type & origin) -{ - static const bool is_areal - = boost::is_same - < - typename tag_cast::type, areal_tag>::type, - areal_tag - >::value; - - if ( is_areal ) - { - geometry::point_iterator - pt_it = geometry::points_begin(geom); - if ( pt_it != geometry::points_end(geom) ) - { - origin = *pt_it; - return; - } - } - - geometry::assign_zero(origin); -} - /*! \brief Calculate the centroid of a Ring or a Linestring. */ @@ -434,10 +353,7 @@ struct centroid_multi #endif // prepare translation transformer - typedef typename geometry::point_type::type point_type; - point_type origin; - assign_origin(multi, origin); - translating_transformer transformer(origin); + translating_transformer transformer(multi); typename Strategy::state_type state; diff --git a/include/boost/geometry/algorithms/detail/centroid/translating_transformer.hpp b/include/boost/geometry/algorithms/detail/centroid/translating_transformer.hpp new file mode 100644 index 000000000..56a7e3ec9 --- /dev/null +++ b/include/boost/geometry/algorithms/detail/centroid/translating_transformer.hpp @@ -0,0 +1,119 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 Mateusz Loskot, London, UK. +// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014 Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_CENTROID_TRANSLATING_TRANSFORMER_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CENTROID_TRANSLATING_TRANSFORMER_HPP + + +#include + +#include +#include + +#include +#include +#include +#include + +#include + +#include + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace centroid +{ + + +// NOTE: There is no need to translate in other coordinate systems than +// cartesian. But if it was needed then one should translate using +// CS-specific technique, e.g. in spherical/geographic a translation +// vector should contain coordinates being multiplies of 2PI or 360 deg. +template ::type, + areal_tag + >::type, + typename CSTag = typename cs_tag::type> +struct translating_transformer +{ + typedef typename geometry::point_type::type point_type; + typedef boost::reference_wrapper result_type; + + explicit translating_transformer(Geometry const&) {} + explicit translating_transformer(point_type const&) {} + + result_type apply(point_type const& pt) const + { + return result_type(pt); + } + + template + void apply_reverse(ResPt &) const {} +}; + +// Specialization for Areal Geometries in cartesian CS +template +struct translating_transformer +{ + typedef typename geometry::point_type::type point_type; + typedef point_type result_type; + + explicit translating_transformer(Geometry const& geom) + : m_origin(NULL) + { + geometry::point_iterator + pt_it = geometry::points_begin(geom); + if ( pt_it != geometry::points_end(geom) ) + { + m_origin = boost::addressof(*pt_it); + } + } + + explicit translating_transformer(point_type const& origin) + : m_origin(boost::addressof(origin)) + {} + + result_type apply(point_type const& pt) const + { + point_type res = pt; + if ( m_origin ) + geometry::subtract_point(res, *m_origin); + return res; + } + + template + void apply_reverse(ResPt & res_pt) const + { + if ( m_origin ) + geometry::add_point(res_pt, *m_origin); + } + + const point_type * m_origin; +}; + + +}} // namespace detail::centroid +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CENTROID_TRANSLATING_TRANSFORMER_HPP