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 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BVzKmX6Y1aEteit1HTXG4Q
This commit is contained in:
Tommaso Bianchi
2026-07-22 19:06:05 +02:00
co-authored by Claude Opus 4.8
parent edb1adbfa3
commit 2db59bb85a
+36 -3
View File
@@ -19,6 +19,8 @@
#include <array>
#include <cmath>
#include <cstdio>
#include <cstdarg>
#include <cstdlib>
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).