summaryrefslogtreecommitdiff
path: root/boost/geometry/algorithms/centroid.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/geometry/algorithms/centroid.hpp')
-rw-r--r--boost/geometry/algorithms/centroid.hpp434
1 files changed, 295 insertions, 139 deletions
diff --git a/boost/geometry/algorithms/centroid.hpp b/boost/geometry/algorithms/centroid.hpp
index 69ad9fe829..65dc9c3753 100644
--- a/boost/geometry/algorithms/centroid.hpp
+++ b/boost/geometry/algorithms/centroid.hpp
@@ -3,6 +3,12 @@
// 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
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -18,7 +24,9 @@
#include <cstddef>
#include <boost/range.hpp>
-#include <boost/typeof/typeof.hpp>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/cs.hpp>
@@ -27,17 +35,27 @@
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/core/tag_cast.hpp>
+#include <boost/geometry/core/tags.hpp>
+#include <boost/geometry/core/point_type.hpp>
-#include <boost/geometry/algorithms/convert.hpp>
-#include <boost/geometry/algorithms/distance.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
+
+#include <boost/geometry/algorithms/assign.hpp>
+#include <boost/geometry/algorithms/detail/interior_iterator.hpp>
+#include <boost/geometry/algorithms/convert.hpp>
+#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/strategies/centroid.hpp>
#include <boost/geometry/strategies/concepts/centroid_concept.hpp>
+#include <boost/geometry/strategies/default_strategy.hpp>
#include <boost/geometry/views/closeable_view.hpp>
#include <boost/geometry/util/for_each_coordinate.hpp>
#include <boost/geometry/util/select_coordinate_type.hpp>
+#include <boost/geometry/algorithms/num_points.hpp>
+#include <boost/geometry/multi/algorithms/num_points.hpp>
+
+#include <boost/geometry/algorithms/detail/centroid/translating_transformer.hpp>
namespace boost { namespace geometry
@@ -62,8 +80,15 @@ class centroid_exception : public geometry::exception
{
public:
+ /*!
+ \brief The default constructor
+ */
inline centroid_exception() {}
+ /*!
+ \brief Returns the explanatory string.
+ \return Pointer to a null-terminated string with explanatory information.
+ */
virtual char const* what() const throw()
{
return "Boost.Geometry Centroid calculation exception";
@@ -77,9 +102,9 @@ public:
namespace detail { namespace centroid
{
-template<typename Point, typename PointCentroid, typename Strategy>
struct centroid_point
{
+ template<typename Point, typename PointCentroid, typename Strategy>
static inline void apply(Point const& point, PointCentroid& centroid,
Strategy const&)
{
@@ -89,55 +114,56 @@ struct centroid_point
template
<
- typename Box,
+ typename Indexed,
typename Point,
std::size_t Dimension,
std::size_t DimensionCount
>
-struct centroid_box_calculator
+struct centroid_indexed_calculator
{
typedef typename select_coordinate_type
<
- Box, Point
+ Indexed, Point
>::type coordinate_type;
- static inline void apply(Box const& box, Point& centroid)
+ static inline void apply(Indexed const& indexed, Point& centroid)
{
- coordinate_type const c1 = get<min_corner, Dimension>(box);
- coordinate_type const c2 = get<max_corner, Dimension>(box);
+ coordinate_type const c1 = get<min_corner, Dimension>(indexed);
+ coordinate_type const c2 = get<max_corner, Dimension>(indexed);
coordinate_type m = c1 + c2;
- m /= 2.0;
+ coordinate_type const two = 2;
+ m /= two;
set<Dimension>(centroid, m);
- centroid_box_calculator
+ centroid_indexed_calculator
<
- Box, Point,
+ Indexed, Point,
Dimension + 1, DimensionCount
- >::apply(box, centroid);
+ >::apply(indexed, centroid);
}
};
-template<typename Box, typename Point, std::size_t DimensionCount>
-struct centroid_box_calculator<Box, Point, DimensionCount, DimensionCount>
+template<typename Indexed, typename Point, std::size_t DimensionCount>
+struct centroid_indexed_calculator<Indexed, Point, DimensionCount, DimensionCount>
{
- static inline void apply(Box const& , Point& )
+ static inline void apply(Indexed const& , Point& )
{
}
};
-template<typename Box, typename Point, typename Strategy>
-struct centroid_box
+struct centroid_indexed
{
- static inline void apply(Box const& box, Point& centroid,
+ template<typename Indexed, typename Point, typename Strategy>
+ static inline void apply(Indexed const& indexed, Point& centroid,
Strategy const&)
{
- centroid_box_calculator
+ centroid_indexed_calculator
<
- Box, Point,
- 0, dimension<Box>::type::value
- >::apply(box, centroid);
+ Indexed, Point,
+ 0, dimension<Indexed>::type::value
+ >::apply(indexed, centroid);
}
};
@@ -169,16 +195,19 @@ inline bool range_ok(Range const& range, Point& centroid)
return true;
}
-
/*!
- \brief Calculate the centroid of a ring.
+ \brief Calculate the centroid of a Ring or a Linestring.
*/
-template<typename Ring, closure_selector Closure, typename Strategy>
+template <closure_selector Closure>
struct centroid_range_state
{
+ template<typename Ring, typename PointTransformer, typename Strategy>
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 geometry::point_type<Ring const>::type point_type;
typedef typename closeable_view<Ring const, Closure>::type view_type;
typedef typename boost::range_iterator<view_type const>::type iterator_type;
@@ -187,31 +216,42 @@ 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(static_cast<point_type const&>(previous_pt),
+ static_cast<point_type const&>(pt),
+ state);
+
+ previous_pt = pt;
}
}
};
-template<typename Range, typename Point, closure_selector Closure, typename Strategy>
+template <closure_selector Closure>
struct centroid_range
{
+ template<typename Range, typename Point, typename Strategy>
static inline void apply(Range const& range, Point& centroid,
- Strategy const& strategy)
+ Strategy const& strategy)
{
if (range_ok(range, centroid))
{
+ // prepare translation transformer
+ translating_transformer<Range> transformer(*boost::begin(range));
+
typename Strategy::state_type state;
- centroid_range_state
- <
- Range,
- Closure,
- Strategy
- >::apply(range, strategy, state);
+ centroid_range_state<Closure>::apply(range, transformer,
+ strategy, state);
strategy.result(state, centroid);
+
+ // translate the result back
+ transformer.apply_reverse(centroid);
}
}
};
@@ -222,48 +262,112 @@ struct centroid_range
\note Because outer ring is clockwise, inners are counter clockwise,
triangle approach is OK and works for polygons with rings.
*/
-template<typename Polygon, typename Strategy>
struct centroid_polygon_state
{
- typedef typename ring_type<Polygon>::type ring_type;
-
+ template<typename Polygon, typename PointTransformer, typename Strategy>
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 centroid_range_state
- <
- ring_type,
- geometry::closure<ring_type>::value,
- Strategy
- > per_ring;
+ typedef typename ring_type<Polygon>::type ring_type;
+ typedef centroid_range_state<geometry::closure<ring_type>::value> per_ring;
- per_ring::apply(exterior_ring(poly), strategy, state);
+ per_ring::apply(exterior_ring(poly), transformer, strategy, state);
- typename interior_return_type<Polygon const>::type rings
- = interior_rings(poly);
- for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
+ typename interior_return_type<Polygon const>::type
+ rings = interior_rings(poly);
+
+ for (typename detail::interior_iterator<Polygon const>::type
+ it = boost::begin(rings); it != boost::end(rings); ++it)
{
- per_ring::apply(*it, strategy, state);
+ per_ring::apply(*it, transformer, strategy, state);
}
}
};
-template<typename Polygon, typename Point, typename Strategy>
struct centroid_polygon
{
+ template<typename Polygon, typename Point, typename Strategy>
static inline void apply(Polygon const& poly, Point& centroid,
Strategy const& strategy)
{
if (range_ok(exterior_ring(poly), centroid))
{
+ // prepare translation transformer
+ translating_transformer<Polygon>
+ transformer(*boost::begin(exterior_ring(poly)));
+
typename Strategy::state_type state;
- centroid_polygon_state
- <
- Polygon,
- Strategy
- >::apply(poly, strategy, state);
+ centroid_polygon_state::apply(poly, transformer, strategy, state);
strategy.result(state, centroid);
+
+ // translate the result back
+ transformer.apply_reverse(centroid);
+ }
+ }
+};
+
+
+/*!
+ \brief Building block of a multi-point, to be used as Policy in the
+ more generec centroid_multi
+*/
+struct centroid_multi_point_state
+{
+ template <typename Point, typename PointTransformer, typename Strategy>
+ static inline void apply(Point const& point,
+ PointTransformer const& transformer,
+ Strategy const& strategy,
+ typename Strategy::state_type& state)
+ {
+ strategy.apply(static_cast<Point const&>(transformer.apply(point)),
+ state);
+ }
+};
+
+
+/*!
+ \brief Generic implementation which calls a policy to calculate the
+ centroid of the total of its single-geometries
+ \details The Policy is, in general, the single-version, with state. So
+ detail::centroid::centroid_polygon_state is used as a policy for this
+ detail::centroid::centroid_multi
+
+*/
+template <typename Policy>
+struct centroid_multi
+{
+ template <typename Multi, typename Point, typename 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
+ // to calculate the centroid
+ if (geometry::num_points(multi) == 0)
+ {
+ throw centroid_exception();
}
+#endif
+
+ // prepare translation transformer
+ translating_transformer<Multi> transformer(multi);
+
+ typename Strategy::state_type state;
+
+ for (typename boost::range_iterator<Multi const>::type
+ it = boost::begin(multi);
+ it != boost::end(multi);
+ ++it)
+ {
+ Policy::apply(*it, transformer, strategy, state);
+ }
+ Strategy::result(state, centroid);
+
+ // translate the result back
+ transformer.apply_reverse(centroid);
}
};
@@ -278,64 +382,153 @@ namespace dispatch
template
<
- typename Tag,
typename Geometry,
- typename Point,
- typename Strategy
+ typename Tag = typename tag<Geometry>::type
>
-struct centroid {};
+struct centroid: not_implemented<Tag>
+{};
-template
-<
- typename Geometry,
- typename Point,
- typename Strategy
->
-struct centroid<point_tag, Geometry, Point, Strategy>
- : detail::centroid::centroid_point<Geometry, Point, Strategy>
+template <typename Geometry>
+struct centroid<Geometry, point_tag>
+ : detail::centroid::centroid_point
{};
-template
-<
- typename Box,
- typename Point,
- typename Strategy
->
-struct centroid<box_tag, Box, Point, Strategy>
- : detail::centroid::centroid_box<Box, Point, Strategy>
+template <typename Box>
+struct centroid<Box, box_tag>
+ : detail::centroid::centroid_indexed
+{};
+
+template <typename Segment>
+struct centroid<Segment, segment_tag>
+ : detail::centroid::centroid_indexed
+{};
+
+template <typename Ring>
+struct centroid<Ring, ring_tag>
+ : detail::centroid::centroid_range<geometry::closure<Ring>::value>
+{};
+
+template <typename Linestring>
+struct centroid<Linestring, linestring_tag>
+ : detail::centroid::centroid_range<closed>
{};
-template <typename Ring, typename Point, typename Strategy>
-struct centroid<ring_tag, Ring, Point, Strategy>
- : detail::centroid::centroid_range
+template <typename Polygon>
+struct centroid<Polygon, polygon_tag>
+ : detail::centroid::centroid_polygon
+{};
+
+template <typename MultiLinestring>
+struct centroid<MultiLinestring, multi_linestring_tag>
+ : detail::centroid::centroid_multi
<
- Ring,
- Point,
- geometry::closure<Ring>::value,
- Strategy
+ detail::centroid::centroid_range_state<closed>
>
{};
-template <typename Linestring, typename Point, typename Strategy>
-struct centroid<linestring_tag, Linestring, Point, Strategy>
- : detail::centroid::centroid_range
+template <typename MultiPolygon>
+struct centroid<MultiPolygon, multi_polygon_tag>
+ : detail::centroid::centroid_multi
<
- Linestring,
- Point,
- closed,
- Strategy
+ detail::centroid::centroid_polygon_state
+ >
+{};
+
+template <typename MultiPoint>
+struct centroid<MultiPoint, multi_point_tag>
+ : detail::centroid::centroid_multi
+ <
+ detail::centroid::centroid_multi_point_state
>
- {};
+{};
-template <typename Polygon, typename Point, typename Strategy>
-struct centroid<polygon_tag, Polygon, Point, Strategy>
- : detail::centroid::centroid_polygon<Polygon, Point, Strategy>
- {};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
+namespace resolve_strategy {
+
+template <typename Geometry>
+struct centroid
+{
+ template <typename Point, typename Strategy>
+ static inline void apply(Geometry const& geometry, Point& out, Strategy const& strategy)
+ {
+ dispatch::centroid<Geometry>::apply(geometry, out, strategy);
+ }
+
+ template <typename Point>
+ static inline void apply(Geometry const& geometry, Point& out, default_strategy)
+ {
+ typedef typename strategy::centroid::services::default_strategy
+ <
+ typename cs_tag<Geometry>::type,
+ typename tag_cast
+ <
+ typename tag<Geometry>::type,
+ pointlike_tag,
+ linear_tag,
+ areal_tag
+ >::type,
+ dimension<Geometry>::type::value,
+ Point,
+ Geometry
+ >::type strategy_type;
+
+ dispatch::centroid<Geometry>::apply(geometry, out, strategy_type());
+ }
+};
+
+} // namespace resolve_strategy
+
+
+namespace resolve_variant {
+
+template <typename Geometry>
+struct centroid
+{
+ template <typename Point, typename Strategy>
+ static inline void apply(Geometry const& geometry, Point& out, Strategy const& strategy)
+ {
+ concept::check_concepts_and_equal_dimensions<Point, Geometry const>();
+ resolve_strategy::centroid<Geometry>::apply(geometry, out, strategy);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct centroid<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ template <typename Point, typename Strategy>
+ struct visitor: boost::static_visitor<void>
+ {
+ Point& m_out;
+ Strategy const& m_strategy;
+
+ visitor(Point& out, Strategy const& strategy)
+ : m_out(out), m_strategy(strategy)
+ {}
+
+ template <typename Geometry>
+ void operator()(Geometry const& geometry) const
+ {
+ centroid<Geometry>::apply(geometry, m_out, m_strategy);
+ }
+ };
+
+ template <typename Point, typename Strategy>
+ static inline void
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
+ Point& out,
+ Strategy const& strategy)
+ {
+ boost::apply_visitor(visitor<Point, Strategy>(out, strategy), geometry);
+ }
+};
+
+} // namespace resolve_variant
+
+
/*!
\brief \brief_calc{centroid} \brief_strategy
\ingroup centroid
@@ -357,21 +550,7 @@ template<typename Geometry, typename Point, typename Strategy>
inline void centroid(Geometry const& geometry, Point& c,
Strategy const& strategy)
{
- //BOOST_CONCEPT_ASSERT( (geometry::concept::CentroidStrategy<Strategy>) );
-
- concept::check_concepts_and_equal_dimensions<Point, Geometry const>();
-
- typedef typename point_type<Geometry>::type point_type;
-
- // Call dispatch apply method. That one returns true if centroid
- // should be taken from state.
- dispatch::centroid
- <
- typename tag<Geometry>::type,
- Geometry,
- Point,
- Strategy
- >::apply(geometry, c, strategy);
+ resolve_variant::centroid<Geometry>::apply(geometry, c, strategy);
}
@@ -394,24 +573,7 @@ inline void centroid(Geometry const& geometry, Point& c,
template<typename Geometry, typename Point>
inline void centroid(Geometry const& geometry, Point& c)
{
- concept::check_concepts_and_equal_dimensions<Point, Geometry const>();
-
- typedef typename strategy::centroid::services::default_strategy
- <
- typename cs_tag<Geometry>::type,
- typename tag_cast
- <
- typename tag<Geometry>::type,
- pointlike_tag,
- linear_tag,
- areal_tag
- >::type,
- dimension<Geometry>::type::value,
- Point,
- Geometry
- >::type strategy_type;
-
- centroid(geometry, c, strategy_type());
+ centroid(geometry, c, default_strategy());
}
@@ -429,8 +591,6 @@ inline void centroid(Geometry const& geometry, Point& c)
template<typename Point, typename Geometry>
inline Point return_centroid(Geometry const& geometry)
{
- concept::check_concepts_and_equal_dimensions<Point, Geometry const>();
-
Point c;
centroid(geometry, c);
return c;
@@ -454,10 +614,6 @@ inline Point return_centroid(Geometry const& geometry)
template<typename Point, typename Geometry, typename Strategy>
inline Point return_centroid(Geometry const& geometry, Strategy const& strategy)
{
- //BOOST_CONCEPT_ASSERT( (geometry::concept::CentroidStrategy<Strategy>) );
-
- concept::check_concepts_and_equal_dimensions<Point, Geometry const>();
-
Point c;
centroid(geometry, c, strategy);
return c;