CAD: Boolean takes its two operands from the viewport (snaporca-310o, e1p item 4)

Ported from snaporca 572eb56d0e. See that commit for the measurements.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Tommaso Bianchi
2026-08-14 22:12:38 +02:00
co-authored by Claude Opus 5
parent dd6363f536
commit 2643c778dc
2 changed files with 34 additions and 0 deletions
+30
View File
@@ -3422,6 +3422,32 @@ DesignPanel::DesignPanel(wxWindow* parent)
// If the Fillet/Chamfer card is open, re-anchor (or drop) the radius arrow on the new pick
// and rebuild the ghost — once an edge is picked the preview-only mode hides the base body.
if (m_active == Tool::Dressup) { sync_dressup_target(); update_fillet_gizmo(); refresh_preview(); }
// Boolean card open: the VIEWPORT is how you choose the two operands. Until now they
// could only come from two combos — the one control the charter names for this tool
// (e1p item 4), and the same pair snaporca-7xx caught silently resolving every row to
// index 0. The highlight already flowed card -> viewport; this closes the loop the
// other way. First pick is the target (kept), second is the tool (consumed); the
// combos mirror both, so the typed half of L2 still works and still round-trips.
// A body cannot be both operands — that boolean is a no-op — but the resolution is to
// SWAP, never to refuse: the pick is the user pointing at a body, and it has to win.
// Refusing it was measurably wrong. Both combos are pre-filled when the card opens
// (target = body 0, tool = a different one), so the very first viewport pick usually
// names a body the other slot already holds; ignoring it left the defaults in place and
// the commit produced body0 - body1 (75000 mm3) when the picks asked for body1 - body0
// (43000 mm3). Swapping keeps the pair distinct AND honours the click.
if (m_active == Tool::Boolean && m_sel_solid_body >= 0) {
ComboBox* dst = (m_bool_next_slot == 0) ? m_bool_target : m_bool_tool;
ComboBox* other = (m_bool_next_slot == 0) ? m_bool_tool : m_bool_target;
const int row = m_sel_solid_body; // selection index == body index
if (dst != nullptr && row < int(dst->GetCount())) {
const int prev = dst->GetSelection();
dst->SetSelection(row);
if (other != nullptr && other->GetSelection() == row && prev >= 0 && prev != row)
other->SetSelection(prev); // displaced operand takes the old slot
m_bool_next_slot ^= 1;
refresh_preview(); // re-tints the operands + rebuilds the ghost
}
}
// If the Shell card is open, a face pick chooses the open face: update the label + gizmo
// + ghost so the hollow updates live.
if (m_active == Tool::Shell) {
@@ -10252,6 +10278,10 @@ void DesignPanel::open_tool(Tool t)
// geometry-first control; the card mirrors the drag. Edit mode keeps today's card-only path.
if (t == Tool::Transform && m_edit_index < 0)
arm_transform_gizmo();
// Opening Boolean re-aims the viewport picks at the target slot, so the first click after
// the card appears always means "keep this one" regardless of what the last session did.
if (t == Tool::Boolean)
m_bool_next_slot = 0;
}
void DesignPanel::close_tool()
+4
View File
@@ -604,6 +604,10 @@ private:
ComboBox* m_bool_op{nullptr}; // 0 = Union, 1 = Subtract, 2 = Intersect
ComboBox* m_bool_target{nullptr}; // body that survives (selection == body index)
ComboBox* m_bool_tool{nullptr}; // body consumed (selection == body index)
// Which operand the NEXT viewport body pick fills: 0 = target, 1 = tool. Reset when the
// card opens, so the first two clicks in the viewport always mean "keep this, cut with
// that" in that order. The combos remain the typed half and mirror whatever is picked.
int m_bool_next_slot{0};
CheckBox* m_bool_keep{nullptr}; // keep the tool body after the op
wxSpinCtrlDouble* m_bool_tol{nullptr}; // OCCT fuzzy tolerance (mm); robust cut on near-coincident faces