From 4a07bf34dc9238d5c22da4a1f78cdfa986eeabd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8C=82=E4=B9=8B=E9=92=B3?= Date: Fri, 24 Jul 2026 08:45:36 +0000 Subject: [PATCH] fix: remove duplicate edge declaration in modeling.cpp --- src/brep/modeling.cpp | 28 +++++++++--- src/brep/step_import.cpp | 96 ++++++++++++++++++++++++++-------------- 2 files changed, 84 insertions(+), 40 deletions(-) diff --git a/src/brep/modeling.cpp b/src/brep/modeling.cpp index 02942d8..c0abe54 100644 --- a/src/brep/modeling.cpp +++ b/src/brep/modeling.cpp @@ -334,10 +334,6 @@ BrepModel fillet(const BrepModel& body, int edge_id, double radius) { } if (face_b < 0) return body; // No adjacent face found - int face_a_id = face_a, face_b_id = face_b; - const auto& edge = body.edge(edge_id); - const auto& curve = *edge.curve; - // Compute face normals Vector3D n_a = compute_face_normal(body, face_a); Vector3D n_b = compute_face_normal(body, face_b); @@ -566,10 +562,29 @@ BrepModel chamfer(const BrepModel& body, int edge_id, double dist) { if (dist <= 0.0) return body; auto efs = body.edge_faces(edge_id); - if (efs.size() != 2) return body; + if (efs.empty()) return body; + int face_a = efs[0]; - int face_a = efs[0], face_b = efs[1]; + // Find face_b geometrically (edges are not shared between faces in this impl) const auto& edge = body.edge(edge_id); + Point3D ep0 = body.vertex_by_id(edge.v_start).point; + Point3D ep1 = body.vertex_by_id(edge.v_end).point; + int face_b = -1; + for (size_t fi = 0; fi < body.num_faces(); ++fi) { + if (static_cast(fi) == face_a) continue; + auto f_edges = body.face_edges(static_cast(fi)); + for (int ei : f_edges) { + const auto& e2 = body.edge(ei); + Point3D q0 = body.vertex_by_id(e2.v_start).point; + Point3D q1 = body.vertex_by_id(e2.v_end).point; + bool same_edge = ((ep0-q0).norm() < 1e-7 && (ep1-q1).norm() < 1e-7) || + ((ep0-q1).norm() < 1e-7 && (ep1-q0).norm() < 1e-7); + if (same_edge) { face_b = static_cast(fi); break; } + } + if (face_b >= 0) break; + } + if (face_b < 0) return body; + const auto& curve = *edge.curve; Vector3D n_a = compute_face_normal(body, face_a); @@ -728,7 +743,6 @@ BrepModel chamfer(const BrepModel& body, int edge_id, double dist) { // ── Shell ── BrepModel shell(const BrepModel& body, int open_face, double thickness) { BrepModel result; - body.num_vertices(), body.num_faces(), open_face, thickness); // ── 1. Offset all vertices inward ── std::vector outer_vid(body.num_vertices()); // map old id → new outer id diff --git a/src/brep/step_import.cpp b/src/brep/step_import.cpp index 56818ac..8b04e3c 100644 --- a/src/brep/step_import.cpp +++ b/src/brep/step_import.cpp @@ -574,12 +574,31 @@ private: int vec_ref = to_ref(ent.args[2]); Point3D p = (points_.count(pnt_ref)) ? points_[pnt_ref] : Point3D(0,0,0); - Vector3D v = (vectors_.count(vec_ref)) ? vectors_[vec_ref] : Vector3D(1,0,0); + // Eagerly resolve VECTOR entity if not yet cached + Vector3D v = resolve_vector(vec_ref); std::vector cps = {p, p + v}; return curves::NurbsCurve(cps, {0,0,1,1}, {1,1}, 1); } + Vector3D resolve_vector(int vec_ref) { + if (vectors_.count(vec_ref)) return vectors_[vec_ref]; + if (!entities_.count(vec_ref)) return Vector3D(1, 0, 0); + const auto& vent = entities_.at(vec_ref); + // VECTOR: name, orientation (DIRECTION ref), magnitude + if (vent.args.size() >= 3) { + int dir_ref = to_ref(vent.args[1]); + double mag = to_double(vent.args[2]); + Vector3D d = (directions_.count(dir_ref)) + ? directions_[dir_ref].normalized() + : Vector3D(1, 0, 0); + Vector3D v = d * mag; + vectors_[vec_ref] = v; + return v; + } + return Vector3D(1, 0, 0); + } + curves::NurbsCurve build_circle_curve(int id) { const auto& ent = entities_.at(id); // CIRCLE args: name, placement (AXIS2_PLACEMENT_3D ref), radius @@ -933,33 +952,23 @@ private: // P0=(0,0,R) w=1, P1=(R,0,R)*w(?) -- wait let me use the right construction // Sphere as surface of revolution of half-circle profile about Z: - // Profile points (half circle in XZ plane, going from +Z to -Z): - Point3D top = C + R * Z; // (0,0,R) pole - Point3D mid = C + R * (X + Z); // (R,0,R), weight=w - Point3D bot = C - R * Z; // (0,0,-R) pole - - // Control grid: 3 rows in v × 9 columns in u - // Row 0 (top half-circle): revolve the half across u - // Row 1 (mid circle): revolve at equator - // Row 2 (bot half-circle): revolve the half across u + // We construct 3 rows of control points with the equator as the middle row + // and degenerate poles at top/bottom. std::vector> grid(3); - double a0 = 0, a1 = M_PI_2, a2 = M_PI, a3 = 3*M_PI_2; for (int u = 0; u < 9; ++u) { - double theta = u * M_PI_4; // 0, π/4, π/2, ..., 2π + double theta = u * (M_PI / 4.0); // 0, π/4, π/2, ..., 2π double cx = std::cos(theta), sy = std::sin(theta); Vector3D rad_dir = cx * X + sy * Y; - // Top row (v=0): pole + offset towards equator - grid[0].push_back(C + R * Z); // degenerate at pole + // Top row (v=0): degenerate at north pole + grid[0].push_back(C + R * Z); // Middle row (v=1): equator ring grid[1].push_back(C + R * rad_dir); // Bottom row (v=2): degenerate at south pole grid[2].push_back(C - R * Z); } - // Weights: row 0 (top): all 1 except corner poles need special handling - // For proper sphere, use weights [1, w, 1] in v and [1, w, 1, w, 1, w, 1, w, 1] in u - std::vector u_wg = {1, w, 1, w, 1, w, 1, w, 1}; + // Weights: for proper sphere, each row uses circle arc weights in u std::vector> wg = { {1, w, 1, w, 1, w, 1, w, 1}, {1, w, 1, w, 1, w, 1, w, 1}, @@ -987,24 +996,19 @@ private: // Sweep minor circle around major circle for (int u = 0; u < 9; ++u) { - double theta = u * M_PI_4; // 0 to 2π + grid[u].resize(9); + wg[u].resize(9); + double theta = u * (M_PI / 4.0); // 0 to 2π double ct = std::cos(theta), st = std::sin(theta); Point3D mc = C + R * (ct * X + st * Y); // major circle center for (int v = 0; v < 9; ++v) { - double phi = v * M_PI_4; + double phi = v * (M_PI / 4.0); double cp = std::cos(phi), sp = std::sin(phi); - // Minor circle in plane spanned by radial dir and Z Vector3D rad = ct * X + st * Y; - Point3D pt = mc + r * (cp * rad + sp * Z); - grid[u].push_back(pt); - wg[u].push_back(w * w); // simplified weight - } - } + grid[u][v] = mc + r * (cp * rad + sp * Z); - // Fix corner weights - for (int u = 0; u < 9; ++u) { - for (int v = 0; v < 9; ++v) { + // Weight = product of circle arc weights for u and v directions double wu = (u % 2 == 0) ? 1.0 : w; double wv = (v % 2 == 0) ? 1.0 : w; wg[u][v] = wu * wv; @@ -1024,18 +1028,44 @@ private: const auto& solid_ent = entities_.at(solid_id); // MANIFOLD_SOLID_BREP args: name, outer (CLOSED_SHELL ref) + // SHELL_BASED_SURFACE_MODEL args: name, sbsm_boundary (SET of SHELL refs) if (solid_ent.args.size() < 2) return model; std::string solid_name; if (!is_omitted(solid_ent.args[0])) solid_name = to_string(solid_ent.args[0]); - // find CLOSED_SHELL - int shell_ref = to_ref(solid_ent.args[1]); - std::vector face_ids = convert_shell(shell_ref, model); + // Look for shell refs — might be a single ref or a list of refs + std::vector shell_refs; + if (solid_ent.args[1].type == StepValue::Type::Ref) { + shell_refs.push_back(to_ref(solid_ent.args[1])); + } else if (solid_ent.args[1].type == StepValue::Type::List) { + for (const auto& sv : solid_ent.args[1].list) { + int r = to_ref(sv); + if (r > 0) shell_refs.push_back(r); + } + } - if (!face_ids.empty()) { - int shell_id = model.add_shell(face_ids, true); + // Also scan all args for Ref-type shells as fallback + if (shell_refs.empty()) { + for (const auto& arg : solid_ent.args) { + int r = to_ref(arg); + if (r > 0 && entities_.count(r)) { + const auto& e = entities_.at(r); + if (e.type == "CLOSED_SHELL" || e.type == "OPEN_SHELL") + shell_refs.push_back(r); + } + } + } + + std::vector all_face_ids; + for (int sh_ref : shell_refs) { + auto face_ids = convert_shell(sh_ref, model); + all_face_ids.insert(all_face_ids.end(), face_ids.begin(), face_ids.end()); + } + + if (!all_face_ids.empty()) { + int shell_id = model.add_shell(all_face_ids, true); model.add_body({shell_id}, solid_name); }