lnmp_spatial/
delta.rs

1use crate::types::*;
2
3/// Trait for types that support delta encoding.
4pub trait Delta: Sized {
5    type DeltaType;
6
7    /// Computes the delta required to go from `start` to `end`.
8    /// `start + delta = end`
9    fn compute_delta(start: &Self, end: &Self) -> Self::DeltaType;
10
11    /// Applies a delta to `start` to get `end`.
12    /// `start + delta = end`
13    fn apply_delta(start: &Self, delta: &Self::DeltaType) -> Self;
14}
15
16impl Delta for Position3D {
17    type DeltaType = PositionDelta;
18
19    fn compute_delta(start: &Self, end: &Self) -> Self::DeltaType {
20        PositionDelta {
21            dx: end.x - start.x,
22            dy: end.y - start.y,
23            dz: end.z - start.z,
24        }
25    }
26
27    fn apply_delta(start: &Self, delta: &Self::DeltaType) -> Self {
28        Self {
29            x: start.x + delta.dx,
30            y: start.y + delta.dy,
31            z: start.z + delta.dz,
32        }
33    }
34}
35
36impl Delta for Rotation {
37    type DeltaType = RotationDelta;
38
39    fn compute_delta(start: &Self, end: &Self) -> Self::DeltaType {
40        RotationDelta {
41            d_pitch: end.pitch - start.pitch,
42            d_yaw: end.yaw - start.yaw,
43            d_roll: end.roll - start.roll,
44        }
45    }
46
47    fn apply_delta(start: &Self, delta: &Self::DeltaType) -> Self {
48        Self {
49            pitch: start.pitch + delta.d_pitch,
50            yaw: start.yaw + delta.d_yaw,
51            roll: start.roll + delta.d_roll,
52        }
53    }
54}
55
56impl Delta for SpatialState {
57    type DeltaType = SpatialDelta;
58
59    fn compute_delta(start: &Self, end: &Self) -> Self::DeltaType {
60        let pos_delta = match (&start.position, &end.position) {
61            (Some(s), Some(e)) => Some(Position3D::compute_delta(s, e)),
62            _ => None,
63        };
64
65        let rot_delta = match (&start.rotation, &end.rotation) {
66            (Some(s), Some(e)) => Some(Rotation::compute_delta(s, e)),
67            _ => None,
68        };
69
70        // Velocity and Acceleration are usually treated as absolute updates in telemetry,
71        // but we could delta them too. For now, we'll just carry over the new value if it changed.
72        // However, SpatialDelta::State definition uses Option<Velocity>.
73        // Let's assume if it's present in `end`, we send it.
74
75        SpatialDelta::State {
76            position: pos_delta,
77            rotation: rot_delta,
78            velocity: end.velocity,
79            acceleration: end.acceleration,
80        }
81    }
82
83    fn apply_delta(start: &Self, delta: &Self::DeltaType) -> Self {
84        match delta {
85            SpatialDelta::State {
86                position,
87                rotation,
88                velocity,
89                acceleration,
90            } => {
91                let new_pos = match (start.position, position) {
92                    (Some(p), Some(d)) => Some(Position3D::apply_delta(&p, d)),
93                    (p, _) => p,
94                };
95
96                let new_rot = match (start.rotation, rotation) {
97                    (Some(r), Some(d)) => Some(Rotation::apply_delta(&r, d)),
98                    (r, _) => r,
99                };
100
101                Self {
102                    position: new_pos,
103                    rotation: new_rot,
104                    velocity: velocity.or(start.velocity),
105                    acceleration: acceleration.or(start.acceleration),
106                }
107            }
108            _ => start.clone(), // Should not happen if types match
109        }
110    }
111}