mirror of
https://github.com/storytold/cadcraft.git
synced 2026-10-25 03:16:50 -06:00
Squash of PR #522 by @vangel76. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
85 lines
3.7 KiB
Rust
85 lines
3.7 KiB
Rust
//! Angular extension lines stay with their legs when the arc is on the other side, and the
|
|
//! DIMCEN centre mark is drawn only when the dimension line is outside the circle (issue #374).
|
|
|
|
use cadcraft_doc::{DimKind, DimStyle, Dimension};
|
|
use cadcraft_geom::{Vec2, Vec3};
|
|
use cadcraft_render::{LineRole, dimension_geometry};
|
|
|
|
fn dim(kind: DimKind) -> Dimension {
|
|
Dimension {
|
|
kind,
|
|
defpt: Vec3::ZERO,
|
|
text_mid: Vec3::ZERO,
|
|
p13: Vec3::ZERO,
|
|
p14: Vec3::ZERO,
|
|
p15: Vec3::ZERO,
|
|
p16: Vec3::ZERO,
|
|
text: String::new(),
|
|
style: "Standard".into(),
|
|
measurement: 0.0,
|
|
text_rotation: 0.0,
|
|
user_text_pos: false,
|
|
block: None,
|
|
overrides: Default::default(),
|
|
assoc: Vec::new(),
|
|
marks: Default::default(),
|
|
}
|
|
}
|
|
|
|
fn ext_lines(d: &Dimension, st: &DimStyle) -> Vec<Vec<Vec2>> {
|
|
dimension_geometry(d, st, 1.0).lines_of(LineRole::Ext).cloned().collect()
|
|
}
|
|
|
|
fn near(a: Vec2, b: Vec2) -> bool {
|
|
a.dist(b) < 1e-9
|
|
}
|
|
|
|
#[test]
|
|
fn angular_extension_lines_follow_their_legs_when_the_arc_is_swapped() {
|
|
// Vertex 0,0; leg 1 to 10,0 (reaches past the arc), leg 2 to 0,2 (short of it); the arc
|
|
// location -3,-3 is outside the 0°→90° sweep, so the 270° arc runs from leg 2 to leg 1.
|
|
let mut a = dim(DimKind::Angular3P);
|
|
a.p13 = Vec3::new(10.0, 0.0, 0.0);
|
|
a.p14 = Vec3::new(0.0, 2.0, 0.0);
|
|
a.defpt = Vec3::new(-3.0, -3.0, 0.0);
|
|
let st = DimStyle::default();
|
|
assert_eq!(dimension_geometry(&a, &st, 1.0).value, "270°");
|
|
let r = 18f64.sqrt();
|
|
// Only leg 2 needs an extension line: from DIMEXO past 0,2 to DIMEXE past the arc.
|
|
let lines = ext_lines(&a, &st);
|
|
assert_eq!(lines.len(), 1, "{lines:?}");
|
|
assert!(near(lines[0][0], Vec2::new(0.0, 2.0 + st.ext_offset)) && near(lines[0][1], Vec2::new(0.0, r + st.ext_extend)), "{lines:?}");
|
|
// DIMSE1 belongs to leg 1 (which has none), DIMSE2 to leg 2.
|
|
assert_eq!(ext_lines(&a, &DimStyle { suppress_ext1: true, ..DimStyle::default() }), lines);
|
|
assert!(ext_lines(&a, &DimStyle { suppress_ext2: true, ..DimStyle::default() }).is_empty());
|
|
// DIMBLK1 sits on leg 1's end of the arc.
|
|
let dot1 = DimStyle { arrow_block1: "_DOT".into(), arrow_block2: "_NONE".into(), ..DimStyle::default() };
|
|
let g = dimension_geometry(&a, &dot1, 1.0);
|
|
assert!(!g.fills.is_empty() && g.fills.iter().flatten().all(|p| p.dist(Vec2::new(r, 0.0)) < st.arrow_size), "{:?}", g.fills.first());
|
|
}
|
|
|
|
#[test]
|
|
fn centre_mark_only_when_the_dimension_line_is_outside_the_circle() {
|
|
let st = DimStyle::default();
|
|
// Radius led out to its text: the mark is drawn.
|
|
let mut rad = dim(DimKind::Radius);
|
|
rad.p15 = Vec3::new(5.0, 0.0, 0.0);
|
|
assert_eq!(ext_lines(&rad, &st).len(), 2, "centre mark of an outside radius dimension");
|
|
// Text moved inside the circle: the dimension line is inside, no mark.
|
|
rad.user_text_pos = true;
|
|
rad.text_mid = Vec3::new(2.0, 0.0, 0.0);
|
|
assert!(ext_lines(&rad, &st).is_empty());
|
|
// A diameter with DIMTOFL runs through the centre: no mark, nor centre lines (negative
|
|
// DIMCEN). Without DIMTOFL it is only led out to its text, like a radius, and has the mark.
|
|
let mut dia = dim(DimKind::Diameter);
|
|
dia.defpt = Vec3::new(-5.0, 0.0, 0.0);
|
|
dia.p15 = Vec3::new(5.0, 0.0, 0.0);
|
|
let tofl = DimStyle { force_line_inside: true, ..DimStyle::default() };
|
|
assert!(ext_lines(&dia, &tofl).is_empty());
|
|
assert!(ext_lines(&dia, &DimStyle { center_mark: -0.5, ..tofl.clone() }).is_empty());
|
|
assert_eq!(ext_lines(&dia, &st).len(), 2);
|
|
// A radius with DIMTOFL runs in from the centre: no mark.
|
|
rad.user_text_pos = false;
|
|
assert!(ext_lines(&rad, &tofl).is_empty());
|
|
}
|