From 417e8e3676e56623def5c4ec00d5ee8d87fc4e49 Mon Sep 17 00:00:00 2001 From: Christopher Overbeck Date: Tue, 15 Sep 2026 12:31:57 -0500 Subject: [PATCH] Add a viewport frame seam for dimension association resolution MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR3 has to map a resolved model point onto the sheet, which needs the layout viewport's paper<->model mapping. PR1 (feat/viewport-snap) owns `Scene::viewport_frame` and is not visible from this branch, so this adds the minimal stand-in the shared contract in `viewport_ref.rs` describes: paper_center from the viewport rectangle's centre, model_target from the saved view target, scale from `vp_effective_scale`, twist from the saved view twist. It is fenced off in one clearly marked block with merge instructions. PR1's version is camera-derived, because it must agree with what is actually drawn — including the auto-fit rescue `camera_for_viewport` applies to stale saved views. Nothing else in PR3 reads viewport fields directly, so replacing this one function is the whole merge. Co-Authored-By: Claude Fable 5.1 --- src/scene/viewport_ref.rs | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/scene/viewport_ref.rs b/src/scene/viewport_ref.rs index 7c64f4e29..66c92d565 100644 --- a/src/scene/viewport_ref.rs +++ b/src/scene/viewport_ref.rs @@ -328,6 +328,43 @@ impl MeasurementScale { } } +// ───────────────────────────────────────────────────────────────────────── +// MERGE SEAM — PR1 (feat/viewport-snap) owns `Scene::viewport_frame`. +// +// PR3 needs a frame to map a resolved model point onto the sheet, but PR1 is +// not visible from this branch. This is the minimal stand-in agreed in the +// shared contract: paper_center = vp.center, model_target = vp.view_target, +// scale = `vp_effective_scale`, twist = vp.twist_angle. PR1's version is +// camera-derived (it must agree with what is actually drawn, including the +// auto-fit rescue in `Scene::camera_for_viewport` for stale saved views). +// +// To merge: delete this whole block. Nothing else in PR3 reads viewport +// fields directly — every call goes through `Scene::viewport_frame`. +// ───────────────────────────────────────────────────────────────────────── +impl crate::scene::Scene { + /// The planar paper<->model mapping of layout viewport `handle`. + /// + /// `None` when the handle is not a viewport, or when its scale is + /// degenerate (a zero-height view cannot map anything). + pub fn viewport_frame(&self, handle: Handle) -> Option { + let Some(acadrust::EntityType::Viewport(vp)) = self.document.get_entity(handle) else { + return None; + }; + let scale = crate::scene::vp_effective_scale(vp.custom_scale, vp.view_height, vp.height); + if !scale.is_finite() || scale.abs() < 1e-12 { + return None; + } + Some(ViewportFrame { + viewport: handle, + paper_center: DVec2::new(vp.center.x, vp.center.y), + model_target: DVec2::new(vp.view_target.x, vp.view_target.y), + scale, + twist: vp.twist_angle, + locked: vp.status.locked, + }) + } +} + #[cfg(test)] mod tests { use super::*;