Temporary repository used to save branch code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

301 lines
12 KiB

#pragma once
#include <macros.h>
#include <vector>
#include <limits>
#include <math/eigen_alias.hpp>
#include <math/math_defs.hpp>
#include <primitive_descriptor.h>
using aabb_t = Eigen::AlignedBox<double, 3>;
namespace internal
{
template <int Dim>
using aabb_t_dim = Eigen::AlignedBox<double, Dim>;
constexpr double EPSILON = std::numeric_limits<double>::epsilon();
// 辅助函数:类型转换
namespace detail
{
static inline Eigen::Vector3d to_eigen(const vector3d& v) { return Eigen::Vector3d(v.x, v.y, v.z); }
} // namespace detail
// 辅助函数:坐标转换
namespace geometry_utils
{
/**
* @brief 投影转换函数
* @detail 将3D点投影到由 x_dir 和 y_dir 定义的平面上,并加上偏移量 offset,使得投影后的坐标系原点位于 offset 位置。
* @param point 3D点坐标
* @param x_dir 投影平面X轴方向
* @param y_dir 投影平面Y轴方向
* @param offset 投影后的偏移量
* @return 2D投影坐标
*/
static inline auto manually_projection(const vector3d& point,
const Eigen::Ref<const Eigen::Vector3d>& x_dir,
const Eigen::Ref<const Eigen::Vector3d>& y_dir,
const Eigen::Ref<const Eigen::Vector2d>& offset)
{
Eigen::Vector3d p = Eigen::Map<const Eigen::Vector3d>(&point.x);
return Eigen::Vector2d{p.dot(x_dir), p.dot(y_dir)} + offset;
}
static inline auto manually_projection(vector3d&& point,
const Eigen::Ref<const Eigen::Vector3d>& x_dir,
const Eigen::Ref<const Eigen::Vector3d>& y_dir,
const Eigen::Ref<const Eigen::Vector2d>& offset)
{
Eigen::Vector3d p = Eigen::Map<const Eigen::Vector3d>(&point.x);
return Eigen::Vector2d{p.dot(x_dir), p.dot(y_dir)} + offset;
}
} // namespace geometry_utils
// ==================== Polyline 几何数据 ====================
/**
* @brief Polyline 路径的几何计算数据
* @details 用于构造拉伸体的 profile 和 axis,支持直线段和圆弧段
*/
EXTERN_C struct PE_API polyline_geometry_data {
// ===== 几何数据 =====
std::vector<Eigen::Vector2d> vertices; // 所有顶点(包括圆弧的圆心和中间点)
std::vector<uint8_t> start_indices; // 每个段的起始索引
std::vector<double> thetas; // 每个段的角度(直线为0,圆弧为实际角度)
bool is_axis = false; // 标记是否为 Axis
// 最近点查询结果
struct line_closest_param_t {
Eigen::Vector3d point; // 最近点的3D坐标
double t; // 参数化坐标 [0, segment_count]
bool is_peak_value; // 是否是极值点(用于符号判定)
};
/**
* @brief 作为 Axis 构建
* @param desc Polyline 描述符
* @param profile_ref_normal Profile 的参考法向量
* @param axis_to_world 输出的坐标系变换矩阵
* @param aabb 输出的3D AABB(世界坐标系)
*/
void build_as_axis(const polyline_descriptor_t& desc,
const vector3d& profile_ref_normal,
Eigen::Transform<double, 3, Eigen::AffineCompact>& axis_to_world,
aabb_t& aabb);
void build_as_axis(polyline_descriptor_t&& desc,
const vector3d& profile_ref_normal,
Eigen::Transform<double, 3, Eigen::AffineCompact>& axis_to_world,
aabb_t& aabb);
/**
* @brief 作为 Profile 构建
* @param desc Polyline 描述符
* @param proj_x_dir 投影平面X轴方向(世界坐标系)
* @param proj_y_dir 投影平面Y轴方向(世界坐标系)
* @param proj_origin 投影平面原点(世界坐标系)
* @param aabb 输出的2D AABB(投影平面坐标系)
*/
void build_as_profile(const polyline_descriptor_t& desc,
const Eigen::Vector3d& proj_x_dir,
const Eigen::Vector3d& proj_y_dir,
const Eigen::Vector3d& proj_origin,
aabb_t_dim<2>& aabb);
void build_as_profile(polyline_descriptor_t&& desc,
const Eigen::Vector3d& proj_x_dir,
const Eigen::Vector3d& proj_y_dir,
const Eigen::Vector3d& proj_origin,
aabb_t_dim<2>& aabb);
/**
* @brief 计算参数 t 处的切线向量
* @param t 参数化坐标 [0, segment_count]
* @return 单位切线向量(2D)
*/
[[nodiscard]] Eigen::Vector2d calculate_tangent(double t) const;
/**
* @brief 计算参数 t 处的法线向量(指向多段线内侧)
* @details 对 CCW 缠绕的多段线,内法向定义为切向量的逆时针旋转 90°。
* 直线段:inward = CCW_rot(tangent)
* 圆弧段:通过顶点帧的叉积符号判断 bulge 正负,确保结果统一指向内侧。
* @param t 参数化坐标 [0, segment_count]
* @return 法线向量(2D,圆弧段可能未归一化)
*/
[[nodiscard]] Eigen::Vector2d calculate_normal(double t) const;
/**
* @brief 计算点到 polyline 的最近点
* @param p 查询点(3D坐标,z分量用于距离计算)
* @return 最近点信息(位置、参数、是否极值)
*/
[[nodiscard]] std::pair<line_closest_param_t, double> calculate_closest_param(
const Eigen::Ref<const Eigen::Vector3d>& p) const;
/**
* @brief Point Membership Classification (PMC)
* @details Determines which side of the polyline boundary a point lies on,
* using the INWARD normal returned by calculate_normal().
*
* Let v = p - q (from closest boundary point q toward query point p).
* v · n_inward < 0 → p opposes inward direction → p is OUTSIDE → return true
* v · n_inward ≥ 0 → p aligns with inward direction → p is INSIDE → return false
*
* Convention (matches SDF sign rule):
* true = point is OUTSIDE the polyline (SDF > 0)
* false = point is INSIDE the polyline (SDF < 0)
*
* @param p 查询点(2D)
* @param closest_param 最近点信息(由 calculate_closest_param 返回)
* @return true 若点在 polyline 外部
* @return false 若点在 polyline 内部
*/
[[nodiscard]] bool pmc(const Eigen::Ref<const Eigen::Vector2d>& p, const line_closest_param_t& closest_param) const;
/**
* @brief 判断参数 t 是否在端点处
* @param t 参数化坐标
* @return true 如果在起点或终点
*/
[[nodiscard]] bool isEnd(double t) const;
private:
/**
* @brief 内部通用构建逻辑
* @param desc Polyline 描述符
* @param project_func 投影函数(3D点 → 2D点)
* @param aabb 2D AABB(可选)
*/
void build_internal(const polyline_descriptor_t& desc,
std::function<Eigen::Vector2d(const vector3d&)> project_func,
aabb_t_dim<2>* aabb = nullptr);
};
// ==================== Helixline 几何数据 ====================
/**
* @brief Helixline(螺旋线)的几何计算数据
* @details 用于螺旋拉伸体的 axis
*/
EXTERN_C struct PE_API helixline_geometry_data {
// ===== 几何参数 =====
double radius; // 螺旋半径
double height; // 轴向高度
double total_theta; // 总旋转角度
bool is_righthanded; // 是否为右旋
// ===== 最近点查询结果 =====
struct line_closest_param_t {
Eigen::Vector3d point; // 最近点的3D坐标
double t; // 参数化坐标
bool is_peak_value; // 是否是极值点
};
// ===== 核心方法 =====
/**
* @brief 从 descriptor 构建几何数据
*/
void build_from_descriptor(const helixline_descriptor_t& desc,
Eigen::Transform<double, 3, Eigen::AffineCompact, Eigen::DontAlign>& axis_to_world,
aabb_t& aabb);
void build_from_descriptor(helixline_descriptor_t&& desc,
Eigen::Transform<double, 3, Eigen::AffineCompact, Eigen::DontAlign>& axis_to_world,
aabb_t& aabb);
/**
* @brief 计算参数 t 处的切线向量
* @param t 参数化坐标 [0, 1]
* @return 单位切线向量(3D)
*/
[[nodiscard]] Eigen::Vector3d calculate_tangent(double t) const;
/**
* @brief 计算参数 t 处的法线向量(径向)
* @param t 参数化坐标 [0, 1]
* @return 法线向量(3D)
*/
[[nodiscard]] Eigen::Vector3d calculate_normal(double t) const;
/**
* @brief 计算点到螺旋线的最近点(使用峰值搜索 + 牛顿迭代)
* @param p 查询点(3D坐标)
* @return 最近点信息
*/
[[nodiscard]] line_closest_param_t calculate_closest_param(const Eigen::Vector3d& p) const;
/**
* @brief 判断参数 t 是否在端点处
*/
[[nodiscard]] bool isEnd(double t) const;
};
// ==================== TBN 坐标系构建 ====================
/**
* @brief 构建 TBN 坐标系矩阵(复现旧架构)
* @param tangent 切线方向(T)
* @param normal 法线方向(N)
* @param origin 坐标系原点
* @return TBN 变换矩阵
*/
// 返回完整的 paired_model_matrix
inline paired_model_matrix build_TBN_paired_matrix(const Eigen::Vector3d& tangent,
const Eigen::Vector3d& normal,
const Eigen::Vector3d& origin)
{
paired_model_matrix result;
// 构建 local_to_world
Eigen::Vector3d T = tangent.normalized();
Eigen::Vector3d N = normal.normalized();
Eigen::Vector3d B = N.cross(T).normalized();
result.local_to_world.matrix().col(0).head<3>() = B;
result.local_to_world.matrix().col(1).head<3>() = N;
result.local_to_world.matrix().col(2).head<3>() = T;
result.local_to_world.matrix().col(3).head<3>() = origin;
// result.local_to_world.matrix()(3, 3) = 1.0;
// 自动计算逆矩阵
result.world_to_local = result.local_to_world.inverse();
return result;
}
// 针对 Polyline 的专用函数
inline paired_model_matrix build_polyline_cap_matrix(const Eigen::Vector3d& axis_point,
const Eigen::Vector3d& axis_tangent,
const Eigen::Vector3d& axis_normal,
bool is_top_cap = false)
{
//Eigen::Vector3d tangent = is_top_cap ? -axis_tangent : axis_tangent;
//return build_TBN_paired_matrix(tangent, axis_normal, axis_point);
(void)is_top_cap; // both caps use the same +tangent direction; mark controls sign
paired_model_matrix result;
const Eigen::Vector3d T = axis_tangent.normalized();
const Eigen::Vector3d N = axis_normal.normalized();
// Gram-Schmidt: make N orthogonal to T
const Eigen::Vector3d N_orth = (N - N.dot(T) * T).normalized();
const Eigen::Vector3d B_orth = T.cross(N_orth);
result.local_to_world.matrix().col(0).head<3>() = T; // plane normal = axis tangent
result.local_to_world.matrix().col(1).head<3>() = N_orth;
result.local_to_world.matrix().col(2).head<3>() = B_orth;
result.local_to_world.matrix().col(3).head<3>() = axis_point;
result.world_to_local = result.local_to_world.inverse();
return result;
}
} // namespace internal