136 lines
3.5 KiB
C++
136 lines
3.5 KiB
C++
#pragma once
|
||
#include "vde/core/point.h"
|
||
#include <algorithm>
|
||
#include <limits>
|
||
|
||
namespace vde::core {
|
||
|
||
/**
|
||
* @brief 轴对齐包围盒(AABB)
|
||
*
|
||
* 用最小/最大两个角点表示的三维轴对齐包围盒。
|
||
* 支持增量扩展、包含/相交测试、几何属性查询。
|
||
*
|
||
* @tparam T 标量类型(通常为 double 或 float)
|
||
*
|
||
* @note 初始状态为空(min = +∞, max = -∞),需要通过 expand() 初始化
|
||
*
|
||
* @ingroup core
|
||
*/
|
||
template <typename T>
|
||
class AABB {
|
||
public:
|
||
/**
|
||
* @brief 构造空包围盒
|
||
*
|
||
* min 初始化为 T 最大值,max 初始化为 T 最小值,
|
||
* 表示"无内容"的空状态。
|
||
*/
|
||
AABB() : min_(Point3D::Constant(std::numeric_limits<T>::max())),
|
||
max_(Point3D::Constant(std::numeric_limits<T>::lowest())) {}
|
||
|
||
/**
|
||
* @brief 从两个角点构造包围盒
|
||
*
|
||
* @param min 最小角点
|
||
* @param max 最大角点
|
||
*
|
||
* @pre min 的各分量 ≤ max 的各分量
|
||
*/
|
||
AABB(const Point3D& min, const Point3D& max) : min_(min), max_(max) {}
|
||
|
||
/**
|
||
* @brief 扩展包围盒以包含给定点
|
||
*
|
||
* 逐分量取 min/max,保证包围盒包含该点。
|
||
* 若包围盒为空,此调用等效于初始化为包含该点的退化盒。
|
||
*
|
||
* @param p 要包含的点
|
||
*
|
||
* @code{.cpp}
|
||
* AABB3D box;
|
||
* for (auto& p : points) box.expand(p);
|
||
* @endcode
|
||
*/
|
||
void expand(const Point3D& p) {
|
||
min_ = min_.cwiseMin(p);
|
||
max_ = max_.cwiseMax(p);
|
||
}
|
||
|
||
/**
|
||
* @brief 扩展包围盒以包含另一个 AABB
|
||
*
|
||
* @param other 另一个包围盒
|
||
*/
|
||
void expand(const AABB& other) {
|
||
min_ = min_.cwiseMin(other.min_);
|
||
max_ = max_.cwiseMax(other.max_);
|
||
}
|
||
|
||
/**
|
||
* @brief 包围盒中心点
|
||
* @return (min + max) / 2
|
||
*/
|
||
[[nodiscard]] Point3D center() const { return (min_ + max_) * 0.5; }
|
||
|
||
/**
|
||
* @brief 包围盒对角线向量(从 min 到 max)
|
||
* @return max - min
|
||
*/
|
||
[[nodiscard]] Vector3D extent() const { return max_ - min_; }
|
||
|
||
/**
|
||
* @brief 包围盒表面积
|
||
* @return 2 * (dx*dy + dy*dz + dz*dx)
|
||
*/
|
||
[[nodiscard]] T surface_area() const {
|
||
Vector3D e = extent();
|
||
return 2.0 * (e.x() * e.y() + e.y() * e.z() + e.z() * e.x());
|
||
}
|
||
|
||
/**
|
||
* @brief 包围盒体积
|
||
* @return dx * dy * dz
|
||
*/
|
||
[[nodiscard]] T volume() const {
|
||
Vector3D e = extent();
|
||
return e.x() * e.y() * e.z();
|
||
}
|
||
|
||
/**
|
||
* @brief 测试点是否在包围盒内部(含边界)
|
||
*
|
||
* @param p 测试点
|
||
* @return true 若 min ≤ p ≤ max(各分量)
|
||
*/
|
||
[[nodiscard]] bool contains(const Point3D& p) const {
|
||
return (p.array() >= min_.array()).all() && (p.array() <= max_.array()).all();
|
||
}
|
||
|
||
/**
|
||
* @brief 测试两个包围盒是否相交(含边界接触)
|
||
*
|
||
* @param other 另一个包围盒
|
||
* @return true 若存在交集
|
||
*/
|
||
[[nodiscard]] bool intersects(const AABB& other) const {
|
||
return (min_.array() <= other.max_.array()).all()
|
||
&& (max_.array() >= other.min_.array()).all();
|
||
}
|
||
|
||
/// 获取最小角点
|
||
[[nodiscard]] const Point3D& min() const { return min_; }
|
||
/// 获取最大角点
|
||
[[nodiscard]] const Point3D& max() const { return max_; }
|
||
|
||
private:
|
||
Point3D min_, max_;
|
||
};
|
||
|
||
/// 双精度三维包围盒
|
||
using AABB3D = AABB<double>;
|
||
/// 单精度三维包围盒
|
||
using AABB3f = AABB<float>;
|
||
|
||
} // namespace vde::core
|