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