Envelopes: a warp handle placed at its own end leaves the warp

object.mesh.movePoint and object.envelope.setMeshPoint compare a handle
end with point plus handle, the form the caller sends, so a rounding
difference in (p + v) - p no longer turns an unchanged warp into a mesh
envelope with an undo step.
This commit is contained in:
dotCooCoo
2026-11-12 22:29:14 -08:00
parent 4316f819a8
commit e5e35e4a5a
2 changed files with 26 additions and 1 deletions
+2 -1
View File
@@ -153,7 +153,8 @@ pub(super) fn warp_point_stays(d: &Document, id: NodeId, index: usize, handle: O
};
let grid = envelope_grid_to_edit(n, cmd, true)?;
Ok(grid.points.get(index).is_some_and(|pt| match handle {
Some(h) => pt.handles.get(h).is_some_and(|v| *v == q - pt.p),
// The caller sends a handle's end as point plus handle; `q - p` can round away from it.
Some(h) => pt.handles.get(h).is_some_and(|v| pt.p + *v == q),
None => pt.p == q,
}))
}
+24
View File
@@ -326,6 +326,30 @@ fn a_warp_edit_that_moves_nothing_leaves_the_warp() {
assert!(s.execute("object.mesh.movePoints", &json!({"id": 99999, "points": [], "dx": 1, "dy": 0})).is_err());
}
/// A handle placed at its own end, sent as point plus handle, leaves a warp a warp, even where
/// `(p + v) - p` rounds to a value other than `v`.
#[test]
fn a_warp_handle_placed_at_its_end_leaves_the_warp() {
let mut s = session();
let (_, e) = enveloped(&mut s, "object.envelope.makeWithWarp", json!({"style": "arc", "bend": 50}));
let (warp, n) = (node(&s, e), undo_len(&s));
let grid = live::warp_grid(&warp).unwrap();
let mut rounds = 0;
for (index, pt) in grid.points.iter().enumerate() {
for (h, v) in pt.handles.iter().enumerate() {
let end = pt.p + *v;
if end - pt.p != *v {
rounds += 1;
}
for cmd in ["object.mesh.movePoint", "object.envelope.setMeshPoint"] {
s.execute(cmd, &json!({"id": e.0, "index": index, "x": end.x, "y": end.y, "handle": h})).unwrap();
assert_eq!((node(&s, e), undo_len(&s)), (warp.clone(), n), "{cmd}: point {index}, handle {h}");
}
}
}
assert!(rounds > 0, "the grid has a handle whose end does not give the handle back");
}
/// With Direct Selection, a selected warp's point drags as `object.mesh.movePoint`: the preview
/// makes it a mesh envelope, Escape gives back the warp with no undo step, and a finished drag is
/// one undo step. While its contents are edited, its points don't take the press.