1
// Generic Geometry Library
3
// Copyright Barend Gehrels 1995-2009, Geodan Holding B.V. Amsterdam, the Netherlands.
4
// Copyright Bruno Lalande 2008, 2009
5
// Use, modification and distribution is subject to the Boost Software License,
6
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
7
// http://www.boost.org/LICENSE_1_0.txt)
9
#ifndef GGL_STRATEGIES_AGNOSTIC_CONVEX_HULL_HPP
10
#define GGL_STRATEGIES_AGNOSTIC_CONVEX_HULL_HPP
13
#pragma warning( disable : 4101 )
20
#include <boost/range/functions.hpp>
22
#include <ggl/core/cs.hpp>
23
#include <ggl/strategies/strategy_traits.hpp>
25
// TODO: Temporary, comparing tests, this can be removed in the end
26
#if defined(GGL_USE_SMOOTH_SORT)
27
# include "SmoothSort.hpp"
28
#elif defined(GGL_USE_MERGE_SORT)
29
# include "MergeSort.hpp"
36
namespace strategy { namespace convex_hull {
38
#ifndef DOXYGEN_NO_DETAIL
42
template <typename Range, typename RangeIterator, typename Strategy>
43
static inline void get_extremes(const Range& range,
44
RangeIterator& min_it, RangeIterator& max_it,
45
const Strategy& strategy)
47
min_it = boost::begin(range);
48
max_it = boost::begin(range);
50
for (RangeIterator it = boost::begin(range) + 1; it != boost::end(range); ++it)
52
if (strategy.smaller(*it, *min_it))
57
if (strategy.larger(*it, *max_it))
65
static inline void sort(R& range)
67
#if defined(USE_SMOOTH_SORT)
68
smoothsort::sort(boost::begin(range), boost::end(range));
69
#elif defined(USE_MERGE_SORT)
70
comparing::merge_sort<thread_count>(boost::begin(range), boost::end(range), std::less<P>());
72
std::sort(boost::begin(range), boost::end(range));
77
#endif // DOXYGEN_NO_DETAIL
80
// Completely reworked version from source at:
81
// http://www.ddj.com/architect/201806315
82
// also available at http://marknelson.us/2007/08/22/convex
88
typedef typename cs_tag<P>::type cs_tag;
89
typedef typename std::vector<P> container;
90
typedef typename std::vector<P>::const_iterator iterator;
91
typedef typename std::vector<P>::const_reverse_iterator rev_iterator;
93
container m_lower_hull;
94
container m_upper_hull;
95
container m_copied_input;
100
// Default constructor, ranges can be added using "add_range" but note they'll be copied
105
// Constructor with a range
106
template <typename Range>
107
inline graham(const Range& range)
113
template <typename OutputIterator>
114
inline void get(OutputIterator out)
116
for (iterator it = m_upper_hull.begin(); it != m_upper_hull.end(); ++it, ++out)
121
// STL Port does not accept iterating from rbegin+1 to rend
122
std::size_t size = m_lower_hull.size();
125
rev_iterator it = m_lower_hull.rbegin() + 1;
126
for (std::size_t i = 1; i < size; ++i, ++it, ++out)
136
// Consider if it is better to create an iterator over a multi, which is then used here,
137
// instead of copying the range
138
// It makes it slightly more complicated but avoids the copy, which is attractive because
139
// multi-polygons (where it is used for) can be large.
140
template <typename Range>
141
inline void add_range(const Range& range)
143
std::copy(boost::begin(range), boost::end(range), std::back_inserter(m_copied_input));
146
inline void handle_input()
148
handle_range(m_copied_input);
154
template <typename Range>
155
inline void handle_range(const Range& range)
157
typedef typename boost::range_const_iterator<Range>::type range_iterator;
159
// Polygons with three corners, or closed with 4 points, are always convex
160
if (boost::size(range) <= 3)
162
for (range_iterator it = boost::begin(range);
163
it != boost::end(range);
166
m_upper_hull.push_back(*it);
171
// Get min/max (in most cases left / right) points
172
range_iterator left_it, right_it;
173
typename strategy_compare<cs_tag, P, 0>::type comparing;
174
detail::get_extremes(range, left_it, right_it, comparing);
176
// Bounding left/right points
177
container lower_points, upper_points;
179
assign_range(range, left_it, right_it, lower_points, upper_points);
181
detail::sort(lower_points);
182
detail::sort(upper_points);
184
build_half_hull<1>(lower_points, m_lower_hull, *left_it, *right_it);
185
build_half_hull<-1>(upper_points, m_upper_hull, *left_it, *right_it);
190
template <typename RangeIterator, typename Range>
191
inline void assign_range(const Range& range,
192
const RangeIterator& left_it,
193
const RangeIterator& right_it,
194
container& lower_points,
195
container& upper_points)
197
typename strategy_side<cs_tag, P>::type side;
199
// Put points in one of the two output sequences
200
for (RangeIterator it = boost::begin(range);
201
it != boost::end(range);
204
if (it != left_it && it != right_it)
206
int dir = side.side(*left_it, *right_it, *it);
209
upper_points.push_back(*it);
213
lower_points.push_back(*it);
220
template <int Factor>
221
inline void build_half_hull(const container& input, container& output,
222
const P& left, const P& right)
224
output.push_back(left);
225
for(iterator it = input.begin(); it != input.end(); ++it)
227
add_to_hull<Factor>(*it, output);
229
add_to_hull<Factor>(right, output);
232
template <int Factor>
233
inline void add_to_hull(const P& p, container& output)
235
typename strategy_side<cs_tag, P>::type side;
238
register std::size_t output_size = output.size();
239
while (output_size >= 3)
241
rev_iterator rit = output.rbegin();
242
const P& last = *rit++;
243
const P& last2 = *rit++;
245
if (Factor * side.side(*rit, last, last2) <= 0)
247
// Remove last two points from stack, and add last again
248
// This is much faster then erasing the one but last.
251
output.push_back(last);
264
}} // namespace strategy::convex_hull
267
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
268
template <typename P>
269
struct strategy_convex_hull<cartesian_tag, P>
271
typedef strategy::convex_hull::graham<P> type;
278
#endif // GGL_STRATEGY_AGNOSTIC_CONVEX_HULL_HPP