从 boost::geometry::index::rtree 中删除点的问题

Posted

技术标签:

【中文标题】从 boost::geometry::index::rtree 中删除点的问题【英文标题】:Issue with removing points from a boost::geometry::index::rtree 【发布时间】:2014-12-23 02:20:36 【问题描述】:

我在 OS X 上使用 boost 1.56,通过自制软件安装。

我遇到了编译问题 - 具体来说,我似乎无法从 boost::geometry::index::rtree 中删除值。

这是我到目前为止提出的代码:

#include <iostream>
#include <vector>
#include <string>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point.hpp>
#include <boost/geometry/geometries/box.hpp>
#include <boost/geometry/index/rtree.hpp>

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

typedef bgm::point<float, 2, bg::cs::spherical_equatorial<bg::degree> > Point;
typedef bgm::box<Point> Box;
typedef std::pair<Box, int> BoxIdPair;

int main(int argc, char** argv) 
  bgi::rtree<BoxIdPair, bgi::rstar<16>> tree;
  // Some tree filling code excised from here for the sake of a minimal example.
  BoxIdPair b1 = std::make_pair(Box(Point(24, 19), Point(35, 26)), 100);
  BoxIdPair b2 = std::make_pair(Box(Point(41, 112), Point(54, 148)), 150);
  BoxIdPair b3 = std::make_pair(Box(Point(34, 24), Point(36, 100)), 92);
  BoxIdPair b4 = std::make_pair(Box(Point(21, 8), Point(43, 15)), 8);
  tree.insert(b1);
  tree.insert(b2);
  tree.insert(b3);
  tree.insert(b4);
  while (!tree.empty()) 
    std::cout << "Tree contains " << tree.size() << "box-id values." << std::endl;
    // 1. Choose arbitrary BoxIdPair to be the leader of a new canopy.
    //    Remove it from the tree. Insert it into the canopy map, with its corresponding id.
    Point origin(0.0, 0.0);
    std::vector<BoxIdPair> result_set;
    tree.query(bgi::nearest(origin, 1), std::back_inserter(result_set));
    Box b = result_set[0].first;
    int id = result_set[0].second;
    tree.remove(result_set[0]); // This is the line that is giving me difficulty, I think.

    // Additional code cut for minimal example
  

此代码无法编译! 具体来说,这里是调用:

clang++ -g -std=c++11 -L/usr/local/Cellar/boost/1.56.0/lib -I/usr/local/Cellar/boost/1.56.0/include test.cc -o test

以下是编译器发出的错误(为简洁起见,链接到 pastebin): http://pastebin.com/d7E0A4Ee

三个相关的错误是:

test.cc:71:10: note: in instantiation of member function 'boost::geometry::index::rtree<std::__1::pair<boost::geometry::model::box<boost::geometry::model::point<float, 2,
      boost::geometry::cs::spherical_equatorial<boost::geometry::degree> > >, int>, boost::geometry::index::rstar<16, 4, 4, 32>,
      boost::geometry::index::indexable<std::__1::pair<boost::geometry::model::box<boost::geometry::model::point<float, 2, boost::geometry::cs::spherical_equatorial<boost::geometry::degree> > >, int> >,
      boost::geometry::index::equal_to<std::__1::pair<boost::geometry::model::box<boost::geometry::model::point<float, 2, boost::geometry::cs::spherical_equatorial<boost::geometry::degree> > >, int> >,
      std::__1::allocator<std::__1::pair<boost::geometry::model::box<boost::geometry::model::point<float, 2, boost::geometry::cs::spherical_equatorial<boost::geometry::degree> > >, int> > >::remove' requested here
tree.remove(result_set[0]);
     ^
/usr/local/Cellar/boost/1.56.0/include/boost/geometry/strategies/concepts/within_concept.hpp:183:21: note: candidate template ignored: couldn't infer template argument 'ApplyMethod'
    static void apply(ApplyMethod const&)

^

