From a93a179b2cdd09023f71f8f913ad6538c5ebb378 Mon Sep 17 00:00:00 2001 From: linchforever <2766643922@qq.com> Date: Sat, 18 Apr 2026 20:46:21 +0800 Subject: [PATCH] feat: automatically calculate the parameters for inserting arcs --- .../subface/geometry/polyline_fillet.hpp | 18 +- .../geometry/extrude_helixline_geometry.cpp | 5 +- .../geometry/extrude_polyline_geometry.cpp | 20 +- .../src/subface/geometry/polyline_fillet.cpp | 251 ++++++++++++------ 4 files changed, 187 insertions(+), 107 deletions(-) diff --git a/primitive_process/interface/subface/geometry/polyline_fillet.hpp b/primitive_process/interface/subface/geometry/polyline_fillet.hpp index 47fadd2..7c33a46 100644 --- a/primitive_process/interface/subface/geometry/polyline_fillet.hpp +++ b/primitive_process/interface/subface/geometry/polyline_fillet.hpp @@ -6,14 +6,20 @@ namespace internal { struct fillet_config_t { - double segment_ratio = 0.05 ;// 圆角切除量占相邻两段中较短段弦长的比例 - double min_turn_angle_deg = 0.5; // 低于此角度(度)的衔接处视为共线,跳过 - bool is_axis = false; - double max_fillet_turn_angle_deg = 135.0; // 超过此转角不做圆角 - double min_fillet_radius = 1e-3; // 圆角半径下限 + bool auto_mode = true; + double max_segment_fraction = 0.10; // 每处圆角弧允许裁切相邻线段的最大比例 + + bool is_axis = false; + + double min_turn_angle_deg = 0.5; // 小于此角度视为共线,跳过 + double max_fillet_turn_angle_deg = 179.0; // 大于此角度视为极端折叠,跳过 + + double segment_ratio = 0.05; // 相对比例模式:trim = ratio × min_chord + double min_fillet_radius = 1e-3; // 圆弧半径下限(用于过滤退化圆弧) + double absolute_fillet_radius = 0.0; // 绝对半径模式:> 0 时以此为目标半径 }; -// 对 2D profile / axis 多段线的衔接顶点插入微小圆角弧,实现 G1 连续。 +// 对 2D profile / axis 多段线的衔接顶点插入微小圆角弧 void insert_polyline_corner_fillets(const polyline_descriptor_t& profile, std::vector& out_points, std::vector& out_bulges, diff --git a/primitive_process/src/subface/geometry/extrude_helixline_geometry.cpp b/primitive_process/src/subface/geometry/extrude_helixline_geometry.cpp index 3987238..1faab2d 100644 --- a/primitive_process/src/subface/geometry/extrude_helixline_geometry.cpp +++ b/primitive_process/src/subface/geometry/extrude_helixline_geometry.cpp @@ -15,9 +15,8 @@ void extrude_helixline_geometry_t::build() // 对 profile 各衔接顶点插入微小圆角弧 std::vector filleted_pts; std::vector filleted_bgs; - const fillet_config_t fillet_cfg{/*segment_ratio=*/0.05, - /*min_turn_angle_deg=*/0.5, - /*is_axis=*/true}; + fillet_config_t fillet_cfg{}; + fillet_cfg.max_segment_fraction = 0.3; 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 a22c60e..7e17c35 100644 --- a/primitive_process/src/subface/geometry/extrude_polyline_geometry.cpp +++ b/primitive_process/src/subface/geometry/extrude_polyline_geometry.cpp @@ -9,12 +9,10 @@ void extrude_polyline_geometry_t::build() const auto& profile_desc = this->descriptor.profiles[0]; const auto& axis_desc = this->descriptor.axis; + fillet_config_t axis_fillet_cfg{}; + axis_fillet_cfg.is_axis = true; std::vector filleted_axis_pts; std::vector filleted_axis_bgs; - const fillet_config_t axis_fillet_cfg{ - /*segment_ratio=*/0.01, - /*min_turn_angle_deg=*/0.5, - /*is_axis=*/true}; insert_polyline_corner_fillets(axis_desc, filleted_axis_pts, filleted_axis_bgs, axis_fillet_cfg); polyline_descriptor_t filleted_axis_desc{}; @@ -25,16 +23,11 @@ void extrude_polyline_geometry_t::build() filleted_axis_desc.reference_normal = axis_desc.reference_normal; filleted_axis_desc.is_close = axis_desc.is_close; - std::cout << "[extrude_polyline_geometry_t::build] " - << "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); + fillet_config_t profile_fillet_cfg{}; std::vector filleted_profile_pts; std::vector filleted_profile_bgs; - const fillet_config_t profile_fillet_cfg{/*segment_ratio=*/0.05, - /*min_turn_angle_deg=*/0.5, - /*is_axis=*/false}; insert_polyline_corner_fillets(profile_desc, filleted_profile_pts, filleted_profile_bgs, profile_fillet_cfg); polyline_descriptor_t filleted_profile_desc{}; @@ -45,9 +38,10 @@ void extrude_polyline_geometry_t::build() filleted_profile_desc.reference_normal = profile_desc.reference_normal; filleted_profile_desc.is_close = profile_desc.is_close; - std::cout << "[extrude_polyline_geometry_t::build] " - << "profile: " << profile_desc.point_number << " pts → " << filleted_profile_desc.point_number - << " pts (after fillet)\n"; + sanitize_negative_bulge_self_intersections(filleted_profile_pts, + filleted_profile_bgs, + /*is_axis=*/false, + filleted_profile_desc.is_close); // 从 axis_to_world 中提取投影方向 const Eigen::Vector3d proj_x = axis_to_world.matrix().col(0).head<3>(); // Binormal diff --git a/primitive_process/src/subface/geometry/polyline_fillet.cpp b/primitive_process/src/subface/geometry/polyline_fillet.cpp index 201fdcd..79d4fa7 100644 --- a/primitive_process/src/subface/geometry/polyline_fillet.cpp +++ b/primitive_process/src/subface/geometry/polyline_fillet.cpp @@ -46,12 +46,51 @@ struct Corner { double fillet_bulge = 0; // 圆弧的 bulge }; +// 计算弧段 A→B(bulge b)的真实弧长,对直线段直接返回弦长。 +static double seg_arc_len(const Eigen::Vector2d& A, const Eigen::Vector2d& B, double bulge) +{ + const double chord = (B - A).norm(); + if (std::abs(bulge) < 1e-10) return chord; + // 弧段包含角 theta_arc = 4·atan(|b|);弦与半径关系:chord = 2R·sin(theta_arc/2) + const double theta_arc = 4.0 * std::atan(std::abs(bulge)); + // 避免 sin(theta_arc/2) → 0 的数值退化 + const double sin_half = std::sin(theta_arc * 0.5); + if (sin_half < 1e-15) return chord; + return chord * theta_arc / (2.0 * sin_half); +} + +static constexpr double kFilletDensity = 0.06; + +static double compute_per_corner_min_trim(double turn_angle, + const Eigen::Vector2d& prev_pt, + const Eigen::Vector2d& cur_pt, + const Eigen::Vector2d& next_pt, + double bulge_in, + double bulge_out, + double max_fraction) +{ + const double arc_len_in = seg_arc_len(prev_pt, cur_pt, bulge_in); + const double arc_len_out = seg_arc_len(cur_pt, next_pt, bulge_out); + const double min_len = std::min(arc_len_in, arc_len_out); + + // 曲率等化公式 + const double cos_q = std::cos(turn_angle / 4.0); // cos(θ/4) + const double R_corner = 2.0 * kFilletDensity * cos_q * cos_q * min_len; + const double trim_nat = R_corner * std::tan(turn_angle / 2.0); + + // 上限:trim 是直线裁切量,需与弦长比较 + const double chord_in = (cur_pt - prev_pt).norm(); + const double chord_out = (next_pt - cur_pt).norm(); + return std::min({trim_nat, chord_in * max_fraction, chord_out * max_fraction}); +} + // 计算顶点 i 的圆角参数 -// @param pts 所有顶点 +// @param pts 所有顶点(2D) // @param bulges 所有段的 bulge(bulges[i] 对应段 i→i+1,bulges[prev] 对应入射段) // @param i 当前顶点索引 // @param prev 入射段起点索引 // @param next 出射段终点索引 +// @param cfg 圆角配置 Corner compute_corner(const std::vector& pts, const std::vector& bulges, uint32_t i, @@ -66,33 +105,52 @@ Corner compute_corner(const std::vector& pts, const double cos_a = std::clamp(T_in.dot(T_out), -1.0, 1.0); const double turn_angle = std::acos(cos_a); + const double half_turn = turn_angle / 2.0; + // 共线判断:转角过小,无需插入圆弧 const double min_turn = cfg.min_turn_angle_deg * (pi / 180.0); - if (turn_angle < min_turn) return c; // 视为共线,不处理 - - // 转角接近 180° 时,fillet 弧两端点几乎重合,弧半径趋近于零。 - // 此时 fillet 无法在当前网格分辨率下被正确表达,应跳过以避免几何崩溃。 - const double max_fillet_turn_angle_deg = cfg.max_fillet_turn_angle_deg; - if (turn_angle > max_fillet_turn_angle_deg * (pi / 180.0)) { - std::cout << "转角 " << turn_angle * 180.0 / pi << "° 超过阈值,跳过圆角(避免退化弧)" << std::endl; - return c; - } + if (turn_angle < min_turn) return c; + + // 接近 180° 的折叠,圆弧几何退化,跳过 + const double max_turn = cfg.max_fillet_turn_angle_deg * (pi / 180.0); + if (turn_angle > max_turn) return c; + + double trim = 0.0; + if (cfg.auto_mode) { + // 依据局部转角和相邻弧段长度计算最小圆弧, + trim = compute_per_corner_min_trim(turn_angle, + pts[prev], + pts[i], + pts[next], + bulges[prev], + bulges[i], + cfg.max_segment_fraction); + if (trim < 1e-15) return c; // 近似共线,跳过 + + } else if (cfg.absolute_fillet_radius > 0.0) { + // 绝对半径 + const double chord_in = (pts[i] - pts[prev]).norm(); + const double chord_out = (pts[next] - pts[i]).norm(); + const double tan_half = std::tan(half_turn); + trim = cfg.absolute_fillet_radius * tan_half; + trim = std::min({trim, chord_in * 0.1, chord_out * 0.1}); + if (trim < 1e-15) return c; - const double chord_in = (pts[i] - pts[prev]).norm(); - const double chord_out = (pts[next] - pts[i]).norm(); - const double trim = std::min({std::min(chord_in, chord_out) * cfg.segment_ratio, chord_in * 0.45, chord_out * 0.45}); - - // 计算实际 fillet 圆弧半径并与最小可分辨阈值比较 - // R_fillet = trim / tan(turn_angle/2) - const double half_turn = turn_angle / 2.0; - const double R_fillet = (std::tan(half_turn) > 1e-9) ? trim / std::tan(half_turn) : 0.0; - if (R_fillet < cfg.min_fillet_radius) { - std::cout << "圆角半径 " << R_fillet << " 低于最小阈值 " << cfg.min_fillet_radius << ",跳过圆角" << std::endl; - return c; + } else { + // 相对比例 + const double chord_in = (pts[i] - pts[prev]).norm(); + const double chord_out = (pts[next] - pts[i]).norm(); + trim = std::min({std::min(chord_in, chord_out) * cfg.segment_ratio, chord_in * 0.1, chord_out * 0.1}); + if (trim < 1e-15) return c; } - if (trim < 1e-12) return c; + // 额外检查半径下限 + if (!cfg.auto_mode) { + const double R_fillet = (std::tan(half_turn) > 1e-15) ? trim / std::tan(half_turn) : 0.0; + if (R_fillet < cfg.min_fillet_radius) return c; + } + // 计算圆弧起终点及 bulge c.trim_in = pts[i] - trim * T_in; c.trim_out = pts[i] + trim * T_out; @@ -108,9 +166,6 @@ Corner compute_corner(const std::vector& pts, /** * @brief 将圆弧 A→B(bulge b)裁切为子弧 A_new→B_new 后,重新计算子弧的 bulge。 * - * Bulge 依赖弦长和包含角,裁切端点后两者均变化,必须重算。 - * 对直线段(b≈0)直接返回 0,不做计算。 - * * @param A 原弧起点 * @param B 原弧终点 * @param b 原弧 bulge @@ -124,46 +179,46 @@ static double recompute_subarc_bulge(const Eigen::Vector2d& A, const Eigen::Vector2d& A_new, const Eigen::Vector2d& B_new) { - // 直线段:裁切后仍是直线 if (std::abs(b) < 1e-10) return 0.0; - // 原弧包含角 θ = 4·atan(|b|),半角 = 2·atan(|b|) const double half_theta = 2.0 * std::atan(std::abs(b)); const double sign_b = (b > 0.0) ? 1.0 : -1.0; - // 原弧弦 const Eigen::Vector2d chord = B - A; const double chord_len = chord.norm(); if (chord_len < 1e-12) return b; - // 圆半径与圆心 const double R = chord_len / (2.0 * std::sin(half_theta)); - // 弦中垂线方向(左手正交),对 CCW 弧(b>0)圆心在弦左侧 const Eigen::Vector2d perp_unit(-chord.y() / chord_len, chord.x() / chord_len); - const double d = R * std::cos(half_theta); // 弦中点到圆心的距离 + const double d = R * std::cos(half_theta); const Eigen::Vector2d center = 0.5 * (A + B) + sign_b * d * perp_unit; - // 新起终点在圆上的角度 - const double ang_A = std::atan2(A_new.y() - center.y(), A_new.x() - center.x()); - const double ang_B = std::atan2(B_new.y() - center.y(), B_new.x() - center.x()); + // 用向量叉积/点积计算子弧张角 + const Eigen::Vector2d rA = A_new - center; + const Eigen::Vector2d rB = B_new - center; - double delta = ang_B - ang_A; + const double ang_A = std::atan2(rA.y(), rA.x()); + const double ang_B = std::atan2(rB.y(), rB.x()); + double delta = ang_B - ang_A; - // 规范化:子弧行进方向与原弧一致(CCW 为正,CW 为负) + // 确保 delta 符号与 b 一致,且 |delta| <= 2π if (sign_b > 0.0) { - // 强制 delta 落入 (0, 2π] - delta = std::fmod(delta, 2.0 * pi); - if (delta <= 0.0) delta += 2.0 * pi; + // CCW:delta 应落入 (0, 2π] + while (delta <= 0.0) delta += 2.0 * pi; + while (delta > 2.0 * pi) delta -= 2.0 * pi; } else { - // 强制 delta 落入 [-2π, 0) - delta = std::fmod(delta, 2.0 * pi); - if (delta >= 0.0) delta -= 2.0 * pi; + // CW:delta 应落入 [-2π, 0) + while (delta >= 0.0) delta -= 2.0 * pi; + while (delta < -2.0 * pi) delta += 2.0 * pi; } - double result = std::tan(delta / 4.0); - if ((b > 0) != (result > 0) && std::abs(result) > 1e-9) { - std::cerr << "[BULGE_SIGN_FLIP] original_b=" << b << " recomputed_bulge=" << result << " delta=" << delta - << " ang_A=" << ang_A << " ang_B=" << ang_B << "\n"; + if (std::abs(delta) < 1e-13) { + const double rA_len = rA.norm(); + const double rB_len = rB.norm(); + if (rA_len < 1e-15 || rB_len < 1e-15) return 0.0; + const double full_theta = 4.0 * std::atan(std::abs(b)); + const double ratio = std::abs(delta) / full_theta; + return sign_b * std::abs(b) * ratio; } return std::tan(delta / 4.0); @@ -181,8 +236,6 @@ inline void push_point(std::vector& out_points, /** * @brief 计算点 p 到线段 [a, b] 的最短距离(2D)。 - * @details 将参数 t 限制在 [0,1] 以保证只测量到线段本身,而非无限延长线, - * 从而避免把圆弧圆心到相邻线段延长线的误距离当作相交依据。 */ static double point_to_segment_dist_2d(const Eigen::Vector2d& p, const Eigen::Vector2d& a, const Eigen::Vector2d& b) { @@ -193,6 +246,57 @@ static double point_to_segment_dist_2d(const Eigen::Vector2d& p, const Eigen::Ve return (p - (a + t * ab)).norm(); } +// 计算点 p 到圆弧段(起点A, 终点B, bulge b)的最短距离 +static double point_to_arc_dist_2d(const Eigen::Vector2d& p, const Eigen::Vector2d& A, const Eigen::Vector2d& B, double bulge) +{ + if (std::abs(bulge) < 1e-9) { return point_to_segment_dist_2d(p, A, B); } + + const double half_theta = 2.0 * std::atan(std::abs(bulge)); + const double chord_len = (B - A).norm(); + if (chord_len < 1e-12) return (p - A).norm(); + + const double R = chord_len / (2.0 * std::sin(half_theta)); + const Eigen::Vector2d chord = B - A; + const double sign_b = (bulge > 0.0) ? 1.0 : -1.0; + const Eigen::Vector2d perp(-chord.y() / chord_len, chord.x() / chord_len); + const double d_center = R * std::cos(half_theta); + const Eigen::Vector2d C = 0.5 * (A + B) + sign_b * d_center * perp; + + const Eigen::Vector2d cp = p - C; + const double cp_len = cp.norm(); + + const double ang_A = std::atan2((A - C).y(), (A - C).x()); + const double ang_B = std::atan2((B - C).y(), (B - C).x()); + const double ang_p = std::atan2(cp.y(), cp.x()); + + auto angle_in_arc = [&]() -> bool { + double span = ang_B - ang_A; + if (sign_b > 0.0) { + while (span <= 0.0) span += 2.0 * pi; + while (span > 2.0 * pi) span -= 2.0 * pi; + } else { + while (span >= 0.0) span -= 2.0 * pi; + while (span < -2.0 * pi) span += 2.0 * pi; + } + double rel = ang_p - ang_A; + if (sign_b > 0.0) { + while (rel < 0.0) rel += 2.0 * pi; + while (rel > 2.0 * pi) rel -= 2.0 * pi; + return rel <= std::abs(span); + } else { + while (rel > 0.0) rel -= 2.0 * pi; + while (rel < -2.0 * pi) rel += 2.0 * pi; + return rel >= span; + } + }; + + if (cp_len > 1e-15 && angle_in_arc()) { + return std::abs(cp_len - R); + } else { + return std::min((p - A).norm(), (p - B).norm()); + } +} + } // anonymous namespace /** @@ -200,18 +304,10 @@ static double point_to_segment_dist_2d(const Eigen::Vector2d& p, const Eigen::Ve * * @details * 对于负 bulge(CW 弧,在 CCW profile 中表现为内凹弧),若其圆心到相邻线段的 - * 距离 < 圆弧半径 R,则该弧与相邻边相交。自相交区域内,PMC 的最近点查询会产生 - * 歧义,导致 SDF 符号局部翻转,进而在错误位置生成多余等值面(即图中异常轮廓)。 - * - * 修复策略:将发生自相交的段的 bulge 置 0,退化为直线段,并输出诊断日志。 + * 距离 < 圆弧半径 R,则该弧与相邻边相交。修复策略:将发生自相交的段的 bulge + * 置 0,退化为直线段。 * - * 几何原理(以 CW 弧为例): - * 弦 AB,半角 half_theta = 2*atan(|b|) - * R = |AB| / (2 * sin(half_theta)) - * 圆心 C = midpoint(A,B) + R*cos(half_theta) * perp_right(AB) - * 若 dist(C, 相邻段) < R → 圆与相邻段相交 → 弧自相交 - * - * @param pts_3d polyline 顶点(3D,原地读取,不修改) + * @param pts_3d polyline 顶点 * @param bulges 各段 bulge 值(若检测到自相交则原地置 0) * @param is_axis true = XZ 平面(Axis),false = XY 平面(Profile) * @param closed 是否为闭合多段线 @@ -245,42 +341,31 @@ void sanitize_negative_bulge_self_intersections(const std::vector& pts const double chord_len = (B - A).norm(); if (chord_len < 1e-12) continue; - // 计算 CW 弧的圆心与半径 - // half_theta = theta/2,其中 theta = 4*atan(|b|) 为弧所对圆心角 const double abs_b = std::abs(b); const double half_theta = 2.0 * std::atan(abs_b); const double R = chord_len / (2.0 * std::sin(half_theta)); const Eigen::Vector2d chord_dir = (B - A) / chord_len; - // CW 弧(b < 0)的圆心在弦 AB 的右侧 const Eigen::Vector2d perp_right = {chord_dir.y(), -chord_dir.x()}; - const double d_center = R * std::cos(half_theta); // 弦中点到圆心的距离 + const double d_center = R * std::cos(half_theta); const Eigen::Vector2d center = 0.5 * (A + B) + d_center * perp_right; bool self_intersects = false; - // ---- 检测与前一段 [pts[i-1], A] 的自相交 ---- + // 检测与前一段 [pts[i-1], A] 的自相交 if (closed || i > 0u) { const uint32_t i0 = (i + n - 1u) % n; const double dist = point_to_segment_dist_2d(center, pts[i0], A); if (dist < R * (1.0 - 1e-6)) { self_intersects = true; - std::cout << "[SANITIZE_ARC] 段[" << i << "] 负bulge圆弧" - << "(R=" << R << ", bulge=" << b << ")" - << "圆心到前段距离=" << dist << " < R," - << "检测到与前段自相交,bulge → 0(退化直线)\n"; } } - // ---- 检测与后一段 [B, pts[i+2]] 的自相交 ---- + // 检测与后一段 [B, pts[i+2]] 的自相交 if (!self_intersects && (closed || i + 2u < n)) { const uint32_t i2 = (i + 2u) % n; const double dist = point_to_segment_dist_2d(center, B, pts[i2]); if (dist < R * (1.0 - 1e-6)) { self_intersects = true; - std::cout << "[SANITIZE_ARC] 段[" << i << "] 负bulge圆弧" - << "(R=" << R << ", bulge=" << b << ")" - << "圆心到后段距离=" << dist << " < R," - << "检测到与后段自相交,bulge → 0(退化直线)\n"; } } @@ -304,17 +389,15 @@ void insert_polyline_corner_fillets(const polyline_descriptor_t& desc, if (cfg.is_axis) { // axis:XZ 平面 - to_2d = [](const vector3d& p) -> Eigen::Vector2d { return {p.z, p.x}; }; // 3D -> 2D: (Z, X) - to_3d = [](const Eigen::Vector2d& q, double fixed_y) -> vector3d { - return {q.y(), fixed_y, q.x()}; - }; // 2D -> 3D: (X, Y, Z) = (q.y, fixed_y, q.x) + to_2d = [](const vector3d& p) -> Eigen::Vector2d { return {p.z, p.x}; }; + to_3d = [](const Eigen::Vector2d& q, double fixed_y) -> vector3d { return {q.y(), fixed_y, q.x()}; }; } 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,无法形成转角 if (n < 3) { for (uint32_t i = 0; i < n; ++i) { out_points.push_back(desc.points[i]); @@ -325,21 +408,20 @@ void insert_polyline_corner_fillets(const polyline_descriptor_t& desc, 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] = 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) + fixed_coords[i] = cfg.is_axis ? desc.points[i].y : desc.points[i].z; } - // 计算每个顶点的圆角 + // 计算每个顶点的圆角参数 std::vector corners(n); if (closed) { for (uint32_t i = 0; i < n; ++i) corners[i] = compute_corner(pts, bulges, i, (i + n - 1) % n, (i + 1) % n, cfg); } else { + // 开放曲线:首尾两端无转角 for (uint32_t i = 1; i <= n - 2; ++i) corners[i] = compute_corner(pts, bulges, i, i - 1, i + 1, cfg); } @@ -357,10 +439,10 @@ void insert_polyline_corner_fillets(const polyline_descriptor_t& desc, const Eigen::Vector2d seg_start = corners[i].active ? corners[i].trim_out : pts[i]; const Eigen::Vector2d seg_end = corners[next].active ? corners[next].trim_in : pts[next]; - // 子弧端点已改变,必须重算 bulge + // 重算 bulge const double seg_bulge = recompute_subarc_bulge(pts[i], pts[next], bulges[i], seg_start, seg_end); - push_pt(seg_start, fixed_coords[i], seg_bulge); // 原来是 bulges[i] + push_pt(seg_start, fixed_coords[i], seg_bulge); if (corners[next].active) push_pt(corners[next].trim_in, fixed_coords[next], corners[next].fillet_bulge); } } else { @@ -370,7 +452,6 @@ void insert_polyline_corner_fillets(const polyline_descriptor_t& desc, const Eigen::Vector2d seg_start = (i == 0) ? pts[0] : (corners[i].active ? corners[i].trim_out : pts[i]); const Eigen::Vector2d seg_end = (next < n - 1 && corners[next].active) ? corners[next].trim_in : pts[next]; - const double seg_bulge = recompute_subarc_bulge(pts[i], pts[next], bulges[i], seg_start, seg_end); push_pt(seg_start, fixed_coords[i], seg_bulge);