Skip to main content

nv_view/
transform.rs

1//! Global transform estimate types.
2
3use nv_core::AffineTransform2D;
4
5use crate::view_state::ViewVersion;
6
7/// A frame-to-reference coordinate transform estimate.
8///
9/// Provided by `ViewStateProvider` implementations that perform
10/// feature matching, optical flow, or PTZ-based modeling.
11#[derive(Clone, Debug, PartialEq)]
12pub struct GlobalTransformEstimate {
13    /// The affine transform from current frame coordinates to reference coordinates.
14    pub transform: AffineTransform2D,
15    /// Confidence in this estimate, in `[0.0, 1.0]`.
16    pub confidence: f32,
17    /// Method used to compute this transform.
18    pub method: TransformEstimationMethod,
19    /// `ViewVersion` at which this transform was computed.
20    ///
21    /// Consumers can compare against the current version to detect staleness.
22    pub computed_at: ViewVersion,
23}
24
25impl GlobalTransformEstimate {
26    /// Displacement magnitude (in normalized coordinates) implied by
27    /// the translation component of the transform.
28    ///
29    /// `sqrt(tx² + ty²)` of the affine matrix.
30    #[must_use]
31    pub fn displacement_magnitude(&self) -> f32 {
32        let tx = self.transform.m[2];
33        let ty = self.transform.m[5];
34        (tx * tx + ty * ty).sqrt() as f32
35    }
36}
37
38/// Method used to estimate a global coordinate transform.
39#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
40pub enum TransformEstimationMethod {
41    /// Computed from PTZ telemetry combined with a camera model.
42    PtzModel,
43    /// Computed from inter-frame feature matching (optical flow, homography).
44    FeatureMatching,
45    /// Provided by a user-supplied external system.
46    External,
47}
48
49#[cfg(test)]
50mod tests {
51    use super::*;
52    use nv_core::AffineTransform2D;
53
54    fn identity_transform() -> GlobalTransformEstimate {
55        GlobalTransformEstimate {
56            transform: AffineTransform2D::IDENTITY,
57            confidence: 1.0,
58            method: TransformEstimationMethod::FeatureMatching,
59            computed_at: ViewVersion::new(1),
60        }
61    }
62
63    #[test]
64    fn identity_has_zero_displacement() {
65        let est = identity_transform();
66        assert!((est.displacement_magnitude() - 0.0).abs() < 1e-6);
67    }
68
69    #[test]
70    fn translation_displacement() {
71        let est = GlobalTransformEstimate {
72            // Translation of (0.3, 0.4) → magnitude = 0.5
73            transform: AffineTransform2D {
74                m: [1.0, 0.0, 0.3, 0.0, 1.0, 0.4],
75            },
76            confidence: 0.9,
77            method: TransformEstimationMethod::PtzModel,
78            computed_at: ViewVersion::new(2),
79        };
80        assert!((est.displacement_magnitude() - 0.5).abs() < 1e-5);
81    }
82
83    #[test]
84    fn clone_eq() {
85        let est = identity_transform();
86        assert_eq!(est, est.clone());
87    }
88}