1use crate::error::{SpatialError, SpatialResult};
7use crate::transform::{Rotation, Slerp};
8use scirs2_core::ndarray::{array, Array1};
9use scirs2_core::numeric::{Float, FromPrimitive};
10
11#[inline(always)]
13fn const_f64<F: Float + FromPrimitive>(value: f64) -> F {
14 F::from(value).expect("Failed to convert constant to target float type")
15}
16
17#[allow(dead_code)]
19fn euler_array(x: f64, y: f64, z: f64) -> Array1<f64> {
20 array![x, y, z]
21}
22
23#[allow(dead_code)]
25fn rotation_from_euler(x: f64, y: f64, z: f64, convention: &str) -> SpatialResult<Rotation> {
26 let angles = euler_array(x, y, z);
27 let angles_view = angles.view();
28 Rotation::from_euler(&angles_view, convention)
29}
30
31#[derive(Clone, Debug)]
65pub struct RotationSpline {
66 rotations: Vec<Rotation>,
68 times: Vec<f64>,
70 velocities: Option<Vec<Array1<f64>>>,
72 interpolation_type: String,
74}
75
76impl RotationSpline {
77 pub fn new(rotations: &[Rotation], times: &[f64]) -> SpatialResult<Self> {
104 if rotations.is_empty() {
105 return Err(SpatialError::ValueError("Rotations cannot be empty".into()));
106 }
107
108 if times.is_empty() {
109 return Err(SpatialError::ValueError("Times cannot be empty".into()));
110 }
111
112 if rotations.len() != times.len() {
113 return Err(SpatialError::ValueError(format!(
114 "Number of _rotations ({}) must match number of times ({})",
115 rotations.len(),
116 times.len()
117 )));
118 }
119
120 for i in 1..times.len() {
122 if times[i] <= times[i - 1] {
123 return Err(SpatialError::ValueError(format!(
124 "Times must be strictly increasing, but times[{}] = {} <= times[{}] = {}",
125 i,
126 times[i],
127 i - 1,
128 times[i - 1]
129 )));
130 }
131 }
132
133 let rotations = rotations.to_vec();
135 let times = times.to_vec();
136
137 Ok(RotationSpline {
138 rotations,
139 times,
140 velocities: None,
141 interpolation_type: "slerp".to_string(),
142 })
143 }
144
145 pub fn set_interpolation_type(&mut self, _interptype: &str) -> SpatialResult<()> {
174 match _interptype.to_lowercase().as_str() {
175 "slerp" => {
176 self.interpolation_type = "slerp".to_string();
177 self.velocities = None;
178 Ok(())
179 }
180 "cubic" => {
181 self.interpolation_type = "cubic".to_string();
182 self.compute_velocities();
184 Ok(())
185 }
186 _ => Err(SpatialError::ValueError(format!(
187 "Invalid interpolation _type: {_interptype}. Must be 'slerp' or 'cubic'"
188 ))),
189 }
190 }
191
192 fn compute_velocities(&mut self) {
194 if self.velocities.is_some() {
195 return; }
197
198 let n = self.times.len();
199 if n <= 2 {
200 let mut vels = Vec::with_capacity(n);
202 for _ in 0..n {
203 vels.push(Array1::zeros(3));
204 }
205 self.velocities = Some(vels);
206 return;
207 }
208
209 let mut rotvecs = Vec::with_capacity(n);
211 for rot in &self.rotations {
212 rotvecs.push(rot.as_rotvec());
213 }
214
215 let mut vels = Vec::with_capacity(n);
217
218 for i in 0..n {
221 let vel = if i == 0 {
222 let dt = self.times[1] - self.times[0];
224 (&rotvecs[1] - &rotvecs[0]) / dt
225 } else if i == n - 1 {
226 let dt = self.times[n - 1] - self.times[n - 2];
228 (&rotvecs[n - 1] - &rotvecs[n - 2]) / dt
229 } else {
230 let dt_prev = self.times[i] - self.times[i - 1];
232 let dt_next = self.times[i + 1] - self.times[i];
233
234 let vel_prev = (&rotvecs[i] - &rotvecs[i - 1]) / dt_prev;
236 let vel_next = (&rotvecs[i + 1] - &rotvecs[i]) / dt_next;
237
238 let weight_prev = dt_next / (dt_prev + dt_next);
240 let weight_next = dt_prev / (dt_prev + dt_next);
241 &vel_prev * weight_prev + &vel_next * weight_next
242 };
243
244 vels.push(vel);
245 }
246
247 self.velocities = Some(vels);
248 }
249
250 #[allow(dead_code)]
252 fn compute_natural_spline_second_derivatives(&self, values: &[f64]) -> Vec<f64> {
253 let n = values.len();
254 if n <= 2 {
255 return vec![0.0; n];
256 }
257
258 let mut a = vec![0.0; n - 2]; let mut b = vec![0.0; n - 2]; let mut c = vec![0.0; n - 2]; let mut d = vec![0.0; n - 2]; for i in 0..n - 2 {
271 let h_i = self.times[i + 1] - self.times[i];
272 let h_ip1 = self.times[i + 2] - self.times[i + 1];
273
274 a[i] = h_i;
275 b[i] = 2.0 * (h_i + h_ip1);
276 c[i] = h_ip1;
277
278 let fd_i = (values[i + 1] - values[i]) / h_i;
279 let fd_ip1 = (values[i + 2] - values[i + 1]) / h_ip1;
280 d[i] = 6.0 * (fd_ip1 - fd_i);
281 }
282
283 let mut x = vec![0.0; n - 2];
285 self.solve_tridiagonal(&a, &b, &c, &d, &mut x);
286
287 let mut second_derivs = vec![0.0; n];
289 second_derivs[1..((n - 2) + 1)].copy_from_slice(&x[..(n - 2)]);
290
291 second_derivs
292 }
293
294 #[allow(dead_code)]
296 fn solve_tridiagonal(
297 &self,
298 a: &[f64], b: &[f64], c: &[f64], d: &[f64], x: &mut [f64], ) {
304 let n = x.len();
305 if n == 0 {
306 return;
307 }
308
309 let mut c_prime = vec![0.0; n];
311 let mut d_prime = vec![0.0; n];
312
313 c_prime[0] = c[0] / b[0];
314 d_prime[0] = d[0] / b[0];
315
316 for i in 1..n {
317 let m = b[i] - a[i - 1] * c_prime[i - 1];
318 c_prime[i] = if i < n - 1 { c[i] / m } else { 0.0 };
319 d_prime[i] = (d[i] - a[i - 1] * d_prime[i - 1]) / m;
320 }
321
322 x[n - 1] = d_prime[n - 1];
324 for i in (0..n - 1).rev() {
325 x[i] = d_prime[i] - c_prime[i] * x[i + 1];
326 }
327 }
328
329 pub fn interpolate(&self, t: f64) -> Rotation {
358 let n = self.times.len();
359
360 if t <= self.times[0] {
362 return self.rotations[0].clone();
363 }
364 if t >= self.times[n - 1] {
365 return self.rotations[n - 1].clone();
366 }
367
368 let mut idx = 0;
370 for i in 0..n - 1 {
371 if t >= self.times[i] && t < self.times[i + 1] {
372 idx = i;
373 break;
374 }
375 }
376
377 match self.interpolation_type.as_str() {
379 "slerp" => self.interpolate_slerp(t, idx),
380 "cubic" => self.interpolate_cubic(t, idx),
381 _ => self.interpolate_slerp(t, idx), }
383 }
384
385 fn interpolate_slerp(&self, t: f64, idx: usize) -> Rotation {
387 let t0 = self.times[idx];
388 let t1 = self.times[idx + 1];
389 let normalized_t = (t - t0) / (t1 - t0);
390
391 let slerp = Slerp::new(self.rotations[idx].clone(), self.rotations[idx + 1].clone())
393 .expect("Test/example failed");
394
395 slerp.interpolate(normalized_t)
396 }
397
398 fn interpolate_cubic(&self, t: f64, idx: usize) -> Rotation {
400 if self.velocities.is_none() {
402 let mut mutable_self = self.clone();
403 mutable_self.compute_velocities();
404 return mutable_self.interpolate_cubic(t, idx);
405 }
406
407 let t0 = self.times[idx];
408 let t1 = self.times[idx + 1];
409 let dt = t1 - t0;
410 let normalized_t = (t - t0) / dt;
411
412 let rot0 = &self.rotations[idx];
413 let rot1 = &self.rotations[idx + 1];
414
415 let rotvec0 = rot0.as_rotvec();
417 let rotvec1 = rot1.as_rotvec();
418
419 let velocities = self.velocities.as_ref().expect("Test/example failed");
421 let vel0 = &velocities[idx];
422 let vel1 = &velocities[idx + 1];
423
424 let t2 = normalized_t * normalized_t;
428 let t3 = t2 * normalized_t;
429
430 let h00 = 2.0 * t3 - 3.0 * t2 + 1.0;
432 let h10 = t3 - 2.0 * t2 + normalized_t;
433 let h01 = -2.0 * t3 + 3.0 * t2;
434 let h11 = t3 - t2;
435
436 let mut result = rotvec0 * h00;
438 result = &result + &(vel0 * dt * h10);
439 result = &result + &(rotvec1 * h01);
440 result = &result + &(vel1 * dt * h11);
441
442 Rotation::from_rotvec(&result.view()).expect("Operation failed")
444 }
445
446 pub fn times(&self) -> &Vec<f64> {
469 &self.times
470 }
471
472 pub fn rotations(&self) -> &Vec<Rotation> {
495 &self.rotations
496 }
497
498 pub fn sample(&self, n: usize) -> (Vec<f64>, Vec<Rotation>) {
528 if n <= 1 {
529 return (vec![self.times[0]], vec![self.rotations[0].clone()]);
530 }
531
532 let t_min = self.times[0];
533 let t_max = self.times[self.times.len() - 1];
534
535 let mut sampled_times = Vec::with_capacity(n);
536 let mut sampled_rotations = Vec::with_capacity(n);
537
538 for i in 0..n {
539 let t = t_min + (t_max - t_min) * (i as f64 / (n - 1) as f64);
540 sampled_times.push(t);
541 sampled_rotations.push(self.interpolate(t));
542 }
543
544 (sampled_times, sampled_rotations)
545 }
546
547 pub fn from_key_rotations(_key_rots: &[Rotation], keytimes: &[f64]) -> SpatialResult<Self> {
577 Self::new(_key_rots, keytimes)
578 }
579
580 pub fn interpolation_type(&self) -> &'_ str {
602 &self.interpolation_type
603 }
604
605 pub fn angular_velocity(&self, t: f64) -> SpatialResult<Array1<f64>> {
634 let n = self.times.len();
635
636 if t <= self.times[0] || t >= self.times[n - 1] {
638 return Ok(Array1::zeros(3));
639 }
640
641 let mut idx = 0;
643 for i in 0..n - 1 {
644 if t >= self.times[i] && t < self.times[i + 1] {
645 idx = i;
646 break;
647 }
648 }
649
650 match self.interpolation_type.as_str() {
652 "slerp" => self.angular_velocity_slerp(t, idx),
653 "cubic" => Ok(self.angular_velocity_cubic(t, idx)),
654 _ => self.angular_velocity_slerp(t, idx), }
656 }
657
658 fn angular_velocity_slerp(&self, t: f64, idx: usize) -> SpatialResult<Array1<f64>> {
660 let t0 = self.times[idx];
661 let t1 = self.times[idx + 1];
662 let dt = t1 - t0;
663 let normalized_t = (t - t0) / dt;
664
665 let r0 = &self.rotations[idx];
667 let r1 = &self.rotations[idx + 1];
668
669 let delta_rot = r0.inv().compose(r1);
671
672 let rotvec = delta_rot.as_rotvec();
674 let angle = (rotvec.dot(&rotvec)).sqrt();
675 let axis = if angle > 1e-10 {
676 &rotvec / angle
677 } else {
678 Array1::zeros(3)
679 };
680
681 let slerp = Slerp::new(r0.clone(), r1.clone()).expect("Test/example failed");
688 let rot_t = slerp.interpolate(normalized_t);
689
690 let angular_rate = angle / dt;
692 let omega_global = axis * angular_rate;
693
694 rot_t.inv().apply(&omega_global.view())
697 }
698
699 fn angular_velocity_cubic(&self, t: f64, idx: usize) -> Array1<f64> {
701 if self.velocities.is_none() {
703 let mut mutable_self = self.clone();
704 mutable_self.compute_velocities();
705 return mutable_self.angular_velocity_cubic(t, idx);
706 }
707
708 let t0 = self.times[idx];
709 let t1 = self.times[idx + 1];
710 let dt = t1 - t0;
711 let normalized_t = (t - t0) / dt;
712
713 let rot0 = &self.rotations[idx];
714 let rot1 = &self.rotations[idx + 1];
715
716 let rotvec0 = rot0.as_rotvec();
718 let rotvec1 = rot1.as_rotvec();
719
720 let velocities = self.velocities.as_ref().expect("Test/example failed");
722 let vel0 = &velocities[idx];
723 let vel1 = &velocities[idx + 1];
724
725 let dh00_dt = (6.0 * normalized_t.powi(2) - 6.0 * normalized_t) / dt;
727 let dh10_dt = (3.0 * normalized_t.powi(2) - 4.0 * normalized_t + 1.0) / dt;
728 let dh01_dt = (-6.0 * normalized_t.powi(2) + 6.0 * normalized_t) / dt;
729 let dh11_dt = (3.0 * normalized_t.powi(2) - 2.0 * normalized_t) / dt;
730
731 let mut d_rotvec_dt = &rotvec0 * dh00_dt;
733 d_rotvec_dt = &d_rotvec_dt + &(vel0 * dt * dh10_dt);
734 d_rotvec_dt = &d_rotvec_dt + &(&rotvec1 * dh01_dt);
735 d_rotvec_dt = &d_rotvec_dt + &(vel1 * dt * dh11_dt);
736
737 d_rotvec_dt
740 }
741
742 pub fn angular_acceleration(&self, t: f64) -> Array1<f64> {
774 if self.interpolation_type != "cubic" {
776 return Array1::zeros(3); }
778
779 let n = self.times.len();
780
781 if t <= self.times[0] || t >= self.times[n - 1] {
783 return Array1::zeros(3);
784 }
785
786 let mut idx = 0;
788 for i in 0..n - 1 {
789 if t >= self.times[i] && t < self.times[i + 1] {
790 idx = i;
791 break;
792 }
793 }
794
795 self.angular_acceleration_cubic(t, idx)
797 }
798
799 fn angular_acceleration_cubic(&self, t: f64, idx: usize) -> Array1<f64> {
801 if self.velocities.is_none() {
803 let mut mutable_self = self.clone();
804 mutable_self.compute_velocities();
805 return mutable_self.angular_acceleration_cubic(t, idx);
806 }
807
808 let t0 = self.times[idx];
809 let t1 = self.times[idx + 1];
810 let dt = t1 - t0;
811 let normalized_t = (t - t0) / dt;
812
813 let rot0 = &self.rotations[idx];
814 let rot1 = &self.rotations[idx + 1];
815
816 let rotvec0 = rot0.as_rotvec();
818 let rotvec1 = rot1.as_rotvec();
819
820 let velocities = self.velocities.as_ref().expect("Test/example failed");
822 let vel0 = &velocities[idx];
823 let vel1 = &velocities[idx + 1];
824
825 let d2h00_dt2 = (12.0 * normalized_t - 6.0) / (dt * dt);
827 let d2h10_dt2 = (6.0 * normalized_t - 4.0) / (dt * dt);
828 let d2h01_dt2 = (-12.0 * normalized_t + 6.0) / (dt * dt);
829 let d2h11_dt2 = (6.0 * normalized_t - 2.0) / (dt * dt);
830
831 let mut d2_rotvec_dt2 = &rotvec0 * d2h00_dt2;
833 d2_rotvec_dt2 = &d2_rotvec_dt2 + &(vel0 * dt * d2h10_dt2);
834 d2_rotvec_dt2 = &d2_rotvec_dt2 + &(&rotvec1 * d2h01_dt2);
835 d2_rotvec_dt2 = &d2_rotvec_dt2 + &(vel1 * dt * d2h11_dt2);
836
837 d2_rotvec_dt2
839 }
840}
841
842#[cfg(test)]
843mod tests {
844 use super::*;
845 use approx::assert_relative_eq;
846 use std::f64::consts::PI;
847
848 #[test]
849 fn test_rotation_spline_creation() {
850 let rotations = vec![
851 Rotation::identity(),
852 rotation_from_euler(0.0, 0.0, PI / 2.0, "xyz").expect("Operation failed"),
853 Rotation::from_euler(&array![0.0, 0.0, PI].view(), "xyz").expect("Operation failed"),
854 ];
855 let times = vec![0.0, 1.0, 2.0];
856
857 let spline = RotationSpline::new(&rotations, ×).expect("Test/example failed");
858
859 assert_eq!(spline.rotations().len(), 3);
860 assert_eq!(spline.times().len(), 3);
861 assert_eq!(spline.interpolation_type(), "slerp");
862 }
863
864 #[test]
865 fn test_rotation_spline_interpolation_endpoints() {
866 let rotations = vec![
867 Rotation::identity(),
868 rotation_from_euler(0.0, 0.0, PI / 2.0, "xyz").expect("Operation failed"),
869 Rotation::from_euler(&array![0.0, 0.0, PI].view(), "xyz").expect("Operation failed"),
870 ];
871 let times = vec![0.0, 1.0, 2.0];
872
873 let spline = RotationSpline::new(&rotations, ×).expect("Test/example failed");
874
875 let interp_start = spline.interpolate(0.0);
877 let interp_end = spline.interpolate(2.0);
878
879 assert_eq!(interp_start.as_quat(), rotations[0].as_quat());
881 assert_eq!(interp_end.as_quat(), rotations[2].as_quat());
882
883 let before_start = spline.interpolate(-1.0);
885 let after_end = spline.interpolate(3.0);
886
887 assert_eq!(before_start.as_quat(), rotations[0].as_quat());
888 assert_eq!(after_end.as_quat(), rotations[2].as_quat());
889 }
890
891 #[test]
892 fn test_rotation_spline_interpolation_midpoints() {
893 let rotations = vec![
894 Rotation::identity(),
895 rotation_from_euler(0.0, 0.0, PI / 2.0, "xyz").expect("Operation failed"),
896 Rotation::from_euler(&array![0.0, 0.0, PI].view(), "xyz").expect("Operation failed"),
897 ];
898 let times = vec![0.0, 1.0, 2.0];
899
900 let spline = RotationSpline::new(&rotations, ×).expect("Test/example failed");
901
902 let interp_mid1 = spline.interpolate(0.5);
904 let interp_mid2 = spline.interpolate(1.5);
905
906 let test_point = array![1.0, 0.0, 0.0];
908
909 let rotated_mid1 = interp_mid1
911 .apply(&test_point.view())
912 .expect("Test/example failed");
913 let rotated_mid2 = interp_mid2
914 .apply(&test_point.view())
915 .expect("Test/example failed");
916
917 assert_relative_eq!(rotated_mid1[0], 2.0_f64.sqrt() / 2.0, epsilon = 1e-3);
919 assert_relative_eq!(rotated_mid1[1], 2.0_f64.sqrt() / 2.0, epsilon = 1e-3);
920 assert_relative_eq!(rotated_mid1[2], 0.0, epsilon = 1e-3);
921
922 assert_relative_eq!(rotated_mid2[0], -2.0_f64.sqrt() / 2.0, epsilon = 1e-3);
924 assert_relative_eq!(rotated_mid2[1], 2.0_f64.sqrt() / 2.0, epsilon = 1e-3);
925 assert_relative_eq!(rotated_mid2[2], 0.0, epsilon = 1e-3);
926 }
927
928 #[test]
929 fn test_rotation_spline_sampling() {
930 let rotations = vec![
931 Rotation::identity(),
932 Rotation::from_euler(&array![0.0, 0.0, PI].view(), "xyz").expect("Operation failed"),
933 ];
934 let times = vec![0.0, 1.0];
935
936 let spline = RotationSpline::new(&rotations, ×).expect("Test/example failed");
937
938 let (sample_times, sample_rotations) = spline.sample(5);
940
941 assert_eq!(sample_times.len(), 5);
942 assert_eq!(sample_rotations.len(), 5);
943
944 assert_relative_eq!(sample_times[0], 0.0, epsilon = 1e-10);
946 assert_relative_eq!(sample_times[1], 0.25, epsilon = 1e-10);
947 assert_relative_eq!(sample_times[2], 0.5, epsilon = 1e-10);
948 assert_relative_eq!(sample_times[3], 0.75, epsilon = 1e-10);
949 assert_relative_eq!(sample_times[4], 1.0, epsilon = 1e-10);
950
951 let point = array![1.0, 0.0, 0.0];
953
954 let rot0 = &sample_rotations[0];
956 let rotated0 = rot0.apply(&point.view()).expect("Test/example failed");
957 assert_relative_eq!(rotated0[0], 1.0, epsilon = 1e-10);
958 assert_relative_eq!(rotated0[1], 0.0, epsilon = 1e-10);
959
960 let rot2 = &sample_rotations[2];
962 let rotated2 = rot2.apply(&point.view()).expect("Test/example failed");
963 assert_relative_eq!(rotated2[0], 0.0, epsilon = 1e-3);
964 assert_relative_eq!(rotated2[1], 1.0, epsilon = 1e-3);
965 assert_relative_eq!(rotated2[2], 0.0, epsilon = 1e-3);
966
967 let rot4 = &sample_rotations[4];
969 let rotated4 = rot4.apply(&point.view()).expect("Test/example failed");
970 assert_relative_eq!(rotated4[0], -1.0, epsilon = 1e-10);
971 assert_relative_eq!(rotated4[1], 0.0, epsilon = 1e-10);
972 assert_relative_eq!(rotated4[2], 0.0, epsilon = 1e-10);
973 }
974
975 #[test]
976 fn test_rotation_spline_errors() {
977 let result = RotationSpline::new(&[], &[0.0]);
979 assert!(result.is_err());
980
981 let rotations = vec![Rotation::identity()];
983 let result = RotationSpline::new(&rotations, &[]);
984 assert!(result.is_err());
985
986 let rotations = vec![Rotation::identity(), Rotation::identity()];
988 let times = vec![0.0];
989 let result = RotationSpline::new(&rotations, ×);
990 assert!(result.is_err());
991
992 let rotations = vec![Rotation::identity(), Rotation::identity()];
994 let times = vec![1.0, 0.0];
995 let result = RotationSpline::new(&rotations, ×);
996 assert!(result.is_err());
997
998 let rotations = vec![Rotation::identity(), Rotation::identity()];
1000 let times = vec![0.0, 0.0];
1001 let result = RotationSpline::new(&rotations, ×);
1002 assert!(result.is_err());
1003
1004 let rotations = vec![Rotation::identity(), Rotation::identity()];
1006 let times = vec![0.0, 1.0];
1007 let mut spline = RotationSpline::new(&rotations, ×).expect("Test/example failed");
1008 let result = spline.set_interpolation_type("invalid");
1009 assert!(result.is_err());
1010 }
1011
1012 #[test]
1013 fn test_interpolation_types() {
1014 let rotations = vec![
1015 Rotation::identity(),
1016 rotation_from_euler(0.0, 0.0, PI / 2.0, "xyz").expect("Operation failed"),
1017 Rotation::from_euler(&array![0.0, 0.0, PI].view(), "xyz").expect("Operation failed"),
1018 ];
1019 let times = vec![0.0, 1.0, 2.0];
1020
1021 let mut spline = RotationSpline::new(&rotations, ×).expect("Test/example failed");
1022
1023 assert_eq!(spline.interpolation_type(), "slerp");
1025
1026 spline
1028 .set_interpolation_type("cubic")
1029 .expect("Test/example failed");
1030 assert_eq!(spline.interpolation_type(), "cubic");
1031
1032 assert!(spline.velocities.is_some());
1034
1035 spline
1037 .set_interpolation_type("slerp")
1038 .expect("Test/example failed");
1039 assert_eq!(spline.interpolation_type(), "slerp");
1040
1041 assert!(spline.velocities.is_none());
1043 }
1044
1045 #[test]
1046 fn test_angular_velocity() {
1047 let rotations = vec![
1048 Rotation::identity(),
1049 Rotation::from_euler(&array![0.0, 0.0, PI].view(), "xyz").expect("Operation failed"),
1050 ];
1051 let times = vec![0.0, 1.0];
1052
1053 let spline = RotationSpline::new(&rotations, ×).expect("Test/example failed");
1054
1055 let velocity = spline.angular_velocity(0.5).expect("Test/example failed");
1057
1058 assert_relative_eq!(velocity[0], 0.0, epsilon = 1e-3);
1061 assert_relative_eq!(velocity[1], 0.0, epsilon = 1e-3);
1062 assert_relative_eq!(velocity[2], PI, epsilon = 1e-3);
1063
1064 let velocity_25 = spline.angular_velocity(0.25).expect("Test/example failed");
1066 let velocity_75 = spline.angular_velocity(0.75).expect("Test/example failed");
1067
1068 assert_relative_eq!(velocity_25[0], velocity[0], epsilon = 1e-10);
1069 assert_relative_eq!(velocity_25[1], velocity[1], epsilon = 1e-10);
1070 assert_relative_eq!(velocity_25[2], velocity[2], epsilon = 1e-10);
1071
1072 assert_relative_eq!(velocity_75[0], velocity[0], epsilon = 1e-10);
1073 assert_relative_eq!(velocity_75[1], velocity[1], epsilon = 1e-10);
1074 assert_relative_eq!(velocity_75[2], velocity[2], epsilon = 1e-10);
1075 }
1076
1077 #[test]
1078 fn test_cubic_interpolation() {
1079 let rotations = vec![
1080 Rotation::identity(),
1081 rotation_from_euler(0.0, 0.0, PI / 2.0, "xyz").expect("Operation failed"),
1082 Rotation::from_euler(&array![0.0, 0.0, PI].view(), "xyz").expect("Operation failed"),
1083 ];
1084 let times = vec![0.0, 1.0, 2.0];
1085
1086 let mut spline = RotationSpline::new(&rotations, ×).expect("Test/example failed");
1087
1088 spline
1090 .set_interpolation_type("cubic")
1091 .expect("Test/example failed");
1092
1093 let rot_0 = spline.interpolate(0.0);
1095 let rot_1 = spline.interpolate(1.0);
1096 let rot_2 = spline.interpolate(2.0);
1097
1098 let test_point = array![1.0, 0.0, 0.0];
1099
1100 let rotated_0 = rot_0
1102 .apply(&test_point.view())
1103 .expect("Test/example failed");
1104 let expected_0 = rotations[0]
1105 .apply(&test_point.view())
1106 .expect("Test/example failed");
1107 assert_relative_eq!(rotated_0[0], expected_0[0], epsilon = 1e-10);
1108 assert_relative_eq!(rotated_0[1], expected_0[1], epsilon = 1e-10);
1109 assert_relative_eq!(rotated_0[2], expected_0[2], epsilon = 1e-10);
1110
1111 let rotated_1 = rot_1
1112 .apply(&test_point.view())
1113 .expect("Test/example failed");
1114 let expected_1 = rotations[1]
1115 .apply(&test_point.view())
1116 .expect("Test/example failed");
1117 assert_relative_eq!(rotated_1[0], expected_1[0], epsilon = 1e-10);
1118 assert_relative_eq!(rotated_1[1], expected_1[1], epsilon = 1e-10);
1119 assert_relative_eq!(rotated_1[2], expected_1[2], epsilon = 1e-10);
1120
1121 let rotated_2 = rot_2
1122 .apply(&test_point.view())
1123 .expect("Test/example failed");
1124 let expected_2 = rotations[2]
1125 .apply(&test_point.view())
1126 .expect("Test/example failed");
1127 assert_relative_eq!(rotated_2[0], expected_2[0], epsilon = 1e-10);
1128 assert_relative_eq!(rotated_2[1], expected_2[1], epsilon = 1e-10);
1129 assert_relative_eq!(rotated_2[2], expected_2[2], epsilon = 1e-10);
1130
1131 let rot_05 = spline.interpolate(0.5);
1134 let rot_15 = spline.interpolate(1.5);
1135
1136 let rotated_05 = rot_05
1138 .apply(&test_point.view())
1139 .expect("Test/example failed");
1140 let rotated_15 = rot_15
1141 .apply(&test_point.view())
1142 .expect("Test/example failed");
1143
1144 let norm_05 = (rotated_05.dot(&rotated_05)).sqrt();
1146 let norm_15 = (rotated_15.dot(&rotated_15)).sqrt();
1147 assert_relative_eq!(norm_05, 1.0, epsilon = 1e-10);
1148 assert_relative_eq!(norm_15, 1.0, epsilon = 1e-10);
1149 }
1150
1151 #[test]
1152 fn test_angular_acceleration() {
1153 let rotations = vec![
1154 Rotation::identity(),
1155 rotation_from_euler(0.0, 0.0, PI / 2.0, "xyz").expect("Operation failed"),
1156 Rotation::from_euler(&array![0.0, 0.0, PI].view(), "xyz").expect("Operation failed"),
1157 ];
1158 let times = vec![0.0, 1.0, 2.0];
1159
1160 let mut spline = RotationSpline::new(&rotations, ×).expect("Test/example failed");
1161
1162 let accel_slerp = spline.angular_acceleration(0.5);
1164 assert_relative_eq!(accel_slerp[0], 0.0, epsilon = 1e-10);
1165 assert_relative_eq!(accel_slerp[1], 0.0, epsilon = 1e-10);
1166 assert_relative_eq!(accel_slerp[2], 0.0, epsilon = 1e-10);
1167
1168 spline
1170 .set_interpolation_type("cubic")
1171 .expect("Test/example failed");
1172
1173 let _accel_cubic = spline.angular_acceleration(0.5);
1175
1176 let complex_rotations = vec![
1179 Rotation::identity(),
1180 {
1181 let angles = array![PI / 2.0, 0.0, 0.0];
1182 Rotation::from_euler(&angles.view(), "xyz").expect("Operation failed")
1183 },
1184 {
1185 let angles = array![PI / 2.0, PI / 2.0, 0.0];
1186 Rotation::from_euler(&angles.view(), "xyz").expect("Operation failed")
1187 },
1188 ];
1189 let complex_times = vec![0.0, 1.0, 2.0];
1190
1191 let mut complex_spline =
1192 RotationSpline::new(&complex_rotations, &complex_times).expect("Test/example failed");
1193 complex_spline
1194 .set_interpolation_type("cubic")
1195 .expect("Test/example failed");
1196
1197 let complex_accel = complex_spline.angular_acceleration(0.5);
1198
1199 let magnitude = (complex_accel.dot(&complex_accel)).sqrt();
1201 assert!(magnitude > 1e-6); }
1203}