From f6b894813ecbca7cb2cf5ef54b9618c0a62d2280 Mon Sep 17 00:00:00 2001 From: Hakan Seven Date: Fri, 12 Jun 2026 00:42:50 +0300 Subject: [PATCH] fix(zoom): fit 3D solids in ZOOM EXTENTS (fit_all) ZOOM EXTENTS routes through fit_all, which built its bounds from the wire set and returned early when there were none. A drawing of only 3D solids has no wires, so ZOOM EXTENTS did nothing. Collect the layout's mesh AABBs alongside the wires, keep going when only meshes exist, and fold them into the fitted bounds. Co-Authored-By: Claude Opus 4.8 --- src/scene/mod.rs | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/scene/mod.rs b/src/scene/mod.rs index c5821a2a2..15c1e781e 100644 --- a/src/scene/mod.rs +++ b/src/scene/mod.rs @@ -5703,7 +5703,21 @@ impl Scene { if self.current_layout != "Model" { wires.extend(self.viewport_content_wires(layout_block, None, None)); } - if wires.is_empty() { + // 3D solids render as meshes, not wires, so collect their (offset-rel) + // XY AABBs separately — a drawing of only solids has no wires to fit. + let mesh_aabbs: Vec<[f32; 4]> = self + .meshes + .iter() + .filter(|(h, _)| { + self.document + .get_entity(**h) + .map(|e| e.common().owner_handle == layout_block) + .unwrap_or(false) + }) + .map(|(_, set)| set.world_aabb) + .filter(|a| a[0].is_finite() && a[2].is_finite()) + .collect(); + if wires.is_empty() && mesh_aabbs.is_empty() { return; } @@ -5743,7 +5757,7 @@ impl Scene { }); } } - if cents.is_empty() { + if cents.is_empty() && mesh_aabbs.is_empty() { return; } @@ -5791,6 +5805,11 @@ impl Scene { max = max.max(glam::Vec3::new(x, y, z)); } } + // Fold in 3D-solid mesh AABBs (not subject to the wire IQR reject). + for [ax, ay, bx, by] in &mesh_aabbs { + min = min.min(glam::Vec3::new(*ax, *ay, 0.0)); + max = max.max(glam::Vec3::new(*bx, *by, 0.0)); + } // If no usable points found, leave the camera unchanged. if min.x > max.x { return;