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]
This commit is contained in:
Barend Gehrels
2011-03-26 17:01:28 +00:00
parent 3cb6482925
commit be95eb40d8
11 changed files with 224 additions and 145 deletions

View File

@@ -26,7 +26,6 @@
#include <boost/geometry/algorithms/convert.hpp>
#include <boost/geometry/algorithms/distance.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/iterators/segment_returning_iterator.hpp>
#include <boost/geometry/strategies/centroid.hpp>
#include <boost/geometry/strategies/concepts/centroid_concept.hpp>
#include <boost/geometry/views/closeable_view.hpp>
@@ -169,7 +168,7 @@ inline bool range_ok(Range const& range, Point& centroid)
\brief Calculate the centroid of a ring.
*/
template<typename Ring, closure_selector Closure, typename Strategy>
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<typename Ring, typename Point, closure_selector Closure, typename Strategy>
struct centroid_ring
template<typename Range, typename Point, closure_selector Closure, typename Strategy>
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<typename Linestring, typename Point, typename Strategy>
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<Linestring>::type point_type;
typedef typename boost::range_iterator<Linestring const>::type point_iterator_type;
typedef segment_returning_iterator<point_iterator_type, point_type> segment_iterator;
typedef typename geometry::distance_result<Linestring>::type distance_type;
distance_type length = distance_type();
std::pair<distance_type, distance_type> 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<ring_type>::value,
@@ -347,7 +301,7 @@ struct centroid<box_tag, Box, Point, Strategy>
template <typename Ring, typename Point, typename Strategy>
struct centroid<ring_tag, Ring, Point, Strategy>
: detail::centroid::centroid_ring
: detail::centroid::centroid_range
<
Ring,
Point,
@@ -358,7 +312,13 @@ struct centroid<ring_tag, Ring, Point, Strategy>
template <typename Linestring, typename Point, typename Strategy>
struct centroid<linestring_tag, Linestring, Point, Strategy>
: detail::centroid::centroid_linestring<Linestring, Point, Strategy>
: detail::centroid::centroid_range
<
Linestring,
Point,
closed,
Strategy
>
{};
template <typename Polygon, typename Point, typename Strategy>
@@ -431,7 +391,13 @@ inline void centroid(Geometry const& geometry, Point& c)
typedef typename strategy::centroid::services::default_strategy
<
typename cs_tag<Geometry>::type,
typename tag<Geometry>::type,
typename tag_cast
<
typename tag<Geometry>::type,
pointlike_tag,
linear_tag,
areal_tag
>::type,
dimension<Geometry>::type::value,
Point,
Geometry

View File

@@ -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 {};

View File

@@ -65,6 +65,7 @@
#include <boost/geometry/multi/multi.hpp>
// check includes all concepts
#include <boost/geometry/geometries/concepts/check.hpp>
@@ -74,4 +75,7 @@
#include <boost/geometry/util/select_coordinate_type.hpp>
#include <boost/geometry/util/write_dsv.hpp>
#include <boost/geometry/domains/gis/io/wkt/wkt.hpp>
#endif // BOOST_GEOMETRY_GEOMETRY_HPP

View File

@@ -99,6 +99,27 @@ struct centroid_multi
namespace dispatch
{
template
<
typename MultiLinestring,
typename Point,
typename Strategy
>
struct centroid<multi_linestring_tag, MultiLinestring, Point, Strategy>
: detail::centroid::centroid_multi
<
MultiLinestring,
Point,
Strategy,
detail::centroid::centroid_range_state
<
typename boost::range_value<MultiLinestring>::type,
closed,
Strategy
>
>
{};
template
<
typename MultiPolygon,

View File

@@ -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 {};

View File

@@ -80,8 +80,15 @@ public :
namespace services
{
template <typename Point, typename Geometry>
struct default_strategy<cartesian_tag, multi_point_tag, 2, Point, Geometry>
template <typename Point, std::size_t DimensionCount, typename Geometry>
struct default_strategy
<
cartesian_tag,
pointlike_tag,
DimensionCount,
Point,
Geometry
>
{
typedef average
<

View File

@@ -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 <boost/geometry/strategies/cartesian/centroid_bashein_detmer.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace strategy { namespace centroid { namespace services
{
template <typename Point, typename Geometry>
struct default_strategy<cartesian_tag, multi_polygon_tag, 2, Point, Geometry>
{
typedef bashein_detmer
<
Point,
typename point_type<Geometry>::type
> type;
};
}}} // namespace strategy::centroid::services
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_MULTI_STRATEGY_CENTROID_HPP
// obsolete

View File

@@ -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 <typename Point, typename Geometry>
struct default_strategy<cartesian_tag, ring_tag, 2, Point, Geometry>
{
typedef bashein_detmer
<
Point,
typename point_type<Geometry>::type
> type;
};
template <typename Point, typename Geometry>
struct default_strategy<cartesian_tag, polygon_tag, 2, Point, Geometry>
struct default_strategy<cartesian_tag, areal_tag, 2, Point, Geometry>
{
typedef bashein_detmer
<

View File

@@ -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 <cstddef>
#include <boost/array.hpp>
#include <boost/geometry/algorithms/distance.hpp>
#include <boost/geometry/util/select_most_precise.hpp>
#include <boost/geometry/strategies/centroid.hpp>
#include <boost/geometry/strategies/distance_result.hpp>
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 <typename Type, std::size_t DimensionCount>
struct weighted_length_sums
{
Type length;
boost::array<Type, DimensionCount> 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<Point>::type,
typename distance_result<PointOfSegment>::type
>::type distance_type;
public :
typedef detail::weighted_length_sums<distance_type, 2> 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 <typename Point, typename Geometry>
struct default_strategy
<
cartesian_tag,
linear_tag,
2,
Point,
Geometry
>
{
typedef weighted_length
<
Point,
typename point_type<Geometry>::type
> type;
};
} // namespace services
#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
}} // namespace strategy::centroid
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_CENTROID_WEIGHTED_LENGTH_HPP

View File

@@ -51,29 +51,6 @@ template
typename Geometry
>
struct default_strategy
{
BOOST_MPL_ASSERT_MSG
(
false, NOT_IMPLEMENTED_FOR_THIS_TYPES
, (types<Point, Geometry>)
);
};
// Register NA-strategy for all where not applicable
template <typename Point, typename Geometry, std::size_t Dimension>
struct default_strategy<cartesian_tag, point_tag, Dimension, Point, Geometry>
{
typedef not_applicable_strategy type;
};
template <typename Point, typename Geometry, std::size_t Dimension>
struct default_strategy<cartesian_tag, box_tag, Dimension, Point, Geometry>
{
typedef not_applicable_strategy type;
};
template <typename Point, typename Geometry, std::size_t Dimension>
struct default_strategy<cartesian_tag, linestring_tag, Dimension, Point, Geometry>
{
typedef not_applicable_strategy type;
};

View File

@@ -25,6 +25,7 @@
#include <boost/geometry/strategies/cartesian/area_surveyor.hpp>
#include <boost/geometry/strategies/cartesian/centroid_bashein_detmer.hpp>
#include <boost/geometry/strategies/cartesian/centroid_weighted_length.hpp>
#include <boost/geometry/strategies/cartesian/distance_pythagoras.hpp>
#include <boost/geometry/strategies/cartesian/distance_projected_point.hpp>
#include <boost/geometry/strategies/cartesian/point_in_poly_franklin.hpp>