1use const_soft_float::soft_f32::SoftF32;
2use const_soft_float::soft_f64::SoftF64;
3use glam_traits_ext::{FloatAffine, FloatMat, FloatVec, TAffine3, TMat3, TVec3};
4
5#[cfg(debug_assertions)]
6use crate::DekeError;
7use crate::SRobotQ;
8
9use super::{
10 AAffine3, AMat3, AVec3, FKChain, FKScalar, check_finite, const_sin_cos, const_sin_cos_f64,
11};
12
13#[derive(Debug, Clone, Copy)]
14pub struct HPJoint<F: FKScalar = f32> {
15 pub a: F,
16 pub alpha: F,
17 pub beta: F,
18 pub d: F,
19 pub theta_offset: F,
20}
21
22#[derive(Debug, Clone)]
29pub struct HPChain<const N: usize, F: FKScalar = f32> {
30 a: [F; N],
31 d: [F; N],
32 sin_alpha: [F; N],
33 cos_alpha: [F; N],
34 sin_beta: [F; N],
35 cos_beta: [F; N],
36 theta_offset: [F; N],
37}
38
39impl<const N: usize> HPChain<N, f32> {
40 pub const fn new(joints: [HPJoint<f32>; N]) -> Self {
41 let mut a = [0.0; N];
42 let mut d = [0.0; N];
43 let mut sin_alpha = [0.0; N];
44 let mut cos_alpha = [0.0; N];
45 let mut sin_beta = [0.0; N];
46 let mut cos_beta = [0.0; N];
47 let mut theta_offset = [0.0; N];
48
49 let mut i = 0;
50 while i < N {
51 a[i] = joints[i].a;
52 d[i] = joints[i].d;
53 let (sa, ca) = const_sin_cos(joints[i].alpha);
54 sin_alpha[i] = sa;
55 cos_alpha[i] = ca;
56 let (sb, cb) = const_sin_cos(joints[i].beta);
57 sin_beta[i] = sb;
58 cos_beta[i] = cb;
59 theta_offset[i] = joints[i].theta_offset;
60 i += 1;
61 }
62
63 Self {
64 a,
65 d,
66 sin_alpha,
67 cos_alpha,
68 sin_beta,
69 cos_beta,
70 theta_offset,
71 }
72 }
73
74 pub const fn from_hp(h: &[[f32; N]; 3], p: &[[f32; N]; 3]) -> Self {
91
92 let mut a = [0.0f32; N];
93 let mut d = [0.0f32; N];
94 let mut sin_alpha = [0.0f32; N];
95 let mut cos_alpha = [0.0f32; N];
96 let mut sin_beta = [0.0f32; N];
97 let mut cos_beta = [0.0f32; N];
98
99 let mut c0 = [1.0f32, 0.0, 0.0];
100 let mut c1 = [0.0f32, 1.0, 0.0];
101 let mut c2 = [0.0f32, 0.0, 1.0];
102
103 const EPS: f32 = 1e-12;
104
105 let mut i = 0;
106 while i < N {
107 let hx = h[0][i];
108 let hy = h[1][i];
109 let hz = h[2][i];
110 let px = p[0][i];
111 let py = p[1][i];
112 let pz = p[2][i];
113
114 let vx = c0[0] * hx + c0[1] * hy + c0[2] * hz;
115 let vy = c1[0] * hx + c1[1] * hy + c1[2] * hz;
116 let vz = c2[0] * hx + c2[1] * hy + c2[2] * hz;
117 let ux = c0[0] * px + c0[1] * py + c0[2] * pz;
118 let uy = c1[0] * px + c1[1] * py + c1[2] * pz;
119 let uz = c2[0] * px + c2[1] * py + c2[2] * pz;
120
121 let sb = vx;
122 let cb = SoftF32::from_f32(vy * vy + vz * vz).sqrt().to_f32();
123
124 let (sa, ca) = if cb > EPS {
125 (-vy / cb, vz / cb)
126 } else {
127 (0.0, 1.0)
128 };
129
130 let big_a = ux;
131 let big_b = sa * uy - ca * uz;
132 let ai = cb * big_a + sb * big_b;
133 let di = sb * big_a - cb * big_b;
134
135 a[i] = ai;
136 d[i] = di;
137 sin_alpha[i] = sa;
138 cos_alpha[i] = ca;
139 sin_beta[i] = sb;
140 cos_beta[i] = cb;
141
142 let sasb = sa * sb;
143 let casb = ca * sb;
144 let sacb = sa * cb;
145 let cacb = ca * cb;
146 let new_c0 = [
147 cb * c0[0] + sasb * c1[0] - casb * c2[0],
148 cb * c0[1] + sasb * c1[1] - casb * c2[1],
149 cb * c0[2] + sasb * c1[2] - casb * c2[2],
150 ];
151 let new_c1 = [
152 ca * c1[0] + sa * c2[0],
153 ca * c1[1] + sa * c2[1],
154 ca * c1[2] + sa * c2[2],
155 ];
156 let new_c2 = [
157 sb * c0[0] - sacb * c1[0] + cacb * c2[0],
158 sb * c0[1] - sacb * c1[1] + cacb * c2[1],
159 sb * c0[2] - sacb * c1[2] + cacb * c2[2],
160 ];
161 c0 = new_c0;
162 c1 = new_c1;
163 c2 = new_c2;
164
165 i += 1;
166 }
167
168 Self {
169 a,
170 d,
171 sin_alpha,
172 cos_alpha,
173 sin_beta,
174 cos_beta,
175 theta_offset: [0.0f32; N],
176 }
177 }
178}
179
180impl<const N: usize> HPChain<N, f64> {
181 pub const fn new_f64(joints: [HPJoint<f64>; N]) -> Self {
183 let mut a = [0.0; N];
184 let mut d = [0.0; N];
185 let mut sin_alpha = [0.0; N];
186 let mut cos_alpha = [0.0; N];
187 let mut sin_beta = [0.0; N];
188 let mut cos_beta = [0.0; N];
189 let mut theta_offset = [0.0; N];
190
191 let mut i = 0;
192 while i < N {
193 a[i] = joints[i].a;
194 d[i] = joints[i].d;
195 let (sa, ca) = const_sin_cos_f64(joints[i].alpha);
196 sin_alpha[i] = sa;
197 cos_alpha[i] = ca;
198 let (sb, cb) = const_sin_cos_f64(joints[i].beta);
199 sin_beta[i] = sb;
200 cos_beta[i] = cb;
201 theta_offset[i] = joints[i].theta_offset;
202 i += 1;
203 }
204
205 Self {
206 a,
207 d,
208 sin_alpha,
209 cos_alpha,
210 sin_beta,
211 cos_beta,
212 theta_offset,
213 }
214 }
215
216 pub const fn from_hp_f64(h: &[[f64; N]; 3], p: &[[f64; N]; 3]) -> Self {
218 let mut a = [0.0f64; N];
219 let mut d = [0.0f64; N];
220 let mut sin_alpha = [0.0f64; N];
221 let mut cos_alpha = [0.0f64; N];
222 let mut sin_beta = [0.0f64; N];
223 let mut cos_beta = [0.0f64; N];
224
225 let mut c0 = [1.0f64, 0.0, 0.0];
226 let mut c1 = [0.0f64, 1.0, 0.0];
227 let mut c2 = [0.0f64, 0.0, 1.0];
228
229 const EPS: f64 = 1e-15;
230
231 let mut i = 0;
232 while i < N {
233 let hx = h[0][i];
234 let hy = h[1][i];
235 let hz = h[2][i];
236 let px = p[0][i];
237 let py = p[1][i];
238 let pz = p[2][i];
239
240 let vx = c0[0] * hx + c0[1] * hy + c0[2] * hz;
241 let vy = c1[0] * hx + c1[1] * hy + c1[2] * hz;
242 let vz = c2[0] * hx + c2[1] * hy + c2[2] * hz;
243 let ux = c0[0] * px + c0[1] * py + c0[2] * pz;
244 let uy = c1[0] * px + c1[1] * py + c1[2] * pz;
245 let uz = c2[0] * px + c2[1] * py + c2[2] * pz;
246
247 let sb = vx;
248 let cb = SoftF64::from_f64(vy * vy + vz * vz).sqrt().to_f64();
249
250 let (sa, ca) = if cb > EPS {
251 (-vy / cb, vz / cb)
252 } else {
253 (0.0, 1.0)
254 };
255
256 let big_a = ux;
257 let big_b = sa * uy - ca * uz;
258 let ai = cb * big_a + sb * big_b;
259 let di = sb * big_a - cb * big_b;
260
261 a[i] = ai;
262 d[i] = di;
263 sin_alpha[i] = sa;
264 cos_alpha[i] = ca;
265 sin_beta[i] = sb;
266 cos_beta[i] = cb;
267
268 let sasb = sa * sb;
269 let casb = ca * sb;
270 let sacb = sa * cb;
271 let cacb = ca * cb;
272 let new_c0 = [
273 cb * c0[0] + sasb * c1[0] - casb * c2[0],
274 cb * c0[1] + sasb * c1[1] - casb * c2[1],
275 cb * c0[2] + sasb * c1[2] - casb * c2[2],
276 ];
277 let new_c1 = [
278 ca * c1[0] + sa * c2[0],
279 ca * c1[1] + sa * c2[1],
280 ca * c1[2] + sa * c2[2],
281 ];
282 let new_c2 = [
283 sb * c0[0] - sacb * c1[0] + cacb * c2[0],
284 sb * c0[1] - sacb * c1[1] + cacb * c2[1],
285 sb * c0[2] - sacb * c1[2] + cacb * c2[2],
286 ];
287 c0 = new_c0;
288 c1 = new_c1;
289 c2 = new_c2;
290
291 i += 1;
292 }
293
294 Self {
295 a,
296 d,
297 sin_alpha,
298 cos_alpha,
299 sin_beta,
300 cos_beta,
301 theta_offset: [0.0f64; N],
302 }
303 }
304}
305
306impl<const N: usize, F: FKScalar> HPChain<N, F> {
307 pub fn from_joints(joints: [HPJoint<F>; N]) -> Self {
311 let zero = F::zero();
312 let mut a = [zero; N];
313 let mut d = [zero; N];
314 let mut sin_alpha = [zero; N];
315 let mut cos_alpha = [zero; N];
316 let mut sin_beta = [zero; N];
317 let mut cos_beta = [zero; N];
318 let mut theta_offset = [zero; N];
319
320 for i in 0..N {
321 a[i] = joints[i].a;
322 d[i] = joints[i].d;
323 let (sa, ca) = joints[i].alpha.sin_cos();
324 sin_alpha[i] = sa;
325 cos_alpha[i] = ca;
326 let (sb, cb) = joints[i].beta.sin_cos();
327 sin_beta[i] = sb;
328 cos_beta[i] = cb;
329 theta_offset[i] = joints[i].theta_offset;
330 }
331
332 Self {
333 a,
334 d,
335 sin_alpha,
336 cos_alpha,
337 sin_beta,
338 cos_beta,
339 theta_offset,
340 }
341 }
342
343 #[inline(always)]
356 fn local_frame(&self, i: usize, st: F, ct: F) -> (AVec3<F>, AVec3<F>, AVec3<F>, AVec3<F>) {
357 let sa = self.sin_alpha[i];
358 let ca = self.cos_alpha[i];
359 let sb = self.sin_beta[i];
360 let cb = self.cos_beta[i];
361 let ai = self.a[i];
362 let di = self.d[i];
363
364 let sa_sb = sa * sb;
365 let sa_cb = sa * cb;
366 let ca_sb = ca * sb;
367 let ca_cb = ca * cb;
368
369 let c0 = AVec3::<F>::new(ct * cb - st * sa_sb, st * cb + ct * sa_sb, -ca_sb);
370 let c1 = AVec3::<F>::new(-st * ca, ct * ca, sa);
371 let c2 = AVec3::<F>::new(ct * sb + st * sa_cb, st * sb - ct * sa_cb, ca_cb);
372 let t = c0 * ai + c2 * di;
373
374 (c0, c1, c2, t)
375 }
376}
377
378#[inline(always)]
380fn accumulate<F: FKScalar>(
381 acc_m: &mut AMat3<F>,
382 acc_t: &mut AVec3<F>,
383 local_c0: AVec3<F>,
384 local_c1: AVec3<F>,
385 local_c2: AVec3<F>,
386 local_t: AVec3<F>,
387) {
388 let new_c0 = *acc_m * local_c0;
389 let new_c1 = *acc_m * local_c1;
390 let new_c2 = *acc_m * local_c2;
391 *acc_t = *acc_m * local_t + *acc_t;
392 *acc_m = AMat3::<F>::from_cols(new_c0, new_c1, new_c2);
393}
394
395impl<const N: usize, F: FKScalar> FKChain<N, F> for HPChain<N, F> {
396 #[cfg(debug_assertions)]
397 type Error = DekeError;
398 #[cfg(not(debug_assertions))]
399 type Error = std::convert::Infallible;
400
401 fn fk(&self, q: &SRobotQ<N, F>) -> Result<[AAffine3<F>; N], Self::Error> {
402 check_finite::<N, F>(q)?;
403 let mut out = [AAffine3::<F>::IDENTITY; N];
404 let mut acc_m = AMat3::<F>::IDENTITY;
405 let mut acc_t = AVec3::<F>::ZERO;
406
407 let mut i = 0;
408 while i < N {
409 let (st, ct) = (q.0[i] + self.theta_offset[i]).sin_cos();
410 let (c0, c1, c2, t) = self.local_frame(i, st, ct);
411 accumulate::<F>(&mut acc_m, &mut acc_t, c0, c1, c2, t);
412
413 out[i] = AAffine3::<F>::from_mat3_translation(acc_m, acc_t);
414 i += 1;
415 }
416 Ok(out)
417 }
418
419 fn fk_end(&self, q: &SRobotQ<N, F>) -> Result<AAffine3<F>, Self::Error> {
420 check_finite::<N, F>(q)?;
421 let mut acc_m = AMat3::<F>::IDENTITY;
422 let mut acc_t = AVec3::<F>::ZERO;
423
424 let mut i = 0;
425 while i < N {
426 let (st, ct) = (q.0[i] + self.theta_offset[i]).sin_cos();
427 let (c0, c1, c2, t) = self.local_frame(i, st, ct);
428 accumulate::<F>(&mut acc_m, &mut acc_t, c0, c1, c2, t);
429 i += 1;
430 }
431
432 Ok(AAffine3::<F>::from_mat3_translation(acc_m, acc_t))
433 }
434
435 fn all_fk(
436 &self,
437 q: &SRobotQ<N, F>,
438 ) -> Result<(AAffine3<F>, [AAffine3<F>; N], AAffine3<F>), Self::Error> {
439 let frames = self.fk(q)?;
440 let end = if N > 0 {
443 frames[N - 1]
444 } else {
445 AAffine3::<F>::IDENTITY
446 };
447 Ok((self.base_tf(), frames, end))
448 }
449
450 fn joint_axes_positions(
451 &self,
452 q: &SRobotQ<N, F>,
453 ) -> Result<([AVec3<F>; N], [AVec3<F>; N], AVec3<F>), Self::Error> {
454 let frames = self.fk(q)?;
455 let mut axes = [AVec3::<F>::Z; N];
456 let mut positions = [AVec3::<F>::ZERO; N];
457
458 for i in 1..N {
459 axes[i] = frames[i - 1].matrix3().z_axis();
460 positions[i] = frames[i - 1].translation();
461 }
462
463 Ok((axes, positions, frames[N - 1].translation()))
464 }
465}
466
467impl From<HPJoint<f32>> for HPJoint<f64> {
468 #[inline]
469 fn from(j: HPJoint<f32>) -> Self {
470 HPJoint {
471 a: j.a as f64,
472 alpha: j.alpha as f64,
473 beta: j.beta as f64,
474 d: j.d as f64,
475 theta_offset: j.theta_offset as f64,
476 }
477 }
478}
479
480impl From<HPJoint<f64>> for HPJoint<f32> {
481 #[inline]
482 fn from(j: HPJoint<f64>) -> Self {
483 HPJoint {
484 a: j.a as f32,
485 alpha: j.alpha as f32,
486 beta: j.beta as f32,
487 d: j.d as f32,
488 theta_offset: j.theta_offset as f32,
489 }
490 }
491}
492
493#[inline]
494fn cast_arr<const N: usize, A: Copy, B: Copy>(src: [A; N], cast: impl Fn(A) -> B) -> [B; N] {
495 std::array::from_fn(|i| cast(src[i]))
496}
497
498impl<const N: usize> From<HPChain<N, f32>> for HPChain<N, f64> {
499 #[inline]
500 fn from(c: HPChain<N, f32>) -> Self {
501 HPChain::<N, f64> {
502 a: cast_arr(c.a, |x| x as f64),
503 d: cast_arr(c.d, |x| x as f64),
504 sin_alpha: cast_arr(c.sin_alpha, |x| x as f64),
505 cos_alpha: cast_arr(c.cos_alpha, |x| x as f64),
506 sin_beta: cast_arr(c.sin_beta, |x| x as f64),
507 cos_beta: cast_arr(c.cos_beta, |x| x as f64),
508 theta_offset: cast_arr(c.theta_offset, |x| x as f64),
509 }
510 }
511}
512
513impl<const N: usize> From<HPChain<N, f64>> for HPChain<N, f32> {
514 #[inline]
515 fn from(c: HPChain<N, f64>) -> Self {
516 HPChain::<N, f32> {
517 a: cast_arr(c.a, |x| x as f32),
518 d: cast_arr(c.d, |x| x as f32),
519 sin_alpha: cast_arr(c.sin_alpha, |x| x as f32),
520 cos_alpha: cast_arr(c.cos_alpha, |x| x as f32),
521 sin_beta: cast_arr(c.sin_beta, |x| x as f32),
522 cos_beta: cast_arr(c.cos_beta, |x| x as f32),
523 theta_offset: cast_arr(c.theta_offset, |x| x as f32),
524 }
525 }
526}