]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/geometry/test/algorithms/test_is_valid.hpp
bump version to 18.2.4-pve3
[ceph.git] / ceph / src / boost / libs / geometry / test / algorithms / test_is_valid.hpp
CommitLineData
7c673cae
FG
1// Boost.Geometry (aka GGL, Generic Geometry Library)
2// Unit Test
3
1e59de90 4// Copyright (c) 2014-2021, Oracle and/or its affiliates.
7c673cae 5
1e59de90 6// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
7c673cae 7// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
b32b8144 8// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
7c673cae
FG
9
10// Licensed under the Boost Software License version 1.0.
11// http://www.boost.org/users/license.html
12
13#ifndef BOOST_GEOMETRY_TEST_IS_VALID_HPP
14#define BOOST_GEOMETRY_TEST_IS_VALID_HPP
15
16#include <iostream>
17#include <sstream>
18#include <string>
19
20#include <boost/core/ignore_unused.hpp>
1e59de90
TL
21#include <boost/range/begin.hpp>
22#include <boost/range/end.hpp>
23#include <boost/range/size.hpp>
24#include <boost/range/value_type.hpp>
7c673cae
FG
25#include <boost/variant/variant.hpp>
26
27#include <boost/geometry/core/closure.hpp>
28#include <boost/geometry/core/exterior_ring.hpp>
29#include <boost/geometry/core/interior_rings.hpp>
30#include <boost/geometry/core/point_order.hpp>
31#include <boost/geometry/core/ring_type.hpp>
32#include <boost/geometry/core/tag.hpp>
33#include <boost/geometry/core/tags.hpp>
34
35#include <boost/geometry/geometries/point_xy.hpp>
36#include <boost/geometry/geometries/segment.hpp>
37#include <boost/geometry/geometries/box.hpp>
38#include <boost/geometry/geometries/linestring.hpp>
39#include <boost/geometry/geometries/ring.hpp>
40#include <boost/geometry/geometries/polygon.hpp>
41#include <boost/geometry/geometries/multi_point.hpp>
42#include <boost/geometry/geometries/multi_linestring.hpp>
43#include <boost/geometry/geometries/multi_polygon.hpp>
44
45#include <boost/geometry/strategies/strategies.hpp>
46
47#include <boost/geometry/io/wkt/wkt.hpp>
48
49#include <boost/geometry/algorithms/convert.hpp>
50#include <boost/geometry/algorithms/num_points.hpp>
51#include <boost/geometry/algorithms/is_valid.hpp>
52
7c673cae
FG
53#include <from_wkt.hpp>
54
55#ifdef BOOST_GEOMETRY_TEST_DEBUG
56#include "pretty_print_geometry.hpp"
57#endif
58
59
60namespace bg = ::boost::geometry;
61
62typedef bg::model::point<double, 2, bg::cs::cartesian> point_type;
63typedef bg::model::segment<point_type> segment_type;
64typedef bg::model::box<point_type> box_type;
65typedef bg::model::linestring<point_type> linestring_type;
66typedef bg::model::multi_linestring<linestring_type> multi_linestring_type;
67typedef bg::model::multi_point<point_type> multi_point_type;
68
69
70//----------------------------------------------------------------------------
71
72
73// returns true if a geometry can be converted to closed
74template
75<
76 typename Geometry,
77 typename Tag = typename bg::tag<Geometry>::type,
78 bg::closure_selector Closure = bg::closure<Geometry>::value
79>
80struct is_convertible_to_closed
81{
82 static inline bool apply(Geometry const&)
83 {
84 return false;
85 }
86};
87
88template <typename Ring>
89struct is_convertible_to_closed<Ring, bg::ring_tag, bg::open>
90{
91 static inline bool apply(Ring const& ring)
92 {
93 return boost::size(ring) > 0;
94 }
95};
96
97template <typename Polygon>
98struct is_convertible_to_closed<Polygon, bg::polygon_tag, bg::open>
99{
1e59de90 100 using ring_type = typename bg::ring_type<Polygon>::type;
7c673cae
FG
101
102 template <typename InteriorRings>
103 static inline
104 bool apply_to_interior_rings(InteriorRings const& interior_rings)
105 {
1e59de90
TL
106 return std::all_of(boost::begin(interior_rings),
107 boost::end(interior_rings),
108 []( auto const& ring ){
109 return is_convertible_to_closed<ring_type>::apply(ring);
110 });
7c673cae
FG
111 }
112
113 static inline bool apply(Polygon const& polygon)
114 {
115 return boost::size(bg::exterior_ring(polygon)) > 0
116 && apply_to_interior_rings(bg::interior_rings(polygon));
117 }
118};
119
120template <typename MultiPolygon>
121struct is_convertible_to_closed<MultiPolygon, bg::multi_polygon_tag, bg::open>
122{
1e59de90 123 using polygon_type = typename boost::range_value<MultiPolygon>::type;
7c673cae
FG
124
125 static inline bool apply(MultiPolygon const& multi_polygon)
126 {
1e59de90
TL
127 return !boost::empty(multi_polygon) && // do not allow empty multi-polygon
128 std::none_of(boost::begin(multi_polygon), boost::end(multi_polygon),
129 []( auto const& polygon ){
130 return ! is_convertible_to_closed<polygon_type>::apply(polygon);
131 });
7c673cae
FG
132 }
133};
134
135
136//----------------------------------------------------------------------------
137
138
139// returns true if a geometry can be converted to cw
140template
141<
142 typename Geometry,
143 typename Tag = typename bg::tag<Geometry>::type,
144 bg::order_selector Order = bg::point_order<Geometry>::value
145>
146struct is_convertible_to_cw
147{
148 static inline bool apply(Geometry const&)
149 {
150 return bg::point_order<Geometry>::value == bg::counterclockwise;
151 }
152};
153
154
155//----------------------------------------------------------------------------
156
157
158// returns true if geometry can be converted to polygon
159template
160<
161 typename Geometry,
162 typename Tag = typename bg::tag<Geometry>::type
163>
164struct is_convertible_to_polygon
165{
166 typedef Geometry type;
167 static bool const value = false;
168};
169
170template <typename Ring>
171struct is_convertible_to_polygon<Ring, bg::ring_tag>
172{
173 typedef bg::model::polygon
174 <
175 typename bg::point_type<Ring>::type,
176 bg::point_order<Ring>::value == bg::clockwise,
177 bg::closure<Ring>::value == bg::closed
178 > type;
179
180 static bool const value = true;
181};
182
183
184//----------------------------------------------------------------------------
185
186
187// returns true if geometry can be converted to multi-polygon
188template
189<
190 typename Geometry,
191 typename Tag = typename bg::tag<Geometry>::type
192>
193struct is_convertible_to_multipolygon
194{
195 typedef Geometry type;
196 static bool const value = false;
197};
198
199template <typename Ring>
200struct is_convertible_to_multipolygon<Ring, bg::ring_tag>
201{
202 typedef bg::model::multi_polygon
203 <
204 typename is_convertible_to_polygon<Ring>::type
205 > type;
206
207 static bool const value = true;
208};
209
210template <typename Polygon>
211struct is_convertible_to_multipolygon<Polygon, bg::polygon_tag>
212{
213 typedef bg::model::multi_polygon<Polygon> type;
214 static bool const value = true;
215};
216
217
218//----------------------------------------------------------------------------
219
220
221template <typename ValidityTester>
222struct validity_checker
223{
224 template <typename Geometry>
225 static inline bool apply(std::string const& case_id,
226 Geometry const& geometry,
227 bool expected_result,
228 std::string& reason)
229 {
230 bool valid = ValidityTester::apply(geometry);
231 std::string const reason_valid
232 = bg::validity_failure_type_message(bg::no_failure);
233 reason = ValidityTester::reason(geometry);
234 std::string reason_short = reason.substr(0, reason_valid.length());
235
236 BOOST_CHECK_MESSAGE(valid == expected_result,
237 "case id: " << case_id
238 << ", Expected: " << expected_result
239 << ", detected: " << valid
240 << "; wkt: " << bg::wkt(geometry));
241
242 BOOST_CHECK_MESSAGE(reason != "",
243 "case id (empty reason): " << case_id
244 << ", Expected: " << valid
245 << ", detected reason: " << reason
246 << "; wkt: " << bg::wkt(geometry));
247
248 BOOST_CHECK_MESSAGE((valid && reason == reason_valid)
249 ||
250 (! valid && reason != reason_valid)
251 ||
252 (! valid && reason_short != reason_valid),
253 "case id (reason): " << case_id
254 << ", Expected: " << valid
255 << ", detected reason: " << reason
256 << "; wkt: " << bg::wkt(geometry));
257
258 return valid;
259 }
260};
261
262
263//----------------------------------------------------------------------------
264
265
266struct default_validity_tester
267{
268 template <typename Geometry>
269 static inline bool apply(Geometry const& geometry)
270 {
271 return bg::is_valid(geometry);
272 }
273
274 template <typename Geometry>
275 static inline std::string reason(Geometry const& geometry)
276 {
277 std::string message;
278 bg::is_valid(geometry, message);
279 return message;
280 }
281};
282
283
284template <bool AllowSpikes>
285struct validity_tester_linear
286{
287 template <typename Geometry>
288 static inline bool apply(Geometry const& geometry)
289 {
290 bool const irrelevant = true;
291 bg::is_valid_default_policy<irrelevant, AllowSpikes> visitor;
b32b8144 292 return bg::is_valid(geometry, visitor, bg::default_strategy());
7c673cae
FG
293 }
294
295 template <typename Geometry>
296 static inline std::string reason(Geometry const& geometry)
297 {
298 bool const irrelevant = true;
299 std::ostringstream oss;
300 bg::failing_reason_policy<irrelevant, AllowSpikes> visitor(oss);
b32b8144 301 bg::is_valid(geometry, visitor, bg::default_strategy());
7c673cae
FG
302 return oss.str();
303 }
304};
305
306
307template <bool AllowDuplicates>
308struct validity_tester_areal
309{
310 template <typename Geometry>
311 static inline bool apply(Geometry const& geometry)
312 {
313 bg::is_valid_default_policy<AllowDuplicates> visitor;
b32b8144 314 return bg::is_valid(geometry, visitor, bg::default_strategy());
7c673cae
FG
315 }
316
317 template <typename Geometry>
318 static inline std::string reason(Geometry const& geometry)
319 {
320 std::ostringstream oss;
321 bg::failing_reason_policy<AllowDuplicates> visitor(oss);
b32b8144
FG
322 bg::is_valid(geometry, visitor, bg::default_strategy());
323 return oss.str();
324 }
325
326};
327
328
329template <bool AllowDuplicates>
330struct validity_tester_geo_areal
331{
332 template <typename Geometry>
333 static inline bool apply(Geometry const& geometry)
334 {
335 bg::is_valid_default_policy<AllowDuplicates> visitor;
336 bg::strategy::intersection::geographic_segments<> s;
337 return bg::is_valid(geometry, visitor, s);
338 }
339
340 template <typename Geometry>
341 static inline std::string reason(Geometry const& geometry)
342 {
343 std::ostringstream oss;
344 bg::failing_reason_policy<AllowDuplicates> visitor(oss);
345 bg::strategy::intersection::geographic_segments<> s;
346 bg::is_valid(geometry, visitor, s);
7c673cae
FG
347 return oss.str();
348 }
349
350};
351
352
353//----------------------------------------------------------------------------
354
355
356template
357<
358 typename ValidityTester,
359 typename Geometry,
360 typename ClosedGeometry = Geometry,
361 typename CWGeometry = Geometry,
362 typename CWClosedGeometry = Geometry,
363 typename Tag = typename bg::tag<Geometry>::type
364>
365class test_valid
366{
367protected:
368 template <typename G>
369 static inline void base_test(std::string const& case_id,
370 G const& g,
371 bool expected_result)
372 {
373#ifdef BOOST_GEOMETRY_TEST_DEBUG
374 std::cout << "=======" << std::endl;
375#endif
376
377 std::string reason;
378 bool valid = validity_checker
379 <
380 ValidityTester
381 >::apply(case_id, g, expected_result, reason);
382 boost::ignore_unused(valid);
383
384#ifdef BOOST_GEOMETRY_TEST_DEBUG
385 std::cout << "case id: " << case_id << ", Geometry: ";
386 pretty_print_geometry<G>::apply(std::cout, g);
387 std::cout << std::endl;
388 std::cout << "wkt: " << bg::wkt(g) << std::endl;
389 std::cout << std::boolalpha;
390 std::cout << "is valid? " << valid << std::endl;
391 std::cout << "expected result: " << expected_result << std::endl;
392 std::cout << "reason: " << reason << std::endl;
393 std::cout << "=======" << std::endl;
394 std::cout << std::noboolalpha;
395#endif
396 }
397
398public:
399 static inline void apply(std::string const& case_id,
400 Geometry const& geometry,
401 bool expected_result)
402 {
403 std::stringstream sstr;
b32b8144 404 sstr << case_id << "-original"; // which is: CCW open
7c673cae
FG
405 base_test(sstr.str(), geometry, expected_result);
406
407 if ( is_convertible_to_closed<Geometry>::apply(geometry) )
408 {
409#ifdef BOOST_GEOMETRY_TEST_DEBUG
410 std::cout << "...checking closed geometry..."
411 << std::endl;
412#endif
413 ClosedGeometry closed_geometry;
414 bg::convert(geometry, closed_geometry);
415 sstr.str("");
416 sstr << case_id << "-2closed";
417 base_test(sstr.str(), closed_geometry, expected_result);
418 }
419 if ( is_convertible_to_cw<Geometry>::apply(geometry) )
420 {
421#ifdef BOOST_GEOMETRY_TEST_DEBUG
422 std::cout << "...checking cw open geometry..."
423 << std::endl;
424#endif
425 CWGeometry cw_geometry;
426 bg::convert(geometry, cw_geometry);
427 sstr.str("");
428 sstr << case_id << "-2CW";
429 base_test(sstr.str(), cw_geometry, expected_result);
430 if ( is_convertible_to_closed<CWGeometry>::apply(cw_geometry) )
431 {
432#ifdef BOOST_GEOMETRY_TEST_DEBUG
433 std::cout << "...checking cw closed geometry..."
434 << std::endl;
435#endif
436 CWClosedGeometry cw_closed_geometry;
437 bg::convert(cw_geometry, cw_closed_geometry);
438 sstr.str("");
439 sstr << case_id << "-2CWclosed";
440 base_test(sstr.str(), cw_closed_geometry, expected_result);
441 }
442 }
443
444 if ( BOOST_GEOMETRY_CONDITION(is_convertible_to_polygon<Geometry>::value) )
445 {
446#ifdef BOOST_GEOMETRY_TEST_DEBUG
447 std::cout << "...checking geometry converted to polygon..."
448 << std::endl;
449#endif
450 typename is_convertible_to_polygon<Geometry>::type polygon;
451 bg::convert(geometry, polygon);
452 sstr.str("");
453 sstr << case_id << "-2Polygon";
454 base_test(sstr.str(), polygon, expected_result);
455 }
456
457 if ( BOOST_GEOMETRY_CONDITION(is_convertible_to_multipolygon<Geometry>::value) )
458 {
459#ifdef BOOST_GEOMETRY_TEST_DEBUG
460 std::cout << "...checking geometry converted to multi-polygon..."
461 << std::endl;
462#endif
463 typename is_convertible_to_multipolygon
464 <
465 Geometry
466 >::type multipolygon;
467
468 bg::convert(geometry, multipolygon);
469 sstr.str("");
470 sstr << case_id << "-2MultiPolygon";
471 base_test(sstr.str(), multipolygon, expected_result);
472 }
473
474#ifdef BOOST_GEOMETRY_TEST_DEBUG
475 std::cout << std::endl << std::endl << std::endl;
476#endif
477 }
478
479 static inline void apply(std::string const& case_id,
480 std::string const& wkt,
481 bool expected_result)
482 {
483 apply(case_id, from_wkt<Geometry>(wkt), expected_result);
484 }
485};
486
487
488//----------------------------------------------------------------------------
489
490
491template <typename VariantGeometry>
492class test_valid_variant
493 : test_valid<default_validity_tester, VariantGeometry>
494{
495private:
496 typedef test_valid<default_validity_tester, VariantGeometry> base_type;
497
498public:
499 static inline void apply(std::string const& case_id,
500 VariantGeometry const& vg,
501 bool expected_result)
502 {
503 std::ostringstream oss;
504 base_type::base_test(case_id, vg, expected_result);
505 }
506};
507
508
509#endif // BOOST_GEOMETRY_TEST_IS_VALID_HPP