cartesian_tree/
pose.rs

1use crate::CartesianTreeError;
2use crate::frame::{Frame, FrameData};
3use crate::orientation::IntoOrientation;
4use crate::tree::Walking;
5use nalgebra::{Isometry3, Translation3, Vector3};
6use std::cell::RefCell;
7use std::rc::Weak;
8
9/// Use [`Frame::add_pose`] to create a new pose.
10#[derive(Clone, Debug)]
11pub struct Pose {
12    /// Reference to the parent frame.
13    parent: Weak<RefCell<FrameData>>,
14    /// Transformation from this frame to its parent frame.
15    transform_to_parent: Isometry3<f64>,
16}
17
18impl Pose {
19    /// Creates a new pose relative to a frame.
20    ///
21    /// This function is intended for internal use. To create a pose associated with a frame,
22    /// use [`Frame::add_pose`], which handles the association safely.
23    pub(crate) fn new<O>(
24        frame: Weak<RefCell<FrameData>>,
25        position: Vector3<f64>,
26        orientation: O,
27    ) -> Pose
28    where
29        O: IntoOrientation,
30    {
31        Pose {
32            parent: frame,
33            transform_to_parent: Isometry3::from_parts(
34                Translation3::from(position),
35                orientation.into_orientation(),
36            ),
37        }
38    }
39
40    /// Returns the parent frame of this pose.
41    ///
42    /// # Returns
43    /// `Some(Frame)` if the parent frame is still valid, or `None` if the frame
44    /// has been dropped or no longer exists.
45    ///
46    /// # Example
47    /// ```
48    /// use cartesian_tree::Frame;
49    /// use nalgebra::{Vector3, UnitQuaternion};
50    ///
51    /// let frame = Frame::new_origin("base");
52    /// let pose = frame.add_pose(Vector3::new(0.0, 0.0, 0.0), UnitQuaternion::identity());
53    /// assert_eq!(pose.frame().unwrap().name(), "base");
54    /// ```
55    pub fn frame(&self) -> Option<Frame> {
56        self.parent.upgrade().map(|data| Frame { data })
57    }
58
59    /// Returns the transformation from this pose to its parent frame.
60    ///
61    /// # Returns
62    /// The transformation of the pose in its parent frame.
63    pub fn transformation(&self) -> Isometry3<f64> {
64        self.transform_to_parent
65    }
66
67    /// Updates the pose's transformation relative to its parent.
68    ///
69    /// # Arguments
70    /// - `position`: A 3D vector representing the new translational offset from the parent.
71    /// - `orientation`: An orientation convertible into a unit quaternion for new orientational offset from the parent.
72    ///
73    /// # Example
74    /// ```
75    /// use cartesian_tree::Frame;
76    /// use nalgebra::{Vector3, UnitQuaternion};
77    ///
78    /// let root = Frame::new_origin("root");
79    /// let mut pose = root.add_pose(Vector3::new(0.0, 0.0, 1.0), UnitQuaternion::identity());
80    /// pose.update(Vector3::new(1.0, 0.0, 0.0), UnitQuaternion::identity());
81    /// ```
82    pub fn update<O>(&mut self, position: Vector3<f64>, orientation: O)
83    where
84        O: IntoOrientation,
85    {
86        self.transform_to_parent =
87            Isometry3::from_parts(Translation3::from(position), orientation.into_orientation());
88    }
89
90    /// Transforms this pose into the coordinate system of the given target frame.
91    ///
92    /// # Arguments
93    /// * `target` - The frame to express this pose in.
94    ///
95    /// # Returns
96    /// - `Ok(Pose)` a new `Pose`, expressed in the `target` frame.
97    /// - `Err(String)` if the frame hierarchy cannot be resolved (due to dropped frames or no common ancestor).
98    ///
99    /// # Example
100    /// ```
101    /// use cartesian_tree::Frame;
102    /// use nalgebra::{Vector3, UnitQuaternion};
103    ///
104    /// let root = Frame::new_origin("root");
105    /// let pose = root.add_pose(Vector3::new(0.0, 0.0, 1.0), UnitQuaternion::identity());
106    /// let new_frame = root.add_child("child", Vector3::new(1.0, 0.0, 0.0), UnitQuaternion::identity()).unwrap();
107    /// let pose_in_new_frame = pose.in_frame(&new_frame);
108    /// ```
109    pub fn in_frame(&self, target: &Frame) -> Result<Pose, CartesianTreeError> {
110        let source_data = self
111            .parent
112            .upgrade()
113            .ok_or(CartesianTreeError::WeakUpgradeFailed())?;
114        let source = Frame { data: source_data };
115        let ancestor = source
116            .lca_with(target)
117            .ok_or(CartesianTreeError::NoCommonAncestor(
118                source.name(),
119                target.name(),
120            ))?;
121
122        // Transformation from source frame up to ancestor
123        let tf_up = source.walk_up_and_transform(&ancestor)? * self.transform_to_parent;
124
125        // Transformation from target frame up to ancestor (to be inverted)
126        let tf_down = target.walk_up_and_transform(&ancestor)?;
127
128        Ok(Pose {
129            parent: target.downgrade(),
130            transform_to_parent: tf_down.inverse() * tf_up,
131        })
132    }
133}