mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-18 22:42:37 +00:00
A reference is a reference whatever feature holds it
Port of snaporca 1bb9825db0. Four defects from an independent 20-agent audit, each verified in the code first; two further findings from the same report were verified OUT and are not in this commit. remove_feature()/move_feature() remapped Extrude::sketch_ref and a Mate's two connectors and nothing else, leaving seven of the nine index-bearing fields — sweep_path_ref, loft_profile_refs[], pattern_curve_sketch, rib_sketch_ref, and sketch_ref on Revolve, Sweep, Rib and the Surface* family — pointing at whatever slid into the slot. Quiet by construction: the shifted index still names a real feature, recompute() succeeds, the solid is built from the wrong profile. The comment above the loop already required "EVERY field holding a feature index"; the code under it handled two, because a type switch is only correct on the day it is written. for_each_feature_ref() visits the FIELDS instead, so a feature type added later is covered the moment it reuses one. plane_base and axis_plane_a/b are excluded on purpose and documented at the helper — they encode an ordinal into the datum-plane list, not an index into features[], and are filed separately. The delete cascade got the same field-based treatment. The regression test was run against the pre-fix code to prove it bites: all three sections fail there, and move_feature returns TRUE while leaving sketch_ref == 1 where it must be 0 — success with the wrong answer, which is what makes this class expensive. apply_constraint, commit_entity_constraints and delete_constraint mutated the recipe with no checkpoint() and no sync_recipe_to_model(), alone among seventeen mutation sites in that file: Ctrl+Z reached past the constraint edit and discarded unrelated work, and saving persisted the pre-constraint blob. A rejected constraint now calls abandon_checkpoint() rather than leaving an undo step that does nothing. MCP: params["generation"].get<uint64_t>() sat outside the try inside a bare CallAfter lambda, so one malformed string terminated the process through the wx event loop; it is type-checked now and the lambda lets nothing escape. The socket bound with no mode of its own in a world-writable directory — umask around bind() plus chmod, and it refuses to listen rather than listen wide. The reply write is no longer a bare write(), which could SIGPIPE the app when a client hung up. Kernel suite on this fork: 190 cases / 2562 assertions, green. GUI target compiles. The full ladder gate ran on snaporca (ALL LADDERS HELD — gestures 98/98, offer 108/108, corpus and corpus-scale green) and fork-check parity holds at 17 identical / 8 diverging as expected, which is what makes that gate transferable here. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MrMzTpAf78U4NG2M8jfvHY
This commit is contained in:
co-authored by
Claude Opus 5
parent
6e7f6429fa
commit
3fd5c3353a
@@ -7850,16 +7850,25 @@ void DesignPanel::commit_entity_constraints(const std::vector<SketchEntityConstr
|
||||
// (Symmetric on two lines) must solve together, so push all then resize back.
|
||||
const std::vector<SketchEntity> saved = feat.entities;
|
||||
const size_t before = feat.entity_constraints.size();
|
||||
// Undo boundary: adding a constraint. Without it Ctrl+Z reached PAST this edit to the
|
||||
// previous boundary and threw away whatever happened in between — a constraint was the
|
||||
// one document mutation the user could not take back on its own.
|
||||
m_doc.checkpoint();
|
||||
for (const auto& d : defs) feat.entity_constraints.push_back(d);
|
||||
if (!m_doc.solve_sketch_feature(m_constrain_feat)) {
|
||||
feat.entity_constraints.resize(before);
|
||||
feat.entities = saved;
|
||||
m_doc.abandon_checkpoint(); // fully restored above: nothing happened, so nothing to undo
|
||||
m_status->SetForegroundColour(wxColour(235, 110, 110));
|
||||
set_status(_L("Constraint rejected (over-constrained)"));
|
||||
m_status->Refresh();
|
||||
return;
|
||||
}
|
||||
m_doc.recompute();
|
||||
// The constraint lives in the recipe, so the save path has to be told the recipe moved;
|
||||
// otherwise saving after a constraint edit wrote the blob from before it.
|
||||
sync_recipe_to_model();
|
||||
update_undo_redo_buttons();
|
||||
m_viewport->update_constrain_entities(m_doc.features[m_constrain_feat].entities);
|
||||
if (!m_doc.display_mesh.its.indices.empty())
|
||||
feed_bodies();
|
||||
@@ -8029,11 +8038,14 @@ void DesignPanel::delete_constraint(int idx)
|
||||
CadFeature& feat = m_doc.features[m_constrain_feat];
|
||||
if (idx < 0 || idx >= int(feat.entity_constraints.size()))
|
||||
return;
|
||||
m_doc.checkpoint(); // undo boundary: deleting a constraint
|
||||
feat.entity_constraints.erase(feat.entity_constraints.begin() + idx);
|
||||
// Re-solve the remaining system (deleting a constraint can only free DoF, so it
|
||||
// cannot fail for over-constraint; ignore the bool and refresh either way).
|
||||
m_doc.solve_sketch_feature(m_constrain_feat);
|
||||
m_doc.recompute();
|
||||
sync_recipe_to_model(); // the removal is part of the recipe
|
||||
update_undo_redo_buttons();
|
||||
m_viewport->set_constraint_highlight({});
|
||||
m_viewport->update_constrain_entities(m_doc.features[m_constrain_feat].entities);
|
||||
if (!m_doc.display_mesh.its.indices.empty())
|
||||
@@ -8867,16 +8879,20 @@ void DesignPanel::apply_constraint(SketchConstraintType type)
|
||||
// solve_sketch_feature rewrites profile.points even on failure, so snapshot
|
||||
// the geometry to roll back a rejected constraint cleanly.
|
||||
const std::vector<Vec2d> saved_pts = feat.profile.points;
|
||||
m_doc.checkpoint(); // undo boundary: adding a constraint (profile sketches)
|
||||
feat.constraints.push_back(SketchConstraintDef{type, a, b, -1, -1, 0.0});
|
||||
if (!m_doc.solve_sketch_feature(m_constrain_feat)) {
|
||||
feat.constraints.pop_back(); // reject the non-converging addition
|
||||
feat.profile.points = saved_pts; // and restore the pre-solve geometry
|
||||
m_doc.abandon_checkpoint(); // restored: no state change, so no undo step
|
||||
m_status->SetForegroundColour(wxColour(235, 110, 110));
|
||||
set_status(_L("Constraint rejected (over-constrained)"));
|
||||
m_status->Refresh();
|
||||
return;
|
||||
}
|
||||
m_doc.recompute();
|
||||
sync_recipe_to_model();
|
||||
update_undo_redo_buttons();
|
||||
m_viewport->update_constrain_profile(m_doc.features[m_constrain_feat].profile.points);
|
||||
if (!m_doc.display_mesh.its.indices.empty())
|
||||
feed_bodies();
|
||||
|
||||
Reference in New Issue
Block a user