我试图了解如何实现一个R-Tree,它将用于“选择”包含在边界矩形中的一组几何对象。我查看了维基百科上的article,其中显示了数据布局的示例B-Tree。
我可以编写B-Tree并用它来编写R-Tree,但这些是两个复杂的数据结构,我必须调试,测试等等。我宁愿重用现有的树实现(std :: set / multiset)并提供排序操作。
假设我的Shapes有以下界面:
class Shape
{
public:
Shape();
virtual ~Shape();
const AABB & bounding_box() const = 0;
};
并提供此仿函数来订购Shapes:
struct OrderShapes
{
bool operator()(Shape * const & left, Shape * const & right) const
{
return right->bounding_box().contains(left->bounding_box());
}
};
std::set<Shape *, OrderShapes>
会表现为有效的R树吗?
如果没有,如何在不重新发明轮子的情况下解决这个问题?
答案 0 :(得分:11)
您也可以使用Boost.Geometry库:
http://www.boost.org/doc/libs/release/libs/geometry/doc/html/index.html
如果您想使用自己的Point和AABB类型,则应将它们调整为Point和Box概念,以告知Boost.Geometry库如何处理这些类型。例如。请参阅以下页面:
否则你可以使用预定义的。
假设你想在rtree中存储指针(我将使用boost :: shared_ptr),代码可能如下所示:
#include <boost/geometry.hpp>
#include <boost/geometry/index/rtree.hpp>
#include <boost/foreach.hpp>
#include <vector>
namespace bg = boost::geometry;
namespace bgi = boost::geometry::index;
namespace bgm = boost::geometry::model;
/* The registration of your Point and Box types goes here */
// OR use predefined ones
typedef bgm::point<float, 2, bg::cs::cartesian> Point;
typedef bgm::box<Point> AABB;
class Shape
{
public:
Shape() {}
virtual ~Shape() {}
const AABB & bounding_box() const { return m_aabb; }
private:
AABB m_aabb;
};
// Tell the rtree how to extract the AABB from the Shape
namespace boost { namespace geometry { namespace index {
template <>
struct indexable< boost::shared_ptr<Shape> >
{
typedef boost::shared_ptr<Shape> V;
typedef AABB const& result_type;
result_type operator()(V const& v) const { return v->bounding_box(); }
};
}}} // namespace boost::geometry::index
int main()
{
// The rtree
bgi::rtree< boost::shared_ptr<Shape>, bgi::rstar<32> > rt;
// Store some shapes
rt.insert(boost::shared_ptr<Shape>(new Shape()));
rt.insert(boost::shared_ptr<Shape>(new Shape()));
rt.insert(boost::shared_ptr<Shape>(new Shape()));
/*...*/
// Search for some shapes
std::vector<boost::shared_ptr<Shape> > query_result;
rt.query(bgi::intersects(AABB(/*...*/)), std::back_inserter(query_result));
BOOST_FOREACH(boost::shared_ptr<Shape> & s, query_result)
{
/* Do something with each shape */
/* but don't modify the AABB if the Shape is stored in the rtree! */
}
// Remove them from the rtree
BOOST_FOREACH(boost::shared_ptr<Shape> & s, query_result)
{
rt.remove(s);
}
return 0;
}
请记住,因为AABB是Shape的属性,并且我们存储指针,所以可以从rtree空间索引的外部修改AABB。当Value存储在索引或容器中时,不应修改用作Key的数据。
如果您不想将AABB存储在Shape中或/并提高rtree安全性,您可以存储例如:的std ::对&LT; AABB,boost :: shared_ptr&gt;。您将无法从索引外部修改用于索引的AABB。在这种情况下,你不会专门化bgi :: indexable&lt;&gt;因为rtree默认知道如何处理std :: pair&lt; Box,...&gt;类型。这看起来像这样:
// The value type
typedef std::pair<AABB, boost::shared_ptr<Shape> > MyVal;
// The rtree
bgi::rtree<MyVal, bgi::rstar<32> > rt;
// Store a shape
boost::shared_ptr<Shape> s(new Shape());
rt.insert(std::make_pair(s->calculate_aabb(), s));
/* The rest of the code */
答案 1 :(得分:3)
R-Trees 不是B-Trees 。它们确实有一些共同点,但可能不会超过任何其他面向块(=磁盘优化)的树数据结构。
恕我直言,首先实现B树有两个好处:A)经验,B)获得稳定的快速块I / O API。
R-Trees的主要难点是而不是查询。他们几乎可以直接查询。挑战在于如何有效地修改树,即删除元素和添加元素,同时保持树平衡。在一维数据集中 - 即在B + -tree中 - 这相当容易,因为您有一个可用于平衡的唯一邻居。这不再适用于高维数据。
但你当然可以寻找现有的R-tree库,例如libspatialindex
P.S。要查询R树,您需要overlaps
,而不是contains
。
答案 2 :(得分:2)
std :: set表现为有效的R-Tree?
绝对没有。 STL甚至不包含B树实现。 std :: set只是一棵红黑树,而不是B树。
如何在不重新发明轮子的情况下解决这个问题?