1use std::ops::Neg;
4
5use crate::movement::spec::RobotSpec;
6
7macro_rules! impl_math {
10 ($type:ty) => {
11 impl Neg for $type {
12 type Output = $type;
13
14 fn neg(self) -> Self::Output {
15 Self(-self.0)
16 }
17 }
18 };
19}
20
21#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
23pub struct Milimeters(pub f32);
24
25#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
27pub struct Degrees(pub f32);
28
29#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
31pub struct Rotations(pub f32);
32
33#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
35pub struct DegreesPerSecond(pub f32);
36
37#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
39pub struct MilimetersPerSecond(pub f32);
40
41#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
43pub struct DegreesPerSecondPerSecond(pub f32);
44
45#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
47pub struct MilimetersPerSecondPerSecond(pub f32);
48
49#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
51pub struct Percent(pub f32);
52
53#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
55pub struct Heading(pub f32);
56
57impl_math!(Milimeters);
58impl_math!(Degrees);
59impl_math!(Rotations);
60impl_math!(DegreesPerSecond);
61impl_math!(MilimetersPerSecond);
62impl_math!(DegreesPerSecondPerSecond);
63impl_math!(MilimetersPerSecondPerSecond);
64impl_math!(Percent);
65impl_math!(Heading);
66
67#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
68pub enum Distance {
69 Milimeters(Milimeters),
70 Degrees(Degrees),
71 Rotations(Rotations),
72}
73
74impl Distance {
75 pub fn to_deg(self, spec: &RobotSpec) -> Degrees {
76 match self {
77 Distance::Milimeters(val) => spec.mm_to_deg(val),
78 Distance::Degrees(val) => val,
79 Distance::Rotations(val) => Degrees(val.0 * 360.0),
80 }
81 }
82
83 pub fn to_rot(self, spec: &RobotSpec) -> Rotations {
84 match self {
85 Distance::Milimeters(val) => Rotations(spec.mm_to_deg(val).0 / 360.0),
86 Distance::Rotations(val) => val,
87 Distance::Degrees(val) => Rotations(val.0 / 360.0),
88 }
89 }
90
91 pub fn to_mm(self, spec: &RobotSpec) -> Milimeters {
92 match self {
93 Distance::Milimeters(val) => val,
94 Distance::Rotations(val) => spec.deg_to_mm((val.0 * 360.0).deg()),
95 Distance::Degrees(val) => spec.deg_to_mm(val),
96 }
97 }
98}
99
100impl From<Degrees> for Distance {
101 fn from(value: Degrees) -> Self {
102 Distance::Degrees(value)
103 }
104}
105
106impl From<Rotations> for Distance {
107 fn from(value: Rotations) -> Self {
108 Distance::Rotations(value)
109 }
110}
111
112impl From<Milimeters> for Distance {
113 fn from(value: Milimeters) -> Self {
114 Distance::Milimeters(value)
115 }
116}
117
118#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
119pub enum Speed {
120 DegreesPerSecond(DegreesPerSecond),
121 MilimetersPerSecond(MilimetersPerSecond),
122 Percent(Percent),
123}
124
125impl Speed {
126 pub fn to_dps(self, spec: &RobotSpec) -> DegreesPerSecond {
127 match self {
128 Speed::DegreesPerSecond(val) => val,
129 Speed::MilimetersPerSecond(val) => DegreesPerSecond(spec.mm_to_deg(val.0.mm()).0),
130 Speed::Percent(val) => DegreesPerSecond(val.0 * spec.max_speed().0),
131 }
132 }
133
134 pub fn to_mmps(self, spec: &RobotSpec) -> MilimetersPerSecond {
135 match self {
136 Speed::DegreesPerSecond(val) => MilimetersPerSecond(spec.deg_to_mm(val.0.deg()).0),
137 Speed::MilimetersPerSecond(val) => val,
138 Speed::Percent(val) => {
139 MilimetersPerSecond(spec.deg_to_mm((val.0 * spec.max_speed().0).deg()).0)
140 }
141 }
142 }
143
144 pub fn to_pct(self, spec: &RobotSpec) -> Percent {
145 match self {
146 Speed::DegreesPerSecond(val) => Percent(val.0 / spec.max_speed().0),
147 Speed::MilimetersPerSecond(val) => {
148 Percent(spec.mm_to_deg(val.0.mm()).0 / spec.max_speed().0)
149 }
150 Speed::Percent(val) => val,
151 }
152 }
153}
154
155impl From<DegreesPerSecond> for Speed {
156 fn from(value: DegreesPerSecond) -> Self {
157 Speed::DegreesPerSecond(value)
158 }
159}
160
161impl From<MilimetersPerSecond> for Speed {
162 fn from(value: MilimetersPerSecond) -> Self {
163 Speed::MilimetersPerSecond(value)
164 }
165}
166
167impl From<Percent> for Speed {
168 fn from(value: Percent) -> Self {
169 Speed::Percent(value)
170 }
171}
172
173#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
174pub enum Acceleration {
175 Degrees(DegreesPerSecondPerSecond),
176 Milimeters(MilimetersPerSecondPerSecond),
177}
178
179impl Acceleration {
180 pub fn to_dps2(self, spec: &RobotSpec) -> DegreesPerSecondPerSecond {
181 match self {
182 Acceleration::Milimeters(val) => {
183 DegreesPerSecondPerSecond(spec.mm_to_deg(val.0.mm()).0)
184 }
185 Acceleration::Degrees(val) => val,
186 }
187 }
188
189 pub fn to_mmps2(self, spec: &RobotSpec) -> MilimetersPerSecondPerSecond {
190 match self {
191 Acceleration::Milimeters(val) => val,
192 Acceleration::Degrees(val) => {
193 MilimetersPerSecondPerSecond(spec.deg_to_mm(val.0.deg()).0)
194 }
195 }
196 }
197}
198
199impl From<DegreesPerSecondPerSecond> for Acceleration {
200 fn from(value: DegreesPerSecondPerSecond) -> Self {
201 Acceleration::Degrees(value)
202 }
203}
204
205impl From<MilimetersPerSecondPerSecond> for Acceleration {
206 fn from(value: MilimetersPerSecondPerSecond) -> Self {
207 Acceleration::Milimeters(value)
208 }
209}
210
211pub trait UnitsExt {
212 fn mm(self) -> Milimeters;
214 fn deg(self) -> Degrees;
216 fn rot(self) -> Rotations;
218
219 fn dps(self) -> DegreesPerSecond;
221 fn mmps(self) -> MilimetersPerSecond;
223
224 fn dps2(self) -> DegreesPerSecondPerSecond;
226 fn mmps2(self) -> MilimetersPerSecondPerSecond;
228
229 fn ang(self) -> Heading;
231
232 fn pct(self) -> Percent;
234}
235
236impl UnitsExt for f32 {
237 fn mm(self) -> Milimeters {
238 Milimeters(self)
239 }
240
241 fn deg(self) -> Degrees {
242 Degrees(self)
243 }
244
245 fn rot(self) -> Rotations {
246 Rotations(self)
247 }
248
249 fn dps(self) -> DegreesPerSecond {
250 DegreesPerSecond(self)
251 }
252
253 fn mmps(self) -> MilimetersPerSecond {
254 MilimetersPerSecond(self)
255 }
256
257 fn dps2(self) -> DegreesPerSecondPerSecond {
258 DegreesPerSecondPerSecond(self)
259 }
260
261 fn mmps2(self) -> MilimetersPerSecondPerSecond {
262 MilimetersPerSecondPerSecond(self)
263 }
264
265 fn ang(self) -> Heading {
266 Heading(self)
267 }
268
269 fn pct(self) -> Percent {
270 Percent(self / 100.0)
271 }
272}
273
274impl UnitsExt for i32 {
275 fn mm(self) -> Milimeters {
276 Milimeters(self as f32)
277 }
278
279 fn deg(self) -> Degrees {
280 Degrees(self as f32)
281 }
282
283 fn rot(self) -> Rotations {
284 Rotations(self as f32)
285 }
286
287 fn dps(self) -> DegreesPerSecond {
288 DegreesPerSecond(self as f32)
289 }
290
291 fn mmps(self) -> MilimetersPerSecond {
292 MilimetersPerSecond(self as f32)
293 }
294
295 fn dps2(self) -> DegreesPerSecondPerSecond {
296 DegreesPerSecondPerSecond(self as f32)
297 }
298
299 fn mmps2(self) -> MilimetersPerSecondPerSecond {
300 MilimetersPerSecondPerSecond(self as f32)
301 }
302
303 fn ang(self) -> Heading {
304 Heading(self as f32)
305 }
306
307 fn pct(self) -> Percent {
308 Percent(self as f32 / 100.0)
309 }
310}