Files
ViewDesignEngine/include/vde/core/plane.h
T

97 lines
2.4 KiB
C++
Raw Normal View History

#pragma once
#include "vde/core/point.h"
namespace vde::core {
/**
* @brief 三维平面
*
* 用 Hessian 法式表示:normal · p + d = 0。
* 其中 normal 为单位法向量,d 为原点到平面的有向距离的负值。
*
* @tparam T 标量类型(通常为 double
*
* @ingroup core
*/
template <typename T>
class Plane {
public:
/// 默认构造:法线 (0,0,1)d=0XY 平面)
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<double> 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<double>;
} // namespace vde::core