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 #if !defined(BOOST_GEOMETRY_INCLUDE_SELF_TURNS)
45 #define TEST_DIFFERENCE_IGNORE(caseid, clips1, area1, clips2, area2, clips3) \
46 { ut_settings ignore_validity; ignore_validity.test_validity = false; \
47 (test_one<polygon, polygon, polygon>) \
48 ( #caseid, caseid[0], caseid[1], clips1, -1, area1, clips2, -1, area2, \
49 clips3, -1, area1 + area2, ignore_validity); }
55 typedef bg::model::box
<P
> box
;
56 typedef bg::model::polygon
<P
> polygon
;
57 typedef bg::model::ring
<P
> ring
;
59 typedef typename
bg::coordinate_type
<P
>::type ct
;
61 ut_settings sym_settings
;
62 #if defined(BOOST_GEOMETRY_NO_ROBUSTNESS)
63 sym_settings
.sym_difference
= false;
66 test_one
<polygon
, polygon
, polygon
>("simplex_normal",
67 simplex_normal
[0], simplex_normal
[1],
68 3, 12, 2.52636706856656,
69 3, 12, 3.52636706856656,
72 test_one
<polygon
, polygon
, polygon
>("simplex_with_empty",
73 simplex_normal
[0], polygon_empty
,
77 test_one
<polygon
, polygon
, polygon
>(
78 "star_ring", example_star
, example_ring
,
83 test_one
<polygon
, polygon
, polygon
>("two_bends",
84 two_bends
[0], two_bends
[1],
88 test_one
<polygon
, polygon
, polygon
>("star_comb_15",
89 star_comb_15
[0], star_comb_15
[1],
90 30, 160, 227.658275102812,
91 30, 198, 480.485775259312,
94 test_one
<polygon
, polygon
, polygon
>("new_hole",
95 new_hole
[0], new_hole
[1],
100 test_one
<polygon
, polygon
, polygon
>("crossed",
101 crossed
[0], crossed
[1],
105 test_one
<polygon
, polygon
, polygon
>("disjoint",
106 disjoint
[0], disjoint
[1],
110 // The too small one might be discarded (depending on point-type / compiler)
111 // We check area only
112 test_one
<polygon
, polygon
, polygon
>("distance_zero",
113 distance_zero
[0], distance_zero
[1],
118 test_one
<polygon
, polygon
, polygon
>("equal_holes_disjoint",
119 equal_holes_disjoint
[0], equal_holes_disjoint
[1],
123 test_one
<polygon
, polygon
, polygon
>("only_hole_intersections1",
124 only_hole_intersections
[0], only_hole_intersections
[1],
129 test_one
<polygon
, polygon
, polygon
>("only_hole_intersection2",
130 only_hole_intersections
[0], only_hole_intersections
[2],
135 test_one
<polygon
, polygon
, polygon
>("first_within_second",
136 first_within_second
[1], first_within_second
[0],
140 test_one
<polygon
, polygon
, polygon
>("fitting",
141 fitting
[0], fitting
[1],
146 test_one
<polygon
, polygon
, polygon
>("identical",
147 identical
[0], identical
[1],
151 test_one
<polygon
, polygon
, polygon
>("intersect_exterior_and_interiors_winded",
152 intersect_exterior_and_interiors_winded
[0], intersect_exterior_and_interiors_winded
[1],
156 test_one
<polygon
, polygon
, polygon
>("intersect_holes_intersect_and_disjoint",
157 intersect_holes_intersect_and_disjoint
[0], intersect_holes_intersect_and_disjoint
[1],
161 test_one
<polygon
, polygon
, polygon
>("intersect_holes_intersect_and_touch",
162 intersect_holes_intersect_and_touch
[0], intersect_holes_intersect_and_touch
[1],
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],
191 test_one
<polygon
, polygon
, polygon
>(
192 "case4", case_4
[0], case_4
[1],
193 6, 28, 2.77878787878788,
194 4, 22, 4.77878787878788,
197 test_one
<polygon
, polygon
, polygon
>(
198 "case5", case_5
[0], case_5
[1],
199 8, 36, 2.43452380952381,
200 7, 33, 3.18452380952381);
202 #ifdef BOOST_GEOMETRY_TEST_INCLUDE_FAILING_TESTS
203 // Fails, a-b is partly generated, b-a does not have any output
204 // It failed already in 1.59
205 test_one
<polygon
, polygon
, polygon
>("case_58_iet",
206 case_58
[0], case_58
[2],
208 1, -1, 11.1666666667);
211 test_one
<polygon
, polygon
, polygon
>("case_80",
212 case_80
[0], case_80
[1],
216 #ifdef BOOST_GEOMETRY_TEST_INCLUDE_FAILING_TESTS
217 // Fails, holes are not subtracted
218 test_one
<polygon
, polygon
, polygon
>("case_81",
219 case_81
[0], case_81
[1],
225 test_one
<polygon
, polygon
, polygon
>("case_100",
226 case_100
[0], case_100
[1],
229 1, 13, 16.0 + 3.125);
231 test_one
<polygon
, polygon
, polygon
>("case_101",
232 case_101
[0], case_101
[1],
236 test_one
<polygon
, polygon
, polygon
>("case_102",
237 case_102
[0], case_102
[1],
241 TEST_DIFFERENCE(case_105
, 4, 8.0, 1, 16.0, 5);
242 TEST_DIFFERENCE(case_106
, 1, 17.5, 2, 32.5, 3);
243 TEST_DIFFERENCE(case_107
, 2, 18.0, 2, 29.0, 4);
245 test_one
<polygon
, polygon
, polygon
>("winded",
246 winded
[0], winded
[1],
250 test_one
<polygon
, polygon
, polygon
>("within_holes_disjoint",
251 within_holes_disjoint
[0], within_holes_disjoint
[1],
255 test_one
<polygon
, polygon
, polygon
>("side_side",
256 side_side
[0], side_side
[1],
261 test_one
<polygon
, polygon
, polygon
>("buffer_mp1",
262 buffer_mp1
[0], buffer_mp1
[1],
266 #if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS)
267 if ( BOOST_GEOMETRY_CONDITION((boost::is_same
<ct
, double>::value
)) )
269 test_one
<polygon
, polygon
, polygon
>("buffer_mp2",
270 buffer_mp2
[0], buffer_mp2
[1],
276 /*** TODO: self-tangencies for difference
277 test_one<polygon, polygon, polygon>("wrapped_a",
278 wrapped[0], wrapped[1],
282 test_one<polygon, polygon, polygon>("wrapped_b",
283 wrapped[0], wrapped[2],
289 ut_settings settings
;
290 #if defined(BOOST_GEOMETRY_NO_ROBUSTNESS)
291 settings
.percentage
= 0.1;
292 settings
.test_validity
= false;
294 settings
.percentage
= 0.001;
297 // Isovist - the # output polygons differ per compiler/pointtype, (very) small
298 // rings might be discarded. We check area only
299 test_one
<polygon
, polygon
, polygon
>("isovist",
300 isovist1
[0], isovist1
[1],
305 // SQL Server gives: 0.279121891701124 and 224.889211358929
306 // PostGIS gives: 0.279121991127244 and 224.889205853156
307 // No robustness gives: 0.279121991127106 and 224.825363749290
309 #ifdef BOOST_GEOMETRY_TEST_INCLUDE_FAILING_TESTS
310 test_one
<polygon
, polygon
, polygon
>("geos_1",
311 geos_1
[0], geos_1
[1],
315 // Excluded this test in the normal suite, it is OK like this for many clang/gcc/msvc
316 // versions, but NOT OK for many other clang/gcc/msvc versions on other platforms
317 // It might depend on partition (order)
318 // 10, -1, 0.02148439); // change in partition might give these results
320 // SQL Server gives: 0.28937764436705 and 0.000786406897532288 with 44/35 rings
321 // PostGIS gives: 0.30859375 and 0.033203125 with 35/35 rings
325 // MSVC 14 expects 138.69214 and 211.85913: increase percentage
327 ut_settings settings
= sym_settings
;
328 settings
.percentage
= 0.01;
329 settings
.test_validity
= false;
331 test_one
<polygon
, polygon
, polygon
>("geos_2",
332 geos_2
[0], geos_2
[1],
338 test_one
<polygon
, polygon
, polygon
>("geos_3",
339 geos_3
[0], geos_3
[1],
342 1, -1, 16211128.5 + 13180420.0,
345 test_one
<polygon
, polygon
, polygon
>("geos_4",
346 geos_4
[0], geos_4
[1],
351 test_one
<polygon
, polygon
, polygon
>("ggl_list_20110306_javier",
352 ggl_list_20110306_javier
[0], ggl_list_20110306_javier
[1],
355 2, -1, 71495.3331 + 8960.49049);
357 test_one
<polygon
, polygon
, polygon
>("ggl_list_20110307_javier",
358 ggl_list_20110307_javier
[0], ggl_list_20110307_javier
[1],
359 1, if_typed
<ct
, float>(14, 13), 16815.6,
363 if ( BOOST_GEOMETRY_CONDITION((! boost::is_same
<ct
, float>::value
)) )
365 test_one
<polygon
, polygon
, polygon
>("ggl_list_20110716_enrico",
366 ggl_list_20110716_enrico
[0], ggl_list_20110716_enrico
[1],
367 3, -1, 35723.8506317139,
368 1, -1, 58456.4964294434,
369 1, -1, 35723.8506317139 + 58456.4964294434);
372 #if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS)
374 // symmetric difference is not valid due to robustness issue, it has
375 // two turns (touch_only) and a midpoint is located in other polygon
376 ut_settings ignore_validity
;
377 ignore_validity
.test_validity
= false;
379 test_one
<polygon
, polygon
, polygon
>("ggl_list_20110820_christophe",
380 ggl_list_20110820_christophe
[0], ggl_list_20110820_christophe
[1],
381 1, -1, 2.8570121719168924,
382 1, -1, 64.498061986388564,
387 test_one
<polygon
, polygon
, polygon
>("ggl_list_20120717_volker",
388 ggl_list_20120717_volker
[0], ggl_list_20120717_volker
[1],
389 1, 11, 3370866.2295081965,
390 1, 5, 384.2295081964694,
393 #if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS)
394 // 2011-07-02 / 2014-06-19
395 // Interesting FP-precision case.
396 // sql server gives: 6.62295817619452E-05
397 // PostGIS gives: 0.0 (no output)
398 // Boost.Geometry gave results depending on FP-type, and compiler, and operating system.
399 // Since rescaling to integer results are equal w.r.t. compiler/FP type,
400 // however, some long spikes are still generated in the resulting difference
401 test_one
<polygon
, polygon
, polygon
>("ggl_list_20110627_phillip",
402 ggl_list_20110627_phillip
[0], ggl_list_20110627_phillip
[1],
403 if_typed_tt
<ct
>(1, 1), -1,
404 if_typed_tt
<ct
>(0.0000000000001105367, 0.000125137888971949),
405 1, -1, 3577.40960816756,
410 // Ticket 8310, one should be completely subtracted from the other.
411 test_one
<polygon
, polygon
, polygon
>("ticket_8310a",
412 ticket_8310a
[0], ticket_8310a
[1],
415 test_one
<polygon
, polygon
, polygon
>("ticket_8310b",
416 ticket_8310b
[0], ticket_8310b
[1],
419 test_one
<polygon
, polygon
, polygon
>("ticket_8310c",
420 ticket_8310c
[0], ticket_8310c
[1],
424 #if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS)
425 test_one
<polygon
, polygon
, polygon
>("ticket_9081_15",
426 ticket_9081_15
[0], ticket_9081_15
[1],
427 2, 10, 0.0334529710902111,
428 1, 4, 5.3469555172380723e-010);
431 test_one
<polygon
, polygon
, polygon
>("ticket_9081_314",
432 ticket_9081_314
[0], ticket_9081_314
[1],
433 2, 12, 0.0451236449624935,
436 #if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS)
437 test_one
<polygon
, polygon
, polygon
>("ticket_9563",
438 ticket_9563
[0], ticket_9563
[1],
443 test_one
<polygon
, polygon
, polygon
>("ticket_10108_a",
444 ticket_10108_a
[0], ticket_10108_a
[1],
449 #if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS)
450 test_one
<polygon
, polygon
, polygon
>("ticket_10108_b",
451 ticket_10108_b
[0], ticket_10108_b
[1],
456 test_one
<polygon
, polygon
, polygon
>("ticket_11725",
457 ticket_11725
[0], ticket_11725
[1],
462 // From assemble-test, with a u/u case
463 test_one
<polygon
, polygon
, polygon
>("assemble_0210",
464 "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))",
465 "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))",
471 test_one
<polygon
, polygon
, ring
>(
472 "star_ring_ring", example_star
, example_ring
,
477 test_one
<polygon
, ring
, polygon
>(
478 "ring_star_ring", example_ring
, example_star
,
483 static std::string
const clip
= "POLYGON((2.5 0.5,5.5 2.5))";
485 test_one
<polygon
, box
, ring
>("star_box",
487 4, 20, 2.833333, 4, 16, 0.833333);
489 test_one
<polygon
, ring
, box
>("box_star",
491 4, 16, 0.833333, 4, 20, 2.833333);
496 typedef bg::model::polygon
<P
, false> polygon_ccw
;
497 test_one
<polygon
, polygon_ccw
, polygon_ccw
>(
498 "star_ring_ccw", example_star
, example_ring
,
502 test_one
<polygon
, polygon
, polygon_ccw
>(
503 "star_ring_ccw1", example_star
, example_ring
,
507 test_one
<polygon
, polygon_ccw
, polygon
>(
508 "star_ring_ccw2", example_star
, example_ring
,
514 // Multi/box (should be moved to multi)
516 typedef bg::model::multi_polygon
<polygon
> mp
;
518 static std::string
const clip
= "POLYGON((2 2,4 4))";
520 test_one
<polygon
, box
, mp
>("simplex_multi_box_mp",
521 clip
, case_multi_simplex
[0],
522 2, -1, 0.53333333333, 3, -1, 8.53333333333);
523 test_one
<polygon
, mp
, box
>("simplex_multi_mp_box",
524 case_multi_simplex
[0], clip
,
525 3, -1, 8.53333333333, 2, -1, 0.53333333333);
530 Experimental (cut), does not work:
531 test_one<polygon, polygon, polygon>(
532 "polygon_pseudo_line",
533 "POLYGON((0 0,0 4,4 4,4 0,0 0))",
534 "POLYGON((2 -2,2 -1,2 6,2 -2))",
539 // Should have 2 outputs
540 #ifdef BOOST_GEOMETRY_INCLUDE_SELF_TURNS
541 TEST_DIFFERENCE(mysql_21977775
,
542 2, 160.856568913, 2, 92.3565689126, 4);
544 TEST_DIFFERENCE_IGNORE(mysql_21977775
,
545 1, 160.856568913, 2, 92.3565689126, 3);
548 TEST_DIFFERENCE(mysql_21965285
, 1, 92.0, 1, 14.0, 1);
550 TEST_DIFFERENCE(mysql_23023665_1
, 1, 92.0, 1, 142.5, 2);
551 TEST_DIFFERENCE(mysql_23023665_2
, 1, 96.0, 1, 16.0, 2);
552 TEST_DIFFERENCE(mysql_23023665_3
, 1, 225.0, 1, 66.0, 2);
553 #ifdef BOOST_GEOMETRY_INCLUDE_SELF_TURNS
554 TEST_DIFFERENCE(mysql_23023665_5
, 2, 165.23735, 2, 105.73735, 4);
556 TEST_DIFFERENCE_IGNORE(mysql_23023665_5
, 1, 165.23735, 2, 105.73735, 3);
559 TEST_DIFFERENCE(mysql_23023665_6
, 2, 105.68756, 3, 10.18756, 5);
561 #ifdef BOOST_GEOMETRY_INCLUDE_SELF_TURNS
562 TEST_DIFFERENCE(mysql_23023665_13
, 3, 99.74526, 3, 37.74526, 6);
564 TEST_DIFFERENCE_IGNORE(mysql_23023665_13
, 2, 99.74526, 3, 37.74526, 5);
569 // Test cases for integer coordinates / ccw / open
570 template <typename Point
, bool ClockWise
, bool Closed
>
573 typedef bg::model::polygon
<Point
, ClockWise
, Closed
> polygon
;
575 test_one
<polygon
, polygon
, polygon
>("ggl_list_20120717_volker",
576 ggl_list_20120717_volker
[0], ggl_list_20120717_volker
[1],
579 1, 16, 3371540 + 385);
581 test_one
<polygon
, polygon
, polygon
>("ticket_10658",
582 ticket_10658
[0], ticket_10658
[1],
586 test_one
<polygon
, polygon
, polygon
>("ticket_11121",
587 ticket_11121
[0], ticket_11121
[1],
591 // Generates spikes, both a-b and b-a
592 #ifdef BOOST_GEOMETRY_INCLUDE_SELF_TURNS
593 TEST_DIFFERENCE(ticket_11676
, 2, 2537992.5, 2, 294963.5, 3);
595 TEST_DIFFERENCE_IGNORE(ticket_11676
, 1, 2537992.5, 2, 294963.5, 2);
600 int test_main(int, char* [])
602 test_all
<bg::model::d2::point_xy
<double> >();
604 test_specific
<bg::model::d2::point_xy
<int>, false, false>();
606 #if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE)
607 test_all
<bg::model::d2::point_xy
<float> >();
610 std::cout
<< "Testing TTMATH" << std::endl
;
611 test_all
<bg::model::d2::point_xy
<ttmath_big
> >();