1use crate::spherical::LatLon;
2use crate::units::Floats;
3use derive_more::{Add, Deref, DerefMut, Sub};
4use std::f64;
5use std::ops::Mul;
6use swarmkit::{FieldwiseClamp, ParticleRefFrom, ParticleRefMut, SetTo};
7
8#[derive(Copy, Clone, Debug)]
16pub struct RouteSegment {
17 pub origin: LatLon,
18 pub destination: LatLon,
19}
20
21#[derive(Copy, Clone, Debug)]
34pub struct ClockedSegment {
35 pub origin: LatLon,
36 pub destination: LatLon,
37 pub segment_time: f64,
38 pub t_depart: f64,
39 pub t_arrive: f64,
40}
41
42#[derive(Copy, Clone, Debug, PartialEq, Add, Sub)]
43pub struct Path<const N: usize> {
44 pub xy: PathXY<N>,
45 pub t: Time<N>,
46}
47
48#[derive(Copy, Clone, Debug, PartialEq, Add, Sub)]
49pub struct PathXY<const N: usize>(pub Floats<N>, pub Floats<N>);
50
51#[derive(Copy, Clone, Debug, PartialEq, Deref, DerefMut, Add, Sub)]
52pub struct Time<const N: usize>(pub Floats<N>);
53
54pub struct SegmentIterator<'a, const N: usize> {
55 i: usize,
56 path: &'a Path<N>,
57}
58
59pub struct ClockedSegmentIterator<'a, const N: usize> {
66 i: usize,
67 t_running: f64,
68 path: &'a Path<N>,
69}
70
71impl<const N: usize> Path<N> {
76 pub fn lat_lon(&self, i: usize) -> LatLon {
77 self.xy.lat_lon(i)
78 }
79
80 pub fn get_segment(&self, i: usize) -> RouteSegment {
81 RouteSegment {
82 origin: self.lat_lon(i),
83 destination: self.lat_lon(i + 1),
84 }
85 }
86
87 pub fn len(&self) -> usize {
88 N
89 }
90
91 pub fn is_empty(&self) -> bool {
94 N == 0
95 }
96
97 pub fn iter_segments(&'_ self) -> SegmentIterator<'_, N> {
101 SegmentIterator::new(self)
102 }
103
104 pub fn iter_with_running_clock(&'_ self, start_time: f64) -> ClockedSegmentIterator<'_, N> {
112 ClockedSegmentIterator {
113 i: 0,
114 t_running: start_time,
115 path: self,
116 }
117 }
118}
119
120impl<const N: usize> Default for Path<N> {
121 fn default() -> Self {
122 Self {
123 xy: PathXY(Floats([0.0; N]), Floats([0.0; N])),
124 t: Time(Floats([0.0; N])),
125 }
126 }
127}
128
129impl<const N: usize> FieldwiseClamp for Path<N> {
130 fn clamp(&self, min: Self, max: Self) -> Self {
131 Self {
132 xy: self.xy.clamp(min.xy, max.xy),
133 t: self.t.clamp(min.t, max.t),
134 }
135 }
136}
137
138impl<const N: usize> Mul<f64> for Path<N> {
139 type Output = Self;
140
141 fn mul(self, rhs: f64) -> Self::Output {
142 let mut result = Self::default();
143 for i in 0..N {
144 result.xy.0[i] = self.xy.0[i] * rhs;
145 result.t.0[i] = self.t.0[i] * rhs;
146 }
147 result
148 }
149}
150
151impl<const N: usize> PathXY<N> {
156 pub fn lat_lon(&self, i: usize) -> LatLon {
160 LatLon::new(self.0[i], self.1[i])
161 }
162
163 pub fn set_lat_lon(&mut self, i: usize, pos: LatLon) {
168 self.0[i] = pos.lon;
169 self.1[i] = pos.lat;
170 }
171}
172
173impl<const N: usize> Default for PathXY<N> {
174 fn default() -> Self {
175 Self(Floats([0.0; N]), Floats([0.0; N]))
176 }
177}
178
179impl<const N: usize> ParticleRefFrom for PathXY<N> {
180 type TSource = Path<N>;
181
182 fn divide_from<'a>(
183 source: &'a mut ParticleRefMut<'_, Self::TSource>,
184 ) -> ParticleRefMut<'a, Self>
185 where
186 Self: Copy,
187 {
188 ParticleRefMut {
189 pos: &mut source.pos.xy,
190 vel: &mut source.vel.xy,
191 fit: source.fit,
192 best_pos: &mut source.best_pos.xy,
193 best_fit: source.best_fit,
194 }
195 }
196}
197
198impl<const N: usize> From<Path<N>> for PathXY<N> {
199 fn from(value: Path<N>) -> Self {
200 value.xy
201 }
202}
203
204impl<const N: usize> FieldwiseClamp for PathXY<N> {
205 fn clamp(&self, min: Self, max: Self) -> Self {
206 Self(self.0.clamp(min.0, max.0), self.1.clamp(min.1, max.1))
207 }
208}
209
210impl<const N: usize> Mul<f64> for PathXY<N> {
211 type Output = Self;
212
213 fn mul(self, rhs: f64) -> Self::Output {
214 Self(self.0 * rhs, self.1 * rhs)
215 }
216}
217
218impl<const N: usize> Default for Time<N> {
223 fn default() -> Self {
224 Self(Floats([0.0; N]))
225 }
226}
227
228impl<const N: usize> ParticleRefFrom for Time<N> {
229 type TSource = Path<N>;
230
231 fn divide_from<'a>(
232 source: &'a mut ParticleRefMut<'_, Self::TSource>,
233 ) -> ParticleRefMut<'a, Self>
234 where
235 Self: Copy,
236 {
237 ParticleRefMut {
238 pos: &mut source.pos.t,
239 vel: &mut source.vel.t,
240 fit: source.fit,
241 best_pos: &mut source.best_pos.t,
242 best_fit: source.best_fit,
243 }
244 }
245}
246
247impl<const N: usize> SetTo for Time<N> {
248 type TTarget = Path<N>;
249
250 fn set_to_ref_mut(&self, target: &mut ParticleRefMut<'_, Self::TTarget>) {
251 target.pos.t = *self;
252 }
253}
254
255impl<const N: usize> From<Path<N>> for Time<N> {
256 fn from(value: Path<N>) -> Self {
257 value.t
258 }
259}
260
261impl<const N: usize> FieldwiseClamp for Time<N> {
262 fn clamp(&self, min: Self, max: Self) -> Self {
263 Self(self.0.clamp(min.0, max.0))
264 }
265}
266
267impl<const N: usize> Mul<f64> for Time<N> {
268 type Output = Self;
269
270 fn mul(self, rhs: f64) -> Self::Output {
271 Self(self.0 * rhs)
272 }
273}
274
275impl<'a, const N: usize> SegmentIterator<'a, N> {
280 pub fn new(path: &'a Path<N>) -> Self {
281 SegmentIterator { i: 0, path }
282 }
283}
284
285impl<const N: usize> Iterator for SegmentIterator<'_, N> {
286 type Item = RouteSegment;
287
288 fn next(&mut self) -> Option<Self::Item> {
289 let i = self.i;
290 self.i += 1;
291 if i + 1 < self.path.len() {
292 Some(self.path.get_segment(i))
293 } else {
294 None
295 }
296 }
297}
298
299impl<const N: usize> Iterator for ClockedSegmentIterator<'_, N> {
300 type Item = ClockedSegment;
301
302 fn next(&mut self) -> Option<Self::Item> {
303 let i = self.i;
304 if i + 1 >= self.path.len() {
305 return None;
306 }
307 self.i += 1;
308 let segment_time = self.path.t[i + 1];
309 let t_depart = self.t_running;
310 let t_arrive = t_depart + segment_time;
311 self.t_running = t_arrive;
312 Some(ClockedSegment {
313 origin: self.path.lat_lon(i),
314 destination: self.path.lat_lon(i + 1),
315 segment_time,
316 t_depart,
317 t_arrive,
318 })
319 }
320}