Chris@16
|
1 // Boost.Geometry (aka GGL, Generic Geometry Library)
|
Chris@16
|
2
|
Chris@16
|
3 // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
|
Chris@16
|
4 // Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
|
Chris@16
|
5 // Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
|
Chris@16
|
6
|
Chris@16
|
7 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
|
Chris@16
|
8 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
|
Chris@16
|
9
|
Chris@16
|
10 // Use, modification and distribution is subject to the Boost Software License,
|
Chris@16
|
11 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
Chris@16
|
12 // http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
13
|
Chris@16
|
14 #ifndef BOOST_GEOMETRY_ALGORITHMS_SIMPLIFY_HPP
|
Chris@16
|
15 #define BOOST_GEOMETRY_ALGORITHMS_SIMPLIFY_HPP
|
Chris@16
|
16
|
Chris@16
|
17
|
Chris@16
|
18 #include <cstddef>
|
Chris@16
|
19
|
Chris@16
|
20 #include <boost/range.hpp>
|
Chris@16
|
21 #include <boost/typeof/typeof.hpp>
|
Chris@16
|
22
|
Chris@16
|
23 #include <boost/geometry/core/cs.hpp>
|
Chris@16
|
24 #include <boost/geometry/core/closure.hpp>
|
Chris@16
|
25 #include <boost/geometry/core/ring_type.hpp>
|
Chris@16
|
26 #include <boost/geometry/core/exterior_ring.hpp>
|
Chris@16
|
27 #include <boost/geometry/core/interior_rings.hpp>
|
Chris@16
|
28 #include <boost/geometry/core/mutable_range.hpp>
|
Chris@16
|
29
|
Chris@16
|
30 #include <boost/geometry/geometries/concepts/check.hpp>
|
Chris@16
|
31 #include <boost/geometry/strategies/agnostic/simplify_douglas_peucker.hpp>
|
Chris@16
|
32 #include <boost/geometry/strategies/concepts/simplify_concept.hpp>
|
Chris@16
|
33
|
Chris@16
|
34 #include <boost/geometry/algorithms/clear.hpp>
|
Chris@16
|
35 #include <boost/geometry/algorithms/convert.hpp>
|
Chris@16
|
36 #include <boost/geometry/algorithms/not_implemented.hpp>
|
Chris@16
|
37 #include <boost/geometry/algorithms/num_interior_rings.hpp>
|
Chris@16
|
38
|
Chris@16
|
39
|
Chris@16
|
40 namespace boost { namespace geometry
|
Chris@16
|
41 {
|
Chris@16
|
42
|
Chris@16
|
43 #ifndef DOXYGEN_NO_DETAIL
|
Chris@16
|
44 namespace detail { namespace simplify
|
Chris@16
|
45 {
|
Chris@16
|
46
|
Chris@16
|
47 struct simplify_range_insert
|
Chris@16
|
48 {
|
Chris@16
|
49 template<typename Range, typename Strategy, typename OutputIterator, typename Distance>
|
Chris@16
|
50 static inline void apply(Range const& range, OutputIterator out,
|
Chris@16
|
51 Distance const& max_distance, Strategy const& strategy)
|
Chris@16
|
52 {
|
Chris@16
|
53 if (boost::size(range) <= 2 || max_distance < 0)
|
Chris@16
|
54 {
|
Chris@16
|
55 std::copy(boost::begin(range), boost::end(range), out);
|
Chris@16
|
56 }
|
Chris@16
|
57 else
|
Chris@16
|
58 {
|
Chris@16
|
59 strategy.apply(range, out, max_distance);
|
Chris@16
|
60 }
|
Chris@16
|
61 }
|
Chris@16
|
62 };
|
Chris@16
|
63
|
Chris@16
|
64
|
Chris@16
|
65 struct simplify_copy
|
Chris@16
|
66 {
|
Chris@16
|
67 template <typename Range, typename Strategy, typename Distance>
|
Chris@16
|
68 static inline void apply(Range const& range, Range& out,
|
Chris@16
|
69 Distance const& , Strategy const& )
|
Chris@16
|
70 {
|
Chris@16
|
71 std::copy
|
Chris@16
|
72 (
|
Chris@16
|
73 boost::begin(range), boost::end(range), std::back_inserter(out)
|
Chris@16
|
74 );
|
Chris@16
|
75 }
|
Chris@16
|
76 };
|
Chris@16
|
77
|
Chris@16
|
78
|
Chris@16
|
79 template<std::size_t Minimum>
|
Chris@16
|
80 struct simplify_range
|
Chris@16
|
81 {
|
Chris@16
|
82 template <typename Range, typename Strategy, typename Distance>
|
Chris@16
|
83 static inline void apply(Range const& range, Range& out,
|
Chris@16
|
84 Distance const& max_distance, Strategy const& strategy)
|
Chris@16
|
85 {
|
Chris@16
|
86 // Call do_container for a linestring / ring
|
Chris@16
|
87
|
Chris@16
|
88 /* For a RING:
|
Chris@16
|
89 The first/last point (the closing point of the ring) should maybe
|
Chris@16
|
90 be excluded because it lies on a line with second/one but last.
|
Chris@16
|
91 Here it is never excluded.
|
Chris@16
|
92
|
Chris@16
|
93 Note also that, especially if max_distance is too large,
|
Chris@16
|
94 the output ring might be self intersecting while the input ring is
|
Chris@16
|
95 not, although chances are low in normal polygons
|
Chris@16
|
96
|
Chris@16
|
97 Finally the inputring might have 3 (open) or 4 (closed) points (=correct),
|
Chris@16
|
98 the output < 3 or 4(=wrong)
|
Chris@16
|
99 */
|
Chris@16
|
100
|
Chris@16
|
101 if (boost::size(range) <= int(Minimum) || max_distance < 0.0)
|
Chris@16
|
102 {
|
Chris@16
|
103 simplify_copy::apply(range, out, max_distance, strategy);
|
Chris@16
|
104 }
|
Chris@16
|
105 else
|
Chris@16
|
106 {
|
Chris@16
|
107 simplify_range_insert::apply
|
Chris@16
|
108 (
|
Chris@16
|
109 range, std::back_inserter(out), max_distance, strategy
|
Chris@16
|
110 );
|
Chris@16
|
111 }
|
Chris@16
|
112 }
|
Chris@16
|
113 };
|
Chris@16
|
114
|
Chris@16
|
115 struct simplify_polygon
|
Chris@16
|
116 {
|
Chris@16
|
117 template <typename Polygon, typename Strategy, typename Distance>
|
Chris@16
|
118 static inline void apply(Polygon const& poly_in, Polygon& poly_out,
|
Chris@16
|
119 Distance const& max_distance, Strategy const& strategy)
|
Chris@16
|
120 {
|
Chris@16
|
121 typedef typename ring_type<Polygon>::type ring_type;
|
Chris@16
|
122
|
Chris@16
|
123 int const Minimum = core_detail::closure::minimum_ring_size
|
Chris@16
|
124 <
|
Chris@16
|
125 geometry::closure<Polygon>::value
|
Chris@16
|
126 >::value;
|
Chris@16
|
127
|
Chris@16
|
128 // Note that if there are inner rings, and distance is too large,
|
Chris@16
|
129 // they might intersect with the outer ring in the output,
|
Chris@16
|
130 // while it didn't in the input.
|
Chris@16
|
131 simplify_range<Minimum>::apply(exterior_ring(poly_in),
|
Chris@16
|
132 exterior_ring(poly_out),
|
Chris@16
|
133 max_distance, strategy);
|
Chris@16
|
134
|
Chris@16
|
135 traits::resize
|
Chris@16
|
136 <
|
Chris@16
|
137 typename boost::remove_reference
|
Chris@16
|
138 <
|
Chris@16
|
139 typename traits::interior_mutable_type<Polygon>::type
|
Chris@16
|
140 >::type
|
Chris@16
|
141 >::apply(interior_rings(poly_out), num_interior_rings(poly_in));
|
Chris@16
|
142
|
Chris@16
|
143 typename interior_return_type<Polygon const>::type rings_in
|
Chris@16
|
144 = interior_rings(poly_in);
|
Chris@16
|
145 typename interior_return_type<Polygon>::type rings_out
|
Chris@16
|
146 = interior_rings(poly_out);
|
Chris@16
|
147 BOOST_AUTO_TPL(it_out, boost::begin(rings_out));
|
Chris@16
|
148 for (BOOST_AUTO_TPL(it_in, boost::begin(rings_in));
|
Chris@16
|
149 it_in != boost::end(rings_in);
|
Chris@16
|
150 ++it_in, ++it_out)
|
Chris@16
|
151 {
|
Chris@16
|
152 simplify_range<Minimum>::apply(*it_in, *it_out, max_distance, strategy);
|
Chris@16
|
153 }
|
Chris@16
|
154 }
|
Chris@16
|
155 };
|
Chris@16
|
156
|
Chris@16
|
157
|
Chris@16
|
158 }} // namespace detail::simplify
|
Chris@16
|
159 #endif // DOXYGEN_NO_DETAIL
|
Chris@16
|
160
|
Chris@16
|
161
|
Chris@16
|
162 #ifndef DOXYGEN_NO_DISPATCH
|
Chris@16
|
163 namespace dispatch
|
Chris@16
|
164 {
|
Chris@16
|
165
|
Chris@16
|
166 template
|
Chris@16
|
167 <
|
Chris@16
|
168 typename Geometry,
|
Chris@16
|
169 typename Tag = typename tag<Geometry>::type
|
Chris@16
|
170 >
|
Chris@16
|
171 struct simplify: not_implemented<Tag>
|
Chris@16
|
172 {};
|
Chris@16
|
173
|
Chris@16
|
174 template <typename Point>
|
Chris@16
|
175 struct simplify<Point, point_tag>
|
Chris@16
|
176 {
|
Chris@16
|
177 template <typename Distance, typename Strategy>
|
Chris@16
|
178 static inline void apply(Point const& point, Point& out,
|
Chris@16
|
179 Distance const& , Strategy const& )
|
Chris@16
|
180 {
|
Chris@16
|
181 geometry::convert(point, out);
|
Chris@16
|
182 }
|
Chris@16
|
183 };
|
Chris@16
|
184
|
Chris@16
|
185
|
Chris@16
|
186 template <typename Linestring>
|
Chris@16
|
187 struct simplify<Linestring, linestring_tag>
|
Chris@16
|
188 : detail::simplify::simplify_range<2>
|
Chris@16
|
189 {};
|
Chris@16
|
190
|
Chris@16
|
191 template <typename Ring>
|
Chris@16
|
192 struct simplify<Ring, ring_tag>
|
Chris@16
|
193 : detail::simplify::simplify_range
|
Chris@16
|
194 <
|
Chris@16
|
195 core_detail::closure::minimum_ring_size
|
Chris@16
|
196 <
|
Chris@16
|
197 geometry::closure<Ring>::value
|
Chris@16
|
198 >::value
|
Chris@16
|
199 >
|
Chris@16
|
200 {};
|
Chris@16
|
201
|
Chris@16
|
202 template <typename Polygon>
|
Chris@16
|
203 struct simplify<Polygon, polygon_tag>
|
Chris@16
|
204 : detail::simplify::simplify_polygon
|
Chris@16
|
205 {};
|
Chris@16
|
206
|
Chris@16
|
207
|
Chris@16
|
208 template
|
Chris@16
|
209 <
|
Chris@16
|
210 typename Geometry,
|
Chris@16
|
211 typename Tag = typename tag<Geometry>::type
|
Chris@16
|
212 >
|
Chris@16
|
213 struct simplify_insert: not_implemented<Tag>
|
Chris@16
|
214 {};
|
Chris@16
|
215
|
Chris@16
|
216
|
Chris@16
|
217 template <typename Linestring>
|
Chris@16
|
218 struct simplify_insert<Linestring, linestring_tag>
|
Chris@16
|
219 : detail::simplify::simplify_range_insert
|
Chris@16
|
220 {};
|
Chris@16
|
221
|
Chris@16
|
222 template <typename Ring>
|
Chris@16
|
223 struct simplify_insert<Ring, ring_tag>
|
Chris@16
|
224 : detail::simplify::simplify_range_insert
|
Chris@16
|
225 {};
|
Chris@16
|
226
|
Chris@16
|
227
|
Chris@16
|
228 } // namespace dispatch
|
Chris@16
|
229 #endif // DOXYGEN_NO_DISPATCH
|
Chris@16
|
230
|
Chris@16
|
231
|
Chris@16
|
232 /*!
|
Chris@16
|
233 \brief Simplify a geometry using a specified strategy
|
Chris@16
|
234 \ingroup simplify
|
Chris@16
|
235 \tparam Geometry \tparam_geometry
|
Chris@16
|
236 \tparam Distance A numerical distance measure
|
Chris@16
|
237 \tparam Strategy A type fulfilling a SimplifyStrategy concept
|
Chris@16
|
238 \param strategy A strategy to calculate simplification
|
Chris@16
|
239 \param geometry input geometry, to be simplified
|
Chris@16
|
240 \param out output geometry, simplified version of the input geometry
|
Chris@16
|
241 \param max_distance distance (in units of input coordinates) of a vertex
|
Chris@16
|
242 to other segments to be removed
|
Chris@16
|
243 \param strategy simplify strategy to be used for simplification, might
|
Chris@16
|
244 include point-distance strategy
|
Chris@16
|
245
|
Chris@16
|
246 \image html svg_simplify_country.png "The image below presents the simplified country"
|
Chris@16
|
247 \qbk{distinguish,with strategy}
|
Chris@16
|
248 */
|
Chris@16
|
249 template<typename Geometry, typename Distance, typename Strategy>
|
Chris@16
|
250 inline void simplify(Geometry const& geometry, Geometry& out,
|
Chris@16
|
251 Distance const& max_distance, Strategy const& strategy)
|
Chris@16
|
252 {
|
Chris@16
|
253 concept::check<Geometry>();
|
Chris@16
|
254
|
Chris@16
|
255 BOOST_CONCEPT_ASSERT(
|
Chris@16
|
256 (concept::SimplifyStrategy<Strategy, typename point_type<Geometry>::type>)
|
Chris@16
|
257 );
|
Chris@16
|
258
|
Chris@16
|
259 geometry::clear(out);
|
Chris@16
|
260
|
Chris@16
|
261 dispatch::simplify<Geometry>::apply(geometry, out, max_distance, strategy);
|
Chris@16
|
262 }
|
Chris@16
|
263
|
Chris@16
|
264
|
Chris@16
|
265
|
Chris@16
|
266
|
Chris@16
|
267 /*!
|
Chris@16
|
268 \brief Simplify a geometry
|
Chris@16
|
269 \ingroup simplify
|
Chris@16
|
270 \tparam Geometry \tparam_geometry
|
Chris@16
|
271 \tparam Distance \tparam_numeric
|
Chris@16
|
272 \note This version of simplify simplifies a geometry using the default
|
Chris@16
|
273 strategy (Douglas Peucker),
|
Chris@16
|
274 \param geometry input geometry, to be simplified
|
Chris@16
|
275 \param out output geometry, simplified version of the input geometry
|
Chris@16
|
276 \param max_distance distance (in units of input coordinates) of a vertex
|
Chris@16
|
277 to other segments to be removed
|
Chris@16
|
278
|
Chris@16
|
279 \qbk{[include reference/algorithms/simplify.qbk]}
|
Chris@16
|
280 */
|
Chris@16
|
281 template<typename Geometry, typename Distance>
|
Chris@16
|
282 inline void simplify(Geometry const& geometry, Geometry& out,
|
Chris@16
|
283 Distance const& max_distance)
|
Chris@16
|
284 {
|
Chris@16
|
285 concept::check<Geometry>();
|
Chris@16
|
286
|
Chris@16
|
287 typedef typename point_type<Geometry>::type point_type;
|
Chris@16
|
288 typedef typename strategy::distance::services::default_strategy
|
Chris@16
|
289 <
|
Chris@16
|
290 segment_tag, point_type
|
Chris@16
|
291 >::type ds_strategy_type;
|
Chris@16
|
292
|
Chris@16
|
293 typedef strategy::simplify::douglas_peucker
|
Chris@16
|
294 <
|
Chris@16
|
295 point_type, ds_strategy_type
|
Chris@16
|
296 > strategy_type;
|
Chris@16
|
297
|
Chris@16
|
298 simplify(geometry, out, max_distance, strategy_type());
|
Chris@16
|
299 }
|
Chris@16
|
300
|
Chris@16
|
301
|
Chris@16
|
302 #ifndef DOXYGEN_NO_DETAIL
|
Chris@16
|
303 namespace detail { namespace simplify
|
Chris@16
|
304 {
|
Chris@16
|
305
|
Chris@16
|
306
|
Chris@16
|
307 /*!
|
Chris@16
|
308 \brief Simplify a geometry, using an output iterator
|
Chris@16
|
309 and a specified strategy
|
Chris@16
|
310 \ingroup simplify
|
Chris@16
|
311 \tparam Geometry \tparam_geometry
|
Chris@16
|
312 \param geometry input geometry, to be simplified
|
Chris@16
|
313 \param out output iterator, outputs all simplified points
|
Chris@16
|
314 \param max_distance distance (in units of input coordinates) of a vertex
|
Chris@16
|
315 to other segments to be removed
|
Chris@16
|
316 \param strategy simplify strategy to be used for simplification,
|
Chris@16
|
317 might include point-distance strategy
|
Chris@16
|
318
|
Chris@16
|
319 \qbk{distinguish,with strategy}
|
Chris@16
|
320 \qbk{[include reference/algorithms/simplify.qbk]}
|
Chris@16
|
321 */
|
Chris@16
|
322 template<typename Geometry, typename OutputIterator, typename Distance, typename Strategy>
|
Chris@16
|
323 inline void simplify_insert(Geometry const& geometry, OutputIterator out,
|
Chris@16
|
324 Distance const& max_distance, Strategy const& strategy)
|
Chris@16
|
325 {
|
Chris@16
|
326 concept::check<Geometry const>();
|
Chris@16
|
327 BOOST_CONCEPT_ASSERT(
|
Chris@16
|
328 (concept::SimplifyStrategy<Strategy, typename point_type<Geometry>::type>)
|
Chris@16
|
329 );
|
Chris@16
|
330
|
Chris@16
|
331 dispatch::simplify_insert<Geometry>::apply(geometry, out, max_distance, strategy);
|
Chris@16
|
332 }
|
Chris@16
|
333
|
Chris@16
|
334 /*!
|
Chris@16
|
335 \brief Simplify a geometry, using an output iterator
|
Chris@16
|
336 \ingroup simplify
|
Chris@16
|
337 \tparam Geometry \tparam_geometry
|
Chris@16
|
338 \param geometry input geometry, to be simplified
|
Chris@16
|
339 \param out output iterator, outputs all simplified points
|
Chris@16
|
340 \param max_distance distance (in units of input coordinates) of a vertex
|
Chris@16
|
341 to other segments to be removed
|
Chris@16
|
342
|
Chris@16
|
343 \qbk{[include reference/algorithms/simplify_insert.qbk]}
|
Chris@16
|
344 */
|
Chris@16
|
345 template<typename Geometry, typename OutputIterator, typename Distance>
|
Chris@16
|
346 inline void simplify_insert(Geometry const& geometry, OutputIterator out,
|
Chris@16
|
347 Distance const& max_distance)
|
Chris@16
|
348 {
|
Chris@16
|
349 typedef typename point_type<Geometry>::type point_type;
|
Chris@16
|
350
|
Chris@16
|
351 // Concept: output point type = point type of input geometry
|
Chris@16
|
352 concept::check<Geometry const>();
|
Chris@16
|
353 concept::check<point_type>();
|
Chris@16
|
354
|
Chris@16
|
355 typedef typename strategy::distance::services::default_strategy
|
Chris@16
|
356 <
|
Chris@16
|
357 segment_tag, point_type
|
Chris@16
|
358 >::type ds_strategy_type;
|
Chris@16
|
359
|
Chris@16
|
360 typedef strategy::simplify::douglas_peucker
|
Chris@16
|
361 <
|
Chris@16
|
362 point_type, ds_strategy_type
|
Chris@16
|
363 > strategy_type;
|
Chris@16
|
364
|
Chris@16
|
365 dispatch::simplify_insert<Geometry>::apply(geometry, out, max_distance, strategy_type());
|
Chris@16
|
366 }
|
Chris@16
|
367
|
Chris@16
|
368 }} // namespace detail::simplify
|
Chris@16
|
369 #endif // DOXYGEN_NO_DETAIL
|
Chris@16
|
370
|
Chris@16
|
371
|
Chris@16
|
372
|
Chris@16
|
373 }} // namespace boost::geometry
|
Chris@16
|
374
|
Chris@16
|
375 #endif // BOOST_GEOMETRY_ALGORITHMS_SIMPLIFY_HPP
|