]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // Boost.Geometry (aka GGL, Generic Geometry Library) |
2 | ||
3 | // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. | |
4 | // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. | |
5 | // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. | |
6 | // Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland. | |
7 | ||
b32b8144 FG |
8 | // This file was modified by Oracle on 2017. |
9 | // Modifications copyright (c) 2017 Oracle and/or its affiliates. | |
10 | // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle | |
11 | ||
7c673cae FG |
12 | // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library |
13 | // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. | |
14 | ||
15 | // Use, modification and distribution is subject to the Boost Software License, | |
16 | // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at | |
17 | // http://www.boost.org/LICENSE_1_0.txt) | |
18 | ||
19 | #ifndef BOOST_GEOMETRY_ALGORITHMS_CORRECT_HPP | |
20 | #define BOOST_GEOMETRY_ALGORITHMS_CORRECT_HPP | |
21 | ||
22 | ||
23 | #include <algorithm> | |
24 | #include <cstddef> | |
25 | #include <functional> | |
26 | ||
27 | #include <boost/mpl/assert.hpp> | |
28 | #include <boost/range.hpp> | |
29 | #include <boost/type_traits/remove_reference.hpp> | |
30 | ||
31 | #include <boost/variant/apply_visitor.hpp> | |
32 | #include <boost/variant/static_visitor.hpp> | |
33 | #include <boost/variant/variant_fwd.hpp> | |
34 | ||
b32b8144 | 35 | #include <boost/geometry/algorithms/correct_closure.hpp> |
7c673cae FG |
36 | #include <boost/geometry/algorithms/detail/interior_iterator.hpp> |
37 | ||
38 | #include <boost/geometry/core/closure.hpp> | |
39 | #include <boost/geometry/core/cs.hpp> | |
40 | #include <boost/geometry/core/exterior_ring.hpp> | |
41 | #include <boost/geometry/core/interior_rings.hpp> | |
42 | #include <boost/geometry/core/mutable_range.hpp> | |
43 | #include <boost/geometry/core/ring_type.hpp> | |
44 | #include <boost/geometry/core/tags.hpp> | |
45 | ||
46 | #include <boost/geometry/geometries/concepts/check.hpp> | |
47 | ||
48 | #include <boost/geometry/algorithms/area.hpp> | |
7c673cae FG |
49 | #include <boost/geometry/algorithms/detail/multi_modify.hpp> |
50 | #include <boost/geometry/util/order_as_direction.hpp> | |
51 | ||
52 | namespace boost { namespace geometry | |
53 | { | |
54 | ||
55 | // Silence warning C4127: conditional expression is constant | |
56 | #if defined(_MSC_VER) | |
57 | #pragma warning(push) | |
58 | #pragma warning(disable : 4127) | |
59 | #endif | |
60 | ||
61 | #ifndef DOXYGEN_NO_DETAIL | |
62 | namespace detail { namespace correct | |
63 | { | |
64 | ||
65 | template <typename Geometry> | |
66 | struct correct_nop | |
67 | { | |
b32b8144 FG |
68 | template <typename Strategy> |
69 | static inline void apply(Geometry& , Strategy const& ) | |
7c673cae FG |
70 | {} |
71 | }; | |
72 | ||
73 | ||
74 | template <typename Box, std::size_t Dimension, std::size_t DimensionCount> | |
75 | struct correct_box_loop | |
76 | { | |
77 | typedef typename coordinate_type<Box>::type coordinate_type; | |
78 | ||
79 | static inline void apply(Box& box) | |
80 | { | |
81 | if (get<min_corner, Dimension>(box) > get<max_corner, Dimension>(box)) | |
82 | { | |
83 | // Swap the coordinates | |
84 | coordinate_type max_value = get<min_corner, Dimension>(box); | |
85 | coordinate_type min_value = get<max_corner, Dimension>(box); | |
86 | set<min_corner, Dimension>(box, min_value); | |
87 | set<max_corner, Dimension>(box, max_value); | |
88 | } | |
89 | ||
90 | correct_box_loop | |
91 | < | |
92 | Box, Dimension + 1, DimensionCount | |
93 | >::apply(box); | |
94 | } | |
95 | }; | |
96 | ||
97 | ||
98 | ||
99 | template <typename Box, std::size_t DimensionCount> | |
100 | struct correct_box_loop<Box, DimensionCount, DimensionCount> | |
101 | { | |
102 | static inline void apply(Box& ) | |
103 | {} | |
104 | ||
105 | }; | |
106 | ||
107 | ||
108 | // Correct a box: make min/max correct | |
109 | template <typename Box> | |
110 | struct correct_box | |
111 | { | |
b32b8144 FG |
112 | template <typename Strategy> |
113 | static inline void apply(Box& box, Strategy const& ) | |
7c673cae FG |
114 | { |
115 | // Currently only for Cartesian coordinates | |
116 | // (or spherical without crossing dateline) | |
117 | // Future version: adapt using strategies | |
118 | correct_box_loop | |
119 | < | |
120 | Box, 0, dimension<Box>::type::value | |
121 | >::apply(box); | |
122 | } | |
123 | }; | |
124 | ||
125 | ||
126 | // Close a ring, if not closed | |
b32b8144 | 127 | template <typename Ring, template <typename> class Predicate> |
7c673cae FG |
128 | struct correct_ring |
129 | { | |
130 | typedef typename point_type<Ring>::type point_type; | |
131 | typedef typename coordinate_type<Ring>::type coordinate_type; | |
132 | ||
7c673cae FG |
133 | typedef detail::area::ring_area |
134 | < | |
135 | order_as_direction<geometry::point_order<Ring>::value>::value, | |
136 | geometry::closure<Ring>::value | |
137 | > ring_area_type; | |
138 | ||
139 | ||
b32b8144 FG |
140 | template <typename Strategy> |
141 | static inline void apply(Ring& r, Strategy const& strategy) | |
7c673cae | 142 | { |
b32b8144 FG |
143 | // Correct closure if necessary |
144 | detail::correct_closure::close_or_open_ring<Ring>::apply(r); | |
145 | ||
7c673cae | 146 | // Check area |
b32b8144 FG |
147 | typedef typename Strategy::return_type area_result_type; |
148 | Predicate<area_result_type> predicate; | |
149 | area_result_type const zero = 0; | |
150 | if (predicate(ring_area_type::apply(r, strategy), zero)) | |
7c673cae FG |
151 | { |
152 | std::reverse(boost::begin(r), boost::end(r)); | |
153 | } | |
154 | } | |
155 | }; | |
156 | ||
157 | // Correct a polygon: normalizes all rings, sets outer ring clockwise, sets all | |
158 | // inner rings counter clockwise (or vice versa depending on orientation) | |
159 | template <typename Polygon> | |
160 | struct correct_polygon | |
161 | { | |
162 | typedef typename ring_type<Polygon>::type ring_type; | |
b32b8144 FG |
163 | |
164 | template <typename Strategy> | |
165 | static inline void apply(Polygon& poly, Strategy const& strategy) | |
7c673cae FG |
166 | { |
167 | correct_ring | |
168 | < | |
169 | ring_type, | |
b32b8144 FG |
170 | std::less |
171 | >::apply(exterior_ring(poly), strategy); | |
7c673cae FG |
172 | |
173 | typename interior_return_type<Polygon>::type | |
174 | rings = interior_rings(poly); | |
175 | for (typename detail::interior_iterator<Polygon>::type | |
176 | it = boost::begin(rings); it != boost::end(rings); ++it) | |
177 | { | |
178 | correct_ring | |
179 | < | |
180 | ring_type, | |
b32b8144 FG |
181 | std::greater |
182 | >::apply(*it, strategy); | |
7c673cae FG |
183 | } |
184 | } | |
185 | }; | |
186 | ||
187 | ||
188 | }} // namespace detail::correct | |
189 | #endif // DOXYGEN_NO_DETAIL | |
190 | ||
191 | ||
192 | #ifndef DOXYGEN_NO_DISPATCH | |
193 | namespace dispatch | |
194 | { | |
195 | ||
196 | template <typename Geometry, typename Tag = typename tag<Geometry>::type> | |
197 | struct correct: not_implemented<Tag> | |
198 | {}; | |
199 | ||
200 | template <typename Point> | |
201 | struct correct<Point, point_tag> | |
202 | : detail::correct::correct_nop<Point> | |
203 | {}; | |
204 | ||
205 | template <typename LineString> | |
206 | struct correct<LineString, linestring_tag> | |
207 | : detail::correct::correct_nop<LineString> | |
208 | {}; | |
209 | ||
210 | template <typename Segment> | |
211 | struct correct<Segment, segment_tag> | |
212 | : detail::correct::correct_nop<Segment> | |
213 | {}; | |
214 | ||
215 | ||
216 | template <typename Box> | |
217 | struct correct<Box, box_tag> | |
218 | : detail::correct::correct_box<Box> | |
219 | {}; | |
220 | ||
221 | template <typename Ring> | |
222 | struct correct<Ring, ring_tag> | |
223 | : detail::correct::correct_ring | |
224 | < | |
225 | Ring, | |
b32b8144 | 226 | std::less |
7c673cae FG |
227 | > |
228 | {}; | |
229 | ||
230 | template <typename Polygon> | |
231 | struct correct<Polygon, polygon_tag> | |
232 | : detail::correct::correct_polygon<Polygon> | |
233 | {}; | |
234 | ||
235 | ||
236 | template <typename MultiPoint> | |
237 | struct correct<MultiPoint, multi_point_tag> | |
238 | : detail::correct::correct_nop<MultiPoint> | |
239 | {}; | |
240 | ||
241 | ||
242 | template <typename MultiLineString> | |
243 | struct correct<MultiLineString, multi_linestring_tag> | |
244 | : detail::correct::correct_nop<MultiLineString> | |
245 | {}; | |
246 | ||
247 | ||
248 | template <typename Geometry> | |
249 | struct correct<Geometry, multi_polygon_tag> | |
250 | : detail::multi_modify | |
251 | < | |
252 | Geometry, | |
253 | detail::correct::correct_polygon | |
254 | < | |
255 | typename boost::range_value<Geometry>::type | |
256 | > | |
257 | > | |
258 | {}; | |
259 | ||
260 | ||
261 | } // namespace dispatch | |
262 | #endif // DOXYGEN_NO_DISPATCH | |
263 | ||
264 | ||
265 | namespace resolve_variant { | |
266 | ||
267 | template <typename Geometry> | |
268 | struct correct | |
269 | { | |
b32b8144 FG |
270 | template <typename Strategy> |
271 | static inline void apply(Geometry& geometry, Strategy const& strategy) | |
7c673cae FG |
272 | { |
273 | concepts::check<Geometry const>(); | |
b32b8144 | 274 | dispatch::correct<Geometry>::apply(geometry, strategy); |
7c673cae FG |
275 | } |
276 | }; | |
277 | ||
278 | template <BOOST_VARIANT_ENUM_PARAMS(typename T)> | |
279 | struct correct<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > | |
280 | { | |
b32b8144 | 281 | template <typename Strategy> |
7c673cae FG |
282 | struct visitor: boost::static_visitor<void> |
283 | { | |
b32b8144 FG |
284 | Strategy const& m_strategy; |
285 | ||
286 | visitor(Strategy const& strategy): m_strategy(strategy) {} | |
287 | ||
7c673cae FG |
288 | template <typename Geometry> |
289 | void operator()(Geometry& geometry) const | |
290 | { | |
b32b8144 | 291 | correct<Geometry>::apply(geometry, m_strategy); |
7c673cae FG |
292 | } |
293 | }; | |
294 | ||
b32b8144 | 295 | template <typename Strategy> |
7c673cae | 296 | static inline void |
b32b8144 | 297 | apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry, Strategy const& strategy) |
7c673cae | 298 | { |
b32b8144 | 299 | boost::apply_visitor(visitor<Strategy>(strategy), geometry); |
7c673cae FG |
300 | } |
301 | }; | |
302 | ||
303 | } // namespace resolve_variant | |
304 | ||
305 | ||
306 | /*! | |
307 | \brief Corrects a geometry | |
308 | \details Corrects a geometry: all rings which are wrongly oriented with respect | |
309 | to their expected orientation are reversed. To all rings which do not have a | |
310 | closing point and are typed as they should have one, the first point is | |
311 | appended. Also boxes can be corrected. | |
312 | \ingroup correct | |
313 | \tparam Geometry \tparam_geometry | |
314 | \param geometry \param_geometry which will be corrected if necessary | |
315 | ||
316 | \qbk{[include reference/algorithms/correct.qbk]} | |
317 | */ | |
318 | template <typename Geometry> | |
319 | inline void correct(Geometry& geometry) | |
320 | { | |
b32b8144 FG |
321 | typedef typename point_type<Geometry>::type point_type; |
322 | ||
323 | typedef typename strategy::area::services::default_strategy | |
324 | < | |
325 | typename cs_tag<point_type>::type, | |
326 | point_type | |
327 | >::type strategy_type; | |
328 | ||
329 | resolve_variant::correct<Geometry>::apply(geometry, strategy_type()); | |
330 | } | |
331 | ||
332 | /*! | |
333 | \brief Corrects a geometry | |
334 | \details Corrects a geometry: all rings which are wrongly oriented with respect | |
335 | to their expected orientation are reversed. To all rings which do not have a | |
336 | closing point and are typed as they should have one, the first point is | |
337 | appended. Also boxes can be corrected. | |
338 | \ingroup correct | |
339 | \tparam Geometry \tparam_geometry | |
340 | \tparam Strategy \tparam_strategy{Area} | |
341 | \param geometry \param_geometry which will be corrected if necessary | |
342 | \param strategy \param_strategy{area} | |
343 | ||
344 | \qbk{distinguish,with strategy} | |
345 | ||
346 | \qbk{[include reference/algorithms/correct.qbk]} | |
347 | */ | |
348 | template <typename Geometry, typename Strategy> | |
349 | inline void correct(Geometry& geometry, Strategy const& strategy) | |
350 | { | |
351 | resolve_variant::correct<Geometry>::apply(geometry, strategy); | |
7c673cae FG |
352 | } |
353 | ||
354 | #if defined(_MSC_VER) | |
355 | #pragma warning(pop) | |
356 | #endif | |
357 | ||
358 | }} // namespace boost::geometry | |
359 | ||
360 | ||
361 | #endif // BOOST_GEOMETRY_ALGORITHMS_CORRECT_HPP |