ak_vis/viewer/session/
camera.rs1use 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}