From be95eb40d8970afc3cfda8f2b1ce0a1eb6e369f5 Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Sat, 26 Mar 2011 17:01:28 +0000 Subject: [PATCH] Splitted strategy "centroid_weighted_length.hpp from centroid.hpp Added tags pointlike_tag, linear_tag, areal_tag to share strategies Implemented multi_linestring making use of weighted_length [SVN r70571] --- .../boost/geometry/algorithms/centroid.hpp | 82 +++-------- include/boost/geometry/core/tags.hpp | 27 +++- include/boost/geometry/geometry.hpp | 4 + .../geometry/multi/algorithms/centroid.hpp | 21 +++ include/boost/geometry/multi/core/tags.hpp | 6 +- .../strategies/cartesian/centroid_average.hpp | 11 +- .../geometry/multi/strategies/centroid.hpp | 35 +---- .../cartesian/centroid_bashein_detmer.hpp | 20 +-- .../cartesian/centroid_weighted_length.hpp | 139 ++++++++++++++++++ .../boost/geometry/strategies/centroid.hpp | 23 --- .../boost/geometry/strategies/strategies.hpp | 1 + 11 files changed, 224 insertions(+), 145 deletions(-) create mode 100644 include/boost/geometry/strategies/cartesian/centroid_weighted_length.hpp diff --git a/include/boost/geometry/algorithms/centroid.hpp b/include/boost/geometry/algorithms/centroid.hpp index c755fa9fb..1af711f45 100644 --- a/include/boost/geometry/algorithms/centroid.hpp +++ b/include/boost/geometry/algorithms/centroid.hpp @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -169,7 +168,7 @@ inline bool range_ok(Range const& range, Point& centroid) \brief Calculate the centroid of a ring. */ template -struct centroid_ring_state +struct centroid_range_state { static inline void apply(Ring const& ring, Strategy const& strategy, typename Strategy::state_type& state) @@ -191,71 +190,26 @@ struct centroid_ring_state } }; -template -struct centroid_ring +template +struct centroid_range { - static inline void apply(Ring const& ring, Point& centroid, + static inline void apply(Range const& range, Point& centroid, Strategy const& strategy) { - if (range_ok(ring, centroid)) + if (range_ok(range, centroid)) { typename Strategy::state_type state; - centroid_ring_state + centroid_range_state < - Ring, + Range, Closure, Strategy - >::apply(ring, strategy, state); + >::apply(range, strategy, state); Strategy::result(state, centroid); } } }; -/*! - \brief Centroid of a linestring. -*/ -template -struct centroid_linestring -{ - static inline void apply(Linestring const& line, Point& centroid, - Strategy const& strategy) - { - if (range_ok(line, centroid)) - { - // First version, should - // - be moved to a strategy - // - be made dim-agnostic - - typedef typename point_type::type point_type; - typedef typename boost::range_iterator::type point_iterator_type; - typedef segment_returning_iterator segment_iterator; - - typedef typename geometry::distance_result::type distance_type; - distance_type length = distance_type(); - std::pair average_sum; - - segment_iterator it(boost::begin(line), boost::end(line)); - segment_iterator end(boost::end(line)); - while (it != end) - { - - distance_type const d = geometry::distance(it->first, it->second); - length += d; - - distance_type two(2); - - distance_type const mx = (get<0>(it->first) + get<0>(it->second)) / two; - distance_type const my = (get<1>(it->first) + get<1>(it->second)) / two; - average_sum.first += d * mx; - average_sum.second += d * my; - ++it; - } - - set<0>(centroid, average_sum.first / length ); - set<1>(centroid, average_sum.second / length ); - } - } -}; /*! \brief Centroid of a polygon. @@ -270,7 +224,7 @@ struct centroid_polygon_state static inline void apply(Polygon const& poly, Strategy const& strategy, typename Strategy::state_type& state) { - typedef centroid_ring_state + typedef centroid_range_state < ring_type, geometry::closure::value, @@ -347,7 +301,7 @@ struct centroid template struct centroid - : detail::centroid::centroid_ring + : detail::centroid::centroid_range < Ring, Point, @@ -358,7 +312,13 @@ struct centroid template struct centroid - : detail::centroid::centroid_linestring + : detail::centroid::centroid_range + < + Linestring, + Point, + closed, + Strategy + > {}; template @@ -431,7 +391,13 @@ inline void centroid(Geometry const& geometry, Point& c) typedef typename strategy::centroid::services::default_strategy < typename cs_tag::type, - typename tag::type, + typename tag_cast + < + typename tag::type, + pointlike_tag, + linear_tag, + areal_tag + >::type, dimension::type::value, Point, Geometry diff --git a/include/boost/geometry/core/tags.hpp b/include/boost/geometry/core/tags.hpp index 14d846530..20885df1d 100644 --- a/include/boost/geometry/core/tags.hpp +++ b/include/boost/geometry/core/tags.hpp @@ -35,6 +35,19 @@ struct single_tag {}; /// For multiple-geometries (multi_point, multi_linestring, multi_polygon) struct multi_tag {}; +/// For point-like types (point, multi_point) +struct pointlike_tag {}; + +/// For linear types (linestring, multi-linestring, segment) +struct linear_tag {}; + +/// For areal types (polygon, multi_polygon, box, ring) +struct areal_tag {}; + +/// For volume types (also box (?), polyhedron) +struct volumetric_tag {}; + + // Tags defining geometry types @@ -42,22 +55,22 @@ struct multi_tag {}; struct geometry_not_recognized_tag {}; /// OGC Point identifying tag -struct point_tag : single_tag {}; +struct point_tag : single_tag, pointlike_tag {}; /// OGC Linestring identifying tag -struct linestring_tag : single_tag {}; +struct linestring_tag : single_tag, linear_tag {}; /// OGC Polygon identifying tag -struct polygon_tag : single_tag {}; +struct polygon_tag : single_tag, areal_tag {}; /// Convenience (linear) ring identifying tag -struct ring_tag : single_tag {}; +struct ring_tag : single_tag, areal_tag {}; -/// Convenience 2D or 3D box (mbr) identifying tag -struct box_tag : single_tag {}; +/// Convenience 2D or 3D box (mbr / aabb) identifying tag +struct box_tag : single_tag, areal_tag {}; /// Convenience segment (2-points) identifying tag -struct segment_tag : single_tag {}; +struct segment_tag : single_tag, linear_tag {}; diff --git a/include/boost/geometry/geometry.hpp b/include/boost/geometry/geometry.hpp index 046243dfa..088484d55 100644 --- a/include/boost/geometry/geometry.hpp +++ b/include/boost/geometry/geometry.hpp @@ -65,6 +65,7 @@ #include + // check includes all concepts #include @@ -74,4 +75,7 @@ #include #include +#include + + #endif // BOOST_GEOMETRY_GEOMETRY_HPP diff --git a/include/boost/geometry/multi/algorithms/centroid.hpp b/include/boost/geometry/multi/algorithms/centroid.hpp index a1797df77..5a312f4cc 100644 --- a/include/boost/geometry/multi/algorithms/centroid.hpp +++ b/include/boost/geometry/multi/algorithms/centroid.hpp @@ -99,6 +99,27 @@ struct centroid_multi namespace dispatch { +template +< + typename MultiLinestring, + typename Point, + typename Strategy +> +struct centroid + : detail::centroid::centroid_multi + < + MultiLinestring, + Point, + Strategy, + detail::centroid::centroid_range_state + < + typename boost::range_value::type, + closed, + Strategy + > + > +{}; + template < typename MultiPolygon, diff --git a/include/boost/geometry/multi/core/tags.hpp b/include/boost/geometry/multi/core/tags.hpp index 60fd8a20a..269fa5c2e 100644 --- a/include/boost/geometry/multi/core/tags.hpp +++ b/include/boost/geometry/multi/core/tags.hpp @@ -16,13 +16,13 @@ namespace boost { namespace geometry { /// OGC Multi point identifying tag -struct multi_point_tag : multi_tag {}; +struct multi_point_tag : multi_tag, pointlike_tag {}; /// OGC Multi linestring identifying tag -struct multi_linestring_tag : multi_tag {}; +struct multi_linestring_tag : multi_tag, linear_tag {}; /// OGC Multi polygon identifying tag -struct multi_polygon_tag : multi_tag{}; +struct multi_polygon_tag : multi_tag, areal_tag {}; /// OGC Geometry Collection identifying tag struct geometry_collection_tag : multi_tag {}; diff --git a/include/boost/geometry/multi/strategies/cartesian/centroid_average.hpp b/include/boost/geometry/multi/strategies/cartesian/centroid_average.hpp index dd8d3ca93..670cd0abe 100644 --- a/include/boost/geometry/multi/strategies/cartesian/centroid_average.hpp +++ b/include/boost/geometry/multi/strategies/cartesian/centroid_average.hpp @@ -80,8 +80,15 @@ public : namespace services { -template -struct default_strategy +template +struct default_strategy +< + cartesian_tag, + pointlike_tag, + DimensionCount, + Point, + Geometry +> { typedef average < diff --git a/include/boost/geometry/multi/strategies/centroid.hpp b/include/boost/geometry/multi/strategies/centroid.hpp index 4f733d517..799aac279 100644 --- a/include/boost/geometry/multi/strategies/centroid.hpp +++ b/include/boost/geometry/multi/strategies/centroid.hpp @@ -6,37 +6,4 @@ // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#ifndef BOOST_GEOMETRY_MULTI_STRATEGY_CENTROID_HPP -#define BOOST_GEOMETRY_MULTI_STRATEGY_CENTROID_HPP - -#include - - -namespace boost { namespace geometry -{ - - -#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS - -namespace strategy { namespace centroid { namespace services -{ - -template -struct default_strategy -{ - typedef bashein_detmer - < - Point, - typename point_type::type - > type; -}; - -}}} // namespace strategy::centroid::services - - -#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS - -}} // namespace boost::geometry - - -#endif // BOOST_GEOMETRY_MULTI_STRATEGY_CENTROID_HPP +// obsolete diff --git a/include/boost/geometry/strategies/cartesian/centroid_bashein_detmer.hpp b/include/boost/geometry/strategies/cartesian/centroid_bashein_detmer.hpp index 36be796e3..26a94d2a4 100644 --- a/include/boost/geometry/strategies/cartesian/centroid_bashein_detmer.hpp +++ b/include/boost/geometry/strategies/cartesian/centroid_bashein_detmer.hpp @@ -147,17 +147,11 @@ private : , sum_y(calculation_type()) { typedef calculation_type ct; - //std::cout << "-> calctype: " << typeid(ct).name() - // << " size: " << sizeof(ct) - // << " init: " << sum_a2 - // << std::endl; } }; public : typedef sums state_type; - typedef Point point_type; - typedef PointOfSegment segment_point_type; static inline void apply(PointOfSegment const& p1, PointOfSegment const& p2, sums& state) @@ -215,19 +209,9 @@ public : namespace services { -// Register this strategy for rings and polygons, in two dimensions +// Register this strategy for rings and (multi)polygons, in two dimensions template -struct default_strategy -{ - typedef bashein_detmer - < - Point, - typename point_type::type - > type; -}; - -template -struct default_strategy +struct default_strategy { typedef bashein_detmer < diff --git a/include/boost/geometry/strategies/cartesian/centroid_weighted_length.hpp b/include/boost/geometry/strategies/cartesian/centroid_weighted_length.hpp new file mode 100644 index 000000000..2702e3796 --- /dev/null +++ b/include/boost/geometry/strategies/cartesian/centroid_weighted_length.hpp @@ -0,0 +1,139 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) +// +// Copyright (c) 2009-2011 Mateusz Loskot, London, UK. +// Copyright (c) 2007-2011 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2011 Bruno Lalande, Paris, France. + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. + +// 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_STRATEGIES_CARTESIAN_CENTROID_WEIGHTED_LENGTH_HPP +#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_CENTROID_WEIGHTED_LENGTH_HPP + +#include + +#include +#include +#include +#include +#include + + +namespace boost { namespace geometry +{ + +// Note: when calling the namespace "centroid", it sometimes, +// somehow, in gcc, gives compilation problems (confusion with function centroid). + +namespace strategy { namespace centroid +{ + +namespace detail +{ + +template +struct weighted_length_sums +{ + Type length; + boost::array average_sum; + + inline weighted_length_sums() + : length(Type()) + { + for (std::size_t i = 0; i < DimensionCount; i++) + { + average_sum[i] = Type(); + } + } +}; +} + +template +< + typename Point, + typename PointOfSegment = Point +> +class weighted_length +{ +private : + typedef typename select_most_precise + < + typename distance_result::type, + typename distance_result::type + >::type distance_type; + +public : + typedef detail::weighted_length_sums state_type; + + static inline void apply(PointOfSegment const& p1, + PointOfSegment const& p2, state_type& state) + { + distance_type const d = geometry::distance(p1, p2); + state.length += d; + + distance_type two(2); + + // Might be made generic for N dimensions using specializations + distance_type const mx = (get<0>(p1) + get<0>(p2)) / two; + distance_type const my = (get<1>(p1) + get<1>(p2)) / two; + state.average_sum[0] += d * mx; + state.average_sum[1] += d * my; + } + + static inline bool result(state_type const& state, Point& centroid) + { + distance_type const zero = distance_type(); + if (! geometry::math::equals(state.length, zero)) + { + set<0>(centroid, state.average_sum[0] / state.length); + set<1>(centroid, state.average_sum[1] / state.length); + return true; + } + + return false; + } + +}; + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + +namespace services +{ + +// Register this strategy for linestrings and polygons, in two or three dimensions +template +struct default_strategy +< + cartesian_tag, + linear_tag, + 2, + Point, + Geometry +> +{ + typedef weighted_length + < + Point, + typename point_type::type + > type; +}; + + + +} // namespace services + + +#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + + +}} // namespace strategy::centroid + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_CENTROID_WEIGHTED_LENGTH_HPP diff --git a/include/boost/geometry/strategies/centroid.hpp b/include/boost/geometry/strategies/centroid.hpp index be3b1d33f..9757e6a39 100644 --- a/include/boost/geometry/strategies/centroid.hpp +++ b/include/boost/geometry/strategies/centroid.hpp @@ -51,29 +51,6 @@ template typename Geometry > struct default_strategy -{ - BOOST_MPL_ASSERT_MSG - ( - false, NOT_IMPLEMENTED_FOR_THIS_TYPES - , (types) - ); -}; - -// Register NA-strategy for all where not applicable -template -struct default_strategy -{ - typedef not_applicable_strategy type; -}; - -template -struct default_strategy -{ - typedef not_applicable_strategy type; -}; - -template -struct default_strategy { typedef not_applicable_strategy type; }; diff --git a/include/boost/geometry/strategies/strategies.hpp b/include/boost/geometry/strategies/strategies.hpp index 52eb5979d..0dcb7eb9b 100644 --- a/include/boost/geometry/strategies/strategies.hpp +++ b/include/boost/geometry/strategies/strategies.hpp @@ -25,6 +25,7 @@ #include #include +#include #include #include #include