From 32be8a655ef27c88f1497153ae738c2ef07c5980 Mon Sep 17 00:00:00 2001 From: dotCooCoo Date: Sat, 24 Oct 2026 18:43:16 -0700 Subject: [PATCH] COMPAREEXPORT: a dimension block with another generated name does not make PART differ A named block such as PART was compared with the other drawing's by the blocks it draws, including a dimension's block. That block's generated name (`*D1` here, `*D3` there) was part of its signature, so the same PART counted as different and was copied as PART_2 with a copy of the dimension block. The comparison now leaves out an anonymous block's name and compares its contents. --- crates/engine/src/cmd/file/compare.rs | 12 +++++-- crates/engine/tests/compare_export.rs | 50 +++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 3 deletions(-) diff --git a/crates/engine/src/cmd/file/compare.rs b/crates/engine/src/cmd/file/compare.rs index bccd7b2d8..d5a9d3ebc 100644 --- a/crates/engine/src/cmd/file/compare.rs +++ b/crates/engine/src/cmd/file/compare.rs @@ -141,7 +141,8 @@ struct Signer<'a> { work: usize, /// When set, a block's signature also covers its base point, units, annotative and overlay /// flags and xref file, with a relative xref path taken from the folder given, and the - /// signatures of a multileader and a dimension cover their blocks'. + /// signatures of a multileader and a dimension cover their blocks'. An anonymous block's + /// signature then leaves out its name. frames: Option>, } @@ -190,9 +191,14 @@ impl<'a> Signer<'a> { return *v; } let mut h = std::collections::hash_map::DefaultHasher::new(); - key.hash(&mut h); + let block = self.d.block(name); + // With frames, an anonymous block (`*D3`, `*U7`) is signed by its contents only: the + // same block can have another generated name in another drawing. + if !(self.frames.is_some() && block.is_some_and(|b| b.anonymous)) { + key.hash(&mut h); + } if depth < MAX_BLOCK_DEPTH - && let Some(b) = self.d.block(name) + && let Some(b) = block { if let Some(folder) = self.frames { let mut xref = b.xref_path.clone(); diff --git a/crates/engine/tests/compare_export.rs b/crates/engine/tests/compare_export.rs index 8a2b0aa47..2aeab751b 100644 --- a/crates/engine/tests/compare_export.rs +++ b/crates/engine/tests/compare_export.rs @@ -352,6 +352,56 @@ fn a_named_block_whose_dimension_draws_another_block_shows_the_other_definition( assert_eq!(ends(&s, "*D2"), vec![5.0]); } +#[test] +fn a_named_block_whose_dimension_block_has_another_generated_name_keeps_this_drawings_definition() { + use cadcraft_engine::doc::{DimKind, Dimension}; + // PART holds the same dimension in both drawings; the block it draws holds the same line but + // is named `*D1` here and `*D3` in the other drawing. + let blocks = |drawn_name: &str, first: u64| { + let dim = Dimension { + kind: DimKind::Linear { rotation: 0.0 }, + defpt: Vec3::new(15.0, 5.0, 0.0), + text_mid: Vec3::new(7.0, 5.0, 0.0), + p13: Vec3::ZERO, + p14: Vec3::new(30.0, 0.0, 0.0), + p15: Vec3::ZERO, + p16: Vec3::ZERO, + text: String::new(), + style: "Standard".into(), + measurement: 30.0, + text_rotation: 0.0, + user_text_pos: false, + block: Some(drawn_name.into()), + overrides: Default::default(), + assoc: Vec::new(), + marks: Default::default(), + }; + let mut part = Block::new("PART"); + part.entities.push(Entity::new(Handle(first), EntityKind::Dimension(dim))); + let mut drawn = Block::new(drawn_name); + drawn.entities.push(Entity::new(Handle(first + 1), line(1.0))); + [part, drawn] + }; + let mut s = Session::new(); + for b in blocks("*D1", 0x700) { + s.doc_mut().unwrap().blocks.insert(b.name.clone(), Arc::new(b)); + } + s.doc_mut().unwrap().add(&Space::Model, Common::default(), EntityKind::Insert(insert("PART"))).unwrap(); + let mut other = Drawing::new_imperial(); + other.handseed = 0x9000; + for b in blocks("*D3", 0x8000) { + other.blocks.insert(b.name.clone(), Arc::new(b)); + } + other.add(&Space::Model, Common::default(), EntityKind::Insert(Insert { insert: Vec3::new(9.0, 9.0, 0.0), ..insert("PART") })).unwrap(); + s.open_drawing(other, "Other", None); + s.execute("document.switch", &json!({"index": 0})).unwrap(); + s.execute("compare", &json!({"document": "Other"})).unwrap(); + s.execute("compareexport", &json!({})).unwrap(); + let d = s.doc().unwrap(); + assert!(d.block("PART_2").is_none(), "PART draws the same thing in both drawings"); + assert!(d.block("*D3").is_none() && d.block("*D2").is_none(), "the other drawing's dimension block is not copied"); +} + #[test] fn block_contents_take_the_comparison_color() { let mut s = Session::new();