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