1use crate::channel_info::{ChannelId, ChannelInfo};
2use crate::error::Error;
3use crate::error::Error::{InvalidChannelId, TransformsNotSorted};
4use crate::frame_info::{FrameId, FrameInfo};
5use crate::isometry_graph::IsometryGraph;
6use crate::ops::filter::filter_by_channel;
7use crate::transform::TransformId;
8use crate::transform_info::TransformInfo;
9use crate::utils::transforms_interpolation::inter_and_extrapolate_transforms;
10
11use crate::Error::{InvalidTransformId, NoChannels, NoTransforms};
12use crate::{ExtrapolationMethod, InterpolationMethod, Transform};
13use chrono::{DateTime, Utc};
14use itertools::Itertools;
15use nalgebra::Isometry3;
16use rayon::iter::ParallelIterator;
17use rayon::prelude::IntoParallelRefIterator;
18use std::collections::{HashMap, HashSet};
19use std::vec;
20
21#[derive(Debug, Default, Clone, PartialEq)]
24pub struct ReferenceFrames {
25 pub transforms: HashMap<(ChannelId, TransformId), Vec<Transform>>,
26 pub frame_info: HashMap<FrameId, FrameInfo>,
27 pub channel_info: HashMap<ChannelId, ChannelInfo>,
28 pub transform_info: HashMap<TransformId, TransformInfo>,
29}
30
31impl ReferenceFrames {
32 pub fn new(
33 transforms: HashMap<(ChannelId, TransformId), Vec<Transform>>,
34 frame_info: HashMap<FrameId, FrameInfo>,
35 channel_info: HashMap<ChannelId, ChannelInfo>,
36 transform_info: HashMap<TransformId, TransformInfo>,
37 ) -> Result<Self, Error> {
38 if !transforms.is_empty() {
39 for frame in frame_info.keys() {
41 let contained_in_transforms = transforms.keys().any(|(_, transform_id)| {
42 &transform_id.frame_id == frame || &transform_id.child_frame_id == frame
43 });
44 assert!(
45 contained_in_transforms,
46 "No transform is referencing child or parent frame: {frame}"
47 );
48 }
49
50 for (current_id, current_transform) in &transforms {
51 if !current_transform.windows(2).all(|t| {
52 t[0].timestamp
53 .timestamp_nanos_opt()
54 .expect("should be defined")
55 < t[1]
56 .timestamp
57 .timestamp_nanos_opt()
58 .expect("should be defined")
59 }) {
60 return Err(TransformsNotSorted {
61 channel_id: current_id.0.clone(),
62 transform_id: current_id.1.clone(),
63 });
64 }
65 }
66 }
67
68 let mut sorted_transforms: HashMap<(ChannelId, TransformId), Vec<Transform>> =
70 HashMap::new();
71 for (current_key, current_transforms) in transforms {
72 let mut current_sorted_transforms = current_transforms.clone();
73 current_sorted_transforms.sort_by_key(|t| t.timestamp);
74
75 sorted_transforms.insert(current_key, current_sorted_transforms);
76 }
77
78 Ok(Self {
97 transforms: sorted_transforms,
98 frame_info,
99 channel_info,
100 transform_info,
101 })
102 }
103
104 pub fn is_empty(&self) -> bool {
105 self.transforms.is_empty()
106 }
107
108 pub fn transforms(&self) -> &HashMap<(ChannelId, TransformId), Vec<Transform>> {
109 &self.transforms
110 }
111
112 pub fn frame_info(&self) -> &HashMap<FrameId, FrameInfo> {
113 &self.frame_info
114 }
115
116 pub fn channel_info(&self) -> &HashMap<ChannelId, ChannelInfo> {
117 &self.channel_info
118 }
119
120 pub fn transform_info(&self) -> &HashMap<TransformId, TransformInfo> {
121 &self.transform_info
122 }
123}
124
125impl ReferenceFrames {
126 pub fn get_channel_ids(&self) -> HashSet<ChannelId> {
127 self.transforms
128 .keys()
129 .map(|(channel_id, _)| channel_id.clone())
130 .collect()
131 }
132
133 pub fn get_frame_ids(&self) -> HashSet<FrameId> {
134 self.transforms
135 .keys()
136 .fold(Vec::<FrameId>::new(), |mut acc, x| {
137 acc.push(x.1.frame_id.clone());
138 acc.push(x.1.child_frame_id.clone());
139 acc
140 })
141 .into_iter()
142 .collect()
143 }
144
145 pub fn get_transforms_of_channel(
146 &self,
147 channel_id: &ChannelId,
148 transform_id: &TransformId,
149 ) -> Result<&Vec<Transform>, Error> {
150 let transforms = self
151 .transforms
152 .get(&(channel_id.clone(), transform_id.clone()))
153 .ok_or(NoTransforms())?;
154 Ok(transforms)
155 }
156
157 pub fn get_channel_priority(&self, channel_id: &ChannelId) -> Result<i32, Error> {
158 if !self.get_channel_ids().contains(channel_id) {
159 return Err(InvalidChannelId(channel_id.clone()));
160 }
161
162 let priority = self.channel_info.get(channel_id).and_then(|x| x.priority);
163 Ok(priority.unwrap_or_default())
164 }
165
166 pub fn get_interpolation_method(&self, transform_id: &TransformId) -> InterpolationMethod {
167 self.transform_info
168 .get(transform_id)
169 .map(|x| x.interpolation_method)
170 .unwrap_or_default()
171 }
172
173 pub fn get_extrapolation_method(&self, transform_id: &TransformId) -> ExtrapolationMethod {
174 self.transform_info
175 .get(transform_id)
176 .map(|x| x.extrapolation_method)
177 .unwrap_or_default()
178 }
179
180 pub fn contains_channel(&self, channel_id: &ChannelId) -> bool {
181 self.get_channel_ids().iter().any(|x| x == channel_id)
182 }
183
184 pub fn contains_frame(&self, frame_id: &FrameId) -> bool {
185 self.get_frame_ids().iter().any(|f| f == frame_id)
186 }
187
188 pub fn contains_transform(&self, channel_id: &ChannelId, transform_id: &TransformId) -> bool {
189 self.transforms
190 .keys()
191 .any(|(current_channel_id, current_transform_id)| {
192 current_channel_id == channel_id && current_transform_id == transform_id
193 })
194 }
195}
196
197impl ReferenceFrames {
198 pub fn set_interpolation_method(
199 &mut self,
200 transform_id: TransformId,
201 method: InterpolationMethod,
202 ) {
203 self.transform_info
204 .entry(transform_id)
205 .or_default()
206 .interpolation_method = method;
207 }
208
209 pub fn set_extrapolation_method(
210 &mut self,
211 transform_id: TransformId,
212 method: ExtrapolationMethod,
213 ) {
214 self.transform_info
215 .entry(transform_id)
216 .or_default()
217 .extrapolation_method = method;
218 }
219
220 pub fn add_transforms(
221 &mut self,
222 channel_id: ChannelId,
223 transform_id: TransformId,
224 transforms: Vec<Transform>,
225 channel_info: Option<ChannelInfo>,
226 transform_info: Option<TransformInfo>,
227 ) -> Result<(), Error> {
228 if transforms.is_empty() {
229 return Err(NoTransforms());
230 }
231
232 self.transforms
233 .insert((channel_id.clone(), transform_id.clone()), transforms);
234 if let Some(channel_info) = channel_info {
235 self.channel_info.insert(channel_id, channel_info);
236 }
237 if let Some(transform_info) = transform_info {
238 self.transform_info.insert(transform_id, transform_info);
239 }
240 Ok(())
241 }
242
243 pub fn extend_transforms(
245 &mut self,
246 channel_id: ChannelId,
247 transform_id: TransformId,
248 transforms: Vec<Transform>,
249 ) -> Result<(), Error> {
250 if transforms.is_empty() {
251 return Err(NoTransforms());
252 }
253 let key = (channel_id, transform_id);
254
255 let mut combined_transforms: Vec<Transform> =
256 self.transforms.get(&key).map_or(Vec::new(), |x| x.clone());
257 combined_transforms.extend(transforms);
258
259 combined_transforms.sort_by_key(|t| t.timestamp);
260
261 self.transforms.insert(key, combined_transforms);
262
263 Ok(())
264 }
265}
266
267impl ReferenceFrames {
268 pub fn filter_by_channel_ids(
270 &self,
271 channel_ids: &[ChannelId],
272 ) -> Result<ReferenceFrames, Error> {
273 let all_transforms: HashMap<(ChannelId, TransformId), Vec<Transform>> = self
274 .transforms
275 .par_iter()
276 .filter(|((channel_id, _), _)| channel_ids.contains(channel_id))
277 .map(|((channel_id, transform_id), transforms)| {
278 (
279 (channel_id.clone(), transform_id.clone()),
280 transforms.clone(),
281 )
282 })
283 .collect();
284
285 let selected_transform_ids: HashSet<TransformId> =
286 all_transforms.keys().map(|(_, t)| t.clone()).collect();
287 let selected_frame_ids: HashSet<FrameId> = selected_transform_ids
288 .par_iter()
289 .flat_map(|t| [t.frame_id.clone(), t.child_frame_id.clone()])
290 .collect();
291
292 let all_frame_info: HashMap<FrameId, FrameInfo> = self
293 .frame_info
294 .par_iter()
295 .filter(|(i, _)| selected_frame_ids.contains(i))
296 .map(|(i, f)| (i.clone(), f.clone()))
297 .collect();
298 let all_channel_info: HashMap<ChannelId, ChannelInfo> = self
299 .channel_info
300 .par_iter()
301 .filter(|(channel_id, _)| channel_ids.contains(channel_id))
302 .map(|(i, c)| (i.clone(), c.clone()))
303 .collect();
304 let all_transform_info: HashMap<TransformId, TransformInfo> = self
305 .transform_info
306 .par_iter()
307 .filter(|(i, _)| selected_transform_ids.contains(i))
308 .map(|(i, c)| (i.clone(), c.clone()))
309 .collect();
310
311 let reference_frame = ReferenceFrames::new(
312 all_transforms,
313 all_frame_info,
314 all_channel_info,
315 all_transform_info,
316 )?;
317 Ok(reference_frame)
318 }
319
320 pub fn filter_by_transform_ids(
321 &self,
322 transform_ids: &[TransformId],
323 ) -> Result<ReferenceFrames, Error> {
324 let all_transforms: HashMap<(ChannelId, TransformId), Vec<Transform>> = self
325 .transforms
326 .par_iter()
327 .filter(|((_, transform_id), _)| transform_ids.contains(transform_id))
328 .map(|((channel_id, transform_id), transforms)| {
329 (
330 (channel_id.clone(), transform_id.clone()),
331 transforms.clone(),
332 )
333 })
334 .collect();
335
336 let selected_channel_ids: HashSet<ChannelId> =
337 all_transforms.keys().map(|(c, _)| c.clone()).collect();
338 let selected_transform_ids: HashSet<TransformId> =
339 all_transforms.keys().map(|(_, t)| t.clone()).collect();
340 let selected_frame_ids: HashSet<FrameId> = selected_transform_ids
341 .par_iter()
342 .flat_map(|t| [t.frame_id.clone(), t.child_frame_id.clone()])
343 .collect();
344
345 let all_frame_info: HashMap<FrameId, FrameInfo> = self
346 .frame_info
347 .par_iter()
348 .filter(|(i, _)| selected_frame_ids.contains(i))
349 .map(|(i, f)| (i.clone(), f.clone()))
350 .collect();
351 let all_channel_info: HashMap<ChannelId, ChannelInfo> = self
352 .channel_info
353 .par_iter()
354 .filter(|(channel_id, _)| selected_channel_ids.contains(channel_id))
355 .map(|(i, c)| (i.clone(), c.clone()))
356 .collect();
357 let all_transform_info: HashMap<TransformId, TransformInfo> = self
358 .transform_info
359 .par_iter()
360 .filter(|(i, _)| selected_transform_ids.contains(i))
361 .map(|(i, c)| (i.clone(), c.clone()))
362 .collect();
363
364 let reference_frame = ReferenceFrames::new(
365 all_transforms,
366 all_frame_info,
367 all_channel_info,
368 all_transform_info,
369 )?;
370 Ok(reference_frame)
371 }
372
373 pub fn filter_by_time_interval(
374 &self,
375 start_time: &Option<DateTime<Utc>>,
376 stop_time: &Option<DateTime<Utc>>,
377 ) -> Result<ReferenceFrames, Error> {
378 if start_time.is_none() && stop_time.is_none() {
379 return Ok(self.clone());
380 }
381
382 let all_transforms: HashMap<(ChannelId, TransformId), Vec<Transform>> = self
383 .transforms
384 .par_iter()
385 .flat_map(|((channel_id, transform_id), transforms)| {
386 let filtered_transforms: Vec<Transform> = transforms
387 .iter()
388 .filter(|t| start_time.is_none_or(|x| x <= t.timestamp))
389 .filter(|t| stop_time.is_none_or(|x| t.timestamp < x))
390 .cloned()
391 .collect();
392 if filtered_transforms.is_empty() {
393 return None;
394 }
395
396 let key = (channel_id.clone(), transform_id.clone());
397 Some((key, filtered_transforms))
398 })
399 .collect();
400
401 let selected_channel_ids: HashSet<ChannelId> =
402 all_transforms.keys().map(|(c, _)| c.clone()).collect();
403 let selected_transform_ids: HashSet<TransformId> =
404 all_transforms.keys().map(|(_, t)| t.clone()).collect();
405 let selected_frame_ids: HashSet<FrameId> = selected_transform_ids
406 .par_iter()
407 .flat_map(|t| [t.frame_id.clone(), t.child_frame_id.clone()])
408 .collect();
409
410 let all_frame_info: HashMap<FrameId, FrameInfo> = self
411 .frame_info
412 .par_iter()
413 .filter(|(i, _)| selected_frame_ids.contains(i))
414 .map(|(i, f)| (i.clone(), f.clone()))
415 .collect();
416 let all_channel_info: HashMap<ChannelId, ChannelInfo> = self
417 .channel_info
418 .par_iter()
419 .filter(|(channel_id, _)| selected_channel_ids.contains(channel_id))
420 .map(|(i, c)| (i.clone(), c.clone()))
421 .collect();
422 let all_transform_info: HashMap<TransformId, TransformInfo> = self
423 .transform_info
424 .par_iter()
425 .filter(|(i, _)| selected_transform_ids.contains(i))
426 .map(|(i, c)| (i.clone(), c.clone()))
427 .collect();
428
429 let reference_frame = ReferenceFrames::new(
430 all_transforms,
431 all_frame_info,
432 all_channel_info,
433 all_transform_info,
434 )?;
435 Ok(reference_frame)
436 }
437}
438
439impl ReferenceFrames {
440 pub fn get_timed_subset(&self, timestamp: &DateTime<Utc>) -> Result<ReferenceFrames, Error> {
441 let all_transforms: HashMap<(ChannelId, TransformId), Vec<Transform>> = self
442 .transforms
443 .iter()
444 .map(|((channel_id, transform_id), transforms)| {
445 let isometry = inter_and_extrapolate_transforms(
446 transforms,
447 &Some(*timestamp),
448 self.get_interpolation_method(transform_id),
449 self.get_extrapolation_method(transform_id),
450 );
451
452 isometry.map(|i| {
453 (
454 (channel_id.clone(), transform_id.clone()),
455 vec![Transform::from(*timestamp, i)],
456 )
457 })
458 })
459 .collect::<Result<HashMap<(ChannelId, TransformId), Vec<Transform>>, _>>()?;
460
461 let all_transform_info = self
462 .transform_info
463 .keys()
464 .map(|k| {
465 (
466 k.clone(),
467 TransformInfo::new(InterpolationMethod::Step, ExtrapolationMethod::default()),
468 )
469 })
470 .collect();
471
472 let reference_frame = ReferenceFrames::new(
473 all_transforms,
474 self.frame_info.clone(),
475 self.channel_info.clone(),
476 all_transform_info,
477 )?;
478 Ok(reference_frame)
479 }
480
481 pub fn get_valid_transform(
483 &self,
484 channel_id: &ChannelId,
485 transform_id: &TransformId,
486 timestamp: &Option<DateTime<Utc>>,
487 ) -> Result<Vec<&Transform>, Error> {
488 if !self.contains_channel(channel_id) {
489 return Err(InvalidChannelId(channel_id.clone()));
490 }
491
492 let all_transforms: Vec<&Transform> = self
493 .transforms
494 .get(&(channel_id.clone(), transform_id.clone()))
495 .ok_or_else(|| InvalidTransformId(channel_id.clone(), transform_id.clone()))?
496 .iter()
497 .collect();
498
499 if timestamp.is_none() {
500 return Ok(all_transforms);
501 }
502 let timestamp = timestamp.unwrap();
503
504 let mut time_based_filtered_transforms: Vec<&Transform> = all_transforms
505 .clone()
506 .windows(2)
507 .filter(|t| {
508 t[0].timestamp.timestamp_nanos_opt().unwrap()
509 <= timestamp.timestamp_nanos_opt().unwrap()
510 && timestamp.timestamp_nanos_opt().unwrap()
511 < t[1].timestamp.timestamp_nanos_opt().unwrap()
512 })
513 .map(|t| t[0])
519 .collect();
520
521 if all_transforms.last().unwrap().timestamp <= timestamp {
522 time_based_filtered_transforms.push(all_transforms.last().unwrap());
523 }
524
525 Ok(time_based_filtered_transforms)
526 }
527
528 pub fn derive_transform_graph(
533 &self,
534 selected_channel_ids: &Option<HashSet<ChannelId>>,
535 selected_timestamp: &Option<DateTime<Utc>>,
536 ) -> Result<IsometryGraph, Error> {
537 if let Some(channel_names) = &selected_channel_ids {
538 if channel_names.is_empty() {
539 return Err(NoChannels());
540 }
541 }
542
543 let mut selected_isometries: HashMap<TransformId, Isometry3<f64>> = HashMap::new();
544 let selected_transforms: HashMap<(ChannelId, TransformId), Vec<Transform>> =
545 match &selected_channel_ids {
546 Some(channel_names) => filter_by_channel(&self.transforms, channel_names),
547 None => self.transforms.clone(),
548 };
549
550 let mut prioritized_selected_transforms: HashMap<TransformId, Vec<Transform>> =
551 HashMap::new();
552 for (_, group) in &selected_transforms
553 .iter()
554 .sorted_by_key(|k| &k.0.1)
555 .chunk_by(|k| k.0.1.clone())
556 {
557 let highest_priority = group
558 .into_iter()
559 .max_by_key(|k| {
560 self.get_channel_priority(&k.0.0)
561 .expect("channel should exist")
562 })
563 .unwrap();
564
565 prioritized_selected_transforms
566 .insert(highest_priority.0.1.clone(), highest_priority.1.clone());
567 }
568
569 for (current_transform_id, current_transforms) in prioritized_selected_transforms {
570 let interpolated_transform = inter_and_extrapolate_transforms(
571 ¤t_transforms,
572 selected_timestamp,
573 self.get_interpolation_method(¤t_transform_id),
574 self.get_extrapolation_method(¤t_transform_id),
575 )?;
576 selected_isometries.insert(current_transform_id.clone(), interpolated_transform);
577 }
578
579 IsometryGraph::new(selected_isometries)
580 }
581}