diff --git a/primitive_process/src/subface/geometry/geometry_data.cpp b/primitive_process/src/subface/geometry/geometry_data.cpp index 0886082..0ad090b 100644 --- a/primitive_process/src/subface/geometry/geometry_data.cpp +++ b/primitive_process/src/subface/geometry/geometry_data.cpp @@ -115,14 +115,8 @@ void polyline_geometry_data::build_internal(const polyline_descriptor_t& if (on_arc) { const Eigen::Vector2d ext_pt = c + r * Eigen::Vector2d(std::cos(ext_angle), std::sin(ext_angle)); aabb->extend(ext_pt); - std::cout << " [ARC_AABB] adding extremum at " << (ext_angle * 180.0 / pi) << "° → (" << ext_pt[0] << "," - << ext_pt[1] << ")\n"; } } - - // 调试输出:AABB 当前状态 - std::cout << " [ARC_AABB] after arc extrema: AABB min=(" << aabb->min().x() << "," << aabb->min().y() << ") max=(" - << aabb->max().x() << "," << aabb->max().y() << ")\n"; } }); } @@ -395,16 +389,13 @@ void polyline_geometry_data::build_as_axis(polyline_descriptor_t&& const auto local_y = base_vec2.dot(p_vec); double phi = std::atan2(local_y, local_x); if (theta > pi + 1e-9) { - if (phi < -EPSILON) { phi += two_pi; } + if (phi < 0.0) { phi += two_pi; } // 优弧:折叠到正值范围 } else { - // 劣弧:phi 只应在 [0, theta],负值直接视为 gap - if (phi < -EPSILON) { - phi = -1.0; // 强制触发端点回退 - } + if (phi < 0.0) { phi = -1.0; } // 劣弧:强制触发端点回退 } // 弧段越界时返回较近端点 - if (phi < -1e-9 || phi > theta + 1e-9) { + if (phi < 0.0 || phi > theta + 1e-9) { 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(); @@ -451,77 +442,61 @@ void polyline_geometry_data::build_as_axis(polyline_descriptor_t&& // Convention: return true = OUTSIDE (SDF > 0), false = INSIDE (SDF <= 0) const Eigen::Vector2d vec = p - closest_param.point.topRows<2>(); - if (closest_param.is_peak_value) { - return vec.dot(this->calculate_normal(closest_param.t)) < 0; - } + if (closest_param.is_peak_value) { return vec.dot(this->calculate_normal(closest_param.t)) < 0; } - constexpr double kChordEps = 1e-12; // 弦长退化阈值 - constexpr double kCrossThresh = 1e-9; // 叉积共线阈值 + constexpr double kCrossThresh = 1e-9; + constexpr double kTangEps = 1e-7; const auto N = static_cast(this->thetas.size()); auto n = static_cast(std::round(closest_param.t)); const bool is_closed = (this->vertices.back() - this->vertices.front()).squaredNorm() < EPSILON; - - // 对闭合曲线,顶点索引 N 等同于顶点 0 if (is_closed && n >= N) n = 0u; - // 顶点 i(0 ≤ i < N)的 2D 坐标存储在 vertices[start_indices[i]]。 - // i == N 时(开放曲线末端),使用 vertices.back()。 - auto get_vertex_2d = [&](uint32_t idx) -> Eigen::Vector2d { - return (idx < N) ? this->vertices[this->start_indices[idx]] : this->vertices.back(); - }; - - const Eigen::Vector2d v_curr = get_vertex_2d(n); - - Eigen::Vector2d v_next = v_curr; - { - const uint32_t n1 = n + 1; - if (n1 <= N) { - v_next = get_vertex_2d(n1); - } else if (is_closed) { - v_next = get_vertex_2d(0); - } - // else: 开放曲线 n == N,无后继,v_next 保持 = v_curr - } - - Eigen::Vector2d v_prev = v_curr; - if (n > 0u) { - v_prev = get_vertex_2d(n - 1u); - } else if (is_closed && N > 1u) { - v_prev = get_vertex_2d(N - 1u); - } + // 入射切线:从段 n-1 的末端取(t = n - ε) + Eigen::Vector2d tang_in; + if (n > 0u) + tang_in = this->calculate_tangent(static_cast(n) - kTangEps); + else if (is_closed && N > 1u) + tang_in = this->calculate_tangent(static_cast(N) - kTangEps); + else + tang_in = this->calculate_tangent(kTangEps); // 开放曲线起点退化 + + // 出射切线:从段 n 的起始取(t = n + ε) + Eigen::Vector2d tang_out; + if (n < N) + tang_out = this->calculate_tangent(static_cast(n) + kTangEps); + else if (is_closed) + tang_out = this->calculate_tangent(kTangEps); + else + tang_out = tang_in; // 开放曲线终点退化 - const Eigen::Vector2d chord_out_raw = v_next - v_curr; - const Eigen::Vector2d chord_in_raw = v_curr - v_prev; - const double len_out = chord_out_raw.norm(); - const double len_in = chord_in_raw.norm(); + const double len_in = tang_in.norm(); + const double len_out = tang_out.norm(); - // 顶点重合,回退到弧/线法线 - if (len_out < kChordEps && len_in < kChordEps) { - const double t_fallback = std::min(static_cast(n) + 1e-9, static_cast(N) - 1e-9); - return vec.dot(this->calculate_normal(t_fallback)) < 0; + if (len_in < 1e-12 && len_out < 1e-12) { + const double t_fb = std::min(static_cast(n) + 1e-9, static_cast(N) - 1e-9); + return vec.dot(this->calculate_normal(t_fb)) < 0; } - // 归一化(单边退化时用另一边代替) - const Eigen::Vector2d chord_out = (len_out >= kChordEps) ? (chord_out_raw / len_out) : (chord_in_raw / len_in); - const Eigen::Vector2d chord_in = (len_in >= kChordEps) ? (chord_in_raw / len_in) : (chord_out_raw / len_out); + const Eigen::Vector2d t_in = (len_in >= 1e-12) ? tang_in / len_in : tang_out / len_out; + const Eigen::Vector2d t_out = (len_out >= 1e-12) ? tang_out / len_out : tang_in / len_in; - const Eigen::Vector2d n_in_chord(-chord_in.y(), chord_in.x()); - const Eigen::Vector2d n_out_chord(-chord_out.y(), chord_out.x()); + // CCW 轮廓内向法线 = 切线的左法线 + const Eigen::Vector2d n_in(-t_in.y(), t_in.x()); + const Eigen::Vector2d n_out(-t_out.y(), t_out.x()); - const double dot_in = vec.dot(n_in_chord); - const double dot_out = vec.dot(n_out_chord); + const double dot_in = vec.dot(n_in); + const double dot_out = vec.dot(n_out); + const double cross = t_in.x() * t_out.y() - t_in.y() * t_out.x(); - const double cross = chord_in.x() * chord_out.y() - chord_in.y() * chord_out.x(); if (cross > kCrossThresh) { - // 凸角 + // 凸角:外部 = 两个外半平面的并集 return dot_in < 0.0 || dot_out < 0.0; } else if (cross < -kCrossThresh) { - // 凹角 - return dot_in < 0.0 && dot_out < 0.0; + // 反凸/凹角:外部 = 两个外半平面的交集 + return dot_in < 0.0 && dot_out < 0.0; } else { - // 平角(切向共线,光滑连接) - // 两半平面方向近似相同,取双法线加权平均 + // 近共线:平滑过渡 return (dot_in + dot_out) < 0.0; } }