oxihuman_export/
camera_fov_export.rs1#![allow(dead_code)]
4
5use std::f32::consts::PI;
8
9#[allow(dead_code)]
11#[derive(Debug, Clone, Copy)]
12pub struct FovKeyframe {
13 pub time: f32,
14 pub fov_degrees: f32,
15}
16
17#[allow(dead_code)]
19#[derive(Debug, Clone)]
20pub struct CameraFovExport {
21 pub camera_name: String,
22 pub keyframes: Vec<FovKeyframe>,
23}
24
25#[allow(dead_code)]
27pub fn new_camera_fov_export(name: &str) -> CameraFovExport {
28 CameraFovExport {
29 camera_name: name.to_string(),
30 keyframes: vec![],
31 }
32}
33
34#[allow(dead_code)]
36pub fn add_fov_keyframe(e: &mut CameraFovExport, time: f32, fov: f32) {
37 e.keyframes.push(FovKeyframe {
38 time,
39 fov_degrees: fov,
40 });
41}
42
43#[allow(dead_code)]
45pub fn fov_keyframe_count(e: &CameraFovExport) -> usize {
46 e.keyframes.len()
47}
48
49#[allow(dead_code)]
51pub fn fov_to_radians(fov_deg: f32) -> f32 {
52 fov_deg * PI / 180.0
53}
54
55#[allow(dead_code)]
57pub fn fov_to_focal_length(fov_deg: f32, sensor_width: f32) -> f32 {
58 sensor_width / (2.0 * (fov_to_radians(fov_deg) / 2.0).tan())
59}
60
61#[allow(dead_code)]
63pub fn fov_duration(e: &CameraFovExport) -> f32 {
64 if e.keyframes.is_empty() {
65 return 0.0;
66 }
67 let min = e.keyframes.iter().map(|k| k.time).fold(f32::MAX, f32::min);
68 let max = e.keyframes.iter().map(|k| k.time).fold(f32::MIN, f32::max);
69 max - min
70}
71
72#[allow(dead_code)]
74pub fn fov_validate(e: &CameraFovExport) -> bool {
75 e.keyframes
76 .iter()
77 .all(|k| k.fov_degrees > 0.0 && k.fov_degrees < 180.0 && k.time >= 0.0)
78}
79
80#[allow(dead_code)]
82pub fn camera_fov_to_json(e: &CameraFovExport) -> String {
83 format!(
84 "{{\"camera\":\"{}\",\"keyframes\":{},\"duration\":{:.6}}}",
85 e.camera_name,
86 fov_keyframe_count(e),
87 fov_duration(e)
88 )
89}
90
91#[cfg(test)]
92mod tests {
93 use super::*;
94 #[test]
95 fn test_new() {
96 let e = new_camera_fov_export("cam1");
97 assert_eq!(e.camera_name, "cam1");
98 }
99 #[test]
100 fn test_add() {
101 let mut e = new_camera_fov_export("c");
102 add_fov_keyframe(&mut e, 0.0, 60.0);
103 assert_eq!(fov_keyframe_count(&e), 1);
104 }
105 #[test]
106 fn test_to_radians() {
107 assert!((fov_to_radians(90.0) - PI / 2.0).abs() < 1e-5);
108 }
109 #[test]
110 fn test_focal_length() {
111 let fl = fov_to_focal_length(90.0, 36.0);
112 assert!(fl > 0.0);
113 }
114 #[test]
115 fn test_duration() {
116 let mut e = new_camera_fov_export("c");
117 add_fov_keyframe(&mut e, 0.0, 60.0);
118 add_fov_keyframe(&mut e, 2.0, 90.0);
119 assert!((fov_duration(&e) - 2.0).abs() < 1e-6);
120 }
121 #[test]
122 fn test_duration_empty() {
123 let e = new_camera_fov_export("c");
124 assert!((fov_duration(&e)).abs() < 1e-9);
125 }
126 #[test]
127 fn test_validate() {
128 let mut e = new_camera_fov_export("c");
129 add_fov_keyframe(&mut e, 0.0, 60.0);
130 assert!(fov_validate(&e));
131 }
132 #[test]
133 fn test_validate_bad() {
134 let mut e = new_camera_fov_export("c");
135 add_fov_keyframe(&mut e, 0.0, 200.0);
136 assert!(!fov_validate(&e));
137 }
138 #[test]
139 fn test_to_json() {
140 let e = new_camera_fov_export("cam");
141 let j = camera_fov_to_json(&e);
142 assert!(j.contains("\"camera\":\"cam\""));
143 }
144 #[test]
145 fn test_focal_known() {
146 let fl = fov_to_focal_length(53.13, 36.0);
147 assert!(fl > 15.0 && fl < 40.0);
148 }
149}