Boost R-tree:计算满足查询的元素

时间:2015-03-25 16:44:33

标签: c++ boost r-tree boost-geometry

到目前为止,当我想要计算我的R树中有多少元素满足特定空间查询时,它归结为运行查询,收集匹配然后计算它们,大致如下:

std::vector<my_type> results;
rtree_ptr->query(bgi::intersects(query_box), std::back_inserter(results));
int nbElements = results.size();

有没有更好的方法,即直接计算而不检索实际元素的方法?我没有找到任何可以做到的但是谁知道。 (我正在使用打包算法构建我的树,以防它有任何相关性。)

我的动机是我注意到我的查询速度取决于匹配的数量。如果有0个匹配,则查询或多或少是即时的;如果有10 000场比赛,则需要几秒钟。由于可以非常快速地确定是否存在任何匹配,因此遍历树的速度非常快(至少在我制作的索引中);它正在收集所有结果,以便在多次匹配时使查询变慢。由于我对收集不感兴趣,只是简单地计算(至少对于某些查询而言),如果我可以跳过收集,那就太棒了。

2 个答案:

答案 0 :(得分:3)

您可以使用函数输出迭代器:

size_t cardinality = 0; // number of matches in set
auto count_only = boost::make_function_output_iterator([&cardinality] (Tree::value_type const&) { ++cardinality; });

像这样使用:

使用lambda

的C ++ 11

<强> Live On Coliru

#include <boost/function_output_iterator.hpp>
#include <boost/geometry/geometries/box.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/index/rtree.hpp>

namespace bgi = boost::geometry::index;
using point = boost::geometry::model::d2::point_xy<int, boost::geometry::cs::cartesian>;
using box = boost::geometry::model::box<point>;

int main()
{
    using Tree = bgi::rtree<box, bgi::rstar<32> >;
    Tree tree;

    size_t cardinality = 0; // number of matches in set
    auto count_only = boost::make_function_output_iterator([&cardinality] (Tree::value_type const&) { ++cardinality; });

    box query_box;
    tree.query(bgi::intersects(query_box), count_only);

    int nbElements = cardinality;

    return nbElements;
}

C ++ 03使用函数对象

对于C ++,您可以将lambda替换为(多态!)函数对象:

struct count_only_f {
    count_only_f(size_t& card) : _cardinality(&card) { }

    template <typename X>
    void operator()(X) const {
        ++(*_cardinality);
    }

  private:
    size_t *_cardinality;
};

// .... later:
boost::function_output_iterator<count_only_f> count_only(cardinality);

C ++ 03使用Boost Phoenix

我认为这是使用Boost Phoenix的好地方:

#include <boost/phoenix.hpp>
// ...

size_t cardinality = 0; // number of matches in set
tree.query(bgi::intersects(query_box), boost::make_function_output_iterator(++boost::phoenix::ref(cardinality)));

或者,通常使用命名空间别名:

#include <boost/phoenix.hpp>
// ...

size_t cardinality = 0; // number of matches in set
tree.query(bgi::intersects(query_box), make_function_output_iterator(++phx::ref(cardinality)));

答案 1 :(得分:2)

我有一个晚脑电波。比使用function_output_iterator更好的方法是使用boost::geometry::index query_iterators。

原则上,它会通过稍微简单的代码导致完全相同的行为:

box query_box;
auto r = boost::make_iterator_range(bgi::qbegin(tree, bgi::intersects(query_box)), {});
// in c++03, spell out the end iterator: bgi::qend(tree)

size_t nbElements = boost::distance(r);
  

注意size()不可用,因为query_const_iterator不属于随机访问类别。

但结合可能稍微舒服一点。比如,如果您想要对每个项目进行额外检查,则可以使用标准库算法,如:

size_t matching = std::count_if(r.begin(), r.end(), some_predicate);

我认为基于范围的解决方案更灵活一些(相同的代码可用于实现其他算法,如partial_sort_copystd::transform,这些算法难以适应输出 - 迭代器的习惯用法。我的earlier answer)。