1use crate::CartesianTreeError;
2use crate::Pose;
3use crate::orientation::IntoOrientation;
4use crate::tree::{HasChildren, HasParent, NodeEquality};
5
6use nalgebra::{Isometry3, Translation3, Vector3};
7use std::cell::RefCell;
8use std::rc::{Rc, Weak};
9
10#[derive(Clone, Debug)]
17pub struct Frame {
18 pub(crate) data: Rc<RefCell<FrameData>>,
19}
20
21#[derive(Debug)]
22pub(crate) struct FrameData {
23 pub(crate) name: String,
25 parent: Option<Weak<RefCell<FrameData>>>,
27 transform_to_parent: Isometry3<f64>,
29 children: Vec<Frame>,
31}
32
33impl Frame {
34 pub fn new_origin(name: impl Into<String>) -> Self {
47 Frame {
48 data: Rc::new(RefCell::new(FrameData {
49 name: name.into(),
50 parent: None,
51 children: Vec::new(),
52 transform_to_parent: Isometry3::identity(),
53 })),
54 }
55 }
56
57 pub(crate) fn borrow(&self) -> std::cell::Ref<FrameData> {
58 self.data.borrow()
59 }
60
61 fn borrow_mut(&self) -> std::cell::RefMut<FrameData> {
62 self.data.borrow_mut()
63 }
64
65 pub(crate) fn downgrade(&self) -> Weak<RefCell<FrameData>> {
66 Rc::downgrade(&self.data)
67 }
68
69 pub(crate) fn walk_up_and_transform(
70 &self,
71 target: &Frame,
72 ) -> Result<Isometry3<f64>, CartesianTreeError> {
73 let mut transform = Isometry3::identity();
74 let mut current = self.clone();
75
76 while !current.is_same(target) {
77 let transform_to_its_parent = {
78 let current_data = current.borrow();
80
81 if current_data.parent.is_none() {
83 return Err(CartesianTreeError::IsNoAncestor(target.name(), self.name()));
84 }
85 current_data.transform_to_parent
86 };
87
88 transform = transform_to_its_parent * transform;
89
90 let parent_frame_opt = current.parent();
91 current = parent_frame_opt
92 .ok_or_else(|| CartesianTreeError::IsNoAncestor(target.name(), self.name()))?;
93 }
94
95 Ok(transform)
96 }
97
98 pub fn name(&self) -> String {
100 self.borrow().name.clone()
101 }
102
103 pub fn transform_to_parent(&self) -> Result<Isometry3<f64>, CartesianTreeError> {
109 if self.parent().is_none() {
110 return Err(CartesianTreeError::RootHasNoParent(self.name()));
111 }
112 Ok(self.borrow().transform_to_parent)
113 }
114
115 pub fn update_transform<O>(
141 &self,
142 position: Vector3<f64>,
143 orientation: O,
144 ) -> Result<(), CartesianTreeError>
145 where
146 O: IntoOrientation,
147 {
148 if self.parent().is_none() {
149 return Err(CartesianTreeError::CannotUpdateRootTransform(self.name()));
150 }
151 self.borrow_mut().transform_to_parent =
152 Isometry3::from_parts(Translation3::from(position), orientation.into_orientation());
153 Ok(())
154 }
155
156 pub fn add_child<O>(
182 &self,
183 name: impl Into<String>,
184 position: Vector3<f64>,
185 orientation: O,
186 ) -> Result<Frame, CartesianTreeError>
187 where
188 O: IntoOrientation,
189 {
190 let child_name = name.into();
191 {
192 let frame = self.borrow();
193 if frame
194 .children
195 .iter()
196 .any(|child| child.borrow().name == child_name)
197 {
198 return Err(CartesianTreeError::ChildNameConflict(
199 child_name,
200 self.name(),
201 ));
202 }
203 }
204 let quat = orientation.into_orientation();
205 let transform = Isometry3::from_parts(Translation3::from(position), quat);
206
207 let child = Frame {
208 data: Rc::new(RefCell::new(FrameData {
209 name: child_name,
210 parent: Some(Rc::downgrade(&self.data)),
211 children: Vec::new(),
212 transform_to_parent: transform,
213 })),
214 };
215
216 self.borrow_mut().children.push(child.clone());
217 Ok(child)
218 }
219
220 pub fn add_pose<O>(&self, position: Vector3<f64>, orientation: O) -> Pose
238 where
239 O: IntoOrientation,
240 {
241 Pose::new(self.downgrade(), position, orientation)
242 }
243}
244
245impl HasParent for Frame {
246 type Node = Frame;
247
248 fn parent(&self) -> Option<Self::Node> {
249 self.borrow()
250 .parent
251 .clone()
252 .and_then(|data_weak| data_weak.upgrade().map(|data_rc| Frame { data: data_rc }))
253 }
254}
255
256impl NodeEquality for Frame {
257 fn is_same(&self, other: &Self) -> bool {
258 Rc::ptr_eq(&self.data, &other.data)
259 }
260}
261
262impl HasChildren for Frame {
263 type Node = Frame;
264 fn children(&self) -> Vec<Frame> {
265 self.borrow().children.clone()
266 }
267}
268
269#[cfg(test)]
270mod tests {
271 use super::*;
272 use nalgebra::{UnitQuaternion, Vector3};
273
274 #[test]
275 fn create_origin_frame() {
276 let root = Frame::new_origin("world");
277 let root_borrow = root.borrow();
278 assert_eq!(root_borrow.name, "world");
279 assert!(root_borrow.parent.is_none());
280 assert_eq!(root_borrow.children.len(), 0);
281 }
282
283 #[test]
284 fn add_child_frame_with_quaternion() {
285 let root = Frame::new_origin("world");
286 let child = root
287 .add_child(
288 "dummy",
289 Vector3::new(1.0, 0.0, 0.0),
290 UnitQuaternion::identity(),
291 )
292 .unwrap();
293
294 let root_borrow = root.borrow();
295 assert_eq!(root_borrow.children.len(), 1);
296
297 let child_borrow = child.borrow();
298 assert_eq!(child_borrow.name, "dummy");
299 assert!(child_borrow.parent.is_some());
300
301 let parent_name = child_borrow
302 .parent
303 .as_ref()
304 .unwrap()
305 .upgrade()
306 .unwrap()
307 .borrow()
308 .name
309 .clone();
310 assert_eq!(parent_name, "world");
311 }
312
313 #[test]
314 fn add_child_frame_with_rpy() {
315 let root = Frame::new_origin("world");
316 let child = root
317 .add_child(
318 "dummy",
319 Vector3::new(0.0, 1.0, 0.0),
320 (0.0, 0.0, std::f64::consts::FRAC_PI_2),
321 )
322 .unwrap();
323
324 let child_borrow = child.borrow();
325 assert_eq!(child_borrow.name, "dummy");
326
327 let rotation = child_borrow.transform_to_parent.rotation;
328 let expected = UnitQuaternion::from_euler_angles(0.0, 0.0, std::f64::consts::FRAC_PI_2);
329 assert!((rotation.angle() - expected.angle()).abs() < 1e-10);
330 }
331
332 #[test]
333 fn multiple_child_frames() {
334 let root = Frame::new_origin("world");
335
336 let a = root
337 .add_child("a", Vector3::new(1.0, 0.0, 0.0), UnitQuaternion::identity())
338 .unwrap();
339 let b = root
340 .add_child("b", Vector3::new(0.0, 1.0, 0.0), UnitQuaternion::identity())
341 .unwrap();
342
343 let root_borrow = root.borrow();
344 assert_eq!(root_borrow.children.len(), 2);
345
346 let a_borrow = a.borrow();
347 let b_borrow = b.borrow();
348
349 assert_eq!(
350 a_borrow
351 .parent
352 .as_ref()
353 .unwrap()
354 .upgrade()
355 .unwrap()
356 .borrow()
357 .name,
358 "world"
359 );
360 assert_eq!(
361 b_borrow
362 .parent
363 .as_ref()
364 .unwrap()
365 .upgrade()
366 .unwrap()
367 .borrow()
368 .name,
369 "world"
370 );
371 }
372
373 #[test]
374 fn reject_duplicate_child_name() {
375 let root = Frame::new_origin("world");
376
377 let _ = root
378 .add_child(
379 "duplicate",
380 Vector3::new(1.0, 0.0, 0.0),
381 UnitQuaternion::identity(),
382 )
383 .unwrap();
384
385 let result = root.add_child(
386 "duplicate",
387 Vector3::new(2.0, 0.0, 0.0),
388 UnitQuaternion::identity(),
389 );
390 assert!(result.is_err());
391 }
392
393 #[test]
394 #[should_panic(expected = "already borrowed")]
395 fn test_borrow_conflict() {
396 let frame = Frame::new_origin("root");
397 let _borrow = frame.borrow(); frame.borrow_mut(); }
400
401 #[test]
402 fn test_add_pose_to_frame() {
403 let frame = Frame::new_origin("dummy");
404 let pose = frame.add_pose(Vector3::new(1.0, 2.0, 3.0), UnitQuaternion::identity());
405
406 assert_eq!(pose.frame_name().as_deref(), Some("dummy"));
407 }
408
409 #[test]
410 fn test_update_transform() {
411 let root = Frame::new_origin("root");
412 let child = root
413 .add_child(
414 "dummy",
415 Vector3::new(0.0, 0.0, 1.0),
416 UnitQuaternion::identity(),
417 )
418 .unwrap();
419 child
420 .update_transform(Vector3::new(1.0, 0.0, 0.0), UnitQuaternion::identity())
421 .unwrap();
422 assert_eq!(
423 child.transform_to_parent().unwrap().translation.vector,
424 Vector3::new(1.0, 0.0, 0.0)
425 );
426
427 assert!(
429 root.update_transform(Vector3::new(1.0, 0.0, 0.0), UnitQuaternion::identity())
430 .is_err()
431 );
432 }
433
434 #[test]
435 fn test_pose_transformation_between_frames() {
436 let root = Frame::new_origin("root");
437
438 let f1 = root
439 .add_child(
440 "f1",
441 Vector3::new(1.0, 0.0, 0.0),
442 UnitQuaternion::identity(),
443 )
444 .unwrap();
445
446 let f2 = f1
447 .add_child(
448 "f2",
449 Vector3::new(0.0, 2.0, 0.0),
450 UnitQuaternion::identity(),
451 )
452 .unwrap();
453
454 let pose_in_f2 = f2.add_pose(Vector3::new(1.0, 1.0, 0.0), UnitQuaternion::identity());
455
456 let pose_in_root = pose_in_f2.in_frame(&root).unwrap();
457 let pos = pose_in_root.transformation().translation.vector;
458
459 assert!((pos - Vector3::new(2.0, 3.0, 0.0)).norm() < 1e-6);
461 }
462}