#pragma once #include "vde/core/point.h" #include namespace vde::core { /** * @brief 三维三角形 * * 由三个顶点定义的平面三角形面片。 * 支持面积、法线、质心、重心坐标包含测试。 * * @tparam T 标量类型(通常为 double) * * @ingroup core */ template class Triangle { public: /// 默认构造:三个顶点均在原点(退化三角形) Triangle() = default; /** * @brief 从三个顶点构造三角形 * * @param v0 第一个顶点 * @param v1 第二个顶点 * @param v2 第三个顶点 */ Triangle(const Point3D& v0, const Point3D& v1, const Point3D& v2) : v_{v0, v1, v2} {} /** * @brief 获取第 i 个顶点 * * @param i 顶点索引(0, 1, 2) * @return 顶点引用 */ [[nodiscard]] const Point3D& v(int i) const { return v_[i]; } /// 获取所有顶点数组 [[nodiscard]] const std::array& vertices() const { return v_; } /** * @brief 三角形单位法向量 * * 使用 (v1 - v0) × (v2 - v0) 的归一化结果。 * 依右手定则方向。 * * @return 单位法向量 * * @note 若三角形退化(面积为零),返回零向量 */ [[nodiscard]] Vector3D normal() const { return (v_[1] - v_[0]).cross(v_[2] - v_[0]).normalized(); } /** * @brief 三角形面积 * @return 0.5 * ||(v1 - v0) × (v2 - v0)|| */ [[nodiscard]] T area() const { return (v_[1] - v_[0]).cross(v_[2] - v_[0]).norm() * 0.5; } /** * @brief 三角形质心(几何中心) * @return (v0 + v1 + v2) / 3 */ [[nodiscard]] Point3D centroid() const { return (v_[0] + v_[1] + v_[2]) / 3.0; } /** * @brief 重心坐标包含测试 * * 将点 p 正交投影到三角形平面上,计算重心坐标并判断是否在三角形内。 * * @param p 测试点(三维空间中的任意点) * @return true 若投影点在三角形内部或边界上 * * @note 该测试等效于三维点在三角形上的包含测试(先投影再测试) * * @code{.cpp} * Triangle3D tri({0,0,0}, {1,0,0}, {0,1,0}); * bool in1 = tri.contains(Point3D(0.2, 0.2, 0)); // true * bool in2 = tri.contains(Point3D(0.2, 0.2, 5)); // true (投影后判断) * @endcode */ [[nodiscard]] bool contains(const Point3D& p) const { Vector3D v0 = v_[2] - v_[0], v1 = v_[1] - v_[0], v2 = p - v_[0]; T d00 = v0.dot(v0), d01 = v0.dot(v1), d11 = v1.dot(v1); T d20 = v2.dot(v0), d21 = v2.dot(v1); T denom = d00 * d11 - d01 * d01; T v = (d11 * d20 - d01 * d21) / denom; T w = (d00 * d21 - d01 * d20) / denom; return v >= 0 && w >= 0 && v + w <= 1; } private: std::array v_{}; }; /// 双精度三维三角形 using Triangle3D = Triangle; /// 单精度三维三角形 using Triangle3f = Triangle; } // namespace vde::core