C++ 我是否需要遍历boost rtree的层次结构以实现最大效率?

C++ 我是否需要遍历boost rtree的层次结构以实现最大效率?,c++,optimization,boost,boost-geometry,r-tree,C++,Optimization,Boost,Boost Geometry,R Tree,经过一番阅读,我了解到boostrtree中并不正式支持层次遍历(尽管可能)。我有几个不同的用例,我可以在没有层次遍历的情况下进行管理,但我不确定效率。因此,我正在就boost rtree如何在内部工作以及这些用例的最佳实践寻求建议 案例1-我有两棵树,我想过滤这两棵树中与另一棵树中至少一个元素相交的元素。我有下面的代码来实现这一点,并给出我想要的结果: std::set<int> results2; std::vector<rtree3d_item> t

经过一番阅读,我了解到boostrtree中并不正式支持层次遍历(尽管可能)。我有几个不同的用例,我可以在没有层次遍历的情况下进行管理,但我不确定效率。因此,我正在就boost rtree如何在内部工作以及这些用例的最佳实践寻求建议

案例1-我有两棵树,我想过滤这两棵树中与另一棵树中至少一个元素相交的元素。我有下面的代码来实现这一点,并给出我想要的结果:

    std::set<int> results2;
    std::vector<rtree3d_item> tempResults, results1;
    std::vector<rtree3d_item>::iterator it;
    tree1->query(bgi::satisfies(
        [&](const rtree3d_item& item) {
            tempResults.clear();
            tree2->query(bgi::intersects(item.first), std::back_inserter(tempResults));
            for (it = tempResults.begin(); it < tempResults.end(); it++)
            {
                results2.insert(it->second);
            }
            return tempResults.size() > 0;
        }
    ), std::back_inserter(results1));
对于内部rtree的每个叶节点,该表达式运行一次,这似乎又是一种浪费。如果我对父节点进行此测试,我可以一次性排除几个叶节点

似乎每当我测试rtree是否满足条件时,我都会遇到相同的情况-(如果boundinbox不满足条件,则其中包含的任何boundingbox也将不满足条件)。我的意思是,如果我要一直测试所有叶节点,那么拥有一个“树”结构有什么意义呢?为什么boost不正式支持遍历树的层次结构

我找到了一个关于不受支持的非官方方法()的源代码,但我想尝试官方的、受支持的方法来优化我的代码

FYI,我在C++中的经验有限,所以欢迎所有的建议,谢谢!p> 为什么boost不正式支持遍历树的层次结构

猜测:

  • 他们正在用一个s友好的API实现高级原语。在文档化的接口中不包含较低的级别,这样可以更灵活地迭代这些接口的设计,而不会给库的用户带来麻烦。因此,最终结果将严格地说是更好、更低级的接口,一旦稳定下来,这些接口就可以被记录下来

  • 遍历的语义与平衡/结构策略密切相关。这意味着在所有情况下都很难理解/记录遍历顺序的含义,这可能是错误的来源。没有文档记录会向用户发出这一信号(他们可以使用它,但风险自负)


案例1 同意。我想说,你最好在第一棵树上做一个BFS,然后查询与第二棵树的交点。通过这种方式,您可以快速删除树(子树)中不感兴趣的“部分”

根据代码,我提出了一个粗略的、最少的访问者:

namespace rtree = bgi::detail::rtree;

template <typename Predicate, typename Value, typename Options, typename Box, typename Allocators>
struct BFSQuery : public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, true>::type
{
    typedef typename rtree::internal_node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node;
    typedef typename rtree::leaf<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type leaf;

    inline BFSQuery(Predicate const& p) : pr(p) {}

    inline void operator()(internal_node const& n) {
        for (auto&& [bounds, node] : rtree::elements(n))
            if (pr(bounds))
                rtree::apply_visitor(*this, *node);
    }

    inline void operator()(leaf const& n) {
        for (auto& item : rtree::elements(n))
            if (pr(item)) results.insert(&item);
    }

    Predicate const& pr;

    std::set<Value const*> results;
};
案例2 我认为您可以通过标准查询谓词实现这一点:

for (auto& value : boost::make_iterator_range(bgi::qbegin(a, bgi::intersects(sphere)), {})) {
    std::cout << "intersects: " << bg::dsv(value) << "\n";
}

