From da3efa945cedb94ef74c63e208c4d4f58ef97ba4 Mon Sep 17 00:00:00 2001 From: linchforever <2766643922@qq.com> Date: Tue, 14 Apr 2026 22:37:48 +0800 Subject: [PATCH] fix: Improve 'insert_polyline_corner_fillets' function and fix the mapping issue in 'polyline_geometry_data::calculate_closest_param' --- .../geometry/extrude_helixline_geometry.cpp | 6 +- .../geometry/extrude_polyline_geometry.cpp | 77 ++++++-- .../src/subface/geometry/geometry_data.cpp | 173 +++++------------- .../src/subface/geometry/polyline_fillet.cpp | 129 ++++++------- .../simple/extrude_helixline_side_face.cpp | 6 - 5 files changed, 158 insertions(+), 233 deletions(-) diff --git a/primitive_process/src/subface/geometry/extrude_helixline_geometry.cpp b/primitive_process/src/subface/geometry/extrude_helixline_geometry.cpp index 9ed08f6..6104798 100644 --- a/primitive_process/src/subface/geometry/extrude_helixline_geometry.cpp +++ b/primitive_process/src/subface/geometry/extrude_helixline_geometry.cpp @@ -15,8 +15,10 @@ void extrude_helixline_geometry_t::build() // 对 profile 各衔接顶点插入微小圆角弧 std::vector filleted_pts; std::vector filleted_bgs; - const fillet_config_t fillet_cfg{/*segment_ratio=*/3.0, - /*min_turn_angle_deg=*/0.5}; + const fillet_config_t fillet_cfg{/*segment_ratio=*/0.05, + /*min_turn_angle_deg=*/0.5, + /*min_fillet_radius=*/0.0, // profile 自身不需要最小半径约束 + /*is_axis=*/true}; insert_polyline_corner_fillets(profile_desc, filleted_pts, filleted_bgs, fillet_cfg); polyline_descriptor_t filleted_desc{}; diff --git a/primitive_process/src/subface/geometry/extrude_polyline_geometry.cpp b/primitive_process/src/subface/geometry/extrude_polyline_geometry.cpp index b8edcd3..7860325 100644 --- a/primitive_process/src/subface/geometry/extrude_polyline_geometry.cpp +++ b/primitive_process/src/subface/geometry/extrude_polyline_geometry.cpp @@ -1,24 +1,60 @@ #include #include +#include namespace internal { +/// 计算 profile 截面的最大半径(原点到各顶点的最大距离)。 +/// 用于确保 axis 圆角半径 > profile 半径,防止挤出体内侧自相交。 +static double compute_profile_max_radius(const polyline_descriptor_t& profile_desc) +{ + if (profile_desc.point_number == 0 || profile_desc.points == nullptr) return 0.0; + + double max_r2 = 0.0; + for (uint32_t i = 0; i < profile_desc.point_number; ++i) { + const double x = profile_desc.points[i].x; + const double y = profile_desc.points[i].y; + max_r2 = std::max(max_r2, x * x + y * y); + } + + // 如果有 bulge 圆弧,圆弧中点可能更远,粗略扩大 10% + if (profile_desc.bulges != nullptr) { + double arc_extra = 0.0; + for (uint32_t i = 0; i < profile_desc.point_number; ++i) { + const double b = profile_desc.bulges[i]; + if (std::abs(b) < 1e-12) continue; + // 圆弧中点偏离弦的距离 = chord/2 * |b| + const uint32_t j = (i + 1) % profile_desc.point_number; + const double dx = profile_desc.points[j].x - profile_desc.points[i].x; + const double dy = profile_desc.points[j].y - profile_desc.points[i].y; + arc_extra = std::max(arc_extra, 0.5 * std::sqrt(dx * dx + dy * dy) * std::abs(b)); + } + return std::sqrt(max_r2) + arc_extra; + } + return std::sqrt(max_r2); +} + void extrude_polyline_geometry_t::build() { const auto& profile_desc = this->descriptor.profiles[0]; const auto& axis_desc = this->descriptor.axis; - // 对 axis 折线插入微小圆角弧 - std::cout << "[extrude_polyline_geometry_t::build]: inserting tiny curve for axis" - << " segment_ratio=" << 0.1 << ", min_turn_angle_deg=" << 0.0 << "\n"; + const double profile_max_radius = compute_profile_max_radius(profile_desc); + const double axis_min_fillet_radius = profile_max_radius * 0.01; + + std::cout << "[extrude_polyline_geometry_t::build] profile_max_radius=" << profile_max_radius + << ", axis_min_fillet_radius=" << axis_min_fillet_radius << "\n"; + std::vector filleted_axis_pts; std::vector filleted_axis_bgs; - const fillet_config_t axis_fillet_cfg{/*segment_ratio=*/0.1, - /*min_turn_angle_deg=*/0.0}; + const fillet_config_t axis_fillet_cfg{ + /*segment_ratio=*/0.15, + /*min_turn_angle_deg=*/0.5, + /*min_fillet_radius=*/axis_min_fillet_radius, + /*is_axis=*/true}; insert_polyline_corner_fillets(axis_desc, filleted_axis_pts, filleted_axis_bgs, axis_fillet_cfg); - // 构建圆角后的 axis 临时描述符 polyline_descriptor_t filleted_axis_desc{}; filleted_axis_desc.point_number = static_cast(filleted_axis_pts.size()); filleted_axis_desc.points = filleted_axis_pts.data(); @@ -28,20 +64,23 @@ void extrude_polyline_geometry_t::build() filleted_axis_desc.is_close = axis_desc.is_close; std::cout << "[extrude_polyline_geometry_t::build] " - << "original axis points: " << axis_desc.point_number << ", after fillet: " << filleted_axis_desc.point_number - << "\n"; + << "axis: " << axis_desc.point_number << " pts → " << filleted_axis_desc.point_number << " pts (after fillet)\n"; + + axis_geom.build_as_axis(filleted_axis_desc, profile_desc.reference_normal, axis_to_world, polyline_aabb); - axis_geom.build_as_axis(filleted_axis_desc, // 改为 filleted_axis_desc - profile_desc.reference_normal, - axis_to_world, - polyline_aabb); + for (uint32_t k = 0; k < axis_desc.point_number; ++k) { + polyline_aabb.extend(Eigen::Vector3d(axis_desc.points[k].x, axis_desc.points[k].y, axis_desc.points[k].z)); + } + polyline_aabb.min().array() -= profile_max_radius; + polyline_aabb.max().array() += profile_max_radius; - std::cout << "[extrude_polyline_geometry_t::build]: inserting tiny curve for profile" - << " segment_ratio=" << 0.05 << ", min_turn_angle_deg=" << 0.0 << "\n"; + // 对 profile 截面插入圆角(不需要最小半径约束) std::vector filleted_profile_pts; std::vector filleted_profile_bgs; - const fillet_config_t profile_fillet_cfg{/*segment_ratio=*/0.1, - /*min_turn_angle_deg=*/0.0}; + const fillet_config_t profile_fillet_cfg{/*segment_ratio=*/0.05, + /*min_turn_angle_deg=*/0.5, + /*min_fillet_radius=*/0.0, // profile 自身不需要最小半径约束 + /*is_axis=*/false}; insert_polyline_corner_fillets(profile_desc, filleted_profile_pts, filleted_profile_bgs, profile_fillet_cfg); polyline_descriptor_t filleted_profile_desc{}; @@ -53,11 +92,9 @@ void extrude_polyline_geometry_t::build() filleted_profile_desc.is_close = profile_desc.is_close; std::cout << "[extrude_polyline_geometry_t::build] " - << "original profile points: " << profile_desc.point_number - << ", after fillet: " << filleted_profile_desc.point_number - << "\n"; + << "profile: " << profile_desc.point_number << " pts → " << filleted_profile_desc.point_number + << " pts (after fillet)\n"; - // 从 axis_to_world 中提取投影方向 const Eigen::Vector3d proj_x = axis_to_world.matrix().col(0).head<3>(); // Binormal const Eigen::Vector3d proj_y = axis_to_world.matrix().col(1).head<3>(); // Normal diff --git a/primitive_process/src/subface/geometry/geometry_data.cpp b/primitive_process/src/subface/geometry/geometry_data.cpp index f3b98ca..bc1e4d6 100644 --- a/primitive_process/src/subface/geometry/geometry_data.cpp +++ b/primitive_process/src/subface/geometry/geometry_data.cpp @@ -205,8 +205,10 @@ void polyline_geometry_data::build_as_axis(const polyline_descriptor_t& profile_aabb); const auto& profile_aabb_min = profile_aabb.min(); const auto& profile_aabb_max = profile_aabb.max(); - aabb = aabb_t(Eigen::Vector3d(profile_aabb_min.y(), 0.0, profile_aabb_min.x()), - Eigen::Vector3d(profile_aabb_max.y(), 0.0, profile_aabb_max.x())); + aabb = aabb_t( + Eigen::Vector3d(profile_aabb_min.y(), 0.0, profile_aabb_min.x()), + Eigen::Vector3d(profile_aabb_max.y(), 0.0, profile_aabb_max.x()) + ); } void polyline_geometry_data::build_as_axis(polyline_descriptor_t&& desc, @@ -282,94 +284,26 @@ void polyline_geometry_data::build_as_axis(polyline_descriptor_t&& frac = 1.0; } - // 调试控制:每1000次调用打印一次调试信息 - static int debug_counter = 0; - constexpr int DEBUG_INTERVAL = 10000; - bool should_debug = (++debug_counter % DEBUG_INTERVAL == 0); - - if (should_debug) { - std::cout << "[DEBUG calculate_normal] 调用#" << debug_counter << " t=" << t << " n=" << n << " frac=" << frac - << " 总段数=" << this->start_indices.size() << " 类型=" << (this->thetas[n] <= EPSILON ? "直线" : "圆弧") - << std::endl; - } - const auto iter = this->vertices.begin() + this->start_indices[n]; if (this->thetas[n] <= EPSILON) { // 直线段:计算切向量然后获取法向量 const auto temp = (*(iter + 1) - *iter).normalized(); - - if (should_debug) { - std::cout << "[DEBUG 直线段] 起点: (" << iter->x() << ", " << iter->y() << ")" - << " 终点: (" << (iter + 1)->x() << ", " << (iter + 1)->y() << ")" - << " 切向量: (" << temp.x() << ", " << temp.y() << ")" - << " 切向量长度: " << temp.norm() << std::endl; - } - Eigen::Vector2d normal = {-temp.y(), temp.x()}; - - if (should_debug) { - std::cout << "[DEBUG 直线段] 法向量: (" << normal.x() << ", " << normal.y() << ")" - << " 法向量长度: " << normal.norm() << std::endl; - } - return normal; } else { // 圆弧段:计算法向量方向 const Eigen::Vector2d vec_ca = *iter - *(iter + 1); // a - c const Eigen::Vector2d vec_cd = *(iter + 2) - *(iter + 1); // d - c - if (should_debug) { - std::cout << "[DEBUG 圆弧段] 起点A: (" << iter->x() << ", " << iter->y() << ")" - << " 圆心C: (" << (iter + 1)->x() << ", " << (iter + 1)->y() << ")" - << " 中间点D: (" << (iter + 2)->x() << ", " << (iter + 2)->y() << ")" - << " 终点B: (" << (iter + 3)->x() << ", " << (iter + 3)->y() << ")" << std::endl; - std::cout << "[DEBUG 圆弧段] vec_ca: (" << vec_ca.x() << ", " << vec_ca.y() << ") 长度: " << vec_ca.norm() - << " vec_cd: (" << vec_cd.x() << ", " << vec_cd.y() << ") 长度: " << vec_cd.norm() << std::endl; - } - const double cross = vec_ca.x() * vec_cd.y() - vec_ca.y() * vec_cd.x(); const double bulge_sign = (cross > 1e-12) ? 1.0 : -1.0; - if (should_debug) { - std::cout << "[DEBUG 圆弧段] 叉积=" << cross << " 方向sign=" << bulge_sign << " theta=" << this->thetas[n] << "(" - << (this->thetas[n] * 180.0 / pi) << "°)" - << " 半径=" << vec_ca.norm() << std::endl; - } - const auto alpha = std::cos(frac * this->thetas[n]); const auto beta = std::sin(frac * this->thetas[n]); - if (should_debug) { - std::cout << "[DEBUG 圆弧段] 参数计算: frac*theta=" << (frac * this->thetas[n]) << "(" - << (frac * this->thetas[n] * 180.0 / pi) << "°)" - << " alpha=cos=" << alpha << " beta=sin=" << beta << std::endl; - } - // 计算法向量 Eigen::Vector2d normal = bulge_sign * ((alpha + beta) * *(iter + 1) - alpha * *iter - beta * *(iter + 2)); - - if (should_debug) { - std::cout << "[DEBUG 圆弧段] 法向量: (" << normal.x() << ", " << normal.y() << ")" - << " 长度: " << normal.norm() << std::endl; - - // 检查法向量长度是否正常 - double norm_length = normal.norm(); - if (norm_length < 0.5 || norm_length > 2.0) { - std::cout << "[DEBUG 警告] 法向量长度异常: " << norm_length << std::endl; - - // 输出详细分量信息用于调试 - Eigen::Vector2d comp1 = (alpha + beta) * *(iter + 1); - Eigen::Vector2d comp2 = -alpha * *iter; - Eigen::Vector2d comp3 = -beta * *(iter + 2); - Eigen::Vector2d sum = comp1 + comp2 + comp3; - std::cout << "[DEBUG 分量详情] comp1=(" << comp1.x() << "," << comp1.y() << ")" - << " comp2=(" << comp2.x() << "," << comp2.y() << ")" - << " comp3=(" << comp3.x() << "," << comp3.y() << ")" - << " 未缩放向量=(" << sum.x() << "," << sum.y() << ")" << std::endl; - } - } - return normal; } } @@ -389,11 +323,12 @@ void polyline_geometry_data::build_as_axis(polyline_descriptor_t&& auto make_vertex_3d = [&](const Eigen::Vector2d& v) -> Eigen::Vector3d { if (this->is_axis) - return {v.y(), 0., v.x()}; + return {v.y(), 0., v.x()}; // Axis: (x,z) -> (z,0,x) else - return {v.x(), v.y(), 0.}; + return {v.x(), v.y(), 0.}; // Profile: (x,y) -> (x,y,0) }; + // 直线段最近点计算 auto line_cpm = [&](auto index) -> comparable_closest_param_t { const auto iter = this->vertices.begin() + this->start_indices[index]; const auto line_vec = *(iter + 1) - *iter; @@ -412,48 +347,36 @@ void polyline_geometry_data::build_as_axis(polyline_descriptor_t&& const auto raw_t = line_vec.dot(p_dir); // 投影越界时直接返回较近端点 - // raw_t ≤ 0 说明 P 在起点外侧,无需计算终点距离 if (raw_t <= 0) { Eigen::Vector3d v = make_vertex_3d(*iter); return {v, 0.0, (p - v).norm(), 1., false}; } - // raw_t ≥ len² 说明 P 在终点外侧,无需计算起点距离 if (raw_t >= line_vec_length_2) { Eigen::Vector3d v = make_vertex_3d(*(iter + 1)); return {v, 1.0, (p - v).norm(), 1., false}; } - const auto p_dir_length_2 = p_dir.squaredNorm(); const auto t = raw_t / line_vec_length_2; - Eigen::Vector3d closest_point_3d; - double dist; + // 计算最近点 + const Eigen::Vector2d closest_2d = *iter + t * line_vec; + Eigen::Vector3d closest_point_3d = make_vertex_3d(closest_2d); - if (this->is_axis) { - // Axis - closest_point_3d.x() = (1 - t) * iter->y() + t * (iter + 1)->y(); - closest_point_3d.y() = 0; - closest_point_3d.z() = (1 - t) * iter->x() + t * (iter + 1)->x(); - dist = (p - closest_point_3d).norm(); - } else { - // Profile - closest_point_3d.x() = (1 - t) * iter->x() + t * (iter + 1)->x(); - closest_point_3d.y() = (1 - t) * iter->y() + t * (iter + 1)->y(); - closest_point_3d.z() = 0; + double dist = (p - closest_point_3d).norm(); - dist = std::sqrt(p_dir_length_2 - raw_t * raw_t / line_vec_length_2 + p[2] * p[2]); - } return {closest_point_3d, t, dist, 1., true}; }; + // 圆弧段最近点计算 auto circle_cpm = [&](auto index) -> comparable_closest_param_t { const auto iter = this->vertices.begin() + this->start_indices[index]; const auto theta = this->thetas[index]; const auto base_vec1 = *iter - *(iter + 1); // 起点 - 圆心 - const auto base_vec2 = *(iter + 2) - *(iter + 1); // 切线辅助点 d - 圆心 c(非弧终点 b + const auto base_vec2 = *(iter + 2) - *(iter + 1); // 切线辅助点 d - 圆心 c Eigen::Vector2d p_vec; double cross_bv = base_vec1.x() * base_vec2.y() - base_vec1.y() * base_vec2.x(); bool is_cw = (cross_bv < 0); + if (this->is_axis) { p_vec = Eigen::Vector2d(p[2], p[0]) - *(iter + 1); } else { @@ -462,46 +385,41 @@ void polyline_geometry_data::build_as_axis(polyline_descriptor_t&& const auto p_vec_norm = p_vec.norm(); // 查询点到圆心的距离 const auto r = base_vec1.norm(); // 圆弧半径 + const double off_plane = this->is_axis ? p[1] : p[2]; + if (p_vec_norm < EPSILON) { // 查询点恰好在圆心,选弧段起点 - const auto closest_point = *iter; - const auto dis_on_plane = -r; - return { - {closest_point.x(), closest_point.y(), 0}, - 0.0, - std::sqrt(p[2] * p[2] + dis_on_plane * dis_on_plane), - 1., - false - }; + const Eigen::Vector3d closest_point = make_vertex_3d(*iter); + const auto dis_on_plane = -r; + return {closest_point, 0.0, std::sqrt(off_plane * off_plane + dis_on_plane * dis_on_plane), 1., false}; } + const auto local_x = base_vec1.dot(p_vec); const auto local_y = base_vec2.dot(p_vec); double phi = std::atan2(local_y, local_x); - // [DEBUG_CIRCLE_CPM] 对凹弧(CW)打印 phi 分布,验证是否全为负 - { - static std::atomic cw_cnt{0}; - if (is_cw && ++cw_cnt <= 100) { - std::cout << "[DEBUG_CIRCLE_CPM] CW弧 #" << cw_cnt << " seg=" << index << " phi=" << phi << " theta=" << theta - << " phi_in_range=[" << (-theta) << "," << 0 << "]" - << " cross_bv=" << cross_bv << " p_vec=(" << p_vec.x() << "," << p_vec.y() << ")" - << " base_vec1=(" << base_vec1.x() << "," << base_vec1.y() << ")" - << " base_vec2=(" << base_vec2.x() << "," << base_vec2.y() << ")" - << " -> fallback_to_endpoint=" << (phi < -EPSILON || phi > theta + 1e-9 ? "YES" : "NO") << "\n"; + + // 根据圆弧转向调整 phi + if (!is_cw) { + // CCW: 有效区间 [0, theta] + if (theta > pi + 1e-9) { + if (phi < -EPSILON) phi += two_pi; + } else { + if (phi < -EPSILON) phi = -1.0; // 触发端点回退 } - } - if (theta > pi + 1e-9) { - if (phi < -EPSILON) { phi += two_pi; } } else { - // 劣弧:phi 只应在 [0, theta],负值直接视为 gap - if (phi < -EPSILON) { - phi = -1.0; // 强制触发端点回退 + // CW: 有效区间 [-theta, 0],翻转后统一用 [0, theta] 处理 + phi = -phi; // 将 CW 的 phi 反号,使有效范围变为 [0, theta] + if (theta > pi + 1e-9) { + if (phi < -EPSILON) phi += two_pi; + } else { + if (phi < -EPSILON) phi = -1.0; } } // 弧段越界时返回较近端点 if (phi < -1e-9 || phi > theta + 1e-9) { - const Eigen::Vector3d start_3d = {iter->x(), iter->y(), 0.}; - const Eigen::Vector3d end_3d = {(iter + 3)->x(), (iter + 3)->y(), 0.}; + const Eigen::Vector3d start_3d = make_vertex_3d(*iter); + const Eigen::Vector3d end_3d = make_vertex_3d(*(iter + 3)); const double dist_start = (p - start_3d).norm(); const double dist_end = (p - end_3d).norm(); if (dist_start <= dist_end) @@ -510,19 +428,20 @@ void polyline_geometry_data::build_as_axis(polyline_descriptor_t&& return {end_3d, 1.0, dist_end, 1., false}; } - const auto dis_on_plane = p_vec_norm - r; - const auto closest_point = p_vec / p_vec_norm * r + *(iter + 1); + const auto dis_on_plane = p_vec_norm - r; + const Eigen::Vector2d closest_2d = p_vec / p_vec_norm * r + *(iter + 1); + Eigen::Vector3d closest_3d = make_vertex_3d(closest_2d); return { - {closest_point.x(), closest_point.y(), 0}, - phi / theta, - std::sqrt(p[2] * p[2] + dis_on_plane * dis_on_plane), - 1., + closest_3d, + phi / theta, + std::sqrt(off_plane * off_plane + dis_on_plane * dis_on_plane), + 1., true }; }; - // 单次遍历 + // 计算每个线段的最近点 std::vector closest_params(this->thetas.size()); std::vector indices(this->thetas.size()); std::iota(indices.begin(), indices.end(), 0); @@ -533,10 +452,10 @@ void polyline_geometry_data::build_as_axis(polyline_descriptor_t&& // 全局最小值:segment 内局部 t ∈ [0,1],加上段索引得到全局 t const auto iter = std::min_element(closest_params.begin(), closest_params.end()); iter->t += static_cast(std::distance(closest_params.begin(), iter)); - return { + return { line_closest_param_t{std::move(iter->point), iter->t, iter->is_peak_value}, iter->dist * iter->dist_sign - }; + }; } [[nodiscard]] bool polyline_geometry_data::pmc(const Eigen::Ref& p, diff --git a/primitive_process/src/subface/geometry/polyline_fillet.cpp b/primitive_process/src/subface/geometry/polyline_fillet.cpp index 3428e60..a34df61 100644 --- a/primitive_process/src/subface/geometry/polyline_fillet.cpp +++ b/primitive_process/src/subface/geometry/polyline_fillet.cpp @@ -1,6 +1,5 @@ #include #include -//#include namespace internal { @@ -105,115 +104,89 @@ inline void push_point(std::vector& out_points, } // anonymous namespace -void insert_polyline_corner_fillets(const polyline_descriptor_t& profile, - std::vector& out_points, - std::vector& out_bulges, - const fillet_config_t& cfg) + +void insert_polyline_corner_fillets(const polyline_descriptor_t& desc, + std::vector& out_points, + std::vector& out_bulges, + const fillet_config_t& cfg) { out_points.clear(); out_bulges.clear(); - const uint32_t n = profile.point_number; - const bool closed = profile.is_close; + const uint32_t n = desc.point_number; + const bool closed = desc.is_close; + + std::function to_2d; + std::function to_3d; + + if (cfg.is_axis) { + // axis:XZ 平面 + to_2d = [](const vector3d& p) -> Eigen::Vector2d {return {p.x, p.z};}; + to_3d = [](const Eigen::Vector2d& q, double fixed_y) -> vector3d { return {q.x(), fixed_y, q.y()};}; + } else { + // profile:XY 平面 + to_2d = [](const vector3d& p) -> Eigen::Vector2d {return {p.x, p.y};}; + to_3d = [](const Eigen::Vector2d& q, double fixed_z) -> vector3d {return {q.x(), q.y(), fixed_z};}; + } - // ── 退化情况:点数过少,无内部衔接顶点可处理 ──────────────────────── - // 闭合:至少需要 3 点才有顶点(含衔接) - // 不闭合:至少需要 3 点才有内部顶点(至少 1 个 interior vertex) + // 退化情况 if (n < 3) { for (uint32_t i = 0; i < n; ++i) { - out_points.push_back(profile.points[i]); - // 只有前n-1个顶点需要凸度(开放折线) - if (i < n - 1) { out_bulges.push_back(profile.bulges ? profile.bulges[i] : 0.0); } + out_points.push_back(desc.points[i]); + if (i < n - 1) out_bulges.push_back(desc.bulges ? desc.bulges[i] : 0.0); } return; } std::vector pts(n); std::vector bulges(n); + // fixed_coord:axis→y分量(恒=0),profile→z分量(恒=0) + std::vector fixed_coords(n); + for (uint32_t i = 0; i < n; ++i) { - pts[i] = {profile.points[i].x, profile.points[i].y}; - bulges[i] = profile.bulges ? profile.bulges[i] : 0.0; + pts[i] = to_2d(desc.points[i]); + bulges[i] = desc.bulges ? desc.bulges[i] : 0.0; + fixed_coords[i] = cfg.is_axis ? desc.points[i].y // axis:保留 y(=0) + : desc.points[i].z; // profile:保留 z(=0) } - // ── 逐顶点计算圆角 ──────────────────────────────────────────────────── - // 闭合:处理全部 n 个顶点(首尾环形相连) - // 不闭合:仅处理内部顶点 [1, n-2](首尾为端点,无入/出射配对) + // 计算每个顶点的圆角 std::vector corners(n); - if (closed) { - for (uint32_t i = 0; i < n; ++i) { - const uint32_t prev = (i + n - 1) % n; - const uint32_t next = (i + 1) % n; - corners[i] = compute_corner(pts, bulges, i, prev, next, cfg); - } + for (uint32_t i = 0; i < n; ++i) corners[i] = compute_corner(pts, bulges, i, (i + n - 1) % n, (i + 1) % n, cfg); } else { - // corners[0] 和 corners[n-1] 保持默认 inactive - for (uint32_t i = 1; i <= n - 2; ++i) { corners[i] = compute_corner(pts, bulges, i, i - 1, i + 1, cfg); } + for (uint32_t i = 1; i <= n - 2; ++i) corners[i] = compute_corner(pts, bulges, i, i - 1, i + 1, cfg); } + auto push_pt = [&](const Eigen::Vector2d& p2d, double fixed, double bulge) { + out_points.push_back(to_3d(p2d, fixed)); + out_bulges.push_back(bulge); + }; + out_points.reserve(n * 2); out_bulges.reserve(n * 2); if (closed) { - // 闭合:环形迭代,输出隐式首尾相连 - // - // 对每段 i(pts[i]→pts[next],bulge=bulges[i]): - // 1.段起点:corners[i].active ? trim_out[i] : pts[i] - // 2.若 corners[next].active:插入 trim_in[next](附 fillet_bulge[next]) - // 下一迭代自然从 trim_out[next] 开始 for (uint32_t i = 0; i < n; ++i) { - const uint32_t next = (i + 1) % n; - const double z_i = profile.points[i].z; - const double z_nxt = profile.points[next].z; - - const Eigen::Vector2d& seg_start = corners[i].active ? corners[i].trim_out : pts[i]; - - push_point(out_points, out_bulges, seg_start, z_i, bulges[i]); - - if (corners[next].active) { - push_point(out_points, out_bulges, corners[next].trim_in, z_nxt, corners[next].fillet_bulge); - } + const uint32_t next = (i + 1) % n; + const auto& seg_start = corners[i].active ? corners[i].trim_out : pts[i]; + push_pt(seg_start, fixed_coords[i], bulges[i]); + if (corners[next].active) push_pt(corners[next].trim_in, fixed_coords[next], corners[next].fillet_bulge); } } else { - // 不闭合:线性迭代,明确保留首尾端点 - // - // 对每段 i(0..n-2),输出段起点;若 next 顶点有圆角(且非末点), - // 则额外插入 trim_in[next](附 fillet_bulge[next])作为本段实际终点, - // 下一迭代从 trim_out[next] 开始。 - for (uint32_t i = 0; i < n - 1; ++i) { - const uint32_t next = i + 1; - const double z_i = profile.points[i].z; - const double z_nxt = profile.points[next].z; - - // 段起点: - // i==0 → 始终为 pts[0](端点,没有圆角) - // corners[i].active → trim_out[i](由上一迭代的圆角偏移得到) - // 否则 → pts[i] - const Eigen::Vector2d& seg_start = (i == 0) ? pts[0] : corners[i].active ? corners[i].trim_out : pts[i]; - - // 若 next 有圆角(且 next 不是末点,末点无圆角): - // 本段实际终点为 trim_in[next],之后插入圆弧, - // 下一迭代从 trim_out[next] 开始 - if (next < n - 1 && corners[next].active) { - push_point(out_points, out_bulges, seg_start, z_i, bulges[i]); - push_point(out_points, out_bulges, corners[next].trim_in, z_nxt, corners[next].fillet_bulge); - } else { - // next 无圆角(或 next 是末点):正常输出段起点 - push_point(out_points, out_bulges, seg_start, z_i, bulges[i]); - } + const uint32_t next = i + 1; + const auto& seg_start = (i == 0) ? pts[0] : corners[i].active ? corners[i].trim_out : pts[i]; + push_pt(seg_start, fixed_coords[i], bulges[i]); + if (next < n - 1 && corners[next].active) + push_pt(corners[next].trim_in, fixed_coords[next], corners[next].fillet_bulge); } - - // 末点:始终为 pts[n-1](端点,没有圆角) - out_points.push_back(profile.points[n - 1]); - //out_bulges.push_back(0.0); + out_points.push_back(desc.points[n - 1]); // 末点原样保留 } - if (closed) { + if (closed) assert(out_points.size() == out_bulges.size()); - } else { - assert(out_bulges.size() + 1 == out_points.size()); // 开放折线:凸度数量 = 点数 - 1 - } + else + assert(out_bulges.size() + 1 == out_points.size()); } - } // namespace internal \ No newline at end of file diff --git a/primitive_process/src/subface/simple/extrude_helixline_side_face.cpp b/primitive_process/src/subface/simple/extrude_helixline_side_face.cpp index b734400..551d251 100644 --- a/primitive_process/src/subface/simple/extrude_helixline_side_face.cpp +++ b/primitive_process/src/subface/simple/extrude_helixline_side_face.cpp @@ -210,12 +210,6 @@ std::tuple extrude_helixline_side_function_impl Eigen::Vector3d axis_normal = face->get_axis_geom().calculate_normal(t_axis); Eigen::Vector3d B = axis_normal.cross(axis_tangent).normalized(); - //Eigen::Transform TBN; - //TBN.matrix().col(0).head<3>() = B; - //TBN.matrix().col(1).head<3>() = axis_normal; - //TBN.matrix().col(2).head<3>() = axis_tangent; - //TBN.matrix().col(3).head<3>() = axis_point; - //TBN.matrix()(3, 3) = 1.0; auto TBN = get_local_TBN_helixline(face->get_axis_geom(), axis_point, t_axis); // ==================== 处理 Profile 参数 ====================