Skip to main content

nv_view/
camera_motion.rs

1//! Camera motion state and motion source types.
2
3/// Whether the camera is stable, moving, or in an unknown state.
4///
5/// Central to the view system's decision-making. Stages receive this
6/// through [`ViewSnapshot`](crate::ViewSnapshot).
7#[derive(Clone, Debug, PartialEq)]
8pub enum CameraMotionState {
9    /// Camera is not moving. Coordinates are stable across frames.
10    Stable,
11
12    /// Camera is actively moving.
13    Moving {
14        /// Angular velocity in degrees/second, if known.
15        angular_velocity: Option<f32>,
16        /// Estimated frame-to-frame displacement magnitude (normalized coordinates).
17        displacement: Option<f32>,
18    },
19
20    /// Camera motion state is unknown.
21    ///
22    /// Occurs when no telemetry is available, no estimator is configured,
23    /// or the estimator's confidence is below threshold. Treated as potentially
24    /// moving for safety — never assumed stable.
25    Unknown,
26}
27
28/// How the current motion state was determined.
29///
30/// Critical for downstream trust decisions — telemetry-sourced motion
31/// is more trustworthy than inferred motion from noisy optical flow.
32#[derive(Clone, Debug, PartialEq)]
33pub enum MotionSource {
34    /// Determined from PTZ telemetry (ONVIF, serial, etc.).
35    Telemetry,
36
37    /// Inferred from video analysis (optical flow, feature matching, homography).
38    Inferred {
39        /// Confidence score in `[0.0, 1.0]`.
40        confidence: f32,
41    },
42
43    /// From a user-supplied external system.
44    External,
45
46    /// No motion information available for this frame.
47    None,
48}
49
50#[cfg(test)]
51mod tests {
52    use super::*;
53
54    #[test]
55    fn stable_is_not_moving() {
56        assert!(!matches!(
57            CameraMotionState::Stable,
58            CameraMotionState::Moving { .. }
59        ));
60    }
61
62    #[test]
63    fn moving_carries_optional_fields() {
64        let m = CameraMotionState::Moving {
65            angular_velocity: Some(30.0),
66            displacement: Some(0.15),
67        };
68        if let CameraMotionState::Moving {
69            angular_velocity,
70            displacement,
71        } = m
72        {
73            assert_eq!(angular_velocity, Some(30.0));
74            assert_eq!(displacement, Some(0.15));
75        } else {
76            panic!("expected Moving");
77        }
78    }
79
80    #[test]
81    fn unknown_treated_as_potentially_moving() {
82        // Verify Unknown is distinct from both Stable and Moving.
83        let u = CameraMotionState::Unknown;
84        assert_ne!(u, CameraMotionState::Stable);
85        assert!(!matches!(u, CameraMotionState::Moving { .. }));
86    }
87
88    #[test]
89    fn motion_source_variants() {
90        assert_ne!(MotionSource::Telemetry, MotionSource::None);
91        let inferred = MotionSource::Inferred { confidence: 0.7 };
92        assert!(matches!(inferred, MotionSource::Inferred { confidence } if confidence > 0.5));
93    }
94}