boost::geometry::Index::rtree

473 阅读5分钟

boost::geometry::Index::rtree


Boost::Geometry扩展

Boost::Geometry 包含可实例化的几何类,但库用户也可以使用自己的几何类。使用注册宏或特征类,可以调整它们的几何形状来实现 Boost::Geometry 概念。 Boost::Geometry 可用于几何发挥作用的所有领域:地图和 GIS、游戏开发、计算机图形和小部件、机器人、天文学等。核心被设计为尽可能通用并支持这些领域。目前,开发主要以 GIS 为主

  • 编译要求

    c++ 14

  • 头文件

    #include <boost/geometry.hpp>
    

快速入门


1. boost::geometry::Index

旨在收集称为空间索引的数据结构,这些结构可用于加速搜索空间中的对象。通常,空间索引存储几何对象的表示,并允许搜索占据某个空间或靠近空间中某个点的对象。 目前,仅实现一个空间索引 - R 树

2. R-tree

2.1 定义


空间数据的建模

基于实体的模型(基于对象)Entity-based models (or object based)

  • 0-dimensional objects : 一般使用点point来表示那些对于不需要使用到形状信息的实体。
  • 1-dimensional objects or linear objects: 用于表示一些路网的边,一般用于表示道路road。 (polyline)
  • 2-dimensional objects or surfacic objects: 用于表示有区域面积的实体。 (polygon)

20170410084842668.jpg

  • 对于B/B+-Trees 由于它的线性特点,通常用来索引一维数据

20170410084842686.jpg

20170410084845749.jpg

R树是b树的多维版

20170410084846718.jpg

R 树是用于空间搜索的树数据结构。它是由Antonin Guttman在1984年提出的,作为多维数据的B树的扩展。它可用于存储点或体积数据,以便执行空间查询。例如,此查询可以返回位于某个区域内或靠近空间中某个点 的对象。可以插入新对象或删除已存储的对象。 R 树结构如下图所示。每个 R 树的节点都存储一个框,描述其子节点所占用的空间。在结构的底部,有包含值(几何对象表示)的叶节点。

性质

  • 自平衡数据结构。
  • R 树的性能取决于平衡插入容器中的算法、参数和数据。( 更快的插入将导致更慢的搜索,反之亦然。)

rstar

更多原理分析

2.2 性能

不同算法构建树的流程

[运行机器](Intel(R) Core(TM) i7 870 @ 2.93GHz, 8GB RAM, MS Windows 7 x64*. The code was compiled with optimization for speed (O2).)

线性算法二次规划算法R*-tree装箱算法
示例结构linearquadraticrstarbulk
1M 数据插入1.76s2.47s6.19s0.64s
100k 数据查询2.21s0.51s0.12s0.07s
100k knn 查询6.37s2.09s0.64s0.52s

knn:( k-nearest neighbor )k个最近邻近查询

2.3 可查询关系

2.3.1 空间几何

20200719225013412.png

rt.query(index::contains(box), std::back_inserter(result));
rt.query(index::covered_by(box), std::back_inserter(result));
rt.query(index::covers(box), std::back_inserter(result));
rt.query(index::disjont(box), std::back_inserter(result));
rt.query(index::intersects(box), std::back_inserter(result));
rt.query(index::overlaps(box), std::back_inserter(result));
rt.query(index::within(box), std::back_inserter(result));

2.3.2 最近邻查询

std::vector<Value> returned_values;
Point pt(/*...*/);
rt.query(bgi::nearest(pt, k), std::back_inserter(returned_values));//返回最近的k个空间索引

Segment seg(/*...*/);
rt.query(bgi::nearest(seg, k), std::back_inserter(returned_values));

2.3.3 函数查询

bool is_red(Value const& v) //函数
{
  return v.is_red();
}

struct is_red_o //函数对象
{
  template <typename Value>
  bool operator()(Value const& v)
  {
    return v.is_red();
  }
}
rt.query(index::intersects(box) && index::satisfies(is_red),
         std::back_inserter(result));
rt.query(index::intersects(box) && index::satisfies(is_red_o()),
         std::back_inserter(result));
//lambda表达式
#ifndef BOOST_NO_CXX11_LAMBDAS
rt.query(index::intersects(box) && index::satisfies([](Value const& v) { return v.is_red(); }),
         std::back_inserter(result));
