// Boost.Geometry Index // Unit Test // Copyright (c) 2011-2012 Adam Wulkiewicz, Lodz, Poland. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_EXTENSIONS_INDEX_TEST_RTREE_HPP #define BOOST_GEOMETRY_EXTENSIONS_INDEX_TEST_RTREE_HPP #include #include #include #include #include #include #include //#include //#include // Set point's coordinates template struct generate_outside_point {}; template struct generate_outside_point< bg::model::point > { typedef bg::model::point P; static P apply() { return P(13, 26); } }; template struct generate_outside_point< bg::model::point > { typedef bg::model::point P; static P apply() { return P(13, 26, 13); } }; // Default value generation template struct generate_value_default { static Value apply(){ return Value(); } }; // Values, input and rtree generation template struct generate_value {}; template struct generate_value< bg::model::point > { typedef bg::model::point P; static P apply(int x, int y) { return P(x, y); } }; template struct generate_value< bg::model::box< bg::model::point > > { typedef bg::model::point P; typedef bg::model::box

B; static B apply(int x, int y) { return B(P(x, y), P(x + 2, y + 3)); } }; template struct generate_value< std::pair, int> > { typedef bg::model::point P; typedef std::pair R; static R apply(int x, int y) { return std::make_pair(P(x, y), x + y * 100); } }; template struct generate_value< std::pair >, int> > { typedef bg::model::point P; typedef bg::model::box

B; typedef std::pair R; static R apply(int x, int y) { return std::make_pair(B(P(x, y), P(x + 2, y + 3)), x + y * 100); } }; template struct generate_value< boost::tuple, int, int> > { typedef bg::model::point P; typedef boost::tuple R; static R apply(int x, int y) { return boost::make_tuple(P(x, y), x + y * 100, 0); } }; template struct generate_value< boost::tuple >, int, int> > { typedef bg::model::point P; typedef bg::model::box

B; typedef boost::tuple R; static R apply(int x, int y) { return boost::make_tuple(B(P(x, y), P(x + 2, y + 3)), x + y * 100, 0); } }; template struct generate_value< bg::model::point > { typedef bg::model::point P; static P apply(int x, int y, int z) { return P(x, y, z); } }; template struct generate_value< bg::model::box< bg::model::point > > { typedef bg::model::point P; typedef bg::model::box

B; static B apply(int x, int y, int z) { return B(P(x, y, z), P(x + 2, y + 3, z + 4)); } }; template struct generate_value< std::pair, int> > { typedef bg::model::point P; typedef std::pair R; static R apply(int x, int y, int z) { return std::make_pair(P(x, y, z), x + y * 100 + z * 10000); } }; template struct generate_value< std::pair >, int> > { typedef bg::model::point P; typedef bg::model::box

B; typedef std::pair R; static R apply(int x, int y, int z) { return std::make_pair(B(P(x, y, z), P(x + 2, y + 3, z + 4)), x + y * 100 + z * 10000); } }; template struct generate_value< boost::tuple, int, int> > { typedef bg::model::point P; typedef boost::tuple R; static R apply(int x, int y, int z) { return boost::make_tuple(P(x, y, z), x + y * 100 + z * 10000, 0); } }; template struct generate_value< boost::tuple >, int, int> > { typedef bg::model::point P; typedef bg::model::box

B; typedef boost::tuple R; static R apply(int x, int y, int z) { return boost::make_tuple(B(P(x, y, z), P(x + 2, y + 3, z + 4)), x + y * 100 + z * 10000, 0); } }; // shared_ptr value template struct test_object { test_object(Indexable const& indexable_) : indexable(indexable_) {} Indexable indexable; }; namespace boost { namespace geometry { namespace index { namespace translator { template struct def< boost::shared_ptr< test_object > > { typedef boost::shared_ptr< test_object > value_type; typedef Indexable const& result_type; result_type operator()(value_type const& value) const { return value->indexable; } bool equals(value_type const& v1, value_type const& v2) const { return v1 == v2; } }; }}}} template struct generate_value< boost::shared_ptr > > > { typedef bg::model::point P; typedef test_object

