mirror of
https://github.com/storytold/cadcraft.git
synced 2026-10-24 10:56:51 -06:00
An R2018+ MTEXT can carry an embedded object (group 101) in which 10 is the X-axis direction and 11 the insertion point. AutoCAD writes one for MTEXT with column settings, and so does the DWG bridge. The reader took the first group 11 anywhere in the entity as the direction, so such text turned towards its own insertion point. Read 11/21 and 50 from the MTEXT's own groups only.
80 lines
2.6 KiB
Rust
80 lines
2.6 KiB
Rust
//! An R2018+ MTEXT can carry an embedded object (group 101) that repeats its geometry with
|
|
//! other meanings: there, 10 is the X-axis direction and 11 the insertion point. AutoCAD writes
|
|
//! one for MTEXT with column settings, and the DWG bridge does too. Reading 11 from it as the
|
|
//! direction turned the text towards its own insertion point (#667).
|
|
|
|
use cadcraft_doc::{Common, Drawing, EntityKind, MText, Space};
|
|
use cadcraft_geom::Vec3;
|
|
use cadcraft_io::{read_dxf, write_dxf};
|
|
|
|
/// An MTEXT at (30, 17) with `rotation`, written by CADCraft, then given an embedded object
|
|
/// as AutoCAD writes it: direction `dir` in 10/20/30 and the insertion point in 11/21/31.
|
|
fn with_embedded_object(rotation: f64, dir: (f64, f64)) -> String {
|
|
let mut d = Drawing::new_metric();
|
|
let t = MText {
|
|
insert: Vec3::new(30.0, 17.0, 0.0),
|
|
height: 0.5,
|
|
width: 6.0,
|
|
attach: 1,
|
|
rotation,
|
|
style: "Standard".into(),
|
|
contents: "Core Layer\\PThickness 1mm".into(),
|
|
line_spacing: 1.0,
|
|
line_spacing_exact: false,
|
|
columns: None,
|
|
};
|
|
d.add(&Space::Model, Common::default(), EntityKind::MText(t)).unwrap();
|
|
let dxf = write_dxf(&d);
|
|
let (dx, dy) = (dir.0.to_string(), dir.1.to_string());
|
|
let groups = [
|
|
(101, "Embedded Object"),
|
|
(70, "1"),
|
|
(10, &dx),
|
|
(20, &dy),
|
|
(30, "0.0"),
|
|
(11, "30.0"),
|
|
(21, "17.0"),
|
|
(31, "0.0"),
|
|
(40, "6.0"),
|
|
(41, "0.0"),
|
|
(42, "5.0"),
|
|
(43, "1.0"),
|
|
(71, "2"),
|
|
(72, "1"),
|
|
(44, "6.0"),
|
|
(45, "0.5"),
|
|
(73, "0"),
|
|
(74, "0"),
|
|
(46, "0.0"),
|
|
];
|
|
let embedded: String = groups.iter().map(|(code, value)| format!("{code:>3}\r\n{value}\r\n")).collect();
|
|
let start = dxf.find("AcDbMText").unwrap();
|
|
let end = start + dxf[start..].find("\r\n 0\r\n").unwrap() + 2;
|
|
format!("{}{embedded}{}", &dxf[..end], &dxf[end..])
|
|
}
|
|
|
|
fn read_rotation(dxf: &str) -> f64 {
|
|
let back = read_dxf(dxf.as_bytes()).unwrap();
|
|
match back.model.iter().find_map(|e| match &e.kind {
|
|
EntityKind::MText(t) => Some(t.rotation),
|
|
_ => None,
|
|
}) {
|
|
Some(r) => r,
|
|
None => panic!("no mtext"),
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn embedded_object_insertion_point_is_not_the_direction() {
|
|
let dxf = with_embedded_object(0.0, (1.0, 0.0));
|
|
assert!(dxf.contains("Embedded Object"));
|
|
assert_eq!(read_rotation(&dxf), 0.0);
|
|
}
|
|
|
|
#[test]
|
|
fn rotated_mtext_keeps_its_rotation_with_an_embedded_object() {
|
|
let r = 0.5_f64;
|
|
let dxf = with_embedded_object(r, (r.cos(), r.sin()));
|
|
assert!((read_rotation(&dxf) - r).abs() < 1e-9);
|
|
}
|