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 2015, 2016.
7 // Modifications copyright (c) 2015-2016, Oracle and/or its affiliates.
8 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
9 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
11 // Use, modification and distribution is subject to the Boost Software License,
12 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
13 // http://www.boost.org/LICENSE_1_0.txt)
20 #include <boost/geometry/algorithms/correct.hpp>
21 #include <boost/geometry/algorithms/is_valid.hpp>
23 #include <boost/geometry/io/wkt/wkt.hpp>
25 #include <boost/geometry/geometries/point_xy.hpp>
27 #include "test_difference.hpp"
28 #include <algorithms/test_overlay.hpp>
29 #include <algorithms/overlay/overlay_cases.hpp>
30 #include <algorithms/overlay/multi_overlay_cases.hpp>
34 # include <boost/geometry/extensions/contrib/ttmath_stub.hpp>
38 // Convenience macros (points are not checked)
39 #define TEST_DIFFERENCE(caseid, clips1, area1, clips2, area2, clips3) \
40 (test_one<polygon, polygon, polygon>) \
41 ( #caseid, caseid[0], caseid[1], clips1, -1, area1, clips2, -1, area2, \
42 clips3, -1, area1 + area2)
44 #define TEST_DIFFERENCE_WITH(caseid, clips1, area1, clips2, area2, clips3) \
45 (test_one<polygon, polygon, polygon>) \
46 ( #caseid, caseid[0], caseid[1], clips1, -1, area1, clips2, -1, area2, \
47 clips3, -1, area1 + area2, settings)
52 typedef bg::model::polygon<P> polygon;
54 typedef typename bg::coordinate_type<P>::type ct;
56 ut_settings sym_settings;
57 #if ! defined(BOOST_GEOMETRY_USE_RESCALING)
58 sym_settings.sym_difference = false;
61 ut_settings ignore_validity_settings;
62 ignore_validity_settings.test_validity = false;
64 test_one<polygon, polygon, polygon>("simplex_normal",
65 simplex_normal[0], simplex_normal[1],
66 3, 12, 2.52636706856656,
67 3, 12, 3.52636706856656,
70 test_one<polygon, polygon, polygon>("simplex_with_empty",
71 simplex_normal[0], polygon_empty,
75 test_one<polygon, polygon, polygon>(
76 "star_ring", example_star, example_ring,
81 test_one<polygon, polygon, polygon>("two_bends",
82 two_bends[0], two_bends[1],
86 test_one<polygon, polygon, polygon>("star_comb_15",
87 star_comb_15[0], star_comb_15[1],
88 30, -1, 227.658275102812,
89 30, -1, 480.485775259312,
92 test_one<polygon, polygon, polygon>("new_hole",
93 new_hole[0], new_hole[1],
98 test_one<polygon, polygon, polygon>("crossed",
99 crossed[0], crossed[1],
103 test_one<polygon, polygon, polygon>("disjoint",
104 disjoint[0], disjoint[1],
108 // The too small one might be discarded (depending on point-type / compiler)
109 // We check area only
110 test_one<polygon, polygon, polygon>("distance_zero",
111 distance_zero[0], distance_zero[1],
116 test_one<polygon, polygon, polygon>("equal_holes_disjoint",
117 equal_holes_disjoint[0], equal_holes_disjoint[1],
121 test_one<polygon, polygon, polygon>("only_hole_intersections1",
122 only_hole_intersections[0], only_hole_intersections[1],
127 test_one<polygon, polygon, polygon>("only_hole_intersection2",
128 only_hole_intersections[0], only_hole_intersections[2],
133 test_one<polygon, polygon, polygon>("first_within_second",
134 first_within_second[1], first_within_second[0],
138 test_one<polygon, polygon, polygon>("fitting",
139 fitting[0], fitting[1],
144 test_one<polygon, polygon, polygon>("identical",
145 identical[0], identical[1],
149 test_one<polygon, polygon, polygon>("intersect_exterior_and_interiors_winded",
150 intersect_exterior_and_interiors_winded[0], intersect_exterior_and_interiors_winded[1],
154 test_one<polygon, polygon, polygon>("intersect_holes_intersect_and_disjoint",
155 intersect_holes_intersect_and_disjoint[0], intersect_holes_intersect_and_disjoint[1],
158 ignore_validity_settings);
160 test_one<polygon, polygon, polygon>("intersect_holes_intersect_and_touch",
161 intersect_holes_intersect_and_touch[0], intersect_holes_intersect_and_touch[1],
164 ignore_validity_settings);
167 ut_settings settings = sym_settings;
168 settings.percentage = 0.01;
169 test_one<polygon, polygon, polygon>("intersect_holes_new_ring",
170 intersect_holes_new_ring[0], intersect_holes_new_ring[1],
176 test_one<polygon, polygon, polygon>("first_within_hole_of_second",
177 first_within_hole_of_second[0], first_within_hole_of_second[1],
181 test_one<polygon, polygon, polygon>("intersect_holes_disjoint",
182 intersect_holes_disjoint[0], intersect_holes_disjoint[1],
186 test_one<polygon, polygon, polygon>("intersect_holes_intersect",
187 intersect_holes_intersect[0], intersect_holes_intersect[1],
190 ignore_validity_settings);
192 test_one<polygon, polygon, polygon>(
193 "case4", case_4[0], case_4[1],
194 6, 28, 2.77878787878788,
195 4, 22, 4.77878787878788,
198 test_one<polygon, polygon, polygon>(
199 "case5", case_5[0], case_5[1],
200 8, 36, 2.43452380952381,
201 7, 33, 3.18452380952381);
203 #if ! defined(BOOST_GEOMETRY_USE_RESCALING) || defined(BOOST_GEOMETRY_TEST_FAILURES)
204 // Fails with rescaling, a-b is partly generated, b-a does not have any output
205 // It failed already in 1.59
206 test_one<polygon, polygon, polygon>("case_58_iet",
207 case_58[0], case_58[2],
209 1, -1, 11.1666666667,
210 2, -1, 0.6666666667 + 11.1666666667);
213 test_one<polygon, polygon, polygon>("case_80",
214 case_80[0], case_80[1],
218 #if ! defined(BOOST_GEOMETRY_USE_RESCALING) || defined(BOOST_GEOMETRY_TEST_FAILURES)
219 // Fails without rescaling, holes are not subtracted
220 test_one<polygon, polygon, polygon>("case_81",
221 case_81[0], case_81[1],
227 test_one<polygon, polygon, polygon>("case_100",
228 case_100[0], case_100[1],
231 1, 13, 16.0 + 3.125);
233 test_one<polygon, polygon, polygon>("case_101",
234 case_101[0], case_101[1],
238 test_one<polygon, polygon, polygon>("case_102",
239 case_102[0], case_102[1],
243 TEST_DIFFERENCE(case_105, 4, 8.0, 1, 16.0, 5);
244 TEST_DIFFERENCE(case_106, 1, 17.5, 2, 32.5, 3);
245 TEST_DIFFERENCE(case_107, 2, 18.0, 2, 29.0, 4);
247 TEST_DIFFERENCE(case_precision_1, 1, 14.0, 1, BG_IF_KRAMER(8.00001, 8.0), 1);
248 TEST_DIFFERENCE(case_precision_2, 1, 14.0, 1, 8.0, 1);
249 TEST_DIFFERENCE(case_precision_3, 1, 14.0, 1, 8.0, 1);
250 TEST_DIFFERENCE(case_precision_4, 1, 14.0, 1, 8.0, 1);
251 #if ! defined(BOOST_GEOMETRY_USE_KRAMER_RULE) || defined(BOOST_GEOMETRY_TEST_FAILURES)
252 TEST_DIFFERENCE(case_precision_5, 1, 14.0, 1, 8.0, 1);
253 TEST_DIFFERENCE(case_precision_6, 0, 0.0, 1, 57.0, 1);
255 TEST_DIFFERENCE(case_precision_7, 1, 14.0, 1, 8.0, 1);
256 TEST_DIFFERENCE(case_precision_8, 0, 0.0, 1, 59.0, 1);
257 #if ! defined(BOOST_GEOMETRY_USE_KRAMER_RULE) || defined(BOOST_GEOMETRY_TEST_FAILURES)
258 TEST_DIFFERENCE(case_precision_9, 0, 0.0, 1, 59.0, 1);
259 TEST_DIFFERENCE(case_precision_10, 0, 0.0, 1, 59.0, 1);
260 TEST_DIFFERENCE(case_precision_11, 0, 0.0, 1, 59.0, 1);
262 TEST_DIFFERENCE(case_precision_12, 1, 12.0, 0, 0.0, 1);
263 TEST_DIFFERENCE(case_precision_13, 1, BG_IF_KRAMER(12.00002, 12.0), 0, 0.0, 1);
264 TEST_DIFFERENCE(case_precision_14, 1, 14.0, 1, 8.0, 1);
265 TEST_DIFFERENCE(case_precision_15, 0, 0.0, 1, 59.0, 1);
266 #if ! defined(BOOST_GEOMETRY_USE_KRAMER_RULE) || defined(BOOST_GEOMETRY_TEST_FAILURES)
267 TEST_DIFFERENCE(case_precision_16, 0, 0.0, 1, 59.0, 1);
269 TEST_DIFFERENCE(case_precision_17, 0, 0.0, 1, 59.0, 1);
270 TEST_DIFFERENCE(case_precision_18, 0, 0.0, 1, 59.0, 1);
271 #if ! defined(BOOST_GEOMETRY_USE_KRAMER_RULE) || defined(BOOST_GEOMETRY_TEST_FAILURES)
272 TEST_DIFFERENCE(case_precision_19, 1, 0.0, 1, 59.0, 2);
274 TEST_DIFFERENCE(case_precision_20, 1, 14.0, 1, 8.0, 1);
275 TEST_DIFFERENCE(case_precision_21, 1, 14.0, 1, 7.99999, 1);
276 #if ! defined(BOOST_GEOMETRY_USE_KRAMER_RULE) || defined(BOOST_GEOMETRY_TEST_FAILURES)
277 TEST_DIFFERENCE(case_precision_22, 0, 0.0, 1, 59.0, 1);
278 TEST_DIFFERENCE(case_precision_23, 0, 0.0, 1, 59.0, 1);
280 TEST_DIFFERENCE(case_precision_24, 1, 14.0, 1, 8.0, 1);
281 TEST_DIFFERENCE(case_precision_25, 1, 14.0, 1, 7.99999, 1);
282 #if ! defined(BOOST_GEOMETRY_USE_KRAMER_RULE) || defined(BOOST_GEOMETRY_TEST_FAILURES)
283 TEST_DIFFERENCE(case_precision_26, 0, 0.0, 1, 59.0, 1);
286 test_one<polygon, polygon, polygon>("winded",
287 winded[0], winded[1],
291 test_one<polygon, polygon, polygon>("within_holes_disjoint",
292 within_holes_disjoint[0], within_holes_disjoint[1],
296 test_one<polygon, polygon, polygon>("side_side",
297 side_side[0], side_side[1],
302 test_one<polygon, polygon, polygon>("buffer_mp1",
303 buffer_mp1[0], buffer_mp1[1],
307 if ( BOOST_GEOMETRY_CONDITION((boost::is_same<ct, double>::value)) )
309 test_one<polygon, polygon, polygon>("buffer_mp2",
310 buffer_mp2[0], buffer_mp2[1],
313 BG_IF_RESCALED(2, 1), -1, 12.09857 + 24.19714);
316 /*** TODO: self-tangencies for difference
317 test_one<polygon, polygon, polygon>("wrapped_a",
318 wrapped[0], wrapped[1],
322 test_one<polygon, polygon, polygon>("wrapped_b",
323 wrapped[0], wrapped[2],
329 ut_settings settings;
330 settings.percentage = BG_IF_RESCALED(0.001, 0.1);
331 settings.test_validity = BG_IF_RESCALED(true, false);
332 settings.sym_difference = BG_IF_RESCALED(true, false);
334 // Isovist - the # output polygons differ per compiler/pointtype, (very) small
335 // rings might be discarded. We check area only
337 // SQL Server gives: 0.279121891701124 and 224.889211358929
338 // PostGIS gives: 0.279121991127244 and 224.889205853156
339 // No robustness gives: 0.279121991127106 and 224.825363749290
341 test_one<polygon, polygon, polygon>("isovist",
342 isovist1[0], isovist1[1],
348 #if ! defined(BOOST_GEOMETRY_USE_RESCALING) || defined(BOOST_GEOMETRY_TEST_FAILURES)
350 ut_settings settings;
351 settings.percentage = 0.1;
352 settings.test_validity = false;
354 // SQL Server gives: 0.28937764436705 and 0.000786406897532288 with 44/35 rings
355 // PostGIS gives: 0.30859375 and 0.033203125 with 35/35 rings
356 TEST_DIFFERENCE_WITH(geos_1,
357 -1, BG_IF_KRAMER(0.29171, 0.20705),
358 -1, BG_IF_KRAMER(0.00076855, 0.00060440758),
364 // MSVC 14 expects 138.69214 and 211.85913: increase percentage
366 ut_settings settings = sym_settings;
367 settings.percentage = 0.01;
368 settings.test_validity = false;
370 // Output polygons for sym difference might be combined
371 test_one<polygon, polygon, polygon>("geos_2",
372 geos_2[0], geos_2[1],
375 BG_IF_RESCALED(2, 1), -1, 138.6923828 + 211.859375,
379 // Output polygons for sym difference might be combined
380 test_one<polygon, polygon, polygon>("geos_3",
381 geos_3[0], geos_3[1],
384 BG_IF_RESCALED(1, 2), -1, 16211128.5 + 13180420.0,
387 test_one<polygon, polygon, polygon>("geos_4",
388 geos_4[0], geos_4[1],
393 test_one<polygon, polygon, polygon>("ggl_list_20110306_javier",
394 ggl_list_20110306_javier[0], ggl_list_20110306_javier[1],
397 2, -1, 71495.3331 + 8960.49049);
399 test_one<polygon, polygon, polygon>("ggl_list_20110307_javier",
400 ggl_list_20110307_javier[0], ggl_list_20110307_javier[1],
401 1, if_typed<ct, float>(14, 13), 16815.6,
405 if ( BOOST_GEOMETRY_CONDITION((! boost::is_same<ct, float>::value)) )
407 TEST_DIFFERENCE(ggl_list_20110716_enrico,
408 3, 35723.8506317139, // TODO FOR GENERIC, misses one of three outputs
413 #if defined(BOOST_GEOMETRY_USE_RESCALING) \
414 || ! defined(BOOST_GEOMETRY_USE_KRAMER_RULE) \
415 || defined(BOOST_GEOMETRY_TEST_FAILURES)
417 // Symmetric difference should output one polygon
418 // Using rescaling, it currently outputs two.
419 ut_settings settings;
420 settings.test_validity = false;
422 TEST_DIFFERENCE_WITH(ggl_list_20110820_christophe,
423 1, 2.8570121719168924,
424 1, 64.498061986388564,
425 BG_IF_RESCALED(2, 1));
429 test_one<polygon, polygon, polygon>("ggl_list_20120717_volker",
430 ggl_list_20120717_volker[0], ggl_list_20120717_volker[1],
431 1, 11, 3370866.2295081965,
432 1, 5, 384.2295081964694,
435 // 2011-07-02 / 2014-06-19
436 // Interesting FP-precision case.
437 // sql server gives: 6.62295817619452E-05
438 // PostGIS gives: 0.0 (no output)
439 // Boost.Geometry gave results depending on FP-type, and compiler, and operating system.
440 // With rescaling results are equal w.r.t. compiler/FP type,
441 // however, some long spikes are still generated in the resulting difference
442 // Without rescaling there is no output, like PostGIS
443 test_one<polygon, polygon, polygon>("ggl_list_20110627_phillip",
444 ggl_list_20110627_phillip[0], ggl_list_20110627_phillip[1],
445 BG_IF_RESCALED(1, 0), -1,
446 BG_IF_RESCALED(if_typed_tt<ct>(0.0000000000001105367, 0.000125137888971949), 0),
447 1, -1, 3577.40960816756,
452 // With rescaling, difference of output a-b and a sym b is invalid
453 ut_settings settings;
454 settings.test_validity = BG_IF_RESCALED(false, true);
455 TEST_DIFFERENCE_WITH(ggl_list_20190307_matthieu_1,
456 BG_IF_KRAMER(2, 1), 0.18461532,
457 BG_IF_KRAMER(2, 1), 0.617978,
459 TEST_DIFFERENCE_WITH(ggl_list_20190307_matthieu_2, 2, 12.357152, 0, 0.0, 2);
462 // Ticket 8310, one should be completely subtracted from the other.
463 test_one<polygon, polygon, polygon>("ticket_8310a",
464 ticket_8310a[0], ticket_8310a[1],
467 test_one<polygon, polygon, polygon>("ticket_8310b",
468 ticket_8310b[0], ticket_8310b[1],
471 test_one<polygon, polygon, polygon>("ticket_8310c",
472 ticket_8310c[0], ticket_8310c[1],
476 test_one<polygon, polygon, polygon>("ticket_9081_15",
477 ticket_9081_15[0], ticket_9081_15[1],
478 2, -1, 0.0334529710902111,
479 BG_IF_RESCALED(1, 0), -1, BG_IF_RESCALED(5.3469555172380723e-010, 0));
481 test_one<polygon, polygon, polygon>("ticket_9081_314",
482 ticket_9081_314[0], ticket_9081_314[1],
483 2, 12, 0.0451236449624935,
487 ut_settings settings;
488 settings.test_validity = BG_IF_RESCALED(true, false);
489 #if ! defined(BOOST_GEOMETRY_USE_RESCALING) && defined(BOOST_GEOMETRY_USE_KRAMER_RULE)
490 const int expected_count = 1; // Wrong, considers all consecutive polygons as one
492 const int expected_count = 6;
494 TEST_DIFFERENCE_WITH(ticket_9563,
496 expected_count, 20.096189,
500 test_one<polygon, polygon, polygon>("ticket_10108_a",
501 ticket_10108_a[0], ticket_10108_a[1],
506 test_one<polygon, polygon, polygon>("ticket_10108_b",
507 ticket_10108_b[0], ticket_10108_b[1],
510 BG_IF_RESCALED(2, 1), -1, 1081.68697 + 1342.65795);
512 test_one<polygon, polygon, polygon>("ticket_11725",
513 ticket_11725[0], ticket_11725[1],
518 // From assemble-test, with a u/u case
519 test_one<polygon, polygon, polygon>("assemble_0210",
520 "POLYGON((0 0,0 10,10 10,10 0,0 0),(8.5 1,9.5 1,9.5 2,8.5 2,8.5 1))",
521 "POLYGON((2 0.5,0.5 2,0.5 8,2 9.5,6 9.5,8.5 8,8.5 2,7 0.5,2 0.5),(2 2,7 2,7 8,2 8,2 2))",
525 #if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE)
526 typedef bg::model::box<P> box;
527 typedef bg::model::ring<P> ring;
529 // Other combinations
531 test_one<polygon, polygon, ring>(
532 "star_ring_ring", example_star, example_ring,
537 test_one<polygon, ring, polygon>(
538 "ring_star_ring", example_ring, example_star,
543 static std::string const clip = "POLYGON((2.5 0.5,5.5 2.5))";
545 test_one<polygon, box, ring>("star_box",
547 4, 20, 2.833333, 4, 16, 0.833333);
549 test_one<polygon, ring, box>("box_star",
551 4, 16, 0.833333, 4, 20, 2.833333);
556 typedef bg::model::polygon<P, false> polygon_ccw;
557 test_one<polygon, polygon_ccw, polygon_ccw>(
558 "star_ring_ccw", example_star, example_ring,
562 test_one<polygon, polygon, polygon_ccw>(
563 "star_ring_ccw1", example_star, example_ring,
567 test_one<polygon, polygon_ccw, polygon>(
568 "star_ring_ccw2", example_star, example_ring,
574 // Multi/box (should be moved to multi)
576 typedef bg::model::multi_polygon<polygon> mp;
578 static std::string const clip = "POLYGON((2 2,4 4))";
580 test_one<polygon, box, mp>("simplex_multi_box_mp",
581 clip, case_multi_simplex[0],
582 2, -1, 0.53333333333, 3, -1, 8.53333333333);
583 test_one<polygon, mp, box>("simplex_multi_mp_box",
584 case_multi_simplex[0], clip,
585 3, -1, 8.53333333333, 2, -1, 0.53333333333);
590 // Rescaling generates a very small false polygon
592 ut_settings settings;
593 #if defined(BOOST_GEOMETRY_USE_KRAMER_RULE)
594 settings.test_validity = BG_IF_RESCALED(true, false);
596 TEST_DIFFERENCE_WITH(issue_566_a, 1, 143.662, BG_IF_RESCALED(1, 0),
597 BG_IF_RESCALED(1.605078e-6, 0.0),
598 BG_IF_RESCALED(2, 1));
600 TEST_DIFFERENCE(issue_566_b, 1, 143.662, BG_IF_RESCALED(1, 0),
601 BG_IF_RESCALED(1.605078e-6, 0.0),
602 BG_IF_RESCALED(2, 1));
604 TEST_DIFFERENCE(mysql_21977775, 2, 160.856568913, 2, 92.3565689126, 4);
605 TEST_DIFFERENCE(mysql_21965285, 1, 92.0, 1, 14.0, 1);
606 TEST_DIFFERENCE(mysql_23023665_1, 1, 92.0, 1, 142.5, 2);
607 TEST_DIFFERENCE(mysql_23023665_2, 1, 96.0, 1, 16.0, 2);
608 TEST_DIFFERENCE(mysql_23023665_3, 1, 225.0, 1, 66.0, 2);
609 TEST_DIFFERENCE(mysql_23023665_5, 2, 165.23735, 2, 105.73735, 4);
610 #if defined(BOOST_GEOMETRY_USE_RESCALING) \
611 || ! defined(BOOST_GEOMETRY_USE_KRAMER_RULE) \
612 || defined(BOOST_GEOMETRY_TEST_FAILURES)
613 // Testcases going wrong with Kramer's rule and no rescaling
614 TEST_DIFFERENCE(mysql_23023665_6, 2, 105.68756, 3, 10.18756, 5);
615 TEST_DIFFERENCE(mysql_23023665_13, 3, 99.74526, 3, 37.74526, 6);
620 // Test cases for integer coordinates / ccw / open
621 template <typename Point, bool ClockWise, bool Closed>
624 typedef bg::model::polygon<Point, ClockWise, Closed> polygon;
626 test_one<polygon, polygon, polygon>("ggl_list_20120717_volker",
627 ggl_list_20120717_volker[0], ggl_list_20120717_volker[1],
630 1, 16, 3371540 + 385);
632 test_one<polygon, polygon, polygon>("ticket_10658",
633 ticket_10658[0], ticket_10658[1],
637 test_one<polygon, polygon, polygon>("ticket_11121",
638 ticket_11121[0], ticket_11121[1],
642 // Generates spikes, both a-b and b-a
643 TEST_DIFFERENCE(ticket_11676, 2, 2537992.5, 2, 294963.5, 3);
646 int test_main(int, char* [])
648 BoostGeometryWriteTestConfiguration();
649 test_all<bg::model::d2::point_xy<default_test_type> >();
651 test_specific<bg::model::d2::point_xy<int>, false, false>();
653 #if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE)
654 test_all<bg::model::d2::point_xy<float> >();
657 std::cout << "Testing TTMATH" << std::endl;
658 test_all<bg::model::d2::point_xy<ttmath_big> >();