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