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}