#pragma once #include #include #include "subface/simple/extrude_polyline_side_face.hpp" #include "subface/simple/extrude_helixline_side_face.hpp" #include 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::max(), std::numeric_limits::max()}; vector2d max_val{std::numeric_limits::lowest(), std::numeric_limits::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::max(), std::numeric_limits::max()}; vector2d max_val{std::numeric_limits::lowest(), std::numeric_limits::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(&desc.points[0].x); Eigen::Vector3d p1 = Eigen::Map(&desc.points[1].x); Eigen::Vector3d tangent = (p1 - origin).normalized(); Eigen::Vector3d axis_normal = Eigen::Map(&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(&desc.points[last_idx].x); Eigen::Vector3d p_prev = Eigen::Map(&desc.points[last_idx - 1].x); Eigen::Vector3d tangent = (origin - p_prev).normalized(); Eigen::Vector3d axis_normal = Eigen::Map(&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(&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 get_subface_geometries() const override; span> get_subfaces() const override { return {const_cast*>(subfaces.data()), subfaces.size()}; } stl_vector_mp 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, 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(&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 get_subface_geometries() const override; span> get_subfaces() const override { return {const_cast*>(subfaces.data()), 3}; } stl_vector_mp 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, 3> subfaces{}; }; } // namespace internal