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

Generated
+3 -3
View File
@@ -88,7 +88,7 @@ checksum = "366ffbaa4442f4684d91e2cd7c5ea7c4ed8add41959a31447066e279e432b618"
[[package]]
name = "acadrust"
version = "0.5.5"
source = "git+https://github.com/HakanSeven12/cadcodec.git?rev=d290dbe#d290dbe1712666d83dfd0fc63341ee3246f8de76"
source = "git+https://github.com/HakanSeven12/cadcodec.git?rev=1c3be0c#1c3be0ca296c99f2f126ba1a03c2be1998d7c64e"
dependencies = [
"ahash 0.8.12",
"anyhow",
@@ -924,7 +924,7 @@ checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04"
[[package]]
name = "cadkernel"
version = "0.1.0"
source = "git+https://github.com/HakanSeven12/cadkernel.git?rev=4134ae3#4134ae386153a76998c2fbf03e81a5c4a23928cc"
source = "git+https://github.com/HakanSeven12/cadkernel.git?rev=deb529b#deb529b34e677c1fedc4e316ce3f49b88f0c1361"
dependencies = [
"acadrust",
"cavalier_contours",
@@ -935,7 +935,7 @@ dependencies = [
[[package]]
name = "cadkernel-constraints"
version = "0.1.0"
source = "git+https://github.com/HakanSeven12/cadkernel.git?rev=4134ae3#4134ae386153a76998c2fbf03e81a5c4a23928cc"
source = "git+https://github.com/HakanSeven12/cadkernel.git?rev=deb529b#deb529b34e677c1fedc4e316ce3f49b88f0c1361"
dependencies = [
"nalgebra",
]
+3 -3
View File
@@ -33,9 +33,9 @@ rfd = "0.17"
clap = { version = "4", features = ["derive", "string"] }
env_logger = "0.11"
log = "0.4"
acadrust = { git = "https://github.com/HakanSeven12/cadcodec.git", rev = "d290dbe", features = ["serde"] }
cadkernel = { git = "https://github.com/HakanSeven12/cadkernel.git", rev = "4134ae3", features = ["acis", "offset"] }
cadkernel-constraints = { git = "https://github.com/HakanSeven12/cadkernel.git", rev = "4134ae3" }
acadrust = { git = "https://github.com/HakanSeven12/cadcodec.git", rev = "1c3be0c", features = ["serde"] }
cadkernel = { git = "https://github.com/HakanSeven12/cadkernel.git", rev = "deb529b", features = ["acis", "offset"] }
cadkernel-constraints = { git = "https://github.com/HakanSeven12/cadkernel.git", rev = "deb529b" }
dwg-thumbnailer = { path = "crates/dwg-thumbnailer" }
flate2 = "1"
image = { version = "0.25", default-features = false, features = ["png", "jpeg", "bmp", "tiff"] }
+2 -2
View File
@@ -15,7 +15,7 @@ serde_json = { version = "1", optional = true }
# Pulled in only by the `host` feature, which adds the `acadrust`-typed
# `HostApi` runtime surface. The default crate stays dependency-free so engine
# crates and external tooling can depend on the manifest/ribbon contract cheaply.
acadrust = { git = "https://github.com/HakanSeven12/cadcodec.git", rev = "d290dbe", optional = true, features = ["serde"] }
acadrust = { git = "https://github.com/HakanSeven12/cadcodec.git", rev = "1c3be0c", optional = true, features = ["serde"] }
# Runtime IPC and serialization (host feature only).
interprocess = { version = "2", optional = true }
@@ -39,7 +39,7 @@ serde_json = "1"
serde = { version = "1", features = ["derive"] }
cargo-lock = "11"
# acadrust is scanned at build time to generate the embedded type registry.
acadrust = { git = "https://github.com/HakanSeven12/cadcodec.git", rev = "d290dbe", features = ["serde"] }
acadrust = { git = "https://github.com/HakanSeven12/cadcodec.git", rev = "1c3be0c", features = ["serde"] }
[dev-dependencies]
serde_json = "1"
+1 -1
View File
@@ -8,7 +8,7 @@ publish = false
crate-type = ["cdylib"]
[dependencies]
acadrust = { git = "https://github.com/HakanSeven12/cadcodec.git", rev = "d290dbe", features = ["serde"] }
acadrust = { git = "https://github.com/HakanSeven12/cadcodec.git", rev = "1c3be0c", features = ["serde"] }
bincode = "1.3"
serde = { version = "1", features = ["derive"] }
console_error_panic_hook = "0.1"
+1 -1
View File
@@ -7,7 +7,7 @@ reloading it, and comparing entity fields.
**Status (23 September 2026):** the fixes landed in cadcodec as
[#48](https://github.com/HakanSeven12/cadcodec/pull/48) (issues 1-6) and
[#51](https://github.com/HakanSeven12/cadcodec/pull/51) (the first three style findings), and
the block description with commit `dd1d7bf` (cadcodec issue #49). OCS pins `d290dbe`, which
the block description with commit `dd1d7bf` (cadcodec issue #49). OCS pins `1c3be0c`, which
includes it; the canaries below were flipped against `dd1d7bf`. What is still open:
- **ATTDEF `lock_position`** (issue 1): the reader is complete, but the DXF writer emits no
+1 -1
View File
@@ -5,7 +5,7 @@ version = 4
[[package]]
name = "acadrust"
version = "0.5.5"
source = "git+https://github.com/HakanSeven12/cadcodec.git?rev=d290dbe#d290dbe1712666d83dfd0fc63341ee3246f8de76"
source = "git+https://github.com/HakanSeven12/cadcodec.git?rev=1c3be0c#1c3be0ca296c99f2f126ba1a03c2be1998d7c64e"
dependencies = [
"ahash 0.8.12",
"anyhow",
+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;