Co-authored-by: Brandon Thomas <echelon@gmail.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2 files changed
+70
-16
No files matched your search
+19
-16
@@ -108,24 +108,27 @@ fn bounds_in<'a>(d: &'a Drawing, e: &Entity, depth: usize, blocks: &mut HashMap<
|
||||
// A reference to a missing block (an unloaded xref, a purged definition) or to an empty
|
||||
// one draws nothing, so it contributes nothing: ZOOM Extents must not fly off to its
|
||||
// insertion point. Attributes below still count.
|
||||
let Some(blk) = d.block(&ins.block) else { return Bounds2::EMPTY };
|
||||
let m = ins.transform(blk.base.xy());
|
||||
let inner = match blocks.get(&(blk.name.as_str(), depth)) {
|
||||
Some(b) => *b,
|
||||
None => {
|
||||
let mut inner = Bounds2::EMPTY;
|
||||
for be in blk.entities.iter().filter(|be| in_block_visible(d, be)) {
|
||||
inner = inner.union(&bounds_in(d, be, depth + 1, blocks));
|
||||
let mut b = Bounds2::EMPTY;
|
||||
if let Some(blk) = d.block(&ins.block) {
|
||||
let m = ins.transform(blk.base.xy());
|
||||
let inner = match blocks.get(&(blk.name.as_str(), depth)) {
|
||||
Some(b) => *b,
|
||||
None => {
|
||||
let mut inner = Bounds2::EMPTY;
|
||||
for be in blk.entities.iter().filter(|be| in_block_visible(d, be)) {
|
||||
inner = inner.union(&bounds_in(d, be, depth + 1, blocks));
|
||||
}
|
||||
blocks.insert((blk.name.as_str(), depth), inner);
|
||||
inner
|
||||
}
|
||||
blocks.insert((blk.name.as_str(), depth), inner);
|
||||
inner
|
||||
};
|
||||
b = if inner.is_empty() { Bounds2::EMPTY } else { Bounds2::from_points(inner.corners().map(|c| m.apply(c))) };
|
||||
if ins.cols > 1 || ins.rows > 1 {
|
||||
let off =
|
||||
Vec2::new(ins.col_spacing * f64::from(ins.cols.saturating_sub(1)), ins.row_spacing * f64::from(ins.rows.saturating_sub(1)))
|
||||
.rotate(ins.rotation);
|
||||
b = b.union(&Bounds2::from_points(b.corners().map(|c| c + off)));
|
||||
}
|
||||
};
|
||||
let mut b = if inner.is_empty() { Bounds2::EMPTY } else { Bounds2::from_points(inner.corners().map(|c| m.apply(c))) };
|
||||
if ins.cols > 1 || ins.rows > 1 {
|
||||
let off = Vec2::new(ins.col_spacing * f64::from(ins.cols.saturating_sub(1)), ins.row_spacing * f64::from(ins.rows.saturating_sub(1)))
|
||||
.rotate(ins.rotation);
|
||||
b = b.union(&Bounds2::from_points(b.corners().map(|c| c + off)));
|
||||
}
|
||||
for a in &ins.attribs {
|
||||
if !a.invisible {
|
||||
|
||||
@@ -79,6 +79,57 @@ fn inserts_of_missing_or_empty_blocks_do_not_stretch_extents() {
|
||||
assert_eq!(d.extents(&Space::Model).max, Vec2::new(12.0, 12.0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn visible_attributes_of_a_missing_block_still_count() {
|
||||
// The renderer draws the attributes of a reference whose definition is missing, so they are
|
||||
// extents and selection targets, as with an empty definition. The insertion point still isn't.
|
||||
let attrib = |invisible: bool| Attrib {
|
||||
tag: "TAG".into(),
|
||||
text: Text {
|
||||
insert: Vec3::new(1000.0, 1000.0, 0.0),
|
||||
align_pt: None,
|
||||
height: 10.0,
|
||||
value: "hello".into(),
|
||||
rotation: 0.0,
|
||||
width_factor: 1.0,
|
||||
oblique: 0.0,
|
||||
style: "Standard".into(),
|
||||
halign: HAlign::Left,
|
||||
valign: VAlign::Baseline,
|
||||
},
|
||||
invisible,
|
||||
constant: false,
|
||||
prompt: String::new(),
|
||||
props: Default::default(),
|
||||
};
|
||||
let ins = |block: &str, attribs: Vec<Attrib>| {
|
||||
Entity::new(
|
||||
Handle(1),
|
||||
EntityKind::Insert(Insert {
|
||||
block: block.into(),
|
||||
insert: Vec3::ZERO,
|
||||
scale: Vec3::new(1.0, 1.0, 1.0),
|
||||
rotation: 0.0,
|
||||
attribs,
|
||||
cols: 1,
|
||||
rows: 1,
|
||||
col_spacing: 0.0,
|
||||
row_spacing: 0.0,
|
||||
}),
|
||||
)
|
||||
};
|
||||
let mut d = Drawing::new_imperial();
|
||||
d.blocks.insert("Empty".into(), std::sync::Arc::new(Block::new("Empty")));
|
||||
let missing = entity_bounds(&d, &ins("Missing", vec![attrib(false)]), 0);
|
||||
let empty = entity_bounds(&d, &ins("Empty", vec![attrib(false)]), 0);
|
||||
assert!(!missing.is_empty());
|
||||
assert_eq!((missing.min, missing.max), (empty.min, empty.max));
|
||||
assert_eq!(missing.min, Vec2::new(1000.0, 1000.0));
|
||||
// Without a visible attribute there is nothing to measure.
|
||||
assert!(entity_bounds(&d, &ins("Missing", vec![]), 0).is_empty());
|
||||
assert!(entity_bounds(&d, &ins("Missing", vec![attrib(true)]), 0).is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transform_arc_mirror_keeps_shape() {
|
||||
let mut k = EntityKind::Arc(Arc { center: Vec3::ZERO, radius: 1.0, start: 0.0, end: std::f64::consts::FRAC_PI_2 });
|
||||
|
||||
Reference in new issue
Block a user