fix(render): DXF leader hookline width + SHAPE name fallback; bump acadrust

Companion to the acadrust DXF-fidelity sweep (bump to 379ce12):
- Legacy LEADER hookline: underline the annotation using the leader's own
  stored text width (DXF code 41) when the MTEXT has no computed extents,
  so the landing spans the text instead of a short stub.
- SHAPE: resolve the glyph by name when the shape number is 0 (DXF SHAPE
  carries only the name), and search shape-file text styles when the entity
  has no direct style reference.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
Hakan SevenandClaude Opus 4.8 committed 2026-07-24 11:30:03 +03:00
1 parent b7dc62ffa5
commit ce49f4da0a
3 files changed
+77 -30

No files matched your search

+17 -7
View File
@@ -761,14 +761,24 @@ impl LeaderTess for Leader {
.or_else(|| style.map(|s| s.dimtad))
.unwrap_or(0);
if dimtad != 0 {
if let Some(acadrust::entities::EntityType::MText(mt)) =
document.get_entity(self.annotation_handle)
{
if mt.extents_width > 0.0 {
let to_far_edge =
sign * (mt.insertion_point.x - last.x) + mt.extents_width;
land_len = land_len.max(to_far_edge);
let mt = match document.get_entity(self.annotation_handle) {
Some(acadrust::entities::EntityType::MText(mt)) => {
Some((mt.extents_width, mt.insertion_point.x))
}
_ => None,
};
// Underline width: the annotation MTEXT's laid-out extents when
// known, otherwise the leader's own stored annotation width
// (DXF code 41) — a DXF-loaded MTEXT often has no computed
// extents (extents_width == 0), which left the hook too short.
let width = mt
.map(|(w, _)| w)
.filter(|w| *w > 0.0)
.unwrap_or(self.text_width);
if width > 0.0 {
let ins_x = mt.map(|(_, x)| x).unwrap_or(last.x);
let to_far_edge = sign * (ins_x - last.x) + width;
land_len = land_len.max(to_far_edge);
}
}
points.push([f64::NAN; 3]);
+58 -21
View File
@@ -63,32 +63,69 @@ fn shx_polylines(
shape: &Shape,
document: &acadrust::CadDocument,
) -> Option<crate::scene::text::shx::ShapePolylines> {
let style = shape
.style_handle
.and_then(|h| document.text_styles.iter().find(|s| s.handle == h))
.or_else(|| {
let name = shape.style_name.trim();
(!name.is_empty())
.then(|| {
document
.text_styles
.iter()
.find(|s| s.name.eq_ignore_ascii_case(name))
})
.flatten()
})?;
let font = style.font_file.trim();
if font.is_empty() {
return None;
}
let base = document
.source_path
.as_deref()
.map(std::path::Path::new)
.and_then(|p| p.parent());
let resolved = crate::io::resolve_image_file(font, base)?;
let num = u16::try_from(shape.shape_number).ok()?;
crate::scene::text::shx::shape_polylines(&resolved, num)
let name = shape.shape_name.trim();
// Resolve the glyph from one style's shape (.shx) file, preferring the
// shape NUMBER but falling back to the NAME — a DXF SHAPE carries only the
// name (code 2), so its `shape_number` is 0.
let try_style = |style: &acadrust::tables::TextStyle| {
let font = style.font_file.trim();
if font.is_empty() {
return None;
}
let resolved = crate::io::resolve_image_file(font, base)?;
if let Ok(num) = u16::try_from(shape.shape_number) {
if num != 0 {
if let Some(p) = crate::scene::text::shx::shape_polylines(&resolved, num) {
return Some(p);
}
}
}
if !name.is_empty() {
return crate::scene::text::shx::shape_polylines_by_name(&resolved, name);
}
None
};
// 1. Direct style referenced by the SHAPE (handle, then name).
let direct = shape
.style_handle
.and_then(|h| document.text_styles.iter().find(|s| s.handle == h))
.or_else(|| {
let sn = shape.style_name.trim();
(!sn.is_empty())
.then(|| {
document
.text_styles
.iter()
.find(|s| s.name.eq_ignore_ascii_case(sn))
})
.flatten()
});
if let Some(style) = direct {
if let Some(p) = try_style(style) {
return Some(p);
}
}
// 2. No usable style reference (the DXF case): search every shape-file
// style — one with a real font file and an empty table name — for a
// glyph named like this shape.
if !name.is_empty() {
for style in document.text_styles.iter() {
if style.name.is_empty() && !style.font_file.trim().is_empty() {
if let Some(p) = try_style(style) {
return Some(p);
}
}
}
}
None
}
impl TruckConvertible for Shape {