From a6592cc9bc40c1e40e2dde5542e5a9427735281c Mon Sep 17 00:00:00 2001 From: Hakan Seven Date: Thu, 23 Apr 2026 19:11:19 +0300 Subject: [PATCH] fix: ViewCube hover, glow, centroids, corner geometry and snap angles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Hide OS crosshair and drawn crosshair when cursor is over ViewCube area - Enhanced hover glow in WGSL shader (blue tint + brightness boost) - Fixed region_centroids() Y-axis sign for all FRONT/BACK-related regions - Swapped corner geometry assignments (TPF↔TBK, BTF↔BBK) to match intended FRONT/BACK semantics (sy=-1 = FRONT, sy=+1 = BACK) - Corrected all snap_angles: yaw_pitch_to_quat(0,0) places eye at -Y (FRONT view), so FRONT=0 and BACK=PI — cascaded through edges/corners Co-Authored-By: Claude Sonnet 4.6 --- src/app/view.rs | 2 +- src/scene/pipeline/viewcube.rs | 112 ++++++++++++++++----------------- src/shaders/viewcube.wgsl | 4 +- src/ui/overlay.rs | 28 ++++++++- 4 files changed, 87 insertions(+), 59 deletions(-) diff --git a/src/app/view.rs b/src/app/view.rs index 2c031748d..1bbd70582 100644 --- a/src/app/view.rs +++ b/src/app/view.rs @@ -189,7 +189,7 @@ impl H7CAD { vec![] }; - overlay::selection_overlay(sel, snap_info, grips, grid, ucs_icon, ost_points, tab.last_cursor_screen) + overlay::selection_overlay(sel, snap_info, grips, grid, ucs_icon, ost_points, tab.last_cursor_screen, !is_paper) }; let nav = container(overlay::nav_toolbar()) diff --git a/src/scene/pipeline/viewcube.rs b/src/scene/pipeline/viewcube.rs index 6b71b33b8..869c94484 100644 --- a/src/scene/pipeline/viewcube.rs +++ b/src/scene/pipeline/viewcube.rs @@ -78,30 +78,30 @@ impl CubeRegion { match self.id() { 0 => (0.0, FRAC_PI_2), 1 => (0.0, -FRAC_PI_2), - 2 => (PI, 0.0), - 3 => (0.0, 0.0), - 4 => (FRAC_PI_2, 0.0), - 5 => (-FRAC_PI_2, 0.0), - 6 => (PI, FRAC_PI_4), - 7 => (0.0, FRAC_PI_4), - 8 => (FRAC_PI_2, FRAC_PI_4), - 9 => (-FRAC_PI_2, FRAC_PI_4), - 10 => (PI, -FRAC_PI_4), - 11 => (0.0, -FRAC_PI_4), + 2 => (0.0, 0.0), // FRONT: yaw=0 (eye at -Y) + 3 => (PI, 0.0), // BACK: yaw=PI (eye at +Y) + 4 => (FRAC_PI_2, 0.0), // RIGHT + 5 => (-FRAC_PI_2, 0.0), // LEFT + 6 => (0.0, FRAC_PI_4), // EDGE_TOP_FRONT + 7 => (PI, FRAC_PI_4), // EDGE_TOP_BACK + 8 => (FRAC_PI_2, FRAC_PI_4), // EDGE_TOP_RIGHT + 9 => (-FRAC_PI_2, FRAC_PI_4), // EDGE_TOP_LEFT + 10 => (0.0, -FRAC_PI_4), // EDGE_BOT_FRONT + 11 => (PI, -FRAC_PI_4), // EDGE_BOT_BACK 12 => (FRAC_PI_2, -FRAC_PI_4), 13 => (-FRAC_PI_2, -FRAC_PI_4), - 14 => (FRAC_PI_4, 0.0), - 15 => (-FRAC_PI_4, 0.0), - 16 => (PI * 0.75, 0.0), - 17 => (-PI * 0.75, 0.0), - 18 => (PI * 0.75, iso), - 19 => (-PI * 0.75, iso), - 20 => (FRAC_PI_4, iso), - 21 => (-FRAC_PI_4, iso), - 22 => (PI * 0.75, -iso), - 23 => (-PI * 0.75, -iso), - 24 => (FRAC_PI_4, -iso), - 25 => (-FRAC_PI_4, -iso), + 14 => (FRAC_PI_4, 0.0), // EDGE_FRONT_RIGHT (between 0 and PI/2) + 15 => (-FRAC_PI_4, 0.0), // EDGE_FRONT_LEFT + 16 => (PI * 0.75, 0.0), // EDGE_BACK_RIGHT (between PI and PI/2) + 17 => (-PI * 0.75, 0.0), // EDGE_BACK_LEFT + 18 => (FRAC_PI_4, iso), // CORNER_TPF_R (FRONT+RIGHT) + 19 => (-FRAC_PI_4, iso), // CORNER_TPF_L (FRONT+LEFT) + 20 => (PI * 0.75, iso), // CORNER_TBK_R (BACK+RIGHT) + 21 => (-PI * 0.75, iso), // CORNER_TBK_L (BACK+LEFT) + 22 => (FRAC_PI_4, -iso), // CORNER_BTF_R + 23 => (-FRAC_PI_4, -iso), // CORNER_BTF_L + 24 => (PI * 0.75, -iso), // CORNER_BBK_R + 25 => (-PI * 0.75, -iso), // CORNER_BBK_L _ => (0.0, 0.0), } } @@ -909,14 +909,14 @@ pub fn build_geometry() -> (Vec, Vec) { &mut is, ); for &([sx, sy, sz], region) in &[ - ([1.0f32, 1.0, 1.0], CORNER_TPF_R), - ([-1.0, 1.0, 1.0], CORNER_TPF_L), - ([1.0, 1.0, -1.0], CORNER_BTF_R), - ([-1.0, 1.0, -1.0], CORNER_BTF_L), - ([1.0, -1.0, 1.0], CORNER_TBK_R), - ([-1.0, -1.0, 1.0], CORNER_TBK_L), - ([1.0, -1.0, -1.0], CORNER_BBK_R), - ([-1.0, -1.0, -1.0], CORNER_BBK_L), + ([1.0f32, 1.0, 1.0], CORNER_TBK_R), // sy=+1 = BACK yönü + ([-1.0, 1.0, 1.0], CORNER_TBK_L), + ([1.0, 1.0, -1.0], CORNER_BBK_R), + ([-1.0, 1.0, -1.0], CORNER_BBK_L), + ([1.0, -1.0, 1.0], CORNER_TPF_R), // sy=-1 = FRONT yönü + ([-1.0, -1.0, 1.0], CORNER_TPF_L), + ([1.0, -1.0, -1.0], CORNER_BTF_R), + ([-1.0, -1.0, -1.0], CORNER_BTF_L), ] { push_tri( [sx * F, sy * F, sz * E], @@ -934,32 +934,32 @@ pub fn build_geometry() -> (Vec, Vec) { pub fn region_centroids() -> [[f32; 3]; NUM_REGIONS] { let m = (F + E) * 0.5; [ - [0.0, 0.0, E], - [0.0, 0.0, -E], - [0.0, E, 0.0], - [0.0, -E, 0.0], - [E, 0.0, 0.0], - [-E, 0.0, 0.0], - [0.0, m, m], - [0.0, -m, m], - [m, 0.0, m], - [-m, 0.0, m], - [0.0, m, -m], - [0.0, -m, -m], - [m, 0.0, -m], - [-m, 0.0, -m], - [m, m, 0.0], - [-m, m, 0.0], - [m, -m, 0.0], - [-m, -m, 0.0], - [m, m, m], - [-m, m, m], - [m, -m, m], - [-m, -m, m], - [m, m, -m], - [-m, m, -m], - [m, -m, -m], - [-m, -m, -m], + [0.0, 0.0, E], // FACE_TOP + [0.0, 0.0, -E], // FACE_BOTTOM + [0.0, -E, 0.0], // FACE_FRONT (geometry Y=-E) + [0.0, E, 0.0], // FACE_BACK (geometry Y=+E) + [E, 0.0, 0.0], // FACE_RIGHT + [-E, 0.0, 0.0], // FACE_LEFT + [0.0, -m, m], // EDGE_TOP_FRONT + [0.0, m, m], // EDGE_TOP_BACK + [m, 0.0, m], // EDGE_TOP_RIGHT + [-m, 0.0, m], // EDGE_TOP_LEFT + [0.0, -m, -m], // EDGE_BOT_FRONT + [0.0, m, -m], // EDGE_BOT_BACK + [m, 0.0, -m], // EDGE_BOT_RIGHT + [-m, 0.0, -m], // EDGE_BOT_LEFT + [m, -m, 0.0], // EDGE_FRONT_RIGHT + [-m, -m, 0.0], // EDGE_FRONT_LEFT + [m, m, 0.0], // EDGE_BACK_RIGHT + [-m, m, 0.0], // EDGE_BACK_LEFT + [m, -m, m], // CORNER_TPF_R (geometry sy=-1 = FRONT) + [-m, -m, m], // CORNER_TPF_L + [m, m, m], // CORNER_TBK_R (geometry sy=+1 = BACK) + [-m, m, m], // CORNER_TBK_L + [m, -m, -m], // CORNER_BTF_R (geometry sy=-1 = FRONT) + [-m, -m, -m], // CORNER_BTF_L + [m, m, -m], // CORNER_BBK_R (geometry sy=+1 = BACK) + [-m, m, -m], // CORNER_BBK_L ] } diff --git a/src/shaders/viewcube.wgsl b/src/shaders/viewcube.wgsl index e316da5be..890088538 100644 --- a/src/shaders/viewcube.wgsl +++ b/src/shaders/viewcube.wgsl @@ -26,7 +26,9 @@ fn fs_main(in: VOut) -> @location(0) vec4 { let is_hovered = abs(in.region_f - u.hover_region.x) < 0.001 && u.hover_region.x >= 0.0; var final_rgb = in.color; if is_hovered { - final_rgb = mix(final_rgb, vec3(0.55, 0.78, 1.0), 0.45); + let glow = vec3(0.68, 0.88, 1.0); + final_rgb = mix(final_rgb, glow, 0.60); + final_rgb = clamp(final_rgb * 1.30, vec3(0.0), vec3(1.0)); } return vec4(final_rgb, 1.0); } diff --git a/src/ui/overlay.rs b/src/ui/overlay.rs index 1982cef93..6f660fe4c 100644 --- a/src/ui/overlay.rs +++ b/src/ui/overlay.rs @@ -204,6 +204,7 @@ pub fn selection_overlay<'a>( ucs_icon: Option, ost_points: Vec, cursor_screen: Point, + show_viewcube: bool, ) -> Element<'a, Message> { canvas(SelectionCanvas { selection, @@ -213,6 +214,7 @@ pub fn selection_overlay<'a>( ucs_icon, ost_points, cursor_screen, + show_viewcube, }) .width(Length::Fill) .height(Length::Fill) @@ -227,6 +229,7 @@ struct SelectionCanvas { ucs_icon: Option, ost_points: Vec, cursor_screen: Point, + show_viewcube: bool, } impl canvas::Program for SelectionCanvas { @@ -238,6 +241,18 @@ impl canvas::Program for SelectionCanvas { bounds: iced::Rectangle, cursor: mouse::Cursor, ) -> mouse::Interaction { + if self.show_viewcube { + if let Some(pos) = cursor.position_in(bounds) { + use crate::scene::{VIEWCUBE_DRAW_PX, VIEWCUBE_PAD}; + let vc_x = bounds.width - VIEWCUBE_DRAW_PX - VIEWCUBE_PAD; + let vc_y = VIEWCUBE_PAD; + if pos.x >= vc_x && pos.x <= vc_x + VIEWCUBE_DRAW_PX + && pos.y >= vc_y && pos.y <= vc_y + VIEWCUBE_DRAW_PX + { + return mouse::Interaction::None; + } + } + } if cursor.is_over(bounds) { mouse::Interaction::Crosshair } else { @@ -251,7 +266,7 @@ impl canvas::Program for SelectionCanvas { renderer: &iced::Renderer, _theme: &Theme, bounds: iced::Rectangle, - _cursor: mouse::Cursor, + cursor: mouse::Cursor, ) -> Vec { let mut frame = canvas::Frame::new(renderer, bounds.size()); @@ -506,6 +521,16 @@ impl canvas::Program for SelectionCanvas { } // ── CAD crosshair cursor ────────────────────────────────────────────── + let over_viewcube = self.show_viewcube && { + use crate::scene::{VIEWCUBE_DRAW_PX, VIEWCUBE_PAD}; + cursor.position_in(bounds).map_or(false, |pos| { + let vc_x = bounds.width - VIEWCUBE_DRAW_PX - VIEWCUBE_PAD; + let vc_y = VIEWCUBE_PAD; + pos.x >= vc_x && pos.x <= vc_x + VIEWCUBE_DRAW_PX + && pos.y >= vc_y && pos.y <= vc_y + VIEWCUBE_DRAW_PX + }) + }; + if !over_viewcube { if let Some(cp) = self.selection.last_move_pos { let color = Color { r: 0.85, @@ -551,6 +576,7 @@ impl canvas::Program for SelectionCanvas { frame.stroke(&v_bot, stroke.clone()); frame.stroke(&square, stroke); } + } // end !over_viewcube // ── UCS icon ────────────────────────────────────────────────────── if let Some(ref ucs) = self.ucs_icon {