mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-18 14:32:36 +00:00
Constraints you apply while sketching are finally visible, and clicking one removes it
The constraint badges existed and had never once been drawn where they were needed. build_constraint_glyphs read m_constrain_cons, a vector only the COMMITTED-feature Constrain mode fills, and the draw call sat inside `if (m_mode == Mode::Constrain)`. Every constraint applied during a live sketch — which is the path the Constrain buttons take while drawing, the one added in "Constrain while you sketch" — went into m_constraints and was rendered by nothing. You could not see that Parallel had applied, so "nothing happens" was indistinguishable from "applied and invisible". The glyph builder now takes its constraint list as a parameter: Constrain mode passes m_constrain_cons as before, the live session passes its own m_constraints. Same glyphs, same teal. Seeing them is half of it. A constraint's entire state is exists / does not exist, so the toggle is a delete, and there was no way to reach one during a session — the ✗ rows in the panel list are bound to the committed feature. Each badge now records where it landed (m_glyph_hits) and a plain left click in Select mode within its cell drops that constraint and re-solves. Shift/Ctrl clicks are left alone so multi-select still works. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011FbJKJAJxxkhDTs9XdZzKA
This commit is contained in:
co-authored by
Claude Opus 5
parent
ea32f8dc2f
commit
3da0af38c3
@@ -2368,6 +2368,25 @@ bool DesignSketchTool::try_add_constraints(const std::vector<SketchEntityConstra
|
||||
return false;
|
||||
}
|
||||
|
||||
// Delete the constraint whose badge is under `p`. Removing a constraint can only FREE degrees
|
||||
// of freedom, so the re-solve cannot fail for over-constraint -- but it is still run, because
|
||||
// the geometry must relax back to what the remaining system allows.
|
||||
bool DesignSketchTool::remove_constraint_near(const Vec2d& p)
|
||||
{
|
||||
if (m_glyph_hits.empty() || m_glyph_r <= 0.0) return false;
|
||||
int best = -1;
|
||||
double best_d = m_glyph_r;
|
||||
for (const GlyphHit& g : m_glyph_hits) {
|
||||
const double d = (g.c - p).norm();
|
||||
if (d < best_d && g.con >= 0 && g.con < int(m_constraints.size())) { best_d = d; best = g.con; }
|
||||
}
|
||||
if (best < 0) return false;
|
||||
m_constraints.erase(m_constraints.begin() + best);
|
||||
solve_sketch_entities(m_entities, m_constraints);
|
||||
m_glyph_hits.clear(); // stale until the next render rebuilds them
|
||||
return true;
|
||||
}
|
||||
|
||||
void DesignSketchTool::infer_auto_constraints(int base, double ang_tol_rad, double weld_tol)
|
||||
{
|
||||
const int n = int(m_entities.size());
|
||||
@@ -7380,9 +7399,11 @@ void DesignSketchTool::render_live_quotes(double unit_per_px)
|
||||
// on-screen size and translated to the anchor; badges on the same entity stack
|
||||
// upward so multiple constraints stay legible.
|
||||
void DesignSketchTool::build_constraint_glyphs(double unit_per_px,
|
||||
std::vector<std::pair<Vec2d, Vec2d>>& out) const
|
||||
const std::vector<SketchEntityConstraintDef>& cons,
|
||||
std::vector<std::pair<Vec2d, Vec2d>>& out)
|
||||
{
|
||||
if (m_constrain_cons.empty() || m_entities.empty()) return;
|
||||
m_glyph_hits.clear();
|
||||
if (cons.empty() || m_entities.empty()) return;
|
||||
using T = SketchConstraintType;
|
||||
const double s = std::max(11.0 * unit_per_px, 1e-4); // glyph cell size in plane units
|
||||
const double step = s * 1.5; // vertical stacking step
|
||||
@@ -7444,10 +7465,13 @@ void DesignSketchTool::build_constraint_glyphs(double unit_per_px,
|
||||
// Stack count per entity so successive badges step upward.
|
||||
std::vector<int> stack(m_entities.size(), 0);
|
||||
const Vec2d up(0.0, 1.0); // plane-space up; offset so badge sits off the geometry
|
||||
for (const SketchEntityConstraintDef& d : m_constrain_cons) {
|
||||
m_glyph_r = 0.6 * s;
|
||||
for (size_t ci = 0; ci < cons.size(); ++ci) {
|
||||
const SketchEntityConstraintDef& d = cons[ci];
|
||||
if (d.ea < 0 || d.ea >= int(m_entities.size())) continue;
|
||||
const int k = stack[d.ea]++;
|
||||
const Vec2d center = anchor_of(d.ea) + up * (step * (1.0 + k));
|
||||
m_glyph_hits.push_back({center, int(ci)});
|
||||
std::vector<std::pair<Vec2d, Vec2d>> cell;
|
||||
unit_glyph(d.type, cell);
|
||||
for (auto& sgp : cell)
|
||||
@@ -8558,7 +8582,7 @@ void DesignSketchTool::render(GLCanvas3D& canvas)
|
||||
{
|
||||
const double upp = 1.0 / std::max(camera.get_zoom(), 1e-6);
|
||||
std::vector<std::pair<Vec2d, Vec2d>> glyphs;
|
||||
build_constraint_glyphs(upp, glyphs);
|
||||
build_constraint_glyphs(upp, m_constrain_cons, glyphs);
|
||||
if (!glyphs.empty()) {
|
||||
const ColorRGBA badge(0.45f, 0.95f, 0.70f, 1.0f); // CAD teal-green
|
||||
draw_strokes(m_fill_model, glyphs, std::max(0.9 * upp, 1e-4), badge);
|
||||
@@ -8672,6 +8696,19 @@ void DesignSketchTool::render(GLCanvas3D& canvas)
|
||||
if (!sel_point_markers.empty())
|
||||
draw_vertices(m_highlight_model, sel_point_markers, sel_col);
|
||||
|
||||
// Constraint badges during a LIVE sketch. They used to render only inside Mode::Constrain
|
||||
// on a COMMITTED feature, so every constraint applied while drawing — which is the path the
|
||||
// Constrain buttons take during a session — was invisible and unremovable: you could not
|
||||
// tell whether Parallel had been applied, nor take it back. Same glyphs, same teal, sourced
|
||||
// from this session's m_constraints; click one to delete it (remove_constraint_near).
|
||||
if (!m_constraints.empty()) {
|
||||
std::vector<std::pair<Vec2d, Vec2d>> glyphs;
|
||||
build_constraint_glyphs(upp_dash, m_constraints, glyphs);
|
||||
if (!glyphs.empty())
|
||||
draw_strokes(m_fill_model, glyphs, std::max(0.9 * upp_dash, 1e-4),
|
||||
ColorRGBA(0.45f, 0.95f, 0.70f, 1.0f)); // CAD teal-green
|
||||
}
|
||||
|
||||
// Endpoint / centre handles so individual points are visible and pickable in the
|
||||
// Select and Dimension tools (a line = a segment + 2 points). Selected ones cyan.
|
||||
m_show_handles = (m_mode == Mode::Select || m_mode == Mode::Dimension);
|
||||
@@ -10225,6 +10262,19 @@ bool DesignSketchTool::on_mouse_impl(wxMouseEvent& evt, GLCanvas3D& canvas)
|
||||
if (update_hover(canvas, evt)) return true; // repaint when the hovered handle changes
|
||||
const bool extend = evt.ShiftDown() || evt.ControlDown();
|
||||
|
||||
// A constraint badge is a click target: clicking it DELETES that constraint. Existing or
|
||||
// not is the whole of a constraint's state, so this click is the toggle. Checked before
|
||||
// entity picking because badges sit clear of the geometry (offset along +Y), so a hit
|
||||
// here is unambiguous; plain click only, so Shift/Ctrl multi-select is never eaten.
|
||||
if (evt.LeftDown() && !extend) {
|
||||
Vec2d gp;
|
||||
if (screen_to_plane(canvas, evt, gp) && remove_constraint_near(gp)) {
|
||||
if (on_selection_changed)
|
||||
on_selection_changed(int(m_selection.size() + m_point_sel.size()));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Live point drag: once an endpoint/centre was grabbed on LeftDown, dragging
|
||||
// moves it (re-solving constraints live) until the button is released. When
|
||||
// nothing is grabbed, drag falls through so the camera can still orbit.
|
||||
|
||||
@@ -485,6 +485,9 @@ public:
|
||||
// inconsistent. Returns true when the batch was kept. Public so the panel's live-constraint
|
||||
// path can commit a plan through the SAME append→solve→keep-or-rollback the gestures use.
|
||||
bool try_add_constraints(const std::vector<SketchEntityConstraintDef>& cands);
|
||||
// Click-to-delete on a constraint badge: drop the constraint whose glyph sits under `p`
|
||||
// and re-solve. Returns true if one was removed (the caller then repaints).
|
||||
bool remove_constraint_near(const Vec2d& p);
|
||||
|
||||
// The loop report: what is CLOSED, what its internal voids are, and where a chain is still
|
||||
// open. This is the answer to "is my profile buildable", and it is the one question the
|
||||
@@ -831,7 +834,9 @@ private:
|
||||
// Iconic constraint badges (C3.4b): for each m_constrain_cons entry, append a
|
||||
// small screen-constant glyph (H, V, ∥, ⊥, =, ○, …) near its primary entity into
|
||||
// `out`; glyphs touching the same entity stack so they don't overlap.
|
||||
void build_constraint_glyphs(double unit_per_px, std::vector<std::pair<Vec2d, Vec2d>>& out) const;
|
||||
void build_constraint_glyphs(double unit_per_px,
|
||||
const std::vector<SketchEntityConstraintDef>& cons,
|
||||
std::vector<std::pair<Vec2d, Vec2d>>& out);
|
||||
void draw_strokes(GLModel& model, const std::vector<std::pair<Vec2d, Vec2d>>& segs,
|
||||
double hw, const ColorRGBA& color);
|
||||
void draw_text(GLModel& model, const std::string& s, const Vec2d& center,
|
||||
@@ -1099,6 +1104,11 @@ private:
|
||||
Vec2d m_pick0_pt{0,0}; // plane-coords of the slot-0 pick (trim/extend)
|
||||
std::vector<int> m_constraint_hl; // entities highlighted by the constraint manager
|
||||
std::vector<SketchEntityConstraintDef> m_constrain_cons; // for glyph badges (C3.4b)
|
||||
// Where each badge landed, so a click can find the constraint it stands for. Rebuilt by
|
||||
// build_constraint_glyphs on every render, which is always the frame the user clicked on.
|
||||
struct GlyphHit { Vec2d c{0,0}; int con{-1}; };
|
||||
std::vector<GlyphHit> m_glyph_hits;
|
||||
double m_glyph_r{0.0}; // badge half-size in plane units (hit radius)
|
||||
GLModel m_line_model;
|
||||
GLModel m_vertex_model;
|
||||
GLModel m_highlight_model;
|
||||
|
||||
Reference in New Issue
Block a user