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 name of the frame in which this pose is defined.
41    ///
42    /// # Returns
43    ///
44    /// `Some(String)` if the parent frame is still valid, or `None` if the frame
45    /// has been dropped or no longer exists.
46    ///
47    /// # Example
48    ///
49    /// ```
50    /// use cartesian_tree::Frame;
51    /// use nalgebra::{Vector3, UnitQuaternion};
52    ///
53    /// let frame = Frame::new_origin("base");
54    /// let pose = frame.add_pose(Vector3::new(0.0, 0.0, 0.0), UnitQuaternion::identity());
55    /// assert_eq!(pose.frame_name().as_deref(), Some("base"));
56    /// ```
57    pub fn frame_name(&self) -> Option<String> {
58        self.parent
59            .upgrade()
60            .map(|frame| frame.borrow().name.clone())
61    }
62
63    /// Returns the transformation from this pose to its parent frame.
64    ///
65    /// # Returns
66    /// The transformation of the pose in its parent frame.
67    pub fn transformation(&self) -> Isometry3<f64> {
68        self.transform_to_parent
69    }
70
71    /// Updates the pose's transformation relative to its parent.
72    ///
73    /// # Arguments
74    /// - `position`: A 3D vector representing the new translational offset from the parent.
75    /// - `orientation`: An orientation convertible into a unit quaternion for new orientational offset from the parent.
76    ///
77    /// # Example
78    /// ```
79    /// use cartesian_tree::Frame;
80    /// use nalgebra::{Vector3, UnitQuaternion};
81    ///
82    /// let root = Frame::new_origin("root");
83    /// let mut pose = root.add_pose(Vector3::new(0.0, 0.0, 1.0), UnitQuaternion::identity());
84    /// pose.update(Vector3::new(1.0, 0.0, 0.0), UnitQuaternion::identity());
85    /// ```
86    pub fn update<O>(&mut self, position: Vector3<f64>, orientation: O)
87    where
88        O: IntoOrientation,
89    {
90        self.transform_to_parent =
91            Isometry3::from_parts(Translation3::from(position), orientation.into_orientation());
92    }
93
94    /// Transforms this pose into the coordinate system of the given target frame.
95    ///
96    /// # Arguments
97    /// * `target` - The frame to express this pose in.
98    ///
99    /// # Returns
100    /// - `Ok(Pose)` a new `Pose`, expressed in the `target` frame.
101    /// - `Err(String)` if the frame hierarchy cannot be resolved (due to dropped frames or no common ancestor).
102    ///
103    /// # Example
104    /// ```
105    /// use cartesian_tree::Frame;
106    /// use nalgebra::{Vector3, UnitQuaternion};
107    ///
108    /// let root = Frame::new_origin("root");
109    /// let pose = root.add_pose(Vector3::new(0.0, 0.0, 1.0), UnitQuaternion::identity());
110    /// let new_frame = root.add_child("child", Vector3::new(1.0, 0.0, 0.0), UnitQuaternion::identity()).unwrap();
111    /// let pose_in_new_frame = pose.in_frame(&new_frame);
112    /// ```
113    pub fn in_frame(&self, target: &Frame) -> Result<Pose, CartesianTreeError> {
114        let source_data = self
115            .parent
116            .upgrade()
117            .ok_or(CartesianTreeError::WeakUpgradeFailed())?;
118        let source = Frame { data: source_data };
119        let ancestor = source
120            .lca_with(target)
121            .ok_or(CartesianTreeError::NoCommonAncestor(
122                source.name(),
123                target.name(),
124            ))?;
125
126        // Transformation from source frame up to ancestor
127        let tf_up = source.walk_up_and_transform(&ancestor)? * self.transform_to_parent;
128
129        // Transformation from target frame up to ancestor (to be inverted)
130        let tf_down = target.walk_up_and_transform(&ancestor)?;
131
132        Ok(Pose {
133            parent: target.downgrade(),
134            transform_to_parent: tf_down.inverse() * tf_up,
135        })
136    }
137}