Skip to main content

oximedia_virtual/tracking/
mod.rs

1//! Camera tracking subsystem for virtual production
2//!
3//! Provides real-time camera position and orientation tracking with
4//! sub-millimeter accuracy and sub-degree rotational precision.
5
6pub mod calibrate;
7pub mod camera;
8pub mod filter;
9pub mod imu;
10pub mod markers;
11
12use crate::math::{Point3, UnitQuaternion, Vector3};
13use serde::{Deserialize, Serialize};
14
15/// Camera pose (position and orientation)
16#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
17pub struct CameraPose {
18    /// Position in world space (meters)
19    pub position: Point3<f64>,
20    /// Orientation as unit quaternion
21    pub orientation: UnitQuaternion<f64>,
22    /// Timestamp in nanoseconds
23    pub timestamp_ns: u64,
24    /// Tracking confidence (0.0 - 1.0)
25    pub confidence: f32,
26}
27
28impl CameraPose {
29    /// Create new camera pose
30    #[must_use]
31    pub fn new(position: Point3<f64>, orientation: UnitQuaternion<f64>, timestamp_ns: u64) -> Self {
32        Self {
33            position,
34            orientation,
35            timestamp_ns,
36            confidence: 1.0,
37        }
38    }
39
40    /// Get forward vector
41    #[must_use]
42    pub fn forward(&self) -> Vector3<f64> {
43        self.orientation * Vector3::new(0.0, 0.0, -1.0)
44    }
45
46    /// Get up vector
47    #[must_use]
48    pub fn up(&self) -> Vector3<f64> {
49        self.orientation * Vector3::new(0.0, 1.0, 0.0)
50    }
51
52    /// Get right vector
53    #[must_use]
54    pub fn right(&self) -> Vector3<f64> {
55        self.orientation * Vector3::new(1.0, 0.0, 0.0)
56    }
57
58    /// Interpolate between two poses
59    #[must_use]
60    pub fn interpolate(&self, other: &Self, t: f64) -> Self {
61        let position = self.position + (other.position - self.position) * t;
62        let orientation = self.orientation.slerp(&other.orientation, t);
63        let timestamp_ns =
64            self.timestamp_ns + ((other.timestamp_ns - self.timestamp_ns) as f64 * t) as u64;
65        let confidence = self.confidence + (other.confidence - self.confidence) * t as f32;
66
67        Self {
68            position,
69            orientation,
70            timestamp_ns,
71            confidence,
72        }
73    }
74}
75
76impl Default for CameraPose {
77    fn default() -> Self {
78        Self {
79            position: Point3::origin(),
80            orientation: UnitQuaternion::identity(),
81            timestamp_ns: 0,
82            confidence: 1.0,
83        }
84    }
85}
86
87#[cfg(test)]
88mod tests {
89    use super::*;
90
91    #[test]
92    fn test_camera_pose_default() {
93        let pose = CameraPose::default();
94        assert_eq!(pose.position, Point3::origin());
95        assert_eq!(pose.confidence, 1.0);
96    }
97
98    #[test]
99    fn test_camera_pose_vectors() {
100        let pose = CameraPose::default();
101        let forward = pose.forward();
102        assert!((forward.z + 1.0).abs() < 1e-6);
103    }
104
105    #[test]
106    fn test_pose_interpolation() {
107        let pose1 = CameraPose::new(Point3::new(0.0, 0.0, 0.0), UnitQuaternion::identity(), 0);
108        let pose2 = CameraPose::new(Point3::new(1.0, 1.0, 1.0), UnitQuaternion::identity(), 1000);
109
110        let interp = pose1.interpolate(&pose2, 0.5);
111        assert!((interp.position.x - 0.5).abs() < 1e-6);
112        assert!((interp.position.y - 0.5).abs() < 1e-6);
113        assert!((interp.position.z - 0.5).abs() < 1e-6);
114    }
115}