mirror of
https://github.com/storytold/cadcraft.git
synced 2026-11-09 20:10:12 -06:00
Viewport twist: normalise with norm_angle on read and write; test the untwisted case on a real viewport
From CodeRabbit's review: a tiny negative angle no longer reads as a full turn, a huge finite twist from JSON or MCP no longer writes an infinite group 51, and the "no group 51" check now looks at a viewport that exists. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DRnJvmr59vS3DS5p2E8FhG
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
f7494840dc
commit
c8e1671eb4
@@ -257,7 +257,7 @@ pub(super) fn entity_with_table_budget(kind: &str, tags: &[Tag], table_cells_lef
|
||||
// Status flags: 65536 = non-rectangular clipping (by the 340 entity), 131072 = off.
|
||||
clip: t.s(340).and_then(|h| Handle::parse_hex(&h)).filter(|h| h.0 != 0 && t.i(90).unwrap_or(0) & 65536 != 0),
|
||||
on: t.i(90).unwrap_or(0) & 131072 == 0,
|
||||
twist: t.f(51).filter(|a| a.is_finite()).map_or(0.0, |a| a.rem_euclid(360.0).to_radians()),
|
||||
twist: t.f(51).map_or(0.0, |a| cadcraft_geom::norm_angle(a.to_radians())),
|
||||
}),
|
||||
"WIPEOUT" => {
|
||||
let o = t.p(10);
|
||||
|
||||
@@ -686,8 +686,9 @@ fn write_viewport_entity(w: &mut W, d: &Drawing, e: &Entity, owner: &str, paper:
|
||||
w.i(69, i64::from(v.id));
|
||||
w.p2(12, v.view_center);
|
||||
w.f(45, v.view_height);
|
||||
if v.twist.is_finite() && v.twist != 0.0 {
|
||||
w.f(51, v.twist.to_degrees());
|
||||
let twist = cadcraft_geom::norm_angle(v.twist);
|
||||
if twist != 0.0 {
|
||||
w.f(51, twist.to_degrees());
|
||||
}
|
||||
// Status flags: 16384 = display locked, 32768 = always set, 65536 = clipped by the
|
||||
// 340 entity, 131072 = off.
|
||||
|
||||
@@ -218,12 +218,24 @@ fn viewport_twist_survives_dxf_and_dwg() {
|
||||
assert!((twist_of(&cadcraft_io::read(&dxf, "x.dxf").unwrap()) - twist).abs() < 1e-9);
|
||||
assert!((twist_of(&through_dwg(&d)) - twist).abs() < 1e-9);
|
||||
|
||||
// An untwisted viewport writes no group 51.
|
||||
let plain = records(&String::from_utf8_lossy(&cadcraft_io::write(&Drawing::new_metric(), "x.dxf").unwrap()), "VIEWPORT");
|
||||
assert!(plain.iter().all(|r| group(r, "51").is_none()));
|
||||
// An untwisted viewport writes no group 51; a hostile twist (from JSON or MCP) writes a finite
|
||||
// angle within one turn, or none.
|
||||
for (value, want) in [(0.0, None), (f64::NAN, None), (f64::INFINITY, None), (1e300, Some(()))] {
|
||||
let mut d = Drawing::new_metric();
|
||||
let EntityKind::Viewport(mut vp) = viewport(2) else { unreachable!() };
|
||||
vp.twist = value;
|
||||
let h = d.add(&space, Common::default(), EntityKind::Viewport(vp)).unwrap();
|
||||
let text = String::from_utf8_lossy(&cadcraft_io::write(&d, "x.dxf").unwrap()).to_string();
|
||||
let rec = records(&text, "VIEWPORT").into_iter().find(|r| group(r, "5") == Some(h.hex().as_str())).unwrap();
|
||||
let written = group(&rec, "51").map(|v| v.parse::<f64>().unwrap());
|
||||
assert_eq!(written.map(|_| ()), want, "{value}: {rec:?}");
|
||||
assert!(written.is_none_or(|a| a.is_finite() && (0.0..360.0).contains(&a)), "{value}: {written:?}");
|
||||
}
|
||||
|
||||
// Hostile angles: not a number reads as 0, a huge one is brought into one turn.
|
||||
for (value, want) in [("nan", Some(0.0)), ("1e400", Some(0.0)), ("-330", Some(30f64.to_radians())), ("7200000000000000000030", None)] {
|
||||
for (value, want) in
|
||||
[("nan", Some(0.0)), ("1e400", Some(0.0)), ("-1e-20", Some(0.0)), ("-330", Some(30f64.to_radians())), ("7200000000000000000030", None)]
|
||||
{
|
||||
let mut lines: Vec<String> = text.lines().map(str::to_string).collect();
|
||||
let at = lines.windows(2).position(|w| w[0].trim() == "51" && Some(w[1].trim()) == group(&rec, "51")).unwrap();
|
||||
lines[at + 1] = value.to_string();
|
||||
|
||||
Reference in New Issue
Block a user