A proxy whose number names no class is left out of the DWG

dxf_to_dwg_as kept a proxy whose class number names no class of the DXF's CLASSES with that
number, which names some other class of the DWG. It is now left out and counted, as a binary
DXF's proxies are, and as CADCraft's own save already does.
This commit is contained in:
ffishman
2026-11-02 10:28:26 -03:00
parent 5d0b723ddb
commit 319351578e
2 changed files with 52 additions and 6 deletions
+17 -6
View File
@@ -678,7 +678,8 @@ mod native {
/// reader puts its own default classes first and numbers the DXF's after them, so the DXF
/// number named another class in the DWG: a 2018 drawing's piping proxies became
/// LARGE_RADIAL_DIMENSION and SECTIONOBJECT, and the ODA File Converter refused the file. A
/// number that names no class of the DXF is left as it is.
/// proxy whose number names no class of the DXF is left out: kept as it is, its number would
/// name some other class of the DWG, for the same reason.
///
/// Before 2013 (AC1027) acadrust writes only the classes it knows a pre-2013 DWG needs, and a
/// proxy's class is not one of them: the proxy would name a missing class (the ODA refuses
@@ -715,24 +716,34 @@ mod native {
let name = classes.get(usize::try_from(id.checked_sub(500)?).ok()?)?;
doc.classes.get_by_name(name).map(|c| i32::from(c.class_number))
};
let objects: Vec<(acadrust::Handle, i32)> = doc
let objects: Vec<(acadrust::Handle, Option<i32>)> = doc
.objects
.iter()
.filter_map(|(h, o)| match o {
acadrust::objects::ObjectType::ProxyObject(p) => number(p.class_id).map(|n| (*h, n)),
acadrust::objects::ObjectType::ProxyObject(p) => Some((*h, number(p.class_id))),
_ => None,
})
.collect();
let entities: Vec<(acadrust::Handle, i32)> = doc
let entities: Vec<(acadrust::Handle, Option<i32>)> = doc
.entities()
.filter_map(|e| match e {
acadrust::entities::EntityType::Extended(x) => match &x.data {
acadrust::entities::ExtendedEntityData::Proxy(p) => number(p.class_id).map(|n| (x.common.handle, n)),
acadrust::entities::ExtendedEntityData::Proxy(p) => Some((x.common.handle, number(p.class_id))),
_ => None,
},
_ => None,
})
.collect();
let unmapped = |list: &[(acadrust::Handle, Option<i32>)]| list.iter().filter(|(_, n)| n.is_none()).map(|(h, _)| *h).collect::<Vec<_>>();
let (gone_objects, gone_entities) = (unmapped(&objects), unmapped(&entities));
for h in &gone_objects {
doc.objects.remove(h);
}
for h in &gone_entities {
doc.remove_entity(*h);
}
let objects = objects.into_iter().filter_map(|(h, n)| Some((h, n?)));
let entities = entities.into_iter().filter_map(|(h, n)| Some((h, n?)));
for (h, n) in objects {
if let Some(acadrust::objects::ObjectType::ProxyObject(p)) = doc.objects.get_mut(&h) {
p.class_id = n;
@@ -747,7 +758,7 @@ mod native {
}
}
}
0
gone_objects.len() + gone_entities.len()
}
/// The current layer (`$CLAYER`) by its name, the same way as [`current_dimstyle`]: a DWG
+35
View File
@@ -2883,6 +2883,41 @@ fn proxies_keep_their_class_in_dwg() {
}
}
/// An ASCII DXF given to the DWG conversion directly, with a proxy whose number names no class of
/// its CLASSES ([`proxy_file`]'s "Stray", 537): kept with that number it would name some other
/// class of the DWG, so the DWG leaves it out, as CADCraft's own save does, and keeps the proxies
/// whose classes it can name.
#[cfg(not(target_arch = "wasm32"))]
#[test]
fn a_proxy_whose_class_is_unknown_is_left_out_of_the_dwg() {
use acadrust::entities::{EntityType, ExtendedEntityData};
use acadrust::objects::ObjectType;
let dwg = cadcraft_dwg::dxf_to_dwg_as(&proxy_file(), "AC1032").unwrap();
let doc = acadrust::DwgReader::from_stream(std::io::Cursor::new(dwg)).read().unwrap();
let class_of = |id: i32| doc.classes.iter().find(|c| i32::from(c.class_number) == id).map(|c| c.dxf_name.clone());
let mut objects: Vec<Option<String>> = doc
.objects
.values()
.filter_map(|o| match o {
ObjectType::ProxyObject(p) => Some(class_of(p.class_id)),
_ => None,
})
.collect();
objects.sort();
assert_eq!(objects, [Some("VISUALSTYLE".to_string()), Some("WIDGETX".to_string())]);
let entities: Vec<Option<String>> = doc
.entities()
.filter_map(|e| match e {
EntityType::Extended(x) => match &x.data {
ExtendedEntityData::Proxy(p) => Some(class_of(p.class_id)),
_ => None,
},
_ => None,
})
.collect();
assert_eq!(entities, [Some("WIDGETX".to_string())]);
}
/// A binary DXF given to the DWG conversion directly: its CLASSES aren't read, so the proxies'
/// numbers can't be mapped to the DWG's classes. Kept as they were, they named other classes
/// (the ODA refuses such a file), so the DWG leaves them out, as a pre-2013 DWG does, and the