use cadcraft_doc::{AssocSnap, DimKind, Dimension, EntityKind, Handle}; use cadcraft_geom::Vec2; use serde_json::{Value, json}; use crate::{Input, Session}; fn h(v: &Value) -> Handle { Handle::parse_hex(v["handle"].as_str().unwrap()).unwrap() } fn dim(s: &Session, hd: Handle) -> Dimension { match &s.doc().unwrap().entity(hd).unwrap().kind { EntityKind::Dimension(d) => d.clone(), other => panic!("not a dimension: {other:?}"), } } fn line(s: &mut Session, a: [f64; 2], b: [f64; 2]) -> Handle { s.execute("line", &json!({ "points": [a, b] })).unwrap(); s.doc().unwrap().model.last().unwrap().handle } fn near(a: Vec2, b: Vec2) -> bool { a.dist(b) < 1e-9 } #[test] fn linear_dimension_follows_line_endpoint() { let mut s = Session::new(); let l = line(&mut s, [0.0, 0.0], [10.0, 0.0]); let d = h(&s.execute("dimlinear", &json!({ "p1": [0, 0], "p2": [10, 0], "at": [5, -2] })).unwrap()); let dm = dim(&s, d); assert_eq!(dm.assoc.len(), 2, "both origins attach to the line: {:?}", dm.assoc); assert!(dm.assoc.iter().all(|a| a.handle == l)); // Move the line's end point: the dimension's second origin follows. s.execute("properties.set", &json!({ "handles": [l.hex()], "end": [12, 0] })).unwrap(); let dm = dim(&s, d); assert!(near(dm.p14.xy(), Vec2::new(12.0, 0.0)), "{:?}", dm.p14); assert!(near(dm.p13.xy(), Vec2::ZERO)); // The dimension line stays where it was. assert!(near(dm.defpt.xy(), Vec2::new(5.0, -2.0))); let g = cadcraft_render::dimension_in(s.doc().unwrap(), &dm); assert_eq!(g.value, "12.0000"); // Undo restores both in one step. s.undo().unwrap(); assert!(near(dim(&s, d).p14.xy(), Vec2::new(10.0, 0.0))); } #[test] fn moving_the_object_carries_the_dimension() { let mut s = Session::new(); let l = line(&mut s, [0.0, 0.0], [10.0, 0.0]); let d = h(&s.execute("dimaligned", &json!({ "p1": [0, 0], "p2": [10, 0], "at": [5, -2] })).unwrap()); s.execute("move", &json!({ "handles": [l.hex()], "from": [0, 0], "to": [3, 4] })).unwrap(); let dm = dim(&s, d); assert!(near(dm.p13.xy(), Vec2::new(3.0, 4.0)) && near(dm.p14.xy(), Vec2::new(13.0, 4.0)), "{dm:?}"); assert!(near(dm.defpt.xy(), Vec2::new(8.0, 2.0)), "rigid move carries the dimension line: {:?}", dm.defpt); // Moving both together keeps them attached and unchanged relative to each other. s.execute("move", &json!({ "handles": [l.hex(), d.hex()], "from": [0, 0], "to": [1, 0] })).unwrap(); let dm = dim(&s, d); assert_eq!(dm.assoc.len(), 2); assert!(near(dm.p13.xy(), Vec2::new(4.0, 4.0)) && near(dm.defpt.xy(), Vec2::new(9.0, 2.0)), "{dm:?}"); } #[test] fn moving_the_object_keeps_the_ordinate_datum() { let mut s = Session::new(); let l = line(&mut s, [5.0, 0.0], [5.0, 5.0]); let d = h(&s.execute("dimordinate", &json!({ "feature": [5, 5], "leader": [5, 8] })).unwrap()); s.execute("move", &json!({ "handles": [l.hex()], "from": [5, 5], "to": [8, 5] })).unwrap(); let dm = dim(&s, d); assert!(near(dm.p13.xy(), Vec2::new(8.0, 5.0)) && near(dm.p14.xy(), Vec2::new(8.0, 8.0)), "{dm:?}"); assert!(near(dm.defpt.xy(), Vec2::ZERO), "datum must stay at the origin: {:?}", dm.defpt); let g = cadcraft_render::dimension_in(s.doc().unwrap(), &dm); assert_eq!(g.value, "8.0000"); } #[test] fn moving_the_line_keeps_a_free_continued_origin() { let mut s = Session::new(); let l = line(&mut s, [0.0, 0.0], [10.0, 0.0]); s.execute("dimlinear", &json!({ "p1": [0, 0], "p2": [10, 0], "at": [5, -2] })).unwrap(); s.execute("dimcontinue", &json!({ "points": [[25, 0]] })).unwrap(); let d = s.doc().unwrap().model.last().unwrap().handle; s.execute("move", &json!({ "handles": [l.hex()], "delta": [3, 0] })).unwrap(); let dm = dim(&s, d); assert!(near(dm.p13.xy(), Vec2::new(13.0, 0.0)), "attached origin follows: {dm:?}"); assert!(near(dm.p14.xy(), Vec2::new(25.0, 0.0)), "free origin stays: {dm:?}"); assert_eq!(cadcraft_render::dimension_in(s.doc().unwrap(), &dm).value, "12.0000"); s.execute("move", &json!({ "handles": [l.hex()], "delta": [3, 0] })).unwrap(); let dm = dim(&s, d); assert!(near(dm.p13.xy(), Vec2::new(16.0, 0.0)) && near(dm.p14.xy(), Vec2::new(25.0, 0.0)), "{dm:?}"); assert_eq!(cadcraft_render::dimension_in(s.doc().unwrap(), &dm).value, "9.0000"); } #[test] fn interactive_dimlinear_select_object_is_associative() { let mut s = Session::new(); s.cmdline("line 0,0 6,0").unwrap(); s.cmdline("").unwrap(); let l = s.doc().unwrap().model.last().unwrap().handle; s.cmdline("dimlinear").unwrap(); s.cmdline("").unwrap(); //