stabilize build system: depends, installer, boost/bdb fixes, cross targets groundwork

This commit is contained in:
2026-02-24 18:38:47 +00:00
parent da8c28aaeb
commit 65cb2619a7
13106 changed files with 2484322 additions and 1804 deletions
@@ -0,0 +1,114 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2012-2014 Barend Gehrels, 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_AGNOSTIC_BUFFER_DISTANCE_ASYMMETRIC_HPP
#define BOOST_GEOMETRY_STRATEGIES_AGNOSTIC_BUFFER_DISTANCE_ASYMMETRIC_HPP
#include <boost/core/ignore_unused.hpp>
#include <boost/geometry/strategies/buffer.hpp>
#include <boost/geometry/util/math.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace buffer
{
/*!
\brief Let the buffer for linestrings be asymmetric
\ingroup strategies
\tparam NumericType \tparam_numeric
\details This strategy can be used as DistanceStrategy for the buffer algorithm.
It can be applied for (multi)linestrings. It uses a (potentially) different
distances for left and for right. This means the (multi)linestrings are
interpreted having a direction.
\qbk{
[heading Example]
[buffer_distance_asymmetric]
[heading Output]
[$img/strategies/buffer_distance_asymmetric.png]
[heading See also]
\* [link geometry.reference.algorithms.buffer.buffer_7_with_strategies buffer (with strategies)]
\* [link geometry.reference.strategies.strategy_buffer_distance_symmetric distance_symmetric]
}
*/
template<typename NumericType>
class distance_asymmetric
{
public :
//! \brief Constructs the strategy, two distances must be specified
//! \param left The distance (or radius) of the buffer on the left side
//! \param right The distance on the right side
distance_asymmetric(NumericType const& left,
NumericType const& right)
: m_left(left)
, m_right(right)
{}
#ifndef DOXYGEN_SHOULD_SKIP_THIS
//! Returns the distance-value for the specified side
template <typename Point>
inline NumericType apply(Point const& , Point const& ,
buffer_side_selector side) const
{
NumericType result = side == buffer_side_left ? m_left : m_right;
return negative() ? math::abs(result) : result;
}
//! Used internally, returns -1 for deflate, 1 for inflate
inline int factor() const
{
return negative() ? -1 : 1;
}
//! Returns true if both distances are negative
inline bool negative() const
{
return m_left < 0 && m_right < 0;
}
//! Returns the max distance distance up to the buffer will reach
template <typename JoinStrategy, typename EndStrategy>
inline NumericType max_distance(JoinStrategy const& join_strategy,
EndStrategy const& end_strategy) const
{
boost::ignore_unused(join_strategy, end_strategy);
NumericType const left = geometry::math::abs(m_left);
NumericType const right = geometry::math::abs(m_right);
NumericType const dist = (std::max)(left, right);
return (std::max)(join_strategy.max_distance(dist),
end_strategy.max_distance(dist));
}
//! Returns the distance at which the input is simplified before the buffer process
inline NumericType simplify_distance() const
{
NumericType const left = geometry::math::abs(m_left);
NumericType const right = geometry::math::abs(m_right);
return (std::min)(left, right) / 1000.0;
}
#endif // DOXYGEN_SHOULD_SKIP_THIS
private :
NumericType m_left;
NumericType m_right;
};
}} // namespace strategy::buffer
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_AGNOSTIC_BUFFER_DISTANCE_ASYMMETRIC_HPP
@@ -0,0 +1,107 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2012-2014 Barend Gehrels, 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_AGNOSTIC_BUFFER_DISTANCE_SYMMETRIC_HPP
#define BOOST_GEOMETRY_STRATEGIES_AGNOSTIC_BUFFER_DISTANCE_SYMMETRIC_HPP
#include <boost/core/ignore_unused.hpp>
#include <boost/geometry/strategies/buffer.hpp>
#include <boost/geometry/util/math.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace buffer
{
/*!
\brief Let the buffer algorithm create buffers with same distances
\ingroup strategies
\tparam NumericType \tparam_numeric
\details This strategy can be used as DistanceStrategy for the buffer algorithm.
It can be applied for all geometries. It uses one distance for left and
for right.
If the distance is negative and used with a (multi)polygon or ring, the
geometry will shrink (deflate) instead of expand (inflate).
\qbk{
[heading Example]
[buffer_distance_symmetric]
[heading Output]
[$img/strategies/buffer_distance_symmetric.png]
[heading See also]
\* [link geometry.reference.algorithms.buffer.buffer_7_with_strategies buffer (with strategies)]
\* [link geometry.reference.strategies.strategy_buffer_distance_asymmetric distance_asymmetric]
}
*/
template<typename NumericType>
class distance_symmetric
{
public :
//! \brief Constructs the strategy, a distance must be specified
//! \param distance The distance (or radius) of the buffer
explicit inline distance_symmetric(NumericType const& distance)
: m_distance(distance)
{}
#ifndef DOXYGEN_SHOULD_SKIP_THIS
//! Returns the distance-value
template <typename Point>
inline NumericType apply(Point const& , Point const& ,
buffer_side_selector ) const
{
return negative() ? geometry::math::abs(m_distance) : m_distance;
}
//! Used internally, returns -1 for deflate, 1 for inflate
inline int factor() const
{
return negative() ? -1 : 1;
}
//! Returns true if distance is negative
inline bool negative() const
{
return m_distance < 0;
}
//! Returns the max distance distance up to the buffer will reach
template <typename JoinStrategy, typename EndStrategy>
inline NumericType max_distance(JoinStrategy const& join_strategy,
EndStrategy const& end_strategy) const
{
boost::ignore_unused(join_strategy, end_strategy);
NumericType const dist = geometry::math::abs(m_distance);
return (std::max)(join_strategy.max_distance(dist),
end_strategy.max_distance(dist));
}
//! Returns the distance at which the input is simplified before the buffer process
inline NumericType simplify_distance() const
{
return geometry::math::abs(m_distance) / 1000.0;
}
#endif // DOXYGEN_SHOULD_SKIP_THIS
private :
NumericType m_distance;
};
}} // namespace strategy::buffer
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_AGNOSTIC_BUFFER_DISTANCE_SYMMETRIC_HPP
@@ -0,0 +1,390 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// 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.
// 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_AGNOSTIC_CONVEX_GRAHAM_ANDREW_HPP
#define BOOST_GEOMETRY_STRATEGIES_AGNOSTIC_CONVEX_GRAHAM_ANDREW_HPP
#include <cstddef>
#include <algorithm>
#include <vector>
#include <boost/range.hpp>
#include <boost/geometry/core/assert.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/strategies/convex_hull.hpp>
#include <boost/geometry/views/detail/range_type.hpp>
#include <boost/geometry/policies/compare.hpp>
#include <boost/geometry/algorithms/detail/for_each_range.hpp>
#include <boost/geometry/views/reversible_view.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace convex_hull
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail
{
template
<
typename InputRange,
typename RangeIterator,
typename StrategyLess,
typename StrategyGreater
>
struct get_extremes
{
typedef typename point_type<InputRange>::type point_type;
point_type left, right;
bool first;
StrategyLess less;
StrategyGreater greater;
inline get_extremes()
: first(true)
{}
inline void apply(InputRange const& range)
{
if (boost::size(range) == 0)
{
return;
}
// First iterate through this range
// (this two-stage approach avoids many point copies,
// because iterators are kept in memory. Because iterators are
// not persistent (in MSVC) this approach is not applicable
// for more ranges together)
RangeIterator left_it = boost::begin(range);
RangeIterator right_it = boost::begin(range);
for (RangeIterator it = boost::begin(range) + 1;
it != boost::end(range);
++it)
{
if (less(*it, *left_it))
{
left_it = it;
}
if (greater(*it, *right_it))
{
right_it = it;
}
}
// Then compare with earlier
if (first)
{
// First time, assign left/right
left = *left_it;
right = *right_it;
first = false;
}
else
{
// Next time, check if this range was left/right from
// the extremes already collected
if (less(*left_it, left))
{
left = *left_it;
}
if (greater(*right_it, right))
{
right = *right_it;
}
}
}
};
template
<
typename InputRange,
typename RangeIterator,
typename Container,
typename SideStrategy
>
struct assign_range
{
Container lower_points, upper_points;
typedef typename point_type<InputRange>::type point_type;
point_type const& most_left;
point_type const& most_right;
inline assign_range(point_type const& left, point_type const& right)
: most_left(left)
, most_right(right)
{}
inline void apply(InputRange const& range)
{
typedef SideStrategy side;
// Put points in one of the two output sequences
for (RangeIterator it = boost::begin(range);
it != boost::end(range);
++it)
{
// check if it is lying most_left or most_right from the line
int dir = side::apply(most_left, most_right, *it);
switch(dir)
{
case 1 : // left side
upper_points.push_back(*it);
break;
case -1 : // right side
lower_points.push_back(*it);
break;
// 0: on line most_left-most_right,
// or most_left, or most_right,
// -> all never part of hull
}
}
}
};
template <typename Range>
static inline void sort(Range& range)
{
typedef typename boost::range_value<Range>::type point_type;
typedef geometry::less<point_type> comparator;
std::sort(boost::begin(range), boost::end(range), comparator());
}
} // namespace detail
#endif // DOXYGEN_NO_DETAIL
/*!
\brief Graham scan strategy to calculate convex hull
\ingroup strategies
\note Completely reworked version inspired on the sources listed below
\see http://www.ddj.com/architect/201806315
\see http://marknelson.us/2007/08/22/convex
*/
template <typename InputGeometry, typename OutputPoint>
class graham_andrew
{
public :
typedef OutputPoint point_type;
typedef InputGeometry geometry_type;
private:
typedef typename cs_tag<point_type>::type cs_tag;
typedef typename std::vector<point_type> container_type;
typedef typename std::vector<point_type>::const_iterator iterator;
typedef typename std::vector<point_type>::const_reverse_iterator rev_iterator;
class partitions
{
friend class graham_andrew;
container_type m_lower_hull;
container_type m_upper_hull;
container_type m_copied_input;
};
public:
typedef partitions state_type;
inline void apply(InputGeometry const& geometry, partitions& state) const
{
// First pass.
// Get min/max (in most cases left / right) points
// This makes use of the geometry::less/greater predicates
// For the left boundary it is important that multiple points
// are sorted from bottom to top. Therefore the less predicate
// does not take the x-only template parameter (this fixes ticket #6019.
// For the right boundary it is not necessary (though also not harmful),
// because points are sorted from bottom to top in a later stage.
// For symmetry and to get often more balanced lower/upper halves
// we keep it.
typedef typename geometry::detail::range_type<InputGeometry>::type range_type;
typedef typename boost::range_iterator
<
range_type const
>::type range_iterator;
detail::get_extremes
<
range_type,
range_iterator,
geometry::less<point_type>,
geometry::greater<point_type>
> extremes;
geometry::detail::for_each_range(geometry, extremes);
// Bounding left/right points
// Second pass, now that extremes are found, assign all points
// in either lower, either upper
detail::assign_range
<
range_type,
range_iterator,
container_type,
typename strategy::side::services::default_strategy<cs_tag>::type
> assigner(extremes.left, extremes.right);
geometry::detail::for_each_range(geometry, assigner);
// Sort both collections, first on x(, then on y)
detail::sort(assigner.lower_points);
detail::sort(assigner.upper_points);
//std::cout << boost::size(assigner.lower_points) << std::endl;
//std::cout << boost::size(assigner.upper_points) << std::endl;
// And decide which point should be in the final hull
build_half_hull<-1>(assigner.lower_points, state.m_lower_hull,
extremes.left, extremes.right);
build_half_hull<1>(assigner.upper_points, state.m_upper_hull,
extremes.left, extremes.right);
}
template <typename OutputIterator>
inline void result(partitions const& state,
OutputIterator out,
bool clockwise,
bool closed) const
{
if (clockwise)
{
output_ranges(state.m_upper_hull, state.m_lower_hull, out, closed);
}
else
{
output_ranges(state.m_lower_hull, state.m_upper_hull, out, closed);
}
}
private:
template <int Factor>
static inline void build_half_hull(container_type const& input,
container_type& output,
point_type const& left, point_type const& right)
{
output.push_back(left);
for(iterator it = input.begin(); it != input.end(); ++it)
{
add_to_hull<Factor>(*it, output);
}
add_to_hull<Factor>(right, output);
}
template <int Factor>
static inline void add_to_hull(point_type const& p, container_type& output)
{
typedef typename strategy::side::services::default_strategy<cs_tag>::type side;
output.push_back(p);
std::size_t output_size = output.size();
while (output_size >= 3)
{
rev_iterator rit = output.rbegin();
point_type const last = *rit++;
point_type const& last2 = *rit++;
if (Factor * side::apply(*rit, last, last2) <= 0)
{
// Remove last two points from stack, and add last again
// This is much faster then erasing the one but last.
output.pop_back();
output.pop_back();
output.push_back(last);
output_size--;
}
else
{
return;
}
}
}
template <typename OutputIterator>
static inline void output_ranges(container_type const& first, container_type const& second,
OutputIterator out, bool closed)
{
std::copy(boost::begin(first), boost::end(first), out);
BOOST_GEOMETRY_ASSERT(closed ? !boost::empty(second) : boost::size(second) > 1);
std::copy(++boost::rbegin(second), // skip the first Point
closed ? boost::rend(second) : --boost::rend(second), // skip the last Point if open
out);
typedef typename boost::range_size<container_type>::type size_type;
size_type const count = boost::size(first) + boost::size(second) - 1;
// count describes a closed case but comparison with min size of closed
// gives the result compatible also with open
// here core_detail::closure::minimum_ring_size<closed> could be used
if (count < 4)
{
// there should be only one missing
*out++ = *boost::begin(first);
}
}
};
}} // namespace strategy::convex_hull
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
template <typename InputGeometry, typename OutputPoint>
struct strategy_convex_hull<InputGeometry, OutputPoint, cartesian_tag>
{
typedef strategy::convex_hull::graham_andrew<InputGeometry, OutputPoint> type;
};
#endif
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_AGNOSTIC_CONVEX_GRAHAM_ANDREW_HPP
@@ -0,0 +1,103 @@
// 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.
// 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_AGNOSTIC_POINT_IN_BOX_BY_SIDE_HPP
#define BOOST_GEOMETRY_STRATEGIES_AGNOSTIC_POINT_IN_BOX_BY_SIDE_HPP
#include <boost/array.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/algorithms/assign.hpp>
#include <boost/geometry/strategies/covered_by.hpp>
#include <boost/geometry/strategies/within.hpp>
namespace boost { namespace geometry { namespace strategy
{
namespace within
{
struct decide_within
{
static inline bool apply(int side, bool& result)
{
if (side != 1)
{
result = false;
return false;
}
return true; // continue
}
};
struct decide_covered_by
{
static inline bool apply(int side, bool& result)
{
if (side != 1)
{
result = side >= 0;
return false;
}
return true; // continue
}
};
// WARNING
// This strategy is not suitable for boxes in non-cartesian CSes having edges
// longer than 180deg because e.g. the SSF formula picks the side of the closer
// longitude, so for long edges the side is the opposite.
template <typename Point, typename Box, typename Decide = decide_within>
struct point_in_box_by_side
{
typedef typename strategy::side::services::default_strategy
<
typename cs_tag<Box>::type
>::type side_strategy_type;
static inline bool apply(Point const& point, Box const& box)
{
// Create (counterclockwise) array of points, the fifth one closes it
// Every point should be on the LEFT side (=1), or ON the border (=0),
// So >= 1 or >= 0
boost::array<typename point_type<Box>::type, 5> bp;
geometry::detail::assign_box_corners_oriented<true>(box, bp);
bp[4] = bp[0];
bool result = true;
side_strategy_type strategy;
boost::ignore_unused_variable_warning(strategy);
for (int i = 1; i < 5; i++)
{
int const side = strategy.apply(point, bp[i - 1], bp[i]);
if (! Decide::apply(side, result))
{
return result;
}
}
return result;
}
};
} // namespace within
}}} // namespace boost::geometry::strategy
#endif // BOOST_GEOMETRY_STRATEGIES_AGNOSTIC_POINT_IN_BOX_BY_SIDE_HPP
@@ -0,0 +1,77 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014-2017 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_STRATEGY_AGNOSTIC_POINT_IN_POINT_HPP
#define BOOST_GEOMETRY_STRATEGY_AGNOSTIC_POINT_IN_POINT_HPP
#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
#include <boost/geometry/strategies/covered_by.hpp>
#include <boost/geometry/strategies/within.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace within
{
template
<
typename Point1, typename Point2
>
struct point_in_point
{
static inline bool apply(Point1 const& point1, Point2 const& point2)
{
return detail::equals::equals_point_point(point1, point2);
}
};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{
template <typename Point, typename PointLike, typename Tag2, typename AnyCS1, typename AnyCS2>
struct default_strategy<Point, PointLike, point_tag, Tag2, pointlike_tag, pointlike_tag, AnyCS1, AnyCS2>
{
typedef strategy::within::point_in_point<Point, typename point_type<PointLike>::type> type;
};
} // namespace services
#endif
}} // namespace strategy::within
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace strategy { namespace covered_by { namespace services
{
template <typename Point, typename PointLike, typename Tag2, typename AnyCS1, typename AnyCS2>
struct default_strategy<Point, PointLike, point_tag, Tag2, pointlike_tag, pointlike_tag, AnyCS1, AnyCS2>
{
typedef strategy::within::point_in_point<Point, typename point_type<PointLike>::type> type;
};
}}} // namespace strategy::covered_by::services
#endif
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGY_AGNOSTIC_POINT_IN_POINT_HPP
@@ -0,0 +1,208 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2011-2012 Barend Gehrels, Amsterdam, the Netherlands.
// 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_STRATEGY_AGNOSTIC_POINT_IN_POLY_ORIENTED_WINDING_HPP
#define BOOST_GEOMETRY_STRATEGY_AGNOSTIC_POINT_IN_POLY_ORIENTED_WINDING_HPP
#include <boost/geometry/core/point_order.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/select_calculation_type.hpp>
#include <boost/geometry/strategies/side.hpp>
#include <boost/geometry/strategies/within.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace within
{
/*!
\brief Within detection using winding rule, but checking if enclosing ring is
counter clockwise and, if so, reverses the result
\ingroup strategies
\tparam Point \tparam_point
\tparam Reverse True if parameter should be reversed
\tparam PointOfSegment \tparam_segment_point
\tparam CalculationType \tparam_calculation
\author Barend Gehrels
\note The implementation is inspired by terralib http://www.terralib.org (LGPL)
\note but totally revised afterwards, especially for cases on segments
\note Only dependant on "side", -> agnostic, suitable for spherical/latlong
\qbk{
[heading See also]
[link geometry.reference.algorithms.within.within_3_with_strategy within (with strategy)]
}
*/
template
<
bool Reverse,
typename Point,
typename PointOfSegment = Point,
typename CalculationType = void
>
class oriented_winding
{
typedef typename select_calculation_type
<
Point,
PointOfSegment,
CalculationType
>::type calculation_type;
typedef typename strategy::side::services::default_strategy
<
typename cs_tag<Point>::type
>::type strategy_side_type;
/*! subclass to keep state */
class counter
{
int m_count;
bool m_touches;
calculation_type m_sum_area;
inline int code() const
{
return m_touches ? 0 : m_count == 0 ? -1 : 1;
}
inline int clockwise_oriented_code() const
{
return (m_sum_area > 0) ? code() : -code();
}
inline int oriented_code() const
{
return Reverse
? -clockwise_oriented_code()
: clockwise_oriented_code();
}
public :
friend class oriented_winding;
inline counter()
: m_count(0)
, m_touches(false)
, m_sum_area(0)
{}
inline void add_to_area(calculation_type triangle)
{
m_sum_area += triangle;
}
};
template <size_t D>
static inline int check_touch(Point const& point,
PointOfSegment const& seg1, PointOfSegment const& seg2,
counter& state)
{
calculation_type const p = get<D>(point);
calculation_type const s1 = get<D>(seg1);
calculation_type const s2 = get<D>(seg2);
if ((s1 <= p && s2 >= p) || (s2 <= p && s1 >= p))
{
state.m_touches = true;
}
return 0;
}
template <size_t D>
static inline int check_segment(Point const& point,
PointOfSegment const& seg1, PointOfSegment const& seg2,
counter& state)
{
calculation_type const p = get<D>(point);
calculation_type const s1 = get<D>(seg1);
calculation_type const s2 = get<D>(seg2);
// Check if one of segment endpoints is at same level of point
bool eq1 = math::equals(s1, p);
bool eq2 = math::equals(s2, p);
if (eq1 && eq2)
{
// Both equal p -> segment is horizontal (or vertical for D=0)
// The only thing which has to be done is check if point is ON segment
return check_touch<1 - D>(point, seg1, seg2, state);
}
return
eq1 ? (s2 > p ? 1 : -1) // Point on level s1, UP/DOWN depending on s2
: eq2 ? (s1 > p ? -1 : 1) // idem
: s1 < p && s2 > p ? 2 // Point between s1 -> s2 --> UP
: s2 < p && s1 > p ? -2 // Point between s2 -> s1 --> DOWN
: 0;
}
public :
// Typedefs and static methods to fulfill the concept
typedef Point point_type;
typedef PointOfSegment segment_point_type;
typedef counter state_type;
static inline bool apply(Point const& point,
PointOfSegment const& s1, PointOfSegment const& s2,
counter& state)
{
state.add_to_area(get<0>(s2) * get<1>(s1) - get<0>(s1) * get<1>(s2));
int count = check_segment<1>(point, s1, s2, state);
if (count != 0)
{
int side = strategy_side_type::apply(s1, s2, point);
if (side == 0)
{
// Point is lying on segment
state.m_touches = true;
state.m_count = 0;
return false;
}
// Side is NEG for right, POS for left.
// The count is -2 for down, 2 for up (or -1/1)
// Side positive thus means UP and LEFTSIDE or DOWN and RIGHTSIDE
// See accompagnying figure (TODO)
if (side * count > 0)
{
state.m_count += count;
}
}
return ! state.m_touches;
}
static inline int result(counter const& state)
{
return state.oriented_code();
}
};
}} // namespace strategy::within
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGY_AGNOSTIC_POINT_IN_POLY_ORIENTED_WINDING_HPP
@@ -0,0 +1,529 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2013, 2014, 2016, 2017.
// Modifications copyright (c) 2013-2017 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.
// 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_STRATEGY_AGNOSTIC_POINT_IN_POLY_WINDING_HPP
#define BOOST_GEOMETRY_STRATEGY_AGNOSTIC_POINT_IN_POLY_WINDING_HPP
#include <boost/core/ignore_unused.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/select_calculation_type.hpp>
#include <boost/geometry/strategies/side.hpp>
#include <boost/geometry/strategies/covered_by.hpp>
#include <boost/geometry/strategies/within.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace within
{
// 1 deg or pi/180 rad
template <typename Point,
typename CalculationType = typename coordinate_type<Point>::type>
struct winding_small_angle
{
typedef typename coordinate_system<Point>::type cs_t;
typedef math::detail::constants_on_spheroid
<
CalculationType,
typename cs_t::units
> constants;
static inline CalculationType apply()
{
return constants::half_period() / CalculationType(180);
}
};
// Fix for https://svn.boost.org/trac/boost/ticket/9628
// For floating point coordinates, the <D> coordinate of a point is compared
// with the segment's points using some EPS. If the coordinates are "equal"
// the sides are calculated. Therefore we can treat a segment as a long areal
// geometry having some width. There is a small ~triangular area somewhere
// between the segment's effective area and a segment's line used in sides
// calculation where the segment is on the one side of the line but on the
// other side of a segment (due to the width).
// Below picture assuming D = 1, if D = 0 horiz<->vert, E<->N, RIGHT<->UP.
// For the s1 of a segment going NE the real side is RIGHT but the point may
// be detected as LEFT, like this:
// RIGHT
// ___----->
// ^ O Pt __ __
// EPS __ __
// v__ __ BUT DETECTED AS LEFT OF THIS LINE
// _____7
// _____/
// _____/
// In the code below actually D = 0, so segments are nearly-vertical
// Called when the point is on the same level as one of the segment's points
// but the point is not aligned with a vertical segment
template <typename CSTag>
struct winding_side_equal
{
typedef typename strategy::side::services::default_strategy
<
CSTag
>::type strategy_side_type;
template <typename Point, typename PointOfSegment>
static inline int apply(Point const& point,
PointOfSegment const& se,
int count)
{
typedef typename coordinate_type<PointOfSegment>::type scoord_t;
typedef typename coordinate_system<PointOfSegment>::type::units units_t;
if (math::equals(get<1>(point), get<1>(se)))
return 0;
// Create a horizontal segment intersecting the original segment's endpoint
// equal to the point, with the derived direction (E/W).
PointOfSegment ss1, ss2;
set<1>(ss1, get<1>(se));
set<0>(ss1, get<0>(se));
set<1>(ss2, get<1>(se));
scoord_t ss20 = get<0>(se);
if (count > 0)
{
ss20 += winding_small_angle<PointOfSegment>::apply();
}
else
{
ss20 -= winding_small_angle<PointOfSegment>::apply();
}
math::normalize_longitude<units_t>(ss20);
set<0>(ss2, ss20);
// Check the side using this vertical segment
return strategy_side_type::apply(ss1, ss2, point);
}
};
// The optimization for cartesian
template <>
struct winding_side_equal<cartesian_tag>
{
template <typename Point, typename PointOfSegment>
static inline int apply(Point const& point,
PointOfSegment const& se,
int count)
{
// NOTE: for D=0 the signs would be reversed
return math::equals(get<1>(point), get<1>(se)) ?
0 :
get<1>(point) < get<1>(se) ?
// assuming count is equal to 1 or -1
-count : // ( count > 0 ? -1 : 1) :
count; // ( count > 0 ? 1 : -1) ;
}
};
template <typename Point,
typename CalculationType,
typename CSTag = typename cs_tag<Point>::type>
struct winding_check_touch
{
typedef CalculationType calc_t;
typedef typename coordinate_system<Point>::type::units units_t;
typedef math::detail::constants_on_spheroid<CalculationType, units_t> constants;
template <typename PointOfSegment, typename State>
static inline int apply(Point const& point,
PointOfSegment const& seg1,
PointOfSegment const& seg2,
State& state,
bool& eq1,
bool& eq2)
{
calc_t const pi = constants::half_period();
calc_t const pi2 = pi / calc_t(2);
calc_t const px = get<0>(point);
calc_t const s1x = get<0>(seg1);
calc_t const s2x = get<0>(seg2);
calc_t const py = get<1>(point);
calc_t const s1y = get<1>(seg1);
calc_t const s2y = get<1>(seg2);
// NOTE: lat in {-90, 90} and arbitrary lon
// it doesn't matter what lon it is if it's a pole
// so e.g. if one of the segment endpoints is a pole
// then only the other lon matters
bool eq1_strict = math::equals(s1x, px);
bool eq2_strict = math::equals(s2x, px);
eq1 = eq1_strict // lon strictly equal to s1
|| math::equals(s1y, pi2) || math::equals(s1y, -pi2); // s1 is pole
eq2 = eq2_strict // lon strictly equal to s2
|| math::equals(s2y, pi2) || math::equals(s2y, -pi2); // s2 is pole
// segment overlapping pole
calc_t s1x_anti = s1x + constants::half_period();
math::normalize_longitude<units_t, calc_t>(s1x_anti);
bool antipodal = math::equals(s2x, s1x_anti);
if (antipodal)
{
eq1 = eq2 = eq1 || eq2;
// segment overlapping pole and point is pole
if (math::equals(py, pi2) || math::equals(py, -pi2))
{
eq1 = eq2 = true;
}
}
// Both equal p -> segment vertical
// The only thing which has to be done is check if point is ON segment
if (eq1 && eq2)
{
// segment endpoints on the same sides of the globe
if (! antipodal
// p's lat between segment endpoints' lats
? (s1y <= py && s2y >= py) || (s2y <= py && s1y >= py)
// going through north or south pole?
: (pi - s1y - s2y <= pi
? (eq1_strict && s1y <= py) || (eq2_strict && s2y <= py) // north
|| math::equals(py, pi2) // point on north pole
: (eq1_strict && s1y >= py) || (eq2_strict && s2y >= py)) // south
|| math::equals(py, -pi2) // point on south pole
)
{
state.m_touches = true;
}
return true;
}
return false;
}
};
// The optimization for cartesian
template <typename Point, typename CalculationType>
struct winding_check_touch<Point, CalculationType, cartesian_tag>
{
typedef CalculationType calc_t;
template <typename PointOfSegment, typename State>
static inline bool apply(Point const& point,
PointOfSegment const& seg1,
PointOfSegment const& seg2,
State& state,
bool& eq1,
bool& eq2)
{
calc_t const px = get<0>(point);
calc_t const s1x = get<0>(seg1);
calc_t const s2x = get<0>(seg2);
eq1 = math::equals(s1x, px);
eq2 = math::equals(s2x, px);
// Both equal p -> segment vertical
// The only thing which has to be done is check if point is ON segment
if (eq1 && eq2)
{
calc_t const py = get<1>(point);
calc_t const s1y = get<1>(seg1);
calc_t const s2y = get<1>(seg2);
if ((s1y <= py && s2y >= py) || (s2y <= py && s1y >= py))
{
state.m_touches = true;
}
return true;
}
return false;
}
};
// Called if point is not aligned with a vertical segment
template <typename Point,
typename CalculationType,
typename CSTag = typename cs_tag<Point>::type>
struct winding_calculate_count
{
typedef CalculationType calc_t;
typedef typename coordinate_system<Point>::type::units units_t;
static inline bool greater(calc_t const& l, calc_t const& r)
{
calc_t diff = l - r;
math::normalize_longitude<units_t, calc_t>(diff);
return diff > calc_t(0);
}
static inline int apply(calc_t const& p,
calc_t const& s1, calc_t const& s2,
bool eq1, bool eq2)
{
// Probably could be optimized by avoiding normalization for some comparisons
// e.g. s1 > p could be calculated from p > s1
// If both segment endpoints were poles below checks wouldn't be enough
// but this means that either both are the same or that they are N/S poles
// and therefore the segment is not valid.
// If needed (eq1 && eq2 ? 0) could be returned
return
eq1 ? (greater(s2, p) ? 1 : -1) // Point on level s1, E/W depending on s2
: eq2 ? (greater(s1, p) ? -1 : 1) // idem
: greater(p, s1) && greater(s2, p) ? 2 // Point between s1 -> s2 --> E
: greater(p, s2) && greater(s1, p) ? -2 // Point between s2 -> s1 --> W
: 0;
}
};
// The optimization for cartesian
template <typename Point, typename CalculationType>
struct winding_calculate_count<Point, CalculationType, cartesian_tag>
{
typedef CalculationType calc_t;
static inline int apply(calc_t const& p,
calc_t const& s1, calc_t const& s2,
bool eq1, bool eq2)
{
return
eq1 ? (s2 > p ? 1 : -1) // Point on level s1, E/W depending on s2
: eq2 ? (s1 > p ? -1 : 1) // idem
: s1 < p && s2 > p ? 2 // Point between s1 -> s2 --> E
: s2 < p && s1 > p ? -2 // Point between s2 -> s1 --> W
: 0;
}
};
/*!
\brief Within detection using winding rule
\ingroup strategies
\tparam Point \tparam_point
\tparam PointOfSegment \tparam_segment_point
\tparam SideStrategy Side strategy
\tparam CalculationType \tparam_calculation
\author Barend Gehrels
\note The implementation is inspired by terralib http://www.terralib.org (LGPL)
\note but totally revised afterwards, especially for cases on segments
\note Only dependant on "side", -> agnostic, suitable for spherical/latlong
\qbk{
[heading See also]
[link geometry.reference.algorithms.within.within_3_with_strategy within (with strategy)]
}
*/
template
<
typename Point,
typename PointOfSegment = Point,
typename SideStrategy = typename strategy::side::services::default_strategy
<
typename cs_tag<Point>::type
>::type,
typename CalculationType = void
>
class winding
{
typedef typename select_calculation_type
<
Point,
PointOfSegment,
CalculationType
>::type calculation_type;
/*! subclass to keep state */
class counter
{
int m_count;
bool m_touches;
inline int code() const
{
return m_touches ? 0 : m_count == 0 ? -1 : 1;
}
public :
friend class winding;
template <typename P, typename CT, typename CST>
friend struct winding_check_touch;
inline counter()
: m_count(0)
, m_touches(false)
{}
};
static inline int check_segment(Point const& point,
PointOfSegment const& seg1, PointOfSegment const& seg2,
counter& state, bool& eq1, bool& eq2)
{
if (winding_check_touch<Point, calculation_type>
::apply(point, seg1, seg2, state, eq1, eq2))
{
return 0;
}
calculation_type const p = get<0>(point);
calculation_type const s1 = get<0>(seg1);
calculation_type const s2 = get<0>(seg2);
return winding_calculate_count<Point, calculation_type>
::apply(p, s1, s2, eq1, eq2);
}
public:
winding()
{}
explicit winding(SideStrategy const& side_strategy)
: m_side_strategy(side_strategy)
{}
// Typedefs and static methods to fulfill the concept
typedef Point point_type;
typedef PointOfSegment segment_point_type;
typedef counter state_type;
inline bool apply(Point const& point,
PointOfSegment const& s1, PointOfSegment const& s2,
counter& state) const
{
typedef typename cs_tag<Point>::type cs_t;
bool eq1 = false;
bool eq2 = false;
boost::ignore_unused(eq2);
int count = check_segment(point, s1, s2, state, eq1, eq2);
if (count != 0)
{
int side = 0;
if (count == 1 || count == -1)
{
side = winding_side_equal<cs_t>::apply(point, eq1 ? s1 : s2, count);
}
else // count == 2 || count == -2
{
// 1 left, -1 right
side = m_side_strategy.apply(s1, s2, point);
}
if (side == 0)
{
// Point is lying on segment
state.m_touches = true;
state.m_count = 0;
return false;
}
// Side is NEG for right, POS for left.
// The count is -2 for down, 2 for up (or -1/1)
// Side positive thus means UP and LEFTSIDE or DOWN and RIGHTSIDE
// See accompagnying figure (TODO)
if (side * count > 0)
{
state.m_count += count;
}
}
return ! state.m_touches;
}
static inline int result(counter const& state)
{
return state.code();
}
private:
SideStrategy m_side_strategy;
};
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace services
{
template <typename Point, typename Geometry, typename AnyTag>
struct default_strategy<Point, Geometry, point_tag, AnyTag, pointlike_tag, polygonal_tag, cartesian_tag, cartesian_tag>
{
typedef winding<Point, typename geometry::point_type<Geometry>::type> type;
};
template <typename Point, typename Geometry, typename AnyTag>
struct default_strategy<Point, Geometry, point_tag, AnyTag, pointlike_tag, polygonal_tag, spherical_tag, spherical_tag>
{
typedef winding<Point, typename geometry::point_type<Geometry>::type> type;
};
template <typename Point, typename Geometry, typename AnyTag>
struct default_strategy<Point, Geometry, point_tag, AnyTag, pointlike_tag, linear_tag, cartesian_tag, cartesian_tag>
{
typedef winding<Point, typename geometry::point_type<Geometry>::type> type;
};
template <typename Point, typename Geometry, typename AnyTag>
struct default_strategy<Point, Geometry, point_tag, AnyTag, pointlike_tag, linear_tag, spherical_tag, spherical_tag>
{
typedef winding<Point, typename geometry::point_type<Geometry>::type> type;
};
} // namespace services
#endif
}} // namespace strategy::within
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
namespace strategy { namespace covered_by { namespace services
{
template <typename Point, typename Geometry, typename AnyTag>
struct default_strategy<Point, Geometry, point_tag, AnyTag, pointlike_tag, polygonal_tag, cartesian_tag, cartesian_tag>
{
typedef strategy::within::winding<Point, typename geometry::point_type<Geometry>::type> type;
};
template <typename Point, typename Geometry, typename AnyTag>
struct default_strategy<Point, Geometry, point_tag, AnyTag, pointlike_tag, polygonal_tag, spherical_tag, spherical_tag>
{
typedef strategy::within::winding<Point, typename geometry::point_type<Geometry>::type> type;
};
template <typename Point, typename Geometry, typename AnyTag>
struct default_strategy<Point, Geometry, point_tag, AnyTag, pointlike_tag, linear_tag, cartesian_tag, cartesian_tag>
{
typedef strategy::within::winding<Point, typename geometry::point_type<Geometry>::type> type;
};
template <typename Point, typename Geometry, typename AnyTag>
struct default_strategy<Point, Geometry, point_tag, AnyTag, pointlike_tag, linear_tag, spherical_tag, spherical_tag>
{
typedef strategy::within::winding<Point, typename geometry::point_type<Geometry>::type> type;
};
}}} // namespace strategy::covered_by::services
#endif
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGY_AGNOSTIC_POINT_IN_POLY_WINDING_HPP
@@ -0,0 +1,321 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 1995, 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 1995 Maarten Hilferink, Amsterdam, the Netherlands
// This file was modified by Oracle on 2015.
// Modifications copyright (c) 2015, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, 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.
// 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_STRATEGY_AGNOSTIC_SIMPLIFY_DOUGLAS_PEUCKER_HPP
#define BOOST_GEOMETRY_STRATEGY_AGNOSTIC_SIMPLIFY_DOUGLAS_PEUCKER_HPP
#include <cstddef>
#ifdef BOOST_GEOMETRY_DEBUG_DOUGLAS_PEUCKER
#include <iostream>
#endif
#include <vector>
#include <boost/range.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/strategies/distance.hpp>
#ifdef BOOST_GEOMETRY_DEBUG_DOUGLAS_PEUCKER
#include <boost/geometry/io/dsv/write.hpp>
#endif
namespace boost { namespace geometry
{
namespace strategy { namespace simplify
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail
{
/*!
\brief Small wrapper around a point, with an extra member "included"
\details
It has a const-reference to the original point (so no copy here)
\tparam the enclosed point type
*/
template<typename Point>
struct douglas_peucker_point
{
Point const& p;
bool included;
inline douglas_peucker_point(Point const& ap)
: p(ap)
, included(false)
{}
// Necessary for proper compilation
inline douglas_peucker_point<Point> operator=(douglas_peucker_point<Point> const& )
{
return douglas_peucker_point<Point>(*this);
}
};
template
<
typename Point,
typename PointDistanceStrategy,
typename LessCompare
= std::less
<
typename strategy::distance::services::return_type
<
PointDistanceStrategy,
Point, Point
>::type
>
>
class douglas_peucker
: LessCompare // for empty base optimization
{
public :
// See also ticket 5954 https://svn.boost.org/trac/boost/ticket/5954
// Comparable is currently not possible here because it has to be compared to the squared of max_distance, and more.
// For now we have to take the real distance.
typedef PointDistanceStrategy distance_strategy_type;
// typedef typename strategy::distance::services::comparable_type<PointDistanceStrategy>::type distance_strategy_type;
typedef typename strategy::distance::services::return_type
<
distance_strategy_type,
Point, Point
>::type distance_type;
douglas_peucker()
{}
douglas_peucker(LessCompare const& less_compare)
: LessCompare(less_compare)
{}
private :
typedef detail::douglas_peucker_point<Point> dp_point_type;
typedef typename std::vector<dp_point_type>::iterator iterator_type;
LessCompare const& less() const
{
return *this;
}
inline void consider(iterator_type begin,
iterator_type end,
distance_type const& max_dist,
int& n,
distance_strategy_type const& ps_distance_strategy) const
{
std::size_t size = end - begin;
// size must be at least 3
// because we want to consider a candidate point in between
if (size <= 2)
{
#ifdef BOOST_GEOMETRY_DEBUG_DOUGLAS_PEUCKER
if (begin != end)
{
std::cout << "ignore between " << dsv(begin->p)
<< " and " << dsv((end - 1)->p)
<< " size=" << size << std::endl;
}
std::cout << "return because size=" << size << std::endl;
#endif
return;
}
iterator_type last = end - 1;
#ifdef BOOST_GEOMETRY_DEBUG_DOUGLAS_PEUCKER
std::cout << "find between " << dsv(begin->p)
<< " and " << dsv(last->p)
<< " size=" << size << std::endl;
#endif
// Find most far point, compare to the current segment
//geometry::segment<Point const> s(begin->p, last->p);
distance_type md(-1.0); // any value < 0
iterator_type candidate;
for(iterator_type it = begin + 1; it != last; ++it)
{
distance_type dist = ps_distance_strategy.apply(it->p, begin->p, last->p);
#ifdef BOOST_GEOMETRY_DEBUG_DOUGLAS_PEUCKER
std::cout << "consider " << dsv(it->p)
<< " at " << double(dist)
<< ((dist > max_dist) ? " maybe" : " no")
<< std::endl;
#endif
if ( less()(md, dist) )
{
md = dist;
candidate = it;
}
}
// If a point is found, set the include flag
// and handle segments in between recursively
if ( less()(max_dist, md) )
{
#ifdef BOOST_GEOMETRY_DEBUG_DOUGLAS_PEUCKER
std::cout << "use " << dsv(candidate->p) << std::endl;
#endif
candidate->included = true;
n++;
consider(begin, candidate + 1, max_dist, n, ps_distance_strategy);
consider(candidate, end, max_dist, n, ps_distance_strategy);
}
}
public :
template <typename Range, typename OutputIterator>
inline OutputIterator apply(Range const& range,
OutputIterator out,
distance_type max_distance) const
{
#ifdef BOOST_GEOMETRY_DEBUG_DOUGLAS_PEUCKER
std::cout << "max distance: " << max_distance
<< std::endl << std::endl;
#endif
distance_strategy_type strategy;
// Copy coordinates, a vector of references to all points
std::vector<dp_point_type> ref_candidates(boost::begin(range),
boost::end(range));
// Include first and last point of line,
// they are always part of the line
int n = 2;
ref_candidates.front().included = true;
ref_candidates.back().included = true;
// Get points, recursively, including them if they are further away
// than the specified distance
consider(boost::begin(ref_candidates), boost::end(ref_candidates), max_distance, n, strategy);
// Copy included elements to the output
for(typename std::vector<dp_point_type>::const_iterator it
= boost::begin(ref_candidates);
it != boost::end(ref_candidates);
++it)
{
if (it->included)
{
// copy-coordinates does not work because OutputIterator
// does not model Point (??)
//geometry::convert(it->p, *out);
*out = it->p;
out++;
}
}
return out;
}
};
}
#endif // DOXYGEN_NO_DETAIL
/*!
\brief Implements the simplify algorithm.
\ingroup strategies
\details The douglas_peucker strategy simplifies a linestring, ring or
vector of points using the well-known Douglas-Peucker algorithm.
\tparam Point the point type
\tparam PointDistanceStrategy point-segment distance strategy to be used
\note This strategy uses itself a point-segment-distance strategy which
can be specified
\author Barend and Maarten, 1995/1996
\author Barend, revised for Generic Geometry Library, 2008
*/
/*
For the algorithm, see for example:
- http://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm
- http://www2.dcs.hull.ac.uk/CISRG/projects/Royal-Inst/demos/dp.html
*/
template
<
typename Point,
typename PointDistanceStrategy
>
class douglas_peucker
{
public :
typedef PointDistanceStrategy distance_strategy_type;
typedef typename detail::douglas_peucker
<
Point,
PointDistanceStrategy
>::distance_type distance_type;
template <typename Range, typename OutputIterator>
static inline OutputIterator apply(Range const& range,
OutputIterator out,
distance_type const& max_distance)
{
namespace services = strategy::distance::services;
typedef typename services::comparable_type
<
PointDistanceStrategy
>::type comparable_distance_strategy_type;
return detail::douglas_peucker
<
Point, comparable_distance_strategy_type
>().apply(range, out,
services::result_from_distance
<
comparable_distance_strategy_type, Point, Point
>::apply(comparable_distance_strategy_type(),
max_distance)
);
}
};
}} // namespace strategy::simplify
namespace traits {
template <typename P>
struct point_type<geometry::strategy::simplify::detail::douglas_peucker_point<P> >
{
typedef P type;
};
} // namespace traits
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGY_AGNOSTIC_SIMPLIFY_DOUGLAS_PEUCKER_HPP