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::interpolate_transforms;
10
11use crate::Error::{InvalidTransformId, MissingTransforms, NoChannels};
12use crate::{InterpolationMethod, Transform};
13use chrono::{DateTime, Utc};
14use itertools::Itertools;
15use nalgebra::Isometry3;
16use std::collections::{HashMap, HashSet};
17
18use std::vec;
19
20#[derive(Debug, Default, Clone, PartialEq)]
23pub struct ReferenceFrames {
24 pub(crate) transforms: HashMap<(ChannelId, TransformId), Vec<Transform>>,
25 pub(crate) frame_info: HashMap<FrameId, FrameInfo>,
26 pub(crate) channel_info: HashMap<ChannelId, ChannelInfo>,
27 pub(crate) transform_info: HashMap<TransformId, TransformInfo>,
28}
29
30impl ReferenceFrames {
31 pub fn new(
32 transforms: HashMap<(ChannelId, TransformId), Vec<Transform>>,
33 frame_info: HashMap<FrameId, FrameInfo>,
34 channel_info: HashMap<ChannelId, ChannelInfo>,
35 transform_info: HashMap<TransformId, TransformInfo>,
36 ) -> Result<Self, Error> {
37 if !transforms.is_empty() {
38 for frame in frame_info.keys() {
40 let contained_in_transforms = transforms.keys().any(|(_, transform_id)| {
41 &transform_id.frame_id == frame || &transform_id.child_frame_id == frame
42 });
43 assert!(
44 contained_in_transforms,
45 "No transform is referencing child or parent frame: {frame}"
46 );
47 }
48
49 for (current_id, current_transform) in &transforms {
50 if !current_transform
51 .windows(2)
52 .all(|t| t[0].timestamp.timestamp_nanos() < t[1].timestamp.timestamp_nanos())
53 {
54 return Err(TransformsNotSorted {
55 channel_id: current_id.0.clone(),
56 transform_id: current_id.1.clone(),
57 });
58 }
59 }
60 }
61
62 let mut sorted_transforms: HashMap<(ChannelId, TransformId), Vec<Transform>> =
64 HashMap::new();
65 for (current_key, current_transforms) in transforms {
66 let mut current_sorted_transforms = current_transforms.clone();
67 current_sorted_transforms.sort_by_key(|t| t.timestamp);
68
69 sorted_transforms.insert(current_key, current_sorted_transforms);
70 }
71
72 Ok(Self {
91 transforms: sorted_transforms,
92 frame_info,
93 channel_info,
94 transform_info,
95 })
96 }
97
98 pub fn is_empty(&self) -> bool {
99 self.transforms.is_empty()
100 }
101
102 pub fn frame_info(&self) -> &HashMap<FrameId, FrameInfo> {
103 &self.frame_info
104 }
105
106 pub fn channel_info(&self) -> &HashMap<ChannelId, ChannelInfo> {
107 &self.channel_info
108 }
109
110 pub fn transform_info(&self) -> &HashMap<TransformId, TransformInfo> {
111 &self.transform_info
112 }
113
114 pub fn get_subset(&self, selected_channel_ids: &[ChannelId]) -> Result<ReferenceFrames, Error> {
116 let all_transforms: HashMap<(ChannelId, TransformId), Vec<Transform>> = self
126 .transforms
127 .iter()
128 .filter(|((channel_id, _), _)| selected_channel_ids.contains(channel_id))
129 .map(|((channel_id, transform_id), transforms)| {
130 (
131 (channel_id.clone(), transform_id.clone()),
132 transforms.clone(),
133 )
134 })
135 .collect();
136
137 let selected_transform_ids: HashSet<TransformId> =
138 all_transforms.keys().map(|(_, t)| t.clone()).collect();
139
140 let selected_frame_ids: HashSet<FrameId> = selected_transform_ids
141 .iter()
142 .flat_map(|t| [t.frame_id.clone(), t.child_frame_id.clone()])
143 .collect();
144
145 let all_frame_info: HashMap<FrameId, FrameInfo> = self
146 .frame_info
147 .iter()
148 .filter(|(i, _)| selected_frame_ids.contains(i))
149 .map(|(i, f)| (i.clone(), f.clone()))
150 .collect();
151
152 let all_channel_info: HashMap<ChannelId, ChannelInfo> = self
153 .channel_info
154 .iter()
155 .filter(|(channel_id, _)| selected_channel_ids.contains(channel_id))
156 .map(|(i, c)| (i.clone(), c.clone()))
157 .collect();
158
159 let all_transform_info: HashMap<TransformId, TransformInfo> = self
160 .transform_info
161 .iter()
162 .filter(|(i, _)| selected_transform_ids.contains(i))
163 .map(|(i, c)| (i.clone(), c.clone()))
164 .collect();
165
166 let reference_frame = ReferenceFrames::new(
167 all_transforms,
168 all_frame_info,
169 all_channel_info,
170 all_transform_info,
171 )?;
172 Ok(reference_frame)
173 }
174
175 pub fn get_timed_subset(&self, timestamp: &DateTime<Utc>) -> Result<ReferenceFrames, Error> {
176 let all_transforms: HashMap<(ChannelId, TransformId), Vec<Transform>> = self
177 .transforms
178 .iter()
179 .map(|((channel_id, transform_id), transforms)| {
180 let interpolation_method = self
181 .get_interpolation_method(transform_id)
182 .unwrap_or_default();
183 let isometry =
184 interpolate_transforms(transforms, &Some(*timestamp), interpolation_method);
185
186 isometry.map(|i| {
187 (
188 (channel_id.clone(), transform_id.clone()),
189 vec![Transform::from(*timestamp, i)],
190 )
191 })
192 })
193 .collect::<Result<HashMap<(ChannelId, TransformId), Vec<Transform>>, _>>()?;
194
195 let all_transform_info = self
196 .transform_info
197 .keys()
198 .map(|k| {
199 (
200 k.clone(),
201 TransformInfo::new(Some(InterpolationMethod::Step)),
202 )
203 })
204 .collect();
205
206 let reference_frame = ReferenceFrames::new(
207 all_transforms,
208 self.frame_info.clone(),
209 self.channel_info.clone(),
210 all_transform_info,
211 )?;
212 Ok(reference_frame)
213 }
214
215 pub fn set_interpolation_method(
216 &mut self,
217 transform_id: TransformId,
218 method: Option<InterpolationMethod>,
219 ) {
220 self.transform_info
221 .entry(transform_id)
222 .or_default()
223 .interpolation_method = method;
224 }
225
226 pub fn transforms(&self) -> &HashMap<(ChannelId, TransformId), Vec<Transform>> {
250 &self.transforms
251 }
252
253 pub fn get_valid_transform(
255 &self,
256 channel_id: &ChannelId,
257 transform_id: &TransformId,
258 timestamp: &Option<DateTime<Utc>>,
259 ) -> Result<Vec<&Transform>, Error> {
260 if !self.contains_channel(channel_id) {
261 return Err(InvalidChannelId(channel_id.clone()));
262 }
263
264 let all_transforms: Vec<&Transform> = self
265 .transforms
266 .get(&(channel_id.clone(), transform_id.clone()))
267 .ok_or_else(|| InvalidTransformId(channel_id.clone(), transform_id.clone()))?
268 .iter()
269 .collect();
270
271 if timestamp.is_none() {
272 return Ok(all_transforms);
273 }
274 let timestamp = timestamp.unwrap();
275
276 let mut time_based_filtered_transforms: Vec<&Transform> = all_transforms
277 .clone()
278 .windows(2)
279 .filter(|t| {
280 t[0].timestamp.timestamp_nanos() <= timestamp.timestamp_nanos()
281 && timestamp.timestamp_nanos() < t[1].timestamp.timestamp_nanos()
282 })
283 .map(|t| t[0])
289 .collect();
290
291 if all_transforms.last().unwrap().timestamp <= timestamp {
292 time_based_filtered_transforms.push(all_transforms.last().unwrap());
293 }
294
295 Ok(time_based_filtered_transforms)
296 }
297
298 pub fn get_channel_ids(&self) -> HashSet<ChannelId> {
299 self.transforms
300 .keys()
301 .map(|(channel_id, _)| channel_id.clone())
302 .collect()
303 }
304
305 pub fn get_frame_ids(&self) -> HashSet<FrameId> {
306 self.transforms
307 .keys()
308 .fold(Vec::<FrameId>::new(), |mut acc, x| {
309 acc.push(x.1.frame_id.clone());
310 acc.push(x.1.child_frame_id.clone());
311 acc
312 })
313 .into_iter()
314 .collect()
315 }
316
317 pub fn get_channel_priority(&self, channel_id: &ChannelId) -> i32 {
325 assert!(self.contains_channel(channel_id));
326 self.channel_info
327 .get(channel_id)
328 .and_then(|x| x.priority)
329 .unwrap_or(0)
330 }
331
332 pub fn contains_channel(&self, channel_id: &ChannelId) -> bool {
333 self.get_channel_ids().iter().any(|x| x == channel_id)
334 }
335
336 pub fn contains_frame(&self, frame_id: &FrameId) -> bool {
337 self.get_frame_ids().iter().any(|f| f == frame_id)
338 }
339
340 pub fn contains_transform(&self, channel_id: &ChannelId, transform_id: &TransformId) -> bool {
341 self.transforms
342 .keys()
343 .any(|(current_channel_id, current_transform_id)| {
344 current_channel_id == channel_id && current_transform_id == transform_id
345 })
346 }
347
348 pub fn add_transform(
349 &mut self,
350 channel_id: ChannelId,
351 transform_id: TransformId,
352 transforms: Vec<Transform>,
353 channel_info: Option<ChannelInfo>,
354 transform_info: Option<TransformInfo>,
355 ) -> Result<(), Error> {
356 if transforms.is_empty() {
357 return Err(MissingTransforms());
358 }
359
360 self.transforms
361 .insert((channel_id.clone(), transform_id.clone()), transforms);
362 if let Some(channel_info) = channel_info {
363 self.channel_info.insert(channel_id, channel_info);
364 }
365 if let Some(transform_info) = transform_info {
366 self.transform_info.insert(transform_id, transform_info);
367 }
368 Ok(())
369 }
370
371 pub fn get_interpolation_method(
372 &self,
373 transform_id: &TransformId,
374 ) -> Option<InterpolationMethod> {
375 self.transform_info
376 .get(transform_id)
377 .and_then(|o| o.interpolation_method)
378 }
379
380 pub fn derive_transform_graph(
385 &self,
386 selected_channel_ids: &Option<HashSet<ChannelId>>,
387 selected_timestamp: &Option<DateTime<Utc>>,
388 ) -> Result<IsometryGraph, Error> {
389 if let Some(channel_names) = &selected_channel_ids {
390 if channel_names.is_empty() {
391 return Err(NoChannels());
392 }
393 }
394
395 let mut selected_isometries: HashMap<TransformId, Isometry3<f64>> = HashMap::new();
396 let selected_transforms: HashMap<(ChannelId, TransformId), Vec<Transform>> =
402 match &selected_channel_ids {
403 Some(channel_names) => filter_by_channel(&self.transforms, channel_names),
404 None => self.transforms.clone(),
405 };
406
407 let mut prioritized_selected_transforms: HashMap<TransformId, Vec<Transform>> =
408 HashMap::new();
409 for (_, group) in &selected_transforms
410 .iter()
411 .sorted_by_key(|k| &k.0 .1)
412 .chunk_by(|k| k.0 .1.clone())
413 {
414 let highest_priority = group
416 .into_iter()
417 .max_by_key(|k| self.get_channel_priority(&k.0 .0))
418 .unwrap();
419
420 prioritized_selected_transforms
422 .insert(highest_priority.0 .1.clone(), highest_priority.1.clone());
423 }
424 for (current_transform_id, current_transforms) in prioritized_selected_transforms {
427 let interpolation_method = self
429 .get_interpolation_method(¤t_transform_id)
430 .unwrap_or_default();
431 let interpolated_transform = interpolate_transforms(
432 ¤t_transforms,
433 selected_timestamp,
434 interpolation_method,
435 )?;
436 selected_isometries.insert(current_transform_id.clone(), interpolated_transform);
437
438 }
474
475 IsometryGraph::new(selected_isometries)
476 }
477 }