#pragma once #include #include "vde/spatial/spatial_index.h" #include "vde/core/aabb.h" #include "vde/core/triangle.h" namespace vde::spatial { using core::Point3D; using core::Vector3D; using core::Ray3Dd; using core::Triangle3D; enum class BVHSplitStrategy { Middle, Equal, SAH }; struct BVHBuildOptions { BVHSplitStrategy strategy = BVHSplitStrategy::SAH; int leaf_size = 4; int max_depth = 64; }; class BVH : public SpatialIndex { public: explicit BVH(const BVHBuildOptions& opts = {}) : opts_(opts) {} void build(const std::vector& tris) override; void insert(const Triangle3D& tri) override; bool remove(const Triangle3D& tri) override; std::vector query_range(const AABB3D& range) const override; std::vector query_knn(const Point3D& point, size_t k) const override; std::vector query_ray(const Ray3Dd& ray) const override; void clear() override; size_t size() const override { return primitives_.size(); } /// Find closest hit along ray struct HitResult { double t; Triangle3D tri; Point3D point; }; std::optional query_ray_nearest(const Ray3Dd& ray) const; private: struct Node { AABB3D bounds; int left = -1, right = -1; int first_prim = 0, prim_count = 0; bool leaf() const { return left < 0; } }; std::vector nodes_; std::vector primitives_; BVHBuildOptions opts_; void build_recursive(int node, int first, int count, int depth); double sah_cost(int n_left, int n_right, const AABB3D& left, const AABB3D& right) const; }; } // namespace vde::spatial