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