O; typedef boost::shared_ptr R; static R apply(int x, int y) { return R(new O(P(x, y))); } }; template struct generate_value< boost::shared_ptr > > > { typedef bg::model::point P; typedef test_object

O; typedef boost::shared_ptr R; static R apply(int x, int y, int z) { return R(new O(P(x, y, z))); } }; // counting value template struct counting_value { counting_value() { counter()++; } counting_value(Indexable const& i) : indexable(i) { counter()++; } counting_value(counting_value const& c) : indexable(c.indexable) { counter()++; } ~counting_value() { counter()--; } static size_t & counter() { static size_t c = 0; return c; } Indexable indexable; }; namespace boost { namespace geometry { namespace index { namespace translator { template struct def< counting_value > { typedef counting_value value_type; typedef Indexable const& result_type; result_type operator()(value_type const& value) const { return value.indexable; } bool equals(value_type const& v1, value_type const& v2) const { return boost::geometry::equals(v1.indexable, v2.indexable); } }; }}}} template struct generate_value< counting_value > > { typedef bg::model::point P; typedef counting_value

R; static R apply(int x, int y) { return R(P(x, y)); } }; template struct generate_value< counting_value > > { typedef bg::model::point P; typedef counting_value

R; static R apply(int x, int y, int z) { return R(P(x, y, z)); } }; template struct generate_value< counting_value > > > { typedef bg::model::point P; typedef bg::model::box

B; typedef counting_value R; static R apply(int x, int y) { return R(B(P(x, y), P(x+2, y+3))); } }; template struct generate_value< counting_value > > > { typedef bg::model::point P; typedef bg::model::box

B; typedef counting_value R; static R apply(int x, int y, int z) { return R(B(P(x, y, z), P(x+2, y+3, z+4))); } }; // value without default constructor template struct value_no_dctor { value_no_dctor(Indexable const& i) : indexable(i) {} Indexable indexable; }; namespace boost { namespace geometry { namespace index { namespace translator { template struct def< value_no_dctor > { typedef value_no_dctor value_type; typedef Indexable const& result_type; result_type operator()(value_type const& value) const { return value.indexable; } bool equals(value_type const& v1, value_type const& v2) const { return boost::geometry::equals(v1.indexable, v2.indexable); } }; }}}} template struct generate_value_default< value_no_dctor > { static value_no_dctor apply() { return value_no_dctor(Indexable()); } }; template struct generate_value< value_no_dctor > > { typedef bg::model::point P; typedef value_no_dctor

