From 1631963ba160fb7e422dba6d4097f4fb519b7b64 Mon Sep 17 00:00:00 2001 From: Tommaso Bianchi Date: Fri, 14 Aug 2026 08:32:19 +0200 Subject: [PATCH] CAD: pick tolerances scale with the face, so a narrow face is reachable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The edge and vertex tolerances were fixed at 8 and 11 px. On a face that is barely wider than that on screen — a thin plate, or any part once you zoom out — every point on it lies within the edge budget, so the pick alternated edge and whole body and the FACE level could never be reached at all. That is not just awkward: a face pick is what gives a Coord Sys its owning body, and a mate needs one, so thin parts could not be assembled. Both tolerances are now capped at a third of the face's shorter on-screen side, measured from the edge samples the picker already walks. They only ever shrink, so a face with room keeps the full budget and nothing changes for ordinary geometry; a narrow one keeps its middle for itself. Verified on the rig on a 16.7 mm-wide plate at three zoom levels including one far enough out to make the face a thin sliver: the middle reports "face 5 selected" every time, while points near the rim still take the edge. --- src/slic3r/GUI/DesignSketchTool.cpp | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/DesignSketchTool.cpp b/src/slic3r/GUI/DesignSketchTool.cpp index da6b9a67c9..c05a77fd12 100644 --- a/src/slic3r/GUI/DesignSketchTool.cpp +++ b/src/slic3r/GUI/DesignSketchTool.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -3070,6 +3071,12 @@ bool DesignSketchTool::resolve_solid_pick(GLCanvas3D& canvas, int mx, int my, So const TopoDS_Face face = GeometryEngine::face_by_index(bshape, out.face); double best_ed = 1e30; std::vector ed_pts; TopoDS_Edge ed_edge; bool have_edge = false; double best_vd = 1e30; Vec3d vtx = Vec3d::Zero(); bool have_vtx = false; + // Screen extent of the face, accumulated from the same edge samples the loop already + // takes. A FIXED edge tolerance makes a narrow face unreachable: a 3 mm-wide plate is + // barely wider on screen than the 8 px budget, so every point on it is "on an edge" and + // the face level can never be picked — which also blocks the face-based Coord Sys that a + // mate needs. The tolerances below shrink with the face so its middle stays its own. + int fx0 = INT_MAX, fy0 = INT_MAX, fx1 = INT_MIN, fy1 = INT_MIN; if (!face.IsNull()) { for (const TopoDS_Edge& e : GeometryEngine::edges_of_face(face)) { std::vector pts = GeometryEngine::sample_edge_world(e); @@ -3088,15 +3095,25 @@ bool DesignSketchTool::resolve_solid_pick(GLCanvas3D& canvas, int mx, int my, So const wxPoint a = world_to_screen_px(cam, pts[s - 1]); const wxPoint b = world_to_screen_px(cam, pts[s]); if (a.x < 0 || b.x < 0) continue; // behind the camera + fx0 = std::min({fx0, a.x, b.x}); fx1 = std::max({fx1, a.x, b.x}); + fy0 = std::min({fy0, a.y, b.y}); fy1 = std::max({fy1, a.y, b.y}); d = std::min(d, seg_px(cursor, a, b)); } if (d < best_ed) { best_ed = d; ed_pts = pts; ed_edge = e; have_edge = true; } } } - if (have_vtx && best_vd <= kVertexTolPx) { + // A third of the face's SHORTER on-screen side, so the two tolerances can never meet in + // the middle. Only ever shrinks: a face big enough keeps the full budget. + double vtol = kVertexTolPx, etol = kEdgeTolPx; + if (fx1 > fx0 && fy1 > fy0) { + const double narrow = double(std::min(fx1 - fx0, fy1 - fy0)) / 3.0; + vtol = std::min(vtol, narrow); + etol = std::min(etol, narrow); + } + if (have_vtx && best_vd <= vtol) { out.vertex_pt = vtx; out.kind = SolidSel::Vertex; - } else if (have_edge && best_ed <= kEdgeTolPx) { + } else if (have_edge && best_ed <= etol) { // Promote the face-relative pick to a STABLE GLOBAL edge id so dress-up ops // (fillet/chamfer) can target this exact edge across recomputes. out.edge = GeometryEngine::edge_index_of(bshape, ed_edge);