From 19bb846c50dcb2733e2befdf26bc68efee47592c Mon Sep 17 00:00:00 2001 From: Hakan Seven Date: Sun, 26 Apr 2026 16:57:23 +0300 Subject: [PATCH] fix: dimension line geometry and DXF rotation unit mismatch append_linear_dimension() applied the same perp offset to both d1 and d2, but only d2 is guaranteed to be at the definition_point level; d1 must be projected independently onto the dimension line, otherwise non-collinear first/second points produce a parallelogram instead of a rectangle. Fix: compute dim_line_pos = def.dot(perp) and project each endpoint separately so the dimension line is always parallel to axis. Additionally, the acadrust DXF reader stores LinearDimension.rotation from group code 50 (degrees) without converting to radians, while DWG and our own annotation commands store it in radians. Add a post-load fixup in load_file() that converts the rotation to radians for DXF files so tessellation can call cos/sin uniformly. Co-Authored-By: Claude Sonnet 4.6 --- src/io/mod.rs | 26 ++++++++++++++++++++++---- src/scene/tessellate.rs | 6 +++--- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/io/mod.rs b/src/io/mod.rs index b3aa279b6..26cd5ed64 100644 --- a/src/io/mod.rs +++ b/src/io/mod.rs @@ -11,6 +11,7 @@ pub mod step; pub mod stl; pub mod xref; +use acadrust::entities::{Dimension, EntityType}; use acadrust::io::dwg::DwgReader; use acadrust::{CadDocument, DwgWriter, DxfReader, DxfWriter}; use std::path::{Path, PathBuf}; @@ -60,10 +61,14 @@ pub fn load_file(path: &Path) -> Result { let mut reader = DwgReader::from_file(path).map_err(|e| e.to_string())?; reader.read().map_err(|e| e.to_string()) } - "dxf" => DxfReader::from_file(path) - .map_err(|e| e.to_string())? - .read() - .map_err(|e| e.to_string()), + "dxf" => { + let mut doc = DxfReader::from_file(path) + .map_err(|e| e.to_string())? + .read() + .map_err(|e| e.to_string())?; + fix_dxf_dimension_rotations(&mut doc); + Ok(doc) + } _ => Err(format!("Unsupported file format: .{ext}")), } } @@ -162,3 +167,16 @@ pub fn save_dxf(doc: &CadDocument, path: &Path) -> Result<(), String> { .write_to_file(path) .map_err(|e| e.to_string()) } + +// ── DXF post-load fixups ────────────────────────────────────────────────── + +/// The acadrust DXF reader stores LinearDimension.rotation directly from DXF +/// group code 50, which is in degrees. DWG and our own dimension-creation code +/// store it in radians. Convert so tessellation can call cos/sin uniformly. +fn fix_dxf_dimension_rotations(doc: &mut CadDocument) { + for entity in doc.entities_mut() { + if let EntityType::Dimension(Dimension::Linear(d)) = entity { + d.rotation = d.rotation.to_radians(); + } + } +} diff --git a/src/scene/tessellate.rs b/src/scene/tessellate.rs index 885f6c96b..f12f13bb7 100644 --- a/src/scene/tessellate.rs +++ b/src/scene/tessellate.rs @@ -707,9 +707,9 @@ fn append_linear_dimension( axis: Vec3, ) { let perp = Vec3::new(-axis.y, axis.x, 0.0); - let offset = (def - first).dot(perp); - let d1 = first + perp * offset; - let d2 = second + perp * offset; + let dim_line_pos = def.dot(perp); + let d1 = first + perp * (dim_line_pos - first.dot(perp)); + let d2 = second + perp * (dim_line_pos - second.dot(perp)); add_segment(points, first, d1); add_segment(points, second, d2); add_segment(points, d1, d2);