Write an unedited dimension's block as it was read (#782)

Saving regenerated every dimension's anonymous block, even dimensions read
from another program's file and never touched: the definition points went
and other programs then showed CADCraft's drawing of each dimension (a
dimension line split around its text came back whole, for instance).

A dimension still linked to the block it was read with hasn't changed
since: every edit drops the link, and the screen draws that block while it
is there. Its block is now written as read, under its name and handles;
edited and new dimensions are generated as before.

On a 1,013-dimension permit set saved DWG -> CADCraft -> DWG, every
dimension's block now matches the original (before: none).

Co-authored-by: Claude Opus 5.5 <[email protected]>
This commit is contained in:
aldozarandClaude Opus 5.5 authored and GitHub committed 2026-10-13 04:35:38 -04:00
1 parent e9d8462828
commit f314d3a591
2 files changed
+58 -2

No files matched your search

+13 -2
View File
@@ -1496,13 +1496,24 @@ fn tags_for(d: &Drawing, version: Version, target: Version) -> Vec<Tag> {
for e in st.iter() {
if let EntityKind::Dimension(dm) = &e.kind {
let reused = dim_plan.reuse.get(&e.handle);
let mut ents = dim_block_entities(d, dm, &e.common.layer);
let ents: Vec<Entity>;
let name = match reused {
// A dimension still linked to the block it was read with hasn't changed since
// (edits drop the link, and the screen draws that block): the block is written
// as read, so other programs show it as they drew it.
Some(b) if !b.entities.is_empty() => {
ents = b.entities.iter().map(|x| x.as_ref().clone()).collect();
reused_handles.extend(ents.iter().map(|x| x.handle).filter(|h| h.0 != 0));
b.name.clone()
}
Some(b) => {
reuse_handles(&mut ents, b, &mut reused_handles);
let mut fresh = dim_block_entities(d, dm, &e.common.layer);
reuse_handles(&mut fresh, b, &mut reused_handles);
ents = fresh;
b.name.clone()
}
None => {
ents = dim_block_entities(d, dm, &e.common.layer);
let mut name = format!("*D{n}");
while d.block(&name).is_some() {
n += 1;
@@ -194,3 +194,48 @@ fn dwg_reopen_and_save_keeps_one_block_per_dimension() {
}
assert!(saves.windows(2).all(|w| w[0] == w[1]), "DWG reopen-and-save changed the file");
}
#[test]
fn an_unedited_dimension_keeps_the_block_it_was_read_with() {
use cadcraft_doc::{Circle, Point};
let mut d = Drawing::new_metric();
// The block another program drew: geometry CADCraft never generates (a circle) and the
// definition point on Defpoints.
let mut b = Block::new("*D3");
for kind in [
EntityKind::Line(Line { a: Vec3::ZERO, b: Vec3::new(10.0, 0.0, 0.0) }),
EntityKind::Circle(Circle { center: Vec3::new(5.0, 3.0, 0.0), radius: 0.25 }),
EntityKind::Point(Point { p: Vec3::new(0.0, 0.0, 0.0), angle: 0.0 }),
] {
let h = d.new_handle();
b.entities.push(Entity::new(h, kind));
}
let kept: Vec<Handle> = b.entities.iter().map(|e| e.handle).collect();
d.blocks.insert("*D3".into(), Arc::new(b));
let mut dm = linear([0.0, 0.0], [10.0, 0.0], [5.0, 3.0]);
dm.block = Some("*D3".into());
let h = d.add(&Space::Model, Common::default(), EntityKind::Dimension(dm)).unwrap();
// Saved untouched: the same block, entity for entity, over a DXF and a DWG round trip.
let circles = |d: &Drawing| {
let Some(EntityKind::Dimension(dm)) = d.entity(h).map(|e| &e.kind) else { panic!("dimension lost") };
let blk = d.block(dm.block.as_deref().unwrap()).unwrap();
(blk.entities.iter().filter(|e| matches!(e.kind, EntityKind::Circle(_))).count(), blk.entities.iter().map(|e| e.handle).collect::<Vec<_>>())
};
let back = cadcraft_io::read_dxf(cadcraft_io::write_dxf(&d).as_bytes()).unwrap();
assert_eq!(circles(&back), (1, kept.clone()));
let dwg = cadcraft_io::read(&cadcraft_io::write(&d, "a.dwg").unwrap(), "a.dwg").unwrap();
assert_eq!(circles(&dwg).0, 1);
// Edited (edits drop the link): regenerated from the dimension, so no circle.
let mut edited = back.clone();
edited
.modify_entity(h, |e| {
if let EntityKind::Dimension(dm) = &mut e.kind {
dm.block = None;
}
})
.unwrap();
let again = cadcraft_io::read_dxf(cadcraft_io::write_dxf(&edited).as_bytes()).unwrap();
assert_eq!(circles(&again).0, 0);
}