R; static R apply(int x, int y) { return R(P(x, y)); } }; template struct generate_value< value_no_dctor > > { typedef bg::model::point P; typedef value_no_dctor

R; static R apply(int x, int y, int z) { return R(P(x, y, z)); } }; template struct generate_value< value_no_dctor > > > { typedef bg::model::point P; typedef bg::model::box

B; typedef value_no_dctor R; static R apply(int x, int y) { return R(B(P(x, y), P(x+2, y+3))); } }; template struct generate_value< value_no_dctor > > > { typedef bg::model::point P; typedef bg::model::box

B; typedef value_no_dctor R; static R apply(int x, int y, int z) { return R(B(P(x, y, z), P(x+2, y+3, z+4))); } }; // generate input template struct generate_input {}; template <> struct generate_input<2> { template static void apply(std::vector & input, Box & qbox, int size = 1) { BOOST_GEOMETRY_INDEX_ASSERT(0 < size, "the value must be greather than 0"); for ( int i = 0 ; i < 12 * size ; i += 3 ) { for ( int j = 1 ; j < 25 * size ; j += 4 ) { input.push_back( generate_value::apply(i, j) ); } } typedef typename bg::traits::point_type::type P; qbox = Box(P(3, 0), P(10, 9)); } }; template <> struct generate_input<3> { template static void apply(std::vector & input, Box & qbox, int size = 1) { BOOST_GEOMETRY_INDEX_ASSERT(0 < size, "the value must be greather than 0"); for ( int i = 0 ; i < 12 * size ; i += 3 ) { for ( int j = 1 ; j < 25 * size ; j += 4 ) { for ( int k = 2 ; k < 12 * size ; k += 5 ) { input.push_back( generate_value::apply(i, j, k) ); } } } typedef typename bg::traits::point_type::type P; qbox = Box(P(3, 0, 3), P(10, 9, 11)); } }; template void generate_rtree(bgi::rtree & tree, std::vector & input, Box & qbox) { typedef bgi::rtree T; typedef typename T::box_type B; typedef typename T::value_type V; typedef typename T::indexable_type I; generate_input< bgi::traits::dimension::value >::apply(input, qbox); tree.insert(input.begin(), input.end()); } // low level test functions template Iter test_find(Rtree const& rtree, Iter first, Iter last, Value const& value) { for ( ; first != last ; ++first ) if ( rtree.translator().equals(value, *first) ) return first; return first; } template void test_compare_outputs(Rtree const& rtree, std::vector const& output, std::vector const& expected_output) { bool are_sizes_ok = (expected_output.size() == output.size()); BOOST_CHECK( are_sizes_ok ); if ( are_sizes_ok ) { BOOST_FOREACH(Value const& v, expected_output) { BOOST_CHECK(test_find(rtree, output.begin(), output.end(), v) != output.end() ); } } } template void test_exactly_the_same_outputs(Rtree const& rtree, Range1 const& output, Range2 const& expected_output) { size_t s1 = std::distance(output.begin(), output.end()); size_t s2 = std::distance(expected_output.begin(), expected_output.end()); BOOST_CHECK(s1 == s2); if ( s1 == s2 ) { typename Range1::const_iterator it1 = output.begin(); typename Range2::const_iterator it2 = expected_output.begin(); for ( ; it1 != output.end() && it2 != expected_output.end() ; ++it1, ++it2 ) { if ( !rtree.translator().equals(*it1, *it2) ) { BOOST_CHECK(false && "rtree.translator().equals(*it1, *it2)"); break; } } } } // spatial query template void test_spatial_query(Rtree & rtree, Predicates const& pred, std::vector const& expected_output) { BOOST_CHECK( bgi::are_levels_ok(rtree) ); if ( !rtree.empty() ) BOOST_CHECK( bgi::are_boxes_ok(rtree) ); std::vector output; size_t n = rtree.spatial_query(pred, std::back_inserter(output)); BOOST_CHECK( expected_output.size() == n ); test_compare_outputs(rtree, output, expected_output); std::vector output2; size_t n2 = spatial_query(rtree, pred, std::back_inserter(output2)); BOOST_CHECK( n == n2 ); test_exactly_the_same_outputs(rtree, output, output2); test_exactly_the_same_outputs(rtree, output, rtree | bgi::adaptors::spatial_queried(pred)); } // rtree specific queries tests template void test_intersects(bgi::rtree const& tree, std::vector const& input, Box const& qbox) { std::vector expected_output; BOOST_FOREACH(Value const& v, input) if ( bg::intersects(tree.translator()(v), qbox) ) expected_output.push_back(v); test_spatial_query(tree, qbox, expected_output); test_spatial_query(tree, bgi::intersects(qbox), expected_output); test_spatial_query(tree, !bgi::disjoint(qbox), expected_output); /*typedef bg::traits::point_type::type P; bg::model::ring

qring; bg::convert(qbox, qring); test_spatial_query(tree, bgi::intersects(qring), expected_output); test_spatial_query(tree, !bgi::disjoint(qring), expected_output); bg::model::polygon

