fix(xclip): follow-ups to the XCLIP merge

- An inverted clip's roundtrip record goes in the filter's extension
  dictionary through the codec's own API (ensure_extension_dictionary /
  xrecord / extension_dictionary_handle) instead of a scan of every
  object, which the renderer ran for each clipped reference.
- Pin cadcodec 1c3be0c (the DXF writer now links a spatial filter's
  extension dictionary, so that record is not left unreferenced) and
  cadkernel deb529b; plugin crates and the Python plugin lock follow.
- The XCLIP boundary preview stays f64.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
Hakan SevenandClaude Opus 5.5 committed 2026-09-24 23:46:50 +03:00
1 parent 58671b191c
commit 6d9365ea88
8 files changed
+19 -37

No files matched your search

+2 -3
View File
@@ -394,10 +394,9 @@ impl CadCommand for XclipCommand {
}
_ => return None,
};
let mut points: Vec<[f32; 3]> =
ring.iter().map(|p| [p.x as f32, p.y as f32, p.z as f32]).collect();
let mut points: Vec<[f64; 3]> = ring.iter().map(|p| p.to_array()).collect();
points.push(points[0]);
Some(WireModel::solid("xclip_boundary".into(), points, WireModel::CYAN, false))
Some(WireModel::solid_f64("xclip_boundary".into(), points, WireModel::CYAN, false))
}
}
+6 -23
View File
@@ -64,14 +64,7 @@ const INVERTED_COMPARE: &str = "ACAD_INVERTEDCLIP_ROUNDTRIP_COMPARE";
/// The boundary an inverted clip was drawn with (WCS), kept beside the
/// filter's ring in an ACAD_XREC_ROUNDTRIP record as the reference keeps it.
pub fn inverted_boundary(doc: &CadDocument, filter: &SpatialFilter) -> Option<Vec<[f64; 2]>> {
let xdict = match doc.objects.get(&filter.handle)? {
ObjectType::SpatialFilter(_) => filter_xdictionary(doc, filter.handle)?,
_ => return None,
};
let record = dict_entry(doc, xdict, ROUNDTRIP)?;
let Some(ObjectType::XRecord(x)) = doc.objects.get(&record) else {
return None;
};
let x = doc.xrecord(filter.handle, ROUNDTRIP)?;
let mut points = Vec::new();
let mut inside = false;
for entry in &x.entries {
@@ -88,15 +81,6 @@ pub fn inverted_boundary(doc: &CadDocument, filter: &SpatialFilter) -> Option<Ve
(points.len() >= 2).then_some(points)
}
/// Filters keep their extension dictionary in the document's owner map: the
/// dictionary owned by the filter.
fn filter_xdictionary(doc: &CadDocument, filter: Handle) -> Option<Handle> {
doc.objects.iter().find_map(|(h, o)| match o {
ObjectType::Dictionary(d) if d.owner == filter => Some(*h),
_ => None,
})
}
/// The inverted boundary drawn as the XCLIP frame and generated polyline,
/// else the stored one; rectangles as four corners (WCS through the stored
/// transforms).
@@ -154,7 +138,7 @@ pub fn remove_insert_clip(doc: &mut CadDocument, insert: Handle) -> bool {
let Some(spatial) = filter_handle(doc, insert) else {
return false;
};
if let Some(xdict) = filter_xdictionary(doc, spatial) {
if let Some(xdict) = doc.extension_dictionary_handle(spatial) {
let children: Vec<Handle> = match doc.objects.get(&xdict) {
Some(ObjectType::Dictionary(d)) => d.entries.iter().map(|(_, h)| *h).collect(),
_ => Vec::new(),
@@ -279,12 +263,11 @@ pub fn set_insert_clip(
parent.add_entry("SPATIAL", spatial);
}
if inverted {
let fdict = doc.allocate_handle();
let fdict = doc.ensure_extension_dictionary(spatial);
let record = doc.allocate_handle();
let mut d = Dictionary::new();
(d.handle, d.owner, d.hard_owner) = (fdict, spatial, true);
d.add_entry(ROUNDTRIP, record);
doc.objects.insert(fdict, ObjectType::Dictionary(d));
if let Some(ObjectType::Dictionary(d)) = doc.objects.get_mut(&fdict) {
d.add_entry(ROUNDTRIP, record);
}
let mut x = XRecord::new();
(x.handle, x.owner) = (record, fdict);
x.cloning_flags = acadrust::objects::DictionaryCloningFlags::KeepExisting;