From c5d186ae92520b554e42d87d1fc6a88cb1c90ae4 Mon Sep 17 00:00:00 2001 From: assamaral Date: Thu, 29 Oct 2026 16:07:47 -0300 Subject: [PATCH] fix(io): the embedded column object carries the column height like AutoCAD's (#2248) Co-Authored-By: Claude Sonnet 5.5 --- crates/io/src/dxf_read/mtext_dxf.rs | 16 ++++++++++++---- crates/io/tests/it/mtext_columns_roundtrip.rs | 10 ++++++++++ 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/crates/io/src/dxf_read/mtext_dxf.rs b/crates/io/src/dxf_read/mtext_dxf.rs index 5a7b6ec55..e7752f711 100644 --- a/crates/io/src/dxf_read/mtext_dxf.rs +++ b/crates/io/src/dxf_read/mtext_dxf.rs @@ -115,11 +115,14 @@ fn read_embedded_columns(tags: &[Tag]) -> Option<(MTextColumns, f64)> { let heights: Vec = obj.iter().filter(|t| t.code == 46).take(MAX_COLUMNS).map(|t| finite(t.f64()).max(0.0)).collect(); let auto_height = first(73).map(Tag::i64).unwrap_or(0) != 0; let manual = kind == MTextColumnType::Dynamic && !auto_height; + // The column height: the entity's own 46 (defined height), else the object's 41 or first 46. + let own_46 = own(tags).iter().find(|t| t.code == 46).map(|t| finite(t.f64()).max(0.0)); + let defined = [own_46, first(41).map(|t| finite(t.f64())), heights.first().copied()].into_iter().flatten().find(|h| *h > 0.0).unwrap_or(0.0); let c = MTextColumns { kind, count: u16::try_from(first(72).map(Tag::i64).unwrap_or(1).clamp(1, MAX_COLUMNS as i64)).unwrap_or(1), gutter: first(45).map(|t| finite(t.f64()).max(0.0)).unwrap_or(0.0), - height: if manual { heights.iter().copied().fold(0.0, f64::max) } else { heights.first().copied().unwrap_or(0.0) }, + height: if manual { heights.iter().copied().fold(0.0, f64::max) } else { defined }, auto_height, heights: if manual { heights } else { Vec::new() }, flow_reversed: first(74).map(Tag::i64).unwrap_or(0) != 0, @@ -137,7 +140,10 @@ pub(crate) fn column_tags(t: &MText, embedded: bool) -> Vec { if embedded { let (sin, cos) = t.rotation.sin_cos(); let total_width = t.width * count as f64 + c.gutter * (count as f64 - 1.0); + // The column height (static, and dynamic with auto height) is the entity's group 46. + let height = if manual { heights.iter().copied().fold(0.0, f64::max) } else { c.height }; let mut v = vec![ + Tag::f(46, height), Tag::s(101, "Embedded Object"), Tag::i(70, 1), Tag::f(10, cos), @@ -147,9 +153,9 @@ pub(crate) fn column_tags(t: &MText, embedded: bool) -> Vec { Tag::f(21, t.insert.y), Tag::f(31, t.insert.z), Tag::f(40, t.width), - Tag::f(41, 0.0), + Tag::f(41, height), Tag::f(42, total_width), - Tag::f(43, heights.iter().copied().fold(0.0, f64::max)), + Tag::f(43, height), Tag::i(71, if c.kind == MTextColumnType::Dynamic { 2 } else { 1 }), Tag::i(72, count as i64), Tag::f(44, t.width), @@ -157,7 +163,9 @@ pub(crate) fn column_tags(t: &MText, embedded: bool) -> Vec { Tag::i(73, i64::from(c.auto_height)), Tag::i(74, i64::from(c.flow_reversed)), ]; - v.extend(heights.into_iter().map(|h| Tag::f(46, h))); + if manual { + v.extend(heights.into_iter().map(|h| Tag::f(46, h))); + } return v; } let mut v = vec![ diff --git a/crates/io/tests/it/mtext_columns_roundtrip.rs b/crates/io/tests/it/mtext_columns_roundtrip.rs index d9a692a8e..3525c8d29 100644 --- a/crates/io/tests/it/mtext_columns_roundtrip.rs +++ b/crates/io/tests/it/mtext_columns_roundtrip.rs @@ -165,6 +165,16 @@ fn embedded_static_columns_are_read() { assert_eq!(t.columns, Some(c)); } +#[test] +fn embedded_column_height_is_the_entitys_defined_height() { + // As ezdxf and AutoCAD write static columns: the height in the entity's 46, none in the object. + let mut tags = embedded_tags(3, 12.5, 2.5, &[]); + let at = tags.iter().position(|t| t.code == 101).unwrap(); + tags.insert(at, cadcraft_dxf::Tag::f(46, 20.0)); + let (_, t) = mtext_from_groups(&tags); + assert_eq!(t.columns.map(|c| c.height), Some(20.0)); +} + #[test] fn r2018_writes_the_embedded_object_and_older_versions_the_legacy_groups() { let (_, t) = mtext_from_groups(&embedded_tags(3, 12.5, 2.5, &[20.0, 20.0, 20.0]));