1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2 // Unit Test
3 
4 // Copyright (c) 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_TEST_MODULE
12 #define BOOST_TEST_MODULE test_is_valid_failure
13 #endif
14 
15 #include <iostream>
16 #include <string>
17 
18 #include <boost/variant/variant.hpp>
19 
20 #include <boost/test/included/unit_test.hpp>
21 
22 #include <boost/geometry/core/cs.hpp>
23 #include <boost/geometry/geometries/geometries.hpp>
24 #include <boost/geometry/algorithms/is_valid.hpp>
25 #include <boost/geometry/algorithms/reverse.hpp>
26 #include <boost/geometry/algorithms/validity_failure_type.hpp>
27 #include <boost/geometry/io/wkt/wkt.hpp>
28 
29 #include <boost/geometry/strategies/strategies.hpp>
30 
31 #include <from_wkt.hpp>
32 
33 
34 namespace bg = ::boost::geometry;
35 
36 typedef bg::validity_failure_type failure_type;
37 
38 typedef bg::model::point<double, 2, bg::cs::cartesian> point_type;
39 typedef bg::model::segment<point_type>                 segment_type;
40 typedef bg::model::box<point_type>                     box_type;
41 typedef bg::model::linestring<point_type>              linestring_type;
42 typedef bg::model::multi_linestring<linestring_type>   multi_linestring_type;
43 typedef bg::model::multi_point<point_type>             multi_point_type;
44 
45 
to_string(failure_type failure)46 char const* to_string(failure_type failure)
47 {
48     switch (failure)
49     {
50     case bg::no_failure:
51         return "no_failure";
52     case bg::failure_few_points:
53         return "failure_few_points";
54     case bg::failure_wrong_topological_dimension:
55         return "failure_wrong_topological_dimension";
56     case bg::failure_spikes:
57         return "failure_spikes";
58     case bg::failure_duplicate_points:
59         return "failure_duplicate_points";
60     case bg::failure_not_closed:
61         return "failure_not_closed";
62     case bg::failure_self_intersections:
63         return "failure_self_intersections";
64     case bg::failure_wrong_orientation:
65         return "failure_wrong_orientation";
66     case bg::failure_interior_rings_outside:
67         return "failure_interior_rings_outside";
68     case bg::failure_nested_interior_rings:
69         return "failure_nested_interior_rings";
70     case bg::failure_disconnected_interior:
71         return "failure_disconnected_interior";
72     case bg::failure_intersecting_interiors:
73         return "failure_intersecting_interiors";
74     case bg::failure_wrong_corner_order:
75         return "failure_wrong_corner_order";
76     default:
77         return ""; // to avoid warnings (-Wreturn-type)
78     }
79 }
80 
81 
82 template <typename Geometry>
83 struct test_failure
84 {
applytest_failure85     static inline void apply(std::string const& case_id,
86                              Geometry const& geometry,
87                              failure_type expected)
88     {
89         failure_type detected;
90         bg::is_valid(geometry, detected);
91         std::string expected_msg = bg::validity_failure_type_message(expected);
92         std::string detected_msg;
93         bg::is_valid(geometry, detected_msg);
94         std::string detected_msg_short
95             = detected_msg.substr(0, expected_msg.length());
96 
97 #ifdef BOOST_GEOMETRY_TEST_DEBUG
98         std::cout << "----------------------" << std::endl;
99         std::cout << "case id: " << case_id << std::endl;
100         std::cout << "Geometry: " << bg::wkt(geometry) << std::endl;
101         std::cout << "Expected reason: " << expected_msg << std::endl;
102         std::cout << "Detected reason: " << detected_msg << std::endl;
103         std::cout << "Expected: " << to_string(expected) << std::endl;
104         std::cout << "Detected: " << to_string(detected) << std::endl;
105         std::cout << std::endl;
106 #endif
107 
108         BOOST_CHECK_MESSAGE(expected == detected,
109             "case id: " << case_id
110             << ", Geometry: " << bg::wkt(geometry)
111             << ", expected: " << to_string(expected)
112             << ", detected: " << to_string(detected));
113 
114         BOOST_CHECK(detected_msg_short == expected_msg);
115 
116 #ifdef BOOST_GEOMETRY_TEST_DEBUG
117         std::cout << "----------------------" << std::endl;
118         std::cout << std::endl << std::endl;
119 #endif
120     }
121 
applytest_failure122     static inline void apply(std::string const& case_id,
123                              std::string const& wkt,
124                              failure_type expected)
125     {
126         Geometry geometry = from_wkt<Geometry>(wkt);
127         apply(case_id, geometry, expected);
128     }
129 };
130 
131 
BOOST_AUTO_TEST_CASE(test_failure_point)132 BOOST_AUTO_TEST_CASE( test_failure_point )
133 {
134 #ifdef BOOST_GEOMETRY_TEST_DEBUG
135     std::cout << std::endl << std::endl;
136     std::cout << "************************************" << std::endl;
137     std::cout << " is_valid_failure: POINT " << std::endl;
138     std::cout << "************************************" << std::endl;
139 #endif
140 
141     typedef point_type G;
142     typedef test_failure<G> test;
143 
144     test::apply("p01", "POINT(0 0)", bg::no_failure);
145 }
146 
BOOST_AUTO_TEST_CASE(test_failure_multipoint)147 BOOST_AUTO_TEST_CASE( test_failure_multipoint )
148 {
149 #ifdef BOOST_GEOMETRY_TEST_DEBUG
150     std::cout << std::endl << std::endl;
151     std::cout << "************************************" << std::endl;
152     std::cout << " is_valid_failure: MULTIPOINT " << std::endl;
153     std::cout << "************************************" << std::endl;
154 #endif
155 
156     typedef multi_point_type G;
157     typedef test_failure<G> test;
158 
159     test::apply("mp01", "MULTIPOINT()", bg::no_failure);
160     test::apply("mp02", "MULTIPOINT(0 0,0 0)", bg::no_failure);
161     test::apply("mp03", "MULTIPOINT(0 0,1 0,1 1,0 1)", bg::no_failure);
162     test::apply("mp04", "MULTIPOINT(0 0,1 0,1 1,1 0,0 1)", bg::no_failure);
163 }
164 
BOOST_AUTO_TEST_CASE(test_failure_segment)165 BOOST_AUTO_TEST_CASE( test_failure_segment )
166 {
167 #ifdef BOOST_GEOMETRY_TEST_DEBUG
168     std::cout << std::endl << std::endl;
169     std::cout << "************************************" << std::endl;
170     std::cout << " is_valid_failure: SEGMENT " << std::endl;
171     std::cout << "************************************" << std::endl;
172 #endif
173 
174     typedef segment_type G;
175     typedef test_failure<G> test;
176 
177     test::apply("s01",
178                 "SEGMENT(0 0,0 0)",
179                 bg::failure_wrong_topological_dimension);
180     test::apply("s02", "SEGMENT(0 0,1 0)", bg::no_failure);
181 }
182 
BOOST_AUTO_TEST_CASE(test_failure_box)183 BOOST_AUTO_TEST_CASE( test_failure_box )
184 {
185 #ifdef BOOST_GEOMETRY_TEST_DEBUG
186     std::cout << std::endl << std::endl;
187     std::cout << "************************************" << std::endl;
188     std::cout << " is_valid_failure: BOX " << std::endl;
189     std::cout << "************************************" << std::endl;
190 #endif
191 
192     typedef box_type G;
193     typedef test_failure<G> test;
194 
195     // boxes where the max corner and below and/or to the left of min corner
196     test::apply("b01",
197                 "BOX(0 0,-1 0)",
198                 bg::failure_wrong_topological_dimension);
199     test::apply("b02", "BOX(0 0,0 -1)", bg::failure_wrong_corner_order);
200     test::apply("b03", "BOX(0 0,-1 -1)", bg::failure_wrong_corner_order);
201 
202     // boxes of zero area; they are not 2-dimensional, so invalid
203     test::apply("b04", "BOX(0 0,0 0)", bg::failure_wrong_topological_dimension);
204     test::apply("b05", "BOX(0 0,1 0)", bg::failure_wrong_topological_dimension);
205     test::apply("b06", "BOX(0 0,0 1)", bg::failure_wrong_topological_dimension);
206 
207     test::apply("b07", "BOX(0 0,1 1)", bg::no_failure);
208 }
209 
BOOST_AUTO_TEST_CASE(test_failure_linestring)210 BOOST_AUTO_TEST_CASE( test_failure_linestring )
211 {
212 #ifdef BOOST_GEOMETRY_TEST_DEBUG
213     std::cout << std::endl << std::endl;
214     std::cout << "************************************" << std::endl;
215     std::cout << " is_valid_failure: LINESTRING " << std::endl;
216     std::cout << "************************************" << std::endl;
217 #endif
218 
219     typedef linestring_type G;
220     typedef test_failure<G> test;
221 
222     // empty linestring
223     test::apply("l01", "LINESTRING()", bg::failure_few_points);
224 
225     // 1-point linestrings
226     test::apply("l02", "LINESTRING(0 0)", bg::failure_few_points);
227     test::apply("l03",
228                 "LINESTRING(0 0,0 0)",
229                 bg::failure_wrong_topological_dimension);
230     test::apply("l04",
231                 "LINESTRING(0 0,0 0,0 0)",
232                 bg::failure_wrong_topological_dimension);
233 
234     // 2-point linestrings
235     test::apply("l05", "LINESTRING(0 0,1 2)", bg::no_failure);
236     test::apply("l06", "LINESTRING(0 0,1 2,1 2)", bg::no_failure);
237     test::apply("l07", "LINESTRING(0 0,0 0,1 2,1 2)", bg::no_failure);
238     test::apply("l08", "LINESTRING(0 0,0 0,0 0,1 2,1 2)", bg::no_failure);
239 
240     // 3-point linestring
241     test::apply("l09", "LINESTRING(0 0,1 0,2 10)", bg::no_failure);
242 
243     // linestrings with spikes
244     test::apply("l10", "LINESTRING(0 0,1 2,0 0)", bg::no_failure);
245 }
246 
BOOST_AUTO_TEST_CASE(test_failure_multilinestring)247 BOOST_AUTO_TEST_CASE( test_failure_multilinestring )
248 {
249 #ifdef BOOST_GEOMETRY_TEST_DEBUG
250     std::cout << std::endl << std::endl;
251     std::cout << "************************************" << std::endl;
252     std::cout << " is_valid_failure: MULTILINESTRING " << std::endl;
253     std::cout << "************************************" << std::endl;
254 #endif
255 
256     typedef multi_linestring_type G;
257     typedef test_failure<G> test;
258 
259     // empty multilinestring
260     test::apply("mls01", "MULTILINESTRING()", bg::no_failure);
261 
262     // multilinestring with empty linestring(s)
263     test::apply("mls02", "MULTILINESTRING(())", bg::failure_few_points);
264     test::apply("mls03", "MULTILINESTRING((),(),())", bg::failure_few_points);
265     test::apply("mls04",
266                 "MULTILINESTRING((),(0 1,1 0))",
267                 bg::failure_few_points);
268 
269     // multilinestring with invalid linestrings
270     test::apply("mls05",
271                 "MULTILINESTRING((0 0),(0 1,1 0))",
272                 bg::failure_few_points);
273     test::apply("mls06",
274                 "MULTILINESTRING((0 0,0 0),(0 1,1 0))",
275                 bg::failure_wrong_topological_dimension);
276     test::apply("mls07", "MULTILINESTRING((0 0),(1 0))",
277                 bg::failure_few_points);
278     test::apply("mls08",
279                 "MULTILINESTRING((0 0,0 0),(1 0,1 0))",
280                 bg::failure_wrong_topological_dimension);
281     test::apply("mls09",
282                 "MULTILINESTRING((0 0),(0 0))",
283                 bg::failure_few_points);
284     test::apply("mls10",
285                 "MULTILINESTRING((0 0,1 0,0 0),(5 0))",
286                 bg::failure_few_points);
287 
288     // multilinstring that has linestrings with spikes
289     test::apply("mls11",
290                 "MULTILINESTRING((0 0,1 0,0 0),(5 0,1 0,4 1))",
291                 bg::no_failure);
292     test::apply("mls12",
293                 "MULTILINESTRING((0 0,1 0,0 0),(1 0,2 0))",
294                 bg::no_failure);
295 
296     // valid multilinestrings
297     test::apply("mls13",
298                 "MULTILINESTRING((0 0,1 0,2 0),(5 0,1 0,4 1))",
299                 bg::no_failure);
300     test::apply("mls14",
301                 "MULTILINESTRING((0 0,1 0,2 0),(1 0,2 0))",
302                 bg::no_failure);
303     test::apply("mls15",
304                 "MULTILINESTRING((0 0,1 1),(0 1,1 0))",
305                 bg::no_failure);
306     test::apply("mls16",
307                 "MULTILINESTRING((0 0,1 1,2 2),(0 1,1 0,2 2))",
308                 bg::no_failure);
309 }
310 
311 template <typename Point>
test_open_rings()312 inline void test_open_rings()
313 {
314 #ifdef BOOST_GEOMETRY_TEST_DEBUG
315     std::cout << std::endl << std::endl;
316     std::cout << "************************************" << std::endl;
317     std::cout << " is_valid_failure: RING (open) " << std::endl;
318     std::cout << "************************************" << std::endl;
319 #endif
320 
321     typedef bg::model::ring<Point, false, false> G; // ccw, open ring
322     typedef test_failure<G> test;
323 
324     // not enough points
325     test::apply("r01", "POLYGON(())", bg::failure_few_points);
326     test::apply("r02", "POLYGON((0 0))", bg::failure_few_points);
327     test::apply("r03", "POLYGON((0 0,1 0))", bg::failure_few_points);
328 
329     // duplicate points
330     test::apply("r04",
331                 "POLYGON((0 0,0 0,0 0))",
332                 bg::failure_wrong_topological_dimension);
333     test::apply("r05",
334                 "POLYGON((0 0,1 0,1 0))",
335                 bg::failure_wrong_topological_dimension);
336     test::apply("r06",
337                 "POLYGON((0 0,1 0,0 0))",
338                 bg::failure_wrong_topological_dimension);
339     test::apply("r07", "POLYGON((0 0,1 0,1 1,0 0,0 0))", bg::no_failure);
340     test::apply("r08", "POLYGON((0 0,1 0,1 0,1 1))", bg::no_failure);
341     test::apply("r09", "POLYGON((0 0,1 0,1 0,1 1,0 0))", bg::no_failure);
342 
343     // with spikes
344     test::apply("r10", "POLYGON((0 0,2 0,2 2,0 2,1 2))", bg::failure_spikes);
345     test::apply("r11", "POLYGON((0 0,2 0,1 0,2 2))", bg::failure_spikes);
346     test::apply("r12",
347                 "POLYGON((0 0,1 0,2 0,1 0,4 0,4 4))",
348                 bg::failure_spikes);
349     test::apply("r13", "POLYGON((0 0,2 0,2 2,1 0))", bg::failure_spikes);
350     test::apply("r14", "POLYGON((0 0,2 0,1 0))", bg::failure_spikes);
351     test::apply("r15",
352                 "POLYGON((0 0,5 0,5 5,4 4,5 5,0 5))",
353                 bg::failure_spikes);
354     test::apply("r16",
355                 "POLYGON((0 0,5 0,5 5,4 4,3 3,5 5,0 5))",
356                 bg::failure_spikes);
357 
358     // with spikes and duplicate points
359     test::apply("r17",
360                 "POLYGON((0 0,0 0,2 0,2 0,1 0,1 0))",
361                 bg::failure_spikes);
362 
363     // with self-crossings
364     test::apply("r18",
365                 "POLYGON((0 0,5 0,5 5,3 -1,0 5))",
366                 bg::failure_self_intersections);
367 
368     // with self-crossings and duplicate points
369     test::apply("r19",
370                 "POLYGON((0 0,5 0,5 5,5 5,3 -1,0 5,0 5))",
371                 bg::failure_self_intersections);
372 
373     // with self-intersections
374     test::apply("r20",
375                 "POLYGON((0 0,5 0,5 5,3 5,3 0,2 0,2 5,0 5))",
376                 bg::failure_self_intersections);
377     test::apply("r21",
378                 "POLYGON((0 0,5 0,5 5,3 5,3 0,2 5,0 5))",
379                 bg::failure_self_intersections);
380     test::apply("r22",
381                 "POLYGON((0 0,5 0,5 1,1 1,1 2,2 2,3 1,4 2,5 2,5 5,0 5))",
382                 bg::failure_self_intersections);
383 
384     // with self-intersections and duplicate points
385     test::apply("r23",
386                 "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))",
387                 bg::failure_self_intersections);
388 
389     // next two suggested by Adam Wulkiewicz
390     test::apply("r24",
391                 "POLYGON((0 0,5 0,5 5,0 5,4 4,2 2,0 5))",
392                 bg::failure_self_intersections);
393     test::apply("r25",
394                 "POLYGON((0 0,5 0,5 5,1 4,4 4,4 1,0 5))",
395                 bg::failure_self_intersections);
396 
397     // and a few more
398     test::apply("r26",
399                 "POLYGON((0 0,5 0,5 5,4 4,1 4,1 1,4 1,4 4,0 5))",
400                 bg::failure_self_intersections);
401     test::apply("r27",
402                 "POLYGON((0 0,5 0,5 5,4 4,4 1,1 1,1 4,4 4,0 5))",
403                 bg::failure_self_intersections);
404 
405     // valid rings
406     test::apply("r28", "POLYGON((0 0,1 0,1 1))", bg::no_failure);
407     test::apply("r29", "POLYGON((1 0,1 1,0 0))", bg::no_failure);
408     test::apply("r30", "POLYGON((0 0,1 0,1 1,0 1))", bg::no_failure);
409     test::apply("r31", "POLYGON((1 0,1 1,0 1,0 0))", bg::no_failure);
410 
411     // test cases coming from buffer
412     test::apply("r32",
413                 "POLYGON((1.1713032141645456 -0.9370425713316364,\
414                           5.1713032141645456 4.0629574286683638,\
415                           4.7808688094430307 4.3753049524455756,\
416                           4.7808688094430307 4.3753049524455756,\
417                           0.7808688094430304 -0.6246950475544243,\
418                           0.7808688094430304 -0.6246950475544243))",
419                 bg::no_failure);
420 
421     // wrong orientation
422     test::apply("r33",
423                 "POLYGON((0 0,0 1,1 1,0 0))",
424                 bg::failure_wrong_orientation);
425 }
426 
427 template <typename Point>
test_closed_rings()428 void test_closed_rings()
429 {
430 #ifdef BOOST_GEOMETRY_TEST_DEBUG
431     std::cout << std::endl << std::endl;
432     std::cout << "************************************" << std::endl;
433     std::cout << " is_valid_failure: RING (closed) " << std::endl;
434     std::cout << "************************************" << std::endl;
435 #endif
436 
437     typedef bg::model::ring<Point, false, true> G; // ccw, closed ring
438     typedef test_failure<G> test;
439 
440     // not enough points
441     test::apply("r01c", "POLYGON(())", bg::failure_few_points);
442     test::apply("r02c", "POLYGON((0 0))", bg::failure_few_points);
443     test::apply("r03c", "POLYGON((0 0,0 0))", bg::failure_few_points);
444     test::apply("r04c", "POLYGON((0 0,1 0))", bg::failure_few_points);
445     test::apply("r05c", "POLYGON((0 0,1 0,1 0))", bg::failure_few_points);
446     test::apply("r06c", "POLYGON((0 0,1 0,2 0))", bg::failure_few_points);
447     test::apply("r07c",
448                 "POLYGON((0 0,1 0,1 0,2 0))",
449                 bg::failure_wrong_topological_dimension);
450     test::apply("r08c",
451                 "POLYGON((0 0,1 0,2 0,2 0))",
452                 bg::failure_wrong_topological_dimension);
453 
454     // boundary not closed
455     test::apply("r09c", "POLYGON((0 0,1 0,1 1,1 2))", bg::failure_not_closed);
456     test::apply("r10c",
457                 "POLYGON((0 0,1 0,1 0,1 1,1 1,1 2))",
458                 bg::failure_not_closed);
459 
460     // with spikes
461     test::apply("r11c", "POLYGON((0 0,1 0,1 0,2 0,0 0))", bg::failure_spikes);
462     test::apply("r12c",
463                 "POLYGON((0 0,1 0,1 1,2 2,0.5 0.5,0 1,0 0))",
464                 bg::failure_spikes);
465 
466     // wrong orientation
467     test::apply("r13c",
468                 "POLYGON((0 0,0 1,1 1,2 0,0 0))",
469                 bg::failure_wrong_orientation);
470 
471 }
472 
BOOST_AUTO_TEST_CASE(test_failure_ring)473 BOOST_AUTO_TEST_CASE( test_failure_ring )
474 {
475     test_open_rings<point_type>();
476     test_closed_rings<point_type>();
477 }
478 
479 
480 template <typename Point>
test_open_polygons()481 void test_open_polygons()
482 {
483 #ifdef BOOST_GEOMETRY_TEST_DEBUG
484     std::cout << std::endl << std::endl;
485     std::cout << "************************************" << std::endl;
486     std::cout << " is_valid_failure: POLYGON (open) " << std::endl;
487     std::cout << "************************************" << std::endl;
488 #endif
489 
490     typedef bg::model::polygon<Point, false, false> G; // ccw, open
491     typedef test_failure<G> test;
492 
493     // not enough points in exterior ring
494     test::apply("pg001", "POLYGON(())", bg::failure_few_points);
495     test::apply("pg002", "POLYGON((0 0))", bg::failure_few_points);
496     test::apply("pg003", "POLYGON((0 0,1 0))", bg::failure_few_points);
497 
498     // not enough points in interior ring
499     test::apply("pg004",
500                 "POLYGON((0 0,10 0,10 10,0 10),())",
501                 bg::failure_few_points);
502     test::apply("pg005",
503                 "POLYGON((0 0,10 0,10 10,0 10),(1 1))",
504                 bg::failure_few_points);
505     test::apply("pg006",
506                 "POLYGON((0 0,10 0,10 10,0 10),(1 1,2 2))",
507                 bg::failure_few_points);
508 
509     // duplicate points in exterior ring
510     test::apply("pg007",
511                 "POLYGON((0 0,0 0,0 0))",
512                 bg::failure_wrong_topological_dimension);
513     test::apply("pg008",
514                 "POLYGON((0 0,1 0,1 0))",
515                 bg::failure_wrong_topological_dimension);
516     test::apply("pg009",
517                 "POLYGON((0 0,1 0,0 0))",
518                 bg::failure_wrong_topological_dimension);
519     test::apply("pg010", "POLYGON((0 0,1 0,1 1,0 0,0 0))", bg::no_failure);
520     test::apply("pg011", "POLYGON((0 0,1 0,1 0,1 1))", bg::no_failure);
521     test::apply("pg012", "POLYGON((0 0,1 0,1 0,1 1,0 0))",  bg::no_failure);
522 
523     test::apply("pg013",
524                 "POLYGON((0 0,10 0,10 10,0 10),(1 1,1 1,1 1))",
525                 bg::failure_wrong_topological_dimension);
526     test::apply("pg014",
527                 "POLYGON((0 0,10 0,10 10,0 10),(1 1,2 1,2 1))",
528                 bg::failure_wrong_topological_dimension);
529     test::apply("pg015",
530                 "POLYGON((0 0,10 0,10 10,0 10),(1 1,2 1,1 1))",
531                 bg::failure_wrong_topological_dimension);
532     test::apply("pg016",
533                 "POLYGON((0 0,10 0,10 10,0 10),(1 1,2 2,2 1,1 1,1 1))",
534                 bg::no_failure);
535     test::apply("pg017",
536                 "POLYGON((0 0,10 0,10 10,0 10),(1 1,2 2,2 2,2 1))",
537                 bg::no_failure);
538     test::apply("pg018",
539                 "POLYGON((0 0,10 0,10 10,0 10),(1 1,2 2,2 1,2 1,1 1))",
540                 bg::no_failure);
541 
542     // with spikes in exterior ring
543     test::apply("pg019", "POLYGON((0 0,2 0,2 2,0 2,1 2))", bg::failure_spikes);
544     test::apply("pg020", "POLYGON((0 0,2 0,1 0,2 2))", bg::failure_spikes);
545     test::apply("pg021",
546                 "POLYGON((0 0,1 0,2 0,1 0,4 0,4 4))",
547                 bg::failure_spikes);
548     test::apply("pg022", "POLYGON((0 0,2 0,2 2,1 0))", bg::failure_spikes);
549     test::apply("pg023", "POLYGON((0 0,2 0,1 0))", bg::failure_spikes);
550     test::apply("pg024",
551                 "POLYGON((0 0,5 0,5 5,4 4,5 5,0 5))",
552                 bg::failure_spikes);
553     test::apply("pg025",
554                 "POLYGON((0 0,5 0,5 5,4 4,3 3,5 5,0 5))",
555                 bg::failure_spikes);
556 
557     // with spikes in interior ring
558     test::apply("pg026",
559                 "POLYGON((0 0,10 0,10 10,0 10),(1 1,3 1,3 3,1 3,2 3))",
560                 bg::failure_spikes);
561     test::apply("pg027",
562                 "POLYGON((0 0,10 0,10 10,0 10),(1 1,3 1,2 1,3 3))",
563                 bg::failure_spikes);
564     test::apply("pg028",
565                 "POLYGON((0 0,10 0,10 10,0 10),(1 1,2 1,3 1,2 1,4 1,4 4))",
566                 bg::failure_spikes);
567     test::apply("pg029",
568                 "POLYGON((0 0,10 0,10 10,0 10),(1 1,3 1,3 3,2 1))",
569                 bg::failure_spikes);
570     test::apply("pg030",
571                 "POLYGON((0 0,10 0,10 10,0 10),(1 1,3 1,2 1))",
572                 bg::failure_spikes);
573 
574     // with self-crossings in exterior ring
575     test::apply("pg031",
576                 "POLYGON((0 0,5 0,5 5,3 -1,0 5))",
577                 bg::failure_self_intersections);
578 
579     // example from Norvald Ryeng
580     test::apply("pg032",
581                 "POLYGON((100 1300,140 1300,140 170,100 1700))",
582                 bg::failure_wrong_orientation);
583     // and with point order reversed
584     test::apply("pg033",
585                 "POLYGON((100 1300,100 1700,140 170,140 1300))",
586                 bg::failure_self_intersections);
587 
588     // with self-crossings in interior ring
589     // the self-crossing causes the area of the interior ring to have
590     // the wrong sign, hence the "wrong orientation" failure
591     test::apply("pg034",
592                 "POLYGON((0 0,10 0,10 10,0 10),(3 3,3 7,4 6,2 6))",
593                 bg::failure_wrong_orientation);
594 
595     // with self-crossings between rings
596     test::apply("pg035",
597                 "POLYGON((0 0,5 0,5 5,0 5),(1 1,2 1,1 -1))",
598                 bg::failure_self_intersections);
599 
600     // with self-intersections in exterior ring
601     test::apply("pg036",
602                 "POLYGON((0 0,5 0,5 5,3 5,3 0,2 0,2 5,0 5))",
603                 bg::failure_self_intersections);
604     test::apply("pg037",
605                 "POLYGON((0 0,5 0,5 5,3 5,3 0,2 5,0 5))",
606                 bg::failure_self_intersections);
607     test::apply("pg038",
608                 "POLYGON((0 0,5 0,5 1,1 1,1 2,2 2,3 1,4 2,5 2,5 5,0 5))",
609                 bg::failure_self_intersections);
610 
611     // next two suggested by Adam Wulkiewicz
612     test::apply("pg039",
613                 "POLYGON((0 0,5 0,5 5,0 5,4 4,2 2,0 5))",
614                 bg::failure_self_intersections);
615     test::apply("pg040",
616                 "POLYGON((0 0,5 0,5 5,1 4,4 4,4 1,0 5))",
617                 bg::failure_self_intersections);
618     test::apply("pg041",
619                 "POLYGON((0 0,5 0,5 5,4 4,1 4,1 1,4 1,4 4,0 5))",
620                 bg::failure_self_intersections);
621     test::apply("pg042",
622                 "POLYGON((0 0,5 0,5 5,4 4,4 1,1 1,1 4,4 4,0 5))",
623                 bg::failure_self_intersections);
624 
625     // with self-intersections in interior ring
626 
627     // same comment as for pg034
628     test::apply("pg043",
629                 "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))",
630                 bg::failure_wrong_orientation);
631 
632     // same comment as for pg034
633     test::apply("pg044",
634                 "POLYGON((-10 -10,10 -10,10 10,-10 10),(0 0,5 0,5 5,3 5,3 0,2 5,0 5))",
635                 bg::failure_wrong_orientation);
636 
637     // same comment as for pg034
638     test::apply("pg045",
639                 "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))",
640                 bg::failure_wrong_orientation);
641 
642     // with self-intersections between rings
643     // hole has common segment with exterior ring
644     test::apply("pg046",
645                 "POLYGON((0 0,10 0,10 10,0 10),(1 1,1 10,2 10,2 1))",
646                 bg::failure_self_intersections);
647     test::apply("pg047",
648                 "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))",
649                 bg::failure_self_intersections);
650     // hole touches exterior ring at one point
651     test::apply("pg048",
652                 "POLYGON((0 0,10 0,10 10,0 10),(1 1,1 10,2 1))",
653                 bg::no_failure);
654 
655     // "hole" is outside the exterior ring, but touches it
656     // TODO: return the failure value failure_interior_rings_outside
657     test::apply("pg049",
658                 "POLYGON((0 0,10 0,10 10,0 10),(5 10,4 11,6 11))",
659                 bg::failure_self_intersections);
660 
661     // hole touches exterior ring at vertex
662     test::apply("pg050",
663                 "POLYGON((0 0,10 0,10 10,0 10),(0 0,1 4,4 1))",
664                 bg::no_failure);
665 
666     // "hole" is completely outside the exterior ring
667     test::apply("pg051",
668                 "POLYGON((0 0,10 0,10 10,0 10),(20 20,20 21,21 21,21 20))",
669                 bg::failure_interior_rings_outside);
670 
671     // two "holes" completely outside the exterior ring, that touch
672     // each other
673     test::apply("pg052",
674                 "POLYGON((0 0,10 0,10 10,0 10),(20 0,25 10,21 0),(30 0,25 10,31 0))",
675                 bg::failure_interior_rings_outside);
676 
677     // example from Norvald Ryeng
678     test::apply("pg053",
679                 "POLYGON((58 31,56.57 30,62 33),(35 9,28 14,31 16),(23 11,29 5,26 4))",
680                 bg::failure_interior_rings_outside);
681     // and with points reversed
682     test::apply("pg054",
683                 "POLYGON((58 31,62 33,56.57 30),(35 9,31 16,28 14),(23 11,26 4,29 5))",
684                 bg::failure_wrong_orientation);
685 
686     // "hole" is completely inside another "hole"
687     test::apply("pg055",
688                 "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))",
689                 bg::failure_nested_interior_rings);
690     test::apply("pg056",
691                 "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))",
692                 bg::failure_wrong_orientation);
693 
694     // "hole" is inside another "hole" (touching)
695     // TODO: return the failure value failure_nested_interior_rings
696     test::apply("pg057",
697                 "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))",
698                 bg::failure_self_intersections);
699     // TODO: return the failure value failure_nested_interior_rings
700     test::apply("pg058",
701                 "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))",
702                 bg::failure_self_intersections);
703     test::apply("pg058a",
704                 "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))",
705                 bg::failure_wrong_orientation);
706     // TODO: return the failure value failure_nested_interior_rings
707     test::apply("pg059",
708                 "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))",
709                 bg::failure_self_intersections);
710     test::apply("pg059a",
711                 "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))",
712                 bg::failure_wrong_orientation);
713     // TODO: return the failure value failure_nested_interior_rings
714     test::apply("pg060",
715                 "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))",
716                 bg::failure_self_intersections);
717     test::apply("pg060a",
718                 "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))",
719                 bg::failure_wrong_orientation);
720     // hole touches exterior ring at two points
721     test::apply("pg061",
722                 "POLYGON((0 0,10 0,10 10,0 10),(5 0,0 5,5 5))",
723                 bg::failure_disconnected_interior);
724 
725     // cases with more holes
726     // two holes, touching the exterior at the same point
727     test::apply("pg062",
728                 "POLYGON((0 0,10 0,10 10,0 10),(0 0,1 9,2 9),(0 0,9 2,9 1))",
729                 bg::no_failure);
730     test::apply("pg063",
731                 "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))",
732                 bg::no_failure);
733     test::apply("pg063",
734                 "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))",
735                 bg::no_failure);
736     // two holes, one inside the other
737     // TODO: return the failure value failure_nested_interior_rings
738     test::apply("pg064",
739                 "POLYGON((0 0,10 0,10 10,0 10),(0 0,1 9,9 1),(0 0,4 5,5 4))",
740                 bg::failure_self_intersections);
741     // 1st hole touches has common segment with 2nd hole
742     test::apply("pg066",
743                 "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))",
744                 bg::failure_self_intersections);
745     // 1st hole touches 2nd hole at two points
746     test::apply("pg067",
747                 "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))",
748                 bg::failure_disconnected_interior);
749     // polygon with many holes, where the last two touch at two points
750     test::apply("pg068",
751                 "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))",
752                 bg::failure_disconnected_interior);
753     // two holes completely inside exterior ring but touching each
754     // other at a point
755     test::apply("pg069",
756                 "POLYGON((0 0,10 0,10 10,0 10),(1 1,1 9,2 9),(1 1,9 2,9 1))",
757                 bg::no_failure);
758     // four holes, each two touching at different points
759     test::apply("pg070",
760                 "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))",
761                 bg::no_failure);
762     // five holes, with two pairs touching each at some point, and
763     // fifth hole creating a disconnected component for the interior
764     test::apply("pg071",
765                 "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))",
766                 bg::failure_disconnected_interior);
767     // five holes, with two pairs touching each at some point, and
768     // fifth hole creating three disconnected components for the interior
769     test::apply("pg072",
770                 "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))",
771                 bg::failure_disconnected_interior);
772 
773     // both examples: a polygon with one hole, where the hole contains
774     // the exterior ring
775     test::apply("pg073",
776                 "POLYGON((0 0,1 0,1 1,0 1),(-10 -10,-10 10,10 10,10 -10))",
777                 bg::failure_interior_rings_outside);
778     // TODO: return the failure value failure_interior_rings_outside
779     test::apply("pg074",
780                 "POLYGON((-10 -10,1 0,1 1,0 1),(-10 -10,-10 10,10 10,10 -10))",
781                 bg::failure_self_intersections);
782 }
783 
784 template <typename Point>
test_doc_example_polygon()785 inline void test_doc_example_polygon()
786 {
787 #ifdef BOOST_GEOMETRY_TEST_DEBUG
788     std::cout << std::endl << std::endl;
789     std::cout << "************************************" << std::endl;
790     std::cout << " is_valid_failure: doc example polygon " << std::endl;
791     std::cout << "************************************" << std::endl;
792 #endif
793 
794     typedef bg::model::polygon<Point> CCW_CG;
795     typedef test_failure<CCW_CG> test;
796 
797     test::apply("pg-doc",
798                 "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))",
799                 bg::failure_disconnected_interior);
800 }
801 
BOOST_AUTO_TEST_CASE(test_failure_polygon)802 BOOST_AUTO_TEST_CASE( test_failure_polygon )
803 {
804     test_open_polygons<point_type>();
805     test_doc_example_polygon<point_type>();
806 }
807 
808 
809 template <typename Point>
test_open_multipolygons()810 void test_open_multipolygons()
811 {
812 #ifdef BOOST_GEOMETRY_TEST_DEBUG
813     std::cout << std::endl << std::endl;
814     std::cout << "************************************" << std::endl;
815     std::cout << " is_valid_failure: MULTIPOLYGON (open) " << std::endl;
816     std::cout << "************************************" << std::endl;
817 #endif
818 
819     typedef bg::model::polygon<point_type,false,false> ccw_open_polygon_type;
820     typedef bg::model::multi_polygon<ccw_open_polygon_type> G;
821 
822     typedef test_failure<G> test;
823 
824     // not enough points
825     test::apply("mpg01", "MULTIPOLYGON()", bg::no_failure);
826     test::apply("mpg02", "MULTIPOLYGON((()))", bg::failure_few_points);
827     test::apply("mpg03", "MULTIPOLYGON(((0 0)),(()))", bg::failure_few_points);
828     test::apply("mpg04", "MULTIPOLYGON(((0 0,1 0)))", bg::failure_few_points);
829 
830     // two disjoint polygons
831     test::apply("mpg05",
832                 "MULTIPOLYGON(((0 0,1 0,1 1,0 1)),((2 2,3 2,3 3,2 3)))",
833                 bg::no_failure);
834 
835     // two disjoint polygons with multiple points
836     test::apply("mpg06",
837                 "MULTIPOLYGON(((0 0,1 0,1 0,1 1,0 1)),((2 2,3 2,3 3,3 3,2 3)))",
838                 bg::no_failure);
839 
840     // two polygons touch at a point
841     test::apply("mpg07",
842                 "MULTIPOLYGON(((0 0,1 0,1 1,0 1)),((1 1,2 1,2 2,1 2)))",
843                 bg::no_failure);
844 
845     // two polygons share a segment at a point
846     test::apply("mpg08",
847                 "MULTIPOLYGON(((0 0,1.5 0,1.5 1,0 1)),((1 1,2 1,2 2,1 2)))",
848                 bg::failure_self_intersections);
849 
850     // one polygon inside another and boundaries touching
851     // TODO: return the failure value failure_intersecting_interiors
852     test::apply("mpg09",
853                 "MULTIPOLYGON(((0 0,10 0,10 10,0 10)),((0 0,9 1,9 2)))",
854                 bg::failure_self_intersections);
855 
856     // one polygon inside another and boundaries not touching
857     test::apply("mpg10",
858                 "MULTIPOLYGON(((0 0,10 0,10 10,0 10)),((1 1,9 1,9 2)))",
859                 bg::failure_intersecting_interiors);
860 
861     // free space is disconnected
862     test::apply("mpg11",
863                 "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)))",
864                 bg::no_failure);
865 
866     // multi-polygon with a polygon inside the hole of another polygon
867     test::apply("mpg12",
868                 "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)))",
869                 bg::no_failure);
870     test::apply("mpg13",
871                 "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)))",
872                 bg::no_failure);
873 
874     // test case suggested by Barend Gehrels: take two valid polygons P1 and
875     // P2 with holes H1 and H2, respectively, and consider P2 to be
876     // fully inside H1; now invalidate the multi-polygon by
877     // considering H2 as a hole of P1 and H1 as a hole of P2; this
878     // should be invalid
879     //
880     // first the valid case:
881     test::apply("mpg14",
882                 "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)))",
883                 bg::no_failure);
884     // and the invalid case:
885     test::apply("mpg15",
886                 "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)))",
887                 bg::failure_interior_rings_outside);
888 
889     test::apply
890         ("mpg16",
891          "MULTIPOLYGON(((-1 4,8 -10,-10 10,7 -6,8 -2,\
892                       -10 10,-10 1,-3 -4,4 1,-1 2,4 3,-8 10,-5 -9,-1 6,-5 0)),\
893                       ((-10 -3,-8 1,2 -8,-2 6,-4 0,8 -5,-1 5,8 2)),\
894                       ((-6 -10,1 10,4 -8,-7 -2,2 0,-4 3,-10 9)),\
895                       ((10 -1,-2 8,-7 3,-6 8,-9 -7,7 -5)),\
896                       ((7 7,-4 -4,9 -8,-10 -6)))",
897          bg::failure_wrong_orientation);
898 
899     test::apply
900         ("mpg17",
901          "MULTIPOLYGON(((-1 4,8 -10,-10 10,7 -6,8 -2,\
902                       -10 10,-10 1,-3 -4,4 1,-1 2,4 3,-8 10,-5 -9,-1 6,-5 0)),\
903                       ((-10 -3,-8 1,2 -8,-2 6,-4 0,8 -5,-1 5,8 2)),\
904                       ((-6 -10,-10 9,-4 3,2 0,-7 -2,4 -8,1 10)),\
905                       ((10 -1,-2 8,-7 3,-6 8,-9 -7,7 -5)),\
906                       ((7 7,-10 -6,9 -8,-4 -4)))",
907          bg::failure_spikes);
908 
909     // test cases coming from buffer
910     {
911         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)))";
912 
913         G open_mpgn = from_wkt<G>(wkt);
914         bg::reverse(open_mpgn);
915 
916         test::apply("mpg18", open_mpgn, bg::failure_wrong_orientation);
917     }
918     {
919         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)))";
920 
921         G open_mpgn = from_wkt<G>(wkt);
922         bg::reverse(open_mpgn);
923 
924         // polygon has a self-touching point
925         test::apply("mpg19", open_mpgn, bg::failure_self_intersections);
926     }
927     {
928         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)))";
929 
930         G open_mpgn = from_wkt<G>(wkt);
931         bg::reverse(open_mpgn);
932 
933         // polygon contains a spike
934         test::apply("mpg20", open_mpgn, bg::failure_spikes);
935     }
936 }
937 
BOOST_AUTO_TEST_CASE(test_failure_multipolygon)938 BOOST_AUTO_TEST_CASE( test_failure_multipolygon )
939 {
940     test_open_multipolygons<point_type>();
941 }
942 
BOOST_AUTO_TEST_CASE(test_failure_variant)943 BOOST_AUTO_TEST_CASE( test_failure_variant )
944 {
945 #ifdef BOOST_GEOMETRY_TEST_DEBUG
946     std::cout << std::endl << std::endl;
947     std::cout << "************************************" << std::endl;
948     std::cout << " is_valid_failure: variant support" << std::endl;
949     std::cout << "************************************" << std::endl;
950 #endif
951 
952     typedef bg::model::polygon<point_type> polygon_type; // cw, closed
953 
954     typedef boost::variant
955         <
956             linestring_type, multi_linestring_type, polygon_type
957         > variant_geometry;
958     typedef test_failure<variant_geometry> test;
959 
960     variant_geometry vg;
961 
962     linestring_type valid_linestring =
963         from_wkt<linestring_type>("LINESTRING(0 0,1 0)");
964     multi_linestring_type invalid_multi_linestring =
965         from_wkt<multi_linestring_type>("MULTILINESTRING((0 0,1 0),(0 0))");
966     polygon_type valid_polygon =
967         from_wkt<polygon_type>("POLYGON((0 0,1 1,1 0,0 0))");
968     polygon_type invalid_polygon =
969         from_wkt<polygon_type>("POLYGON((0 0,2 2,2 0,1 0))");
970 
971     vg = valid_linestring;
972     test::apply("v01", vg, bg::no_failure);
973     vg = invalid_multi_linestring;
974     test::apply("v02", vg, bg::failure_few_points);
975     vg = valid_polygon;
976     test::apply("v03", vg, bg::no_failure);
977     vg = invalid_polygon;
978     test::apply("v04", vg, bg::failure_not_closed);
979 }
980