Files
ViewDesignEngine/include/vde/spatial/r_tree.h
T

171 lines
4.6 KiB
C++

/**
* @file r_tree.h
* @brief R 树 (R-Tree) 动态空间索引
*
* 高度平衡的树形结构,每个节点存储其子节点的最小包围矩形(MBR)。
* 适合需要频繁插入和删除的动态数据集。
*
* @ingroup spatial
*/
#pragma once
#include "vde/spatial/spatial_index.h"
#include "vde/core/aabb.h"
#include <queue>
#include <limits>
namespace vde::spatial {
using core::Point3D;
using core::Vector3D;
using core::Ray3Dd;
using core::Triangle3D;
/**
* @brief R 树节点
*
* 内部节点存储子节点索引列表;叶节点存储对象索引列表。
* 每个节点维护其所有子条目的最小包围盒。
*
* @tparam T 被索引的空间对象类型
*/
template <typename T>
struct RTreeNode {
AABB3D bbox; /**< 节点包围盒(子节点/对象 MBR 的并集) */
bool is_leaf = true; /**< 是否为叶节点 */
std::vector<size_t> children; /**< 内部节点:子节点索引列表 */
std::vector<size_t> item_indices; /**< 叶节点:对象索引列表 */
size_t parent = static_cast<size_t>(-1); /**< 父节点索引 */
};
/**
* @brief R 树动态空间索引
*
* R 树是一种高度平衡的树,所有叶节点位于同一层。
* 插入时选择包围盒扩展最小的子节点;溢出时分裂节点。
* 支持增量插入和删除,适合数据集频繁变化的场景。
*
* 构建: O(n log n)(逐项插入)
* 范围查询: O(log n + k)
* KNN 查询: O(log n + k log k)
* 插入: O(log n)
* 删除: O(log n)
*
* @tparam T 被索引的空间对象类型
*
* @note R 树在动态场景(如编辑中的几何体)中比 BVH 更合适。
* BVH 查询效率更高但构建后不易修改。
*
* @code{.cpp}
* RTree<Point3D> rtree;
* rtree.build(points);
* rtree.insert(new_point); // 增量插入
* auto nearby = rtree.query_range(search_box);
* @endcode
*
* @see SpatialIndex, BVH, RStarTree
*/
template <typename T>
class RTree : public SpatialIndex<T> {
public:
/**
* @brief 批量构建 R 树
*
* 清空已有数据,将所有 items 逐个插入。
* 构建复杂度 O(n log n)。
*
* @param items 待索引的对象数组
*/
void build(const std::vector<T>& items) override;
/**
* @brief 增量插入对象
*
* 从根节点出发选择包围盒扩展最小的子节点递归插入。
* 节点溢出时分裂。复杂度 O(log n)。
*
* @param item 待插入的空间对象
*/
void insert(const T& item) override;
/**
* @brief 删除对象
*
* 定位到所在叶节点后移除。
* 复杂度 O(log n)。
*
* @param item 待删除的空间对象
* @return 删除成功返回 true
*/
bool remove(const T& item) override;
/**
* @brief 范围查询
*
* 从根节点遍历,仅访问与 range 相交的子节点。
* 复杂度 O(log n + k)。
*
* @param range 查询包围盒
* @return 与 range 相交的对象列表
*/
std::vector<T> query_range(const AABB3D& range) const override;
/**
* @brief K 近邻查询
*
* 使用优先队列按 MBR 最小距离剪枝。
*
* @param point 查询点
* @param k 返回数量
* @return 最近的 k 个对象
*/
std::vector<T> query_knn(const Point3D& point, size_t k) const override;
/**
* @brief 射线查询
*
* 从根节点递归,遍历被射线穿过的子节点。
*
* @param ray 查询射线
* @return 与射线相交的对象列表
*/
std::vector<T> query_ray(const Ray3Dd& ray) const override;
/**
* @brief 清空 R 树
*/
void clear() override;
/**
* @brief 对象数量
*
* @return 当前索引的对象总数
*/
size_t size() const override { return count_; }
/**
* @brief R 树节点总数
*
* @return 内部节点 + 叶节点数量
*/
size_t node_count() const { return nodes_.size(); }
private:
/**
* @brief 递归范围查询
*
* @param node_idx 当前节点索引
* @param range 查询包围盒
* @param result 累积结果
*/
void query_range_recursive(size_t node_idx, const AABB3D& range,
std::vector<T>& result) const;
std::vector<T> items_; /**< 对象数组 */
std::vector<AABB3D> item_bounds_; /**< 对象包围盒数组 */
std::vector<RTreeNode<T>> nodes_; /**< R 树节点数组 */
size_t root_idx_ = 0; /**< 根节点索引 */
size_t count_ = 0; /**< 对象计数 */
};
} // namespace vde::spatial