From 514a9a633c52af1f35f1e311ccdb79ac4f11fa63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8C=82=E4=B9=8B=E9=92=B3?= Date: Tue, 28 Jul 2026 08:04:34 +0800 Subject: [PATCH] =?UTF-8?q?fix(v1.0.1):=20VDE-016=20=E2=80=94=20definitive?= =?UTF-8?q?=20fix:=20fully-qualified=20names=20throughout?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Root cause: GCC two-phase lookup with multiple anonymous namespaces creates barriers that using declarations cannot cross. Fix: Replace all unqualified SSICurveData/ClassResult with vde::brep::SSICurveData/vde::brep::ClassResult throughout the file. This is the only approach verified to work by ViewDesign. --- docs/feedback/VDE-016.md | 2 +- src/brep/ssi_boolean.cpp | 42 ++++++++++++++++++++-------------------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/docs/feedback/VDE-016.md b/docs/feedback/VDE-016.md index bc61549..128ae93 100644 --- a/docs/feedback/VDE-016.md +++ b/docs/feedback/VDE-016.md @@ -1,6 +1,6 @@ --- id: VDE-016 -status: open +status: fixed severity: critical category: bug date: 2026-07-27 diff --git a/src/brep/ssi_boolean.cpp b/src/brep/ssi_boolean.cpp index 941247c..9444199 100644 --- a/src/brep/ssi_boolean.cpp +++ b/src/brep/ssi_boolean.cpp @@ -64,7 +64,7 @@ namespace { // ═══════════════════════════════════════════════════════════ // Constants & types BrepModel extract_face_fragment(const BrepModel& body, int face_id); -ClassResult classify_point_adaptive( +vde::brep::ClassResult classify_point_adaptive( const BrepModel& body, const Point3D& p, int& num_exact_upgrades); // ═══════════════════════════════════════════════════════════ @@ -507,11 +507,11 @@ BrepModel extract_face_fragment(const BrepModel& body, int face_id) { /// Compute all SSI curves between body A and body B. /// Returns a list of SSICurveData, one per intersecting face pair. /// Uses OpenMP parallelization over face pairs. -std::vector compute_all_ssi( +std::vector compute_all_ssi( const BrepModel& a, const BrepModel& b, int& num_exact_upgrades) { - std::vector all_isects; + std::vector all_isects; std::mutex isect_mutex; // Build face-AABB cache for quick rejection @@ -537,11 +537,11 @@ std::vector compute_all_ssi( #ifdef VDE_USE_OPENMP #pragma omp parallel { - std::vector local; + std::vector local; #pragma omp for schedule(dynamic) nowait for (size_t pi = 0; pi < pairs.size(); ++pi) { #else - std::vector local; + std::vector local; for (size_t pi = 0; pi < pairs.size(); ++pi) { #endif int ia = pairs[pi].first; @@ -558,7 +558,7 @@ std::vector compute_all_ssi( for (const auto& curve : curves) { if (curve.points.size() < 4) continue; - SSICurveData d; + vde::brep::SSICurveData d; d.face_a = ia; d.face_b = ib; d.points = curve.points; @@ -610,7 +610,7 @@ struct CuttingPlane { }; std::unordered_map> -build_face_cutting_planes(const std::vector& ssi_curves, +build_face_cutting_planes(const std::vector& ssi_curves, bool for_body_a) { std::unordered_map> result; for (const auto& c : ssi_curves) { @@ -641,14 +641,14 @@ build_face_cutting_planes(const std::vector& ssi_curves, /// Split all faces of a body using SSI-derived cutting planes, /// then classify each resulting fragment against the other body. /// Returns a vector of (fragment, classification) pairs. -std::vector> +std::vector> split_and_classify_faces_ssi( const BrepModel& body, const std::unordered_map>& cutting_planes, const BrepModel& other_body, int& num_exact_upgrades) { - std::vector> result; + std::vector> result; std::mutex result_mutex; #ifdef VDE_USE_OPENMP @@ -685,7 +685,7 @@ split_and_classify_faces_ssi( } // Classify each fragment using multi-point sampling - std::vector> local; + std::vector> local; for (auto& frag : fragments) { // Use the new multi-point classify_face_fragment // Extract face_id from the fragment (fragment has exactly one face at index 0) @@ -711,7 +711,7 @@ split_and_classify_faces_ssi( /// This avoids expensive mesh construction for clearly IN/OUT faces. bool classify_face_uniform(const BrepModel& face_body, const BrepModel& other_body, - ClassResult& uniform_result) { + vde::brep::ClassResult& uniform_result) { if (face_body.num_faces() == 0) return false; const auto& surf = face_body.surface(face_body.face(0).surface_id); double u0 = surf.knots_u().front(), u1 = surf.knots_u().back(); @@ -725,7 +725,7 @@ bool classify_face_uniform(const BrepModel& face_body, double radius = (bb.max() - bb.min()).norm() * 0.5; double radius_sq = radius * radius; - ClassResult first; + vde::brep::ClassResult first; { Point3D p = surf.evaluate(us[0], vs[0]); if (!bb.contains(p)) { first = OUT; } @@ -734,7 +734,7 @@ bool classify_face_uniform(const BrepModel& face_body, } for (int i = 1; i < 5; ++i) { Point3D p = surf.evaluate(us[i], vs[i]); - ClassResult cls; + vde::brep::ClassResult cls; if (!bb.contains(p)) cls = OUT; else if ((p - center).squaredNorm() <= radius_sq * 0.5) cls = IN; else return false; @@ -747,7 +747,7 @@ bool classify_face_uniform(const BrepModel& face_body, /// Double-precision ray cast classification for a point against a mesh. /// Returns IN/OUT (never ON — ON is handled separately). /// Uses exact_orient3d for robust coplanarity tests on boundary triangles. -ClassResult classify_point_double(const BrepModel& body, const Point3D& p) { +vde::brep::ClassResult classify_point_double(const BrepModel& body, const Point3D& p) { const mesh::HalfedgeMesh& mesh = get_mesh(body); if (mesh.num_faces() == 0) return OUT; @@ -838,7 +838,7 @@ bool point_on_surface_double(const BrepModel& body, const Point3D& p, } /// Adaptive classification: try double first, upgrade to GMP exact if uncertain. -ClassResult classify_point_adaptive( +vde::brep::ClassResult classify_point_adaptive( const BrepModel& body, const Point3D& p, int& num_exact_upgrades) { // Step 1: Check ON surface (double precision is adequate here) @@ -847,12 +847,12 @@ ClassResult classify_point_adaptive( } // Step 2: Try double-precision ray cast - ClassResult result = classify_point_double(body, p); + vde::brep::ClassResult result = classify_point_double(body, p); // Step 3: check if the result is uncertain (near boundary) // Re-cast with a slightly offset origin to check consistency Point3D p2(p.x() + 1e-8, p.y(), p.z()); - ClassResult verify = classify_point_double(body, p2); + vde::brep::ClassResult verify = classify_point_double(body, p2); if (result != verify) { // Inconsistent: upgrade to exact @@ -947,7 +947,7 @@ ClassResult classify_point_adaptive( } // anonymous namespace — classify_face_fragment is public -ClassResult classify_face_fragment( +vde::brep::ClassResult classify_face_fragment( const BrepModel& body, const BrepModel& other_body, int face_id, int& num_exact_upgrades) { @@ -986,7 +986,7 @@ ClassResult classify_face_fragment( std::mt19937 rng(42); // fixed seed for reproducibility std::uniform_real_distribution dist(0.0, 1.0); - auto sample_and_vote = [&](int n_samples) -> ClassResult { + auto sample_and_vote = [&](int n_samples) -> vde::brep::ClassResult { int in_count = 0, out_count = 0, on_count = 0; for (int i = 0; i < n_samples; ++i) { @@ -1100,7 +1100,7 @@ ClassResult classify_face_fragment( }; // First pass: N samples - ClassResult result = sample_and_vote(N); + vde::brep::ClassResult result = sample_and_vote(N); // If result is ON or the vote was close, re-sample with 2N points if (result == ON) { @@ -1377,7 +1377,7 @@ SSIBooleanResult ssi_boolean_core( std::vector keep_fragments; // Predicate: which fragments to keep based on operation type - auto should_keep = [op_type](ClassResult cls, bool from_a) -> bool { + auto should_keep = [op_type](vde::brep::ClassResult cls, bool from_a) -> bool { switch (op_type) { case 0: // union // Keep A fragments OUT/ON of B; keep B fragments OUT of A