mirror of
https://github.com/storytold/cadcraft.git
synced 2026-10-25 11:26:46 -06:00
For every justification but baseline-left (and aligned/fit) the DXF Reference makes group 11 the point the text is placed by; group 10 is a computed point on the baseline. Left-justified text with a vertical alignment was drawn, measured and picked from group 10 and then shifted by the alignment again: TL and ML too low, BL too high. The renderer (fonts::place) and text extents (doc text_box, used for picking) now place it from the alignment point; a mirrored (extrusion 0,0,-1) TL/ML/BL text keeps its alignment point when it turns right-justified; and the Properties position moves justified text by its alignment point. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
47 lines
2.5 KiB
Rust
47 lines
2.5 KiB
Rust
//! Left-justified TEXT with a vertical alignment (TL, ML, BL) is placed by its alignment point
|
|
//! (DXF group 11), like every justification but baseline-left; group 10 is then a computed point
|
|
//! on the baseline (#342).
|
|
|
|
use cadcraft_doc::{EntityKind, Space, entity_bounds};
|
|
|
|
/// One TEXT, height 1, "AB", group 72 = 0 and group 73 = `v`, with group 10 at `p10`, group 11 at
|
|
/// `p11`, and `extra` group codes.
|
|
fn dxf(v: i32, p10: (f64, f64), p11: (f64, f64), extra: &str) -> String {
|
|
format!(
|
|
"0\nSECTION\n2\nENTITIES\n0\nTEXT\n8\n0\n10\n{}\n20\n{}\n40\n1\n1\nAB\n72\n0\n11\n{}\n21\n{}\n{extra}73\n{v}\n0\nENDSEC\n0\nEOF\n",
|
|
p10.0, p10.1, p11.0, p11.1
|
|
)
|
|
}
|
|
|
|
/// (rendered box, extents box) of the drawing's only object, as (min x, min y, max x, max y).
|
|
fn boxes(text: &str) -> ([f64; 4], [f64; 4]) {
|
|
let d = cadcraft_io::read(text.as_bytes(), "t.dxf").unwrap();
|
|
let r = cadcraft_render::build(&d, &Space::Model, &cadcraft_render::Options::default()).bounds;
|
|
let e = d.model.iter().find(|e| matches!(e.kind, EntityKind::Text(_))).map(|e| entity_bounds(&d, e, 0)).unwrap();
|
|
([r.min.x, r.min.y, r.max.x, r.max.y], [e.min.x, e.min.y, e.max.x, e.max.y])
|
|
}
|
|
|
|
fn near(a: f64, b: f64) -> bool {
|
|
(a - b).abs() < 1e-6
|
|
}
|
|
|
|
#[test]
|
|
fn left_justified_text_is_placed_by_its_alignment_point() {
|
|
// TL: the top-left of the text at the alignment point 0,0; the baseline one height lower.
|
|
let (r, e) = boxes(&dxf(3, (0.0, -1.0), (0.0, 0.0), ""));
|
|
assert!(near(r[0], 0.0) && near(r[3], 0.0), "TL drawn at {r:?}");
|
|
assert!(near(e[0], 0.0) && near(e[3], 0.0) && near(e[1], -1.0), "TL extents {e:?}");
|
|
// ML: the middle of the text height at the alignment point.
|
|
let (r, e) = boxes(&dxf(2, (0.0, -0.5), (0.0, 0.0), ""));
|
|
assert!(near(r[3], 0.5) && near(e[3], 0.5) && near(e[1], -0.5), "ML drawn at {r:?}, extents {e:?}");
|
|
// BL: the descender line at the alignment point, so the baseline ("AB" has no descenders) a
|
|
// third of the height above it.
|
|
let (r, e) = boxes(&dxf(1, (0.0, 1.0 / 3.0), (0.0, 0.0), ""));
|
|
assert!(near(r[1], 1.0 / 3.0) && near(e[1], 1.0 / 3.0) && near(e[3], 4.0 / 3.0), "BL drawn at {r:?}, extents {e:?}");
|
|
|
|
// Mirrored (extrusion 0,0,-1): the OCS points (-10,4) and (-10,5) are WCS (10,4) and (10,5);
|
|
// drawn readable, the text runs left from its alignment point with its top there.
|
|
let (r, _) = boxes(&dxf(3, (-10.0, 4.0), (-10.0, 5.0), "210\n0\n220\n0\n230\n-1\n"));
|
|
assert!(near(r[2], 10.0) && near(r[3], 5.0), "mirrored TL drawn at {r:?}");
|
|
}
|