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