mirror of
https://github.com/bherbruck/solidcraft.git
synced 2026-11-07 12:31:56 +00:00
Delete: in a rolled-back history, the check builds the history once when nothing breaks (#9917) (#9972)
* Delete: the check in a rolled-back history builds the history once when nothing breaks (#9917) With the history rolled back, the check before a delete (which features the delete would break) built the whole history twice, before and after the change, with the marker removed. On a large design each build ran every boolean after the marker: deleting twelve splines took half a minute on the window thread. Only a feature that fails after the change can be newly broken, so the history after it is built first, and when nothing fails there the history before it isn't built at all. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Delete: test that the check in a rolled-back history still reports what breaks (#9917) Deleting a hole in the plate changes the plate and every cut after the marker and breaks none of them: the check reports nothing. Deleting a side of the outline breaks the plate, and the check still says so, with a cache too small to keep a state. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -336,6 +336,36 @@ mod tests {
|
||||
assert!(s.model.state().sketch(sk).unwrap().sketch.constraints.iter().all(|c| c.id != angle));
|
||||
}
|
||||
|
||||
/// #9917: the check before a delete in a sketch with a rolled-back history after it builds the
|
||||
/// history before the delete only when a feature fails after it. Deleting a hole in the plate
|
||||
/// changes the plate and every cut after it and breaks none of them: the check reports
|
||||
/// nothing. Deleting a side of the plate's outline breaks the plate, and the check still says
|
||||
/// so, with the cache too small to keep a state (as on a large design).
|
||||
#[test]
|
||||
fn a_delete_in_a_rolled_back_history_reports_what_breaks_after_the_marker_and_nothing_else() {
|
||||
let mut s = Session::default();
|
||||
let sk = run(&mut s, "sketch.create", json!({"plane": "XY"}))["sketch"].as_u64().unwrap();
|
||||
let outline = run(&mut s, "sketch.line", json!({"points": [[0, 0], [40, 0], [30, 20], [10, 20]], "closed": true}))["curves"][0]
|
||||
.as_str()
|
||||
.unwrap()
|
||||
.to_string();
|
||||
let hole = run(&mut s, "sketch.circle.center", json!({"center": [30, 15], "radius": 2}))["curves"][0].as_str().unwrap().to_string();
|
||||
run(&mut s, "sketch.finish", json!({}));
|
||||
run(&mut s, "solid.extrude", json!({"distance": 5, "name": "Plate"}));
|
||||
for i in 0..6 {
|
||||
run(&mut s, "solid.cylinder", json!({"base": [12 + 3 * i, 8, -1], "radius": 1, "height": 10, "operation": "cut"}));
|
||||
}
|
||||
run(&mut s, "timeline.roll_to", json!({"position": 1}));
|
||||
run(&mut s, "sketch.edit", json!({"sketch": sk}));
|
||||
*s.model.cache.lock().unwrap() = solidcraft_doc::EvalCache::with_budget(1);
|
||||
let doc = s.doc.clone();
|
||||
let dry = run(&mut s, "selection.delete", json!({"items": [{"type": "sketch_curve", "id": hole}], "dry_run": true}));
|
||||
assert_eq!(dry["would_fail"], json!([]), "{dry}");
|
||||
let dry = run(&mut s, "selection.delete", json!({"items": [{"type": "sketch_curve", "id": outline}], "dry_run": true}));
|
||||
assert!(dry["would_fail"].as_array().unwrap().contains(&json!("Plate")), "{dry}");
|
||||
assert_eq!(*s.doc, *doc, "the checks change nothing");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mixed_selection_is_one_undo_step() {
|
||||
let (mut s, _) = part();
|
||||
|
||||
@@ -1353,7 +1353,14 @@ pub(super) fn newly_broken_in_history(
|
||||
model.evaluate(&doc);
|
||||
model
|
||||
};
|
||||
newly_broken(&whole(before_doc, before), &whole(after_doc, after))
|
||||
// Only a feature that fails after the change can be newly broken: when none does, the
|
||||
// history before it needn't be built again (#9917: each build ran every boolean after the
|
||||
// marker, half a minute on a large design).
|
||||
let after = whole(after_doc, after);
|
||||
if after.results.iter().all(|r| r.error.is_none()) {
|
||||
return Vec::new();
|
||||
}
|
||||
newly_broken(&whole(before_doc, before), &after)
|
||||
}
|
||||
|
||||
/// Whether `after_doc` differs from `before_doc` only in sketch constraints and dimensions (and
|
||||
|
||||
Reference in New Issue
Block a user