fix: DXF attribute rotation converted once; plugin layers refuse unknown linetypes

- The acadrust DXF reader has converted ATTRIB/ATTDEF rotation to radians
  since f226110 (in every codec rev OCS pinned from 2026-08-08 on), while
  fix_dxf_dimension_rotations still applied to_radians a second time on
  load. Only Shape needs the conversion here. Surfaced by #1391's hunk.
- Shape-file text styles are found by their is_shape_file flag instead of
  an empty name (also from #1391).
- #1393's add_layer/modify_layer wrote an unresolved linetype name into
  the LAYER record; a name the drawing (plus the standard set) cannot
  supply is now refused, through one resolve_linetype helper.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
This commit is contained in:
Hakan SevenandClaude Fable 5.1 committed 2026-09-20 20:18:18 +03:00
1 parent 97b471949c
commit 8845095432
3 files changed
+30 -52

No files matched your search

+25 -39
View File
@@ -269,24 +269,14 @@ impl<'a> HostSession<'a> {
return None;
}
let resolved_lt = if let Some(ref lt_name) = config.linetype {
let matched = doc
.line_types
.iter()
.find(|lt| lt.name.eq_ignore_ascii_case(lt_name))
.map(|lt| lt.name.clone());
if let Some(m) = matched {
m
} else {
crate::io::linetypes::populate_document(doc);
doc.line_types
.iter()
.find(|lt| lt.name.eq_ignore_ascii_case(lt_name))
.map(|lt| lt.name.clone())
.unwrap_or_else(|| lt_name.clone())
}
} else {
"Continuous".to_string()
let resolved_lt = match config.linetype {
// A name the drawing does not carry would leave the LAYER record
// pointing at no LTYPE, so it is refused rather than written.
Some(ref lt_name) => match resolve_linetype(doc, lt_name) {
Some(name) => name,
None => return None,
},
None => "Continuous".to_string(),
};
let mut layer = acadrust::tables::Layer::new(trimmed);
@@ -325,27 +315,12 @@ impl<'a> HostSession<'a> {
return false;
}
let resolved_lt = if let Some(ref lt_name) = config.linetype {
let doc = self.document_mut();
let matched = doc
.line_types
.iter()
.find(|lt| lt.name.eq_ignore_ascii_case(lt_name))
.map(|lt| lt.name.clone());
if let Some(m) = matched {
Some(m)
} else {
crate::io::linetypes::populate_document(doc);
Some(
doc.line_types
.iter()
.find(|lt| lt.name.eq_ignore_ascii_case(lt_name))
.map(|lt| lt.name.clone())
.unwrap_or_else(|| lt_name.clone()),
)
}
} else {
None
let resolved_lt = match config.linetype {
Some(ref lt_name) => match resolve_linetype(self.document_mut(), lt_name) {
Some(name) => Some(name),
None => return false,
},
None => None,
};
let doc = self.document_mut();
@@ -397,6 +372,17 @@ impl<'a> HostSession<'a> {
}
}
/// The stored spelling of `name` in the drawing's linetype table, loading the
/// standard linetypes first when it is not there yet. `None` when the drawing
/// cannot supply it: a layer must not reference a linetype that does not exist.
fn resolve_linetype(doc: &mut acadrust::CadDocument, name: &str) -> Option<String> {
let stored = |doc: &acadrust::CadDocument| doc.line_types.get(name).map(|lt| lt.name.clone());
stored(doc).or_else(|| {
crate::io::linetypes::populate_document(doc);
stored(doc)
})
}
/// The stable contract a plugin's `dispatch` sees. Each method forwards to the
/// inherent `HostSession` method of the same name (inherent methods take
/// resolution priority, so this is plain delegation, not recursion). The
+1 -1
View File
@@ -119,7 +119,7 @@ fn shx_polylines(
// 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 style.is_shape_file && !style.font_file.trim().is_empty() {
if let Some(p) = try_style(style) {
return Some(p);
}
+4 -12
View File
@@ -2368,21 +2368,13 @@ fn fix_viewport_status_flags(doc: &mut CadDocument) {
}
}
/// The acadrust DXF reader stores several rotation fields directly from DXF
/// group code 50 in degrees, while DWG and our own creation code store radians.
/// Apply to_radians() on load so tessellation can call cos/sin uniformly.
/// The acadrust DXF reader still stores Shape rotation directly from group
/// code 50 in degrees, while DWG and our own creation code store radians.
/// Dimension angles and ATTRIB/ATTDEF rotation are converted inside the
/// reader, so arms for them here would convert twice.
fn fix_dxf_dimension_rotations(doc: &mut CadDocument) {
for entity in doc.entities_mut() {
match entity {
// Dimension angles (rotation / text / oblique) are converted
// degrees->radians inside the acadrust DXF reader now, so a
// dimension arm here would double-convert.
EntityType::AttributeDefinition(a) => {
a.rotation = a.rotation.to_radians();
}
EntityType::AttributeEntity(a) => {
a.rotation = a.rotation.to_radians();
}
EntityType::Shape(s) => {
s.rotation = s.rotation.to_radians();
}