1 // Boost.Geometry (aka GGL, Generic Geometry Library)
4 // Copyright (c) 2010-2015 Barend Gehrels, Amsterdam, the Netherlands.
6 // This file was modified by Oracle on 2021.
7 // Modifications copyright (c) 2021, Oracle and/or its affiliates.
8 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
10 // Use, modification and distribution is subject to the Boost Software License,
11 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
12 // http://www.boost.org/LICENSE_1_0.txt)
14 #define BOOST_GEOMETRY_DEFINE_STREAM_OPERATOR_SEGMENT_RATIO
22 #include <geometry_test_common.hpp>
25 // #define BOOST_GEOMETRY_DEBUG_ENRICH
26 //#define BOOST_GEOMETRY_DEBUG_RELATIVE_ORDER
28 // #define BOOST_GEOMETRY_DEBUG_SEGMENT_IDENTIFIER
31 #define BOOST_GEOMETRY_TEST_OVERLAY_NOT_EXCHANGED
33 #ifdef BOOST_GEOMETRY_DEBUG_ENRICH
34 # define BOOST_GEOMETRY_DEBUG_IDENTIFIER
37 #include <boost/geometry/algorithms/area.hpp>
38 #include <boost/geometry/algorithms/correct.hpp>
39 #include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp>
40 #include <boost/geometry/algorithms/detail/overlay/enrichment_info.hpp>
41 #include <boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp>
42 #include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
43 #include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
44 #include <boost/geometry/algorithms/detail/overlay/overlay.hpp>
45 #include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp>
46 #include <boost/geometry/algorithms/detail/overlay/traverse.hpp>
47 #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
49 #include <boost/geometry/geometries/geometries.hpp>
51 #include <boost/geometry/io/wkt/wkt.hpp>
53 #if defined(TEST_WITH_SVG)
54 # include <boost/geometry/io/svg/svg_mapper.hpp>
57 #include <boost/geometry/policies/robustness/get_rescale_policy.hpp>
59 #include <boost/geometry/strategies/strategies.hpp>
61 #include <algorithms/overlay/overlay_cases.hpp>
63 template <bg::overlay_type Op
>
64 static inline std::string
operation()
68 case bg::overlay_union
: return "union";
69 case bg::overlay_intersection
: return "intersection";
70 case bg::overlay_difference
: return "difference";
81 typename G1
, typename G2
,
82 bg::overlay_type OverlayType
,
83 bool Reverse1
, bool Reverse2
88 static void apply(std::string
const& id
,
89 std::size_t expected_count
, double expected_area
,
90 G1
const& g1
, G2
const& g2
,
93 // DEBUG ONE or FEW CASE(S) ONLY
94 //if (! boost::contains(id, "36") || Direction != 1) return;
95 //if (! boost::contains(id, "iet_") || boost::contains(id, "st")) return;
96 //if (! boost::contains(id, "66") || Direction != 1) return;
97 //if (! boost::contains(id, "92") && ! boost::contains(id, "96") ) return;
98 //if (! (boost::contains(id, "58_st") || boost::contains(id, "59_st") || boost::contains(id, "60_st") || boost::contains(id, "83")) ) return;
99 //if (! (boost::contains(id, "81") || boost::contains(id, "82") || boost::contains(id, "84") || boost::contains(id, "85") || boost::contains(id, "68")) ) return;
100 //if (! (boost::contains(id, "81") || boost::contains(id, "86") || boost::contains(id, "88")) ) return;
101 //if (! boost::contains(id, "58_") || Direction != 1) return;
102 //if (! boost::contains(id, "55") || Direction != 1) return;
103 //if (! boost::contains(id, "55_iet_iet") || Direction != 1) return;
104 //if (! boost::contains(id, "55_st_iet") || Direction != 1) return;
105 //if (! boost::contains(id, "55_iet_st") || Direction != 1) return;
106 //if (! boost::contains(id, "54_st_st") || Direction != 1) return;
107 //if (! boost::contains(id, "54_iet_st") || Direction != 1) return;
108 //if (! (boost::contains(id, "54_") || boost::contains(id, "55_")) || Direction != 1) return;
109 //if (Direction != 1) return;
113 /*** FOR REVERSING ONLY
115 // If one or both are invalid (e.g. ccw),
116 // they can be corrected by uncommenting this section
121 std::cout << std::setprecision(12)
122 << bg::wkt(cg1) << std::endl
123 << bg::wkt(cg2) << std::endl;
127 #if defined(BOOST_GEOMETRY_DEBUG_OVERLAY) || defined(BOOST_GEOMETRY_DEBUG_ENRICH)
129 bg::point_order
<G1
>::value
== bg::counterclockwise
130 || bg::point_order
<G2
>::value
== bg::counterclockwise
;
132 std::cout
<< std::endl
135 << (ccw
? "_ccw" : "")
136 << " " << string_from_type
<typename
bg::coordinate_type
<G1
>::type
>::name()
137 << "(" << OverlayType
<< ")" << std::endl
;
139 //std::cout << bg::area(g1) << " " << bg::area(g2) << std::endl;
142 typename
bg::strategy::intersection::services::default_strategy
144 typename
bg::cs_tag
<G1
>::type
147 typedef typename
bg::point_type
<G2
>::type point_type
;
148 typedef typename
bg::rescale_policy_type
<point_type
>::type
151 rescale_policy_type rescale_policy
152 = bg::get_rescale_policy
<rescale_policy_type
>(g1
, g2
);
154 typedef bg::detail::overlay::traversal_turn_info
157 typename
bg::detail::segment_ratio_type
<point_type
, rescale_policy_type
>::type
159 std::vector
<turn_info
> turns
;
161 std::map
<bg::signed_size_type
, bg::detail::overlay::cluster_info
> clusters
;
163 bg::detail::get_turns::no_interrupt_policy policy
;
164 bg::get_turns
<Reverse1
, Reverse2
, bg::detail::overlay::assign_null_policy
>(g1
, g2
, strategy
, rescale_policy
, turns
, policy
);
165 bg::enrich_intersection_points
<Reverse1
, Reverse2
, OverlayType
>(turns
, clusters
, g1
, g2
, rescale_policy
, strategy
);
167 typedef bg::model::ring
<typename
bg::point_type
<G2
>::type
> ring_type
;
168 typedef std::vector
<ring_type
> out_vector
;
171 bg::detail::overlay::overlay_null_visitor visitor
;
173 // TODO: this function requires additional arguments
174 bg::detail::overlay::traverse
179 >::apply(g1
, g2
, strategy
, rescale_policy
, turns
, v
, visitor
);
181 // Check number of resulting rings
182 BOOST_CHECK_MESSAGE(expected_count
== boost::size(v
),
184 << " (" << operation
<OverlayType
>() << ")"
185 << " #shapes expected: " << expected_count
186 << " detected: " << boost::size(v
)
187 << " type: " << string_from_type
188 <typename
bg::coordinate_type
<G1
>::type
>::name()
191 // Check total area of resulting rings
192 typename
bg::default_area_result
<G1
>::type total_area
= 0;
193 for (ring_type
const& ring
: v
)
195 total_area
+= bg::area(ring
);
196 //std::cout << bg::wkt(ring) << std::endl;
199 BOOST_CHECK_CLOSE(expected_area
, total_area
, precision
);
201 #if defined(TEST_WITH_SVG)
203 std::ostringstream filename
;
204 filename
<< "traverse_" << operation
<OverlayType
>()
206 << "_" << string_from_type
<typename
bg::coordinate_type
<G1
>::type
>::name()
209 std::ofstream
svg(filename
.str().c_str());
211 bg::svg_mapper
<typename
bg::point_type
<G2
>::type
> mapper(svg
, 500, 500);
215 // Input shapes in green (src=0) / blue (src=1)
216 mapper
.map(g1
, "fill-opacity:0.5;fill:rgb(153,204,0);"
217 "stroke:rgb(153,204,0);stroke-width:3");
218 mapper
.map(g2
, "fill-opacity:0.3;fill:rgb(51,51,153);"
219 "stroke:rgb(51,51,153);stroke-width:3");
221 // Traversal rings in magenta outline/red fill -> over blue/green this gives brown
222 for (ring_type
const& ring
: v
)
224 mapper
.map(ring
, "fill-opacity:0.2;stroke-opacity:0.4;fill:rgb(255,0,0);"
225 "stroke:rgb(255,0,255);stroke-width:8");
228 // turn points in orange, + enrichment/traversal info
229 typedef typename
bg::coordinate_type
<G1
>::type coordinate_type
;
231 // Simple map to avoid two texts at same place (note that can still overlap!)
232 std::map
<std::pair
<int, int>, int> offsets
;
234 int const margin
= 5;
236 for (turn_info
const& turn
: turns
)
239 mapper
.map(turn
.point
, "fill:rgb(255,128,0);"
240 "stroke:rgb(0,0,0);stroke-width:1", 3);
243 coordinate_type half
= 0.5;
244 coordinate_type ten
= 10;
245 // Map characteristics
246 // Create a rounded off point
247 std::pair
<int, int> p
249 boost::numeric_cast
<int>(half
250 + ten
* bg::get
<0>(turn
.point
)),
251 boost::numeric_cast
<int>(half
252 + ten
* bg::get
<1>(turn
.point
))
254 std::string style
= "fill:rgb(0,0,0);font-family:Arial;font-size:8px";
258 style
= "fill:rgb(255,0,0);font-family:Arial;font-size:8px";
260 else if (turn
.discarded
)
262 style
= "fill:rgb(92,92,92);font-family:Arial;font-size:6px";
266 //if (! turn.is_discarded() && ! turn.blocked() && ! turn.both(bg::detail::overlay::operation_union))
267 //if (! turn.discarded)
269 std::ostringstream out
;
271 << ": " << bg::method_char(turn
.method
)
273 << "op: " << bg::operation_char(turn
.operations
[0].operation
)
274 << " / " << bg::operation_char(turn
.operations
[1].operation
)
275 //<< (turn.is_discarded() ? " (discarded) " : turn.blocked() ? " (blocked)" : "")
278 out
<< "r: " << turn
.operations
[0].fraction
279 << " ; " << turn
.operations
[1].fraction
281 if (turn
.operations
[0].enriched
.next_ip_index
!= -1)
283 out
<< "ip: " << turn
.operations
[0].enriched
.next_ip_index
;
287 out
<< "vx: " << turn
.operations
[0].enriched
.travels_to_vertex_index
288 << " -> ip: " << turn
.operations
[0].enriched
.travels_to_ip_index
;
291 if (turn
.operations
[1].enriched
.next_ip_index
!= -1)
293 out
<< "ip: " << turn
.operations
[1].enriched
.next_ip_index
;
297 out
<< "vx: " << turn
.operations
[1].enriched
.travels_to_vertex_index
298 << " -> ip: " << turn
.operations
[1].enriched
.travels_to_ip_index
;
305 << std::setprecision(3)
306 << "dist: " << boost::numeric_cast<double>(turn.operations[0].enriched.distance)
307 << " / " << boost::numeric_cast<double>(turn.operations[1].enriched.distance)
309 << "vis: " << bg::visited_char(turn.operations[0].visited)
310 << " / " << bg::visited_char(turn.operations[1].visited);
315 << ": " << bg::operation_char(turn.operations[0].operation)
316 << " " << bg::operation_char(turn.operations[1].operation)
317 << " (" << bg::method_char(turn.method) << ")"
318 << (turn.ignore() ? " (ignore) " : " ")
321 << "ip: " << turn.operations[0].enriched.travels_to_ip_index
322 << "/" << turn.operations[1].enriched.travels_to_ip_index;
324 if (turn.operations[0].enriched.next_ip_index != -1
325 || turn.operations[1].enriched.next_ip_index != -1)
327 out << " [" << turn.operations[0].enriched.next_ip_index
328 << "/" << turn.operations[1].enriched.next_ip_index
336 << "vx:" << turn.operations[0].enriched.travels_to_vertex_index
337 << "/" << turn.operations[1].enriched.travels_to_vertex_index
340 << std::setprecision(3)
341 << "dist: " << turn.operations[0].fraction
342 << " / " << turn.operations[1].fraction
348 offsets
[p
] += lineheight
;
349 int offset
= offsets
[p
];
350 offsets
[p
] += lineheight
* 3;
351 mapper
.text(turn
.point
, out
.str(), style
, margin
, offset
, lineheight
);
364 typename G1
, typename G2
,
365 bg::overlay_type OverlayType
,
366 bool Reverse1
= false,
367 bool Reverse2
= false
371 typedef detail::test_traverse
373 G1
, G2
, OverlayType
, Reverse1
, Reverse2
374 > detail_test_traverse
;
376 inline static void apply(std::string
const& id
, std::size_t expected_count
, double expected_area
,
377 std::string
const& wkt1
, std::string
const& wkt2
,
378 double precision
= 0.001)
380 if (wkt1
.empty() || wkt2
.empty())
386 bg::read_wkt(wkt1
, g1
);
389 bg::read_wkt(wkt2
, g2
);
394 //std::cout << bg::wkt(g1) << std::endl;
395 //std::cout << bg::wkt(g2) << std::endl;
397 // Try the overlay-function in both ways
398 std::string caseid
= id
;
399 //goto case_reversed;
401 #ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION
402 std::cout
<< std::endl
<< std::endl
<< "# " << caseid
<< std::endl
;
404 detail_test_traverse::apply(caseid
, expected_count
, expected_area
, g1
, g2
, precision
);
406 #ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION
411 #if ! defined(BOOST_GEOMETRY_TEST_OVERLAY_NOT_EXCHANGED)
412 caseid
= id
+ "_rev";
413 #ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION
414 std::cout
<< std::endl
<< std::endl
<< "# " << caseid
<< std::endl
;
417 detail_test_traverse::apply(caseid
, expected_count
, expected_area
, g2
, g1
, precision
);
422 #if ! defined(BOOST_GEOMETRY_TEST_MULTI)
423 template <typename T
>
424 void test_all(bool test_self_tangencies
= true, bool test_mixed
= false)
426 typedef bg::model::point
<T
, 2, bg::cs::cartesian
> P
;
427 typedef bg::model::polygon
<P
> polygon
;
428 //typedef bg::model::box<P> box;
430 typedef test_traverse
432 polygon
, polygon
, bg::overlay_intersection
433 > test_traverse_intersection
;
434 typedef test_traverse
436 polygon
, polygon
, bg::overlay_union
437 > test_traverse_union
;
440 test_traverse_intersection::apply("1", 1, 5.4736, case_1
[0], case_1
[1]);
441 test_traverse_intersection::apply("2", 1, 12.0545, case_2
[0], case_2
[1]);
442 test_traverse_intersection::apply("3", 1, 5, case_3
[0], case_3
[1]);
443 test_traverse_intersection::apply("4", 1, 10.2212, case_4
[0], case_4
[1]);
444 test_traverse_intersection::apply("5", 2, 12.8155, case_5
[0], case_5
[1]);
445 test_traverse_intersection::apply("6", 1, 4.5, case_6
[0], case_6
[1]);
448 test_traverse_intersection::apply("7", 0, 0, case_7
[0], case_7
[1]);
449 test_traverse_intersection::apply("8", 0, 0, case_8
[0], case_8
[1]);
450 test_traverse_intersection::apply("9", 0, 0, case_9
[0], case_9
[1]);
451 test_traverse_intersection::apply("10", 0, 0, case_10
[0], case_10
[1]);
452 test_traverse_intersection::apply("11", 1, 1, case_11
[0], case_11
[1]);
453 test_traverse_intersection::apply("12", 2, 0.63333, case_12
[0], case_12
[1]);
456 test_traverse_intersection::apply("13", 0, 0, case_13
[0], case_13
[1]);
457 test_traverse_intersection::apply("14", 0, 0, case_14
[0], case_14
[1]);
458 test_traverse_intersection::apply("15", 0, 0, case_15
[0], case_15
[1]);
459 test_traverse_intersection::apply("16", 0, 0, case_16
[0], case_16
[1]);
460 test_traverse_intersection::apply("17", 1, 2, case_17
[0], case_17
[1]);
461 test_traverse_intersection::apply("18", 1, 2, case_18
[0], case_18
[1]);
464 test_traverse_intersection::apply("19", 0, 0, case_19
[0], case_19
[1]);
465 test_traverse_intersection::apply("20", 1, 5.5, case_20
[0], case_20
[1]);
466 test_traverse_intersection::apply("21", 0, 0, case_21
[0], case_21
[1]);
467 test_traverse_intersection::apply("22", 0, 0, case_22
[0], case_22
[1]);
468 test_traverse_intersection::apply("23", 1, 1.4, case_23
[0], case_23
[1]);
469 test_traverse_intersection::apply("24", 1, 1.0, case_24
[0], case_24
[1]);
472 test_traverse_intersection::apply("25", 0, 0, case_25
[0], case_25
[1]);
473 test_traverse_intersection::apply("26", 0, 0, case_26
[0], case_26
[1]);
474 test_traverse_intersection::apply("27", 1, 0.9545454, case_27
[0], case_27
[1]);
475 test_traverse_intersection::apply("28", 1, 0.9545454, case_28
[0], case_28
[1]);
476 test_traverse_intersection::apply("29", 1, 1.4, case_29
[0], case_29
[1]);
477 test_traverse_intersection::apply("30", 1, 0.5, case_30
[0], case_30
[1]);
480 test_traverse_intersection::apply("31", 0, 0, case_31
[0], case_31
[1]);
481 test_traverse_intersection::apply("32", 0, 0, case_32
[0], case_32
[1]);
482 test_traverse_intersection::apply("33", 0, 0, case_33
[0], case_33
[1]);
483 test_traverse_intersection::apply("34", 1, 0.5, case_34
[0], case_34
[1]);
484 test_traverse_intersection::apply("35", 1, 1.0, case_35
[0], case_35
[1]);
485 test_traverse_intersection::apply("36", 1, 1.625, case_36
[0], case_36
[1]);
488 test_traverse_intersection::apply("37", 2, 0.666666, case_37
[0], case_37
[1]);
489 test_traverse_intersection::apply("38", 2, 0.971429, case_38
[0], case_38
[1]);
490 test_traverse_intersection::apply("39", 1, 24, case_39
[0], case_39
[1]);
491 test_traverse_intersection::apply("40", 0, 0, case_40
[0], case_40
[1]);
492 test_traverse_intersection::apply("41", 1, 5, case_41
[0], case_41
[1]);
493 test_traverse_intersection::apply("42", 1, 5, case_42
[0], case_42
[1]);
495 // 43-48 - invalid polygons
496 //test_traverse_intersection::apply("43", 2, 0.75, case_43[0], case_43[1]);
497 //test_traverse_intersection::apply("44", 1, 44, case_44[0], case_44[1]);
498 //test_traverse_intersection::apply("45", 1, 45, case_45[0], case_45[1]);
499 //test_traverse_intersection::apply("46", 1, 46, case_46[0], case_46[1]);
500 //test_traverse_intersection::apply("47", 1, 47, case_47[0], case_47[1]);
504 test_traverse_intersection::apply("50", 0, 0, case_50
[0], case_50
[1]);
505 test_traverse_intersection::apply("51", 0, 0, case_51
[0], case_51
[1]);
506 test_traverse_intersection::apply("52", 1, 10.5, case_52
[0], case_52
[1]);
507 if (test_self_tangencies
)
509 test_traverse_intersection::apply("53_st", 0, 0, case_53
[0], case_53
[1]);
511 test_traverse_intersection::apply("53_iet", 0, 0, case_53
[0], case_53
[2]);
513 test_traverse_intersection::apply("54_iet_iet", 1, 2, case_54
[1], case_54
[3]);
514 if (test_self_tangencies
)
516 test_traverse_intersection::apply("54_st_iet", 1, 2, case_54
[0], case_54
[3]);
517 test_traverse_intersection::apply("54_iet_st", 1, 2, case_54
[1], case_54
[2]);
518 test_traverse_intersection::apply("54_st_st", 1, 2, case_54
[0], case_54
[2]);
521 if (test_self_tangencies
)
524 test_traverse_intersection::apply("55_st_st", 1, 2, case_55
[0], case_55
[2]);
527 test_traverse_intersection::apply("55_st_iet", 1, 2, case_55
[0], case_55
[3]);
528 test_traverse_intersection::apply("55_iet_st", 1, 2, case_55
[1], case_55
[2]);
529 if (test_self_tangencies
)
531 test_traverse_intersection::apply("56", 2, 4.5, case_56
[0], case_56
[1]);
533 test_traverse_intersection::apply("55_iet_iet", 1, 2, case_55
[1], case_55
[3]);
534 test_traverse_intersection::apply("57", 2, 5.9705882, case_57
[0], case_57
[1]);
536 if (test_self_tangencies
)
538 test_traverse_intersection::apply("58_st",
539 2, 0.333333, case_58
[0], case_58
[1]);
540 test_traverse_intersection::apply("59_st",
541 2, 1.5416667, case_59
[0], case_59
[1]);
542 test_traverse_intersection::apply("60_st",
543 3, 2, case_60
[0], case_60
[1]);
545 test_traverse_intersection::apply("58_iet",
546 2, 0.333333, case_58
[0], case_58
[2]);
547 test_traverse_intersection::apply("59_iet",
548 2, 1.5416667, case_59
[0], case_59
[2]);
549 test_traverse_intersection::apply("60_iet",
550 3, 2, case_60
[0], case_60
[2]);
551 test_traverse_intersection::apply("61_st",
552 0, 0, case_61
[0], case_61
[1]);
554 test_traverse_intersection::apply("70",
555 2, 4, case_70
[0], case_70
[1]);
556 test_traverse_intersection::apply("71",
557 2, 2, case_71
[0], case_71
[1]);
558 test_traverse_intersection::apply("72",
559 3, 2.85, case_72
[0], case_72
[1]);
560 test_traverse_intersection::apply("79",
561 2, 20, case_79
[0], case_79
[1]);
563 // Should be 3 shapes
564 test_traverse_intersection::apply("82a",
565 2, 2.0, case_82
[0], case_82
[1]);
566 // Should be 3 shapes
567 test_traverse_intersection::apply("82b",
568 2, 2.0, case_82
[0], case_82
[2]);
571 #ifdef BOOST_GEOMETRY_TEST_FAILURES
572 // simplified version of 82, area should be different
573 // missing IP at (1.5 3.5) from (1 4,1.5 3.5,2 4)x(2 4,1 3)
574 test_traverse_intersection::apply("83",
575 1, 0.0, case_83
[0], case_83
[1]);
578 // pies (went wrong when not all cases where implemented, especially some collinear (opposite) cases
579 test_traverse_intersection::apply("pie_16_4_12",
580 1, 491866.5, pie_16_4_12
[0], pie_16_4_12
[1]);
581 test_traverse_intersection::apply("pie_23_21_12_500",
582 2, 2363199.3313, pie_23_21_12_500
[0], pie_23_21_12_500
[1]);
583 test_traverse_intersection::apply("pie_23_23_3_2000",
584 2, 1867779.9349, pie_23_23_3_2000
[0], pie_23_23_3_2000
[1]);
585 test_traverse_intersection::apply("pie_23_16_16",
586 2, 2128893.9555, pie_23_16_16
[0], pie_23_16_16
[1]);
587 test_traverse_intersection::apply("pie_16_2_15_0",
588 0, 0, pie_16_2_15_0
[0], pie_16_2_15_0
[1]);
589 test_traverse_intersection::apply("pie_4_13_15",
590 1, 490887.06678, pie_4_13_15
[0], pie_4_13_15
[1]);
591 test_traverse_intersection::apply("pie_20_20_7_100",
592 2, 2183372.2718, pie_20_20_7_100
[0], pie_20_20_7_100
[1]);
597 test_traverse_union::apply("1", 1, 11.5264, case_1
[0], case_1
[1]);
598 test_traverse_union::apply("2", 1, 17.9455, case_2
[0], case_2
[1]);
599 test_traverse_union::apply("3", 1, 9, case_3
[0], case_3
[1]);
600 test_traverse_union::apply("4", 3, 17.7788, case_4
[0], case_4
[1]);
601 test_traverse_union::apply("5", 2, 18.4345, case_5
[0], case_5
[1]);
602 test_traverse_union::apply("6", 1, 9, case_6
[0], case_6
[1]);
605 test_traverse_union::apply("7", 1, 9, case_7
[0], case_7
[1]);
606 test_traverse_union::apply("8", 1, 12, case_8
[0], case_8
[1]);
607 test_traverse_union::apply("9", 0, 0 /*UU 2, 11*/, case_9
[0], case_9
[1]);
608 test_traverse_union::apply("10", 1, 9, case_10
[0], case_10
[1]);
609 test_traverse_union::apply("11", 1, 8, case_11
[0], case_11
[1]);
610 test_traverse_union::apply("12", 2, 8.36667, case_12
[0], case_12
[1]);
613 test_traverse_union::apply("13", 1, 4, case_13
[0], case_13
[1]);
614 test_traverse_union::apply("14", 1, 12, case_14
[0], case_14
[1]);
615 test_traverse_union::apply("15", 1, 12, case_15
[0], case_15
[1]);
616 test_traverse_union::apply("16", 1, 9, case_16
[0], case_16
[1]);
617 test_traverse_union::apply("17", 1, 8, case_17
[0], case_17
[1]);
618 test_traverse_union::apply("18", 1, 8, case_18
[0], case_18
[1]);
621 test_traverse_union::apply("19", 1, 10, case_19
[0], case_19
[1]);
622 test_traverse_union::apply("20", 1, 5.5, case_20
[0], case_20
[1]);
623 test_traverse_union::apply("21", 0, 0, case_21
[0], case_21
[1]);
624 test_traverse_union::apply("22", 0, 0 /*UU 2, 9.5*/, case_22
[0], case_22
[1]);
625 test_traverse_union::apply("23", 1, 6.1, case_23
[0], case_23
[1]);
626 test_traverse_union::apply("24", 1, 5.5, case_24
[0], case_24
[1]);
629 test_traverse_union::apply("25", 0, 0 /*UU 2, 7*/, case_25
[0], case_25
[1]);
630 test_traverse_union::apply("26", 0, 0 /*UU 2, 7.5 */, case_26
[0], case_26
[1]);
631 test_traverse_union::apply("27", 1, 8.04545, case_27
[0], case_27
[1]);
632 test_traverse_union::apply("28", 1, 10.04545, case_28
[0], case_28
[1]);
633 test_traverse_union::apply("29", 1, 8.1, case_29
[0], case_29
[1]);
634 test_traverse_union::apply("30", 1, 6.5, case_30
[0], case_30
[1]);
637 test_traverse_union::apply("31", 0, 0 /*UU 2, 4.5 */, case_31
[0], case_31
[1]);
638 test_traverse_union::apply("32", 0, 0 /*UU 2, 4.5 */, case_32
[0], case_32
[1]);
639 test_traverse_union::apply("33", 0, 0 /*UU 2, 4.5 */, case_33
[0], case_33
[1]);
640 test_traverse_union::apply("34", 1, 6.0, case_34
[0], case_34
[1]);
641 test_traverse_union::apply("35", 1, 10.5, case_35
[0], case_35
[1]);
642 test_traverse_union::apply("36", 1 /*UU 2*/, 14.375, case_36
[0], case_36
[1]);
645 test_traverse_union::apply("37", 1, 7.33333, case_37
[0], case_37
[1]);
646 test_traverse_union::apply("38", 1, 9.52857, case_38
[0], case_38
[1]);
647 test_traverse_union::apply("39", 1, 40.0, case_39
[0], case_39
[1]);
648 test_traverse_union::apply("40", 0, 0 /*UU 2, 11 */, case_40
[0], case_40
[1]);
649 test_traverse_union::apply("41", 1, 5, case_41
[0], case_41
[1]);
650 test_traverse_union::apply("42", 1, 5, case_42
[0], case_42
[1]);
653 //test_traverse_union::apply("43", 3, 8.1875, case_43[0], case_43[1]);
654 //test_traverse_union::apply("44", 1, 44, case_44[0], case_44[1]);
655 //test_traverse_union::apply("45", 1, 45, case_45[0], case_45[1]);
656 //test_traverse_union::apply("46", 1, 46, case_46[0], case_46[1]);
657 //test_traverse_union::apply("47", 1, 47, case_47[0], case_47[1]);
661 test_traverse_union::apply("50", 1, 25, case_50
[0], case_50
[1]);
662 test_traverse_union::apply("51", 0, 0, case_51
[0], case_51
[1]);
663 test_traverse_union::apply("52", 1, 15.5, case_52
[0], case_52
[1]);
664 if (test_self_tangencies
)
666 test_traverse_union::apply("53_st", 2, 16, case_53
[0], case_53
[1]);
668 test_traverse_union::apply("53_iet",
669 2, 16, case_53
[0], case_53
[2]);
670 if (test_self_tangencies
)
672 test_traverse_union::apply("54_st_st", 2, 20, case_54
[0], case_54
[2]);
673 test_traverse_union::apply("54_st_iet", 2, 20, case_54
[0], case_54
[3]);
674 test_traverse_union::apply("54_iet_st", 2, 20, case_54
[1], case_54
[2]);
676 test_traverse_union::apply("54_iet_iet", 2, 20, case_54
[1], case_54
[3]);
680 test_traverse_union::apply("55_st_iet", 2, 18, case_55
[0], case_55
[3]);
681 test_traverse_union::apply("55_iet_st", 2, 18, case_55
[1], case_55
[2]);
683 test_traverse_union::apply("55_iet_iet", 3, 18, case_55
[1], case_55
[3]);
687 if (test_self_tangencies
)
689 // 55 with both input polygons having self tangencies (st_st) generates 1 correct shape
690 test_traverse_union::apply("55_st_st", 1, 18, case_55
[0], case_55
[2]);
691 // 55 with one of them self-tangency, other int/ext ring tangency generate 2 correct shapes
693 test_traverse_union::apply("56", 2, 14, case_56
[0], case_56
[1]);
695 test_traverse_union::apply("57", 1, 14.029412, case_57
[0], case_57
[1]);
697 if (test_self_tangencies
)
699 test_traverse_union::apply("58_st",
700 4, 12.16666, case_58
[0], case_58
[1]);
701 test_traverse_union::apply("59_st",
702 2, 17.208333, case_59
[0], case_59
[1]);
703 test_traverse_union::apply("60_st",
704 3, 19, case_60
[0], case_60
[1]);
706 test_traverse_union::apply("58_iet",
707 4, 12.16666, case_58
[0], case_58
[2]);
708 test_traverse_union::apply("59_iet",
709 1, -3.791666, // 2, 17.208333), outer ring (ii/ix) is done by ASSEMBLE
710 case_59
[0], case_59
[2]);
711 test_traverse_union::apply("60_iet",
712 3, 19, case_60
[0], case_60
[2]);
713 test_traverse_union::apply("61_st",
714 1, 4, case_61
[0], case_61
[1]);
716 test_traverse_union::apply("70",
717 1, 9, case_70
[0], case_70
[1]);
718 test_traverse_union::apply("71",
719 2, 9, case_71
[0], case_71
[1]);
720 test_traverse_union::apply("72",
721 1, 10.65, case_72
[0], case_72
[1]);
724 test_traverse_union::apply("box_poly5",
726 "POLYGON((1.5 1.5, 1.5 2.5, 4.5 2.5, 4.5 1.5, 1.5 1.5))",
727 "POLYGON((2 1.3,2.4 1.7,2.8 1.8,3.4 1.2,3.7 1.6,3.4 2,4.1 2.5,4.5 2.5,4.5 2.3,5.0 2.3,5.0 2.1,4.5 2.1,4.5 1.9,4.0 1.9,4.5 1.2,4.9 0.8,2.9 0.7,2 1.3))");
729 test_traverse_intersection::apply("collinear_overlaps",
731 collinear_overlaps
[0], collinear_overlaps
[1]);
732 test_traverse_union::apply("collinear_overlaps",
734 collinear_overlaps
[0], collinear_overlaps
[1]);
736 test_traverse_intersection::apply("many_situations", 1, 184, case_many_situations
[0], case_many_situations
[1]);
737 test_traverse_union::apply("many_situations",
738 1, 207, case_many_situations
[0], case_many_situations
[1]);
741 // From "intersection piets", robustness test.
742 // This all went wrong in the past
743 // (when not all cases (get_turns) where implemented,
744 // especially important are some collinear (opposite) cases)
745 test_traverse_union::apply("pie_16_4_12",
746 1, 3669665.5, pie_16_4_12
[0], pie_16_4_12
[1]);
747 test_traverse_union::apply("pie_23_21_12_500",
748 1, 6295516.7185, pie_23_21_12_500
[0], pie_23_21_12_500
[1]);
749 test_traverse_union::apply("pie_23_23_3_2000",
750 1, 7118735.0530, pie_23_23_3_2000
[0], pie_23_23_3_2000
[1]);
751 test_traverse_union::apply("pie_23_16_16",
752 1, 5710474.5406, pie_23_16_16
[0], pie_23_16_16
[1]);
753 test_traverse_union::apply("pie_16_2_15_0",
754 1, 3833641.5, pie_16_2_15_0
[0], pie_16_2_15_0
[1]);
755 test_traverse_union::apply("pie_4_13_15",
756 1, 2208122.43322, pie_4_13_15
[0], pie_4_13_15
[1]);
757 test_traverse_union::apply("pie_20_20_7_100",
758 1, 5577158.72823, pie_20_20_7_100
[0], pie_20_20_7_100
[1]);
763 test_traverse_union::apply("pie_5_12_12_0_7s",
764 1, 3271710.48516, pie_5_12_12_0_7s[0], pie_5_12_12_0_7s[1]);
768 static const bool is_float
= std::is_same
<T
, float>::value
;
770 static const double float_might_deviate_more
= is_float
? 0.1 : 0.001; // In some cases up to 1 promille permitted
772 // GCC: does not everywhere handle float correctly (in our algorithms)
773 static bool const is_float_on_non_msvc
=
774 #if defined(_MSC_VER)
782 // From "Random Ellipse Stars", robustness test.
783 // This all went wrong in the past
784 // when using Determinant/ra/rb and comparing with 0/1
785 // Solved now by avoiding determinant / using sides
786 // ("hv" means "high volume")
788 double deviation
= is_float
? 0.01 : 0.001;
789 test_traverse_union::apply("hv1", 1, 1624.508688461573, hv_1
[0], hv_1
[1], deviation
);
790 test_traverse_intersection::apply("hv1", 1, 1622.7200125123809, hv_1
[0], hv_1
[1], deviation
);
792 test_traverse_union::apply("hv2", 1, 1622.9193392726836, hv_2
[0], hv_2
[1], deviation
);
793 test_traverse_intersection::apply("hv2", 1, 1622.1733591429329, hv_2
[0], hv_2
[1], deviation
);
795 test_traverse_union::apply("hv3", 1, 1624.22079205664, hv_3
[0], hv_3
[1], deviation
);
796 test_traverse_intersection::apply("hv3", 1, 1623.8265057282042, hv_3
[0], hv_3
[1], deviation
);
799 if ( BOOST_GEOMETRY_CONDITION(! is_float
) )
801 test_traverse_union::apply("hv4", 1, 1626.5146964146334, hv_4
[0], hv_4
[1], deviation
);
802 test_traverse_intersection::apply("hv4", 1, 1626.2580370864305, hv_4
[0], hv_4
[1], deviation
);
803 test_traverse_union::apply("hv5", 1, 1624.2158307261871, hv_5
[0], hv_5
[1], deviation
);
804 test_traverse_intersection::apply("hv5", 1, 1623.4506071521519, hv_5
[0], hv_5
[1], deviation
);
807 test_traverse_intersection::apply("hv6", 1, 1604.6318757402121, hv_6
[0], hv_6
[1], deviation
);
808 test_traverse_union::apply("hv6", 1, 1790.091872401327, hv_6
[0], hv_6
[1], deviation
);
810 // Case 2009-12-08, needing sorting on side in enrich_intersection_points
811 test_traverse_union::apply("hv7", 1, 1624.5779453641017, hv_7
[0], hv_7
[1], deviation
);
812 test_traverse_intersection::apply("hv7", 1, 1623.6936420295772, hv_7
[0], hv_7
[1], deviation
);
816 // From "Random Ellipse Stars", robustness test.
817 // This all went wrong in the past when distances (see below) were zero (dz)
818 // "Distance zero", dz, means: the distance between two intersection points
819 // on a same segment is 0, therefore it can't be sorted normally, therefore
820 // the chance is 50% that the segments are not sorted correctly and the wrong
821 // decision is taken.
822 // Solved now (by sorting on sides in those cases)
823 if ( BOOST_GEOMETRY_CONDITION(! is_float_on_non_msvc
) )
825 test_traverse_intersection::apply("dz_1",
826 2, 16.887537949472005, dz_1
[0], dz_1
[1]);
827 test_traverse_union::apply("dz_1",
828 3, 1444.2621305732864, dz_1
[0], dz_1
[1]);
830 test_traverse_intersection::apply("dz_2",
831 2, 68.678921274288541, dz_2
[0], dz_2
[1]);
832 test_traverse_union::apply("dz_2",
833 1, 1505.4202304878663, dz_2
[0], dz_2
[1]);
835 test_traverse_intersection::apply("dz_3",
836 5, 192.49316937645651, dz_3
[0], dz_3
[1]);
837 test_traverse_union::apply("dz_3",
838 5, 1446.496005965641, dz_3
[0], dz_3
[1]);
840 test_traverse_intersection::apply("dz_4",
841 1, 473.59423868207693, dz_4
[0], dz_4
[1]);
842 test_traverse_union::apply("dz_4",
843 1, 1871.6125138873476, dz_4
[0], dz_4
[1]);
846 // Real-life problems
848 // SNL (Subsidiestelsel Natuur & Landschap - verAANnen)
850 test_traverse_intersection::apply("snl-1",
853 float_might_deviate_more
);
855 test_traverse_union::apply("snl-1",
858 float_might_deviate_more
);
861 test_traverse_intersection::apply("isov",
862 1, 88.1920, isovist
[0], isovist
[1],
863 float_might_deviate_more
);
864 test_traverse_union::apply("isov",
865 1, 313.3604, isovist
[0], isovist
[1],
866 float_might_deviate_more
);
869 if ( BOOST_GEOMETRY_CONDITION(! is_float
) )
872 /* TODO check this BSG 2013-09-24
873 #if defined(_MSC_VER)
874 double const expected = if_typed_tt<T>(3.63794e-17, 0.0);
875 int expected_count = if_typed_tt<T>(1, 0);
877 double const expected = if_typed<T, long double>(2.77555756156289135106e-17, 0.0);
878 int expected_count = if_typed<T, long double>(1, 0);
881 // Calculate intersection/union of two triangles. Robustness case.
882 // some precise types can form a very small intersection triangle
883 // (which is even not accomplished by SQL Server/PostGIS)
884 std::string const caseid = "ggl_list_20110820_christophe";
885 test_traverse_intersection::apply(caseid,
886 expected_count, expected,
887 ggl_list_20110820_christophe[0], ggl_list_20110820_christophe[1]);
888 test_traverse_union::apply(caseid,
890 ggl_list_20110820_christophe[0], ggl_list_20110820_christophe[1]);
894 test_traverse_union::apply("buffer_rt_f",
896 buffer_rt_f
[0], buffer_rt_f
[1]);
897 test_traverse_intersection::apply("buffer_rt_f",
898 1, 0.0002943725152286,
899 buffer_rt_f
[0], buffer_rt_f
[1], 0.01);
901 test_traverse_union::apply("buffer_rt_g",
903 buffer_rt_g
[0], buffer_rt_g
[1]);
905 test_traverse_union::apply("buffer_rt_g_boxes1",
907 buffer_rt_g_boxes
[0], buffer_rt_g_boxes
[1]);
908 test_traverse_union::apply("buffer_rt_g_boxes2",
910 buffer_rt_g_boxes
[0], buffer_rt_g_boxes
[2]);
911 test_traverse_union::apply("buffer_rt_g_boxes3",
913 buffer_rt_g_boxes
[0], buffer_rt_g_boxes
[3]);
915 test_traverse_union::apply("buffer_rt_g_boxes43",
917 buffer_rt_g_boxes
[4], buffer_rt_g_boxes
[3]);
919 test_traverse_union::apply("buffer_rt_l",
920 1, 19.3995, buffer_rt_l
[0], buffer_rt_l
[1]);
922 test_traverse_union::apply("buffer_mp2",
923 1, 36.7535642, buffer_mp2
[0], buffer_mp2
[1], 0.01);
924 test_traverse_union::apply("collinear_opposite_rr",
925 1, 6.41, collinear_opposite_right
[0], collinear_opposite_right
[1]);
926 test_traverse_union::apply("collinear_opposite_ll",
927 1, 11.75, collinear_opposite_left
[0], collinear_opposite_left
[1]);
928 test_traverse_union::apply("collinear_opposite_ss",
929 1, 6, collinear_opposite_straight
[0], collinear_opposite_straight
[1]);
930 test_traverse_union::apply("collinear_opposite_lr",
931 1, 8.66, collinear_opposite_left
[0], collinear_opposite_right
[1]);
932 test_traverse_union::apply("collinear_opposite_rl",
933 1, 9, collinear_opposite_right
[0], collinear_opposite_left
[1]);
935 test_traverse_intersection::apply("ticket_7462", 1, 0.220582, ticket_7462
[0], ticket_7462
[1]);
937 test_traverse_intersection::apply
938 ("ticket_9081_15", 1, 0.006889578,
939 ticket_9081_15
[0], ticket_9081_15
[1]);
941 #ifdef BOOST_GEOMETRY_OVERLAY_NO_THROW
943 // NOTE: currently throws (normally)
944 std::string caseid
= "ggl_list_20120229_volker";
945 test_traverse_union::apply(caseid
,
947 ggl_list_20120229_volker
[0], ggl_list_20120229_volker
[1]);
948 test_traverse_intersection::apply(caseid
,
950 ggl_list_20120229_volker
[0], ggl_list_20120229_volker
[1]);
951 caseid
= "ggl_list_20120229_volker_2";
952 test_traverse_union::apply(caseid
,
954 ggl_list_20120229_volker
[2], ggl_list_20120229_volker
[1]);
955 test_traverse_intersection::apply(caseid
,
957 ggl_list_20120229_volker
[2], ggl_list_20120229_volker
[1]);
962 #if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE)
963 template <typename T
>
966 typedef bg::model::polygon
968 bg::model::point
<T
, 2, bg::cs::cartesian
>,
972 typedef test_traverse
974 polygon
, polygon
, bg::overlay_intersection
975 > test_traverse_intersection
;
976 typedef test_traverse
978 polygon
, polygon
, bg::overlay_union
979 > test_traverse_union
;
981 test_traverse_intersection::apply("open_1", 1, 5.4736,
982 open_case_1
[0], open_case_1
[1]);
983 test_traverse_union::apply("open_1", 1, 11.5264,
984 open_case_1
[0], open_case_1
[1]);
988 template <typename T
>
991 typedef bg::model::polygon
993 bg::model::point
<T
, 2, bg::cs::cartesian
>,
997 test_traverse
<polygon
, polygon
, bg::overlay_intersection
, true, true>::apply("ccw_1", 1, 5.4736,
998 ccw_case_1
[0], ccw_case_1
[1]);
999 test_traverse
<polygon
, polygon
, bg::overlay_union
, true, true>::apply("ccw_1", 1, 11.5264,
1000 ccw_case_1
[0], ccw_case_1
[1]);
1005 int test_main(int, char* [])
1007 #if defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE)
1012 test_open
<double>();
1015 #if ! defined(_MSC_VER)
1016 test_all
<long double>();