#pragma once #include "vde/core/point.h" namespace vde::core { /** * @brief 三维平面 * * 用 Hessian 法式表示:normal · p + d = 0。 * 其中 normal 为单位法向量,d 为原点到平面的有向距离的负值。 * * @tparam T 标量类型(通常为 double) * * @ingroup core */ template class Plane { public: /// 默认构造:法线 (0,0,1),d=0(XY 平面) Plane() = default; /** * @brief 从点和法线构造平面 * * @param point 平面上一点 * @param normal 法向量(自动归一化) */ Plane(const Point3D& point, const Vector3D& normal) : normal_(normal.normalized()), d_(-normal_.dot(point)) {} /** * @brief 从三点构造平面 * * @param a,b,c 平面上不共线的三点(右手定则决定法线方向) * * @pre 三点不共线 */ Plane(const Point3D& a, const Point3D& b, const Point3D& c) : Plane(a, (b - a).cross(c - a)) {} /// 获取单位法向量 [[nodiscard]] const Vector3D& normal() const { return normal_; } /** * @brief 获取平面方程常数 d * * 平面方程为 normal · x + d = 0。 * d 是原点到平面有向距离的负值。 * * @return d 值 */ [[nodiscard]] T d() const { return d_; } /** * @brief 有向点到平面距离 * * 正表示点在法线方向一侧,负表示相反侧。 * * @param p 测试点 * @return normal · p + d * * @code{.cpp} * Plane plane(Point3D(0,0,0), Vector3D::UnitZ()); * double sd = plane.signed_distance(Point3D(1,2,3)); * // sd == 3.0 (点在法线方向,正) * @endcode */ [[nodiscard]] T signed_distance(const Point3D& p) const { return normal_.dot(p) + d_; } /** * @brief 绝对点到平面距离 * * @param p 测试点 * @return |signed_distance(p)| */ [[nodiscard]] T distance(const Point3D& p) const { return std::abs(signed_distance(p)); } /** * @brief 点在平面上的正交投影 * * @param p 原点 * @return 投影点(满足在平面上且连线垂直于平面) */ [[nodiscard]] Point3D project(const Point3D& p) const { return p - normal_ * signed_distance(p); } private: Vector3D normal_{0,0,1}; T d_{0}; }; /// 双精度三维平面 using Plane3D = Plane; } // namespace vde::core