Chris@102
|
1 // Boost.Geometry (aka GGL, Generic Geometry Library)
|
Chris@102
|
2
|
Chris@102
|
3 // Copyright (c) 2007-2013 Barend Gehrels, Amsterdam, the Netherlands.
|
Chris@102
|
4 // Copyright (c) 2008-2013 Bruno Lalande, Paris, France.
|
Chris@102
|
5 // Copyright (c) 2009-2013 Mateusz Loskot, London, UK.
|
Chris@102
|
6 // Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
|
Chris@102
|
7
|
Chris@102
|
8 // Use, modification and distribution is subject to the Boost Software License,
|
Chris@102
|
9 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
Chris@102
|
10 // http://www.boost.org/LICENSE_1_0.txt)
|
Chris@102
|
11
|
Chris@102
|
12 #ifndef BOOST_GEOMETRY_ALGORITHMS_REMOVE_SPIKES_HPP
|
Chris@102
|
13 #define BOOST_GEOMETRY_ALGORITHMS_REMOVE_SPIKES_HPP
|
Chris@102
|
14
|
Chris@102
|
15 #include <deque>
|
Chris@102
|
16
|
Chris@102
|
17 #include <boost/range.hpp>
|
Chris@102
|
18 #include <boost/type_traits/remove_reference.hpp>
|
Chris@102
|
19
|
Chris@102
|
20 #include <boost/variant/apply_visitor.hpp>
|
Chris@102
|
21 #include <boost/variant/static_visitor.hpp>
|
Chris@102
|
22 #include <boost/variant/variant_fwd.hpp>
|
Chris@102
|
23
|
Chris@102
|
24 #include <boost/geometry/core/closure.hpp>
|
Chris@102
|
25 #include <boost/geometry/core/coordinate_type.hpp>
|
Chris@102
|
26 #include <boost/geometry/core/cs.hpp>
|
Chris@102
|
27 #include <boost/geometry/core/interior_rings.hpp>
|
Chris@102
|
28 #include <boost/geometry/core/point_order.hpp>
|
Chris@102
|
29 #include <boost/geometry/core/tags.hpp>
|
Chris@102
|
30
|
Chris@102
|
31 #include <boost/geometry/geometries/concepts/check.hpp>
|
Chris@102
|
32
|
Chris@102
|
33 #include <boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp>
|
Chris@102
|
34 #include <boost/geometry/algorithms/detail/interior_iterator.hpp>
|
Chris@102
|
35 #include <boost/geometry/algorithms/clear.hpp>
|
Chris@102
|
36
|
Chris@102
|
37 #include <boost/geometry/util/condition.hpp>
|
Chris@102
|
38
|
Chris@102
|
39
|
Chris@102
|
40 /*
|
Chris@102
|
41 Remove spikes from a ring/polygon.
|
Chris@102
|
42 Ring (having 8 vertices, including closing vertex)
|
Chris@102
|
43 +------+
|
Chris@102
|
44 | |
|
Chris@102
|
45 | +--+
|
Chris@102
|
46 | | ^this "spike" is removed, can be located outside/inside the ring
|
Chris@102
|
47 +------+
|
Chris@102
|
48 (the actualy determination if it is removed is done by a strategy)
|
Chris@102
|
49
|
Chris@102
|
50 */
|
Chris@102
|
51
|
Chris@102
|
52
|
Chris@102
|
53 namespace boost { namespace geometry
|
Chris@102
|
54 {
|
Chris@102
|
55
|
Chris@102
|
56
|
Chris@102
|
57 #ifndef DOXYGEN_NO_DETAIL
|
Chris@102
|
58 namespace detail { namespace remove_spikes
|
Chris@102
|
59 {
|
Chris@102
|
60
|
Chris@102
|
61
|
Chris@102
|
62 template <typename Range>
|
Chris@102
|
63 struct range_remove_spikes
|
Chris@102
|
64 {
|
Chris@102
|
65 typedef typename strategy::side::services::default_strategy
|
Chris@102
|
66 <
|
Chris@102
|
67 typename cs_tag<Range>::type
|
Chris@102
|
68 >::type side_strategy;
|
Chris@102
|
69
|
Chris@102
|
70 typedef typename coordinate_type<Range>::type coordinate_type;
|
Chris@102
|
71 typedef typename point_type<Range>::type point_type;
|
Chris@102
|
72
|
Chris@102
|
73
|
Chris@102
|
74 static inline void apply(Range& range)
|
Chris@102
|
75 {
|
Chris@102
|
76 std::size_t n = boost::size(range);
|
Chris@102
|
77 std::size_t const min_num_points = core_detail::closure::minimum_ring_size
|
Chris@102
|
78 <
|
Chris@102
|
79 geometry::closure<Range>::value
|
Chris@102
|
80 >::value - 1; // subtract one: a polygon with only one spike should result into one point
|
Chris@102
|
81 if (n < min_num_points)
|
Chris@102
|
82 {
|
Chris@102
|
83 return;
|
Chris@102
|
84 }
|
Chris@102
|
85
|
Chris@102
|
86 std::deque<point_type> cleaned;
|
Chris@102
|
87 for (typename boost::range_iterator<Range const>::type it = boost::begin(range);
|
Chris@102
|
88 it != boost::end(range); ++it)
|
Chris@102
|
89 {
|
Chris@102
|
90 // Add point
|
Chris@102
|
91 cleaned.push_back(*it);
|
Chris@102
|
92
|
Chris@102
|
93 while(cleaned.size() >= 3
|
Chris@102
|
94 && detail::point_is_spike_or_equal(cleaned.back(), *(cleaned.end() - 3), *(cleaned.end() - 2)))
|
Chris@102
|
95 {
|
Chris@102
|
96 // Remove pen-ultimate point causing the spike (or which was equal)
|
Chris@102
|
97 cleaned.erase(cleaned.end() - 2);
|
Chris@102
|
98 }
|
Chris@102
|
99 }
|
Chris@102
|
100
|
Chris@102
|
101 // For a closed-polygon, remove closing point, this makes checking first point(s) easier and consistent
|
Chris@102
|
102 if ( BOOST_GEOMETRY_CONDITION(geometry::closure<Range>::value == geometry::closed) )
|
Chris@102
|
103 {
|
Chris@102
|
104 cleaned.pop_back();
|
Chris@102
|
105 }
|
Chris@102
|
106
|
Chris@102
|
107 bool found = false;
|
Chris@102
|
108 do
|
Chris@102
|
109 {
|
Chris@102
|
110 found = false;
|
Chris@102
|
111 // Check for spike in first point
|
Chris@102
|
112 int const penultimate = 2;
|
Chris@102
|
113 while(cleaned.size() >= 3 && detail::point_is_spike_or_equal(cleaned.front(), *(cleaned.end() - penultimate), cleaned.back()))
|
Chris@102
|
114 {
|
Chris@102
|
115 cleaned.pop_back();
|
Chris@102
|
116 found = true;
|
Chris@102
|
117 }
|
Chris@102
|
118 // Check for spike in second point
|
Chris@102
|
119 while(cleaned.size() >= 3 && detail::point_is_spike_or_equal(*(cleaned.begin() + 1), cleaned.back(), cleaned.front()))
|
Chris@102
|
120 {
|
Chris@102
|
121 cleaned.pop_front();
|
Chris@102
|
122 found = true;
|
Chris@102
|
123 }
|
Chris@102
|
124 }
|
Chris@102
|
125 while (found);
|
Chris@102
|
126
|
Chris@102
|
127 if (cleaned.size() == 2)
|
Chris@102
|
128 {
|
Chris@102
|
129 // Ticket #9871: open polygon with only two points.
|
Chris@102
|
130 // the second point forms, by definition, a spike
|
Chris@102
|
131 cleaned.pop_back();
|
Chris@102
|
132 }
|
Chris@102
|
133
|
Chris@102
|
134 // Close if necessary
|
Chris@102
|
135 if ( BOOST_GEOMETRY_CONDITION(geometry::closure<Range>::value == geometry::closed) )
|
Chris@102
|
136 {
|
Chris@102
|
137 cleaned.push_back(cleaned.front());
|
Chris@102
|
138 }
|
Chris@102
|
139
|
Chris@102
|
140 // Copy output
|
Chris@102
|
141 geometry::clear(range);
|
Chris@102
|
142 std::copy(cleaned.begin(), cleaned.end(), std::back_inserter(range));
|
Chris@102
|
143 }
|
Chris@102
|
144 };
|
Chris@102
|
145
|
Chris@102
|
146
|
Chris@102
|
147 template <typename Polygon>
|
Chris@102
|
148 struct polygon_remove_spikes
|
Chris@102
|
149 {
|
Chris@102
|
150 static inline void apply(Polygon& polygon)
|
Chris@102
|
151 {
|
Chris@102
|
152 typedef typename geometry::ring_type<Polygon>::type ring_type;
|
Chris@102
|
153
|
Chris@102
|
154 typedef range_remove_spikes<ring_type> per_range;
|
Chris@102
|
155 per_range::apply(exterior_ring(polygon));
|
Chris@102
|
156
|
Chris@102
|
157 typename interior_return_type<Polygon>::type
|
Chris@102
|
158 rings = interior_rings(polygon);
|
Chris@102
|
159
|
Chris@102
|
160 for (typename detail::interior_iterator<Polygon>::type
|
Chris@102
|
161 it = boost::begin(rings); it != boost::end(rings); ++it)
|
Chris@102
|
162 {
|
Chris@102
|
163 per_range::apply(*it);
|
Chris@102
|
164 }
|
Chris@102
|
165 }
|
Chris@102
|
166 };
|
Chris@102
|
167
|
Chris@102
|
168
|
Chris@102
|
169 template <typename MultiGeometry, typename SingleVersion>
|
Chris@102
|
170 struct multi_remove_spikes
|
Chris@102
|
171 {
|
Chris@102
|
172 static inline void apply(MultiGeometry& multi)
|
Chris@102
|
173 {
|
Chris@102
|
174 for (typename boost::range_iterator<MultiGeometry>::type
|
Chris@102
|
175 it = boost::begin(multi);
|
Chris@102
|
176 it != boost::end(multi);
|
Chris@102
|
177 ++it)
|
Chris@102
|
178 {
|
Chris@102
|
179 SingleVersion::apply(*it);
|
Chris@102
|
180 }
|
Chris@102
|
181 }
|
Chris@102
|
182 };
|
Chris@102
|
183
|
Chris@102
|
184
|
Chris@102
|
185 }} // namespace detail::remove_spikes
|
Chris@102
|
186 #endif // DOXYGEN_NO_DETAIL
|
Chris@102
|
187
|
Chris@102
|
188
|
Chris@102
|
189
|
Chris@102
|
190 #ifndef DOXYGEN_NO_DISPATCH
|
Chris@102
|
191 namespace dispatch
|
Chris@102
|
192 {
|
Chris@102
|
193
|
Chris@102
|
194
|
Chris@102
|
195 template
|
Chris@102
|
196 <
|
Chris@102
|
197 typename Geometry,
|
Chris@102
|
198 typename Tag = typename tag<Geometry>::type
|
Chris@102
|
199 >
|
Chris@102
|
200 struct remove_spikes
|
Chris@102
|
201 {
|
Chris@102
|
202 static inline void apply(Geometry&)
|
Chris@102
|
203 {}
|
Chris@102
|
204 };
|
Chris@102
|
205
|
Chris@102
|
206
|
Chris@102
|
207 template <typename Ring>
|
Chris@102
|
208 struct remove_spikes<Ring, ring_tag>
|
Chris@102
|
209 : detail::remove_spikes::range_remove_spikes<Ring>
|
Chris@102
|
210 {};
|
Chris@102
|
211
|
Chris@102
|
212
|
Chris@102
|
213
|
Chris@102
|
214 template <typename Polygon>
|
Chris@102
|
215 struct remove_spikes<Polygon, polygon_tag>
|
Chris@102
|
216 : detail::remove_spikes::polygon_remove_spikes<Polygon>
|
Chris@102
|
217 {};
|
Chris@102
|
218
|
Chris@102
|
219
|
Chris@102
|
220 template <typename MultiPolygon>
|
Chris@102
|
221 struct remove_spikes<MultiPolygon, multi_polygon_tag>
|
Chris@102
|
222 : detail::remove_spikes::multi_remove_spikes
|
Chris@102
|
223 <
|
Chris@102
|
224 MultiPolygon,
|
Chris@102
|
225 detail::remove_spikes::polygon_remove_spikes
|
Chris@102
|
226 <
|
Chris@102
|
227 typename boost::range_value<MultiPolygon>::type
|
Chris@102
|
228 >
|
Chris@102
|
229 >
|
Chris@102
|
230 {};
|
Chris@102
|
231
|
Chris@102
|
232
|
Chris@102
|
233 } // namespace dispatch
|
Chris@102
|
234 #endif
|
Chris@102
|
235
|
Chris@102
|
236
|
Chris@102
|
237 namespace resolve_variant {
|
Chris@102
|
238
|
Chris@102
|
239 template <typename Geometry>
|
Chris@102
|
240 struct remove_spikes
|
Chris@102
|
241 {
|
Chris@102
|
242 static void apply(Geometry& geometry)
|
Chris@102
|
243 {
|
Chris@102
|
244 concept::check<Geometry>();
|
Chris@102
|
245 dispatch::remove_spikes<Geometry>::apply(geometry);
|
Chris@102
|
246 }
|
Chris@102
|
247 };
|
Chris@102
|
248
|
Chris@102
|
249 template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
|
Chris@102
|
250 struct remove_spikes<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
|
Chris@102
|
251 {
|
Chris@102
|
252 struct visitor: boost::static_visitor<void>
|
Chris@102
|
253 {
|
Chris@102
|
254 template <typename Geometry>
|
Chris@102
|
255 void operator()(Geometry& geometry) const
|
Chris@102
|
256 {
|
Chris@102
|
257 remove_spikes<Geometry>::apply(geometry);
|
Chris@102
|
258 }
|
Chris@102
|
259 };
|
Chris@102
|
260
|
Chris@102
|
261 static inline void apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry)
|
Chris@102
|
262 {
|
Chris@102
|
263 boost::apply_visitor(visitor(), geometry);
|
Chris@102
|
264 }
|
Chris@102
|
265 };
|
Chris@102
|
266
|
Chris@102
|
267 } // namespace resolve_variant
|
Chris@102
|
268
|
Chris@102
|
269
|
Chris@102
|
270 /*!
|
Chris@102
|
271 \ingroup remove_spikes
|
Chris@102
|
272 \tparam Geometry geometry type
|
Chris@102
|
273 \param geometry the geometry to make remove_spikes
|
Chris@102
|
274 */
|
Chris@102
|
275 template <typename Geometry>
|
Chris@102
|
276 inline void remove_spikes(Geometry& geometry)
|
Chris@102
|
277 {
|
Chris@102
|
278 resolve_variant::remove_spikes<Geometry>::apply(geometry);
|
Chris@102
|
279 }
|
Chris@102
|
280
|
Chris@102
|
281
|
Chris@102
|
282 }} // namespace boost::geometry
|
Chris@102
|
283
|
Chris@102
|
284
|
Chris@102
|
285 #endif // BOOST_GEOMETRY_ALGORITHMS_REMOVE_SPIKES_HPP
|