Merge pull request #5095 from dotCooCoo/fix/mesh-create-outside

Mesh: Create Gradient Mesh at a point outside the object keeps the path
This commit is contained in:
BFlat
2026-11-02 12:29:35 +07:00
committed by GitHub
2 changed files with 44 additions and 1 deletions
+8 -1
View File
@@ -59,7 +59,14 @@ pub(super) fn mesh_create(s: &mut Session, p: &Value) -> Result<Value> {
};
let Some(mut m) = m else { continue };
if let Some(q) = at {
index = m.add_lines_at(q, tol);
// A point the new mesh can't place its lines at leaves the object as it is.
match m.add_lines_at(q, tol) {
Some(i) => index = Some(i),
None => {
refused.get_or_insert("point is outside the object");
continue;
}
}
}
let mut mn = Node::new(n.id, NodeKind::Mesh(m));
mn.name = n.name.clone();
+36
View File
@@ -1040,6 +1040,42 @@ fn mesh_create_at_point_single_undo() {
assert!(b.x0 > -3.0 && b.x1 < 103.0, "{b:?}");
}
/// Create Gradient Mesh with an `at` the new mesh can't place its lines at (outside the object,
/// or past `tolerance`) is an error that leaves the path a path; within `tolerance` it adds them.
#[test]
fn mesh_create_at_a_point_outside_keeps_the_path() {
let mut s = session();
let a = rect(&mut s, 0.0, 0.0, 100.0, 100.0);
sel(&mut s, &[a]);
let n = undo_len(&s);
for p in [json!({"at": [300, 300]}), json!({"at": [50, 103]}), json!({"at": [50, 110], "tolerance": 3})] {
let r = s.execute("object.mesh.create", &p);
assert!(matches!(&r, Err(EngineError::BadParams { msg, .. }) if msg == "point is outside the object"), "{p}: {r:?}");
assert!(matches!(node(&s, a).kind, NodeKind::Path { .. }), "{p}: still a path");
}
assert_eq!(undo_len(&s), n, "nothing changed");
let r = s.execute("object.mesh.create", &json!({"at": [50, 102], "tolerance": 3})).unwrap();
let m = mesh_of(&s, a);
assert_eq!((m.rows, m.cols), (1, 2), "a column through the bottom edge");
assert!(m.points[r["index"].as_u64().unwrap() as usize].p.distance(Point::new(50.0, 100.0)) < 0.5);
}
/// With several objects selected, Create Gradient Mesh at a point turns the objects that hold the
/// point into meshes in one undo step and leaves the others paths, without an error.
#[test]
fn mesh_create_at_a_point_inside_one_of_two_objects_converts_only_that_one() {
let mut s = session();
let a = rect(&mut s, 0.0, 0.0, 100.0, 100.0);
let b = rect(&mut s, 200.0, 0.0, 300.0, 100.0);
sel(&mut s, &[a, b]);
let n = undo_len(&s);
let r = s.execute("object.mesh.create", &json!({"at": [50, 50]})).unwrap();
assert_eq!(r["ids"], json!([a.0]), "{r}");
assert!(matches!(node(&s, a).kind, NodeKind::Mesh(_)), "a holds the point");
assert!(matches!(node(&s, b).kind, NodeKind::Path { .. }), "b stays a path");
assert_eq!(undo_len(&s), n + 1, "one undo step");
}
#[test]
fn mesh_expand_to_flat_pieces() {
let mut s = session();