]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/geometry/test/algorithms/buffer/test_buffer.hpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / libs / geometry / test / algorithms / buffer / test_buffer.hpp
1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2 // Unit Test Helper
3
4 // Copyright (c) 2010-2015 Barend Gehrels, Amsterdam, the Netherlands.
5
6 // This file was modified by Oracle on 2016-2017.
7 // Modifications copyright (c) 2016-2017, Oracle and/or its affiliates.
8 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
9
10 // Use, modification and distribution is subject to the Boost Software License,
11 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
12 // http://www.boost.org/LICENSE_1_0.txt)
13
14
15 #ifndef BOOST_GEOMETRY_TEST_BUFFER_HPP
16 #define BOOST_GEOMETRY_TEST_BUFFER_HPP
17
18 #if defined(TEST_WITH_SVG)
19 // Define before including any buffer headerfile
20 #define BOOST_GEOMETRY_BUFFER_USE_HELPER_POINTS
21 #endif
22
23 #include <iostream>
24 #include <fstream>
25 #include <iomanip>
26
27 #include <boost/foreach.hpp>
28 #include <geometry_test_common.hpp>
29
30 #include <boost/geometry/algorithms/envelope.hpp>
31 #include <boost/geometry/algorithms/area.hpp>
32 #include <boost/geometry/algorithms/buffer.hpp>
33 #include <boost/geometry/algorithms/correct.hpp>
34 #include <boost/geometry/algorithms/disjoint.hpp>
35 #include <boost/geometry/algorithms/intersects.hpp>
36 #include <boost/geometry/algorithms/is_empty.hpp>
37 #include <boost/geometry/algorithms/is_valid.hpp>
38 #include <boost/geometry/algorithms/num_interior_rings.hpp>
39 #include <boost/geometry/algorithms/union.hpp>
40
41 #include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp>
42 #include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp>
43
44 #include <boost/geometry/geometries/geometries.hpp>
45
46 #include <boost/geometry/strategies/strategies.hpp>
47
48 #include <boost/geometry/strategies/buffer.hpp>
49
50 #include <boost/geometry/io/wkt/wkt.hpp>
51
52 #include <boost/geometry/util/condition.hpp>
53
54 const double same_distance = -999;
55
56 #if defined(TEST_WITH_SVG)
57 # include <test_buffer_svg.hpp>
58 # include <test_buffer_svg_per_turn.hpp>
59 #endif
60
61 //-----------------------------------------------------------------------------
62 template <typename JoinStrategy>
63 struct JoinTestProperties
64 {
65 static std::string name() { return "joinunknown"; }
66 };
67
68 template<> struct JoinTestProperties<boost::geometry::strategy::buffer::join_round>
69 {
70 static std::string name() { return "round"; }
71 };
72
73 template<> struct JoinTestProperties<boost::geometry::strategy::buffer::join_miter>
74 {
75 static std::string name() { return "miter"; }
76 };
77
78 template<> struct JoinTestProperties<boost::geometry::strategy::buffer::join_round_by_divide>
79 {
80 static std::string name() { return "divide"; }
81 };
82
83
84 //-----------------------------------------------------------------------------
85 template <typename EndStrategy>
86 struct EndTestProperties { };
87
88 template<> struct EndTestProperties<boost::geometry::strategy::buffer::end_round>
89 {
90 static std::string name() { return "round"; }
91 };
92
93 template<> struct EndTestProperties<boost::geometry::strategy::buffer::end_flat>
94 {
95 static std::string name() { return "flat"; }
96 };
97
98 struct ut_settings
99 {
100 double tolerance;
101 bool test_validity;
102 bool test_area;
103
104 explicit ut_settings(double tol = 0.01, bool val = true)
105 : tolerance(tol)
106 , test_validity(val)
107 , test_area(true)
108 {}
109
110 static inline ut_settings ignore_validity()
111 {
112 ut_settings result;
113 result.test_validity = false;
114 return result;
115 }
116
117 static inline ut_settings assertions_only()
118 {
119 ut_settings result;
120 result.test_validity = false;
121 result.test_area = false;
122 return result;
123 }
124
125 static inline double ignore_area() { return 9999.9; }
126 };
127
128 template
129 <
130 typename GeometryOut,
131 typename JoinStrategy,
132 typename EndStrategy,
133 typename DistanceStrategy,
134 typename SideStrategy,
135 typename PointStrategy,
136 typename Geometry
137 >
138 void test_buffer(std::string const& caseid, Geometry const& geometry,
139 JoinStrategy const& join_strategy,
140 EndStrategy const& end_strategy,
141 DistanceStrategy const& distance_strategy,
142 SideStrategy const& side_strategy,
143 PointStrategy const& point_strategy,
144 int expected_count,
145 int expected_holes_count,
146 double expected_area,
147 ut_settings const& settings)
148 {
149 namespace bg = boost::geometry;
150
151 typedef typename bg::coordinate_type<Geometry>::type coordinate_type;
152 typedef typename bg::point_type<Geometry>::type point_type;
153
154 typedef typename bg::tag<Geometry>::type tag;
155 // TODO use something different here:
156 std::string type = boost::is_same<tag, bg::polygon_tag>::value ? "poly"
157 : boost::is_same<tag, bg::linestring_tag>::value ? "line"
158 : boost::is_same<tag, bg::point_tag>::value ? "point"
159 : boost::is_same<tag, bg::multi_polygon_tag>::value ? "multipoly"
160 : boost::is_same<tag, bg::multi_linestring_tag>::value ? "multiline"
161 : boost::is_same<tag, bg::multi_point_tag>::value ? "multipoint"
162 : ""
163 ;
164
165 bg::model::box<point_type> envelope;
166 if (bg::is_empty(geometry))
167 {
168 bg::assign_values(envelope, 0, 0, 1, 1);
169 }
170 else
171 {
172 bg::envelope(geometry, envelope);
173 }
174
175 std::string join_name = JoinTestProperties<JoinStrategy>::name();
176 std::string end_name = EndTestProperties<EndStrategy>::name();
177
178 if ( BOOST_GEOMETRY_CONDITION((
179 boost::is_same<tag, bg::point_tag>::value
180 || boost::is_same<tag, bg::multi_point_tag>::value )) )
181 {
182 join_name.clear();
183 }
184
185 std::ostringstream complete;
186 complete
187 << type << "_"
188 << caseid << "_"
189 << string_from_type<coordinate_type>::name()
190 << "_" << join_name
191 << (end_name.empty() ? "" : "_") << end_name
192 << (distance_strategy.negative() ? "_deflate" : "")
193 << (bg::point_order<GeometryOut>::value == bg::counterclockwise ? "_ccw" : "")
194 // << "_" << point_buffer_count
195 ;
196
197 //std::cout << complete.str() << std::endl;
198
199 #if defined(TEST_WITH_SVG_PER_TURN)
200 save_turns_visitor<point_type> visitor;
201 #elif defined(TEST_WITH_SVG)
202
203 buffer_svg_mapper<point_type> buffer_mapper(complete.str());
204
205 std::ostringstream filename;
206 filename << "buffer_" << complete.str() << ".svg";
207 std::ofstream svg(filename.str().c_str());
208 typedef bg::svg_mapper<point_type> mapper_type;
209 mapper_type mapper(svg, 1000, 800);
210
211 svg_visitor<mapper_type, bg::model::box<point_type> > visitor(mapper);
212
213 buffer_mapper.prepare(mapper, visitor, envelope,
214 distance_strategy.negative()
215 ? 1.0
216 : 1.1 * distance_strategy.max_distance(join_strategy, end_strategy)
217 );
218 #else
219 bg::detail::buffer::visit_pieces_default_policy visitor;
220 #endif
221
222 typedef typename bg::point_type<Geometry>::type point_type;
223 typedef typename bg::rescale_policy_type<point_type>::type
224 rescale_policy_type;
225 typedef typename bg::strategy::intersection::services::default_strategy
226 <
227 typename bg::cs_tag<Geometry>::type
228 >::type strategy_type;
229
230 // Enlarge the box to get a proper rescale policy
231 bg::buffer(envelope, envelope, distance_strategy.max_distance(join_strategy, end_strategy));
232
233 strategy_type strategy;
234 rescale_policy_type rescale_policy
235 = bg::get_rescale_policy<rescale_policy_type>(envelope);
236
237 bg::model::multi_polygon<GeometryOut> buffered;
238
239 bg::detail::buffer::buffer_inserter<GeometryOut>(geometry,
240 std::back_inserter(buffered),
241 distance_strategy,
242 side_strategy,
243 join_strategy,
244 end_strategy,
245 point_strategy,
246 strategy,
247 rescale_policy,
248 visitor);
249
250 #if defined(TEST_WITH_SVG)
251 buffer_mapper.map_input_output(mapper, geometry, buffered, distance_strategy.negative());
252 #endif
253
254 //Uncomment to create simple CSV to compare/use in tests - adapt precision if necessary
255 //std::cout << complete.str() << "," << std::fixed << std::setprecision(0) << area << std::endl;
256 //return;
257
258 if (bg::is_empty(buffered) && bg::math::equals(expected_area, 0.0))
259 {
260 // As expected - don't get rescale policy for output (will be invalid)
261 return;
262 }
263
264 if (settings.test_area)
265 {
266 BOOST_CHECK_MESSAGE
267 (
268 ! bg::is_empty(buffered),
269 complete.str() << " output is empty (unexpected)."
270 );
271 }
272
273 bg::model::box<point_type> envelope_output;
274 bg::assign_values(envelope_output, 0, 0, 1, 1);
275 bg::envelope(buffered, envelope_output);
276
277 // std::cout << caseid << std::endl;
278 // std::cout << "INPUT: " << bg::wkt(geometry) << std::endl;
279 // std::cout << "OUTPUT: " << area << std::endl;
280 // std::cout << "OUTPUT env: " << bg::wkt(envelope_output) << std::endl;
281 // std::cout << bg::wkt(buffered) << std::endl;
282
283 if (expected_count >= 0)
284 {
285 BOOST_CHECK_MESSAGE
286 (
287 int(buffered.size()) == expected_count,
288 "#outputs not as expected."
289 << " Expected: " << expected_count
290 << " Detected: " << buffered.size()
291 );
292 }
293
294 if (expected_holes_count >= 0)
295 {
296 std::size_t nholes = bg::num_interior_rings(buffered);
297 BOOST_CHECK_MESSAGE
298 (
299 int(nholes) == expected_holes_count,
300 complete.str() << " #holes not as expected."
301 << " Expected: " << expected_holes_count
302 << " Detected: " << nholes
303 );
304 }
305
306 if (settings.test_area)
307 {
308 typename bg::default_area_result<GeometryOut>::type area = bg::area(buffered);
309 double const difference = area - expected_area;
310 BOOST_CHECK_MESSAGE
311 (
312 bg::math::abs(difference) < settings.tolerance,
313 complete.str() << " not as expected. "
314 << std::setprecision(18)
315 << " Expected: " << expected_area
316 << " Detected: " << area
317 << " Diff: " << difference
318 << " Tol: " << settings.tolerance
319 << std::setprecision(3)
320 << " , " << 100.0 * (difference / expected_area) << "%"
321 );
322 }
323
324 if (settings.test_validity && ! bg::is_valid(buffered))
325 {
326 BOOST_CHECK_MESSAGE(bg::is_valid(buffered), complete.str() << " is not valid");
327 }
328
329 #if defined(TEST_WITH_SVG_PER_TURN)
330 {
331 // Create a per turn visitor to map per turn, and buffer again with it
332 per_turn_visitor<point_type> ptv(complete.str(), visitor.get_points());
333 bg::detail::buffer::buffer_inserter<GeometryOut>(geometry,
334 std::back_inserter(buffered),
335 distance_strategy,
336 side_strategy,
337 join_strategy,
338 end_strategy,
339 point_strategy,
340 rescale_policy,
341 ptv);
342 ptv.map_input_output(geometry, buffered, distance_strategy.negative());
343 // self_ips NYI here
344 }
345 #elif defined(TEST_WITH_SVG)
346 rescale_policy_type rescale_policy_output
347 = bg::get_rescale_policy<rescale_policy_type>(envelope_output);
348 buffer_mapper.map_self_ips(mapper, buffered, strategy, rescale_policy_output);
349 #endif
350
351 }
352
353 template
354 <
355 typename GeometryOut,
356 typename JoinStrategy,
357 typename EndStrategy,
358 typename DistanceStrategy,
359 typename SideStrategy,
360 typename PointStrategy,
361 typename Geometry
362 >
363 void test_buffer(std::string const& caseid, Geometry const& geometry,
364 JoinStrategy const& join_strategy,
365 EndStrategy const& end_strategy,
366 DistanceStrategy const& distance_strategy,
367 SideStrategy const& side_strategy,
368 PointStrategy const& point_strategy,
369 double expected_area,
370 ut_settings const& settings = ut_settings())
371 {
372 test_buffer<GeometryOut>(caseid, geometry,
373 join_strategy, end_strategy, distance_strategy, side_strategy, point_strategy,
374 -1, -1, expected_area, settings);
375 }
376
377 #ifdef BOOST_GEOMETRY_CHECK_WITH_POSTGIS
378 static int counter = 0;
379 #endif
380
381 template
382 <
383 typename Geometry,
384 typename GeometryOut,
385 typename JoinStrategy,
386 typename EndStrategy
387 >
388 void test_one(std::string const& caseid, std::string const& wkt,
389 JoinStrategy const& join_strategy, EndStrategy const& end_strategy,
390 int expected_count, int expected_holes_count, double expected_area,
391 double distance_left, ut_settings const& settings = ut_settings(),
392 double distance_right = same_distance)
393 {
394 namespace bg = boost::geometry;
395 Geometry g;
396 bg::read_wkt(wkt, g);
397 bg::correct(g);
398
399
400 #ifdef BOOST_GEOMETRY_CHECK_WITH_POSTGIS
401 std::cout
402 << (counter > 0 ? "union " : "")
403 << "select " << counter++
404 << ", '" << caseid << "' as caseid"
405 << ", ST_Area(ST_Buffer(ST_GeomFromText('" << wkt << "'), "
406 << distance_left
407 << ", 'endcap=" << end_name << " join=" << join_name << "'))"
408 << ", " << expected_area
409 << std::endl;
410 #endif
411
412
413 bg::strategy::buffer::side_straight side_strategy;
414 bg::strategy::buffer::point_circle circle_strategy(88);
415
416 bg::strategy::buffer::distance_asymmetric
417 <
418 typename bg::coordinate_type<Geometry>::type
419 > distance_strategy(distance_left,
420 bg::math::equals(distance_right, same_distance)
421 ? distance_left : distance_right);
422
423 test_buffer<GeometryOut>
424 (caseid, g,
425 join_strategy, end_strategy,
426 distance_strategy, side_strategy, circle_strategy,
427 expected_count, expected_holes_count, expected_area,
428 settings);
429
430 #if !defined(BOOST_GEOMETRY_COMPILER_MODE_DEBUG) && defined(BOOST_GEOMETRY_COMPILER_MODE_RELEASE)
431
432 // Also test symmetric distance strategy if right-distance is not specified
433 // (only in release mode)
434 if (bg::math::equals(distance_right, same_distance))
435 {
436 bg::strategy::buffer::distance_symmetric
437 <
438 typename bg::coordinate_type<Geometry>::type
439 > sym_distance_strategy(distance_left);
440
441 test_buffer<GeometryOut>
442 (caseid + "_sym", g,
443 join_strategy, end_strategy,
444 sym_distance_strategy, side_strategy, circle_strategy,
445 expected_count, expected_holes_count, expected_area,
446 settings);
447
448 }
449 #endif
450 }
451
452 template
453 <
454 typename Geometry,
455 typename GeometryOut,
456 typename JoinStrategy,
457 typename EndStrategy
458 >
459 void test_one(std::string const& caseid, std::string const& wkt,
460 JoinStrategy const& join_strategy, EndStrategy const& end_strategy,
461 double expected_area,
462 double distance_left, ut_settings const& settings = ut_settings(),
463 double distance_right = same_distance)
464 {
465 test_one<Geometry, GeometryOut>(caseid, wkt, join_strategy, end_strategy,
466 -1 ,-1, expected_area,
467 distance_left, settings, distance_right);
468 }
469
470 template
471 <
472 typename Geometry,
473 typename GeometryOut,
474 typename JoinStrategy,
475 typename EndStrategy,
476 typename DistanceStrategy,
477 typename SideStrategy,
478 typename PointStrategy
479 >
480 void test_with_custom_strategies(std::string const& caseid,
481 std::string const& wkt,
482 JoinStrategy const& join_strategy,
483 EndStrategy const& end_strategy,
484 DistanceStrategy const& distance_strategy,
485 SideStrategy const& side_strategy,
486 PointStrategy const& point_strategy,
487 double expected_area,
488 ut_settings const& settings = ut_settings())
489 {
490 namespace bg = boost::geometry;
491 Geometry g;
492 bg::read_wkt(wkt, g);
493 bg::correct(g);
494
495 test_buffer<GeometryOut>
496 (caseid, g,
497 join_strategy, end_strategy,
498 distance_strategy, side_strategy, point_strategy,
499 expected_area, settings);
500 }
501
502 #endif