1 // Boost.Geometry (aka GGL, Generic Geometry Library)
4 // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
5 // Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
6 // Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
8 // This file was modified by Oracle on 2015, 2016, 2017.
9 // Modifications copyright (c) 2015-2017, Oracle and/or its affiliates.
10 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
11 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
13 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
14 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
16 // Use, modification and distribution is subject to the Boost Software License,
17 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
18 // http://www.boost.org/LICENSE_1_0.txt)
24 #include <boost/config.hpp>
25 #include <boost/core/ignore_unused.hpp>
27 #include <boost/geometry/geometries/point_xy.hpp>
28 #include <boost/geometry/geometries/register/linestring.hpp>
30 #include <boost/geometry/util/condition.hpp>
31 #include <boost/geometry/util/rational.hpp>
33 #include "test_intersection.hpp"
34 #include <algorithms/test_overlay.hpp>
36 #include <algorithms/overlay/overlay_cases.hpp>
38 #include <test_common/test_point.hpp>
39 #include <test_common/with_pointer.hpp>
40 #include <test_geometries/custom_segment.hpp>
43 BOOST_GEOMETRY_REGISTER_LINESTRING_TEMPLATED(std::vector)
45 #define TEST_INTERSECTION(caseid, clips, points, area) \
46 (test_one<Polygon, Polygon, Polygon>) \
47 ( #caseid, caseid[0], caseid[1], clips, points, area)
49 #define TEST_INTERSECTION_REV(caseid, clips, points, area) \
50 (test_one<Polygon, Polygon, Polygon>) \
51 ( #caseid "_rev", caseid[1], caseid[0], clips, points, area)
53 #define TEST_INTERSECTION_WITH(caseid, index1, index2, \
54 clips, points, area, settings) \
55 (test_one<Polygon, Polygon, Polygon>) \
56 ( #caseid "_" #index1 "_" #index2, caseid[index1], caseid[index2], \
57 clips, points, area, settings)
59 template <typename Polygon>
62 typedef typename bg::coordinate_type<Polygon>::type ct;
63 bool const ccw = bg::point_order<Polygon>::value == bg::counterclockwise;
64 bool const open = bg::closure<Polygon>::value == bg::open;
66 test_one<Polygon, Polygon, Polygon>("simplex_with_empty_1",
67 simplex_normal[0], polygon_empty,
69 test_one<Polygon, Polygon, Polygon>("simplex_with_empty_2",
70 polygon_empty, simplex_normal[0],
73 test_one<Polygon, Polygon, Polygon>("simplex_normal",
74 simplex_normal[0], simplex_normal[1],
76 test_one<Polygon, Polygon, Polygon>("star_ring", example_star, example_ring,
79 test_one<Polygon, Polygon, Polygon>("star_poly", example_star, example_polygon,
80 1, 0, // CLN: 23 points, other types: 22 point (one is merged)
82 test_one<Polygon, Polygon, Polygon>("first_within_second1",
83 first_within_second[0], first_within_second[1],
86 test_one<Polygon, Polygon, Polygon>("first_within_second2",
87 first_within_second[1], first_within_second[0],
90 test_one<Polygon, Polygon, Polygon>("first_within_hole_of_second",
91 first_within_hole_of_second[0], first_within_hole_of_second[1],
94 // Two forming new hole
95 test_one<Polygon, Polygon, Polygon>("new_hole",
96 new_hole[0], new_hole[1],
100 test_one<Polygon, Polygon, Polygon>("identical",
101 identical[0], identical[1],
104 test_one<Polygon, Polygon, Polygon>("intersect_exterior_and_interiors_winded",
105 intersect_exterior_and_interiors_winded[0], intersect_exterior_and_interiors_winded[1],
108 test_one<Polygon, Polygon, Polygon>("intersect_holes_disjoint",
109 intersect_holes_disjoint[0], intersect_holes_disjoint[1],
112 test_one<Polygon, Polygon, Polygon>("intersect_holes_intersect",
113 intersect_holes_intersect[0], intersect_holes_intersect[1],
116 test_one<Polygon, Polygon, Polygon>("intersect_holes_intersect_and_disjoint",
117 intersect_holes_intersect_and_disjoint[0], intersect_holes_intersect_and_disjoint[1],
120 test_one<Polygon, Polygon, Polygon>("intersect_holes_intersect_and_touch",
121 intersect_holes_intersect_and_touch[0], intersect_holes_intersect_and_touch[1],
124 test_one<Polygon, Polygon, Polygon>("intersect_holes_new_ring",
125 intersect_holes_new_ring[0], intersect_holes_new_ring[1],
128 test_one<Polygon, Polygon, Polygon>("winded",
129 winded[0], winded[1],
132 test_one<Polygon, Polygon, Polygon>("within_holes_disjoint",
133 within_holes_disjoint[0], within_holes_disjoint[1],
136 test_one<Polygon, Polygon, Polygon>("side_side",
137 side_side[0], side_side[1],
140 test_one<Polygon, Polygon, Polygon>("two_bends",
141 two_bends[0], two_bends[1],
144 test_one<Polygon, Polygon, Polygon>("star_comb_15",
145 star_comb_15[0], star_comb_15[1],
146 28, 150, 189.952883);
148 test_one<Polygon, Polygon, Polygon>("simplex_normal",
149 simplex_normal[0], simplex_normal[1],
152 test_one<Polygon, Polygon, Polygon>("distance_zero",
153 distance_zero[0], distance_zero[1],
154 1, 0 /* f: 4, other: 5 */, 0.29516139, ut_settings(0.01));
156 test_one<Polygon, Polygon, Polygon>("equal_holes_disjoint",
157 equal_holes_disjoint[0], equal_holes_disjoint[1],
158 1, 20, 81.0 - 2.0 * 3.0 * 3.0 - 3.0 * 7.0);
160 test_one<Polygon, Polygon, Polygon>("only_hole_intersections1",
161 only_hole_intersections[0], only_hole_intersections[1],
163 test_one<Polygon, Polygon, Polygon>("only_hole_intersection2",
164 only_hole_intersections[0], only_hole_intersections[2],
167 test_one<Polygon, Polygon, Polygon>("fitting",
168 fitting[0], fitting[1],
171 test_one<Polygon, Polygon, Polygon>("crossed",
172 crossed[0], crossed[1],
175 test_one<Polygon, Polygon, Polygon>("pie_2_3_23_0",
176 pie_2_3_23_0[0], pie_2_3_23_0[1],
177 1, 4, 163292.679042133, ut_settings(0.1));
180 ut_settings settings(if_typed_tt<ct>(0.01, 0.1));
181 settings.test_validity = BG_IF_RESCALED(true, false);
183 // SQL Server gives: 88.1920416352664
184 // PostGIS gives: 88.19203677911
185 test_one<Polygon, Polygon, Polygon>("isovist",
186 isovist1[0], isovist1[1],
191 if (! BOOST_GEOMETRY_CONDITION((boost::is_same<ct, float>::value)) )
193 test_one<Polygon, Polygon, Polygon>("geos_1",
194 geos_1[0], geos_1[1],
195 1, -1, BG_IF_RESCALED(3461.12321694, BG_IF_KRAMER(3461.02336, 3461.105448)), // MSVC 14 reports 3461.025390625
196 ut_settings(0.01, false));
200 // In most cases: 0 (no intersection)
201 // In some cases: 1.430511474609375e-05 (clang/gcc on Xubuntu using b2)
202 // In some cases: 5.6022983000000002e-05 (powerpc64le-gcc-6-0)
203 test_one<Polygon, Polygon, Polygon>("geos_2", geos_2[0], geos_2[1],
204 0, 0, 6.0e-5, ut_settings(-1.0)); // -1 denotes: compare with <=
206 test_one<Polygon, Polygon, Polygon>("geos_3",
207 geos_3[0], geos_3[1],
209 test_one<Polygon, Polygon, Polygon>("geos_4",
210 geos_4[0], geos_4[1],
211 1, -1, 0.08368849, ut_settings(0.01));
214 if ( BOOST_GEOMETRY_CONDITION(! ccw && open) )
216 // Pointcount for ttmath/double (both 5) or float (4)
217 // double returns 5 (since method append_no_dups_or_spikes)
218 // but not for ccw/open. Those cases has to be adapted once, anyway,
219 // because for open always one point too much is generated...
220 test_one<Polygon, Polygon, Polygon>("ggl_list_20110306_javier",
221 ggl_list_20110306_javier[0], ggl_list_20110306_javier[1],
222 1, if_typed<ct, float>(4, 5),
224 ut_settings(if_typed<ct, float>(1.0, 0.01)));
227 // SQL Server reports: 0.400390625
228 // PostGIS reports 0.4
229 // BG did report 0.4 but with rescaling 0.397
230 // when selecting other IP closer at endpoint or if segment B is smaller than A
231 test_one<Polygon, Polygon, Polygon>("ggl_list_20110307_javier",
232 ggl_list_20110307_javier[0], ggl_list_20110307_javier[1],
233 1, 4, BG_IF_RESCALED(0.397162651, 0.40), ut_settings(0.01));
235 test_one<Polygon, Polygon, Polygon>("ggl_list_20110627_phillip",
236 ggl_list_20110627_phillip[0], ggl_list_20110627_phillip[1],
237 1, if_typed_tt<ct>(6, 5), 11151.6618);
239 test_one<Polygon, Polygon, Polygon>("ggl_list_20110716_enrico",
240 ggl_list_20110716_enrico[0], ggl_list_20110716_enrico[1],
241 3, 16, 35723.8506317139);
243 test_one<Polygon, Polygon, Polygon>("ggl_list_20131119_james",
244 ggl_list_20131119_james[0], ggl_list_20131119_james[1],
245 1, 4, 6.6125873045, ut_settings(0.1));
247 test_one<Polygon, Polygon, Polygon>("ggl_list_20140223_shalabuda",
248 ggl_list_20140223_shalabuda[0], ggl_list_20140223_shalabuda[1],
249 1, 4, 3.77106, ut_settings(0.001));
251 // Mailed to the Boost.Geometry list on 2014/03/21 by 7415963@gmail.com
252 test_one<Polygon, Polygon, Polygon>("ggl_list_20140321_7415963",
253 ggl_list_20140321_7415963[0], ggl_list_20140321_7415963[1],
254 0, 0, 0, ut_settings(0.1));
256 TEST_INTERSECTION(ggl_list_20190307_matthieu_1, 2, -1, 0.035136);
257 TEST_INTERSECTION(ggl_list_20190307_matthieu_2, 1, -1, 3.64285);
259 #if defined(BOOST_GEOMETRY_USE_RESCALING) || ! defined(BOOST_GEOMETRY_USE_KRAMER_RULE) || defined(BOOST_GEOMETRY_TEST_FAILURES)
260 test_one<Polygon, Polygon, Polygon>("buffer_rt_f", buffer_rt_f[0], buffer_rt_f[1],
261 1, 4, 0.00029437899183903937, ut_settings(0.01));
263 test_one<Polygon, Polygon, Polygon>("buffer_rt_g", buffer_rt_g[0], buffer_rt_g[1],
264 1, 0, 2.914213562373);
266 test_one<Polygon, Polygon, Polygon>("ticket_8254", ticket_8254[0], ticket_8254[1],
267 if_typed<ct, float>(0, 1), -1, if_typed<ct, float>(0.0, 3.635930e-08), ut_settings(0.01));
268 test_one<Polygon, Polygon, Polygon>("ticket_6958", ticket_6958[0], ticket_6958[1],
269 if_typed<ct, float>(0, 1), -1, if_typed<ct, float>(0.0, 4.34355e-05), ut_settings(0.01));
270 test_one<Polygon, Polygon, Polygon>("ticket_8652", ticket_8652[0], ticket_8652[1],
273 TEST_INTERSECTION(ticket_8310a, 1, 5, 0.3843747);
274 TEST_INTERSECTION(ticket_8310b, 1, 5, 0.3734379);
275 TEST_INTERSECTION(ticket_8310c, 1, 5, 0.4689541);
276 TEST_INTERSECTION_REV(ticket_8310a, 1, 5, 0.3843747);
277 TEST_INTERSECTION_REV(ticket_8310b, 1, 5, 0.3734379);
278 TEST_INTERSECTION_REV(ticket_8310c, 1, 5, 0.4689541);
280 test_one<Polygon, Polygon, Polygon>("ticket_9081_15",
281 ticket_9081_15[0], ticket_9081_15[1],
282 1, 4, 0.0068895780745301394);
284 test_one<Polygon, Polygon, Polygon>("ticket_10108_a",
285 ticket_10108_a[0], ticket_10108_a[1],
289 // mingw 5.6022954e-5
290 test_one<Polygon, Polygon, Polygon>("ticket_10108_b",
291 ticket_10108_b[0], ticket_10108_b[1],
292 0, 0, 5.6022983e-5, ut_settings(-1.0));
294 test_one<Polygon, Polygon, Polygon>("ticket_10747_a",
295 ticket_10747_a[0], ticket_10747_a[1],
296 1, 4, 70368744177664.0);
297 test_one<Polygon, Polygon, Polygon>("ticket_10747_b",
298 ticket_10747_b[0], ticket_10747_b[1],
299 1, 4, 7036874417766400.0);
300 test_one<Polygon, Polygon, Polygon>("ticket_10747_c",
301 ticket_10747_c[0], ticket_10747_c[1],
302 1, 4, 17592186044416.0);
303 test_one<Polygon, Polygon, Polygon>("ticket_10747_d",
304 ticket_10747_d[0], ticket_10747_d[1],
305 1, 4, 703687777321.0);
307 // Delivers very small triangle < 1.0e-13, or zero
308 test_one<Polygon, Polygon, Polygon>("ticket_10747_e",
309 ticket_10747_e[0], ticket_10747_e[1],
310 BG_IF_RESCALED(1, 0), -1, 1.0e-13, ut_settings(-1.0));
312 test_one<Polygon, Polygon, Polygon>("ticket_11576",
313 ticket_11576[0], ticket_11576[1],
314 if_typed<ct, float>(0, 1), -1, if_typed<ct, float>(0.0, 5.585617332907136e-07));
317 // Not yet valid when rescaling is turned off
318 ut_settings settings;
319 settings.test_validity = BG_IF_RESCALED(true, false);
320 test_one<Polygon, Polygon, Polygon>("ticket_9563", ticket_9563[0], ticket_9563[1],
321 1, 8, 129.90381, settings);
324 #if ! defined(BOOST_GEOMETRY_USE_RESCALING) || defined(BOOST_GEOMETRY_TEST_FAILURES)
325 // With rescaling the output is empty
326 TEST_INTERSECTION(issue_548, 1, -1, 1958824415.2151);
329 TEST_INTERSECTION(issue_566_a, 1, -1, 70.7107);
330 TEST_INTERSECTION(issue_566_b, 1, -1, 70.7107);
332 test_one<Polygon, Polygon, Polygon>("buffer_mp1", buffer_mp1[0], buffer_mp1[1],
334 test_one<Polygon, Polygon, Polygon>("buffer_mp2", buffer_mp2[0], buffer_mp2[1],
337 test_one<Polygon, Polygon, Polygon>("case_58_iet",
338 case_58[0], case_58[2],
341 test_one<Polygon, Polygon, Polygon>("case_80",
342 case_80[0], case_80[1],
345 test_one<Polygon, Polygon, Polygon>("case_81",
346 case_81[0], case_81[1],
349 test_one<Polygon, Polygon, Polygon>("case_101",
350 case_101[0], case_101[1],
352 test_one<Polygon, Polygon, Polygon>("case_102",
353 case_102[0], case_102[1],
356 test_one<Polygon, Polygon, Polygon>("case_103",
357 case_103[0], case_103[1],
359 test_one<Polygon, Polygon, Polygon>("case_104",
360 case_104[0], case_104[1],
363 TEST_INTERSECTION(case_105, 1, 34, 76.0);
364 TEST_INTERSECTION(case_106, 2, -1, 3.5);
365 TEST_INTERSECTION(case_107, 3, -1, 3.0);
367 TEST_INTERSECTION(case_precision_1, 0, 0, 0.0);
368 TEST_INTERSECTION(case_precision_2, 0, 0, 0.0);
369 TEST_INTERSECTION(case_precision_3, 0, 0, 0.0);
370 TEST_INTERSECTION(case_precision_4, 0, 0, 0.0);
371 TEST_INTERSECTION(case_precision_5, 0, 0, 0.0);
372 TEST_INTERSECTION(case_precision_6, 1, -1, 14.0);
373 TEST_INTERSECTION(case_precision_7, 0, -1, 0.0);
374 TEST_INTERSECTION(case_precision_8, 1, -1, 14.0);
375 TEST_INTERSECTION(case_precision_9, 1, -1, 14.0);
376 TEST_INTERSECTION(case_precision_10, 1, -1, 14.0);
377 TEST_INTERSECTION(case_precision_11, 1, -1, 14.0);
378 TEST_INTERSECTION(case_precision_12, 1, -1, 2.0);
379 TEST_INTERSECTION(case_precision_13, 1, -1, 1.99998);
380 TEST_INTERSECTION(case_precision_14, 0, -1, 0.0);
381 TEST_INTERSECTION(case_precision_15, 1, -1, 14.0);
382 TEST_INTERSECTION(case_precision_16, 1, -1, 14.0);
383 TEST_INTERSECTION(case_precision_17, 1, -1, 14.0);
384 TEST_INTERSECTION(case_precision_18, 1, -1, 14.0);
385 TEST_INTERSECTION(case_precision_19, 1, -1, 14.0);
386 TEST_INTERSECTION(case_precision_20, 0, 0, 0.0);
387 TEST_INTERSECTION(case_precision_21, 0, 0, 0.0);
388 TEST_INTERSECTION(case_precision_22, 1, -1, 14.0);
389 TEST_INTERSECTION(case_precision_23, 1, -1, 14.0);
390 TEST_INTERSECTION(case_precision_24, 0, 0, 0.0);
391 TEST_INTERSECTION(case_precision_25, 0, 0, 0.0);
392 TEST_INTERSECTION(case_precision_26, 1, -1, 14.0);
394 TEST_INTERSECTION_REV(case_precision_1, 0, 0, 0.0);
395 TEST_INTERSECTION_REV(case_precision_2, 0, 0, 0.0);
396 TEST_INTERSECTION_REV(case_precision_3, 0, 0, 0.0);
397 TEST_INTERSECTION_REV(case_precision_4, 0, 0, 0.0);
398 TEST_INTERSECTION_REV(case_precision_5, 0, 0, 0.0);
399 TEST_INTERSECTION_REV(case_precision_6, 1, -1, 14.0);
400 TEST_INTERSECTION_REV(case_precision_7, 0, -1, 0.0);
401 TEST_INTERSECTION_REV(case_precision_8, 1, -1, 14.0);
402 TEST_INTERSECTION_REV(case_precision_9, 1, -1, 14.0);
403 TEST_INTERSECTION_REV(case_precision_10, 1, -1, 14.0);
404 TEST_INTERSECTION_REV(case_precision_11, 1, -1, 14.0);
405 TEST_INTERSECTION_REV(case_precision_12, 1, -1, 2.0);
406 TEST_INTERSECTION_REV(case_precision_13, 1, -1, 1.99998);
407 TEST_INTERSECTION_REV(case_precision_14, 0, -1, 0.0);
408 TEST_INTERSECTION_REV(case_precision_15, 1, -1, 14.0);
409 TEST_INTERSECTION_REV(case_precision_16, 1, -1, 14.0);
410 TEST_INTERSECTION_REV(case_precision_17, 1, -1, 14.0);
411 TEST_INTERSECTION_REV(case_precision_18, 1, -1, 14.0);
412 TEST_INTERSECTION_REV(case_precision_19, 1, -1, 14.0);
413 TEST_INTERSECTION_REV(case_precision_20, 0, 0, 0.0);
414 TEST_INTERSECTION_REV(case_precision_21, 0, 0, 0.0);
415 TEST_INTERSECTION_REV(case_precision_22, 1, -1, 14.0);
416 TEST_INTERSECTION_REV(case_precision_23, 1, -1, 14.0);
417 TEST_INTERSECTION_REV(case_precision_24, 0, 0, 0.0);
418 TEST_INTERSECTION_REV(case_precision_25, 0, 0, 0.0);
419 TEST_INTERSECTION_REV(case_precision_26, 1, -1, 14.0);
421 test_one<Polygon, Polygon, Polygon>("mysql_21964049",
422 mysql_21964049[0], mysql_21964049[1],
425 test_one<Polygon, Polygon, Polygon>("mysql_21964465",
426 mysql_21964465[0], mysql_21964465[1],
429 test_one<Polygon, Polygon, Polygon>("mysql_21965285_b_inv",
430 mysql_21965285_b_inv[0],
431 mysql_21965285_b_inv[1],
432 2, -1, 183.71376870369406);
434 TEST_INTERSECTION(mysql_23023665_6, 2, 0, 11.812440191387557);
436 test_one<Polygon, Polygon, Polygon>("mysql_23023665_10",
437 mysql_23023665_10[0], mysql_23023665_10[1],
438 1, 0, -1, 54.701340543162523);
440 test_one<Polygon, Polygon, Polygon>("mysql_23023665_11",
441 mysql_23023665_11[0], mysql_23023665_11[1],
442 1, 0, -1, 35.933385462482065);
444 // test_one<Polygon, Polygon, Polygon>(
445 // "polygon_pseudo_line",
446 // "Polygon((0 0,0 4,4 4,4 0,0 0))",
447 // "Polygon((2 -2,2 -1,2 6,2 -2))",
448 // 5, 22, 1.1901714);
451 template <typename Polygon, typename Box>
452 void test_areal_clip()
454 test_one<Polygon, Box, Polygon>("boxring", example_box, example_ring,
456 test_one<Polygon, Polygon, Box>("boxring2", example_ring,example_box,
459 test_one<Polygon, Box, Polygon>("boxpoly", example_box, example_polygon,
462 test_one<Polygon, Box, Polygon>("poly1", example_box,
463 "POLYGON((3.4 2,4.1 3,5.3 2.6,5.4 1.2,4.9 0.8,2.9 0.7,2 1.3,2.4 1.7,2.8 1.8,3.4 1.2,3.7 1.6,3.4 2))",
466 test_one<Polygon, Box, Polygon>("clip_poly2", example_box,
467 "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,5.3 2.5,5.4 1.2,4.9 0.8,2.9 0.7,2 1.3))",
470 test_one<Polygon, Box, Polygon>("clip_poly3", example_box,
471 "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 1.2,4.9 0.8,2.9 0.7,2 1.3))",
474 test_one<Polygon, Box, Polygon>("clip_poly4", example_box,
475 "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))",
478 test_one<Polygon, Box, Polygon>("clip_poly5", example_box,
479 "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 1.2,2.9 0.7,2 1.3))",
482 test_one<Polygon, Box, Polygon>("clip_poly6", example_box,
483 "POLYGON((2 1.3,2.4 1.7,2.8 1.8,3.4 1.2,3.7 1.6,3.4 2,4.0 3.0,5.0 2.0,2.9 0.7,2 1.3))",
486 test_one<Polygon, Box, Polygon>("clip_poly7", "Box(0 0, 3 3)",
487 "POLYGON((2 2, 1 4, 2 4, 3 3, 2 2))",
492 template <typename Box>
493 void test_boxes(std::string const& wkt1, std::string const& wkt2, double expected_area, bool expected_result)
496 bg::read_wkt(wkt1, box1);
497 bg::read_wkt(wkt2, box2);
500 bg::assign_zero(box_out);
501 bool detected = bg::intersection(box1, box2, box_out);
502 typename bg::default_area_result<Box>::type area = bg::area(box_out);
504 BOOST_CHECK_EQUAL(detected, expected_result);
505 if (detected && expected_result)
507 BOOST_CHECK_CLOSE(area, expected_area, 0.01);
511 template <typename P>
512 void test_point_output()
514 typedef bg::model::linestring<P> linestring;
515 typedef bg::model::polygon<P> polygon;
516 typedef bg::model::box<P> box;
517 //typedef bg::model::segment<P> segment;
519 test_point_output<polygon, polygon>(simplex_normal[0], simplex_normal[1], 6);
520 test_point_output<box, polygon>("box(1 1,6 4)", simplex_normal[0], 4);
521 test_point_output<linestring, polygon>("linestring(0 2,6 2)", simplex_normal[0], 2);
522 // NYI because of sectionize:
523 // test_point_output<segment, polygon>("linestring(0 2,6 2)", simplex_normal[0], 2);
524 // NYI because needs special treatment:
525 // test_point_output<box, box>("box(0 0,4 4)", "box(2 2,6 6)", 2);
529 template <typename Polygon, typename LineString>
530 void test_areal_linear()
532 std::string const poly_simplex = "POLYGON((1 1,1 3,3 3,3 1,1 1))";
534 test_one_lp<LineString, Polygon, LineString>("simplex", poly_simplex, "LINESTRING(0 2,4 2)", 1, 2, 2.0);
535 test_one_lp<LineString, Polygon, LineString>("case2", poly_simplex, "LINESTRING(0 1,4 3)", 1, 2, sqrt(5.0));
536 test_one_lp<LineString, Polygon, LineString>("case3", "POLYGON((2 0,2 5,5 5,5 0,2 0))", "LINESTRING(0 1,1 2,3 2,4 3,6 3,7 4)", 1, 4, 2 + sqrt(2.0));
537 test_one_lp<LineString, Polygon, LineString>("case4", "POLYGON((0 0,0 4,2 4,2 0,0 0))", "LINESTRING(1 1,3 2,1 3)", 2, 4, sqrt(5.0));
539 test_one_lp<LineString, Polygon, LineString>("case5", poly_simplex, "LINESTRING(0 1,3 4)", 1, 2, sqrt(2.0));
540 test_one_lp<LineString, Polygon, LineString>("case6", "POLYGON((2 0,2 4,3 4,3 1,4 1,4 3,5 3,5 1,6 1,6 3,7 3,7 1,8 1,8 3,9 3,9 0,2 0))", "LINESTRING(1 1,10 3)", 4, 8,
541 // Pieces are 1 x 2/9:
542 4.0 * sqrt(1.0 + 4.0/81.0));
543 test_one_lp<LineString, Polygon, LineString>("case7", poly_simplex, "LINESTRING(1.5 1.5,2.5 2.5)", 1, 2, sqrt(2.0));
544 test_one_lp<LineString, Polygon, LineString>("case8", poly_simplex, "LINESTRING(1 0,2 0)", 0, 0, 0.0);
546 std::string const poly_9 = "POLYGON((1 1,1 4,4 4,4 1,1 1))";
547 test_one_lp<LineString, Polygon, LineString>("case9", poly_9, "LINESTRING(0 1,1 2,2 2)", 1, 2, 1.0);
548 test_one_lp<LineString, Polygon, LineString>("case10", poly_9, "LINESTRING(0 1,1 2,0 2)", 0, 0, 0.0);
549 test_one_lp<LineString, Polygon, LineString>("case11", poly_9, "LINESTRING(2 2,4 2,3 3)", 1, 3, 2.0 + sqrt(2.0));
550 test_one_lp<LineString, Polygon, LineString>("case12", poly_9, "LINESTRING(2 3,4 4,5 6)", 1, 2, sqrt(5.0));
552 test_one_lp<LineString, Polygon, LineString>("case13", poly_9, "LINESTRING(3 2,4 4,2 3)", 1, 3, 2.0 * sqrt(5.0));
553 test_one_lp<LineString, Polygon, LineString>("case14", poly_9, "LINESTRING(5 6,4 4,6 5)", 0, 0, 0.0);
554 test_one_lp<LineString, Polygon, LineString>("case15", poly_9, "LINESTRING(0 2,1 2,1 3,0 3)", 1, 2, 1.0);
555 test_one_lp<LineString, Polygon, LineString>("case16", poly_9, "LINESTRING(2 2,1 2,1 3,2 3)", 1, 4, 3.0);
557 std::string const angly = "LINESTRING(2 2,2 1,4 1,4 2,5 2,5 3,4 3,4 4,5 4,3 6,3 5,2 5,2 6,0 4)";
558 // PROPERTIES CHANGED BY switch_to_integer
559 // TODO test_one_lp<LineString, Polygon, LineString>("case17", "POLYGON((1 1,1 5,4 5,4 1,1 1))", angly, 3, 8, 6.0);
560 test_one_lp<LineString, Polygon, LineString>("case18", "POLYGON((1 1,1 5,5 5,5 1,1 1))", angly, 2, 12, 10.0 + sqrt(2.0));
561 test_one_lp<LineString, Polygon, LineString>("case19", poly_9, "LINESTRING(1 2,1 3,0 3)", 1, 2, 1.0);
562 test_one_lp<LineString, Polygon, LineString>("case20", poly_9, "LINESTRING(1 2,1 3,2 3)", 1, 3, 2.0);
564 test_one_lp<LineString, Polygon, LineString>("case21",
565 "POLYGON((2 3,-9 -7,12 -13,2 3))",
566 "LINESTRING(-1.3 0,-15 0,-1.3 0)",
569 test_one_lp<LineString, Polygon, LineString>("case22",
570 "POLYGON((0 0,0 10,10 10,10 0,0 0))",
571 "LINESTRING(5 5,-10 5,5 5)",
574 test_one_lp<LineString, Polygon, LineString>("case22a",
575 "POLYGON((0 0,0 10,10 10,10 0,0 0))",
576 "LINESTRING(1 1,5 5,-10 5,5 5,6 6)",
579 test_one_lp<LineString, Polygon, LineString>("case23",
580 "POLYGON((0 0,0 10,10 10,10 0,0 0))",
581 "LINESTRING(-10 5,5 5,-10 5)",
584 test_one_lp<LineString, Polygon, LineString>("case23a",
585 "POLYGON((0 0,0 10,10 10,10 0,0 0))",
586 "LINESTRING(-20 10,-10 5,5 5,-10 5,-20 -10)",
589 test_one_lp<LineString, Polygon, LineString>("case24",
590 "POLYGON((0 0,0 10,10 10,10 0,0 0))",
591 "LINESTRING(0 5,5 5,0 5)",
594 test_one_lp<LineString, Polygon, LineString>("case24",
595 "POLYGON((0 0,0 10,10 10,10 0,0 0))",
596 "LINESTRING(0 5,5 5,1 1,9 1,5 5,0 5)",
599 test_one_lp<LineString, Polygon, LineString>("case25",
600 "POLYGON((0 0,0 10,10 10,10 0,0 0))",
601 "LINESTRING(5 5,0 5,5 5)",
604 test_one_lp<LineString, Polygon, LineString>("case25a",
605 "POLYGON((0 0,0 10,10 10,10 0,0 0))",
606 "LINESTRING(-10 10,5 5,0 5,5 5,20 10)",
609 test_one_lp<LineString, Polygon, LineString>("case25b",
610 "POLYGON((0 0,0 10,10 10,10 0,0 0))",
611 "LINESTRING(-10 10,5 5,1 5,5 5,20 10)",
614 test_one_lp<LineString, Polygon, LineString>("case25c",
615 "POLYGON((0 0,0 10,10 10,10 0,0 0))",
616 "LINESTRING(-10 10,5 5,-1 5,5 5,20 10)",
619 test_one_lp<LineString, Polygon, LineString>("case26",
620 "POLYGON((0 0,0 10,10 10,10 0,0 0))",
621 "LINESTRING(-5 5,0 5,-5 5)",
624 test_one_lp<LineString, Polygon, LineString>("case26a",
625 "POLYGON((0 0,0 10,10 10,10 0,0 0))",
626 "LINESTRING(-10 10,-5 5,0 5,-5 5,-10 -10)",
629 test_one_lp<LineString, Polygon, LineString>("case27",
630 "POLYGON((0 0,0 10,10 10,10 0,0 0))",
631 "LINESTRING(5 5,0 5,5 5,5 4,0 4,5 4)",
634 test_one_lp<LineString, Polygon, LineString>("case28",
635 "POLYGON((0 0,0 10,10 10,10 0,0 0))",
636 "LINESTRING(5 5,0 5,5 5,5 4,0 4,5 3)",
639 test_one_lp<LineString, Polygon, LineString>("case29",
640 "POLYGON((5 5,15 15,15 5,5 5))",
641 "LINESTRING(0 0,10 10)",
642 1, 2, 5 * std::sqrt(2.0));
644 // PROPERTIES CHANGED BY switch_to_integer
645 // TODO test_one_lp<LineString, Polygon, LineString>("case21", poly_9, "LINESTRING(1 2,1 4,4 4,4 1,2 1,2 2)", 1, 6, 11.0);
647 // Compile test - arguments in any order:
648 test_one<LineString, Polygon, LineString>("simplex", poly_simplex, "LINESTRING(0 2,4 2)", 1, 2, 2.0);
649 test_one<LineString, LineString, Polygon>("simplex", "LINESTRING(0 2,4 2)", poly_simplex, 1, 2, 2.0);
651 typedef typename bg::point_type<Polygon>::type Point;
652 test_one<LineString, bg::model::ring<Point>, LineString>("simplex", poly_simplex, "LINESTRING(0 2,4 2)", 1, 2, 2.0);
654 test_one_lp<LineString, Polygon, LineString>("case30",
655 "POLYGON((25 0,0 15,30 15,22 10,25 0))",
656 "LINESTRING(10 15,20 15)",
659 test_one_lp<LineString, Polygon, LineString>("case31",
660 "POLYGON((25 0,0 15,30 15,22 10,25 0))",
661 "LINESTRING(0 15,20 15)",
664 test_one_lp<LineString, Polygon, LineString>("case32",
665 "POLYGON((25 0,0 15,30 15,22 10,25 0))",
666 "LINESTRING(25 0, 0 15,20 15)",
667 1, 3, 49.15475947422650 /*sqrt(25^2+15^2)+20*/);
669 typedef typename bg::point_type<Polygon>::type P;
671 test_one_lp<P, Polygon, LineString>("case30p",
672 "POLYGON((25 0,0 15,30 15,22 10,25 0))",
673 "LINESTRING(10 15,20 15)",
678 template <typename Linestring, typename Box>
679 void test_linear_box()
681 typedef bg::model::multi_linestring<Linestring> multi_linestring_type;
683 test_one_lp<Linestring, Box, Linestring>
685 "BOX(-10 -10,10 10)",
686 "LINESTRING(-20 -20, 0 0,20 20)",
687 1, 3, 20 * sqrt(2.0));
689 test_one_lp<Linestring, Box, Linestring>
691 "BOX(-10 -10,10 10)",
692 "LINESTRING(-20 -20, 20 20)",
693 1, 2, 20.0 * sqrt(2.0));
695 test_one_lp<Linestring, Box, Linestring>
697 "BOX(-10 -10,10 10)",
698 "LINESTRING(-20 -20, 20 20,15 0,0 -15)",
699 2, 4, 25.0 * sqrt(2.0));
701 test_one_lp<Linestring, Box, multi_linestring_type>
703 "BOX(-10 -10,10 10)",
704 "MULTILINESTRING((-20 -20, 20 20),(0 -15,15 0))",
705 2, 4, 25.0 * sqrt(2.0));
709 template <typename P>
712 typedef bg::model::linestring<P> linestring;
713 typedef bg::model::polygon<P> polygon;
714 typedef bg::model::box<P> box;
715 typedef bg::model::segment<P> segment;
717 typedef bg::model::polygon<P, false> polygon_ccw;
718 typedef bg::model::polygon<P, true, false> polygon_open;
719 typedef bg::model::polygon<P, false, false> polygon_ccw_open;
720 boost::ignore_unused<polygon_ccw, polygon_open, polygon_ccw_open>();
722 ut_settings ignore_validity;
723 ignore_validity.test_validity = false;
725 std::string clip = "box(2 2,8 8)";
727 test_areal_linear<polygon, linestring>();
728 #if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE)
729 test_areal_linear<polygon_open, linestring>();
730 test_areal_linear<polygon_ccw, linestring>();
731 test_areal_linear<polygon_ccw_open, linestring>();
734 test_linear_box<linestring, box>();
736 // Test polygons clockwise and counter clockwise
737 test_areal<polygon>();
739 #if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE)
740 test_areal<polygon_ccw>();
741 test_areal<polygon_open>();
742 test_areal<polygon_ccw_open>();
745 test_areal_clip<polygon, box>();
746 #if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE)
747 test_areal_clip<polygon_ccw, box>();
750 #if defined(TEST_FAIL_DIFFERENT_ORIENTATIONS)
751 // Should NOT compile
752 // NOTE: this can probably be relaxed later on.
753 test_one<polygon, polygon_ccw, polygon>("simplex_normal",
754 simplex_normal[0], simplex_normal[1],
756 // Output ccw, nyi (should be just reversing afterwards)
757 test_one<polygon, polygon, polygon_ccw>("simplex_normal",
758 simplex_normal[0], simplex_normal[1],
762 // Basic check: box/linestring, is clipping OK? should compile in any order
763 test_one<linestring, linestring, box>("llb", "LINESTRING(0 0,10 10)", clip, 1, 2, sqrt(2.0 * 6.0 * 6.0));
764 test_one<linestring, box, linestring>("lbl", clip, "LINESTRING(0 0,10 10)", 1, 2, sqrt(2.0 * 6.0 * 6.0));
767 test_one<linestring, segment, box>("lsb", "LINESTRING(0 0,10 10)", clip, 1, 2, sqrt(2.0 * 6.0 * 6.0));
768 test_one<linestring, box, segment>("lbs", clip, "LINESTRING(0 0,10 10)", 1, 2, sqrt(2.0 * 6.0 * 6.0));
771 test_one<linestring, linestring, box>("llbi", "LINESTRING(3 3,7 7)", clip, 1, 2, sqrt(2.0 * 4.0 * 4.0));
773 // Completely outside
774 test_one<linestring, linestring, box>("llbo", "LINESTRING(9 9,10 10)", clip, 0, 0, 0.0);
776 // Touching with point (-> output linestring with ONE point)
777 test_one<linestring, linestring, box>("llb_touch", "LINESTRING(8 8,10 10)", clip, 1, 1, 0.0, ignore_validity);
780 test_one<linestring, linestring, box>("llb_along", "LINESTRING(2 2,2 8)", clip, 1, 2, 6.0);
782 // Outputting two lines (because of 3-4-5 constructions (0.3,0.4,0.5)
783 // which occur 4 times, the length is expected to be 2.0)
784 test_one<linestring, linestring, box>("llb_2", "LINESTRING(1.7 1.6,2.3 2.4,2.9 1.6,3.5 2.4,4.1 1.6)", clip, 2, 6, 4.0 * 0.5);
787 test_one<P, linestring, linestring>("llp1", "LINESTRING(0 0,1 1)", "LINESTRING(0 1,1 0)", 1, 1, 0.0);
788 test_one<P, segment, segment>("ssp1", "LINESTRING(0 0,1 1)", "LINESTRING(0 1,1 0)", 1, 1, 0.0);
789 test_one<P, linestring, linestring>("llp2", "LINESTRING(0 0,1 1)", "LINESTRING(0 0,2 2)", 2, 2, 0.0);
791 // polygons outputing points
792 //test_one<P, polygon, polygon>("ppp1", simplex_normal[0], simplex_normal[1], 1, 7, 5.47363293);
794 test_boxes<box>("box(2 2,8 8)", "box(4 4,10 10)", 16, true);
795 test_boxes<box>("box(2 2,8 7)", "box(4 4,10 10)", 12, true);
796 test_boxes<box>("box(2 2,8 7)", "box(14 4,20 10)", 0, false);
797 test_boxes<box>("box(2 2,4 4)", "box(4 4,8 8)", 0, true);
799 test_point_output<P>();
803 test_one<polygon, box, polygon>(99, "box(115041.10 471900.10, 118334.60 474523.40)",
804 "POLYGON ((115483.40 474533.40, 116549.40 474059.20, 117199.90 473762.50, 117204.90 473659.50, 118339.40 472796.90, 118334.50 472757.90, 118315.10 472604.00, 118344.60 472520.90, 118277.90 472419.10, 118071.40 472536.80, 118071.40 472536.80, 117943.10 472287.70, 117744.90 472248.40, 117708.00 472034.50, 117481.90 472056.90, 117481.90 472056.90, 117272.30 471890.10, 117077.90 472161.20, 116146.60 473054.50, 115031.10 473603.30, 115483.40 474533.40))",
810 void test_pointer_version()
812 std::vector<test::test_point_xy*> ln;
813 test::test_point_xy* p;
814 p = new test::test_point_xy; p->x = 0; p->y = 0; ln.push_back(p);
815 p = new test::test_point_xy; p->x = 10; p->y = 10; ln.push_back(p);
817 bg::model::box<bg::model::d2::point_xy<double> > box;
818 bg::assign_values(box, 2, 2, 8, 8);
820 typedef bg::model::linestring<bg::model::d2::point_xy<double> > output_type;
821 std::vector<output_type> clip;
822 bg::detail::intersection::intersection_insert<output_type>(box, ln, std::back_inserter(clip));
826 for (std::vector<output_type>::const_iterator it = clip.begin();
827 it != clip.end(); ++it)
829 length += bg::length(*it);
830 n += bg::num_points(*it);
833 BOOST_CHECK_EQUAL(clip.size(), 1u);
834 BOOST_CHECK_EQUAL(n, 2u);
835 BOOST_CHECK_CLOSE(length, sqrt(2.0 * 6.0 * 6.0), 0.001);
837 for (std::size_t i = 0; i < ln.size(); i++)
844 template <typename P>
845 void test_exception()
847 typedef bg::model::polygon<P> polygon;
851 // Define polygon with a spike (= invalid)
852 std::string spike = "POLYGON((0 0,0 4,2 4,2 6,2 4,4 4,4 0,0 0))";
854 test_one<polygon, polygon, polygon>("with_spike",
855 simplex_normal[0], spike,
858 catch(bg::overlay_invalid_input_exception const& )
862 BOOST_CHECK_MESSAGE(false, "No exception thrown");
865 template <typename Point>
868 typedef bg::model::polygon<Point> polygon;
869 test_one<polygon, polygon, polygon>("simplex_normal",
870 simplex_normal[0], simplex_normal[1],
875 template <typename P>
876 void test_boxes_per_d(P const& min1, P const& max1, P const& min2, P const& max2, bool expected_result)
878 typedef bg::model::box<P> box;
881 bool detected = bg::intersection(box(min1, max1), box(min2, max2), box_out);
883 BOOST_CHECK_EQUAL(detected, expected_result);
884 if ( detected && expected_result )
886 BOOST_CHECK( bg::equals(box_out, box(min2,max1)) );
890 template <typename CoordinateType>
893 typedef bg::model::point<CoordinateType, 1, bg::cs::cartesian> p1;
894 typedef bg::model::point<CoordinateType, 2, bg::cs::cartesian> p2;
895 typedef bg::model::point<CoordinateType, 3, bg::cs::cartesian> p3;
897 test_boxes_per_d(p1(0), p1(5), p1(3), p1(6), true);
898 test_boxes_per_d(p2(0,0), p2(5,5), p2(3,3), p2(6,6), true);
899 test_boxes_per_d(p3(0,0,0), p3(5,5,5), p3(3,3,3), p3(6,6,6), true);
903 template <typename CoordinateType>
904 void test_ticket_10868(std::string const& wkt_out)
906 typedef bg::model::point<CoordinateType, 2, bg::cs::cartesian> point_type;
907 typedef bg::model::polygon
909 point_type, /*ClockWise*/false, /*Closed*/false
911 typedef bg::model::multi_polygon<polygon_type> multipolygon_type;
913 polygon_type polygon1;
914 bg::read_wkt(ticket_10868[0], polygon1);
915 polygon_type polygon2;
916 bg::read_wkt(ticket_10868[1], polygon2);
918 multipolygon_type multipolygon_out;
919 bg::intersection(polygon1, polygon2, multipolygon_out);
920 std::stringstream stream;
921 stream << bg::wkt(multipolygon_out);
923 BOOST_CHECK_EQUAL(stream.str(), wkt_out);
925 test_one<polygon_type, polygon_type, polygon_type>("ticket_10868",
926 ticket_10868[0], ticket_10868[1],
927 1, 7, 20266195244586.0);
930 int test_main(int, char* [])
932 BoostGeometryWriteTestConfiguration();
933 test_all<bg::model::d2::point_xy<default_test_type> >();
935 #if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE)
936 test_all<bg::model::d2::point_xy<float> >();
938 #if defined(HAVE_TTMATH)
939 std::cout << "Testing TTMATH" << std::endl;
940 test_all<bg::model::d2::point_xy<ttmath_big> >();
944 // Commented, because exception is now disabled:
945 // test_exception<bg::model::d2::point_xy<double> >();
947 test_pointer_version();
948 #if ! defined(BOOST_GEOMETRY_RESCALE_TO_ROBUST)
949 test_rational<bg::model::d2::point_xy<boost::rational<int> > >();
952 test_boxes_nd<double>();
954 #if defined(BOOST_GEOMETRY_TEST_FAILURES)
955 // ticket #10868 still fails for 32-bit integers
956 test_ticket_10868<int32_t>("MULTIPOLYGON(((33520458 6878575,33480192 14931538,31446819 18947953,30772384 19615678,30101303 19612322,30114725 16928001,33520458 6878575)))");
958 #if !defined(BOOST_NO_INT64) || defined(BOOST_HAS_INT64_T) || defined(BOOST_HAS_MS_INT64)
959 test_ticket_10868<int64_t>("MULTIPOLYGON(((33520458 6878575,33480192 14931538,31446819 18947953,30772384 19615678,30101303 19612322,30114725 16928001,33520458 6878575)))");
962 if (BOOST_GEOMETRY_CONDITION(sizeof(long) * CHAR_BIT >= 64))
964 test_ticket_10868<long>("MULTIPOLYGON(((33520458 6878575,33480192 14931538,31446819 18947953,30772384 19615678,30101303 19612322,30114725 16928001,33520458 6878575)))");
967 #if defined(BOOST_HAS_LONG_LONG)
968 test_ticket_10868<boost::long_long_type>("MULTIPOLYGON(((33520458 6878575,33480192 14931538,31446819 18947953,30772384 19615678,30101303 19612322,30114725 16928001,33520458 6878575)))");