qpoly; bg::convert(qbox, qpoly); test_spatial_query(tree, bgi::intersects(qpoly), expected_output); test_spatial_query(tree, !bgi::disjoint(qpoly), expected_output);*/ } template void test_disjoint(bgi::rtree const& tree, std::vector const& input, Box const& qbox) { std::vector expected_output; BOOST_FOREACH(Value const& v, input) if ( bg::disjoint(tree.translator()(v), qbox) ) expected_output.push_back(v); test_spatial_query(tree, bgi::disjoint(qbox), expected_output); test_spatial_query(tree, !bgi::intersects(qbox), expected_output); /*typedef bg::traits::point_type::type P; bg::model::ring

qring; bg::convert(qbox, qring); test_spatial_query(tree, bgi::disjoint(qring), expected_output); bg::model::polygon

qpoly; bg::convert(qbox, qpoly); test_spatial_query(tree, bgi::disjoint(qpoly), expected_output);*/ } template void test_covered_by(bgi::rtree const& tree, std::vector const& input, Box const& qbox) { std::vector expected_output; BOOST_FOREACH(Value const& v, input) if ( bg::covered_by(tree.translator()(v), qbox) ) expected_output.push_back(v); test_spatial_query(tree, bgi::covered_by(qbox), expected_output); /*typedef bg::traits::point_type::type P; bg::model::ring

qring; bg::convert(qbox, qring); test_spatial_query(tree, bgi::covered_by(qring), expected_output); bg::model::polygon

qpoly; bg::convert(qbox, qpoly); test_spatial_query(tree, bgi::covered_by(qpoly), expected_output);*/ } template struct test_overlap_impl { template static void apply(bgi::rtree const& tree, std::vector const& input, Box const& qbox) { std::vector expected_output; BOOST_FOREACH(Value const& v, input) if ( bg::overlaps(tree.translator()(v), qbox) ) expected_output.push_back(v); test_spatial_query(tree, bgi::overlaps(qbox), expected_output); /*typedef bg::traits::point_type::type P; bg::model::ring

qring; bg::convert(qbox, qring); test_spatial_query(tree, bgi::overlaps(qring), expected_output); bg::model::polygon

qpoly; bg::convert(qbox, qpoly); test_spatial_query(tree, bgi::overlaps(qpoly), expected_output);*/ } }; template <> struct test_overlap_impl { template static void apply(bgi::rtree const& /*tree*/, std::vector const& /*input*/, Box const& /*qbox*/) {} }; template void test_overlaps(bgi::rtree const& tree, std::vector const& input, Box const& qbox) { test_overlap_impl< typename bgi::traits::tag< typename bgi::rtree::indexable_type >::type >::apply(tree, input, qbox); } //template //struct test_touches_impl //{ // template // static void apply(bgi::rtree const& tree, std::vector const& input, Box const& qbox) // {} //}; // //template <> //struct test_touches_impl //{ // template // static void apply(bgi::rtree const& tree, std::vector const& input, Box const& qbox) // { // std::vector expected_output; // // BOOST_FOREACH(Value const& v, input) // if ( bg::touches(tree.translator()(v), qbox) ) // expected_output.push_back(v); // // test_spatial_query(tree, bgi::touches(qbox), expected_output); // } //}; // //template //void test_touches(bgi::rtree const& tree, std::vector const& input, Box const& qbox) //{ // test_touches_impl< // bgi::traits::tag< // typename bgi::rtree::indexable_type // >::type, // bgi::traits::dimension< // typename bgi::rtree::indexable_type // >::value // >::apply(tree, input, qbox); //} template void test_within(bgi::rtree const& tree, std::vector const& input, Box const& qbox) { std::vector expected_output; BOOST_FOREACH(Value const& v, input) if ( bg::within(tree.translator()(v), qbox) ) expected_output.push_back(v); test_spatial_query(tree, bgi::within(qbox), expected_output); /*typedef bg::traits::point_type::type P; bg::model::ring

qring; bg::convert(qbox, qring); test_spatial_query(tree, bgi::within(qring), expected_output); bg::model::polygon

