From 0287c1d3bbf3562376a01bdf3fe4dad3dcb263ad Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Wed, 11 Jun 2014 14:17:09 +0200 Subject: [PATCH] [partition] support heterogenous collections --- .../geometry/algorithms/detail/partition.hpp | 88 ++++++++----- test/algorithms/detail/partition.cpp | 123 +++++++++++++++++- 2 files changed, 178 insertions(+), 33 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/partition.hpp b/include/boost/geometry/algorithms/detail/partition.hpp index a2d4912e3..0b64f3e3f 100644 --- a/include/boost/geometry/algorithms/detail/partition.hpp +++ b/include/boost/geometry/algorithms/detail/partition.hpp @@ -106,10 +106,15 @@ static inline void handle_one(InputCollection const& collection, } // Match collection 1 with collection 2 -template -static inline void handle_two( - InputCollection const& collection1, index_vector_type const& input1, - InputCollection const& collection2, index_vector_type const& input2, +template +< + typename InputCollection1, + typename InputCollection2, + typename Policy +> +inline void handle_two( + InputCollection1 const& collection1, index_vector_type const& input1, + InputCollection2 const& collection2, index_vector_type const& input2, Policy& policy) { typedef boost::range_iterator @@ -209,7 +214,8 @@ template < int Dimension, typename Box, - typename OverlapsPolicy, + typename OverlapsPolicy1, + typename OverlapsPolicy2, typename VisitBoxPolicy > class partition_two_collections @@ -220,15 +226,21 @@ class partition_two_collections < 1 - Dimension, Box, - OverlapsPolicy, + OverlapsPolicy1, + OverlapsPolicy2, VisitBoxPolicy > sub_divide; - template + template + < + typename InputCollection1, + typename InputCollection2, + typename Policy + > static inline void next_level(Box const& box, - InputCollection const& collection1, + InputCollection1 const& collection1, index_vector_type const& input1, - InputCollection const& collection2, + InputCollection2 const& collection2, index_vector_type const& input2, int level, std::size_t min_elements, Policy& policy, VisitBoxPolicy& box_policy) @@ -252,10 +264,15 @@ class partition_two_collections } public : - template + template + < + typename InputCollection1, + typename InputCollection2, + typename Policy + > static inline void apply(Box const& box, - InputCollection const& collection1, index_vector_type const& input1, - InputCollection const& collection2, index_vector_type const& input2, + InputCollection1 const& collection1, index_vector_type const& input1, + InputCollection2 const& collection2, index_vector_type const& input2, int level, std::size_t min_elements, Policy& policy, VisitBoxPolicy& box_policy) @@ -267,9 +284,9 @@ public : index_vector_type lower1, upper1, exceeding1; index_vector_type lower2, upper2, exceeding2; - divide_into_subsets(lower_box, upper_box, collection1, + divide_into_subsets(lower_box, upper_box, collection1, input1, lower1, upper1, exceeding1); - divide_into_subsets(lower_box, upper_box, collection2, + divide_into_subsets(lower_box, upper_box, collection2, input2, lower2, upper2, exceeding2); if (boost::size(exceeding1) > 0) @@ -308,15 +325,17 @@ struct visit_no_policy template < typename Box, - typename ExpandPolicy, - typename OverlapsPolicy, + typename ExpandPolicy1, + typename OverlapsPolicy1, + typename ExpandPolicy2 = ExpandPolicy1, + typename OverlapsPolicy2 = OverlapsPolicy1, typename VisitBoxPolicy = visit_no_policy > class partition { typedef std::vector index_vector_type; - template + template static inline void expand_to_collection(InputCollection const& collection, Box& total, index_vector_type& index_vector) { @@ -344,12 +363,12 @@ public : index_vector_type index_vector; Box total; assign_inverse(total); - expand_to_collection(collection, total, index_vector); + expand_to_collection(collection, total, index_vector); detail::partition::partition_one_collection < 0, Box, - OverlapsPolicy, + OverlapsPolicy1, VisitBoxPolicy >::apply(total, collection, index_vector, 0, min_elements, visitor, box_visitor); @@ -373,9 +392,14 @@ public : } } - template - static inline void apply(InputCollection const& collection1, - InputCollection const& collection2, + template + < + typename InputCollection1, + typename InputCollection2, + typename VisitPolicy + > + static inline void apply(InputCollection1 const& collection1, + InputCollection2 const& collection2, VisitPolicy& visitor, std::size_t min_elements = 16, VisitBoxPolicy box_visitor = visit_no_policy() @@ -387,12 +411,12 @@ public : index_vector_type index_vector1, index_vector2; Box total; assign_inverse(total); - expand_to_collection(collection1, total, index_vector1); - expand_to_collection(collection2, total, index_vector2); + expand_to_collection(collection1, total, index_vector1); + expand_to_collection(collection2, total, index_vector2); detail::partition::partition_two_collections < - 0, Box, OverlapsPolicy, VisitBoxPolicy + 0, Box, OverlapsPolicy1, OverlapsPolicy2, VisitBoxPolicy >::apply(total, collection1, index_vector1, collection2, index_vector2, @@ -402,13 +426,17 @@ public : { typedef typename boost::range_iterator < - InputCollection const - >::type iterator_type; - for(iterator_type it1 = boost::begin(collection1); + InputCollection1 const + >::type iterator_type1; + typedef typename boost::range_iterator + < + InputCollection2 const + >::type iterator_type2; + for(iterator_type1 it1 = boost::begin(collection1); it1 != boost::end(collection1); ++it1) { - for(iterator_type it2 = boost::begin(collection2); + for(iterator_type2 it2 = boost::begin(collection2); it2 != boost::end(collection2); ++it2) { @@ -417,9 +445,9 @@ public : } } } - }; + }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_PARTITION_HPP diff --git a/test/algorithms/detail/partition.cpp b/test/algorithms/detail/partition.cpp index a3189635c..90cbe137f 100644 --- a/test/algorithms/detail/partition.cpp +++ b/test/algorithms/detail/partition.cpp @@ -89,6 +89,40 @@ struct box_visitor } }; +struct point_in_box_visitor +{ + int count; + point_in_box_visitor() + : count(0) + {} + + template + inline void apply(Point const& point, BoxItem const& box_item) + { + if (bg::within(point, box_item.box)) + { + count++; + } + } +}; + +struct reversed_point_in_box_visitor +{ + int count; + reversed_point_in_box_visitor() + : count(0) + {} + + template + inline void apply(BoxItem const& box_item, Point const& point) + { + if (bg::within(point, box_item.box)) + { + count++; + } + } +}; + template @@ -335,7 +369,9 @@ void test_many_points(int seed, int size, int count) point_visitor visitor; bg::partition < - bg::model::box, get_point, ovelaps_point, + bg::model::box, + get_point, ovelaps_point, + get_point, ovelaps_point, box_visitor_type >::apply(mp1, mp2, visitor, 2, box_visitor); @@ -441,7 +477,9 @@ void test_many_boxes(int seed, int size, int count) box_visitor visitor; bg::partition < - box_type, get_box, ovelaps_box, + box_type, + get_box, ovelaps_box, + get_box, ovelaps_box, partition_box_visitor_type >::apply(boxes, visitor, 2, partition_box_visitor); @@ -507,7 +545,9 @@ void test_two_collections(int seed1, int seed2, int size, int count) box_visitor visitor; bg::partition < - box_type, get_box, ovelaps_box, + box_type, + get_box, ovelaps_box, + get_box, ovelaps_box, partition_box_visitor_type >::apply(boxes1, boxes2, visitor, 2, partition_box_visitor); @@ -515,6 +555,81 @@ void test_two_collections(int seed1, int seed2, int size, int count) BOOST_CHECK_CLOSE(visitor.area, expected_area, 0.001); } + +void test_heterogenuous_collections(int seed1, int seed2, int size, int count) +{ + typedef bg::model::box box_type; + std::vector points; + std::vector > boxes; + + fill_points(points, seed1, size, count); + fill_boxes(boxes, seed2, size, count); + + // Get expectations in quadratic loop + int expected_count = 0; + BOOST_FOREACH(point_item const& point, points) + { + BOOST_FOREACH(box_item const& box_item, boxes) + { + if (bg::within(point, box_item.box)) + { + expected_count++; + } + } + } + + +#if defined(TEST_WITH_SVG) + std::ostringstream filename; + filename << "partition_heterogeneous_" << seed1 << "_" << seed2 << ".svg"; + std::ofstream svg(filename.str().c_str()); + + bg::svg_mapper mapper(svg, 800, 800); + + { + point_item p; + p.x = -1; p.y = -1; mapper.add(p); + p.x = size + 1; p.y = size + 1; mapper.add(p); + } + + BOOST_FOREACH(point_item const& point, points) + { + mapper.map(point, "fill:rgb(255,128,0);stroke:rgb(0,0,100);stroke-width:1", 8); + } + BOOST_FOREACH(box_item const& item, boxes) + { + mapper.map(item.box, "opacity:0.6;fill:rgb(0,255,0);stroke:rgb(0,0,0);stroke-width:1"); + } + + typedef svg_visitor > partition_box_visitor_type; + partition_box_visitor_type partition_box_visitor(mapper); +#else + typedef bg::visit_no_policy partition_box_visitor_type; + partition_box_visitor_type partition_box_visitor; +#endif + + point_in_box_visitor visitor1; + bg::partition + < + box_type, + get_point, ovelaps_point, + get_box, ovelaps_box, + partition_box_visitor_type + >::apply(points, boxes, visitor1, 2, partition_box_visitor); + + reversed_point_in_box_visitor visitor2; + bg::partition + < + box_type, + get_box, ovelaps_box, + get_point, ovelaps_point, + partition_box_visitor_type + >::apply(boxes, points, visitor2, 2, partition_box_visitor); + + BOOST_CHECK_EQUAL(visitor1.count, expected_count); + BOOST_CHECK_EQUAL(visitor2.count, expected_count); +} + int test_main( int , char* [] ) { test_all >(); @@ -537,5 +652,7 @@ int test_main( int , char* [] ) test_two_collections(12345, 54321, 20, 40); test_two_collections(67890, 98765, 20, 60); + test_heterogenuous_collections(67890, 98765, 20, 60); + return 0; }