1use glam_traits_ext::{FloatVec, TAffine3};
2
3use crate::SRobotQ;
4
5use super::{AAffine3, AVec3, FKChain, FKScalar, URDFBuildError, URDFJoint, compose_fixed_joints};
6
7#[derive(Debug, Clone)]
14pub struct TransformedFK<const N: usize, F: FKScalar, FK: FKChain<N, F>> {
15 inner: FK,
16 prefix: Option<AAffine3<F>>,
17 suffix: Option<AAffine3<F>>,
18}
19
20impl<const N: usize, F: FKScalar, FK: FKChain<N, F>> TransformedFK<N, F, FK> {
21 pub const fn new(inner: FK) -> Self {
22 Self {
23 inner,
24 prefix: None,
25 suffix: None,
26 }
27 }
28
29 pub fn with_prefix(mut self, prefix: AAffine3<F>) -> Self {
30 self.prefix = Some(prefix);
31 self
32 }
33
34 pub fn with_suffix(mut self, suffix: AAffine3<F>) -> Self {
35 self.suffix = Some(suffix);
36 self
37 }
38
39 pub fn with_prefix_opt(mut self, prefix: Option<AAffine3<F>>) -> Self {
41 self.prefix = prefix;
42 self
43 }
44
45 pub fn with_suffix_opt(mut self, suffix: Option<AAffine3<F>>) -> Self {
47 self.suffix = suffix;
48 self
49 }
50
51 pub fn set_prefix(&mut self, prefix: Option<AAffine3<F>>) {
52 self.prefix = prefix;
53 }
54
55 pub fn set_suffix(&mut self, suffix: Option<AAffine3<F>>) {
56 self.suffix = suffix;
57 }
58
59 pub fn prefix(&self) -> Option<&AAffine3<F>> {
60 self.prefix.as_ref()
61 }
62
63 pub fn suffix(&self) -> Option<&AAffine3<F>> {
64 self.suffix.as_ref()
65 }
66
67 pub fn inner(&self) -> &FK {
68 &self.inner
69 }
70}
71
72impl<const N: usize, FK: FKChain<N, f32>> TransformedFK<N, f32, FK> {
73 pub fn with_prefix_joints(mut self, joints: &[URDFJoint]) -> Result<Self, URDFBuildError> {
78 if joints.is_empty() {
79 self.prefix = None;
80 Ok(self)
81 } else {
82 self.prefix = Some(compose_fixed_joints(joints)?);
83 Ok(self)
84 }
85 }
86
87 pub fn with_suffix_joints(mut self, joints: &[URDFJoint]) -> Result<Self, URDFBuildError> {
92 if joints.is_empty() {
93 self.suffix = None;
94 Ok(self)
95 } else {
96 self.suffix = Some(compose_fixed_joints(joints)?);
97 Ok(self)
98 }
99 }
100}
101
102impl<const N: usize, F: FKScalar, FK: FKChain<N, F>> FKChain<N, F> for TransformedFK<N, F, FK> {
103 type Error = FK::Error;
104
105 fn base_tf(&self) -> AAffine3<F> {
106 match &self.prefix {
107 Some(p) => *p * self.inner.base_tf(),
108 None => self.inner.base_tf(),
109 }
110 }
111
112 fn max_reach(&self) -> Result<F, Self::Error> {
113 let mut reach = self.inner.max_reach()?;
114 if let Some(suf) = &self.suffix {
115 reach = reach + suf.translation().length();
116 }
117 Ok(reach)
118 }
119
120 fn fk(&self, q: &SRobotQ<N, F>) -> Result<[AAffine3<F>; N], Self::Error> {
121 let mut frames = self.inner.fk(q)?;
122 if let Some(pre) = &self.prefix {
123 for f in &mut frames {
124 *f = *pre * *f;
125 }
126 }
127 Ok(frames)
128 }
129
130 fn fk_end(&self, q: &SRobotQ<N, F>) -> Result<AAffine3<F>, Self::Error> {
131 let mut end = self.inner.fk_end(q)?;
132 if let Some(pre) = &self.prefix {
133 end = *pre * end;
134 }
135 if let Some(suf) = &self.suffix {
136 end = end * *suf;
137 }
138 Ok(end)
139 }
140
141 fn joint_axes_positions(
142 &self,
143 q: &SRobotQ<N, F>,
144 ) -> Result<([AVec3<F>; N], [AVec3<F>; N], AVec3<F>), Self::Error> {
145 let (mut axes, mut positions, inner_p_ee) = self.inner.joint_axes_positions(q)?;
146
147 if let Some(pre) = &self.prefix {
148 let rot = pre.matrix3();
149 let t = pre.translation();
150 for i in 0..N {
151 axes[i] = rot * axes[i];
152 positions[i] = rot * positions[i] + t;
153 }
154 }
155
156 let p_ee = if self.prefix.is_some() || self.suffix.is_some() {
157 self.fk_end(q)?.translation()
158 } else {
159 inner_p_ee
160 };
161
162 Ok((axes, positions, p_ee))
163 }
164}
165
166impl<const N: usize, FK32, FK64> From<TransformedFK<N, f32, FK32>> for TransformedFK<N, f64, FK64>
167where
168 FK32: FKChain<N, f32>,
169 FK64: FKChain<N, f64> + From<FK32>,
170{
171 #[inline]
172 fn from(t: TransformedFK<N, f32, FK32>) -> Self {
173 TransformedFK {
174 inner: FK64::from(t.inner),
175 prefix: t.prefix.map(|p| glam::DAffine3 {
176 matrix3: p.matrix3.as_dmat3(),
177 translation: p.translation.as_dvec3(),
178 }),
179 suffix: t.suffix.map(|p| glam::DAffine3 {
180 matrix3: p.matrix3.as_dmat3(),
181 translation: p.translation.as_dvec3(),
182 }),
183 }
184 }
185}
186
187impl<const N: usize, FK64, FK32> From<TransformedFK<N, f64, FK64>> for TransformedFK<N, f32, FK32>
188where
189 FK64: FKChain<N, f64>,
190 FK32: FKChain<N, f32> + From<FK64>,
191{
192 #[inline]
193 fn from(t: TransformedFK<N, f64, FK64>) -> Self {
194 TransformedFK {
195 inner: FK32::from(t.inner),
196 prefix: t.prefix.map(|p| glam::Affine3A {
197 matrix3: glam::Mat3A::from(p.matrix3.as_mat3()),
198 translation: p.translation.as_vec3a(),
199 }),
200 suffix: t.suffix.map(|p| glam::Affine3A {
201 matrix3: glam::Mat3A::from(p.matrix3.as_mat3()),
202 translation: p.translation.as_vec3a(),
203 }),
204 }
205 }
206}