1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2 // Unit Test
3 
4 // Copyright (c) 2015-2018, Oracle and/or its affiliates.
5 
6 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
7 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
8 
9 // Licensed under the Boost Software License version 1.0.
10 // http://www.boost.org/users/license.html
11 
12 #ifndef BOOST_TEST_MODULE
13 #define BOOST_TEST_MODULE test_is_valid_failure
14 #endif
15 
16 #include <iostream>
17 #include <string>
18 
19 #include <boost/variant/variant.hpp>
20 
21 #include <boost/test/included/unit_test.hpp>
22 
23 #include <boost/geometry/core/cs.hpp>
24 #include <boost/geometry/geometries/geometries.hpp>
25 #include <boost/geometry/algorithms/is_valid.hpp>
26 #include <boost/geometry/algorithms/reverse.hpp>
27 #include <boost/geometry/algorithms/validity_failure_type.hpp>
28 #include <boost/geometry/io/wkt/wkt.hpp>
29 
30 #include <boost/geometry/strategies/strategies.hpp>
31 
32 #include <from_wkt.hpp>
33 
34 
35 namespace bg = ::boost::geometry;
36 
37 typedef bg::validity_failure_type failure_type;
38 
39 typedef bg::model::point<double, 2, bg::cs::cartesian> point_type;
40 typedef bg::model::segment<point_type>                 segment_type;
41 typedef bg::model::box<point_type>                     box_type;
42 typedef bg::model::linestring<point_type>              linestring_type;
43 typedef bg::model::multi_linestring<linestring_type>   multi_linestring_type;
44 typedef bg::model::multi_point<point_type>             multi_point_type;
45 
46 
to_string(failure_type failure)47 char const* to_string(failure_type failure)
48 {
49     switch (failure)
50     {
51     case bg::no_failure:
52         return "no_failure";
53     case bg::failure_few_points:
54         return "failure_few_points";
55     case bg::failure_wrong_topological_dimension:
56         return "failure_wrong_topological_dimension";
57     case bg::failure_spikes:
58         return "failure_spikes";
59     case bg::failure_duplicate_points:
60         return "failure_duplicate_points";
61     case bg::failure_not_closed:
62         return "failure_not_closed";
63     case bg::failure_self_intersections:
64         return "failure_self_intersections";
65     case bg::failure_wrong_orientation:
66         return "failure_wrong_orientation";
67     case bg::failure_interior_rings_outside:
68         return "failure_interior_rings_outside";
69     case bg::failure_nested_interior_rings:
70         return "failure_nested_interior_rings";
71     case bg::failure_disconnected_interior:
72         return "failure_disconnected_interior";
73     case bg::failure_intersecting_interiors:
74         return "failure_intersecting_interiors";
75     case bg::failure_wrong_corner_order:
76         return "failure_wrong_corner_order";
77     default:
78         return ""; // to avoid warnings (-Wreturn-type)
79     }
80 }
81 
82 
83 template <typename Geometry>
84 struct test_failure
85 {
applytest_failure86     static inline void apply(std::string const& case_id,
87                              Geometry const& geometry,
88                              failure_type expected)
89     {
90         failure_type detected;
91         bg::is_valid(geometry, detected);
92         std::string expected_msg = bg::validity_failure_type_message(expected);
93         std::string detected_msg;
94         bg::is_valid(geometry, detected_msg);
95         std::string detected_msg_short
96             = detected_msg.substr(0, expected_msg.length());
97 
98 #ifdef BOOST_GEOMETRY_TEST_DEBUG
99         std::cout << "----------------------" << std::endl;
100         std::cout << "case id: " << case_id << std::endl;
101         std::cout << "Geometry: " << bg::wkt(geometry) << std::endl;
102         std::cout << "Expected reason: " << expected_msg << std::endl;
103         std::cout << "Detected reason: " << detected_msg << std::endl;
104         std::cout << "Expected: " << to_string(expected) << std::endl;
105         std::cout << "Detected: " << to_string(detected) << std::endl;
106         std::cout << std::endl;
107 #endif
108 
109         BOOST_CHECK_MESSAGE(expected == detected,
110             "case id: " << case_id
111             << ", Geometry: " << bg::wkt(geometry)
112             << ", expected: " << to_string(expected)
113             << ", detected: " << to_string(detected));
114 
115         BOOST_CHECK(detected_msg_short == expected_msg);
116 
117 #ifdef BOOST_GEOMETRY_TEST_DEBUG
118         std::cout << "----------------------" << std::endl;
119         std::cout << std::endl << std::endl;
120 #endif
121     }
122 
applytest_failure123     static inline void apply(std::string const& case_id,
124                              std::string const& wkt,
125                              failure_type expected)
126     {
127         Geometry geometry = from_wkt<Geometry>(wkt);
128         apply(case_id, geometry, expected);
129     }
130 };
131 
132 
BOOST_AUTO_TEST_CASE(test_failure_point)133 BOOST_AUTO_TEST_CASE( test_failure_point )
134 {
135 #ifdef BOOST_GEOMETRY_TEST_DEBUG
136     std::cout << std::endl << std::endl;
137     std::cout << "************************************" << std::endl;
138     std::cout << " is_valid_failure: POINT " << std::endl;
139     std::cout << "************************************" << std::endl;
140 #endif
141 
142     typedef point_type G;
143     typedef test_failure<G> test;
144 
145     test::apply("p01", "POINT(0 0)", bg::no_failure);
146 }
147 
BOOST_AUTO_TEST_CASE(test_failure_multipoint)148 BOOST_AUTO_TEST_CASE( test_failure_multipoint )
149 {
150 #ifdef BOOST_GEOMETRY_TEST_DEBUG
151     std::cout << std::endl << std::endl;
152     std::cout << "************************************" << std::endl;
153     std::cout << " is_valid_failure: MULTIPOINT " << std::endl;
154     std::cout << "************************************" << std::endl;
155 #endif
156 
157     typedef multi_point_type G;
158     typedef test_failure<G> test;
159 
160     test::apply("mp01", "MULTIPOINT()", bg::no_failure);
161     test::apply("mp02", "MULTIPOINT(0 0,0 0)", bg::no_failure);
162     test::apply("mp03", "MULTIPOINT(0 0,1 0,1 1,0 1)", bg::no_failure);
163     test::apply("mp04", "MULTIPOINT(0 0,1 0,1 1,1 0,0 1)", bg::no_failure);
164 }
165 
BOOST_AUTO_TEST_CASE(test_failure_segment)166 BOOST_AUTO_TEST_CASE( test_failure_segment )
167 {
168 #ifdef BOOST_GEOMETRY_TEST_DEBUG
169     std::cout << std::endl << std::endl;
170     std::cout << "************************************" << std::endl;
171     std::cout << " is_valid_failure: SEGMENT " << std::endl;
172     std::cout << "************************************" << std::endl;
173 #endif
174 
175     typedef segment_type G;
176     typedef test_failure<G> test;
177 
178     test::apply("s01",
179                 "SEGMENT(0 0,0 0)",
180                 bg::failure_wrong_topological_dimension);
181     test::apply("s02", "SEGMENT(0 0,1 0)", bg::no_failure);
182 }
183 
BOOST_AUTO_TEST_CASE(test_failure_box)184 BOOST_AUTO_TEST_CASE( test_failure_box )
185 {
186 #ifdef BOOST_GEOMETRY_TEST_DEBUG
187     std::cout << std::endl << std::endl;
188     std::cout << "************************************" << std::endl;
189     std::cout << " is_valid_failure: BOX " << std::endl;
190     std::cout << "************************************" << std::endl;
191 #endif
192 
193     typedef box_type G;
194     typedef test_failure<G> test;
195 
196     // boxes where the max corner and below and/or to the left of min corner
197     test::apply("b01",
198                 "BOX(0 0,-1 0)",
199                 bg::failure_wrong_topological_dimension);
200     test::apply("b02", "BOX(0 0,0 -1)", bg::failure_wrong_corner_order);
201     test::apply("b03", "BOX(0 0,-1 -1)", bg::failure_wrong_corner_order);
202 
203     // boxes of zero area; they are not 2-dimensional, so invalid
204     test::apply("b04", "BOX(0 0,0 0)", bg::failure_wrong_topological_dimension);
205     test::apply("b05", "BOX(0 0,1 0)", bg::failure_wrong_topological_dimension);
206     test::apply("b06", "BOX(0 0,0 1)", bg::failure_wrong_topological_dimension);
207 
208     test::apply("b07", "BOX(0 0,1 1)", bg::no_failure);
209 }
210 
BOOST_AUTO_TEST_CASE(test_failure_linestring)211 BOOST_AUTO_TEST_CASE( test_failure_linestring )
212 {
213 #ifdef BOOST_GEOMETRY_TEST_DEBUG
214     std::cout << std::endl << std::endl;
215     std::cout << "************************************" << std::endl;
216     std::cout << " is_valid_failure: LINESTRING " << std::endl;
217     std::cout << "************************************" << std::endl;
218 #endif
219 
220     typedef linestring_type G;
221     typedef test_failure<G> test;
222 
223     // empty linestring
224     test::apply("l01", "LINESTRING()", bg::failure_few_points);
225 
226     // 1-point linestrings
227     test::apply("l02", "LINESTRING(0 0)", bg::failure_few_points);
228     test::apply("l03",
229                 "LINESTRING(0 0,0 0)",
230                 bg::failure_wrong_topological_dimension);
231     test::apply("l04",
232                 "LINESTRING(0 0,0 0,0 0)",
233                 bg::failure_wrong_topological_dimension);
234 
235     // 2-point linestrings
236     test::apply("l05", "LINESTRING(0 0,1 2)", bg::no_failure);
237     test::apply("l06", "LINESTRING(0 0,1 2,1 2)", bg::no_failure);
238     test::apply("l07", "LINESTRING(0 0,0 0,1 2,1 2)", bg::no_failure);
239     test::apply("l08", "LINESTRING(0 0,0 0,0 0,1 2,1 2)", bg::no_failure);
240 
241     // 3-point linestring
242     test::apply("l09", "LINESTRING(0 0,1 0,2 10)", bg::no_failure);
243 
244     // linestrings with spikes
245     test::apply("l10", "LINESTRING(0 0,1 2,0 0)", bg::no_failure);
246 }
247 
BOOST_AUTO_TEST_CASE(test_failure_multilinestring)248 BOOST_AUTO_TEST_CASE( test_failure_multilinestring )
249 {
250 #ifdef BOOST_GEOMETRY_TEST_DEBUG
251     std::cout << std::endl << std::endl;
252     std::cout << "************************************" << std::endl;
253     std::cout << " is_valid_failure: MULTILINESTRING " << std::endl;
254     std::cout << "************************************" << std::endl;
255 #endif
256 
257     typedef multi_linestring_type G;
258     typedef test_failure<G> test;
259 
260     // empty multilinestring
261     test::apply("mls01", "MULTILINESTRING()", bg::no_failure);
262 
263     // multilinestring with empty linestring(s)
264     test::apply("mls02", "MULTILINESTRING(())", bg::failure_few_points);
265     test::apply("mls03", "MULTILINESTRING((),(),())", bg::failure_few_points);
266     test::apply("mls04",
267                 "MULTILINESTRING((),(0 1,1 0))",
268                 bg::failure_few_points);
269 
270     // multilinestring with invalid linestrings
271     test::apply("mls05",
272                 "MULTILINESTRING((0 0),(0 1,1 0))",
273                 bg::failure_few_points);
274     test::apply("mls06",
275                 "MULTILINESTRING((0 0,0 0),(0 1,1 0))",
276                 bg::failure_wrong_topological_dimension);
277     test::apply("mls07", "MULTILINESTRING((0 0),(1 0))",
278                 bg::failure_few_points);
279     test::apply("mls08",
280                 "MULTILINESTRING((0 0,0 0),(1 0,1 0))",
281                 bg::failure_wrong_topological_dimension);
282     test::apply("mls09",
283                 "MULTILINESTRING((0 0),(0 0))",
284                 bg::failure_few_points);
285     test::apply("mls10",
286                 "MULTILINESTRING((0 0,1 0,0 0),(5 0))",
287                 bg::failure_few_points);
288 
289     // multilinstring that has linestrings with spikes
290     test::apply("mls11",
291                 "MULTILINESTRING((0 0,1 0,0 0),(5 0,1 0,4 1))",
292                 bg::no_failure);
293     test::apply("mls12",
294                 "MULTILINESTRING((0 0,1 0,0 0),(1 0,2 0))",
295                 bg::no_failure);
296 
297     // valid multilinestrings
298     test::apply("mls13",
299                 "MULTILINESTRING((0 0,1 0,2 0),(5 0,1 0,4 1))",
300                 bg::no_failure);
301     test::apply("mls14",
302                 "MULTILINESTRING((0 0,1 0,2 0),(1 0,2 0))",
303                 bg::no_failure);
304     test::apply("mls15",
305                 "MULTILINESTRING((0 0,1 1),(0 1,1 0))",
306                 bg::no_failure);
307     test::apply("mls16",
308                 "MULTILINESTRING((0 0,1 1,2 2),(0 1,1 0,2 2))",
309                 bg::no_failure);
310 }
311 
312 template <typename Point>
test_open_rings()313 inline void test_open_rings()
314 {
315 #ifdef BOOST_GEOMETRY_TEST_DEBUG
316     std::cout << std::endl << std::endl;
317     std::cout << "************************************" << std::endl;
318     std::cout << " is_valid_failure: RING (open) " << std::endl;
319     std::cout << "************************************" << std::endl;
320 #endif
321 
322     typedef bg::model::ring<Point, false, false> G; // ccw, open ring
323     typedef test_failure<G> test;
324 
325     // not enough points
326     test::apply("r01", "POLYGON(())", bg::failure_few_points);
327     test::apply("r02", "POLYGON((0 0))", bg::failure_few_points);
328     test::apply("r03", "POLYGON((0 0,1 0))", bg::failure_few_points);
329 
330     // duplicate points
331     test::apply("r04",
332                 "POLYGON((0 0,0 0,0 0))",
333                 bg::failure_wrong_topological_dimension);
334     test::apply("r05",
335                 "POLYGON((0 0,1 0,1 0))",
336                 bg::failure_wrong_topological_dimension);
337     test::apply("r06",
338                 "POLYGON((0 0,1 0,0 0))",
339                 bg::failure_wrong_topological_dimension);
340     test::apply("r07", "POLYGON((0 0,1 0,1 1,0 0,0 0))", bg::no_failure);
341     test::apply("r08", "POLYGON((0 0,1 0,1 0,1 1))", bg::no_failure);
342     test::apply("r09", "POLYGON((0 0,1 0,1 0,1 1,0 0))", bg::no_failure);
343 
344     // with spikes
345     test::apply("r10", "POLYGON((0 0,2 0,2 2,0 2,1 2))", bg::failure_spikes);
346     test::apply("r11", "POLYGON((0 0,2 0,1 0,2 2))", bg::failure_spikes);
347     test::apply("r12",
348                 "POLYGON((0 0,1 0,2 0,1 0,4 0,4 4))",
349                 bg::failure_spikes);
350     test::apply("r13", "POLYGON((0 0,2 0,2 2,1 0))", bg::failure_spikes);
351     test::apply("r14", "POLYGON((0 0,2 0,1 0))", bg::failure_spikes);
352     test::apply("r15",
353                 "POLYGON((0 0,5 0,5 5,4 4,5 5,0 5))",
354                 bg::failure_spikes);
355     test::apply("r16",
356                 "POLYGON((0 0,5 0,5 5,4 4,3 3,5 5,0 5))",
357                 bg::failure_spikes);
358 
359     // with spikes and duplicate points
360     test::apply("r17",
361                 "POLYGON((0 0,0 0,2 0,2 0,1 0,1 0))",
362                 bg::failure_spikes);
363 
364     // with self-crossings
365     test::apply("r18",
366                 "POLYGON((0 0,5 0,5 5,3 -1,0 5))",
367                 bg::failure_self_intersections);
368 
369     // with self-crossings and duplicate points
370     test::apply("r19",
371                 "POLYGON((0 0,5 0,5 5,5 5,3 -1,0 5,0 5))",
372                 bg::failure_self_intersections);
373 
374     // with self-intersections
375     test::apply("r20",
376                 "POLYGON((0 0,5 0,5 5,3 5,3 0,2 0,2 5,0 5))",
377                 bg::failure_self_intersections);
378     test::apply("r21",
379                 "POLYGON((0 0,5 0,5 5,3 5,3 0,2 5,0 5))",
380                 bg::failure_self_intersections);
381     test::apply("r22",
382                 "POLYGON((0 0,5 0,5 1,1 1,1 2,2 2,3 1,4 2,5 2,5 5,0 5))",
383                 bg::failure_self_intersections);
384 
385     // with self-intersections and duplicate points
386     test::apply("r23",
387                 "POLYGON((0 0,5 0,5 5,3 5,3 5,3 0,3 0,2 0,2 0,2 5,2 5,0 5))",
388                 bg::failure_self_intersections);
389 
390     // next two suggested by Adam Wulkiewicz
391     test::apply("r24",
392                 "POLYGON((0 0,5 0,5 5,0 5,4 4,2 2,0 5))",
393                 bg::failure_self_intersections);
394     test::apply("r25",
395                 "POLYGON((0 0,5 0,5 5,1 4,4 4,4 1,0 5))",
396                 bg::failure_self_intersections);
397 
398     // and a few more
399     test::apply("r26",
400                 "POLYGON((0 0,5 0,5 5,4 4,1 4,1 1,4 1,4 4,0 5))",
401                 bg::failure_self_intersections);
402     test::apply("r27",
403                 "POLYGON((0 0,5 0,5 5,4 4,4 1,1 1,1 4,4 4,0 5))",
404                 bg::failure_self_intersections);
405 
406     // valid rings
407     test::apply("r28", "POLYGON((0 0,1 0,1 1))", bg::no_failure);
408     test::apply("r29", "POLYGON((1 0,1 1,0 0))", bg::no_failure);
409     test::apply("r30", "POLYGON((0 0,1 0,1 1,0 1))", bg::no_failure);
410     test::apply("r31", "POLYGON((1 0,1 1,0 1,0 0))", bg::no_failure);
411 
412     // test cases coming from buffer
413     test::apply("r32",
414                 "POLYGON((1.1713032141645456 -0.9370425713316364,\
415                           5.1713032141645456 4.0629574286683638,\
416                           4.7808688094430307 4.3753049524455756,\
417                           4.7808688094430307 4.3753049524455756,\
418                           0.7808688094430304 -0.6246950475544243,\
419                           0.7808688094430304 -0.6246950475544243))",
420                 bg::no_failure);
421 
422     // wrong orientation
423     test::apply("r33",
424                 "POLYGON((0 0,0 1,1 1,0 0))",
425                 bg::failure_wrong_orientation);
426 }
427 
428 template <typename Point>
test_closed_rings()429 void test_closed_rings()
430 {
431 #ifdef BOOST_GEOMETRY_TEST_DEBUG
432     std::cout << std::endl << std::endl;
433     std::cout << "************************************" << std::endl;
434     std::cout << " is_valid_failure: RING (closed) " << std::endl;
435     std::cout << "************************************" << std::endl;
436 #endif
437 
438     typedef bg::model::ring<Point, false, true> G; // ccw, closed ring
439     typedef test_failure<G> test;
440 
441     // not enough points
442     test::apply("r01c", "POLYGON(())", bg::failure_few_points);
443     test::apply("r02c", "POLYGON((0 0))", bg::failure_few_points);
444     test::apply("r03c", "POLYGON((0 0,0 0))", bg::failure_few_points);
445     test::apply("r04c", "POLYGON((0 0,1 0))", bg::failure_few_points);
446     test::apply("r05c", "POLYGON((0 0,1 0,1 0))", bg::failure_few_points);
447     test::apply("r06c", "POLYGON((0 0,1 0,2 0))", bg::failure_few_points);
448     test::apply("r07c",
449                 "POLYGON((0 0,1 0,1 0,2 0))",
450                 bg::failure_wrong_topological_dimension);
451     test::apply("r08c",
452                 "POLYGON((0 0,1 0,2 0,2 0))",
453                 bg::failure_wrong_topological_dimension);
454 
455     // boundary not closed
456     test::apply("r09c", "POLYGON((0 0,1 0,1 1,1 2))", bg::failure_not_closed);
457     test::apply("r10c",
458                 "POLYGON((0 0,1 0,1 0,1 1,1 1,1 2))",
459                 bg::failure_not_closed);
460 
461     // with spikes
462     test::apply("r11c", "POLYGON((0 0,1 0,1 0,2 0,0 0))", bg::failure_spikes);
463     test::apply("r12c",
464                 "POLYGON((0 0,1 0,1 1,2 2,0.5 0.5,0 1,0 0))",
465                 bg::failure_spikes);
466 
467     // wrong orientation
468     test::apply("r13c",
469                 "POLYGON((0 0,0 1,1 1,2 0,0 0))",
470                 bg::failure_wrong_orientation);
471 
472 }
473 
BOOST_AUTO_TEST_CASE(test_failure_ring)474 BOOST_AUTO_TEST_CASE( test_failure_ring )
475 {
476     test_open_rings<point_type>();
477     test_closed_rings<point_type>();
478 }
479 
480 
481 template <typename Point>
test_open_polygons()482 void test_open_polygons()
483 {
484 #ifdef BOOST_GEOMETRY_TEST_DEBUG
485     std::cout << std::endl << std::endl;
486     std::cout << "************************************" << std::endl;
487     std::cout << " is_valid_failure: POLYGON (open) " << std::endl;
488     std::cout << "************************************" << std::endl;
489 #endif
490 
491     typedef bg::model::polygon<Point, false, false> G; // ccw, open
492     typedef test_failure<G> test;
493 
494     // not enough points in exterior ring
495     test::apply("pg001", "POLYGON(())", bg::failure_few_points);
496     test::apply("pg002", "POLYGON((0 0))", bg::failure_few_points);
497     test::apply("pg003", "POLYGON((0 0,1 0))", bg::failure_few_points);
498 
499     // not enough points in interior ring
500     test::apply("pg004",
501                 "POLYGON((0 0,10 0,10 10,0 10),())",
502                 bg::failure_few_points);
503     test::apply("pg005",
504                 "POLYGON((0 0,10 0,10 10,0 10),(1 1))",
505                 bg::failure_few_points);
506     test::apply("pg006",
507                 "POLYGON((0 0,10 0,10 10,0 10),(1 1,2 2))",
508                 bg::failure_few_points);
509 
510     // duplicate points in exterior ring
511     test::apply("pg007",
512                 "POLYGON((0 0,0 0,0 0))",
513                 bg::failure_wrong_topological_dimension);
514     test::apply("pg008",
515                 "POLYGON((0 0,1 0,1 0))",
516                 bg::failure_wrong_topological_dimension);
517     test::apply("pg009",
518                 "POLYGON((0 0,1 0,0 0))",
519                 bg::failure_wrong_topological_dimension);
520     test::apply("pg010", "POLYGON((0 0,1 0,1 1,0 0,0 0))", bg::no_failure);
521     test::apply("pg011", "POLYGON((0 0,1 0,1 0,1 1))", bg::no_failure);
522     test::apply("pg012", "POLYGON((0 0,1 0,1 0,1 1,0 0))",  bg::no_failure);
523 
524     test::apply("pg013",
525                 "POLYGON((0 0,10 0,10 10,0 10),(1 1,1 1,1 1))",
526                 bg::failure_wrong_topological_dimension);
527     test::apply("pg014",
528                 "POLYGON((0 0,10 0,10 10,0 10),(1 1,2 1,2 1))",
529                 bg::failure_wrong_topological_dimension);
530     test::apply("pg015",
531                 "POLYGON((0 0,10 0,10 10,0 10),(1 1,2 1,1 1))",
532                 bg::failure_wrong_topological_dimension);
533     test::apply("pg016",
534                 "POLYGON((0 0,10 0,10 10,0 10),(1 1,2 2,2 1,1 1,1 1))",
535                 bg::no_failure);
536     test::apply("pg017",
537                 "POLYGON((0 0,10 0,10 10,0 10),(1 1,2 2,2 2,2 1))",
538                 bg::no_failure);
539     test::apply("pg018",
540                 "POLYGON((0 0,10 0,10 10,0 10),(1 1,2 2,2 1,2 1,1 1))",
541                 bg::no_failure);
542 
543     // with spikes in exterior ring
544     test::apply("pg019", "POLYGON((0 0,2 0,2 2,0 2,1 2))", bg::failure_spikes);
545     test::apply("pg020", "POLYGON((0 0,2 0,1 0,2 2))", bg::failure_spikes);
546     test::apply("pg021",
547                 "POLYGON((0 0,1 0,2 0,1 0,4 0,4 4))",
548                 bg::failure_spikes);
549     test::apply("pg022", "POLYGON((0 0,2 0,2 2,1 0))", bg::failure_spikes);
550     test::apply("pg023", "POLYGON((0 0,2 0,1 0))", bg::failure_spikes);
551     test::apply("pg024",
552                 "POLYGON((0 0,5 0,5 5,4 4,5 5,0 5))",
553                 bg::failure_spikes);
554     test::apply("pg025",
555                 "POLYGON((0 0,5 0,5 5,4 4,3 3,5 5,0 5))",
556                 bg::failure_spikes);
557 
558     // with spikes in interior ring
559     test::apply("pg026",
560                 "POLYGON((0 0,10 0,10 10,0 10),(1 1,3 1,3 3,1 3,2 3))",
561                 bg::failure_spikes);
562     test::apply("pg027",
563                 "POLYGON((0 0,10 0,10 10,0 10),(1 1,3 1,2 1,3 3))",
564                 bg::failure_spikes);
565     test::apply("pg028",
566                 "POLYGON((0 0,10 0,10 10,0 10),(1 1,2 1,3 1,2 1,4 1,4 4))",
567                 bg::failure_spikes);
568     test::apply("pg029",
569                 "POLYGON((0 0,10 0,10 10,0 10),(1 1,3 1,3 3,2 1))",
570                 bg::failure_spikes);
571     test::apply("pg030",
572                 "POLYGON((0 0,10 0,10 10,0 10),(1 1,3 1,2 1))",
573                 bg::failure_spikes);
574 
575     // with self-crossings in exterior ring
576     test::apply("pg031",
577                 "POLYGON((0 0,5 0,5 5,3 -1,0 5))",
578                 bg::failure_self_intersections);
579 
580     // example from Norvald Ryeng
581     test::apply("pg032",
582                 "POLYGON((100 1300,140 1300,140 170,100 1700))",
583                 bg::failure_wrong_orientation);
584     // and with point order reversed
585     test::apply("pg033",
586                 "POLYGON((100 1300,100 1700,140 170,140 1300))",
587                 bg::failure_self_intersections);
588 
589     // with self-crossings in interior ring
590     // the self-crossing causes the area of the interior ring to have
591     // the wrong sign, hence the "wrong orientation" failure
592     test::apply("pg034",
593                 "POLYGON((0 0,10 0,10 10,0 10),(3 3,3 7,4 6,2 6))",
594                 bg::failure_wrong_orientation);
595 
596     // with self-crossings between rings
597     test::apply("pg035",
598                 "POLYGON((0 0,5 0,5 5,0 5),(1 1,2 1,1 -1))",
599                 bg::failure_self_intersections);
600 
601     // with self-intersections in exterior ring
602     test::apply("pg036",
603                 "POLYGON((0 0,5 0,5 5,3 5,3 0,2 0,2 5,0 5))",
604                 bg::failure_self_intersections);
605     test::apply("pg037",
606                 "POLYGON((0 0,5 0,5 5,3 5,3 0,2 5,0 5))",
607                 bg::failure_self_intersections);
608     test::apply("pg038",
609                 "POLYGON((0 0,5 0,5 1,1 1,1 2,2 2,3 1,4 2,5 2,5 5,0 5))",
610                 bg::failure_self_intersections);
611 
612     // next two suggested by Adam Wulkiewicz
613     test::apply("pg039",
614                 "POLYGON((0 0,5 0,5 5,0 5,4 4,2 2,0 5))",
615                 bg::failure_self_intersections);
616     test::apply("pg040",
617                 "POLYGON((0 0,5 0,5 5,1 4,4 4,4 1,0 5))",
618                 bg::failure_self_intersections);
619     test::apply("pg041",
620                 "POLYGON((0 0,5 0,5 5,4 4,1 4,1 1,4 1,4 4,0 5))",
621                 bg::failure_self_intersections);
622     test::apply("pg042",
623                 "POLYGON((0 0,5 0,5 5,4 4,4 1,1 1,1 4,4 4,0 5))",
624                 bg::failure_self_intersections);
625 
626     // with self-intersections in interior ring
627 
628     // same comment as for pg034
629     test::apply("pg043",
630                 "POLYGON((-10 -10,10 -10,10 10,-10 10),(0 0,5 0,5 5,3 5,3 0,2 0,2 5,0 5))",
631                 bg::failure_wrong_orientation);
632 
633     // same comment as for pg034
634     test::apply("pg044",
635                 "POLYGON((-10 -10,10 -10,10 10,-10 10),(0 0,5 0,5 5,3 5,3 0,2 5,0 5))",
636                 bg::failure_wrong_orientation);
637 
638     // same comment as for pg034
639     test::apply("pg045",
640                 "POLYGON((-10 -10,10 -10,10 10,-10 10),(0 0,5 0,5 1,1 1,1 2,2 2,3 1,4 2,5 2,5 5,0 5))",
641                 bg::failure_wrong_orientation);
642 
643     // with self-intersections between rings
644     // hole has common segment with exterior ring
645     test::apply("pg046",
646                 "POLYGON((0 0,10 0,10 10,0 10),(1 1,1 10,2 10,2 1))",
647                 bg::failure_self_intersections);
648     test::apply("pg047",
649                 "POLYGON((0 0,0 0,10 0,10 10,0 10,0 10),(1 1,1 10,1 10,2 10,2 10,2 1))",
650                 bg::failure_self_intersections);
651     // hole touches exterior ring at one point
652     test::apply("pg048",
653                 "POLYGON((0 0,10 0,10 10,0 10),(1 1,1 10,2 1))",
654                 bg::no_failure);
655 
656     // "hole" is outside the exterior ring, but touches it
657     // TODO: return the failure value failure_interior_rings_outside
658     test::apply("pg049",
659                 "POLYGON((0 0,10 0,10 10,0 10),(5 10,4 11,6 11))",
660                 bg::failure_self_intersections);
661 
662     // hole touches exterior ring at vertex
663     test::apply("pg050",
664                 "POLYGON((0 0,10 0,10 10,0 10),(0 0,1 4,4 1))",
665                 bg::no_failure);
666 
667     // "hole" is completely outside the exterior ring
668     test::apply("pg051",
669                 "POLYGON((0 0,10 0,10 10,0 10),(20 20,20 21,21 21,21 20))",
670                 bg::failure_interior_rings_outside);
671 
672     // two "holes" completely outside the exterior ring, that touch
673     // each other
674     test::apply("pg052",
675                 "POLYGON((0 0,10 0,10 10,0 10),(20 0,25 10,21 0),(30 0,25 10,31 0))",
676                 bg::failure_interior_rings_outside);
677 
678     // example from Norvald Ryeng
679     test::apply("pg053",
680                 "POLYGON((58 31,56.57 30,62 33),(35 9,28 14,31 16),(23 11,29 5,26 4))",
681                 bg::failure_interior_rings_outside);
682     // and with points reversed
683     test::apply("pg054",
684                 "POLYGON((58 31,62 33,56.57 30),(35 9,31 16,28 14),(23 11,26 4,29 5))",
685                 bg::failure_wrong_orientation);
686 
687     // "hole" is completely inside another "hole"
688     test::apply("pg055",
689                 "POLYGON((0 0,10 0,10 10,0 10),(1 1,1 9,9 9,9 1),(2 2,2 8,8 8,8 2))",
690                 bg::failure_nested_interior_rings);
691     test::apply("pg056",
692                 "POLYGON((0 0,10 0,10 10,0 10),(1 1,1 9,9 9,9 1),(2 2,8 2,8 8,2 8))",
693                 bg::failure_wrong_orientation);
694 
695     // "hole" is inside another "hole" (touching)
696     // TODO: return the failure value failure_nested_interior_rings
697     test::apply("pg057",
698                 "POLYGON((0 0,10 0,10 10,0 10),(1 1,1 9,9 9,9 1),(2 2,2 8,8 8,9 6,8 2))",
699                 bg::failure_self_intersections);
700     // TODO: return the failure value failure_nested_interior_rings
701     test::apply("pg058",
702                 "POLYGON((0 0,10 0,10 10,0 10),(1 1,1 9,9 9,9 1),(2 2,2 8,8 8,9 6,8 2))",
703                 bg::failure_self_intersections);
704     test::apply("pg058a",
705                 "POLYGON((0 0,10 0,10 10,0 10),(1 1,1 9,9 9,9 1),(2 2,8 2,9 6,8 8,2 8))",
706                 bg::failure_wrong_orientation);
707     // TODO: return the failure value failure_nested_interior_rings
708     test::apply("pg059",
709                 "POLYGON((0 0,10 0,10 10,0 10),(1 1,1 9,9 9,9 1),(2 2,2 8,8 8,9 6,8 2))",
710                 bg::failure_self_intersections);
711     test::apply("pg059a",
712                 "POLYGON((0 0,10 0,10 10,0 10),(1 1,9 1,9 9,1 9),(2 2,2 8,8 8,9 6,8 2))",
713                 bg::failure_wrong_orientation);
714     // TODO: return the failure value failure_nested_interior_rings
715     test::apply("pg060",
716                 "POLYGON((0 0,10 0,10 10,0 10),(1 1,1 9,9 9,9 1),(2 2,2 8,8 8,9 6,8 2))",
717                 bg::failure_self_intersections);
718     test::apply("pg060a",
719                 "POLYGON((0 0,10 0,10 10,0 10),(1 1,9 1,9 9,1 9),(2 2,8 2,9 6,8 8,2 8))",
720                 bg::failure_wrong_orientation);
721     // hole touches exterior ring at two points
722     test::apply("pg061",
723                 "POLYGON((0 0,10 0,10 10,0 10),(5 0,0 5,5 5))",
724                 bg::failure_disconnected_interior);
725 
726     // cases with more holes
727     // two holes, touching the exterior at the same point
728     test::apply("pg062",
729                 "POLYGON((0 0,10 0,10 10,0 10),(0 0,1 9,2 9),(0 0,9 2,9 1))",
730                 bg::no_failure);
731     test::apply("pg063",
732                 "POLYGON((0 0,0 0,10 0,10 10,0 10,0 0),(0 0,0 0,1 9,2 9),(0 0,0 0,9 2,9 1))",
733                 bg::no_failure);
734     test::apply("pg063",
735                 "POLYGON((0 10,0 0,0 0,0 0,10 0,10 10),(2 9,0 0,0 0,1 9),(9 1,0 0,0 0,9 2))",
736                 bg::no_failure);
737     // two holes, one inside the other
738     // TODO: return the failure value failure_nested_interior_rings
739     test::apply("pg064",
740                 "POLYGON((0 0,10 0,10 10,0 10),(0 0,1 9,9 1),(0 0,4 5,5 4))",
741                 bg::failure_self_intersections);
742     // 1st hole touches has common segment with 2nd hole
743     test::apply("pg066",
744                 "POLYGON((0 0,10 0,10 10,0 10),(1 1,1 5,5 5,5 1),(5 4,5 8,8 8,8 4))",
745                 bg::failure_self_intersections);
746     // 1st hole touches 2nd hole at two points
747     test::apply("pg067",
748                 "POLYGON((0 0,10 0,10 10,0 10),(1 1,1 9,9 9,9 8,2 8,2 1),(2 5,5 8,5 5))",
749                 bg::failure_disconnected_interior);
750     // polygon with many holes, where the last two touch at two points
751     test::apply("pg068",
752                 "POLYGON((0 0,20 0,20 20,0 20),(1 18,1 19,2 19,2 18),(3 18,3 19,4 19,4 18),(5 18,5 19,6 19,6 18),(7 18,7 19,8 19,8 18),(9 18,9 19,10 19,10 18),(11 18,11 19,12 19,12 18),(13 18,13 19,14 19,14 18),(15 18,15 19,16 19,16 18),(17 18,17 19,18 19,18 18),(1 1,1 9,9 9,9 8,2 8,2 1),(2 5,5 8,5 5))",
753                 bg::failure_disconnected_interior);
754     // two holes completely inside exterior ring but touching each
755     // other at a point
756     test::apply("pg069",
757                 "POLYGON((0 0,10 0,10 10,0 10),(1 1,1 9,2 9),(1 1,9 2,9 1))",
758                 bg::no_failure);
759     // four holes, each two touching at different points
760     test::apply("pg070",
761                 "POLYGON((0 0,10 0,10 10,0 10),(0 10,2 1,1 1),(0 10,4 1,3 1),(10 10,9 1,8 1),(10 10,7 1,6 1))",
762                 bg::no_failure);
763     // five holes, with two pairs touching each at some point, and
764     // fifth hole creating a disconnected component for the interior
765     test::apply("pg071",
766                 "POLYGON((0 0,10 0,10 10,0 10),(0 10,2 1,1 1),(0 10,4 1,3 1),(10 10,9 1,8 1),(10 10,7 1,6 1),(4 1,4 4,6 4,6 1))",
767                 bg::failure_disconnected_interior);
768     // five holes, with two pairs touching each at some point, and
769     // fifth hole creating three disconnected components for the interior
770     test::apply("pg072",
771                 "POLYGON((0 0,10 0,10 10,0 10),(0 10,2 1,1 1),(0 10,4 1,3 1),(10 10,9 1,8 1),(10 10,7 1,6 1),(4 1,4 4,6 4,6 1,5 0))",
772                 bg::failure_disconnected_interior);
773 
774     // both examples: a polygon with one hole, where the hole contains
775     // the exterior ring
776     test::apply("pg073",
777                 "POLYGON((0 0,1 0,1 1,0 1),(-10 -10,-10 10,10 10,10 -10))",
778                 bg::failure_interior_rings_outside);
779     // TODO: return the failure value failure_interior_rings_outside
780     test::apply("pg074",
781                 "POLYGON((-10 -10,1 0,1 1,0 1),(-10 -10,-10 10,10 10,10 -10))",
782                 bg::failure_self_intersections);
783 }
784 
785 template <typename Point>
test_doc_example_polygon()786 inline void test_doc_example_polygon()
787 {
788 #ifdef BOOST_GEOMETRY_TEST_DEBUG
789     std::cout << std::endl << std::endl;
790     std::cout << "************************************" << std::endl;
791     std::cout << " is_valid_failure: doc example polygon " << std::endl;
792     std::cout << "************************************" << std::endl;
793 #endif
794 
795     typedef bg::model::polygon<Point> CCW_CG;
796     typedef test_failure<CCW_CG> test;
797 
798     test::apply("pg-doc",
799                 "POLYGON((0 0,0 10,10 10,10 0,0 0),(0 0,9 1,9 2,0 0),(0 0,2 9,1 9,0 0),(2 9,9 2,9 9,2 9))",
800                 bg::failure_disconnected_interior);
801 }
802 
BOOST_AUTO_TEST_CASE(test_failure_polygon)803 BOOST_AUTO_TEST_CASE( test_failure_polygon )
804 {
805     test_open_polygons<point_type>();
806     test_doc_example_polygon<point_type>();
807 }
808 
809 
810 template <typename Point>
test_open_multipolygons()811 void test_open_multipolygons()
812 {
813 #ifdef BOOST_GEOMETRY_TEST_DEBUG
814     std::cout << std::endl << std::endl;
815     std::cout << "************************************" << std::endl;
816     std::cout << " is_valid_failure: MULTIPOLYGON (open) " << std::endl;
817     std::cout << "************************************" << std::endl;
818 #endif
819 
820     typedef bg::model::polygon<point_type,false,false> ccw_open_polygon_type;
821     typedef bg::model::multi_polygon<ccw_open_polygon_type> G;
822 
823     typedef test_failure<G> test;
824 
825     // not enough points
826     test::apply("mpg01", "MULTIPOLYGON()", bg::no_failure);
827     test::apply("mpg02", "MULTIPOLYGON((()))", bg::failure_few_points);
828     test::apply("mpg03", "MULTIPOLYGON(((0 0)),(()))", bg::failure_few_points);
829     test::apply("mpg04", "MULTIPOLYGON(((0 0,1 0)))", bg::failure_few_points);
830 
831     // two disjoint polygons
832     test::apply("mpg05",
833                 "MULTIPOLYGON(((0 0,1 0,1 1,0 1)),((2 2,3 2,3 3,2 3)))",
834                 bg::no_failure);
835 
836     // two disjoint polygons with multiple points
837     test::apply("mpg06",
838                 "MULTIPOLYGON(((0 0,1 0,1 0,1 1,0 1)),((2 2,3 2,3 3,3 3,2 3)))",
839                 bg::no_failure);
840 
841     // two polygons touch at a point
842     test::apply("mpg07",
843                 "MULTIPOLYGON(((0 0,1 0,1 1,0 1)),((1 1,2 1,2 2,1 2)))",
844                 bg::no_failure);
845 
846     // two polygons share a segment at a point
847     test::apply("mpg08",
848                 "MULTIPOLYGON(((0 0,1.5 0,1.5 1,0 1)),((1 1,2 1,2 2,1 2)))",
849                 bg::failure_self_intersections);
850 
851     // one polygon inside another and boundaries touching
852     test::apply("mpg09",
853                 "MULTIPOLYGON(((0 0,10 0,10 10,0 10)),((0 0,9 1,9 2)))",
854                 bg::failure_intersecting_interiors);
855     test::apply("mpg09_2",
856                 "MULTIPOLYGON(((0 0,5 1,10 0,10 10,0 10)),((1 1,9 1,9 2)))",
857                 bg::failure_intersecting_interiors);
858 
859     // one polygon inside another and boundaries not touching
860     test::apply("mpg10",
861                 "MULTIPOLYGON(((0 0,10 0,10 10,0 10)),((1 1,9 1,9 2)))",
862                 bg::failure_intersecting_interiors);
863 
864     // free space is disconnected
865     test::apply("mpg11",
866                 "MULTIPOLYGON(((0 0,1 0,1 1,0 1)),((1 1,2 1,2 2,1 2)),((0 1,0 2,-1 2,-1 -1)),((1 2,1 3,0 3,0 2)))",
867                 bg::no_failure);
868 
869     // multi-polygon with a polygon inside the hole of another polygon
870     test::apply("mpg12",
871                 "MULTIPOLYGON(((0 0,100 0,100 100,0 100),(1 1,1 99,99 99,99 1)),((2 2,98 2,98 98,2 98)))",
872                 bg::no_failure);
873     test::apply("mpg13",
874                 "MULTIPOLYGON(((0 0,100 0,100 100,0 100),(1 1,1 99,99 99,99 1)),((1 1,98 2,98 98,2 98)))",
875                 bg::no_failure);
876 
877     // test case suggested by Barend Gehrels: take two valid polygons P1 and
878     // P2 with holes H1 and H2, respectively, and consider P2 to be
879     // fully inside H1; now invalidate the multi-polygon by
880     // considering H2 as a hole of P1 and H1 as a hole of P2; this
881     // should be invalid
882     //
883     // first the valid case:
884     test::apply("mpg14",
885                 "MULTIPOLYGON(((0 0,100 0,100 100,0 100),(1 1,1 99,99 99,99 1)),((2 2,98 2,98 98,2 98),(3 3,3 97,97 97,97 3)))",
886                 bg::no_failure);
887     // and the invalid case:
888     test::apply("mpg15",
889                 "MULTIPOLYGON(((0 0,100 0,100 100,0 100),(3 3,3 97,97 97,97 3)),((2 2,98 2,98 98,2 98),(1 1,1 99,99 99,99 1)))",
890                 bg::failure_interior_rings_outside);
891 
892     test::apply
893         ("mpg16",
894          "MULTIPOLYGON(((-1 4,8 -10,-10 10,7 -6,8 -2,\
895                       -10 10,-10 1,-3 -4,4 1,-1 2,4 3,-8 10,-5 -9,-1 6,-5 0)),\
896                       ((-10 -3,-8 1,2 -8,-2 6,-4 0,8 -5,-1 5,8 2)),\
897                       ((-6 -10,1 10,4 -8,-7 -2,2 0,-4 3,-10 9)),\
898                       ((10 -1,-2 8,-7 3,-6 8,-9 -7,7 -5)),\
899                       ((7 7,-4 -4,9 -8,-10 -6)))",
900          bg::failure_wrong_orientation);
901 
902     test::apply
903         ("mpg17",
904          "MULTIPOLYGON(((-1 4,8 -10,-10 10,7 -6,8 -2,\
905                       -10 10,-10 1,-3 -4,4 1,-1 2,4 3,-8 10,-5 -9,-1 6,-5 0)),\
906                       ((-10 -3,-8 1,2 -8,-2 6,-4 0,8 -5,-1 5,8 2)),\
907                       ((-6 -10,-10 9,-4 3,2 0,-7 -2,4 -8,1 10)),\
908                       ((10 -1,-2 8,-7 3,-6 8,-9 -7,7 -5)),\
909                       ((7 7,-10 -6,9 -8,-4 -4)))",
910          bg::failure_spikes);
911 
912     // test cases coming from buffer
913     {
914         std::string wkt = "MULTIPOLYGON(((1.1713032141645456 -0.9370425713316364,5.1713032141645456 4.0629574286683638,4.7808688094430307 4.3753049524455756,4.7808688094430307 4.3753049524455756,0.7808688094430304 -0.6246950475544243,0.7808688094430304 -0.6246950475544243,1.1713032141645456 -0.9370425713316364)))";
915 
916         G open_mpgn = from_wkt<G>(wkt);
917         bg::reverse(open_mpgn);
918 
919         test::apply("mpg18", open_mpgn, bg::failure_wrong_orientation);
920     }
921     {
922         std::string wkt = "MULTIPOLYGON(((5.2811206375710933 9.9800205994776228,5.2446420208654896 10.0415020265598844,5.1807360092909640 10.1691699739962242,5.1261005500004773 10.3010716408018013,5.0810140527710059 10.4365348863171388,5.0457062680576819 10.5748694208940446,5.0203571162381344 10.7153703234534277,5.0050957707794934 10.8573216336015328,5.0000000000000000 10.9999999999999964,5.0050957707794925 11.1426783663984619,5.0203571162381344 11.2846296765465670,5.0457062680576801 11.4251305791059501,5.0810140527710042 11.5634651136828559,5.1261005500004755 11.6989283591981934,5.1807360092909622 11.8308300260037704,5.2446420208654869 11.9584979734401102,5.3174929343376363 12.0812816349111927,5.3989175181512774 12.1985553330226910,5.4885008512914810 12.3097214678905669,5.5857864376269024 12.4142135623730923,5.6902785321094269 12.5114991487085145,5.8014446669773028 12.6010824818487190,5.9187183650888020 12.6825070656623602,6.0415020265598844 12.7553579791345104,6.1691699739962260 12.8192639907090360,6.3010716408018030 12.8738994499995236,6.4365348863171405 12.9189859472289950,6.5748694208940472 12.9542937319423199,6.7153703234534312 12.9796428837618656,6.8573216336015381 12.9949042292205075,7.0000000000000036 13.0000000000000000,7.1426783663984690 12.9949042292205075,7.2846296765465750 12.9796428837618656,7.4251305791059590 12.9542937319423181,7.5634651136828657 12.9189859472289932,7.6989283591982032 12.8738994499995201,7.8308300260037802 12.8192639907090324,7.9584979734401209 12.7553579791345069,8.0812816349112033 12.6825070656623566,8.1985553330227017 12.6010824818487137,8.3097214678905793 12.5114991487085092,8.4142135623731029 12.4142135623730869,8.5114991487085252 12.3097214678905598,8.6010824818487297 12.1985553330226821,8.6825070656623708 12.0812816349111838,8.7553579791345193 11.9584979734400996,8.8192639907090431 11.8308300260037580,8.8738994499995290 11.6989283591981810,8.9189859472290003 11.5634651136828417,8.9542937319423235 11.4251305791059359,8.9796428837618691 11.2846296765465510,8.9949042292205093 11.1426783663984441,9.0000000000000000 11.0000000000000000,8.9949042292205075 10.8573216336015346,8.9796428837618656 10.7153703234534294,8.9542937319423181 10.5748694208940464,8.9189859472289950 10.4365348863171405,8.8738994499995236 10.3010716408018030,8.8192639907090360 10.1691699739962278,8.7553579791345122 10.0415020265598862,8.7188787869375428 9.9800200826281831,8.8573216336015381 9.9949042292205075,9.0000000000000036 10.0000000000000000,9.1426783663984690 9.9949042292205075,9.2846296765465759 9.9796428837618656,9.4251305791059590 9.9542937319423181,9.5634651136828648 9.9189859472289932,9.6989283591982041 9.8738994499995201,9.8308300260037793 9.8192639907090324,9.9584979734401209 9.7553579791345069,10.0812816349112033 9.6825070656623566,10.1985553330227017 9.6010824818487137,10.3097214678905793 9.5114991487085092,10.4142135623731029 9.4142135623730869,10.5114991487085252 9.3097214678905598,10.6010824818487297 9.1985553330226821,10.6825070656623708 9.0812816349111838,10.7553579791345193 8.9584979734400996,10.8192639907090431 8.8308300260037580,10.8738994499995290 8.6989283591981810,10.9189859472290003 8.5634651136828417,10.9542937319423235 8.4251305791059359,10.9796428837618691 8.2846296765465510,10.9949042292205093 8.1426783663984441,11.0000000000000000 8.0000000000000000,10.9949042292205075 7.8573216336015355,10.9796428837618656 7.7153703234534294,10.9542937319423181 7.5748694208940464,10.9189859472289950 7.4365348863171405,10.8738994499995236 7.3010716408018030,10.8192639907090360 7.1691699739962269,10.7553579791345122 7.0415020265598862,10.6825070656623620 6.9187183650888047,10.6010824818487208 6.8014446669773063,10.5114991487085163 6.6902785321094296,10.4142135623730958 6.5857864376269051,10.3097214678905704 6.4885008512914837,10.1985553330226946 6.3989175181512792,10.0812816349111962 6.3174929343376380,9.9584979734401138 6.2446420208654887,9.8308300260037740 6.1807360092909640,9.6989283591981970 6.1261005500004764,9.5634651136828595 6.0810140527710050,9.4251305791059536 6.0457062680576810,9.2846296765465706 6.0203571162381344,9.1426783663984654 6.0050957707794925,9.0000000000000018 6.0000000000000000,8.8573216336015363 6.0050957707794925,8.7153703234534312 6.0203571162381344,8.5748694208940481 6.0457062680576810,8.4365348863171423 6.0810140527710050,8.3010716408018048 6.1261005500004764,8.1691699739962278 6.1807360092909622,8.0415020265598880 6.2446420208654878,7.9187183650888064 6.3174929343376363,7.8014446669773072 6.3989175181512783,7.6902785321094314 6.4885008512914819,7.5857864376269060 6.5857864376269033,7.4885008512914846 6.6902785321094278,7.3989175181512810 6.8014446669773045,7.3174929343376389 6.9187183650888029,7.2446420208654896 7.0415020265598844,7.1807360092909640 7.1691699739962251,7.1261005500004773 7.3010716408018013,7.0810140527710059 7.4365348863171379,7.0457062680576819 7.5748694208940437,7.0203571162381344 7.7153703234534268,7.0050957707794934 7.8573216336015328,7.0000000000000000 7.9999999999999973,7.0050957707794925 8.1426783663984619,7.0203571162381344 8.2846296765465670,7.0457062680576801 8.4251305791059501,7.0810140527710042 8.5634651136828559,7.1261005500004755 8.6989283591981934,7.1807360092909622 8.8308300260037704,7.2446420208654869 8.9584979734401102,7.2811219724467575 9.0199799990140797,7.1426783663984654 9.0050957707794925,7.0000000000000009 9.0000000000000000,6.8573216336015363 9.0050957707794925,6.7188786030357956 9.0199806804111571,6.7553579791345184 8.9584979734400996,6.8192639907090431 8.8308300260037580,6.8738994499995290 8.6989283591981810,6.9189859472290003 8.5634651136828417,6.9542937319423235 8.4251305791059359,6.9796428837618683 8.2846296765465510,6.9949042292205084 8.1426783663984441,7.0000000000000000 8.0000000000000000,6.9949042292205075 7.8573216336015355,6.9796428837618656 7.7153703234534294,6.9542937319423190 7.5748694208940464,6.9189859472289950 7.4365348863171405,6.8738994499995236 7.3010716408018030,6.8192639907090369 7.1691699739962269,6.7553579791345113 7.0415020265598862,6.6825070656623620 6.9187183650888047,6.6010824818487208 6.8014446669773063,6.5114991487085163 6.6902785321094296,6.4142135623730949 6.5857864376269051,6.3097214678905704 6.4885008512914837,6.1985553330226946 6.3989175181512792,6.0812816349111953 6.3174929343376380,5.9584979734401138 6.2446420208654887,5.8308300260037731 6.1807360092909640,5.6989283591981970 6.1261005500004764,5.5634651136828603 6.0810140527710050,5.4251305791059536 6.0457062680576810,5.2846296765465715 6.0203571162381344,5.1426783663984654 6.0050957707794925,5.0000000000000009 6.0000000000000000,4.8573216336015363 6.0050957707794925,4.7153703234534312 6.0203571162381344,4.5748694208940481 6.0457062680576810,4.4365348863171423 6.0810140527710050,4.3010716408018048 6.1261005500004764,4.1691699739962287 6.1807360092909622,4.0415020265598880 6.2446420208654878,3.9187183650888064 6.3174929343376363,3.8014446669773077 6.3989175181512783,3.6902785321094314 6.4885008512914819,3.5857864376269064 6.5857864376269033,3.4885008512914846 6.6902785321094278,3.3989175181512805 6.8014446669773045,3.3174929343376389 6.9187183650888029,3.2446420208654896 7.0415020265598844,3.1807360092909640 7.1691699739962251,3.1261005500004773 7.3010716408018013,3.0810140527710059 7.4365348863171379,3.0457062680576819 7.5748694208940437,3.0203571162381349 7.7153703234534268,3.0050957707794934 7.8573216336015328,3.0000000000000000 7.9999999999999973,3.0050957707794925 8.1426783663984619,3.0203571162381344 8.2846296765465670,3.0457062680576801 8.4251305791059501,3.0810140527710042 8.5634651136828559,3.1261005500004755 8.6989283591981934,3.1807360092909618 8.8308300260037704,3.2446420208654869 8.9584979734401102,3.3174929343376358 9.0812816349111927,3.3989175181512770 9.1985553330226910,3.4885008512914810 9.3097214678905669,3.5857864376269024 9.4142135623730923,3.6902785321094269 9.5114991487085145,3.8014446669773028 9.6010824818487190,3.9187183650888020 9.6825070656623602,4.0415020265598844 9.7553579791345104,4.1691699739962260 9.8192639907090360,4.3010716408018030 9.8738994499995236,4.4365348863171405 9.9189859472289950,4.5748694208940472 9.9542937319423199,4.7153703234534312 9.9796428837618656,4.8573216336015381 9.9949042292205075,5.0000000000000036 10.0000000000000000,5.1426783663984690 9.9949042292205075)))";
923 
924         G open_mpgn = from_wkt<G>(wkt);
925         bg::reverse(open_mpgn);
926 
927         // polygon has a self-touching point
928         test::apply("mpg19", open_mpgn, bg::failure_self_intersections);
929     }
930     {
931         std::string wkt = "MULTIPOLYGON(((-1.1713032141645421 0.9370425713316406,-1.2278293047051545 0.8616467945203863,-1.2795097139219473 0.7828504914601357,-1.3261404828502752 0.7009646351604617,-1.3675375811487496 0.6163123916860891,-1.4035376333829217 0.5292278447680804,-1.4339985637934827 0.4400546773279756,-1.4588001570043776 0.3491448151183161,-1.4778445324579732 0.2568570378324778,-1.4910565307049013 0.1635555631651331,-1.4983840100240693 0.0696086094114048,-1.4997980522022116 -0.0246130577225216,-1.4952930766608652 -0.1187375883622537,-1.4848868624803642 -0.2123935159867641,-1.4686204782339323 -0.3052112234370423,-1.4465581199087858 -0.3968244016261590,-1.4187868575539013 -0.4868714951938814,-1.3854162916543107 -0.5749971294005020,-1.3465781205880585 -0.6608535126285795,-1.3024256208728704 -0.7441018089575634,-1.2531330422537639 -0.8244134753943718,-1.1988949200189114 -0.9014715584824893,-1.1399253072577331 -0.9749719451724563,-1.0764569300911435 -1.0446245630171400,-1.0087402692078766 -1.1101545249551616,-0.9370425713316382 -1.1713032141645441,-0.8616467945203836 -1.2278293047051563,-0.7828504914601331 -1.2795097139219491,-0.7009646351604588 -1.3261404828502767,-0.6163123916860862 -1.3675375811487509,-0.5292278447680773 -1.4035376333829228,-0.4400546773279725 -1.4339985637934838,-0.3491448151183129 -1.4588001570043785,-0.2568570378324746 -1.4778445324579736,-0.1635555631651299 -1.4910565307049017,-0.0696086094114016 -1.4983840100240695,0.0246130577225248 -1.4997980522022114,0.1187375883622569 -1.4952930766608650,0.2123935159867673 -1.4848868624803639,0.3052112234370455 -1.4686204782339316,0.3968244016261621 -1.4465581199087849,0.4868714951938845 -1.4187868575539002,0.5749971294005050 -1.3854162916543096,0.6608535126285824 -1.3465781205880569,0.7441018089575662 -1.3024256208728686,0.8244134753943745 -1.2531330422537621,0.9014715584824917 -1.1988949200189096,0.9749719451724583 -1.1399253072577313,1.0446245630171418 -1.0764569300911420,1.1101545249551634 -1.0087402692078746,1.1713032141645456 -0.9370425713316364,5.1713032141645456 4.0629574286683638,5.1713032141645439 4.0629574286683621,5.2278293047051561 4.1383532054796159,5.2795097139219491 4.2171495085398671,5.3261404828502767 4.2990353648395407,5.3675375811487509 4.3836876083139131,5.4035376333829230 4.4707721552319217,5.4339985637934838 4.5599453226720268,5.4588001570043785 4.6508551848816859,5.4778445324579739 4.7431429621675241,5.4910565307049017 4.8364444368348689,5.4983840100240693 4.9303913905885972,5.4997980522022116 5.0246130577225232,5.4952930766608645 5.1187375883622552,5.4848868624803639 5.2123935159867658,5.4686204782339320 5.3052112234370439,5.4465581199087856 5.3968244016261604,5.4187868575539007 5.4868714951938822,5.3854162916543107 5.5749971294005025,5.3465781205880578 5.6608535126285799,5.3024256208728699 5.7441018089575637,5.2531330422537632 5.8244134753943726,5.1988949200189110 5.9014715584824895,5.1399253072577329 5.9749719451724559,5.0764569300911440 6.0446245630171394,5.0087402692078768 6.1101545249551616,4.9370425713316379 6.1713032141645439,4.8616467945203841 6.2278293047051561,4.7828504914601337 6.2795097139219482,4.7009646351604593 6.3261404828502759,4.6163123916860869 6.3675375811487509,4.5292278447680783 6.4035376333829230,4.4400546773279732 6.4339985637934838,4.3491448151183141 6.4588001570043785,4.2568570378324750 6.4778445324579739,4.1635555631651311 6.4910565307049017,4.0696086094114028 6.4983840100240693,3.9753869422774759 6.4997980522022116,3.8812624116377439 6.4952930766608645,3.7876064840132333 6.4848868624803639,3.6947887765629552 6.4686204782339320,3.6031755983738387 6.4465581199087847,3.5131285048061165 6.4187868575539007,3.4250028705994957 6.3854162916543098,3.3391464873714183 6.3465781205880578,3.2558981910424345 6.3024256208728691,3.1755865246056261 6.2531330422537623,3.0985284415175087 6.1988949200189101,3.0250280548275423 6.1399253072577320,2.9553754369828584 6.0764569300911422,2.8898454750448366 6.0087402692078751,2.8286967858354544 5.9370425713316362,-1.1713032141645456 0.9370425713316364,-1.1713032141645421 0.9370425713316406)))";
932 
933         G open_mpgn = from_wkt<G>(wkt);
934         bg::reverse(open_mpgn);
935 
936         // polygon contains a spike
937         test::apply("mpg20", open_mpgn, bg::failure_spikes);
938     }
939 }
940 
BOOST_AUTO_TEST_CASE(test_failure_multipolygon)941 BOOST_AUTO_TEST_CASE( test_failure_multipolygon )
942 {
943     test_open_multipolygons<point_type>();
944 }
945 
BOOST_AUTO_TEST_CASE(test_failure_variant)946 BOOST_AUTO_TEST_CASE( test_failure_variant )
947 {
948 #ifdef BOOST_GEOMETRY_TEST_DEBUG
949     std::cout << std::endl << std::endl;
950     std::cout << "************************************" << std::endl;
951     std::cout << " is_valid_failure: variant support" << std::endl;
952     std::cout << "************************************" << std::endl;
953 #endif
954 
955     typedef bg::model::polygon<point_type> polygon_type; // cw, closed
956 
957     typedef boost::variant
958         <
959             linestring_type, multi_linestring_type, polygon_type
960         > variant_geometry;
961     typedef test_failure<variant_geometry> test;
962 
963     variant_geometry vg;
964 
965     linestring_type valid_linestring =
966         from_wkt<linestring_type>("LINESTRING(0 0,1 0)");
967     multi_linestring_type invalid_multi_linestring =
968         from_wkt<multi_linestring_type>("MULTILINESTRING((0 0,1 0),(0 0))");
969     polygon_type valid_polygon =
970         from_wkt<polygon_type>("POLYGON((0 0,1 1,1 0,0 0))");
971     polygon_type invalid_polygon =
972         from_wkt<polygon_type>("POLYGON((0 0,2 2,2 0,1 0))");
973 
974     vg = valid_linestring;
975     test::apply("v01", vg, bg::no_failure);
976     vg = invalid_multi_linestring;
977     test::apply("v02", vg, bg::failure_few_points);
978     vg = valid_polygon;
979     test::apply("v03", vg, bg::no_failure);
980     vg = invalid_polygon;
981     test::apply("v04", vg, bg::failure_not_closed);
982 }
983