#endif

2.4 创建和使用

  • 可索引类型
  • Indexable = Point | Box | Segment
  • Value = Indexable | std::pair<Indexable, T> | boost::tuple<Indexable, ...> [ | std::tuple<Indexable, ...> ]
rtree<Point, ...>rtree<Box, ...>rtree<Segment, ...>
rtree_ptrstarrtree_seg
  • 支持三种平衡算法

    • 编译时

      //线性
      index::rtree< Value, index::linear<16> > rt;
      //二次规划
      index::rtree< Value, index::quadratic<16> > rt;
      //R*
      index::rtree< Value, index::rstar<16> > rt;
      
    • 运行时

      //线性
      index::rtree<Value, index::dynamic_linear>rt(index::dynamic_linear(16));
      //二次规划
      index::rtree<Value, index::dynamic_quadratic>rt(index::dynamic_quadratic(16));
      //R*
      index::rtree<Value, index::dynamic_rstar> rt(index::dynamic_rstar(16));
      
  • 插入和删除

    Value v = std::make_pair(Box(...), 0);
    rt.insert(v);
    rt.remove(v);
    
  • 迭代器插入

    namespace bgi = boost::geometry::index;
    typedef std::pair<Box, int> Value;
    typedef bgi::rtree< Value, bgi::linear<32> > RTree;
    
    std::vector<Value> values;
    /* vector filling code, here */
    
    // create R-tree and insert values from the vector
    RTree rt1;
    std::copy(values.begin(), values.end(), bgi::inserter(rt1));
    
    // create R-tree and insert values returned by a query
    RTree rt2;
    rt1.spatial_query(Box(/*...*/), bgi::inserter(rt2));
    

2.5 实例

//导入头文件
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point.hpp>
#include <boost/geometry/geometries/box.hpp>

#include <boost/geometry/index/rtree.hpp>
#include <vector>
#include <iostream>
#include <boost/foreach.hpp>

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

/*
MyGeometryId 将是存储在其他容器中的复杂几何图形的某个标识符,
例如存储在向量中的多边形的索引类型或环列表的迭代器。
为了简化定义 Value 的过程,我们将使用预定义的 Box 和 unsigned int。
*/
typedef bg::model::point<float, 2, bg::cs::cartesian> point;
typedef bg::model::box<point> box;
typedef std::pair<box, unsigned> value;

/*
可以使用各种算法和参数创建R树。您应该选择最适合您目的的算法。
在此示例中,我们将使用二次算法。参数作为模板参数传递。节点中的最大元素数设置为 16
*/
bgi::rtree< value, bgi::quadratic<16> > rtree;

//手动生成一些框,并使用 insert() 方法将它们插入到 R 树中
for ( unsigned i = 0 ; i < 10 ; ++i )
{
    // create a box
    box b(point(i + 0.0f, i + 0.0f), point(i + 0.5f, i + 0.5f));
    // insert new value
    rtree.insert(std::make_pair(b, i));
}

/*
可以执行各种类型的空间查询,甚至可以在一次调用中将它们组合在一起。
为简单起见,我们使用默认的。以下查询返回与框相交的值。未指定结果中值的顺序。
*/
box query_box(point(0, 0), point(5, 5));
std::vector<value> result_s;
rtree.query(bgi::intersects(query_box), std::back_inserter(result_s));

// KNN 查询
std::vector<value> result_n;
rtree.query(bgi::nearest(point(0, 0), 5), std::back_inserter(result_n));

//查询结果打印
// display results
std::cout << "spatial query box:" << std::endl;
std::cout << bg::wkt<box>(query_box) << std::endl;
std::cout << "spatial query result:" << std::endl;
BOOST_FOREACH(value const& v, result_s)
    std::cout << bg::wkt<box>(v.first) << " - " << v.second << std::endl;

std::cout << "knn query point:" << std::endl;
std::cout << bg::wkt<point>(point(0, 0)) << std::endl;
std::cout << "knn query result:" << std::endl;
BOOST_FOREACH(value const& v, result_n)
    std::cout << bg::wkt<box>(v.first) << " - " << v.second << std::endl;

本文由博客一文多发平台 OpenWrite 发布!