4 // Copyright (c) 2019 Barend Gehrels, Amsterdam, the Netherlands.
6 // Use, modification and distribution is subject to the Boost Software License,
7 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
8 // http://www.boost.org/LICENSE_1_0.txt)
16 #include <boost/type_traits/is_same.hpp>
18 #include <geometry_test_common.hpp>
20 #include <boost/geometry.hpp>
21 #include <boost/geometry/geometries/geometries.hpp>
23 // Basic case. Union should deliver 22.0
24 static std::string case_a
[2] =
26 "MULTIPOLYGON(((0 0,0 4,2 4,2 3,4 3,4 0,0 0)))",
27 "MULTIPOLYGON(((2 7,4 7,4 3,2 3,2 7)))"
30 // Case with an interior ring. Union should deliver 73.0
31 static std::string case_b
[2] =
33 "MULTIPOLYGON(((0 0,0 4,2 4,2 3,4 3,4 0,0 0)))",
34 "MULTIPOLYGON(((-1 -1,-1 8,8 8,8 -1,-1 -1),(2 7,2 3,4 3,4 7,2 7)))"
37 static std::string case_c
[2] =
39 "MULTIPOLYGON(((0 0,0 4,2 4,2 3,4 3,4 0,0 0)))",
40 "MULTIPOLYGON(((1 1,0 1,0 3,1 3,1 1)))"
43 template <bg::overlay_type OverlayType
, typename Geometry
>
44 bool test_overlay(std::string
const& caseid
,
45 Geometry
const& g1
, Geometry
const& g2
,
50 typedef typename
boost::range_value
<Geometry
>::type geometry_out
;
51 typedef bg::detail::overlay::overlay
54 bg::detail::overlay::do_reverse
<bg::point_order
<Geometry
>::value
>::value
,
55 OverlayType
== bg::overlay_difference
56 ? ! bg::detail::overlay::do_reverse
<bg::point_order
<Geometry
>::value
>::value
57 : bg::detail::overlay::do_reverse
<bg::point_order
<Geometry
>::value
>::value
,
58 bg::detail::overlay::do_reverse
<bg::point_order
<Geometry
>::value
>::value
,
63 typedef typename
bg::strategy::intersection::services::default_strategy
65 typename
bg::cs_tag
<Geometry
>::type
66 >::type strategy_type
;
68 strategy_type strategy
;
70 typedef typename
bg::rescale_overlay_policy_type
74 >::type rescale_policy_type
;
76 rescale_policy_type robust_policy
77 = bg::get_rescale_policy
<rescale_policy_type
>(g1
, g2
);
80 bg::detail::overlay::overlay_null_visitor visitor
;
81 overlay::apply(g1
, g2
, robust_policy
, std::back_inserter(result
),
84 const double detected_area
= bg::area(result
);
85 if (std::fabs(detected_area
- expected_area
) > 0.01)
89 std::cout
<< "ERROR: " << caseid
<< std::setprecision(18)
90 << " detected=" << detected_area
91 << " expected=" << expected_area
<< std::endl
92 << " " << bg::wkt(g1
) << std::endl
93 << " " << bg::wkt(g2
) << std::endl
;
100 template <typename Ring
>
101 void update(Ring
& ring
, double x
, double y
, std::size_t index
)
103 if (index
>= ring
.size())
107 bg::set
<0>(ring
[index
], bg::get
<0>(ring
[index
]) + x
);
108 bg::set
<1>(ring
[index
], bg::get
<1>(ring
[index
]) + y
);
111 ring
.back() = ring
.front();
115 template <bg::overlay_type OverlayType
, typename MultiPolygon
>
116 std::size_t test_case(std::size_t& error_count
,
117 std::size_t case_index
, std::size_t i
, std::size_t j
,
118 std::size_t min_vertex_index
, std::size_t max_vertex_index
,
119 double x
, double y
, double expectation
,
120 MultiPolygon
const& poly1
, MultiPolygon
const& poly2
,
124 for (std::size_t k
= min_vertex_index
; k
<= max_vertex_index
; k
++, ++n
)
126 MultiPolygon poly2_adapted
= poly2
;
131 update(bg::interior_rings(poly2_adapted
.front()).front(), x
, y
, k
);
134 update(bg::exterior_ring(poly2_adapted
.front()), x
, y
, k
);
138 std::ostringstream out
;
139 out
<< "case_" << i
<< "_" << j
<< "_" << k
;
140 if (! test_overlay
<OverlayType
>(out
.str(), poly1
, poly2_adapted
, expectation
, do_output
))
142 if (error_count
== 0)
144 // First failure is always reported
145 test_overlay
<OverlayType
>(out
.str(), poly1
, poly2_adapted
, expectation
, true);
153 template <typename T
, bool Clockwise
, bg::overlay_type OverlayType
>
154 std::size_t test_all(std::size_t case_index
, std::size_t min_vertex_index
,
155 std::size_t max_vertex_index
,
156 double expectation
, bool do_output
)
158 typedef bg::model::point
<T
, 2, bg::cs::cartesian
> point_type
;
159 typedef bg::model::polygon
<point_type
, Clockwise
> polygon
;
160 typedef bg::model::multi_polygon
<polygon
> multi_polygon
;
162 const std::string
& first
= case_a
[0];
164 const std::string
& second
165 = case_index
== 1 ? case_a
[1]
166 : case_index
== 2 ? case_b
[1]
167 : case_index
== 3 ? case_c
[1]
171 bg::read_wkt(first
, poly1
);
174 bg::read_wkt(second
, poly2
);
176 std::size_t error_count
= 0;
178 for (double factor
= 1.0; factor
> 1.0e-10; factor
/= 10.0)
181 double const bound
= 1.0e-5 * factor
;
182 double const step
= 1.0e-6 * factor
;
183 for (double x
= -bound
; x
<= bound
; x
+= step
, ++i
)
186 for (double y
= -bound
; y
<= bound
; y
+= step
, ++j
, ++n
)
188 n
+= test_case
<OverlayType
>(error_count
,
190 min_vertex_index
, max_vertex_index
,
192 poly1
, poly2
, do_output
);
197 std::cout
<< case_index
198 << " #cases: " << n
<< " #errors: " << error_count
<< std::endl
;
199 BOOST_CHECK_EQUAL(error_count
, 0u);
204 int test_main(int argc
, char** argv
)
206 typedef double coordinate_type
;
208 const double factor
= argc
> 1 ? atof(argv
[1]) : 2.0;
209 const bool do_output
= argc
> 2 && atol(argv
[2]) == 1;
211 std::cout
<< std::endl
<< " -> TESTING "
212 << string_from_type
<coordinate_type
>::name()
216 test_all
<coordinate_type
, true, bg::overlay_union
>(1, 0, 3, 22.0, do_output
);
217 test_all
<coordinate_type
, true, bg::overlay_union
>(2, 0, 3, 73.0, do_output
);
218 test_all
<coordinate_type
, true, bg::overlay_intersection
>(3, 1, 2, 2.0, do_output
);
219 test_all
<coordinate_type
, true, bg::overlay_union
>(3, 1, 2, 14.0, do_output
);