qpoly; bg::convert(qbox, qpoly); test_spatial_query(tree, bgi::within(qpoly), expected_output);*/ } // rtree nearest queries template void test_nearest_query(Rtree const& rtree, std::vector const& input, Point const& pt) { // TODO: Nearest object may not be the same as found by the rtree if distances are equal // Should all objects with the same closest distance be picked? typedef typename bg::default_distance_result::type D; D smallest_d = (std::numeric_limits::max)(); Value expected_output(generate_value_default::apply()); BOOST_FOREACH(Value const& v, input) { D d = bgi::comparable_distance_near(pt, rtree.translator()(v)); if ( d < smallest_d ) { smallest_d = d; expected_output = v; } } size_t n = ( (std::numeric_limits::max)() == smallest_d ) ? 0 : 1; Value output(generate_value_default::apply()); size_t n_res = rtree.nearest_query(pt, output); BOOST_CHECK(n == n_res); if ( n == n_res && 0 < n ) { // TODO - perform explicit check here? // should all objects which are closest be checked and should exactly the same be found? if ( !rtree.translator().equals(output, expected_output) ) { D d1 = bgi::comparable_distance_near(pt, rtree.translator()(output)); D d2 = bgi::comparable_distance_near(pt, rtree.translator()(expected_output)); BOOST_CHECK(d1 == d2); } } } template struct TestNearestKLess { typedef typename bg::default_distance_result::type D; template bool operator()(std::pair const& p1, std::pair const& p2) const { return p1.first < p2.first; } }; template struct TestNearestKTransform { typedef typename bg::default_distance_result::type D; template Value const& operator()(std::pair const& p) const { return p.second; } }; template void test_nearest_query_k(Rtree const& rtree, std::vector const& input, Point const& pt, size_t k) { // TODO: Nearest object may not be the same as found by the rtree if distances are equal // All objects with the same closest distance should be picked typedef typename bg::default_distance_result::type D; std::vector< std::pair > test_output; // calculate test output - k closest values pairs BOOST_FOREACH(Value const& v, input) { D d = bgi::comparable_distance_near(pt, rtree.translator()(v)); if ( test_output.size() < k ) test_output.push_back(std::make_pair(d, v)); else { std::sort(test_output.begin(), test_output.end(), TestNearestKLess()); if ( d < test_output.back().first ) test_output.back() = std::make_pair(d, v); } } // caluclate biggest distance std::sort(test_output.begin(), test_output.end(), TestNearestKLess()); D biggest_d = 0; if ( !test_output.empty() ) biggest_d = test_output.back().first; // transform test output to vector of values std::vector expected_output(test_output.size(), generate_value_default::apply()); std::transform(test_output.begin(), test_output.end(), expected_output.begin(), TestNearestKTransform()); // calculate output using rtree std::vector output; rtree.nearest_query(pt, k, std::back_inserter(output)); // check output bool are_sizes_ok = (expected_output.size() == output.size()); BOOST_CHECK( are_sizes_ok ); if ( are_sizes_ok ) { BOOST_FOREACH(Value const& v, output) { // TODO - perform explicit check here? // should all objects which are closest be checked and should exactly the same be found? if ( test_find(rtree, expected_output.begin(), expected_output.end(), v) == expected_output.end() ) { D d = bgi::comparable_distance_near(pt, rtree.translator()(v)); BOOST_CHECK(d == biggest_d); } } } test_exactly_the_same_outputs(rtree, output, rtree | bgi::adaptors::nearest_queried(pt, k)); } // rtree nearest not found template void test_nearest_query_not_found(Rtree const& rtree, Point const& pt, CoordinateType max_distance_1, CoordinateType max_distance_k) { typedef typename Rtree::value_type Value; Value output(generate_value_default::apply()); size_t n_res = rtree.nearest_query(bgi::max_bounded(pt, max_distance_1), output); BOOST_CHECK(0 == n_res); std::vector output_v; n_res = rtree.nearest_query(bgi::max_bounded(pt, max_distance_k), 5, std::back_inserter(output_v)); BOOST_CHECK(output_v.size() == n_res); BOOST_CHECK(n_res < 5); } // rtree copying and moving template void test_copy_assignment_swap_move(bgi::rtree const& tree, Box const& qbox) { size_t s = tree.size(); std::vector expected_output; tree.spatial_query(qbox, std::back_inserter(expected_output)); // copy constructor bgi::rtree t1(tree); BOOST_CHECK(tree.empty() == t1.empty()); BOOST_CHECK(tree.size() == t1.size()); std::vector output; t1.spatial_query(qbox, std::back_inserter(output)); test_exactly_the_same_outputs(t1, output, expected_output); // copying assignment operator t1 = tree; BOOST_CHECK(tree.empty() == t1.empty()); BOOST_CHECK(tree.size() == t1.size()); output.clear(); t1.spatial_query(qbox, std::back_inserter(output)); test_exactly_the_same_outputs(t1, output, expected_output); bgi::rtree t2(tree.parameters()); t2.swap(t1); BOOST_CHECK(tree.empty() == t2.empty()); BOOST_CHECK(tree.size() == t2.size()); BOOST_CHECK(true == t1.empty()); BOOST_CHECK(0 == t1.size()); output.clear(); t1.spatial_query(qbox, std::back_inserter(output)); BOOST_CHECK(output.empty()); output.clear(); t2.spatial_query(qbox, std::back_inserter(output)); test_exactly_the_same_outputs(t2, output, expected_output); t2.swap(t1); // moving constructor bgi::rtree t3(boost::move(t1)); BOOST_CHECK(t3.size() == s); BOOST_CHECK(t1.size() == 0); output.clear(); t3.spatial_query(qbox, std::back_inserter(output)); test_exactly_the_same_outputs(t3, output, expected_output); // moving assignment operator t1 = boost::move(t3); BOOST_CHECK(t1.size() == s); BOOST_CHECK(t3.size() == 0); output.clear(); t1.spatial_query(qbox, std::back_inserter(output)); test_exactly_the_same_outputs(t1, output, expected_output); //TODO - test SWAP } // rtree creation and insertion template void test_create_insert(bgi::rtree & tree, std::vector const& input, Box const& qbox) { typedef bgi::rtree T; std::vector expected_output; tree.spatial_query(qbox, std::back_inserter(expected_output)); { T t(tree.parameters()); BOOST_FOREACH(Value const& v, input) t.insert(v); BOOST_CHECK(tree.size() == t.size()); std::vector output; t.spatial_query(qbox, std::back_inserter(output)); test_exactly_the_same_outputs(t, output, expected_output); } { T t(tree.parameters()); std::copy(input.begin(), input.end(), bgi::inserter(t)); BOOST_CHECK(tree.size() == t.size()); std::vector output; t.spatial_query(qbox, std::back_inserter(output)); test_exactly_the_same_outputs(t, output, expected_output); } { T t(input.begin(), input.end(), tree.parameters()); BOOST_CHECK(tree.size() == t.size()); std::vector output; t.spatial_query(qbox, std::back_inserter(output)); test_exactly_the_same_outputs(t, output, expected_output); } { T t(input, tree.parameters()); BOOST_CHECK(tree.size() == t.size()); std::vector output; t.spatial_query(qbox, std::back_inserter(output)); test_exactly_the_same_outputs(t, output, expected_output); } { T t(tree.parameters()); t.insert(input.begin(), input.end()); BOOST_CHECK(tree.size() == t.size()); std::vector output; t.spatial_query(qbox, std::back_inserter(output)); test_exactly_the_same_outputs(t, output, expected_output); } { T t(tree.parameters()); t.insert(input); BOOST_CHECK(tree.size() == t.size()); std::vector output; t.spatial_query(qbox, std::back_inserter(output)); test_exactly_the_same_outputs(t, output, expected_output); } { T t(tree.parameters()); BOOST_FOREACH(Value const& v, input) bgi::insert(t, v); BOOST_CHECK(tree.size() == t.size()); std::vector output; bgi::spatial_query(t, qbox, std::back_inserter(output)); test_exactly_the_same_outputs(t, output, expected_output); } { T t(tree.parameters()); bgi::insert(t, input.begin(), input.end()); BOOST_CHECK(tree.size() == t.size()); std::vector output; bgi::spatial_query(t, qbox, std::back_inserter(output)); test_exactly_the_same_outputs(t, output, expected_output); } { T t(tree.parameters()); bgi::insert(t, input); BOOST_CHECK(tree.size() == t.size()); std::vector output; bgi::spatial_query(t, qbox, std::back_inserter(output)); test_exactly_the_same_outputs(t, output, expected_output); } } // rtree removing template void test_remove(bgi::rtree & tree, std::vector const& input, Box const& qbox) { typedef bgi::rtree T; std::vector values_to_remove; tree.spatial_query(qbox, std::back_inserter(values_to_remove)); BOOST_CHECK(0 < values_to_remove.size()); std::vector expected_output; tree.spatial_query(bgi::disjoint(qbox), std::back_inserter(expected_output)); { T t(tree); BOOST_FOREACH(Value const& v, values_to_remove) t.remove(v); std::vector output; t.spatial_query(bgi::disjoint(qbox), std::back_inserter(output)); BOOST_CHECK( output.size() == tree.size() - values_to_remove.size() ); test_compare_outputs(t, output, expected_output); } { T t(tree); t.remove(values_to_remove.begin(), values_to_remove.end()); std::vector output; t.spatial_query(bgi::disjoint(qbox), std::back_inserter(output)); BOOST_CHECK( output.size() == tree.size() - values_to_remove.size() ); test_compare_outputs(t, output, expected_output); } { T t(tree); t.remove(values_to_remove); std::vector output; t.spatial_query(bgi::disjoint(qbox), std::back_inserter(output)); BOOST_CHECK( output.size() == tree.size() - values_to_remove.size() ); test_compare_outputs(t, output, expected_output); } { T t(tree); BOOST_FOREACH(Value const& v, values_to_remove) bgi::remove(t, v); std::vector output; bgi::spatial_query(t, bgi::disjoint(qbox), std::back_inserter(output)); BOOST_CHECK( output.size() == tree.size() - values_to_remove.size() ); test_compare_outputs(t, output, expected_output); } { T t(tree); bgi::remove(t, values_to_remove.begin(), values_to_remove.end()); std::vector output; bgi::spatial_query(t, bgi::disjoint(qbox), std::back_inserter(output)); BOOST_CHECK( output.size() == tree.size() - values_to_remove.size() ); test_compare_outputs(t, output, expected_output); } { T t(tree); bgi::remove(t, values_to_remove); std::vector output; bgi::spatial_query(t, bgi::disjoint(qbox), std::back_inserter(output)); BOOST_CHECK( output.size() == tree.size() - values_to_remove.size() ); test_compare_outputs(t, output, expected_output); } } template void test_clear(bgi::rtree & tree, std::vector const& input, Box const& qbox) { typedef bgi::rtree T; std::vector values_to_remove; tree.spatial_query(qbox, std::back_inserter(values_to_remove)); BOOST_CHECK(0 < values_to_remove.size()); //clear { T t(tree); std::vector expected_output; t.spatial_query(bgi::intersects(qbox), std::back_inserter(expected_output)); size_t s = t.size(); t.clear(); BOOST_CHECK(t.empty()); BOOST_CHECK(t.size() == 0); t.insert(input); BOOST_CHECK(t.size() == s); std::vector output; t.spatial_query(bgi::intersects(qbox), std::back_inserter(output)); test_exactly_the_same_outputs(t, output, expected_output); } ////assign iterators //{ // T t(tree); // BOOST_CHECK(t.size() == tree.size()); // std::vector expected_output; // t.spatial_query(t.box(), std::back_inserter(expected_output)); // // std::vector values_to_remove; // t.spatial_query(bgi::intersects(qbox), std::back_inserter(values_to_remove)); // t.remove(values_to_remove); // // BOOST_CHECK(t.size() == tree.size() - values_to_remove.size()); // t.assign(input.begin(), input.end()); // BOOST_CHECK(t.size() == tree.size()); // std::vector output; // t.spatial_query(t.box(), std::back_inserter(output)); // test_exactly_the_same_outputs(t, output, expected_output); //} ////assign range //{ // T t(tree); // BOOST_CHECK(t.size() == tree.size()); // std::vector expected_output; // t.spatial_query(t.box(), std::back_inserter(expected_output)); // std::vector values_to_remove; // t.spatial_query(bgi::intersects(qbox), std::back_inserter(values_to_remove)); // t.remove(values_to_remove); // BOOST_CHECK(t.size() == tree.size() - values_to_remove.size()); // t.assign(input); // BOOST_CHECK(t.size() == tree.size()); // std::vector output; // t.spatial_query(t.box(), std::back_inserter(output)); // test_exactly_the_same_outputs(t, output, expected_output); //} } // run all tests for a single Algorithm and single rtree // defined by Value template void test_rtree_by_value(Parameters const& parameters) { typedef bgi::rtree Tree; typedef typename Tree::box_type B; // not empty tree test Tree tree(parameters); std::vector input; B qbox; generate_rtree(tree, input, qbox); test_intersects(tree, input, qbox); test_disjoint(tree, input, qbox); test_covered_by(tree, input, qbox); test_overlaps(tree, input, qbox); //test_touches(tree, input, qbox); test_within(tree, input, qbox); typedef typename bgi::traits::point_type::type P; P pt; bg::centroid(qbox, pt); test_nearest_query(tree, input, pt); test_nearest_query_k(tree, input, pt, 10); test_nearest_query_not_found(tree, generate_outside_point

