diff --git a/crates/io/src/dxf_write.rs b/crates/io/src/dxf_write.rs index c79be654..f70474a7 100644 --- a/crates/io/src/dxf_write.rs +++ b/crates/io/src/dxf_write.rs @@ -1496,13 +1496,24 @@ fn tags_for(d: &Drawing, version: Version, target: Version) -> Vec { 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; 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; diff --git a/crates/io/tests/dim_block_resave_roundtrip.rs b/crates/io/tests/dim_block_resave_roundtrip.rs index 15581fd0..f0705d6f 100644 --- a/crates/io/tests/dim_block_resave_roundtrip.rs +++ b/crates/io/tests/dim_block_resave_roundtrip.rs @@ -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 = 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::>()) + }; + 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); +}