mirror of
https://github.com/storytold/effectcraft.git
synced 2026-10-14 19:27:05 -04:00
Merge pull request #342 from HEOJUNFO/fix-313-single-pin-jump
Puppet: the first pin no longer turns the layer about it (#313)
This commit is contained in:
commit
e52ff9ab95
3 files changed
+40
No files matched your search
@@ -164,6 +164,12 @@ pub fn deform(rest: &[[f64; 2]], tris: &[[usize; 3]], weights: &[f64], h: &Handl
|
||||
t[1] /= h.fixed.len() as f64;
|
||||
}
|
||||
let x0: Vec<[f64; 2]> = rest.iter().map(|p| [p[0] + t[0], p[1] + t[1]]).collect();
|
||||
// One pin and no edge targets: every rotation and scale about the pin costs nothing, and
|
||||
// the regulariser that picks the translation is too weak to stop CG turning round-off
|
||||
// into a visible rotation (#313). The translation is the exact solution.
|
||||
if h.fixed.len() == 1 && h.edges.is_empty() {
|
||||
return x0;
|
||||
}
|
||||
let mut fixed = vec![false; n];
|
||||
for (i, _) in &h.fixed {
|
||||
fixed[*i] = true;
|
||||
|
||||
@@ -306,3 +306,20 @@ fn groups_round_trip_serde() {
|
||||
assert_eq!(m[0].pins[1].kind, PinKind::Starch);
|
||||
assert_eq!(m[0].pins[0].position, [3.0, 4.0]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_pin_on_a_traced_solid_does_not_rotate_it() {
|
||||
// #313: an 800×600 solid traced from its alpha, as the Puppet Pin tool builds it. One
|
||||
// pin is not enough to rotate or scale the mesh, so it may only translate it.
|
||||
let (w, h) = (800, 600);
|
||||
let o = outline(&vec![1.0; w * h], w, h, 1.0, [0.0; 2], [400.0, 300.0], 3.0);
|
||||
let m = triangulate(&o, &MeshOpts::default());
|
||||
check_valid(&m);
|
||||
for at in [[40.0, 40.0], [760.0, 30.0], [20.0, 580.0], [790.0, 590.0], [400.0, 300.0], [123.0, 456.0]] {
|
||||
for t in [[0.0, 0.0], [35.0, -20.0]] {
|
||||
let d = solve(&m, &[pin(PinKind::Position, at, [at[0] + t[0], at[1] + t[1]])], 2);
|
||||
let err = d.iter().zip(&m.verts).map(|(a, b)| (a[0] - b[0] - t[0]).hypot(a[1] - b[1] - t[1])).fold(0.0, f64::max);
|
||||
assert!(err < 1e-6, "pin at {at:?} moved by {t:?}: vertices off by up to {err} px");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -186,6 +186,23 @@ fn puppet_pins_deform_and_undo() {
|
||||
assert_eq!(px(&s, 1.0, 100, 25), [0.0, 0.0, 1.0, 1.0]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn first_puppet_pin_leaves_the_layer_still() {
|
||||
// #313: an 800×600 solid in a 1920×1080 comp turned about the first pin at these spots.
|
||||
let mut s = Session::default();
|
||||
s.execute("comp.new", json!({"name": "C", "width": 1920, "height": 1080, "duration": 2, "frameRate": 30})).unwrap();
|
||||
let id = s.execute("layer.newSolid", json!({"width": 800, "height": 600, "color": [0, 0, 1]})).unwrap()["layer"].as_u64().unwrap();
|
||||
let cid = s.active_comp_id().unwrap();
|
||||
let before = s.render(cid, Tick::ZERO, RenderOpts::default());
|
||||
for at in [[40, 40], [400, 300], [123, 456]] {
|
||||
s.execute("puppet.addPin", json!({"layer": id, "position": at})).unwrap();
|
||||
let after = s.render(cid, Tick::ZERO, RenderOpts::default());
|
||||
let moved = after.data.iter().zip(&before.data).filter(|(a, b)| (0..4).any(|c| (a[c] - b[c]).abs() > 1e-3)).count();
|
||||
assert_eq!(moved, 0, "pin at {at:?} changed {moved} pixels");
|
||||
s.undo();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn puppet_pin_kinds_and_mesh_options() {
|
||||
let (mut s, id) = setup();
|
||||
|
||||
Reference in new issue
Block a user