From 3f8f46f93f7e13cf24125841665e813780d8c7a2 Mon Sep 17 00:00:00 2001 From: Tommaso Bianchi Date: Thu, 30 Jul 2026 14:24:29 +0200 Subject: [PATCH] Delete the sketch plane dropdown; the viewport decides MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The plane combo is gone. A sketch takes its plane from what is picked in the viewport: a face on a solid, or one of the reference-plane ghosts, clicked in 3D. The card is now a single line of instruction instead of a control. The combo had become worse than redundant. Once a picked face could be the plane it displayed a row that CONTRADICTED the actual target — it still said XY while the sketch went onto the face — so the one place a user could look to confirm where they were drawing was the one place guaranteed to be wrong. What replaces it is state, not UI: m_ref_plane records which reference plane was last clicked in 3D (0/1/2 = XY/XZ/YZ, >=3 indexes the datums) and ref_plane_name() turns it into text for the on-geometry hint. Clicking a ghost plane while a session is live re-planes it immediately, which the combo's own handler used to do; that behaviour is kept, just driven from the geometry instead of the widget. A plane click also drops a stale face pick, so last pick wins in both directions. populate_plane_choices() stays — seven other pickers use it (Plane base, Axis A/B, Helix, Project, Mirror, Cut). Those are the next candidates, tracked on snaporca-e1p; this commit only removes the one that had become actively misleading. Also: tessellation now matches Orca's OWN STEP importer, linear deflection 0.003 instead of 0.01 (Format/STEP.hpp default; angular was already 0.5 rad and unchanged). The Design viewport was never using a different rendering technique — it hosts a real GLCanvas3D, builds a real Model/ModelVolume and goes through the same reload/GLVolume path and the same shaders as Prepare and Preview. What differed was the mesh handed to it: 3.3x coarser than anything else in the application, which is why a curved face read as faceted beside an imported part. Suite unaffected at 154 cases / 2125 assertions, so nothing depended on the old density. Verified on :10: the card shows no dropdown, one click on a face then a sketch tool still reports "on the picked face", and the circle is drawn in that face's plane (artifacts/shots/h3a2-02-sketch.png, h3a2-03-drawn.png). snaporca-e1p, snaporca-3a2. --- src/libslic3r/CadDocument.hpp | 8 ++++- src/slic3r/GUI/DesignPanel.cpp | 61 ++++++++++++++++++---------------- src/slic3r/GUI/DesignPanel.hpp | 6 +++- 3 files changed, 44 insertions(+), 31 deletions(-) diff --git a/src/libslic3r/CadDocument.hpp b/src/libslic3r/CadDocument.hpp index 405a5a22fe..ed00bdddab 100644 --- a/src/libslic3r/CadDocument.hpp +++ b/src/libslic3r/CadDocument.hpp @@ -424,7 +424,13 @@ public: // world 0). Not serialized — the GUI re-applies it from the live bed on every tab show. Vec3d modeling_origin{Vec3d::Zero()}; - double linear_deflection{0.01}; + // Tessellation quality, matched to Orca's OWN STEP importer (Format/STEP.hpp defaults: + // linear 0.003, angular 0.5 rad) so a body modelled here reaches the screen at the same + // density as the identical body imported through Prepare. It was 0.01 linear — 3.3x coarser + // than anything else in the app, which is why curved faces read as faceted next to an + // imported part. Angular already matched. Same BRepMesh_IncrementalMesh call, same GLVolume + // path, same shaders: the renderer was never the difference, the mesh fed to it was. + double linear_deflection{0.003}; double angular_deflection{0.5}; int add_sketch(SketchShape shape, const SketchPlane& plane, diff --git a/src/slic3r/GUI/DesignPanel.cpp b/src/slic3r/GUI/DesignPanel.cpp index 730727d00c..b4dcf1b61a 100644 --- a/src/slic3r/GUI/DesignPanel.cpp +++ b/src/slic3r/GUI/DesignPanel.cpp @@ -511,10 +511,9 @@ DesignPanel::DesignPanel(wxWindow* parent) auto* b_sketch = icon_btn("design_sketch", _L("Sketch")); std::function act_sketch = [this] { - populate_plane_choices(m_draw_plane); // surface datum planes in the picker set_ui_mode(UiMode::Sketch); m_status->SetForegroundColour(wxNullColour); - m_status->SetLabel(_L("Pick a plane and a sketch tool, then draw")); + m_status->SetLabel(_L("Click a face or a reference plane in the viewport, then a sketch tool")); m_status->Refresh(); }; b_sketch->Bind(wxEVT_BUTTON, [act_sketch](wxCommandEvent&) { act_sketch(); }); @@ -2669,24 +2668,13 @@ DesignPanel::DesignPanel(wxWindow* parent) 0, wxLEFT | wxRIGHT | wxTOP, 12); m_box_sketch_session->Add(new wxStaticLine(m_cards), 0, wxEXPAND | wxALL, 8); { - auto* prow = new wxBoxSizer(wxHORIZONTAL); - prow->Add(new wxStaticText(m_cards, wxID_ANY, _L("Plane")), 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 8); - m_draw_plane = make_combo(m_cards); - m_draw_plane->Append(_L("XY")); m_draw_plane->Append(_L("XZ")); m_draw_plane->Append(_L("YZ")); - m_draw_plane->SetSelection(0); - // Live re-plane: begin_sketch captures the plane only at first-tool-pick, so changing the - // dropdown afterwards used to be inert (sketch stayed on its original plane while the - // committed feature would silently land on the new one). Honour the change immediately — - // the 2D entities are re-lifted through the chosen plane, matching what Finish commits. - m_draw_plane->Bind(wxEVT_COMBOBOX, [this](wxCommandEvent&) { - if (m_viewport && m_viewport->is_sketching()) - m_viewport->set_sketch_plane(plane_from_choice(m_draw_plane->GetSelection())); - }); - prow->AddStretchSpacer(); // label left, control right — same row idiom as the grids - prow->Add(m_draw_plane, 0, wxALIGN_CENTER_VERTICAL); - m_box_sketch_session->Add(prow, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, 12); + // NO plane dropdown. The sketch plane comes from what is picked in the VIEWPORT — a face + // on a solid, or one of the reference-plane ghosts — because that is where the user is + // looking and pointing. A combo duplicated that decision somewhere the geometry could not + // see it, and once a face could be picked it went further and displayed a stale row that + // contradicted the real target. snaporca-e1p. auto* hint = new wxStaticText(m_cards, wxID_ANY, - _L("Pick a plane, then draw. Finish (✓) when done.")); + _L("Click a face or a reference plane, then a sketch tool.")); hint->SetForegroundColour(dp_sec_text()); m_box_sketch_session->Add(hint, 0, wxLEFT | wxRIGHT | wxTOP | wxBOTTOM, 12); } @@ -3296,9 +3284,16 @@ DesignPanel::DesignPanel(wxWindow* parent) refresh_plane_labels(); refresh_preview(); // re-resolve the frame + move the gizmo/ghosts to the new base } else { - // Fallback (no object yet): clicking a reference plane selects it as the sketch plane. - if (m_draw_plane && base >= 0 && base < int(m_draw_plane->GetCount())) - m_draw_plane->SetSelection(base); + // Clicking a reference plane in 3D IS how a sketch plane is chosen now. Record it and, + // when a session is already live, re-plane it immediately: begin_sketch captures the + // plane at first-tool-pick, so without this the entities would stay on the old plane + // while the committed feature landed on the new one. + if (base >= 0) { + m_ref_plane = base; + m_pick_face = m_pick_face_body = -1; // last pick wins: a plane beats a stale face + if (m_viewport && m_viewport->is_sketching()) + m_viewport->set_sketch_plane(plane_from_choice(m_ref_plane)); + } const char* nm = (base == 0) ? "XY" : (base == 1) ? "XZ" : (base == 2) ? "YZ" : "datum"; m_status->SetForegroundColour(wxColour(120, 210, 120)); // The "press Sketch" half is only true in Feature mode, where that button exists. @@ -3967,8 +3962,7 @@ void DesignPanel::add_imported_sketch( } } if (!on_face) { - if (m_draw_plane) f.plane = plane_from_choice(m_draw_plane->GetSelection()); - else { f.plane = SketchPlane::XY(); f.plane.origin += m_doc.modeling_origin; } + f.plane = plane_from_choice(m_ref_plane); } // Drop the live face selection (its body is now remembered on import_face_body): otherwise @@ -4840,6 +4834,18 @@ void DesignPanel::populate_plane_choices(ComboBox* c) const c->SetSelection((keep >= 0 && keep < int(c->GetCount())) ? keep : 0); } +wxString DesignPanel::ref_plane_name(int row) const +{ + if (row == 1) return "XZ"; + if (row == 2) return "YZ"; + if (row >= 3) { + const auto datums = m_doc.resolve_datum_planes(); + const int di = row - 3; + if (di < int(datums.size())) return wxString::FromUTF8(datums[di].first); + } + return "XY"; +} + SketchPlane DesignPanel::plane_from_choice(int row) const { if (row < 3) { // 0=XY,1=XZ,2=YZ through the modeling origin @@ -4875,11 +4881,8 @@ SketchPlane DesignPanel::sketch_plane_from_selection(wxString& what) const : _L("the picked face"); return p; } - const int row = m_draw_plane ? m_draw_plane->GetSelection() : 0; - what = (m_draw_plane && row >= 0 && row < int(m_draw_plane->GetCount())) - ? m_draw_plane->GetString(unsigned(row)) - : wxString("XY"); - return plane_from_choice(row); + what = ref_plane_name(m_ref_plane); + return plane_from_choice(m_ref_plane); } void DesignPanel::apply_plane_refs(CadFeature& f) const diff --git a/src/slic3r/GUI/DesignPanel.hpp b/src/slic3r/GUI/DesignPanel.hpp index dbfb70b245..ad0f7f8078 100644 --- a/src/slic3r/GUI/DesignPanel.hpp +++ b/src/slic3r/GUI/DesignPanel.hpp @@ -229,6 +229,7 @@ private: // Plane pickers: fill a choice with XY/XZ/YZ + the document's datum planes, and // map a choice row back to the actual SketchPlane (rows 0-2 base, 3+ datum). void populate_plane_choices(ComboBox* c) const; + wxString ref_plane_name(int row) const; // "XY" / a datum's name, for the on-geometry hint SketchPlane plane_from_choice(int row) const; // Where a new sketch goes, resolved from what is SELECTED IN THE VIEWPORT rather than from a // list: a picked planar face wins, otherwise the reference plane last clicked in 3D. `what` @@ -392,7 +393,10 @@ private: wxSpinCtrl* m_sides{nullptr}; // polygon sides CheckBox* m_poly_circ{nullptr}; // polygon circumscribed toggle (Orca teal check) - ComboBox* m_draw_plane{nullptr}; + // Which reference plane a sketch falls back to when no face is picked: 0/1/2 = XY/XZ/YZ, + // >=3 indexes resolve_datum_planes(). Set by CLICKING a ghost plane in the viewport — there is + // deliberately no dropdown for it. snaporca-e1p. + int m_ref_plane{0}; ComboBox* m_shape{nullptr}; ComboBox* m_plane{nullptr}; ComboBox* m_mode{nullptr};