欢迎您链接这些“外部来源”。当yoursI添加链接时,它们将对回答问题的人以及遇到类似问题的人非常有帮助。感谢您提供如此详细的答案!帮助很大!后续问题-对于案例2,您创建的球体是一个具有4个点(正方形)的多边形,对吗?但这不会给我和检查实际球体(或2d中的圆)相同的结果。或者我遗漏了什么?我没有心情做一个更好的球体近似(花太多时间阅读文档)。您可以通过提供代码来防止这种“不匹配”,这样我就可以复制/粘贴了。我并没有将球体近似为多边形/多面体。在我的例子中,我实际上必须在没有任何近似的情况下检查球体,所以我使用boost:geometry::distance函数来检查一个框是否在半径范围内。因为近似对我来说不是一个真正的选项,所以我也将对球体查询使用相同的BFS策略。谢谢你可以用包围盒的方法剔除错误的假设
template <typename TreeA, typename TreeB, typename F>
void tree_insersects(TreeA const& a, TreeB const& b, F action) {
    using V = rtree::utilities::view<TreeA>;
    V av(a);

    auto const pred = [&b](auto const& bounds) {
        return bgi::qbegin(b, bgi::intersects(bounds)) != bgi::qend(b);
    };

    BFSQuery<
      decltype(pred),
      typename V::value_type,
      typename V::options_type,
      typename V::box_type,
      typename V::allocators_type
    > vis(pred);

    av.apply_visitor(vis);

    auto tr = av.translator();
    for (auto* hit : vis.results)
        action(tr(*hit));
}
int main() {
    using Box = bg::model::box<bg::model::d2::point_xy<int> >;

    // generate some boxes with nesting
    bgi::rtree<Box, bgi::rstar<5>> a;
    for (auto [k,l] : { std::pair(0, 1), std::pair(-1, 2) }) {
        std::generate_n(bgi::insert_iterator(a), 10,
            [k,l,i=1]() mutable { Box b{ {i+k,i+k}, {i+l,i+l} }; i+=2; return b; });
    }

    // another simple tree to intersect with
    bgi::rtree<Box, bgi::quadratic<16> > b;
    b.insert({ {9,9}, {12,12} });
    b.insert({ {-9,-9}, {1,2} });

    Demo::tree_insersects(a, b, [](auto& value) {
        std::cout << "intersects: " << bg::dsv(value) << "\n";
    });
}
intersects: ((1, 1), (2, 2))
intersects: ((0, 0), (3, 3))
intersects: ((11, 11), (12, 12))
intersects: ((10, 10), (13, 13))
intersects: ((12, 12), (15, 15))
intersects: ((6, 6), (9, 9))
intersects: ((8, 8), (11, 11))
intersects: ((9, 9), (10, 10))
for (auto& value : boost::make_iterator_range(bgi::qbegin(a, bgi::intersects(sphere)), {})) {
    std::cout << "intersects: " << bg::dsv(value) << "\n";
}
#include <boost/geometry/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/index/rtree.hpp>
#include <boost/geometry/index/detail/utilities.hpp>
#include <boost/geometry/index/predicates.hpp>
#include <iostream>

namespace bg = boost::geometry;
namespace bgi = bg::index;

namespace Demo {
    namespace rtree = bgi::detail::rtree;

    template <typename Predicate, typename Value, typename Options, typename Box, typename Allocators>
    struct BFSQuery : public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, true>::type
    {
        typedef typename rtree::internal_node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node;
        typedef typename rtree::leaf<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type leaf;

        inline BFSQuery(Predicate const& p) : pr(p) {}

        inline void operator()(internal_node const& n) {
            for (auto&& [bounds, node] : rtree::elements(n)) {
                if (pr(bounds))
                    rtree::apply_visitor(*this, *node);
            }
        }

        inline void operator()(leaf const& n) {
            for (auto& item : rtree::elements(n))
                if (pr(item)) results.insert(&item);
        }

        Predicate const& pr;

        std::set<Value const*> results;
    };

    template <typename TreeA, typename TreeB, typename F> void tree_insersects(TreeA const& a, TreeB const& b, F action) {
        using V = rtree::utilities::view<TreeA>;
        V av(a);

        auto const pred = [&b](auto const& bounds) {
            return bgi::qbegin(b, bgi::intersects(bounds)) != bgi::qend(b);
        };

        BFSQuery<
          decltype(pred),
          typename V::value_type,
          typename V::options_type,
          typename V::box_type,
          typename V::allocators_type
        > vis(pred);

        av.apply_visitor(vis);

        auto tr = av.translator();
        for (auto* hit : vis.results)
            action(tr(*hit));
    }
}

int main() {
    using Box = bg::model::box<bg::model::d2::point_xy<int> >;

    // generate some boxes with nesting
    bgi::rtree<Box, bgi::rstar<5>> a;
    for (auto [k,l] : { std::pair(0, 1), std::pair(-1, 2) }) {
        std::generate_n(bgi::insert_iterator(a), 10,
            [k,l,i=1]() mutable { Box b{ {i+k,i+k}, {i+l,i+l} }; i+=2; return b; });
    }

    // another simple tree to intersect with
    bgi::rtree<Box, bgi::quadratic<16> > b;
    b.insert({ {9,9}, {12,12} });
    b.insert({ {-9,-9}, {1,2} });

    Demo::tree_insersects(a, b, [](auto& value) {
        std::cout << "intersects: " << bg::dsv(value) << "\n";
    });
}