libits_client/reception/exchange/
mobile.rs1extern crate integer_sqrt;
10
11use crate::reception::exchange::ReferencePosition;
12
13use self::integer_sqrt::IntegerSquareRoot;
14
15pub trait Mobile {
16 fn mobile_id(&self) -> u32;
17
18 fn position(&self) -> &ReferencePosition;
19
20 fn speed(&self) -> Option<u16>;
21
22 fn heading(&self) -> Option<u16>;
23
24 fn stopped(&self) -> bool {
25 if let Some(speed) = self.speed() {
26 return speed <= 36;
27 }
28 false
29 }
30
31 fn heading_in_degrees(&self) -> Option<f64> {
32 if let Some(heading) = self.heading() {
33 return Some(heading_in_degrees(heading));
34 }
35 None
36 }
37
38 fn speed_in_meter_per_second(&self) -> Option<f64> {
39 if let Some(speed) = self.speed() {
40 return Some(speed_in_meter_per_second(speed));
41 }
42 None
43 }
44
45 fn speed_in_kilometer_per_hour(&self) -> Option<f64> {
46 if let Some(speed) = self.speed() {
47 return Some(speed_in_kilometer_per_hour(speed));
48 }
49 None
50 }
51}
52
53pub(crate) fn heading_in_degrees(heading: u16) -> f64 {
54 heading as f64 / 10.0
55}
56
57pub(crate) fn speed_in_meter_per_second(speed: u16) -> f64 {
58 speed as f64 / 100.0
59}
60
61pub(crate) fn speed_in_kilometer_per_hour(speed: u16) -> f64 {
62 speed_in_meter_per_second(speed) * 3.6
63}
64
65pub(crate) fn speed_from_yaw_angle(x_speed: i16, y_speed: i16) -> u16 {
66 ((x_speed.abs() as u32).pow(2) + (y_speed.abs() as u32).pow(2)).integer_sqrt() as u16
67}
68
69#[cfg(test)]
70mod tests {
71 use crate::reception::exchange::mobile::{speed_from_yaw_angle, Mobile};
72 use crate::reception::exchange::reference_position::ReferencePosition;
73
74 #[test]
75 fn it_can_compute_speed() {
76 assert_eq!(speed_from_yaw_angle(1400, 500), 1486);
77 assert_eq!(speed_from_yaw_angle(-1400, 500), 1486);
78 assert_eq!(speed_from_yaw_angle(1400, -500), 1486);
79 assert_eq!(speed_from_yaw_angle(-1400, -500), 1486);
80 }
81
82 struct StoppedMobileStub {}
83
84 impl Mobile for StoppedMobileStub {
85 fn mobile_id(&self) -> u32 {
86 todo!()
87 }
88
89 fn position(&self) -> &ReferencePosition {
90 todo!()
91 }
92
93 fn speed(&self) -> Option<u16> {
94 Some(35)
95 }
96
97 fn heading(&self) -> Option<u16> {
98 Some(1800) }
100 }
101
102 struct MovingMobileStub {}
103
104 impl Mobile for MovingMobileStub {
105 fn mobile_id(&self) -> u32 {
106 todo!()
107 }
108
109 fn position(&self) -> &ReferencePosition {
110 todo!()
111 }
112
113 fn speed(&self) -> Option<u16> {
114 Some(37)
115 }
116
117 fn heading(&self) -> Option<u16> {
118 Some(900) }
120 }
121
122 #[test]
123 fn it_can_check_if_stopped() {
124 assert!(StoppedMobileStub {}.stopped());
125 }
126
127 #[test]
128 fn it_can_check_if_moving() {
129 assert_eq!(MovingMobileStub {}.stopped(), false);
130 }
131
132 #[test]
133 fn it_can_provide_heading_in_degrees() {
134 assert_eq!(StoppedMobileStub {}.heading_in_degrees(), Some(180.0));
136 assert_eq!(MovingMobileStub {}.heading_in_degrees(), Some(90.0));
138 }
139
140 #[test]
141 fn it_can_provide_speed_in_meter_per_second() {
142 assert_eq!(StoppedMobileStub {}.speed_in_meter_per_second(), Some(0.35));
144 assert_eq!(MovingMobileStub {}.speed_in_meter_per_second(), Some(0.37));
146 }
147
148 #[test]
149 fn it_can_provide_speed_in_kilometer_per_hour() {
150 assert_eq!(
152 StoppedMobileStub {}.speed_in_kilometer_per_hour(),
153 Some(1.26)
154 );
155 assert_eq!(
157 MovingMobileStub {}.speed_in_kilometer_per_hour(),
158 Some(1.332)
159 );
160 }
161}