无法通过索引从 boost::geometry::index::rtree 中删除元素

Jep*_*sen 4 c++ boost r-tree boost-geometry

我正在创建一个boost geometry rtree

从我创建的示例页面:

typedef bg::model::point<float, 2, bg::cs::cartesian> point;
typedef bg::model::box<point> box;
typedef std::pair<box, unsigned> value;
Run Code Online (Sandbox Code Playgroud)

我想向value树中添加元素:

bgi::rtree< value, bgi::quadratic<16> > rtree;
box b(point(2.0f, 2.0f), point(2.5f, 2.5f));
// insert new value
rtree.insert(std::make_pair(b, 2));
Run Code Online (Sandbox Code Playgroud)

现在我想知道是否可以通过知道box标识符(或者它的所有元素,如果可以设置更多具有相同 id 的元素)来删除元素。

我想要做的是删除我在上面添加的元素,例如调用以下内容:

rtree.remove(2); // why I can't do this?
Run Code Online (Sandbox Code Playgroud)

我怎样才能做到这一点?

seh*_*ehe 5

您将不得不使用迭代器。可能的重载是

remove(value_type const &)
remove(Iterator, Iterator)
remove(ConvertibleOrRange const &)
Run Code Online (Sandbox Code Playgroud)

首先,您应该通过搜索找到要删除的值(可能会运行查询,但我认为您不需要那个,因为您的问题不存在。)

因此,您可能想要使用std::find_if. 我不确定如何提高性能(不求助于反向映射)。我想您的分析器应该用于在那里提供保证。

更新:概念证明

天真的方法失败了:

// UNDEFINED BEHAVIOUR:
template <typename Rtree, typename Id>
size_t remove_ids_loop(Rtree& rtree, Id const& id) {
    using V = typename Rtree::value_type;
    static_assert(sizeof(V) == 0, "don't use; UNDEFINED BEHAVIOUR!");

    size_t removed = 0;
    std::for_each(rtree.begin(), rtree.end(), [&](V const& v) { 
            if (id == v.second)
                removed += rtree.remove(v);
        });

    return removed;
}
Run Code Online (Sandbox Code Playgroud)

这是因为如文档所示

? 警告

rtree 的修改可能会使迭代器失效。

简单的方法:

template <typename Rtree, typename Id>
size_t remove_ids_bulk(Rtree& rtree, Id const& id) {
    using V = typename Rtree::value_type;
    std::vector<V> v;
    std::copy_if(rtree.begin(), rtree.end(), back_inserter(v), [id](V const& v) { return v.second == id; });

    return rtree.remove(v.begin(), v.end());
}
Run Code Online (Sandbox Code Playgroud)

这通过将查询与删除分开来避免竞争。请注意,这可能更有效,因为我们一次通过了整个范围。

注意:对于重复的条目,这应该没问题,因为一次rtree::remove只删除一个值。

现场演示

Live On Coliru

#include <boost/geometry.hpp>
#include <boost/geometry/index/rtree.hpp>

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

typedef bg::model::point<float, 2, bg::cs::cartesian> point;
typedef bg::model::box<point> box;

typedef std::pair<box, unsigned> value;

template <typename Rtree, typename Id>
size_t remove_ids_bulk(Rtree& rtree, Id const& id) {
    using V = typename Rtree::value_type;
    std::vector<V> v;
    std::copy_if(rtree.begin(), rtree.end(), back_inserter(v), [id](V const& v) { return v.second == id; });

    return rtree.remove(v.begin(), v.end());
}

// UNDEFINED BEHAVIOUR:
template <typename Rtree, typename Id>
size_t remove_ids_loop(Rtree& rtree, Id const& id) {
    using V = typename Rtree::value_type;
    static_assert(sizeof(V) == 0, "don't use; UNDEFINED BEHAVIOUR!");

    size_t removed = 0;
    std::for_each(rtree.begin(), rtree.end(), [&](V const& v) { 
            if (id == v.second)
                removed += rtree.remove(v);
        });

    return removed;
}

int main() {
    //I want to add value elements to the tree:

    bgi::rtree< value, bgi::quadratic<16> > rtree;
    box b(point(2.0f, 2.0f), point(2.5f, 2.5f));
    // insert new value
    rtree.insert(std::make_pair(b, 2));
    std::cout << "Elements: " << rtree.size() << "\n";

    // remove id 2
    remove_ids_bulk(rtree, 2u);
    std::cout << "Elements: " << rtree.size() << "\n";
}
Run Code Online (Sandbox Code Playgroud)

印刷

Elements: 1
Elements: 0
Run Code Online (Sandbox Code Playgroud)