From 03fb81020e6c04be841d8f0f24f89b48b963b1c3 Mon Sep 17 00:00:00 2001 From: Tommaso Bianchi Date: Fri, 14 Aug 2026 10:01:28 +0200 Subject: [PATCH] CAD: picking a face for a Coord Sys must also make it a face-based frame MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A mate between two connectors committed cleanly, recomputed without error, and moved nothing. apply_mate was reached and computed a translation of exactly (0, 0, 0). The connectors were the cause, not the mate. Picking a face stores coordsys_face and coordsys_body but left the Type combo on its default, Point (world) — and datum_frame ignores the pick entirely for that type, resolving the connector to coordsys_point, which is (0,0,0) unless the user typed otherwise. Two connectors built that way share one frame, so the mate between them is an identity transform: everything reports success and the assembly never moves. Capturing a face or an edge now switches the type to FaceAndDirection. Picking a face IS the choice of a face-based frame; asking for it twice, with no hint that the second half is required, is what made every mate a silent no-op. Verified on the rig, two bodies with a face-based connector each: before Extrude4 [-71.6, 402.6, 156.5] .. [-8.8, 412.6, 237.3] after Extrude4 [-31.4, -40.4, -10.0] .. [ 31.4, 40.4, -0.0] with the mate transform now (40.19, -196.88, 402.56) instead of (0, 0, 0). That is the first mate in this tree that assembles anything. Not the kernel: recompute applies mates exactly as preview does, proven by an A/B harness over all five kinds — the two paths give identical bounding boxes. --- src/slic3r/GUI/DesignPanel.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/DesignPanel.cpp b/src/slic3r/GUI/DesignPanel.cpp index f701534272..cc8f590c81 100644 --- a/src/slic3r/GUI/DesignPanel.cpp +++ b/src/slic3r/GUI/DesignPanel.cpp @@ -3502,7 +3502,19 @@ DesignPanel::DesignPanel(wxWindow* parent) case CoordSysPick::Edge: if (m_sel_solid_edge >= 0) { m_cs_face_body = m_sel_solid_body; m_cs_edge = m_sel_solid_edge; got = true; } break; default: break; } - if (got) { m_coordsys_pick = CoordSysPick::None; refresh_coordsys_labels(); } + if (got) { + // A picked face or edge is only meaningful to FaceAndDirection. Left on the + // default Point (world), datum_frame ignores the pick entirely and resolves the + // connector to coordsys_point — which is (0,0,0) unless the user typed + // otherwise. Two such connectors then share one frame, so a mate between them + // computes an IDENTITY transform: the feature commits, the recompute succeeds, + // and nothing moves. Picking a face IS the choice of a face-based frame, so make + // the type follow the pick rather than asking for it twice. + if (m_coordsys_type && m_coordsys_type->GetSelection() != (int)CoordSysType::FaceAndDirection) + m_coordsys_type->SetSelection((int)CoordSysType::FaceAndDirection); + m_coordsys_pick = CoordSysPick::None; + refresh_coordsys_labels(); + } if (got && m_viewport) m_viewport->set_escalate_on_repick(true); } m_status->SetForegroundColour(wxNullColour);