]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/geometry/algorithms/detail/is_valid/ring.hpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / boost / geometry / algorithms / detail / is_valid / ring.hpp
1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2
3 // Copyright (c) 2014-2017, Oracle and/or its affiliates.
4
5 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
6 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
7
8 // Licensed under the Boost Software License version 1.0.
9 // http://www.boost.org/users/license.html
10
11 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_RING_HPP
12 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_RING_HPP
13
14 #include <deque>
15
16 #include <boost/core/ignore_unused.hpp>
17
18 #include <boost/geometry/core/closure.hpp>
19 #include <boost/geometry/core/cs.hpp>
20 #include <boost/geometry/core/point_order.hpp>
21
22 #include <boost/geometry/util/order_as_direction.hpp>
23 #include <boost/geometry/util/range.hpp>
24
25 #include <boost/geometry/algorithms/equals.hpp>
26
27 #include <boost/geometry/views/closeable_view.hpp>
28
29 #include <boost/geometry/algorithms/area.hpp>
30 #include <boost/geometry/algorithms/intersects.hpp>
31 #include <boost/geometry/algorithms/validity_failure_type.hpp>
32 #include <boost/geometry/algorithms/detail/num_distinct_consecutive_points.hpp>
33 #include <boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp>
34 #include <boost/geometry/algorithms/detail/is_valid/has_invalid_coordinate.hpp>
35 #include <boost/geometry/algorithms/detail/is_valid/has_spikes.hpp>
36 #include <boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp>
37
38 #include <boost/geometry/strategies/area.hpp>
39
40 #ifdef BOOST_GEOMETRY_TEST_DEBUG
41 #include <boost/geometry/io/dsv/write.hpp>
42 #endif
43
44 namespace boost { namespace geometry
45 {
46
47
48 #ifndef DOXYGEN_NO_DETAIL
49 namespace detail { namespace is_valid
50 {
51
52
53 // struct to check whether a ring is topologically closed
54 template <typename Ring, closure_selector Closure /* open */>
55 struct is_topologically_closed
56 {
57 template <typename VisitPolicy>
58 static inline bool apply(Ring const&, VisitPolicy& visitor)
59 {
60 boost::ignore_unused(visitor);
61
62 return visitor.template apply<no_failure>();
63 }
64 };
65
66 template <typename Ring>
67 struct is_topologically_closed<Ring, closed>
68 {
69 template <typename VisitPolicy>
70 static inline bool apply(Ring const& ring, VisitPolicy& visitor)
71 {
72 boost::ignore_unused(visitor);
73
74 if (geometry::equals(range::front(ring), range::back(ring)))
75 {
76 return visitor.template apply<no_failure>();
77 }
78 else
79 {
80 return visitor.template apply<failure_not_closed>();
81 }
82 }
83 };
84
85
86
87 template <typename ResultType, bool IsInteriorRing /* false */>
88 struct ring_area_predicate
89 {
90 typedef std::greater<ResultType> type;
91 };
92
93 template <typename ResultType>
94 struct ring_area_predicate<ResultType, true>
95 {
96 typedef std::less<ResultType> type;
97 };
98
99
100
101 template <typename Ring, bool IsInteriorRing>
102 struct is_properly_oriented
103 {
104 template <typename VisitPolicy, typename Strategy>
105 static inline bool apply(Ring const& ring, VisitPolicy& visitor,
106 Strategy const& strategy)
107 {
108 boost::ignore_unused(visitor);
109
110 typedef typename point_type<Ring>::type point_type;
111
112 typedef detail::area::ring_area
113 <
114 order_as_direction<geometry::point_order<Ring>::value>::value,
115 geometry::closure<Ring>::value
116 > ring_area_type;
117
118 typedef typename Strategy::template area_strategy
119 <
120 point_type
121 >::type::return_type area_result_type;
122
123 typename ring_area_predicate
124 <
125 area_result_type, IsInteriorRing
126 >::type predicate;
127
128 // Check area
129 area_result_type const zero = 0;
130 area_result_type const area
131 = ring_area_type::apply(ring,
132 strategy.template get_area_strategy<point_type>());
133 if (predicate(area, zero))
134 {
135 return visitor.template apply<no_failure>();
136 }
137 else
138 {
139 return visitor.template apply<failure_wrong_orientation>();
140 }
141 }
142 };
143
144
145
146 template
147 <
148 typename Ring,
149 bool CheckSelfIntersections = true,
150 bool IsInteriorRing = false
151 >
152 struct is_valid_ring
153 {
154 template <typename VisitPolicy, typename Strategy>
155 static inline bool apply(Ring const& ring, VisitPolicy& visitor,
156 Strategy const& strategy)
157 {
158 // return invalid if any of the following condition holds:
159 // (a) the ring's point coordinates are not invalid (e.g., NaN)
160 // (b) the ring's size is below the minimal one
161 // (c) the ring consists of at most two distinct points
162 // (d) the ring is not topologically closed
163 // (e) the ring has spikes
164 // (f) the ring has duplicate points (if AllowDuplicates is false)
165 // (g) the boundary of the ring has self-intersections
166 // (h) the order of the points is inconsistent with the defined order
167 //
168 // Note: no need to check if the area is zero. If this is the
169 // case, then the ring must have at least two spikes, which is
170 // checked by condition (d).
171
172 if (has_invalid_coordinate<Ring>::apply(ring, visitor))
173 {
174 return false;
175 }
176
177 closure_selector const closure = geometry::closure<Ring>::value;
178 typedef typename closeable_view<Ring const, closure>::type view_type;
179
180 if (boost::size(ring)
181 < core_detail::closure::minimum_ring_size<closure>::value)
182 {
183 return visitor.template apply<failure_few_points>();
184 }
185
186 view_type const view(ring);
187 if (detail::num_distinct_consecutive_points
188 <
189 view_type, 4u, true,
190 not_equal_to<typename point_type<Ring>::type>
191 >::apply(view)
192 < 4u)
193 {
194 return
195 visitor.template apply<failure_wrong_topological_dimension>();
196 }
197
198 return
199 is_topologically_closed<Ring, closure>::apply(ring, visitor)
200 && ! has_duplicates<Ring, closure>::apply(ring, visitor)
201 && ! has_spikes<Ring, closure>::apply(ring, visitor, strategy.get_side_strategy())
202 && (! CheckSelfIntersections
203 || has_valid_self_turns<Ring>::apply(ring, visitor, strategy))
204 && is_properly_oriented<Ring, IsInteriorRing>::apply(ring, visitor, strategy);
205 }
206 };
207
208
209 }} // namespace detail::is_valid
210 #endif // DOXYGEN_NO_DETAIL
211
212
213
214 #ifndef DOXYGEN_NO_DISPATCH
215 namespace dispatch
216 {
217
218 // A Ring is a Polygon with exterior boundary only.
219 // The Ring's boundary must be a LinearRing (see OGC 06-103-r4,
220 // 6.1.7.1, for the definition of LinearRing)
221 //
222 // Reference (for polygon validity): OGC 06-103r4 (6.1.11.1)
223 template <typename Ring, bool AllowEmptyMultiGeometries>
224 struct is_valid
225 <
226 Ring, ring_tag, AllowEmptyMultiGeometries
227 > : detail::is_valid::is_valid_ring<Ring>
228 {};
229
230
231 } // namespace dispatch
232 #endif // DOXYGEN_NO_DISPATCH
233
234
235 }} // namespace boost::geometry
236
237 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_RING_HPP