]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/geometry/test/algorithms/set_operations/union/test_union.hpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / libs / geometry / test / algorithms / set_operations / union / test_union.hpp
1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2 // Unit Test
3
4 // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
5
6 // This file was modified by Oracle on 2015, 2016, 2017.
7 // Modifications copyright (c) 2015-2017 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
10
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)
14
15 #ifndef BOOST_GEOMETRY_TEST_UNION_HPP
16 #define BOOST_GEOMETRY_TEST_UNION_HPP
17
18 #include <fstream>
19
20 #include <geometry_test_common.hpp>
21 #include "../setop_output_type.hpp"
22 #include "../check_validity.hpp"
23
24 #include <boost/core/ignore_unused.hpp>
25 #include <boost/foreach.hpp>
26 #include <boost/range/algorithm/copy.hpp>
27
28 #include <boost/geometry/algorithms/union.hpp>
29
30 #include <boost/geometry/algorithms/area.hpp>
31 #include <boost/geometry/algorithms/correct.hpp>
32 #include <boost/geometry/algorithms/is_empty.hpp>
33 #include <boost/geometry/algorithms/length.hpp>
34 #include <boost/geometry/algorithms/num_points.hpp>
35 #include <boost/geometry/algorithms/is_valid.hpp>
36
37 #include <boost/geometry/geometries/geometries.hpp>
38
39 #include <boost/geometry/strategies/strategies.hpp>
40
41 #include <boost/geometry/io/wkt/wkt.hpp>
42
43
44 #if defined(TEST_WITH_SVG)
45 # include <boost/geometry/io/svg/svg_mapper.hpp>
46 #endif
47
48 struct ut_settings
49 {
50 double percentage;
51 bool test_validity;
52
53 ut_settings()
54 : percentage(0.001)
55 , test_validity(true)
56 {}
57
58 };
59
60 #if defined(BOOST_GEOMETRY_TEST_CHECK_VALID_INPUT)
61 template <typename Geometry>
62 inline void check_input_validity(std::string const& caseid, int case_index,
63 Geometry const& geometry)
64 {
65 std::string message;
66 if (!bg::is_valid(geometry, message))
67 {
68 std::cout << caseid << " Input ["
69 << case_index << "] not valid" << std::endl
70 << " (" << message << ")" << std::endl;
71 }
72 }
73 #endif
74
75
76
77 template <typename Range>
78 inline std::size_t num_points(Range const& rng, bool add_for_open = false)
79 {
80 std::size_t result = 0;
81 for (typename boost::range_iterator<Range const>::type it = boost::begin(rng);
82 it != boost::end(rng); ++it)
83 {
84 result += bg::num_points(*it, add_for_open);
85 }
86 return result;
87 }
88
89 template <typename OutputType, typename G1, typename G2>
90 void test_union(std::string const& caseid, G1 const& g1, G2 const& g2,
91 int expected_count, int expected_hole_count,
92 int expected_point_count, double expected_area,
93 ut_settings const& settings)
94 {
95 typedef typename bg::coordinate_type<G1>::type coordinate_type;
96 boost::ignore_unused<coordinate_type>();
97 boost::ignore_unused(expected_point_count);
98
99 // Declare output (vector of rings or multi_polygon)
100 typedef typename setop_output_type<OutputType>::type result_type;
101 result_type clip;
102
103 #if defined(BOOST_GEOMETRY_DEBUG_ROBUSTNESS)
104 std::cout << "*** UNION " << caseid << std::endl;
105 #endif
106
107 #if defined(BOOST_GEOMETRY_TEST_CHECK_VALID_INPUT)
108 check_input_validity(caseid, 0, g1);
109 check_input_validity(caseid, 1, g2);
110 #endif
111
112 // Check normal behaviour
113 bg::union_(g1, g2, clip);
114
115 #if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE)
116 {
117 // Check strategy passed explicitly
118 result_type clip_s;
119 typedef typename bg::strategy::intersection::services::default_strategy
120 <
121 typename bg::cs_tag<OutputType>::type
122 >::type strategy_type;
123 bg::union_(g1, g2, clip_s, strategy_type());
124 BOOST_CHECK_EQUAL(num_points(clip), num_points(clip_s));
125 }
126 #endif
127
128 if (settings.test_validity)
129 {
130 std::string message;
131 bool const valid = check_validity<result_type>::apply(clip, message);
132 BOOST_CHECK_MESSAGE(valid,
133 "union: " << caseid << " not valid: " << message
134 << " type: " << (type_for_assert_message<G1, G2>()));
135 }
136
137
138 typename bg::default_area_result<OutputType>::type area = 0;
139 std::size_t n = 0;
140 std::size_t holes = 0;
141 for (typename result_type::iterator it = clip.begin();
142 it != clip.end(); ++it)
143 {
144 area += bg::area(*it);
145 holes += bg::num_interior_rings(*it);
146 n += bg::num_points(*it, true);
147 }
148
149
150 #if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE)
151 {
152 // Test inserter functionality
153 // Test if inserter returns output-iterator (using Boost.Range copy)
154 result_type inserted, array_with_one_empty_geometry;
155 array_with_one_empty_geometry.push_back(OutputType());
156 boost::copy(array_with_one_empty_geometry, bg::detail::union_::union_insert<OutputType>(g1, g2, std::back_inserter(inserted)));
157
158 typename bg::default_area_result<OutputType>::type area_inserted = 0;
159 int index = 0;
160 for (typename result_type::iterator it = inserted.begin();
161 it != inserted.end();
162 ++it, ++index)
163 {
164 // Skip the empty polygon created above to avoid the empty_input_exception
165 if (! bg::is_empty(*it))
166 {
167 area_inserted += bg::area(*it);
168 }
169 }
170 BOOST_CHECK_EQUAL(boost::size(clip), boost::size(inserted) - 1);
171 BOOST_CHECK_CLOSE(area_inserted, expected_area, settings.percentage);
172 }
173 #endif
174
175
176
177 #if defined(BOOST_GEOMETRY_DEBUG_ROBUSTNESS)
178 std::cout << "*** case: " << caseid
179 << " area: " << area
180 << " points: " << n
181 << " polygons: " << boost::size(clip)
182 << " holes: " << holes
183 << std::endl;
184 #endif
185
186 BOOST_CHECK_MESSAGE(expected_count < 0 || int(clip.size()) == expected_count,
187 "union: " << caseid
188 << " #clips expected: " << expected_count
189 << " detected: " << clip.size()
190 << " type: " << (type_for_assert_message<G1, G2>())
191 );
192
193 BOOST_CHECK_MESSAGE(expected_hole_count < 0 || int(holes) == expected_hole_count,
194 "union: " << caseid
195 << " #holes expected: " << expected_hole_count
196 << " detected: " << holes
197 << " type: " << (type_for_assert_message<G1, G2>())
198 );
199
200 #if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS)
201 BOOST_CHECK_MESSAGE(expected_point_count < 0 || std::abs(int(n) - expected_point_count) < 3,
202 "union: " << caseid
203 << " #points expected: " << expected_point_count
204 << " detected: " << n
205 << " type: " << (type_for_assert_message<G1, G2>())
206 );
207 #endif
208
209 BOOST_CHECK_CLOSE(area, expected_area, settings.percentage);
210
211 #if defined(TEST_WITH_SVG)
212 {
213 bool const ccw =
214 bg::point_order<G1>::value == bg::counterclockwise
215 || bg::point_order<G2>::value == bg::counterclockwise;
216 bool const open =
217 bg::closure<G1>::value == bg::open
218 || bg::closure<G2>::value == bg::open;
219
220 std::ostringstream filename;
221 filename << "union_"
222 << caseid << "_"
223 << string_from_type<coordinate_type>::name()
224 << (ccw ? "_ccw" : "")
225 << (open ? "_open" : "")
226 #if defined(BOOST_GEOMETRY_INCLUDE_SELF_TURNS)
227 << "_self"
228 #endif
229 #if defined(BOOST_GEOMETRY_NO_ROBUSTNESS)
230 << "_no_rob"
231 #endif
232 << ".svg";
233
234 std::ofstream svg(filename.str().c_str());
235
236 bg::svg_mapper
237 <
238 typename bg::point_type<G2>::type
239 > mapper(svg, 500, 500);
240 mapper.add(g1);
241 mapper.add(g2);
242
243 mapper.map(g1, "fill-opacity:0.5;fill:rgb(153,204,0);"
244 "stroke:rgb(153,204,0);stroke-width:3");
245 mapper.map(g2, "fill-opacity:0.3;fill:rgb(51,51,153);"
246 "stroke:rgb(51,51,153);stroke-width:3");
247 //mapper.map(g1, "opacity:0.6;fill:rgb(0,0,255);stroke:rgb(0,0,0);stroke-width:1");
248 //mapper.map(g2, "opacity:0.6;fill:rgb(0,255,0);stroke:rgb(0,0,0);stroke-width:1");
249
250 for (typename result_type::const_iterator it = clip.begin();
251 it != clip.end(); ++it)
252 {
253 mapper.map(*it, "fill-opacity:0.2;stroke-opacity:0.4;fill:rgb(255,0,0);"
254 "stroke:rgb(255,0,255);stroke-width:8");
255 //mapper.map(*it, "opacity:0.6;fill:none;stroke:rgb(255,0,0);stroke-width:5");
256 }
257 }
258 #endif
259 }
260
261 template <typename OutputType, typename G1, typename G2>
262 void test_one(std::string const& caseid,
263 std::string const& wkt1, std::string const& wkt2,
264 int expected_count, int expected_hole_count,
265 int expected_point_count, double expected_area,
266 ut_settings const& settings = ut_settings())
267 {
268 G1 g1;
269 bg::read_wkt(wkt1, g1);
270
271 G2 g2;
272 bg::read_wkt(wkt2, g2);
273
274 // Reverse/close if necessary (e.g. G1/G2 are ccw and/or open)
275 bg::correct(g1);
276 bg::correct(g2);
277
278 test_union<OutputType>(caseid, g1, g2,
279 expected_count, expected_hole_count, expected_point_count,
280 expected_area, settings);
281 }
282
283 #endif