::apply(), 1, 3); test_copy_assignment_swap_move(tree, qbox); test_create_insert(tree, input, qbox); test_remove(tree, input, qbox); test_clear(tree, input, qbox); // empty tree test Tree empty_tree(parameters); std::vector empty_input; test_intersects(empty_tree, empty_input, qbox); test_disjoint(empty_tree, empty_input, qbox); test_covered_by(empty_tree, empty_input, qbox); test_overlaps(empty_tree, empty_input, qbox); //test_touches(empty_tree, empty_input, qbox); test_within(empty_tree, empty_input, qbox); test_nearest_query(empty_tree, empty_input, pt); test_nearest_query_k(empty_tree, empty_input, pt, 10); test_nearest_query_not_found(empty_tree, generate_outside_point

::apply(), 1, 3); test_copy_assignment_swap_move(empty_tree, qbox); } // rtree inserting and removing of counting_value template void test_count_rtree_values(Parameters const& parameters) { typedef counting_value Value; typedef bgi::rtree Tree; typedef typename Tree::box_type B; Tree t(parameters); std::vector input; B qbox; generate_rtree(t, input, qbox); size_t rest_count = input.size(); BOOST_CHECK(t.size() + rest_count == Value::counter()); std::vector values_to_remove; t.spatial_query(qbox, std::back_inserter(values_to_remove)); rest_count += values_to_remove.size(); BOOST_CHECK(t.size() + rest_count == Value::counter()); size_t values_count = Value::counter(); BOOST_FOREACH(Value const& v, values_to_remove) { t.remove(v); --values_count; BOOST_CHECK(Value::counter() == values_count); BOOST_CHECK(t.size() + rest_count == values_count); } } // rtree count template void test_rtree_count(Parameters const& parameters) { typedef std::pair Value; typedef bgi::rtree Tree; typedef typename Tree::box_type B; Tree t(parameters); std::vector input; B qbox; generate_rtree(t, input, qbox); BOOST_CHECK(t.count(input[0]) == 1); BOOST_CHECK(t.count(input[0].first) == 1); t.insert(input[0]); BOOST_CHECK(t.count(input[0]) == 2); BOOST_CHECK(t.count(input[0].first) == 2); t.insert(std::make_pair(input[0].first, -1)); BOOST_CHECK(t.count(input[0]) == 2); BOOST_CHECK(t.count(input[0].first) == 3); } // run all tests for one Algorithm for some number of rtrees // defined by some number of Values constructed from given Point template void test_rtree_for_point(Parameters const& parameters = Parameters()) { typedef std::pair PairP; typedef boost::tuple TupleP; typedef boost::shared_ptr< test_object > SharedPtrP; typedef value_no_dctor VNoDCtor; test_rtree_by_value(parameters); test_rtree_by_value(parameters); test_rtree_by_value(parameters); test_rtree_by_value(parameters); test_rtree_by_value(parameters); test_count_rtree_values(parameters); test_rtree_count(parameters); } template void test_rtree_for_box(Parameters const& parameters = Parameters()) { typedef bg::model::box Box; typedef std::pair PairB; typedef boost::tuple TupleB; typedef value_no_dctor VNoDCtor; test_rtree_by_value(parameters); test_rtree_by_value(parameters); test_rtree_by_value(parameters); test_rtree_by_value(parameters); test_count_rtree_values(parameters); test_rtree_count(parameters); } #endif