mirror of
https://github.com/storytold/cadcraft.git
synced 2026-10-26 11:56:50 -06:00
Squash of PR #523 by @vangel76. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
68 lines
2.7 KiB
Rust
68 lines
2.7 KiB
Rust
//! The remaining object snaps (#519, gaps.md U8): Insertion on attribute definitions and
|
|
//! multileaders, Geometric Center on closed splines, and no Midpoint on closed curves.
|
|
|
|
use cadcraft_doc::{EntityKind, Space};
|
|
use cadcraft_engine::Session;
|
|
use cadcraft_engine::snap::{self, mode};
|
|
use cadcraft_geom::Vec2;
|
|
use serde_json::json;
|
|
|
|
/// The snap of `modes` near `p` (a hair off it, inside a 0.1 aperture).
|
|
fn snap_at(s: &Session, p: Vec2, modes: u32) -> Option<(Vec2, u32)> {
|
|
snap::osnap(s.doc().unwrap(), &Space::Model, p + Vec2::new(0.02, -0.01), 0.1, modes, None, false).map(|h| (h.point, h.mode))
|
|
}
|
|
|
|
fn near(a: Option<(Vec2, u32)>, p: Vec2, m: u32) -> bool {
|
|
a.is_some_and(|(q, k)| k == m && q.dist(p) < 1e-6)
|
|
}
|
|
|
|
#[test]
|
|
fn insertion_snaps_to_attribute_definitions() {
|
|
let mut s = Session::new();
|
|
s.execute("attdef", &json!({"tag": "PART", "default": "A-1", "at": [3, 4]})).unwrap();
|
|
assert!(near(snap_at(&s, Vec2::new(3.0, 4.0), mode::INS), Vec2::new(3.0, 4.0), mode::INS));
|
|
}
|
|
|
|
#[test]
|
|
fn insertion_snaps_to_a_multileader_text() {
|
|
let mut s = Session::new();
|
|
s.execute("mleader", &json!({"points": [[0, 0], [10, 5]], "text": "NOTE"})).unwrap();
|
|
let at = s
|
|
.doc()
|
|
.unwrap()
|
|
.model
|
|
.iter()
|
|
.find_map(|e| match &e.kind {
|
|
EntityKind::MLeader(m) => m.text.as_ref().map(|t| t.insert.xy()),
|
|
_ => None,
|
|
})
|
|
.expect("a multileader with text");
|
|
assert!(near(snap_at(&s, at, mode::INS), at, mode::INS));
|
|
}
|
|
|
|
#[test]
|
|
fn geometric_center_of_a_closed_spline() {
|
|
let mut s = Session::new();
|
|
// A closed fit spline symmetric about (5,5): its centroid is the centre.
|
|
s.execute("spline", &json!({"fit": [[0, 5], [5, 0], [10, 5], [5, 10]], "closed": true})).unwrap();
|
|
let c = Vec2::new(5.0, 5.0);
|
|
let hit = snap::osnap(s.doc().unwrap(), &Space::Model, c + Vec2::new(0.05, 0.0), 0.5, mode::GCEN, None, false).expect("a geometric center");
|
|
assert_eq!(hit.mode, mode::GCEN);
|
|
assert!(hit.point.dist(c) < 1e-3, "{:?}", hit.point);
|
|
// An open spline has none.
|
|
let mut s = Session::new();
|
|
s.execute("spline", &json!({"fit": [[0, 5], [5, 0], [10, 5], [5, 10]]})).unwrap();
|
|
assert!(snap::osnap(s.doc().unwrap(), &Space::Model, c, 0.5, mode::GCEN, None, false).is_none());
|
|
}
|
|
|
|
#[test]
|
|
fn closed_curves_have_no_midpoint() {
|
|
// As in AutoCAD: Midpoint works on arcs and elliptical arcs, not on a full circle or ellipse.
|
|
let mut s = Session::new();
|
|
s.cmdline("circle 0,0 5").unwrap();
|
|
s.cmdline("ellipse 20,0 30,0 3").unwrap();
|
|
for p in [Vec2::new(-5.0, 0.0), Vec2::new(5.0, 0.0), Vec2::new(10.0, 0.0), Vec2::new(30.0, 0.0), Vec2::new(20.0, 3.0)] {
|
|
assert_eq!(snap_at(&s, p, mode::MID), None, "{p:?}");
|
|
}
|
|
}
|