diff --git a/include/boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp b/include/boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp index f7d48fa95..78de4d438 100644 --- a/include/boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp @@ -15,6 +15,8 @@ #include #include +#include + namespace boost { namespace geometry { @@ -108,7 +110,11 @@ inline void clean_closing_dups_and_spikes(Range& range, } typedef typename boost::range_iterator::type iterator_type; - const bool closed = geometry::closure::value == geometry::closed; + static const bool closed = geometry::closure::value == geometry::closed; + +// TODO: the following algorithm could be rewritten to first look for spikes +// and then erase some number of points from the beginning of the Range + bool found = false; do { @@ -125,13 +131,13 @@ inline void clean_closing_dups_and_spikes(Range& range, // considered as a spike w.r.t. the last segment) if (point_is_spike_or_equal(*second, *ultimate, *first, robust_policy)) { - range.erase(first); + range::erase(range, first); if (closed) { // Remove closing last point - traits::resize::apply(range, boost::size(range) - 1); + range::resize(range, boost::size(range) - 1); // Add new closing point - traits::push_back::apply(range, *boost::begin(range)); + range::push_back(range, *boost::begin(range)); } found = true; } diff --git a/include/boost/geometry/util/range.hpp b/include/boost/geometry/util/range.hpp index 986aba660..ddee14ea8 100644 --- a/include/boost/geometry/util/range.hpp +++ b/include/boost/geometry/util/range.hpp @@ -14,6 +14,9 @@ #ifndef BOOST_GEOMETRY_UTIL_RANGE_HPP #define BOOST_GEOMETRY_UTIL_RANGE_HPP +#include + +#include #include #include #include @@ -21,6 +24,8 @@ #include #include +#include + namespace boost { namespace geometry { namespace range { // NOTE: For SinglePassRanges at could iterate over all elements until the i-th element is met. @@ -105,6 +110,110 @@ back(BidirectionalRange & rng) return *(--boost::end(rng)); } + +/*! +\brief Short utility to conveniently clear a mutable range. + It uses traits::clear<>. +\ingroup utility +*/ +template +inline void clear(Range & rng) +{ + // NOTE: this trait is probably not needed since it could be implemented using resize() + geometry::traits::clear::apply(rng); +} + +/*! +\brief Short utility to conveniently insert a new element at the end of a mutable range. + It uses boost::geometry::traits::push_back<>. +\ingroup utility +*/ +template +inline void push_back(Range & rng, + typename boost::range_value::type const& value) +{ + geometry::traits::push_back::apply(rng, value); +} + +/*! +\brief Short utility to conveniently resize a mutable range. + It uses boost::geometry::traits::resize<>. +\ingroup utility +*/ +template +inline void resize(Range & rng, + typename boost::range_size::type new_size) +{ + geometry::traits::resize::apply(rng, new_size); +} + + +/*! +\brief Short utility to conveniently remove an element from the back of a mutable range. + It uses resize(). +\ingroup utility +*/ +template +inline void pop_back(Range & rng) +{ + BOOST_ASSERT(!boost::empty(rng)); + range::resize(rng, boost::size(rng) - 1); +} + +/*! +\brief Short utility to conveniently remove an element from a mutable range. + It uses std::copy() and resize(). It requires mutable iterator as parameter. +\ingroup utility +*/ +template +inline typename boost::range_iterator::type +erase(Range & rng, + typename boost::range_iterator::type it) +{ + BOOST_ASSERT(!boost::empty(rng)); + BOOST_ASSERT(it != boost::end(rng)); + + typename boost::range_iterator::type + next = it; + ++next; + + std::copy(next, boost::end(rng), it); + range::resize(rng, boost::size(rng) - 1); + + // NOTE: assuming that resize() doesn't invalidate the iterators + return it; +} + +/*! +\brief Short utility to conveniently remove a range of elements from a mutable range. + It uses std::copy() and resize(). It requires mutable iterators as parameters. +\ingroup utility +*/ +template +inline typename boost::range_iterator::type +erase(Range & rng, + typename boost::range_iterator::type first, + typename boost::range_iterator::type last) +{ + typename std::iterator_traits + < + typename boost::range_iterator::type + >::difference_type const diff = std::distance(first, last); + BOOST_ASSERT(diff >= 0); + + std::size_t const count = static_cast(diff); + BOOST_ASSERT(count <= boost::size(rng)); + + if ( count > 0 ) + { + std::copy(last, boost::end(rng), first); + range::resize(rng, boost::size(rng) - count); + } + + // NOTE: assuming that resize() doesn't invalidate the iterators + return first; +} + }}} // namespace boost::geometry::range #endif // BOOST_GEOMETRY_UTIL_RANGE_HPP