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.
 
 
 
 
 
 

350 lines
13 KiB

#pragma once
#include <data/data_center.hpp>
#include <base/primitive.hpp>
#include "subface/simple/extrude_polyline_side_face.hpp"
#include "subface/simple/extrude_helixline_side_face.hpp"
#include <subface/simple/plane.hpp>
namespace internal
{
inline void expand_aabb_for_bulge_segment(const vector2d& A,
const vector2d& B,
double bulge,
vector2d& aabb_min,
vector2d& aabb_max)
{
// 端点始终纳入(无论是直线还是圆弧,端点必在 AABB 内)
aabb_min.x = std::min({aabb_min.x, A.x, B.x});
aabb_min.y = std::min({aabb_min.y, A.y, B.y});
aabb_max.x = std::max({aabb_max.x, A.x, B.x});
aabb_max.y = std::max({aabb_max.y, A.y, B.y});
if (std::abs(bulge) < 1e-12) return; // 直线段,端点已处理完毕
// 计算圆心与半径
Eigen::Vector2d Av(A.x, A.y), Bv(B.x, B.y);
Eigen::Vector2d chord = Bv - Av;
double chord_len = chord.norm();
if (chord_len < 1e-12) return;
Eigen::Vector2d chord_dir = chord / chord_len;
Eigen::Vector2d chord_perp(-chord_dir.y(), chord_dir.x()); // 左法向
// d = chord/2 * (1/bulge - bulge) / 2 = chord*(1-b²)/(4b)
double d = 0.5 * chord_len * (1.0 / bulge - bulge) * 0.5;
Eigen::Vector2d M = 0.5 * (Av + Bv);
Eigen::Vector2d center = M + chord_perp * d;
double radius = std::sqrt(d * d + 0.25 * chord_len * chord_len);
// 计算端点对应的极角
double angle_A = std::atan2(A.y - center.y(), A.x - center.x());
double angle_B = std::atan2(B.y - center.y(), B.x - center.x());
// 判断某极角是否在弧段内
// bulge > 0 → CCW(从 angle_A 逆时针到 angle_B)
// bulge < 0 → CW (从 angle_A 顺时针到 angle_B)
auto angle_in_arc = [&](double theta) -> bool {
// 将所有角度归一化到 [0, 2π)
auto norm2pi = [](double a) -> double {
a = std::fmod(a, 2.0 * pi);
return a < 0.0 ? a + 2.0 * pi : a;
};
double sa = norm2pi(angle_A);
double ea = norm2pi(angle_B);
double ta = norm2pi(theta);
if (bulge > 0.0) { // CCW: sa → ea,增角方向
if (sa <= ea)
return ta >= sa && ta <= ea;
else
return ta >= sa || ta <= ea; // 跨过 0°/360°
} else { // CW: sa → ea,减角方向
if (sa >= ea)
return ta <= sa && ta >= ea;
else
return ta <= sa || ta >= ea; // 跨过 0°/360°
}
};
// 检查四个坐标轴极值方向(0°, 90°, 180°, 270°)
struct {
double angle;
double dx;
double dy;
} extrema[] = {
{0.0, radius, 0.0 },
{pi / 2.0, 0.0, radius },
{pi, -radius, 0.0 },
{3.0 * pi / 2.0, 0.0, -radius},
};
for (const auto& e : extrema) {
if (angle_in_arc(e.angle)) {
aabb_min.x = std::min(aabb_min.x, center.x() + e.dx);
aabb_min.y = std::min(aabb_min.y, center.y() + e.dy);
aabb_max.x = std::max(aabb_max.x, center.x() + e.dx);
aabb_max.y = std::max(aabb_max.y, center.y() + e.dy);
}
}
}
// 计算单段 bulge 圆弧的 AABB 扩展
// bulge = tan(θ/4), θ = 圆弧包角
// 圆心: c = M + perp * d, 其中 perp 为弦的单位法向, d = (chord/2)(1/bulge - bulge)/2
inline vector2d compute_profile_aabb_min(const polyline_descriptor_t* profile)
{
if (!profile || profile->point_number == 0) return {0.0, 0.0};
vector2d min_val{std::numeric_limits<double>::max(), std::numeric_limits<double>::max()};
vector2d max_val{std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest()};
for (uint32_t i = 0; i < profile->point_number; ++i) {
min_val.x = std::min(min_val.x, profile->points[i].x);
min_val.y = std::min(min_val.y, profile->points[i].y);
max_val.x = std::max(max_val.x, profile->points[i].x);
max_val.y = std::max(max_val.y, profile->points[i].y);
}
if (profile->bulges) {
uint32_t n = profile->point_number;
for (uint32_t i = 0; i < n; ++i) {
double bulge = profile->bulges[i];
if (std::abs(bulge) < 1e-12) continue;
uint32_t j = (i + 1) % n;
vector2d A_2d = {profile->points[i].x, profile->points[i].y};
vector2d B_2d = {profile->points[j].x, profile->points[j].y};
expand_aabb_for_bulge_segment(A_2d, B_2d, bulge, min_val, max_val);
}
}
constexpr double margin = 1e-6;
min_val.x -= margin;
min_val.y -= margin;
return min_val;
}
inline vector2d compute_profile_aabb_max(const polyline_descriptor_t* profile)
{
if (!profile || profile->point_number == 0) return {0.0, 0.0};
vector2d min_val{std::numeric_limits<double>::max(), std::numeric_limits<double>::max()};
vector2d max_val{std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest()};
for (uint32_t i = 0; i < profile->point_number; ++i) {
min_val.x = std::min(min_val.x, profile->points[i].x);
min_val.y = std::min(min_val.y, profile->points[i].y);
max_val.x = std::max(max_val.x, profile->points[i].x);
max_val.y = std::max(max_val.y, profile->points[i].y);
}
if (profile->bulges) {
uint32_t n = profile->point_number;
for (uint32_t i = 0; i < n; ++i) {
double bulge = profile->bulges[i];
if (std::abs(bulge) < 1e-12) continue;
uint32_t j = (i + 1) % n;
// 修改处:从vector3d转换为vector2d
vector2d A_2d = {profile->points[i].x, profile->points[i].y};
vector2d B_2d = {profile->points[j].x, profile->points[j].y};
expand_aabb_for_bulge_segment(A_2d, B_2d, bulge, min_val, max_val);
}
}
constexpr double margin = 1e-6;
max_val.x += margin;
max_val.y += margin;
return max_val;
}
/**
* @brief 从 polyline descriptor 计算底盖 matrix
* @param desc polyline descriptor
* @return 底盖的 paired_model_matrix
*/
inline paired_model_matrix compute_polyline_bottom_cap_matrix(const polyline_descriptor_t& desc)
{
Eigen::Vector3d origin = Eigen::Map<const Eigen::Vector3d>(&desc.points[0].x);
Eigen::Vector3d p1 = Eigen::Map<const Eigen::Vector3d>(&desc.points[1].x);
Eigen::Vector3d tangent = (p1 - origin).normalized();
Eigen::Vector3d axis_normal = Eigen::Map<const Eigen::Vector3d>(&desc.reference_normal.x);
axis_normal.normalize();
return build_polyline_cap_matrix(origin, tangent, axis_normal, false);
}
/**
* @brief 从 polyline descriptor 计算顶盖 matrix
* @param desc polyline descriptor
* @return 顶盖的 paired_model_matrix
*/
inline paired_model_matrix compute_polyline_top_cap_matrix(const polyline_descriptor_t& desc)
{
uint32_t last_idx = desc.point_number - 1;
Eigen::Vector3d origin = Eigen::Map<const Eigen::Vector3d>(&desc.points[last_idx].x);
Eigen::Vector3d p_prev = Eigen::Map<const Eigen::Vector3d>(&desc.points[last_idx - 1].x);
Eigen::Vector3d tangent = (origin - p_prev).normalized();
Eigen::Vector3d axis_normal = Eigen::Map<const Eigen::Vector3d>(&desc.reference_normal.x);
axis_normal.normalize();
return build_polyline_cap_matrix(origin, tangent, axis_normal, true);
}
/**
* @brief 从螺旋线几何数据计算端盖变换矩阵
* @param ag 螺旋线几何数据
* @param t 参数化位置 (0.0 表示起点, 1.0 表示终点)
* @return 端盖的 paired_model_matrix
*
* 这个函数计算螺旋线在参数 t 处的 Frenet 标架(切线、法线、副法线),
* 并构建从局部坐标系到世界坐标系的变换矩阵。
* 切线方向作为平面的法向,指向几何体内部。
*/
inline paired_model_matrix make_helixline_cap_matrix(const helixline_geometry_data& ag, double t)
{
// 计算曲线端点处的切线 / 法线 / 副法线
const Eigen::Vector3d T = ag.calculate_tangent(t);
const Eigen::Vector3d N = ag.calculate_normal(t);
const Eigen::Vector3d B = N.cross(T);
// 计算曲线端点的世界坐标
const double angle = t * ag.total_theta;
const Eigen::Vector3d P(ag.radius * std::cos(angle), ag.radius * std::sin(angle), t * ag.height);
paired_model_matrix m;
auto& mat = m.local_to_world.matrix();
mat.setIdentity();
mat.col(0).head<3>() = T; // 平面法向 = 切线方向(指向几何体内部)
mat.col(1).head<3>() = N; // 平面内轴
mat.col(2).head<3>() = B; // 平面内轴
mat.col(3).head<3>() = P;
m.world_to_local = m.local_to_world.inverse();
return m;
}
inline paired_model_matrix compute_helixline_bottom_cap_matrix(const helixline_geometry_data& ag)
{
return make_helixline_cap_matrix(ag, 0.0);
}
/**
* @brief 从 helixline descriptor 计算顶盖 matrix
* @param ag 螺旋线几何数据
* @return 顶盖的 paired_model_matrix
*/
inline paired_model_matrix compute_helixline_top_cap_matrix(const helixline_geometry_data& ag)
{
return make_helixline_cap_matrix(ag, 1.0);
}
// ==================== Polyline 拉伸体 ====================
/**
* @brief Polyline 路径的拉伸体
*/
struct extrude_polyline_t final : primitive {
extrude_polyline_t(primitive_data_center_t* data_center_ptr) : primitive(data_center_ptr)
{
// 使用默认 descriptor 初始化
extrude_polyline_descriptor_t full_desc{};
full_desc.profile_number = 1;
full_desc.profiles = const_cast<polyline_descriptor_t*>(&descriptor_defaults::unit_square_profile);
full_desc.axis = descriptor_defaults::unit_polyline_axis;
initialize_from_descriptor(data_center_ptr, full_desc);
}
primitive_type get_type() const override { return PRIMITIVE_TYPE_EXTRUDE_POLYLINE; }
stl_vector_mp<const void*> get_subface_geometries() const override;
span<marked_subface_ptr_t<subface>> get_subfaces() const override
{
return {const_cast<marked_subface_ptr_t<subface>*>(subfaces.data()), subfaces.size()};
}
stl_vector_mp<surface_type> get_subface_types() const override
{
return {
surface_type::extrude_polyline_side,
surface_type::plane, // 底盖
surface_type::plane // 顶盖
};
}
/**
* @brief 从 descriptor 初始化(内部方法,类似 cylinder 的 initialize)
* @details 先准备好所有参数,然后一次性调用基类的 initialize
*/
PE_API void initialize_from_descriptor(primitive_data_center_t* dc, const extrude_polyline_descriptor_t& desc);
/**
* @brief 使用 Profile 和 Axis 初始化拉伸体
*/
PE_API void initialize_with_components(primitive_data_center_t* dc, const extrude_polyline_descriptor_t& desc)
{
initialize_from_descriptor(dc, desc);
}
/**
* @brief 替换 Profile
* @details 保持 Axis 不变,仅更新 Profile
*/
PE_API void replace_profile(const profile_descriptor_t& new_profile);
/**
* @brief 替换 Axis
* @details 保持 Profile 不变,仅更新 Axis
*/
PE_API void replace_axis(const axis_descriptor_t& new_axis);
// 3个子面:侧面 + 底盖 + 顶盖
std::array<marked_subface_ptr_t<subface>, 3> subfaces{};
};
// ==================== Helixline 拉伸体 ====================
/**
* @brief Helixline 路径的拉伸体
*/
struct extrude_helixline_t final : primitive {
extrude_helixline_t(primitive_data_center_t* data_center_ptr) : primitive(data_center_ptr)
{
// 使用默认 descriptor 初始化
extrude_helixline_descriptor_t full_desc{};
full_desc.profile_number = 1;
full_desc.profiles = const_cast<polyline_descriptor_t*>(&descriptor_defaults::unit_square_profile);
full_desc.axis = descriptor_defaults::unit_helix;
initialize_from_descriptor(data_center_ptr, full_desc);
}
primitive_type get_type() const override { return PRIMITIVE_TYPE_EXTRUDE_HELIXLINE; }
stl_vector_mp<const void*> get_subface_geometries() const override;
span<marked_subface_ptr_t<subface>> get_subfaces() const override
{
return {const_cast<marked_subface_ptr_t<subface>*>(subfaces.data()), 3};
}
stl_vector_mp<surface_type> get_subface_types() const override
{
return {surface_type::extrude_helixline_side, surface_type::plane, surface_type::plane};
}
PE_API void initialize_from_descriptor(primitive_data_center_t* dc, const extrude_helixline_descriptor_t& desc);
PE_API void initialize_with_components(primitive_data_center_t* dc, const extrude_helixline_descriptor_t& desc)
{
initialize_from_descriptor(dc, desc);
}
PE_API void replace_profile(const profile_descriptor_t& new_profile);
PE_API void replace_axis(const axis_descriptor_t& new_axis);
std::array<marked_subface_ptr_t<subface>, 3> subfaces{};
};
} // namespace internal