test.cc:71:10: note: in instantiation of member function 'boost::geometry::index::rtree<std::__1::pair<boost::geometry::model::box<boost::geometry::model::point<float, 2,
  boost::geometry::cs::spherical_equatorial<boost::geometry::degree> > >, int>, boost::geometry::index::rstar<16, 4, 4, 32>,
      boost::geometry::index::indexable<std::__1::pair<boost::geometry::model::box<boost::geometry::model::point<float, 2, boost::geometry::cs::spherical_equatorial<boost::geometry::degree> > >, int> >,
      boost::geometry::index::equal_to<std::__1::pair<boost::geometry::model::box<boost::geometry::model::point<float, 2, boost::geometry::cs::spherical_equatorial<boost::geometry::degree> > >, int> >,
      std::__1::allocator<std::__1::pair<boost::geometry::model::box<boost::geometry::model::point<float, 2, boost::geometry::cs::spherical_equatorial<boost::geometry::degree> > >, int> > >::remove' requested here
tree.remove(result_set[0]);
     ^
/usr/local/Cellar/boost/1.56.0/include/boost/mpl/assert.hpp:83:5: note: candidate function [with C = false] not viable: no known conversion from 'boost::mpl::failed
  ************(boost::geometry::nyi::not_implemented_error<boost::geometry::info::BOX, boost::geometry::info::BOX, void>::THIS_OPERATION_IS_NOT_OR_NOT_YET_IMPLEMENTED::************)(types<boost::geometry::info::BOX,
  boost::geometry::info::BOX, void>)' to 'typename assert<false>::type' (aka 'mpl_::assert<false>') for 1st argument
int assertion_failed( typename assert<C>::type );

^

test.cc:71:10: note: in instantiation of member function 'boost::geometry::index::rtree<std::__1::pair<boost::geometry::model::box<boost::geometry::model::point<float, 2,
  boost::geometry::cs::spherical_equatorial<boost::geometry::degree> > >, int>,   boost::geometry::index::rstar<16, 4, 4, 32>,
      boost::geometry::index::indexable<std::__1::pair<boost::geometry::model::box<boost::geometry::model::point<float, 2, boost::geometry::cs::spherical_equatorial<boost::geometry::degree> > >, int> >,
  boost::geometry::index::equal_to<std::__1::pair<boost::geometry::model::box<boost::geometry::model::point<float, 2, boost::geometry::cs::spherical_equatorial<boost::geometry::degree> > >, int> >,
  std::__1::allocator<std::__1::pair<boost::geometry::model::box<boost::geometry::model::point<float, 2, boost::geometry::cs::spherical_equatorial<boost::geometry::degree> > >, int> > >::remove' requested here
tree.remove(result_set[0]);
     ^
/usr/local/Cellar/boost/1.56.0/include/boost/geometry/algorithms/detail/relate/relate.hpp:282:1: note: candidate template ignored: substitution failure [with MatrixOrMask =
  boost::mpl::vector<boost::geometry::detail::relate::static_mask<'T', '*', 'F', '*', '*', 'F', '*', '*', '*'>, boost::geometry::detail::relate::static_mask<'*', 'T', 'F', '*', '*', 'F', '*', '*', '*'>,
  boost::geometry::detail::relate::static_mask<'*', '*', 'F', 'T', '*', 'F', '*', '*', '*'>, boost::geometry::detail::relate::static_mask<'*', '*', 'F', '*', 'T', 'F', '*', '*', '*'>, mpl_::na, mpl_::na, mpl_::na, mpl_::na,
  mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na>, Geometry1 = boost::geometry::model::box<boost::geometry::model::point<float, 2,
  boost::geometry::cs::spherical_equatorial<boost::geometry::degree> > >, Geometry2 = boost::geometry::model::box<boost::geometry::model::point<float, 2, boost::geometry::cs::spherical_equatorial<boost::geometry::degree> >
  >]
