From 2db59bb85aa9a45cd19204d455a20794603ac3e6 Mon Sep 17 00:00:00 2001 From: Tommaso Bianchi Date: Wed, 22 Jul 2026 19:06:05 +0200 Subject: [PATCH] Design: trace the solid-pick path behind SNAPORCA_PICK_TRACE Selection failures on a real desktop kept looking identical from the UI whether the ray missed the solid, the click was rejected as a drag, or the press never reached the tool at all. The status line added in edb1adbfa3 reports WHICH body/face was picked, so it distinguishes "picked" from "silence" and nothing finer -- not enough to tell those three apart. This narrates the whole press -> release -> ray path on stderr, one distinct line per failure mode: down x= y= the press reached the tool up with no pending press the press was eaten upstream up ... drift=N / rejected the click-vs-drag threshold decided ray tris=N -> body= face= t= the ray reached the solid (or missed) no solid data (bodies= mesh=) the pick pointers were never wired Gated on getenv("SNAPORCA_PICK_TRACE"), cached in a function-local static, so a normal build pays one load and prints nothing. It ships enabled-on- demand because the failing environment is a real X session with a real mouse, which the headless rig cannot reproduce. First use retired a wrong theory of my own: the trace showed drift=0 on three consecutive picks, so the widened threshold in edb1adbfa3 was not what fixed anything. The reported symptom is best explained by a stale pre-orcawidgets binary left running alongside the current one. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01BVzKmX6Y1aEteit1HTXG4Q --- src/slic3r/GUI/DesignSketchTool.cpp | 39 ++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/DesignSketchTool.cpp b/src/slic3r/GUI/DesignSketchTool.cpp index 5fdab0824d..05596f0874 100644 --- a/src/slic3r/GUI/DesignSketchTool.cpp +++ b/src/slic3r/GUI/DesignSketchTool.cpp @@ -19,6 +19,8 @@ #include #include #include +#include +#include namespace Slic3r { namespace GUI { @@ -2748,11 +2750,31 @@ void DesignSketchTool::select_body(int body) m_solid_sel = SolidSel::Whole; // render_solid_highlight tints just this body } +// Pick tracing. Selection failures on a real desktop have repeatedly turned out to be an +// event that never arrived rather than a ray that missed, and the two look identical from +// the UI. Set SNAPORCA_PICK_TRACE=1 and the whole press->release->ray path narrates itself +// on stderr. Off by default: no cost, no noise. +static void dp_pick_trace(const char* fmt, ...) +{ + static const bool on = ::getenv("SNAPORCA_PICK_TRACE") != nullptr; + if (!on) return; + va_list ap; va_start(ap, fmt); + std::fputs("[pick] ", stderr); + std::vfprintf(stderr, fmt, ap); + std::fputc('\n', stderr); + va_end(ap); + std::fflush(stderr); +} + // LeftDown on the solid cycles whole->face->edge. Returns true if the click hit the solid // (consumed); false otherwise so the caller can try committed-sketch loop picking. bool DesignSketchTool::handle_solid_click(GLCanvas3D& canvas, const wxMouseEvent& evt) { - if (m_solid_bodies == nullptr || m_solid_mesh == nullptr) return false; + if (m_solid_bodies == nullptr || m_solid_mesh == nullptr) { + dp_pick_trace("no solid data (bodies=%p mesh=%p)", + (const void*) m_solid_bodies, (const void*) m_solid_mesh); + return false; + } const Linef3 r = canvas.mouse_ray(Point(evt.GetX(), evt.GetY())); const Vec3d ro = r.a, rd = r.b - r.a; @@ -2774,6 +2796,8 @@ bool DesignSketchTool::handle_solid_click(GLCanvas3D& canvas, const wxMouseEvent best_body = cand_body; } } + dp_pick_trace("ray tris=%zu -> body=%d face=%d t=%.3f", its.indices.size(), + best_body, best_face, best_t); if (best_face < 0 || best_body < 0 || best_body >= int(m_solid_bodies->size())) return false; // missed the solid @@ -7655,17 +7679,26 @@ bool DesignSketchTool::on_mouse(wxMouseEvent& evt, GLCanvas3D& canvas) m_pick_press_x = evt.GetX(); m_pick_press_y = evt.GetY(); m_pick_pending = true; + dp_pick_trace("down x=%d y=%d", evt.GetX(), evt.GetY()); + return false; + } + if (!(evt.LeftUp() && m_pick_pending)) { + if (evt.LeftUp()) dp_pick_trace("up with no pending press (press was eaten upstream)"); return false; } - if (!(evt.LeftUp() && m_pick_pending)) return false; m_pick_pending = false; + dp_pick_trace("up x=%d y=%d drift=%d", evt.GetX(), evt.GetY(), + std::max(std::abs(evt.GetX() - m_pick_press_x), + std::abs(evt.GetY() - m_pick_press_y))); // Threshold per axis, at GTK's own drag threshold. A hand-held mouse drifts several // pixels during an ordinary click — a tight budget silently swallowed real clicks and // looked exactly like "selection does not work". Synthetic clicks never drift, which // is why the headless rig could not show this. if (std::max(std::abs(evt.GetX() - m_pick_press_x), - std::abs(evt.GetY() - m_pick_press_y)) > 8) + std::abs(evt.GetY() - m_pick_press_y)) > 8) { + dp_pick_trace("rejected as drag"); return false; // it was a drag: the canvas already orbited, don't also select + } // Committed-sketch loop pick is computed FIRST. A click that lands on a loop's // STROKE (edge) selects that loop even when it lies on a solid face — so a sketch // drawn ON a face can be selected and extruded/cut (Onshape engraving workflow).