ak_vis/viewer/session/
camera.rs

1use bevy::prelude::Vec3;
2
3use crate::structure_vec3_to_world;
4
5use super::{CameraState, CameraView, OrbitMotion, ViewerCommand, ViewerState};
6
7impl CameraState {
8    pub fn new(viewer: &ViewerState) -> Self {
9        Self::from_view(camera_view_for_frame(viewer).unwrap_or(CameraView {
10            focus: Vec3::ZERO,
11            radius: 1.0,
12            yaw: -std::f32::consts::FRAC_PI_2,
13            pitch: 0.0,
14        }))
15    }
16
17    pub fn from_view(view: CameraView) -> Self {
18        Self {
19            focus: view.focus,
20            radius: view.radius,
21            yaw: view.yaw,
22            pitch: view.pitch,
23            needs_apply: true,
24            motion: None,
25        }
26    }
27
28    pub fn apply_command(&mut self, viewer: &ViewerState, command: &ViewerCommand) {
29        match command {
30            ViewerCommand::SetCameraView {
31                focus,
32                radius,
33                yaw,
34                pitch,
35            } => {
36                self.motion = None;
37                if let Some(focus) = focus {
38                    self.focus = Vec3::from_array(*focus);
39                }
40                if let Some(radius) = radius {
41                    self.radius = (*radius).max(f32::EPSILON);
42                }
43                if let Some(yaw) = yaw {
44                    self.yaw = *yaw;
45                }
46                if let Some(pitch) = pitch {
47                    self.pitch = *pitch;
48                }
49                self.needs_apply = true;
50            }
51            ViewerCommand::PanCamera { delta } => {
52                self.motion = None;
53                self.focus += Vec3::from_array(*delta);
54                self.needs_apply = true;
55            }
56            ViewerCommand::ZoomCamera { factor, delta } => {
57                self.motion = None;
58                if let Some(factor) = factor {
59                    self.radius = (self.radius * *factor).max(f32::EPSILON);
60                }
61                if let Some(delta) = delta {
62                    self.radius = (self.radius + *delta).max(f32::EPSILON);
63                }
64                self.needs_apply = true;
65            }
66            ViewerCommand::OrbitCamera {
67                yaw_delta,
68                pitch_delta,
69            } => {
70                self.motion = None;
71                self.yaw += *yaw_delta;
72                self.pitch += *pitch_delta;
73                self.needs_apply = true;
74            }
75            ViewerCommand::FrameAll => {
76                if let Some(view) = camera_view_for_frame(viewer) {
77                    *self = Self::from_view(view);
78                }
79            }
80            ViewerCommand::StartOrbit {
81                yaw_rate,
82                pitch_rate,
83            } => {
84                self.motion = Some(OrbitMotion {
85                    yaw_rate: *yaw_rate,
86                    pitch_rate: *pitch_rate,
87                });
88            }
89            ViewerCommand::StopCameraMotion => {
90                self.motion = None;
91            }
92            _ => {}
93        }
94    }
95
96    pub fn reset_for_frame(&mut self, viewer: &ViewerState) {
97        if let Some(view) = camera_view_for_frame(viewer) {
98            *self = Self::from_view(view);
99        }
100    }
101
102    pub fn tick_motion(&mut self, delta_seconds: f32) {
103        if let Some(motion) = self.motion {
104            self.yaw += motion.yaw_rate * delta_seconds;
105            self.pitch += motion.pitch_rate * delta_seconds;
106            self.needs_apply = true;
107        }
108    }
109}
110
111pub fn camera_view_for_frame(viewer: &ViewerState) -> Option<CameraView> {
112    if !viewer.has_frames() {
113        return None;
114    }
115
116    let view = viewer.traj.view(viewer.current);
117    let focus = structure_vec3_to_world(Vec3::from_slice(
118        view.cell.reduced(0.5, 0.5, 0.5).cast::<f32>().as_slice(),
119    ));
120    let radius = [view.cell.a(), view.cell.b(), view.cell.c()]
121        .iter()
122        .fold(0.0_f64, |acc, v| acc.max(v.norm())) as f32;
123
124    Some(CameraView {
125        focus,
126        radius: 2.5 * radius.max(f32::EPSILON),
127        yaw: -std::f32::consts::FRAC_PI_2,
128        pitch: 0.0,
129    })
130}