Chris@16
|
1 // Boost.Geometry (aka GGL, Generic Geometry Library)
|
Chris@16
|
2
|
Chris@101
|
3 // Copyright (c) 1995, 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
|
Chris@16
|
4 // Copyright (c) 1995 Maarten Hilferink, Amsterdam, the Netherlands
|
Chris@16
|
5
|
Chris@101
|
6 // This file was modified by Oracle on 2015.
|
Chris@101
|
7 // Modifications copyright (c) 2015, Oracle and/or its affiliates.
|
Chris@101
|
8
|
Chris@101
|
9 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
|
Chris@101
|
10
|
Chris@16
|
11 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
|
Chris@16
|
12 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
|
Chris@16
|
13
|
Chris@16
|
14 // Use, modification and distribution is subject to the Boost Software License,
|
Chris@16
|
15 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
Chris@16
|
16 // http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
17
|
Chris@16
|
18 #ifndef BOOST_GEOMETRY_STRATEGY_AGNOSTIC_SIMPLIFY_DOUGLAS_PEUCKER_HPP
|
Chris@16
|
19 #define BOOST_GEOMETRY_STRATEGY_AGNOSTIC_SIMPLIFY_DOUGLAS_PEUCKER_HPP
|
Chris@16
|
20
|
Chris@16
|
21
|
Chris@16
|
22 #include <cstddef>
|
Chris@101
|
23 #ifdef BOOST_GEOMETRY_DEBUG_DOUGLAS_PEUCKER
|
Chris@101
|
24 #include <iostream>
|
Chris@101
|
25 #endif
|
Chris@16
|
26 #include <vector>
|
Chris@16
|
27
|
Chris@16
|
28 #include <boost/range.hpp>
|
Chris@16
|
29
|
Chris@16
|
30 #include <boost/geometry/core/cs.hpp>
|
Chris@16
|
31 #include <boost/geometry/strategies/distance.hpp>
|
Chris@16
|
32
|
Chris@16
|
33
|
Chris@101
|
34 #ifdef BOOST_GEOMETRY_DEBUG_DOUGLAS_PEUCKER
|
Chris@16
|
35 #include <boost/geometry/io/dsv/write.hpp>
|
Chris@16
|
36 #endif
|
Chris@16
|
37
|
Chris@16
|
38
|
Chris@16
|
39 namespace boost { namespace geometry
|
Chris@16
|
40 {
|
Chris@16
|
41
|
Chris@16
|
42 namespace strategy { namespace simplify
|
Chris@16
|
43 {
|
Chris@16
|
44
|
Chris@16
|
45
|
Chris@16
|
46 #ifndef DOXYGEN_NO_DETAIL
|
Chris@16
|
47 namespace detail
|
Chris@16
|
48 {
|
Chris@16
|
49
|
Chris@16
|
50 /*!
|
Chris@16
|
51 \brief Small wrapper around a point, with an extra member "included"
|
Chris@16
|
52 \details
|
Chris@16
|
53 It has a const-reference to the original point (so no copy here)
|
Chris@16
|
54 \tparam the enclosed point type
|
Chris@16
|
55 */
|
Chris@16
|
56 template<typename Point>
|
Chris@16
|
57 struct douglas_peucker_point
|
Chris@16
|
58 {
|
Chris@16
|
59 Point const& p;
|
Chris@16
|
60 bool included;
|
Chris@16
|
61
|
Chris@16
|
62 inline douglas_peucker_point(Point const& ap)
|
Chris@16
|
63 : p(ap)
|
Chris@16
|
64 , included(false)
|
Chris@16
|
65 {}
|
Chris@16
|
66
|
Chris@16
|
67 // Necessary for proper compilation
|
Chris@16
|
68 inline douglas_peucker_point<Point> operator=(douglas_peucker_point<Point> const& )
|
Chris@16
|
69 {
|
Chris@16
|
70 return douglas_peucker_point<Point>(*this);
|
Chris@16
|
71 }
|
Chris@16
|
72 };
|
Chris@101
|
73
|
Chris@101
|
74 template
|
Chris@101
|
75 <
|
Chris@101
|
76 typename Point,
|
Chris@101
|
77 typename PointDistanceStrategy,
|
Chris@101
|
78 typename LessCompare
|
Chris@101
|
79 = std::less
|
Chris@101
|
80 <
|
Chris@101
|
81 typename strategy::distance::services::return_type
|
Chris@101
|
82 <
|
Chris@101
|
83 PointDistanceStrategy,
|
Chris@101
|
84 Point, Point
|
Chris@101
|
85 >::type
|
Chris@101
|
86 >
|
Chris@101
|
87 >
|
Chris@101
|
88 class douglas_peucker
|
Chris@101
|
89 : LessCompare // for empty base optimization
|
Chris@101
|
90 {
|
Chris@101
|
91 public :
|
Chris@101
|
92
|
Chris@101
|
93 // See also ticket 5954 https://svn.boost.org/trac/boost/ticket/5954
|
Chris@101
|
94 // Comparable is currently not possible here because it has to be compared to the squared of max_distance, and more.
|
Chris@101
|
95 // For now we have to take the real distance.
|
Chris@101
|
96 typedef PointDistanceStrategy distance_strategy_type;
|
Chris@101
|
97 // typedef typename strategy::distance::services::comparable_type<PointDistanceStrategy>::type distance_strategy_type;
|
Chris@101
|
98
|
Chris@101
|
99 typedef typename strategy::distance::services::return_type
|
Chris@101
|
100 <
|
Chris@101
|
101 distance_strategy_type,
|
Chris@101
|
102 Point, Point
|
Chris@101
|
103 >::type distance_type;
|
Chris@101
|
104
|
Chris@101
|
105 douglas_peucker()
|
Chris@101
|
106 {}
|
Chris@101
|
107
|
Chris@101
|
108 douglas_peucker(LessCompare const& less_compare)
|
Chris@101
|
109 : LessCompare(less_compare)
|
Chris@101
|
110 {}
|
Chris@101
|
111
|
Chris@101
|
112 private :
|
Chris@101
|
113 typedef detail::douglas_peucker_point<Point> dp_point_type;
|
Chris@101
|
114 typedef typename std::vector<dp_point_type>::iterator iterator_type;
|
Chris@101
|
115
|
Chris@101
|
116
|
Chris@101
|
117 LessCompare const& less() const
|
Chris@101
|
118 {
|
Chris@101
|
119 return *this;
|
Chris@101
|
120 }
|
Chris@101
|
121
|
Chris@101
|
122 inline void consider(iterator_type begin,
|
Chris@101
|
123 iterator_type end,
|
Chris@101
|
124 distance_type const& max_dist,
|
Chris@101
|
125 int& n,
|
Chris@101
|
126 distance_strategy_type const& ps_distance_strategy) const
|
Chris@101
|
127 {
|
Chris@101
|
128 std::size_t size = end - begin;
|
Chris@101
|
129
|
Chris@101
|
130 // size must be at least 3
|
Chris@101
|
131 // because we want to consider a candidate point in between
|
Chris@101
|
132 if (size <= 2)
|
Chris@101
|
133 {
|
Chris@101
|
134 #ifdef BOOST_GEOMETRY_DEBUG_DOUGLAS_PEUCKER
|
Chris@101
|
135 if (begin != end)
|
Chris@101
|
136 {
|
Chris@101
|
137 std::cout << "ignore between " << dsv(begin->p)
|
Chris@101
|
138 << " and " << dsv((end - 1)->p)
|
Chris@101
|
139 << " size=" << size << std::endl;
|
Chris@101
|
140 }
|
Chris@101
|
141 std::cout << "return because size=" << size << std::endl;
|
Chris@101
|
142 #endif
|
Chris@101
|
143 return;
|
Chris@101
|
144 }
|
Chris@101
|
145
|
Chris@101
|
146 iterator_type last = end - 1;
|
Chris@101
|
147
|
Chris@101
|
148 #ifdef BOOST_GEOMETRY_DEBUG_DOUGLAS_PEUCKER
|
Chris@101
|
149 std::cout << "find between " << dsv(begin->p)
|
Chris@101
|
150 << " and " << dsv(last->p)
|
Chris@101
|
151 << " size=" << size << std::endl;
|
Chris@101
|
152 #endif
|
Chris@101
|
153
|
Chris@101
|
154
|
Chris@101
|
155 // Find most far point, compare to the current segment
|
Chris@101
|
156 //geometry::segment<Point const> s(begin->p, last->p);
|
Chris@101
|
157 distance_type md(-1.0); // any value < 0
|
Chris@101
|
158 iterator_type candidate;
|
Chris@101
|
159 for(iterator_type it = begin + 1; it != last; ++it)
|
Chris@101
|
160 {
|
Chris@101
|
161 distance_type dist = ps_distance_strategy.apply(it->p, begin->p, last->p);
|
Chris@101
|
162
|
Chris@101
|
163 #ifdef BOOST_GEOMETRY_DEBUG_DOUGLAS_PEUCKER
|
Chris@101
|
164 std::cout << "consider " << dsv(it->p)
|
Chris@101
|
165 << " at " << double(dist)
|
Chris@101
|
166 << ((dist > max_dist) ? " maybe" : " no")
|
Chris@101
|
167 << std::endl;
|
Chris@101
|
168
|
Chris@101
|
169 #endif
|
Chris@101
|
170 if ( less()(md, dist) )
|
Chris@101
|
171 {
|
Chris@101
|
172 md = dist;
|
Chris@101
|
173 candidate = it;
|
Chris@101
|
174 }
|
Chris@101
|
175 }
|
Chris@101
|
176
|
Chris@101
|
177 // If a point is found, set the include flag
|
Chris@101
|
178 // and handle segments in between recursively
|
Chris@101
|
179 if ( less()(max_dist, md) )
|
Chris@101
|
180 {
|
Chris@101
|
181 #ifdef BOOST_GEOMETRY_DEBUG_DOUGLAS_PEUCKER
|
Chris@101
|
182 std::cout << "use " << dsv(candidate->p) << std::endl;
|
Chris@101
|
183 #endif
|
Chris@101
|
184
|
Chris@101
|
185 candidate->included = true;
|
Chris@101
|
186 n++;
|
Chris@101
|
187
|
Chris@101
|
188 consider(begin, candidate + 1, max_dist, n, ps_distance_strategy);
|
Chris@101
|
189 consider(candidate, end, max_dist, n, ps_distance_strategy);
|
Chris@101
|
190 }
|
Chris@101
|
191 }
|
Chris@101
|
192
|
Chris@101
|
193
|
Chris@101
|
194 public :
|
Chris@101
|
195
|
Chris@101
|
196 template <typename Range, typename OutputIterator>
|
Chris@101
|
197 inline OutputIterator apply(Range const& range,
|
Chris@101
|
198 OutputIterator out,
|
Chris@101
|
199 distance_type max_distance) const
|
Chris@101
|
200 {
|
Chris@101
|
201 #ifdef BOOST_GEOMETRY_DEBUG_DOUGLAS_PEUCKER
|
Chris@101
|
202 std::cout << "max distance: " << max_distance
|
Chris@101
|
203 << std::endl << std::endl;
|
Chris@101
|
204 #endif
|
Chris@101
|
205 distance_strategy_type strategy;
|
Chris@101
|
206
|
Chris@101
|
207 // Copy coordinates, a vector of references to all points
|
Chris@101
|
208 std::vector<dp_point_type> ref_candidates(boost::begin(range),
|
Chris@101
|
209 boost::end(range));
|
Chris@101
|
210
|
Chris@101
|
211 // Include first and last point of line,
|
Chris@101
|
212 // they are always part of the line
|
Chris@101
|
213 int n = 2;
|
Chris@101
|
214 ref_candidates.front().included = true;
|
Chris@101
|
215 ref_candidates.back().included = true;
|
Chris@101
|
216
|
Chris@101
|
217 // Get points, recursively, including them if they are further away
|
Chris@101
|
218 // than the specified distance
|
Chris@101
|
219 consider(boost::begin(ref_candidates), boost::end(ref_candidates), max_distance, n, strategy);
|
Chris@101
|
220
|
Chris@101
|
221 // Copy included elements to the output
|
Chris@101
|
222 for(typename std::vector<dp_point_type>::const_iterator it
|
Chris@101
|
223 = boost::begin(ref_candidates);
|
Chris@101
|
224 it != boost::end(ref_candidates);
|
Chris@101
|
225 ++it)
|
Chris@101
|
226 {
|
Chris@101
|
227 if (it->included)
|
Chris@101
|
228 {
|
Chris@101
|
229 // copy-coordinates does not work because OutputIterator
|
Chris@101
|
230 // does not model Point (??)
|
Chris@101
|
231 //geometry::convert(it->p, *out);
|
Chris@101
|
232 *out = it->p;
|
Chris@101
|
233 out++;
|
Chris@101
|
234 }
|
Chris@101
|
235 }
|
Chris@101
|
236 return out;
|
Chris@101
|
237 }
|
Chris@101
|
238
|
Chris@101
|
239 };
|
Chris@16
|
240 }
|
Chris@16
|
241 #endif // DOXYGEN_NO_DETAIL
|
Chris@16
|
242
|
Chris@16
|
243
|
Chris@16
|
244 /*!
|
Chris@16
|
245 \brief Implements the simplify algorithm.
|
Chris@16
|
246 \ingroup strategies
|
Chris@16
|
247 \details The douglas_peucker strategy simplifies a linestring, ring or
|
Chris@16
|
248 vector of points using the well-known Douglas-Peucker algorithm.
|
Chris@16
|
249 \tparam Point the point type
|
Chris@16
|
250 \tparam PointDistanceStrategy point-segment distance strategy to be used
|
Chris@16
|
251 \note This strategy uses itself a point-segment-distance strategy which
|
Chris@16
|
252 can be specified
|
Chris@16
|
253 \author Barend and Maarten, 1995/1996
|
Chris@16
|
254 \author Barend, revised for Generic Geometry Library, 2008
|
Chris@16
|
255 */
|
Chris@16
|
256
|
Chris@16
|
257 /*
|
Chris@16
|
258 For the algorithm, see for example:
|
Chris@16
|
259 - http://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm
|
Chris@16
|
260 - http://www2.dcs.hull.ac.uk/CISRG/projects/Royal-Inst/demos/dp.html
|
Chris@16
|
261 */
|
Chris@16
|
262 template
|
Chris@16
|
263 <
|
Chris@16
|
264 typename Point,
|
Chris@16
|
265 typename PointDistanceStrategy
|
Chris@16
|
266 >
|
Chris@16
|
267 class douglas_peucker
|
Chris@16
|
268 {
|
Chris@16
|
269 public :
|
Chris@16
|
270
|
Chris@16
|
271 typedef PointDistanceStrategy distance_strategy_type;
|
Chris@16
|
272
|
Chris@101
|
273 typedef typename detail::douglas_peucker
|
Chris@101
|
274 <
|
Chris@101
|
275 Point,
|
Chris@101
|
276 PointDistanceStrategy
|
Chris@101
|
277 >::distance_type distance_type;
|
Chris@16
|
278
|
Chris@16
|
279 template <typename Range, typename OutputIterator>
|
Chris@16
|
280 static inline OutputIterator apply(Range const& range,
|
Chris@101
|
281 OutputIterator out,
|
Chris@101
|
282 distance_type const& max_distance)
|
Chris@16
|
283 {
|
Chris@101
|
284 namespace services = strategy::distance::services;
|
Chris@16
|
285
|
Chris@101
|
286 typedef typename services::comparable_type
|
Chris@101
|
287 <
|
Chris@101
|
288 PointDistanceStrategy
|
Chris@101
|
289 >::type comparable_distance_strategy_type;
|
Chris@16
|
290
|
Chris@101
|
291 return detail::douglas_peucker
|
Chris@101
|
292 <
|
Chris@101
|
293 Point, comparable_distance_strategy_type
|
Chris@101
|
294 >().apply(range, out,
|
Chris@101
|
295 services::result_from_distance
|
Chris@101
|
296 <
|
Chris@101
|
297 comparable_distance_strategy_type, Point, Point
|
Chris@101
|
298 >::apply(comparable_distance_strategy_type(),
|
Chris@101
|
299 max_distance)
|
Chris@101
|
300 );
|
Chris@16
|
301 }
|
Chris@16
|
302
|
Chris@16
|
303 };
|
Chris@16
|
304
|
Chris@16
|
305 }} // namespace strategy::simplify
|
Chris@16
|
306
|
Chris@16
|
307
|
Chris@16
|
308 namespace traits {
|
Chris@16
|
309
|
Chris@16
|
310 template <typename P>
|
Chris@16
|
311 struct point_type<strategy::simplify::detail::douglas_peucker_point<P> >
|
Chris@16
|
312 {
|
Chris@16
|
313 typedef P type;
|
Chris@16
|
314 };
|
Chris@16
|
315
|
Chris@16
|
316 } // namespace traits
|
Chris@16
|
317
|
Chris@16
|
318
|
Chris@16
|
319 }} // namespace boost::geometry
|
Chris@16
|
320
|
Chris@16
|
321 #endif // BOOST_GEOMETRY_STRATEGY_AGNOSTIC_SIMPLIFY_DOUGLAS_PEUCKER_HPP
|