relate(Geometry1 const& geometry1,
^

有人对可能出了什么问题有想法吗?我很困惑。

【问题讨论】:

【参考方案1】:

我查看了您的代码,看起来还不错。您只是遇到了所选坐标系的限制,您的坐标还没有得到完全支持。

您可以通过更改坐标来验证这一点(这会使数据有点滑稽,但这里是关于编译成功)。请参阅此测试程序,该程序显示了删除项目的不同等效方法:

Live On Coliru

#include <iostream>
#include <vector>
#include <string>
#include <boost/geometry.hpp>
#include <boost/geometry/io/io.hpp>
#include <boost/geometry/geometries/box.hpp>
#include <boost/geometry/geometries/point.hpp>
#include <boost/geometry/index/distance_predicates.hpp>
#include <boost/geometry/index/predicates.hpp>
#include <boost/geometry/index/rtree.hpp>

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

//typedef bgm::point<float, 2, bg::cs::spherical_equatorial<bg::degree> > Point;
typedef bgm::point<float, 2, bg::cs::cartesian> Point;
typedef bgm::box<Point> Box;
typedef std::pair<Box, int> BoxIdPair;

int main() 
    using Tree = bgi::rtree<BoxIdPair, bgi::rstar<16> >;
    Tree tree;

    // Some tree filling code excised from here for the sake of a minimal example.
    tree.insert(  Point(24,  19), Point(35,  26) , 100 );
    tree.insert(  Point(41, 112), Point(54, 148) , 150 );
    tree.insert(  Point(34,  24), Point(36, 100) ,  92 );
    tree.insert(  Point(21,   8), Point(43,  15) ,   8 );

    while (!tree.empty()) 
        std::cout << "Tree contains " << tree.size() << " box-id values." << std::endl;
        // 1. Choose arbitrary BoxIdPair to be the leader of a new canopy.
        //    Remove it from the tree. Insert it into the canopy map, with its
        //    corresponding id.
        Point origin(0.0, 0.0);

        auto first = bgi::qbegin(tree, bgi::nearest(origin, 1)), 
             last  = bgi::qend(tree);

        if (first != last) 
            tree.remove(*first); // assuming single result
        
    
    std::cout << "Tree emptied\n";

注意不要将基于迭代器的remove() 与迭代器使用到同一个rtree,因为remove() 可能会使它们无效。

注意所有remove() 重载最终都会在内部推迟到raw_remove

我不完全确定它为什么不起作用。似乎没有为这种特定的几何组合定义确定索引操作是否为interruptible 的特征。

更新感谢 Adam 在下面的评论,我们知道这是因为在内部使用 within() 来决定在树遍历期间应该检查哪个节点。而within(box, box) 目前还没有针对非笛卡尔坐标系实现。

【讨论】:

这个限制似乎有点武断,特别是因为在这种情况下它只适用于remove。这是您在开发邮件列表中询问时可以使用的一个最小示例:coliru.stacked-crooked.com/a/f8417a454c645642 另请注意,当使用nearest 谓词时,您将按距离增加的顺序获得匹配项,因此您可以通过查询一次而不是重复查询一个项目中的一项来提高效率环形;请参阅 nearest neighbors using a circle,尤其是库开发人员的 cmets。 上述代码存在严重问题。 remove() 可能会使迭代器无效!顺便说一句,这就是为什么它被称为remove(),而不是erase()。但我明白为什么这样做似乎很明显。我想,如果传递了 rtree 迭代器,编译可能会失败,或者如果为同一个 rtree 对象创建迭代器,则运行时断言可能会失败。但是,如果迭代器被包装在其他类型的迭代器(Boost.Range 适配器)中,问题仍然存在。 非常清楚。该函数被称为remove(),因为应该将一个值或一系列不属于 rtree 索引的值传递给它。 STL 的erase() 接受一个指向容器元素的迭代器。 顺便说一句,remove() 不能编译在spherical_equatorial CS 中定义的框,因为内部within() 用于决定在树遍历期间应该检查哪个节点。而within(box, box) 目前还没有针对非笛卡尔坐标系实现。

以上是关于从 boost::geometry::index::rtree 中删除点的问题的主要内容,如果未能解决你的问题,请参考以下文章

我可以在线程中使用 Boost.Geometry.index.rtree 吗?

在将元素插入 boost::geometry::index::rtree 时获取“可索引无效”

R-trees 上的多级查询(交集、联合)

从 NIB 与从代码加载自定义滑块:从代码加载时不存在子视图

如何从其他面板从 JTextField 获取输入

从PRISM开始学WPFMVVMViewModel?