/** * @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 #include namespace vde::spatial { using core::Point3D; using core::Vector3D; using core::Ray3Dd; using core::Triangle3D; /** * @brief R 树节点 * * 内部节点存储子节点索引列表;叶节点存储对象索引列表。 * 每个节点维护其所有子条目的最小包围盒。 * * @tparam T 被索引的空间对象类型 */ template struct RTreeNode { AABB3D bbox; /**< 节点包围盒(子节点/对象 MBR 的并集) */ bool is_leaf = true; /**< 是否为叶节点 */ std::vector children; /**< 内部节点:子节点索引列表 */ std::vector item_indices; /**< 叶节点:对象索引列表 */ size_t parent = static_cast(-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 rtree; * rtree.build(points); * rtree.insert(new_point); // 增量插入 * auto nearby = rtree.query_range(search_box); * @endcode * * @see SpatialIndex, BVH, RStarTree */ template class RTree : public SpatialIndex { public: /** * @brief 批量构建 R 树 * * 清空已有数据,将所有 items 逐个插入。 * 构建复杂度 O(n log n)。 * * @param items 待索引的对象数组 */ void build(const std::vector& 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 query_range(const AABB3D& range) const override; /** * @brief K 近邻查询 * * 使用优先队列按 MBR 最小距离剪枝。 * * @param point 查询点 * @param k 返回数量 * @return 最近的 k 个对象 */ std::vector query_knn(const Point3D& point, size_t k) const override; /** * @brief 射线查询 * * 从根节点递归,遍历被射线穿过的子节点。 * * @param ray 查询射线 * @return 与射线相交的对象列表 */ std::vector 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& result) const; std::vector items_; /**< 对象数组 */ std::vector item_bounds_; /**< 对象包围盒数组 */ std::vector> nodes_; /**< R 树节点数组 */ size_t root_idx_ = 0; /**< 根节点索引 */ size_t count_ = 0; /**< 对象计数 */ }; } // namespace vde::spatial