Files
cadcraft/crates/engine/tests/zoom_viewport.rs

110 lines
4.9 KiB
Rust
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! ZOOM inside a layout viewport (MSPACE) works on that viewport, as in AutoCAD: Extents and
//! Window fit the viewport, nX keeps its centre, nXP sets its scale (#370).
use cadcraft_doc::{EntityKind, Viewport};
use cadcraft_engine::Session;
use serde_json::json;
fn viewport(s: &Session, h: &str) -> Viewport {
let d = s.doc().unwrap();
let e = d.layout("Layout1").unwrap().entities.iter().find(|e| e.handle.hex() == h).unwrap();
match &e.kind {
EntityKind::Viewport(v) => v.clone(),
_ => panic!("not a viewport"),
}
}
/// A 1000 × 500 model and a 100 × 80 viewport on Layout1, entered with MSPACE.
fn session() -> (Session, String) {
let mut s = Session::new();
s.new_drawing(true);
s.viewport_px = (1600.0, 900.0);
s.execute("line", &json!({"points": [[0, 0], [1000, 0]]})).unwrap();
s.execute("line", &json!({"points": [[0, 0], [0, 500]]})).unwrap();
s.execute("layout.set", &json!({"name": "Layout1"})).unwrap();
let r = s.execute("mview", &json!({"p1": [20, 20], "p2": [120, 100]})).unwrap();
let h = r["viewports"][0].as_str().unwrap().to_string();
s.execute("viewport.set", &json!({"handle": h, "scale": 1, "center": [0, 0]})).unwrap();
s.execute("mspace", &json!({"handle": h})).unwrap();
(s, h)
}
#[test]
fn zoom_inside_a_viewport_acts_on_the_viewport() {
let (mut s, h) = session();
let paper = s.state().unwrap().paper_view();
// Extents fit the viewport (aspect 1.25): 1000 wide needs a view height of 800.
s.cmdline("zoom e").unwrap();
let v = viewport(&s, &h);
assert!(v.view_center.near(cadcraft_geom::Vec2::new(500.0, 250.0), 1e-6), "{:?}", v.view_center);
assert!(v.view_height >= 800.0 && v.view_height < 900.0, "{}", v.view_height);
// nX zooms about the viewport centre.
s.cmdline("zoom 2x").unwrap();
let v2 = viewport(&s, &h);
assert!(v2.view_center.near(v.view_center, 1e-6), "{:?}", v2.view_center);
assert!((v2.view_height - v.view_height / 2.0).abs() < 1e-9);
// nXP sets the scale (paper units per model unit), whatever the zoom before.
for (t, scale) in [("zoom 0.1xp", 0.1), ("zoom 1/50xp", 0.02), ("zoom 1/50xp", 0.02)] {
s.cmdline(t).unwrap();
let v = viewport(&s, &h);
assert!((v.height / v.view_height - scale).abs() < 1e-12, "{t}: {}", v.height / v.view_height);
assert!(v.view_center.near(cadcraft_geom::Vec2::new(500.0, 250.0), 1e-6), "{t}: {:?}", v.view_center);
}
// A window fills the viewport: 200 × 100 at aspect 1.25 → height 160.
s.cmdline("zoom w 400,200 600,300").unwrap();
let v = viewport(&s, &h);
assert!(v.view_center.near(cadcraft_geom::Vec2::new(500.0, 250.0), 1e-6), "{:?}", v.view_center);
assert!((v.view_height - 160.0).abs() < 1e-9, "{}", v.view_height);
// The JSON form agrees, and the sheet itself never moves.
s.execute("zoom", &json!({"mode": "scale", "factor": 0.25, "xp": true})).unwrap();
assert!((viewport(&s, &h).view_height - 320.0).abs() < 1e-9);
assert_eq!(s.state().unwrap().paper_view(), paper);
}
#[test]
fn a_view_too_large_for_the_viewport_is_refused_and_keeps_the_viewport() {
// A small paper view makes a finite but huge request map to an infinite model view (#714).
let (mut s, h) = session();
s.execute("pspace", &json!({})).unwrap();
s.execute("view.set", &json!({"center": [70, 60], "height": 0.5})).unwrap();
s.execute("mspace", &json!({"handle": h})).unwrap();
let before = viewport(&s, &h);
assert!(s.execute("view.set", &json!({"center": [0, 0], "height": 1e308})).is_err());
let after = viewport(&s, &h);
assert_eq!(after, before);
assert!(after.view_center.is_finite() && after.view_height.is_finite());
// A representable view still applies.
s.execute("view.set", &json!({"center": [0, 0], "height": 1})).unwrap();
let v = viewport(&s, &h);
assert!(v.view_height.is_finite() && v.view_height != before.view_height, "{}", v.view_height);
}
#[test]
fn zoom_in_a_locked_viewport_or_on_the_model_tab_is_unchanged() {
// A locked viewport keeps its view: ZOOM moves the sheet instead.
let (mut s, h) = session();
s.execute("viewport.set", &json!({"handle": h, "locked": true})).unwrap();
let before = viewport(&s, &h);
let paper = s.state().unwrap().paper_view();
s.cmdline("zoom e").unwrap();
s.cmdline("zoom 0.1xp").unwrap();
assert_eq!(viewport(&s, &h), before);
assert_ne!(s.state().unwrap().paper_view(), paper);
// The Model tab still fits the drawing window; nXP there acts like nX.
let mut s = Session::new();
s.new_drawing(true);
s.viewport_px = (1600.0, 900.0);
s.execute("line", &json!({"points": [[0, 0], [1000, 0]]})).unwrap();
s.cmdline("zoom e").unwrap();
let v = s.state().unwrap().view();
assert!((v.height - 1000.0 / (1600.0 / 900.0) * 1.05).abs() < 1e-6, "{}", v.height);
s.cmdline("zoom 2xp").unwrap();
assert!((s.state().unwrap().view().height - v.height / 2.0).abs() < 1e-9);
}