forked from 1b-agent/opencadstudio-upstream
feat(ucs): per-viewport UCS applied inside floating viewports
Extend UCS support to in-viewport (MSPACE) editing through the existing single-converter structure: one active_ucs drives every UCS-aware system, now in the Model tab AND inside a floating viewport. - Single predicate DocumentTab::editing_model_space() (Model tab or active viewport) replaces the model-only gate in ucs_wire_affine, ucs_rotation_angle, ucs_grid_basis, viewcube_ucs_mat, the coordinate readout and the cursor-plane pick. - Per-viewport UCS: refresh_active_ucs() sets active_ucs to the pane's UCS on every transition (the entered viewport's own UCS from its ucs_origin/x_axis/y_axis/ucs_per_viewport fields, the header model UCS in the Model tab, none in plain paper); persist_active_ucs() writes changes back to the viewport entity or the header so they round-trip. Wired into EnterViewport/ExitViewport, layout switch, load and the UCS command. - Visuals: grid_views now returns each pane's handle so every content viewport's grid aligns to its own UCS; the UCS icon draws inside the active viewport projected through the viewport camera. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
a66d873e51
commit
295d3b1b5d
5 files changed
+164
-33
No files matched your search
+41
-14
@@ -155,11 +155,10 @@ impl OpenCADStudio {
|
||||
// stay independent: model tiles in model space; the sheet plus each
|
||||
// floating viewport (clipped to its rectangle) in paper space. One
|
||||
// enumeration for both, shared with the renderer.
|
||||
// Align the model grid to the active UCS (origin in wire space, world
|
||||
// axis directions); paper space stays plain WCS.
|
||||
let (grid_origin, grid_axes): (glam::DVec3, _) = if is_paper {
|
||||
(glam::DVec3::ZERO, (glam::Vec3::X, glam::Vec3::Y, glam::Vec3::Z))
|
||||
} else {
|
||||
// Align each grid to its pane's UCS (origin in wire space, world
|
||||
// axis directions): model tiles to the tab's model UCS, each content
|
||||
// viewport to its own per-viewport UCS, the paper sheet to plain WCS.
|
||||
let model_basis = {
|
||||
let (o, ux, uy, uz) = tab.ucs_xform().axes();
|
||||
(o.as_dvec3(), (ux, uy, uz))
|
||||
};
|
||||
@@ -167,27 +166,53 @@ impl OpenCADStudio {
|
||||
.scene
|
||||
.grid_views(vw, vh)
|
||||
.into_iter()
|
||||
.map(|(bounds, cam)| {
|
||||
.map(|(bounds, cam, handle)| {
|
||||
let (origin, axes): (glam::DVec3, _) = if is_paper {
|
||||
match tab.ucs_from_viewport(handle) {
|
||||
Some(u) => {
|
||||
let (o, ux, uy, uz) =
|
||||
super::helpers::UcsXform::from_ucs(&u).axes();
|
||||
(o.as_dvec3(), (ux, uy, uz))
|
||||
}
|
||||
None => (
|
||||
glam::DVec3::ZERO,
|
||||
(glam::Vec3::X, glam::Vec3::Y, glam::Vec3::Z),
|
||||
),
|
||||
}
|
||||
} else {
|
||||
model_basis
|
||||
};
|
||||
let plane = grid_plane_from_camera(cam.pitch, cam.yaw);
|
||||
overlay::GridParams {
|
||||
view_rot: cam.view_proj_rte(bounds),
|
||||
eye: cam.eye_f64(),
|
||||
bounds,
|
||||
plane,
|
||||
origin: grid_origin,
|
||||
axes: grid_axes,
|
||||
origin,
|
||||
axes,
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
let ucs_icon = if self.show_ucs_icon && !is_paper {
|
||||
// The UCS icon shows the active pane's UCS tripod: the model view, or
|
||||
// (inside a floating viewport) projected through the viewport camera
|
||||
// at the viewport's rect so it tracks the in-viewport UCS.
|
||||
// Rotation-only projection (view_proj_rte): the icon shows axis
|
||||
// DIRECTIONS only, so the full view_proj's huge UTM translation would
|
||||
// cancel catastrophically in f32 and make the tripod jitter.
|
||||
let ucs_icon = if !self.show_ucs_icon {
|
||||
None
|
||||
} else if let Some((vp_cam, full)) = tab.scene.viewport_edit_frame((vw, vh)) {
|
||||
let (_, ux, uy, uz) = tab.ucs_xform().axes();
|
||||
Some(overlay::UcsIconParams {
|
||||
view_proj: vp_cam.view_proj_rte(full),
|
||||
bounds: full,
|
||||
axes: (ux, uy, uz),
|
||||
})
|
||||
} else if !is_paper {
|
||||
let cam = tab.scene.camera.borrow();
|
||||
let (_, ux, uy, uz) = tab.ucs_xform().axes();
|
||||
Some(overlay::UcsIconParams {
|
||||
// Rotation-only projection: the icon shows axis DIRECTIONS
|
||||
// only, so the full view_proj's huge UTM translation would
|
||||
// just cancel catastrophically in f32 and make the tripod
|
||||
// jitter. view_proj_rte drops the translation. (#utm-ucs)
|
||||
view_proj: cam.view_proj_rte(vp_bounds),
|
||||
bounds: vp_bounds,
|
||||
axes: (ux, uy, uz),
|
||||
@@ -916,7 +941,9 @@ impl OpenCADStudio {
|
||||
// user's coordinate system, not raw WCS (no-op without UCS).
|
||||
let cursor_coord = {
|
||||
let lc = tab.last_cursor_world;
|
||||
if is_model {
|
||||
// The readout follows the active pane's UCS — model space
|
||||
// or inside a floating viewport (no-op without a UCS).
|
||||
if tab.editing_model_space() {
|
||||
let wo = [0.0_f64; 3];
|
||||
let wcs = glam::Vec3::new(
|
||||
lc.x + wo[0] as f32,
|
||||
|
||||
Reference in new issue
Block a user