cad-editor/tests/dim_copy_check.rs
Hakan Seven a72b143628 fix(copy): duplicate a dimension's baked block so COPY copies it (#161)
A dimension's drawn geometry lives in a baked anonymous *D block. COPY
cloned the Dimension entity (translating its definition points) but left
its block_name pointing at the source block, whose sub-entities stay at
the original location — so the copy rendered on top of the original and
appeared not to copy at all.

Add `clone_transformed_block`: when copying a dimension that has a baked
block, duplicate that block under a fresh *D name with every sub-entity
transformed by the same offset, and repoint the copy at it. The copy now
lands at the drop point with its baked geometry and text preserved (no
synthesis, so diameter/radius values stay correct). Covered by a portable
regression test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 22:30:45 +03:00

72 lines
2.6 KiB
Rust

// Regression for #161: COPY must duplicate a dimension's baked block so the
// copy renders at the copy position, not on top of the original.
use acadrust::entities::{Dimension, DimensionLinear, Line};
use acadrust::tables::BlockRecord;
use acadrust::types::Vector3;
use acadrust::{EntityType, Handle};
use glam::DVec3;
use OpenCADStudio::command::EntityTransform;
use OpenCADStudio::scene::Scene;
#[test]
fn copy_dimension_duplicates_its_block() {
let mut scene = Scene::new();
// A baked *D0 block holding one line at (0,0)-(10,0).
let br_h = Handle::new(scene.document.next_handle());
let mut br = BlockRecord::new("*D0");
br.handle = br_h;
scene.document.block_records.add(br).unwrap();
let mut sub = Line::new();
sub.start = Vector3::new(0.0, 0.0, 0.0);
sub.end = Vector3::new(10.0, 0.0, 0.0);
let mut sub_e = EntityType::Line(sub);
sub_e.common_mut().owner_handle = br_h; // route into *D0
scene.document.add_entity(sub_e).unwrap();
// A linear dimension whose drawn geometry is that baked block.
let mut dim = DimensionLinear::new(
Vector3::new(0.0, 0.0, 0.0),
Vector3::new(10.0, 0.0, 0.0),
);
dim.base.block_name = "*D0".to_string();
let dim_h = scene.add_entity(EntityType::Dimension(Dimension::Linear(dim)));
// Copy the dimension by (0, 50).
let copies = scene.copy_entities(
&[dim_h],
&EntityTransform::Translate(DVec3::new(0.0, 50.0, 0.0)),
);
assert_eq!(copies.len(), 1);
let copy_h = copies[0];
// The copy must reference its OWN block, not the source's.
let copy_block = match scene.document.get_entity(copy_h) {
Some(EntityType::Dimension(d)) => d.base().block_name.clone(),
_ => panic!("copy is not a dimension"),
};
assert_ne!(copy_block, "*D0", "copy must get its own block");
assert!(!copy_block.trim().is_empty(), "copy block name must be set");
// The copy block's sub-line must be translated by (0, 50): (0,50)-(10,50).
let new_br = scene
.document
.block_records
.iter()
.find(|b| b.name == copy_block)
.expect("copy block record exists");
let subh = *new_br
.entity_handles
.first()
.expect("copy block has a sub-entity");
match scene.document.get_entity(subh) {
Some(EntityType::Line(l)) => assert!(
(l.start.y - 50.0).abs() < 1e-6 && (l.end.y - 50.0).abs() < 1e-6,
"copy block sub-line not translated: {:?}-{:?}",
(l.start.x, l.start.y),
(l.end.x, l.end.y)
),
other => panic!("copy block sub is not a line: {:?}", other.map(std::mem::discriminant)),
}
}