Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
moppeeerandClaude Opus 5.5 committed 2026-10-29 13:31:57 +01:00
1 parent 542ee6d5bc
commit dccda2cd4c
1 file changed
+57 -57
+57 -57
View File
@@ -86,65 +86,65 @@ fn bleed_and_slug_are_preview_modes_that_show_their_area() {
}
}
/// An empty graphic frame's X joins its corners: a rectangle's, and a frame slanted by
/// moving its top points, as in the Zero2Graphic tutorial's row of parallelograms.
#[test]
fn an_empty_frames_x_follows_its_corners() {
let mut app = DesignApp::new(designcraft_engine::Session::new(), crate::Services::default());
app.run("file.new", json!({})).unwrap();
let id = app.run("frame.create", json!({"rect": [100, 100, 200, 160]})).unwrap()["id"].as_u64().unwrap();
let x = |app: &DesignApp| {
let it = app.session.active().unwrap().doc.item(designcraft_doc::ItemId(id)).unwrap().clone();
let m = it.xf;
frame_x(&it).map(|(a, b)| {
let (a, b) = (m * a, m * b);
[(a.x.round(), a.y.round()), (b.x.round(), b.y.round())]
})
};
let mut lines = x(&app).to_vec();
lines.iter_mut().for_each(|l| l.sort_by(|a, b| a.partial_cmp(b).unwrap()));
lines.sort_by(|a, b| a.partial_cmp(b).unwrap());
assert_eq!(lines, vec![[(100.0, 100.0), (200.0, 160.0)], [(100.0, 160.0), (200.0, 100.0)]], "corner to corner");
// Slant it: the two top points move 30 pt right.
/// An empty graphic frame's X joins its corners: a rectangle's, and a frame slanted by
/// moving its top points, as in the Zero2Graphic tutorial's row of parallelograms.
#[test]
fn an_empty_frames_x_follows_its_corners() {
let mut app = DesignApp::new(designcraft_engine::Session::new(), crate::Services::default());
app.run("file.new", json!({})).unwrap();
let id = app.run("frame.create", json!({"rect": [100, 100, 200, 160]})).unwrap()["id"].as_u64().unwrap();
let x = |app: &DesignApp| {
let it = app.session.active().unwrap().doc.item(designcraft_doc::ItemId(id)).unwrap().clone();
let top: Vec<Value> =
it.path.subpaths[0].anchors.iter().enumerate().filter(|(_, a)| (it.xf * a.p).y < 130.0).map(|(k, _)| json!([0, k])).collect();
assert_eq!(top.len(), 2);
app.run("path.moveAnchors", json!({"id": id, "anchors": top, "dx": 30, "dy": 0})).unwrap();
let mut lines = x(&app).to_vec();
lines.iter_mut().for_each(|l| l.sort_by(|a, b| a.partial_cmp(b).unwrap()));
lines.sort_by(|a, b| a.partial_cmp(b).unwrap());
assert_eq!(lines, vec![[(100.0, 160.0), (230.0, 100.0)], [(130.0, 100.0), (200.0, 160.0)]], "the slanted corners");
// An ellipse frame (four smooth anchors) keeps the X across its bounds, not a plus.
let e = app.run("frame.create", json!({"rect": [300, 100, 400, 160], "shape": "ellipse"})).unwrap()["id"].as_u64().unwrap();
let it = app.session.active().unwrap().doc.item(designcraft_doc::ItemId(e)).unwrap().clone();
let mut lines: Vec<[(f64, f64); 2]> = frame_x(&it)
.map(|(a, b)| {
let (a, b) = (it.xf * a, it.xf * b);
[(a.x.round(), a.y.round()), (b.x.round(), b.y.round())]
})
.to_vec();
lines.iter_mut().for_each(|l| l.sort_by(|a, b| a.partial_cmp(b).unwrap()));
lines.sort_by(|a, b| a.partial_cmp(b).unwrap());
assert_eq!(lines, vec![[(300.0, 100.0), (400.0, 160.0)], [(300.0, 160.0), (400.0, 100.0)]], "the ellipse's bounds");
// So does a four-sided polygon frame (a diamond): its corners would cross as a plus.
let mut diamond = it.clone();
diamond.shape = designcraft_doc::Shape::Polygon;
for a in &mut diamond.path.subpaths[0].anchors {
(a.h_in, a.h_out) = (a.p, a.p);
}
let lines: Vec<_> = frame_x(&diamond).to_vec();
assert!(lines.iter().all(|(a, b)| (a.x - b.x).abs() > 1e-6 && (a.y - b.y).abs() > 1e-6), "diagonals, not a plus: {lines:?}");
// Still after one of its points moves (which makes it a path).
let p = app.run("frame.create", json!({"rect": [300, 200, 400, 260], "shape": "polygon", "sides": 4, "starInset": 0})).unwrap()["id"]
.as_u64()
.unwrap();
app.run("path.moveAnchors", json!({"id": p, "anchors": [[0, 0]], "dx": 5, "dy": 0})).unwrap();
let it = app.session.active().unwrap().doc.item(designcraft_doc::ItemId(p)).unwrap().clone();
assert_eq!(it.shape, designcraft_doc::Shape::Path);
let lines: Vec<_> = frame_x(&it).to_vec();
assert!(lines.iter().all(|(a, b)| (a.x - b.x).abs() > 1e-6 && (a.y - b.y).abs() > 1e-6), "an edited diamond: {lines:?}");
let m = it.xf;
frame_x(&it).map(|(a, b)| {
let (a, b) = (m * a, m * b);
[(a.x.round(), a.y.round()), (b.x.round(), b.y.round())]
})
};
let mut lines = x(&app).to_vec();
lines.iter_mut().for_each(|l| l.sort_by(|a, b| a.partial_cmp(b).unwrap()));
lines.sort_by(|a, b| a.partial_cmp(b).unwrap());
assert_eq!(lines, vec![[(100.0, 100.0), (200.0, 160.0)], [(100.0, 160.0), (200.0, 100.0)]], "corner to corner");
// Slant it: the two top points move 30 pt right.
let it = app.session.active().unwrap().doc.item(designcraft_doc::ItemId(id)).unwrap().clone();
let top: Vec<Value> =
it.path.subpaths[0].anchors.iter().enumerate().filter(|(_, a)| (it.xf * a.p).y < 130.0).map(|(k, _)| json!([0, k])).collect();
assert_eq!(top.len(), 2);
app.run("path.moveAnchors", json!({"id": id, "anchors": top, "dx": 30, "dy": 0})).unwrap();
let mut lines = x(&app).to_vec();
lines.iter_mut().for_each(|l| l.sort_by(|a, b| a.partial_cmp(b).unwrap()));
lines.sort_by(|a, b| a.partial_cmp(b).unwrap());
assert_eq!(lines, vec![[(100.0, 160.0), (230.0, 100.0)], [(130.0, 100.0), (200.0, 160.0)]], "the slanted corners");
// An ellipse frame (four smooth anchors) keeps the X across its bounds, not a plus.
let e = app.run("frame.create", json!({"rect": [300, 100, 400, 160], "shape": "ellipse"})).unwrap()["id"].as_u64().unwrap();
let it = app.session.active().unwrap().doc.item(designcraft_doc::ItemId(e)).unwrap().clone();
let mut lines: Vec<[(f64, f64); 2]> = frame_x(&it)
.map(|(a, b)| {
let (a, b) = (it.xf * a, it.xf * b);
[(a.x.round(), a.y.round()), (b.x.round(), b.y.round())]
})
.to_vec();
lines.iter_mut().for_each(|l| l.sort_by(|a, b| a.partial_cmp(b).unwrap()));
lines.sort_by(|a, b| a.partial_cmp(b).unwrap());
assert_eq!(lines, vec![[(300.0, 100.0), (400.0, 160.0)], [(300.0, 160.0), (400.0, 100.0)]], "the ellipse's bounds");
// So does a four-sided polygon frame (a diamond): its corners would cross as a plus.
let mut diamond = it.clone();
diamond.shape = designcraft_doc::Shape::Polygon;
for a in &mut diamond.path.subpaths[0].anchors {
(a.h_in, a.h_out) = (a.p, a.p);
}
let lines: Vec<_> = frame_x(&diamond).to_vec();
assert!(lines.iter().all(|(a, b)| (a.x - b.x).abs() > 1e-6 && (a.y - b.y).abs() > 1e-6), "diagonals, not a plus: {lines:?}");
// Still after one of its points moves (which makes it a path).
let p = app.run("frame.create", json!({"rect": [300, 200, 400, 260], "shape": "polygon", "sides": 4, "starInset": 0})).unwrap()["id"]
.as_u64()
.unwrap();
app.run("path.moveAnchors", json!({"id": p, "anchors": [[0, 0]], "dx": 5, "dy": 0})).unwrap();
let it = app.session.active().unwrap().doc.item(designcraft_doc::ItemId(p)).unwrap().clone();
assert_eq!(it.shape, designcraft_doc::Shape::Path);
let lines: Vec<_> = frame_x(&it).to_vec();
assert!(lines.iter().all(|(a, b)| (a.x - b.x).abs() > 1e-6 && (a.y - b.y).abs() > 1e-6), "an edited diamond: {lines:?}");
}
/// Each preview mode's shown area: Preview stops at the trim, Bleed reaches the bleed box and
/// Slug the slug box. A slug narrower than the bleed never pulls the edge back in.