1 // Boost.Geometry (aka GGL, Generic Geometry Library)
3 // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
4 // Use, modification and distribution is subject to the Boost Software License,
5 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt)
8 #include <geometry_test_common.hpp>
10 #include <algorithms/test_overlay.hpp>
13 #include <boost/geometry/geometry.hpp>
14 #include <boost/geometry/geometries/multi_point.hpp>
15 #include <boost/geometry/geometries/point_xy.hpp>
16 #include <boost/geometry/geometries/register/point.hpp>
18 #include <boost/geometry/algorithms/detail/partition.hpp>
20 #include <boost/geometry/io/wkt/wkt.hpp>
22 #if defined(TEST_WITH_SVG)
23 # include <boost/geometry/io/svg/svg_mapper.hpp>
26 #include <boost/random/linear_congruential.hpp>
27 #include <boost/random/uniform_int.hpp>
28 #include <boost/random/uniform_real.hpp>
29 #include <boost/random/variate_generator.hpp>
32 template <typename Box
>
37 box_item(int i
= 0, std::string
const& wkt
= "")
42 bg::read_wkt(wkt
, box
);
50 template <typename Box
, typename InputItem
>
51 static inline void apply(Box
& total
, InputItem
const& item
)
53 bg::expand(total
, item
.box
);
59 template <typename Box
, typename InputItem
>
60 static inline bool apply(Box
const& box
, InputItem
const& item
)
62 return ! bg::detail::disjoint::disjoint_box_box(box
, item
.box
);
67 template <typename Box
>
71 typename
bg::default_area_result
<Box
>::type area
;
78 template <typename Item
>
79 inline void apply(Item
const& item1
, Item
const& item2
)
81 if (bg::intersects(item1
.box
, item2
.box
))
84 bg::intersection(item1
.box
, item2
.box
, b
);
91 struct point_in_box_visitor
94 point_in_box_visitor()
98 template <typename Point
, typename BoxItem
>
99 inline void apply(Point
const& point
, BoxItem
const& box_item
)
101 if (bg::within(point
, box_item
.box
))
108 struct reversed_point_in_box_visitor
111 reversed_point_in_box_visitor()
115 template <typename BoxItem
, typename Point
>
116 inline void apply(BoxItem
const& box_item
, Point
const& point
)
118 if (bg::within(point
, box_item
.box
))
127 template <typename Box
>
128 void test_boxes(std::string
const& wkt_box_list
, double expected_area
, int expected_count
)
130 std::vector
<std::string
> wkt_boxes
;
132 boost::split(wkt_boxes
, wkt_box_list
, boost::is_any_of(";"), boost::token_compress_on
);
134 typedef box_item
<Box
> sample
;
135 std::vector
<sample
> boxes
;
138 BOOST_FOREACH(std::string
const& wkt
, wkt_boxes
)
140 boxes
.push_back(sample(index
++, wkt
));
143 box_visitor
<Box
> visitor
;
146 Box
, get_box
, ovelaps_box
147 >::apply(boxes
, visitor
, 1);
149 BOOST_CHECK_CLOSE(visitor
.area
, expected_area
, 0.001);
150 BOOST_CHECK_EQUAL(visitor
.count
, expected_count
);
166 BOOST_GEOMETRY_REGISTER_POINT_2D(point_item
, double, cs::cartesian
, x
, y
)
171 template <typename Box
, typename InputItem
>
172 static inline void apply(Box
& total
, InputItem
const& item
)
174 bg::expand(total
, item
);
180 template <typename Box
, typename InputItem
>
181 static inline bool apply(Box
const& box
, InputItem
const& item
)
183 return ! bg::disjoint(item
, box
);
196 template <typename Item
>
197 inline void apply(Item
const& item1
, Item
const& item2
)
199 if (bg::equals(item1
, item2
))
208 void test_points(std::string
const& wkt1
, std::string
const& wkt2
, int expected_count
)
210 bg::model::multi_point
<point_item
> mp1
, mp2
;
211 bg::read_wkt(wkt1
, mp1
);
212 bg::read_wkt(wkt2
, mp2
);
215 BOOST_FOREACH(point_item
& p
, mp1
)
218 BOOST_FOREACH(point_item
& p
, mp2
)
221 point_visitor visitor
;
224 bg::model::box
<point_item
>, get_point
, ovelaps_point
225 >::apply(mp1
, mp2
, visitor
, 1);
227 BOOST_CHECK_EQUAL(visitor
.count
, expected_count
);
232 template <typename P
>
235 typedef bg::model::box
<P
> box
;
239 "box(0 0,1 1); box(0 0,2 2); box(9 9,10 10); box(8 8,9 9); box(4 4,6 6); box(2 4,6 8); box(7 1,8 2)",
240 5, // Area(Intersection(1,2)) + A(I(5,6))
244 "box(0 0,10 10); box(4 4,6 6); box(3 3,7 7)",
245 4 + 16 + 4, // A(I(1,2)) + A(I(1,3)) + A(I(2,3))
249 "box(0 2,10 3); box(3 1,4 5); box(7 1,8 5)",
250 1 + 1, // A(I(1,2)) + A(I(1,3))
253 test_points("multipoint((1 1))", "multipoint((1 1))", 1);
254 test_points("multipoint((0 0),(1 1),(7 3),(10 10))", "multipoint((1 1),(2 2),(7 3))", 2);
258 //------------------- higher volumes
260 #if defined(TEST_WITH_SVG)
261 template <typename SvgMapper
>
266 svg_visitor(SvgMapper
& mapper
)
270 template <typename Box
>
271 inline void apply(Box
const& box
, int level
)
274 std::string color("rgb(64,64,64)");
277 case 0 : color = "rgb(255,0,0)"; break;
278 case 1 : color = "rgb(0,255,0)"; break;
279 case 2 : color = "rgb(0,0,255)"; break;
280 case 3 : color = "rgb(255,255,0)"; break;
281 case 4 : color = "rgb(255,0,255)"; break;
282 case 5 : color = "rgb(0,255,255)"; break;
283 case 6 : color = "rgb(255,128,0)"; break;
284 case 7 : color = "rgb(0,128,255)"; break;
286 std::ostringstream style;
287 style << "fill:none;stroke-width:" << (5.0 - level / 2.0) << ";stroke:" << color << ";";
288 m_mapper.map(box, style.str());
290 m_mapper
.map(box
, "fill:none;stroke-width:2;stroke:rgb(0,0,0);");
297 template <typename Collection
>
298 void fill_points(Collection
& collection
, int seed
, int size
, int count
)
300 typedef boost::minstd_rand base_generator_type
;
302 base_generator_type
generator(seed
);
304 boost::uniform_int
<> random_coordinate(0, size
- 1);
305 boost::variate_generator
<base_generator_type
&, boost::uniform_int
<> >
306 coordinate_generator(generator
, random_coordinate
);
308 std::set
<std::pair
<int, int> > included
;
311 for (int i
= 0; n
< count
&& i
< count
*count
; i
++)
313 int x
= coordinate_generator();
314 int y
= coordinate_generator();
315 std::pair
<int, int> pair
= std::make_pair(x
, y
);
316 if (included
.find(pair
) == included
.end())
318 included
.insert(pair
);
319 typename
boost::range_value
<Collection
>::type item
;
322 collection
.push_back(item
);
328 void test_many_points(int seed
, int size
, int count
)
330 bg::model::multi_point
<point_item
> mp1
, mp2
;
332 fill_points(mp1
, seed
, size
, count
);
333 fill_points(mp2
, seed
* 2, size
, count
);
335 // Test equality in quadratic loop
336 int expected_count
= 0;
337 BOOST_FOREACH(point_item
const& item1
, mp1
)
339 BOOST_FOREACH(point_item
const& item2
, mp2
)
341 if (bg::equals(item1
, item2
))
348 #if defined(TEST_WITH_SVG)
349 std::ostringstream filename
;
350 filename
<< "partition" << seed
<< ".svg";
351 std::ofstream
svg(filename
.str().c_str());
353 bg::svg_mapper
<point_item
> mapper(svg
, 800, 800);
357 p
.x
= -1; p
.y
= -1; mapper
.add(p
);
358 p
.x
= size
+ 1; p
.y
= size
+ 1; mapper
.add(p
);
361 typedef svg_visitor
<bg::svg_mapper
<point_item
> > box_visitor_type
;
362 box_visitor_type
box_visitor(mapper
);
364 typedef bg::detail::partition::visit_no_policy box_visitor_type
;
365 box_visitor_type box_visitor
;
368 point_visitor visitor
;
371 bg::model::box
<point_item
>,
372 get_point
, ovelaps_point
,
373 get_point
, ovelaps_point
,
374 bg::detail::partition::include_all_policy
,
375 bg::detail::partition::include_all_policy
,
377 >::apply(mp1
, mp2
, visitor
, 2, box_visitor
);
379 BOOST_CHECK_EQUAL(visitor
.count
, expected_count
);
381 #if defined(TEST_WITH_SVG)
382 BOOST_FOREACH(point_item
const& item
, mp1
)
384 mapper
.map(item
, "fill:rgb(255,128,0);stroke:rgb(0,0,100);stroke-width:1", 8);
386 BOOST_FOREACH(point_item
const& item
, mp2
)
388 mapper
.map(item
, "fill:rgb(0,128,255);stroke:rgb(0,0,100);stroke-width:1", 4);
393 template <typename Collection
>
394 void fill_boxes(Collection
& collection
, int seed
, int size
, int count
)
396 typedef boost::minstd_rand base_generator_type
;
398 base_generator_type
generator(seed
);
400 boost::uniform_int
<> random_coordinate(0, size
* 10 - 1);
401 boost::variate_generator
<base_generator_type
&, boost::uniform_int
<> >
402 coordinate_generator(generator
, random_coordinate
);
405 for (int i
= 0; n
< count
&& i
< count
*count
; i
++)
407 int w
= coordinate_generator() % 30;
408 int h
= coordinate_generator() % 30;
411 int x
= coordinate_generator();
412 int y
= coordinate_generator();
413 if (x
+ w
< size
* 10 && y
+ h
< size
* 10)
415 typename
boost::range_value
<Collection
>::type
item(n
+1);
416 bg::assign_values(item
.box
, x
/ 10.0, y
/ 10.0, (x
+ w
) / 10.0, (y
+ h
) / 10.0);
417 collection
.push_back(item
);
424 void test_many_boxes(int seed
, int size
, int count
)
426 typedef bg::model::box
<point_item
> box_type
;
427 std::vector
<box_item
<box_type
> > boxes
;
429 fill_boxes(boxes
, seed
, size
, count
);
431 // Test equality in quadratic loop
432 int expected_count
= 0;
433 double expected_area
= 0.0;
434 BOOST_FOREACH(box_item
<box_type
> const& item1
, boxes
)
436 BOOST_FOREACH(box_item
<box_type
> const& item2
, boxes
)
438 if (item1
.id
< item2
.id
)
440 if (bg::intersects(item1
.box
, item2
.box
))
443 bg::intersection(item1
.box
, item2
.box
, b
);
444 expected_area
+= bg::area(b
);
452 #if defined(TEST_WITH_SVG)
453 std::ostringstream filename
;
454 filename
<< "partition_box_" << seed
<< ".svg";
455 std::ofstream
svg(filename
.str().c_str());
457 bg::svg_mapper
<point_item
> mapper(svg
, 800, 800);
461 p
.x
= -1; p
.y
= -1; mapper
.add(p
);
462 p
.x
= size
+ 1; p
.y
= size
+ 1; mapper
.add(p
);
465 BOOST_FOREACH(box_item
<box_type
> const& item
, boxes
)
467 mapper
.map(item
.box
, "opacity:0.6;fill:rgb(50,50,210);stroke:rgb(0,0,0);stroke-width:1");
470 typedef svg_visitor
<bg::svg_mapper
<point_item
> > partition_box_visitor_type
;
471 partition_box_visitor_type
partition_box_visitor(mapper
);
474 typedef bg::detail::partition::visit_no_policy partition_box_visitor_type
;
475 partition_box_visitor_type partition_box_visitor
;
478 box_visitor
<box_type
> visitor
;
482 get_box
, ovelaps_box
,
483 get_box
, ovelaps_box
,
484 bg::detail::partition::include_all_policy
,
485 bg::detail::partition::include_all_policy
,
486 partition_box_visitor_type
487 >::apply(boxes
, visitor
, 2, partition_box_visitor
);
489 BOOST_CHECK_EQUAL(visitor
.count
, expected_count
);
490 BOOST_CHECK_CLOSE(visitor
.area
, expected_area
, 0.001);
493 void test_two_collections(int seed1
, int seed2
, int size
, int count
)
495 typedef bg::model::box
<point_item
> box_type
;
496 std::vector
<box_item
<box_type
> > boxes1
, boxes2
;
498 fill_boxes(boxes1
, seed1
, size
, count
);
499 fill_boxes(boxes2
, seed2
, size
, count
);
501 // Get expectations in quadratic loop
502 int expected_count
= 0;
503 double expected_area
= 0.0;
504 BOOST_FOREACH(box_item
<box_type
> const& item1
, boxes1
)
506 BOOST_FOREACH(box_item
<box_type
> const& item2
, boxes2
)
508 if (bg::intersects(item1
.box
, item2
.box
))
511 bg::intersection(item1
.box
, item2
.box
, b
);
512 expected_area
+= bg::area(b
);
519 #if defined(TEST_WITH_SVG)
520 std::ostringstream filename
;
521 filename
<< "partition_boxes_" << seed1
<< "_" << seed2
<< ".svg";
522 std::ofstream
svg(filename
.str().c_str());
524 bg::svg_mapper
<point_item
> mapper(svg
, 800, 800);
528 p
.x
= -1; p
.y
= -1; mapper
.add(p
);
529 p
.x
= size
+ 1; p
.y
= size
+ 1; mapper
.add(p
);
532 BOOST_FOREACH(box_item
<box_type
> const& item
, boxes1
)
534 mapper
.map(item
.box
, "opacity:0.6;fill:rgb(50,50,210);stroke:rgb(0,0,0);stroke-width:1");
536 BOOST_FOREACH(box_item
<box_type
> const& item
, boxes2
)
538 mapper
.map(item
.box
, "opacity:0.6;fill:rgb(0,255,0);stroke:rgb(0,0,0);stroke-width:1");
541 typedef svg_visitor
<bg::svg_mapper
<point_item
> > partition_box_visitor_type
;
542 partition_box_visitor_type
partition_box_visitor(mapper
);
544 typedef bg::detail::partition::visit_no_policy partition_box_visitor_type
;
545 partition_box_visitor_type partition_box_visitor
;
548 box_visitor
<box_type
> visitor
;
552 get_box
, ovelaps_box
,
553 get_box
, ovelaps_box
,
554 bg::detail::partition::include_all_policy
,
555 bg::detail::partition::include_all_policy
,
556 partition_box_visitor_type
557 >::apply(boxes1
, boxes2
, visitor
, 2, partition_box_visitor
);
559 BOOST_CHECK_EQUAL(visitor
.count
, expected_count
);
560 BOOST_CHECK_CLOSE(visitor
.area
, expected_area
, 0.001);
564 void test_heterogenuous_collections(int seed1
, int seed2
, int size
, int count
)
566 typedef bg::model::box
<point_item
> box_type
;
567 std::vector
<point_item
> points
;
568 std::vector
<box_item
<box_type
> > boxes
;
570 fill_points(points
, seed1
, size
, count
);
571 fill_boxes(boxes
, seed2
, size
, count
);
573 // Get expectations in quadratic loop
574 int expected_count
= 0;
575 BOOST_FOREACH(point_item
const& point
, points
)
577 BOOST_FOREACH(box_item
<box_type
> const& box_item
, boxes
)
579 if (bg::within(point
, box_item
.box
))
587 #if defined(TEST_WITH_SVG)
588 std::ostringstream filename
;
589 filename
<< "partition_heterogeneous_" << seed1
<< "_" << seed2
<< ".svg";
590 std::ofstream
svg(filename
.str().c_str());
592 bg::svg_mapper
<point_item
> mapper(svg
, 800, 800);
596 p
.x
= -1; p
.y
= -1; mapper
.add(p
);
597 p
.x
= size
+ 1; p
.y
= size
+ 1; mapper
.add(p
);
600 BOOST_FOREACH(point_item
const& point
, points
)
602 mapper
.map(point
, "fill:rgb(255,128,0);stroke:rgb(0,0,100);stroke-width:1", 8);
604 BOOST_FOREACH(box_item
<box_type
> const& item
, boxes
)
606 mapper
.map(item
.box
, "opacity:0.6;fill:rgb(0,255,0);stroke:rgb(0,0,0);stroke-width:1");
609 typedef svg_visitor
<bg::svg_mapper
<point_item
> > partition_box_visitor_type
;
610 partition_box_visitor_type
partition_box_visitor(mapper
);
612 typedef bg::detail::partition::visit_no_policy partition_box_visitor_type
;
613 partition_box_visitor_type partition_box_visitor
;
616 point_in_box_visitor visitor1
;
620 get_point
, ovelaps_point
,
621 get_box
, ovelaps_box
,
622 bg::detail::partition::include_all_policy
,
623 bg::detail::partition::include_all_policy
,
624 partition_box_visitor_type
625 >::apply(points
, boxes
, visitor1
, 2, partition_box_visitor
);
627 reversed_point_in_box_visitor visitor2
;
631 get_box
, ovelaps_box
,
632 get_point
, ovelaps_point
,
633 bg::detail::partition::include_all_policy
,
634 bg::detail::partition::include_all_policy
,
635 partition_box_visitor_type
636 >::apply(boxes
, points
, visitor2
, 2, partition_box_visitor
);
638 BOOST_CHECK_EQUAL(visitor1
.count
, expected_count
);
639 BOOST_CHECK_EQUAL(visitor2
.count
, expected_count
);
642 int test_main( int , char* [] )
644 test_all
<bg::model::d2::point_xy
<double> >();
646 test_many_points(12345, 20, 40);
647 test_many_points(54321, 20, 60);
648 test_many_points(67890, 20, 80);
649 test_many_points(98765, 20, 100);
650 for (int i
= 1; i
< 10; i
++)
652 test_many_points(i
, 30, i
* 20);
655 test_many_boxes(12345, 20, 40);
656 for (int i
= 1; i
< 10; i
++)
658 test_many_boxes(i
, 20, i
* 10);
661 test_two_collections(12345, 54321, 20, 40);
662 test_two_collections(67890, 98765, 20, 60);
664 test_heterogenuous_collections(67890, 98765, 20, 60);