quaternion_core/lib.rs
1//! Quaternion library written in Rust.
2//!
3//! This provides Quaternion operations and interconversion with several attitude
4//! representations as generic functions (supports `f32` & `f64`).
5//!
6//! ## Generics
7//!
8//! Functions implementing the `QuaternionOps` trait can take both `Quaternion<T>`
9//! and `Vector3<T>` as arguments. In this case, `Vector3<T>` is treated as a Pure Quaternion.
10//!
11//! For example:
12//! ```
13//! use quaternion_core::{Vector3, Quaternion, add};
14//!
15//! // --- Vector3 --- //
16//! let v1: Vector3<f32> = [1.0, 2.0, 3.0];
17//! let v2: Vector3<f32> = [0.1, 0.2, 0.3];
18//! println!("{:?}", add(v1, v2)); // <--- It's [1.1, 2.2, 3.3]
19//!
20//! // --- Quaternion --- //
21//! let q1: Quaternion<f64> = (1.0, [2.0, 3.0, 4.0]);
22//! let q2: Quaternion<f64> = (0.1, [0.2, 0.3, 0.4]);
23//! println!("{:?}", add(q1, q2)); // <--- It's (1.1, [2.2, 3.3, 4.4])
24//! ```
25//!
26//! ## Versor
27//!
28//! Versor refers to a Quaternion representing a rotation, the norm of which is 1.
29//!
30//! The documentation for this crate basically writes Versor instead of Unit Quaternion,
31//! but the difference in usage is not clear.
32//! Please think Versor = Unit Quaternion.
33
34#![no_std]
35#[cfg(feature = "std")]
36extern crate std;
37
38#[cfg(any(feature = "std", feature = "libm"))]
39use num_traits::float::{Float, FloatConst};
40
41mod euler;
42mod generics;
43mod pfs;
44pub use generics::QuaternionOps;
45
46/// Three dimensional vector (Pure Quaternion)
47///
48/// The type `[q1, q2, q3]` is equivalent to the expression `q1i + q2j + q3k`,
49/// where `i`, `j`, `k` are basis of quaternions and satisfy the following equality:
50///
51/// `i^2 = j^2 = k^2 = ijk = -1`
52pub type Vector3<T> = [T; 3];
53
54/// Quaternion
55///
56/// The type `(q0, [q1, q2, q3])` is equivalent to the expression `q0 + q1i + q2j + q3k`,
57/// where `1`, `i`, `j`, `k` are basis of quaternions and satisfy the following equality:
58///
59/// `i^2 = j^2 = k^2 = ijk = -1`
60pub type Quaternion<T> = (T, Vector3<T>);
61
62/// Direction Cosine Matrix
63///
64/// `mij`: row `i`, column `j`
65///
66/// `
67/// [
68/// [m11, m12, m13],
69/// [m21, m22, m23],
70/// [m31, m32, m33]
71/// ]
72/// `
73pub type DCM<T> = [Vector3<T>; 3];
74
75/// Specifies the rotation type of Euler angles.
76///
77/// Considering a fixed `Reference frame` and a rotating `Body frame`,
78/// `Intrinsic rotation` and `Extrinsic rotation` represent the following rotations:
79///
80/// * `Intrinsic`: Rotate around the axes of the `Body frame`
81/// * `Extrinsic`: Rotate around the axes of the `Reference frame`
82#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize, serde::Deserialize))]
83#[derive(Debug, Clone, Copy)]
84pub enum RotationType {
85 Intrinsic,
86 Extrinsic,
87}
88
89/// Specifies the rotation sequence of Euler angles.
90///
91/// Each variant reads from left to right.
92/// For example, `RotationSequence::XYZ` represents first a rotation
93/// around the X axis, then around the Y axis, and finally around
94/// the Z axis (X ---> Y ---> Z).
95#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize, serde::Deserialize))]
96#[derive(Debug, Clone, Copy)]
97pub enum RotationSequence {
98 // Proper (z-x-z, x-y-x, y-z-y, z-y-z, x-z-x, y-x-y)
99 ZXZ,
100 XYX,
101 YZY,
102 ZYZ,
103 XZX,
104 YXY,
105 // Tait–Bryan (x-y-z, y-z-x, z-x-y, x-z-y, z-y-x, y-x-z)
106 XYZ,
107 YZX,
108 ZXY,
109 XZY,
110 ZYX,
111 YXZ,
112}
113
114/// Generate identity quaternion.
115///
116/// ```
117/// # use quaternion_core::{Quaternion, identity};
118/// let q: Quaternion<f64> = identity();
119/// println!("{:?}", q); // <-- (1.0, [0.0, 0.0, 0.0])
120/// ```
121#[inline]
122pub fn identity<T>() -> Quaternion<T>
123where T: Float {
124 (T::one(), [T::zero(); 3])
125}
126
127/// Generate Versor by specifying rotation `angle`\[rad\] and `axis` vector.
128///
129/// The `axis` vector does not have to be a unit vector.
130///
131/// If you enter a zero vector, it returns an identity quaternion.
132///
133/// # Examples
134///
135/// ```
136/// # use quaternion_core::{from_axis_angle, point_rotation};
137/// # let PI = std::f64::consts::PI;
138/// // Generates a quaternion representing the
139/// // rotation of pi/2[rad] around the y-axis.
140/// let q = from_axis_angle([0.0, 1.0, 0.0], PI/2.0);
141///
142/// // Rotate the point.
143/// let r = point_rotation(q, [2.0, 2.0, 0.0]);
144///
145/// assert!( (r[0] - 0.0).abs() < 1e-12 );
146/// assert!( (r[1] - 2.0).abs() < 1e-12 );
147/// assert!( (r[2] + 2.0).abs() < 1e-12 );
148/// ```
149#[inline]
150pub fn from_axis_angle<T>(axis: Vector3<T>, angle: T) -> Quaternion<T>
151where T: Float + FloatConst {
152 let theta = angle % ( T::PI() + T::PI() ); // Range reduction: (-2π, 2π)
153 let (sin, cos) = ( theta * pfs::cast(0.5) ).sin_cos();
154 let coef = sin / norm(axis);
155 if coef.is_infinite() {
156 identity()
157 } else {
158 ( cos, scale(coef, axis) )
159 }
160}
161
162/// Calculate the rotation `axis` (unit vector) and the rotation `angle`\[rad\]
163/// around the `axis` from the Versor.
164///
165/// If identity quaternion is entered, `angle` returns zero and the `axis` returns a zero vector.
166///
167/// Range of `angle`: `(-pi, pi]`
168///
169/// Because this function returns a normalized rotation axis,
170/// when the norm of the vector part of Versor is zero, a singularity
171/// occurs and accuracy decreases. Therefore, if you want to use the
172/// calculated `angle` and `axis` as `scale(angle, axis)`,
173/// it is better to use the `to_rotation_vector` function.
174/// The `to_rotation_vector` function can be calculated without singularities.
175///
176/// # Examples
177///
178/// ```
179/// # use quaternion_core::{from_axis_angle, to_axis_angle};
180/// # let PI = std::f64::consts::PI;
181/// let axis_ori = [0.0, 1.0, 2.0];
182/// let angle_ori = PI / 2.0;
183/// let q = from_axis_angle(axis_ori, angle_ori);
184///
185/// let (axis, angle) = to_axis_angle(q);
186///
187/// assert!( (axis_ori[0] - axis[0]).abs() < 1e-12 );
188/// assert!( (axis_ori[0] - axis[0]).abs() < 1e-12 );
189/// assert!( (axis_ori[0] - axis[0]).abs() < 1e-12 );
190/// assert!( (angle_ori - angle).abs() < 1e-12 );
191/// ```
192#[inline]
193pub fn to_axis_angle<T>(q: Quaternion<T>) -> (Vector3<T>, T)
194where T: Float {
195 let norm_v = norm(q.1);
196 let norm_inv = norm_v.recip();
197 if norm_inv.is_infinite() {
198 ( [T::zero(); 3], T::zero() )
199 } else {
200 let mut angle = pfs::cast::<T>(2.0) * norm_v.min( T::one() ).asin();
201 if q.0 < T::zero() {
202 angle = -angle;
203 }
204 ( scale(norm_inv, q.1), angle )
205 }
206}
207
208/// Convert a DCM to a Versor representing
209/// the `q v q*` rotation (Point Rotation - Frame Fixed).
210///
211/// When convert to a DCM representing `q* v q` rotation
212/// (Frame Rotation - Point Fixed) to a Versor, do the following:
213///
214/// ```
215/// # use quaternion_core::{from_dcm, to_dcm, conj};
216/// # let dcm = to_dcm((1.0, [0.0; 3]));
217/// let q = conj( from_dcm(dcm) );
218/// ```
219///
220/// # Examples
221///
222/// ```
223/// # use quaternion_core::{
224/// # from_axis_angle, dot, conj, negate, to_dcm, from_dcm,
225/// # matrix_product, point_rotation, frame_rotation
226/// # };
227/// # let PI = std::f64::consts::PI;
228/// // Make these as you like.
229/// let v = [1.0, 0.5, -8.0];
230/// let q = from_axis_angle([0.2, 1.0, -2.0], PI/4.0);
231///
232/// // --- Point rotation --- //
233/// {
234/// let m = to_dcm(q);
235/// let q_check = from_dcm(m);
236///
237/// assert!( (q.0 - q_check.0).abs() < 1e-12 );
238/// assert!( (q.1[0] - q_check.1[0]).abs() < 1e-12 );
239/// assert!( (q.1[1] - q_check.1[1]).abs() < 1e-12 );
240/// assert!( (q.1[2] - q_check.1[2]).abs() < 1e-12 );
241/// }
242///
243/// // --- Frame rotation --- //
244/// {
245/// let m = to_dcm( conj(q) );
246/// let q_check = conj( from_dcm(m) );
247///
248/// assert!( (q.0 - q_check.0).abs() < 1e-12 );
249/// assert!( (q.1[0] - q_check.1[0]).abs() < 1e-12 );
250/// assert!( (q.1[1] - q_check.1[1]).abs() < 1e-12 );
251/// assert!( (q.1[2] - q_check.1[2]).abs() < 1e-12 );
252/// }
253/// ```
254#[inline]
255pub fn from_dcm<T>(m: DCM<T>) -> Quaternion<T>
256where T: Float {
257 // ゼロ除算を避けるために,4通りの式で求めたうちの最大値を係数として使う.
258 let m22_p_m33 = m[1][1] + m[2][2];
259 let m22_m_m33 = m[1][1] - m[2][2];
260 let (index, max_num) = pfs::max4([
261 m[0][0] + m22_p_m33,
262 m[0][0] - m22_p_m33,
263 -m[0][0] + m22_m_m33,
264 -m[0][0] - m22_m_m33,
265 ]);
266
267 let half: T = pfs::cast(0.5);
268 let tmp = ( max_num + T::one() ).sqrt();
269 let coef = half / tmp;
270
271 let (q0, [q1, q2, q3]): Quaternion<T>;
272 match index {
273 0 => {
274 q0 = half * tmp;
275 q1 = (m[2][1] - m[1][2]) * coef;
276 q2 = (m[0][2] - m[2][0]) * coef;
277 q3 = (m[1][0] - m[0][1]) * coef;
278 },
279 1 => {
280 q0 = (m[2][1] - m[1][2]) * coef;
281 q1 = half * tmp;
282 q2 = (m[0][1] + m[1][0]) * coef;
283 q3 = (m[0][2] + m[2][0]) * coef;
284 },
285 2 => {
286 q0 = (m[0][2] - m[2][0]) * coef;
287 q1 = (m[0][1] + m[1][0]) * coef;
288 q2 = half * tmp;
289 q3 = (m[1][2] + m[2][1]) * coef;
290 },
291 3 => {
292 q0 = (m[1][0] - m[0][1]) * coef;
293 q1 = (m[0][2] + m[2][0]) * coef;
294 q2 = (m[1][2] + m[2][1]) * coef;
295 q3 = half * tmp;
296 },
297 _ => unreachable!(),
298 };
299
300 (q0, [q1, q2, q3])
301}
302
303/// Convert a Versor to a DCM representing
304/// the `q v q*` rotation (Point Rotation - Frame Fixed).
305///
306/// When convert to a DCM representing the
307/// `q* v q` rotation (Frame Rotation - Point Fixed), do the following:
308///
309/// ```
310/// # use quaternion_core::{to_dcm, conj};
311/// # let q = (1.0, [0.0; 3]);
312/// let dcm = to_dcm( conj(q) );
313/// ```
314///
315/// # Examples
316///
317/// ```
318/// # use quaternion_core::{
319/// # from_axis_angle, to_dcm, conj,
320/// # matrix_product, point_rotation, frame_rotation
321/// # };
322/// # let PI = std::f64::consts::PI;
323/// // Make these as you like.
324/// let v = [1.0, 0.5, -8.0];
325/// let q = from_axis_angle([0.2, 1.0, -2.0], PI/4.0);
326///
327/// // --- Point rotation --- //
328/// {
329/// let m = to_dcm(q);
330///
331/// let rm = matrix_product(m, v);
332/// let rq = point_rotation(q, v);
333/// assert!( (rm[0] - rq[0]).abs() < 1e-12 );
334/// assert!( (rm[1] - rq[1]).abs() < 1e-12 );
335/// assert!( (rm[2] - rq[2]).abs() < 1e-12 );
336/// }
337///
338/// // --- Frame rotation --- //
339/// {
340/// let m = to_dcm( conj(q) );
341///
342/// let rm = matrix_product(m, v);
343/// let rq = frame_rotation(q, v);
344/// assert!( (rm[0] - rq[0]).abs() < 1e-12 );
345/// assert!( (rm[1] - rq[1]).abs() < 1e-12 );
346/// assert!( (rm[2] - rq[2]).abs() < 1e-12 );
347/// }
348/// ```
349#[inline]
350pub fn to_dcm<T>(q: Quaternion<T>) -> DCM<T>
351where T: Float {
352 let neg_one = -T::one();
353 let two = pfs::cast(2.0);
354
355 // Compute these value only once.
356 let (q0_q0, [q0_q1, q0_q2, q0_q3]) = scale(q.0, q);
357 let q1_q2 = q.1[0] * q.1[1];
358 let q1_q3 = q.1[0] * q.1[2];
359 let q2_q3 = q.1[1] * q.1[2];
360
361 let m11 = pfs::mul_add(pfs::mul_add(q.1[0], q.1[0], q0_q0), two, neg_one);
362 let m12 = (q1_q2 - q0_q3) * two;
363 let m13 = (q1_q3 + q0_q2) * two;
364 let m21 = (q1_q2 + q0_q3) * two;
365 let m22 = pfs::mul_add(pfs::mul_add(q.1[1], q.1[1], q0_q0), two, neg_one);
366 let m23 = (q2_q3 - q0_q1) * two;
367 let m31 = (q1_q3 - q0_q2) * two;
368 let m32 = (q2_q3 + q0_q1) * two;
369 let m33 = pfs::mul_add(pfs::mul_add(q.1[2], q.1[2], q0_q0), two, neg_one);
370
371 [
372 [m11, m12, m13],
373 [m21, m22, m23],
374 [m31, m32, m33],
375 ]
376}
377
378/// Convert euler angles to versor.
379///
380/// The type of rotation (Intrinsic or Extrinsic) is specified by `RotationType` enum,
381/// and the rotation sequence (XZX, XYZ, ...) is specified by `RotationSequence` enum.
382///
383/// Each element of `angles` should be specified in the range: `[-2π, 2π]`.
384///
385/// Sequences: `angles[0]` ---> `angles[1]` ---> `angles[2]`
386///
387/// # Examples
388///
389/// ```
390/// # use quaternion_core::{from_axis_angle, mul, from_euler_angles, point_rotation};
391/// # let PI = std::f64::consts::PI;
392/// use quaternion_core::{RotationType::*, RotationSequence::XYZ};
393///
394/// let angles = [PI/6.0, 1.6*PI, -PI/4.0];
395/// let v = [1.0, 0.5, -0.4];
396///
397/// // Quaternions representing rotation around each axis.
398/// let x = from_axis_angle([1.0, 0.0, 0.0], angles[0]);
399/// let y = from_axis_angle([0.0, 1.0, 0.0], angles[1]);
400/// let z = from_axis_angle([0.0, 0.0, 1.0], angles[2]);
401///
402/// // ---- Intrinsic (X-Y-Z) ---- //
403/// // These represent the same rotation.
404/// let q_in = mul( mul(x, y), z );
405/// let e2q_in = from_euler_angles(Intrinsic, XYZ, angles);
406/// // Confirmation
407/// let a_in = point_rotation(q_in, v);
408/// let b_in = point_rotation(e2q_in, v);
409/// assert!( (a_in[0] - b_in[0]).abs() < 1e-12 );
410/// assert!( (a_in[1] - b_in[1]).abs() < 1e-12 );
411/// assert!( (a_in[2] - b_in[2]).abs() < 1e-12 );
412///
413/// // ---- Extrinsic (X-Y-Z) ---- //
414/// // These represent the same rotation.
415/// let q_ex = mul( mul(z, y), x );
416/// let e2q_ex = from_euler_angles(Extrinsic, XYZ, angles);
417/// // Confirmation
418/// let a_ex = point_rotation(q_ex, v);
419/// let b_ex = point_rotation(e2q_ex, v);
420/// assert!( (a_ex[0] - b_ex[0]).abs() < 1e-12 );
421/// assert!( (a_ex[1] - b_ex[1]).abs() < 1e-12 );
422/// assert!( (a_ex[2] - b_ex[2]).abs() < 1e-12 );
423/// ```
424#[inline]
425pub fn from_euler_angles<T>(rt: RotationType, rs: RotationSequence, angles: Vector3<T>) -> Quaternion<T>
426where T: Float + FloatConst {
427 debug_assert!( angles[0].abs() <= T::PI() + T::PI(), "angles[0] is out of range!");
428 debug_assert!( angles[1].abs() <= T::PI() + T::PI(), "angles[1] is out of range!");
429 debug_assert!( angles[2].abs() <= T::PI() + T::PI(), "angles[2] is out of range!");
430
431 match rt {
432 RotationType::Intrinsic => euler::from_intrinsic_euler_angles(rs, angles),
433 RotationType::Extrinsic => euler::from_extrinsic_euler_angles(rs, angles),
434 }
435}
436
437/// Convert versor to euler angles.
438///
439/// The type of rotation (Intrinsic or Extrinsic) is specified by `RotationType` enum,
440/// and the rotation sequence (XZX, XYZ, ...) is specified by `RotationSequence` enum.
441///
442/// ```
443/// # use quaternion_core::{RotationType::Intrinsic, RotationSequence::XYZ, to_euler_angles};
444/// # let q = (1.0, [0.0; 3]);
445/// let angles = to_euler_angles(Intrinsic, XYZ, q);
446/// ```
447///
448/// Each element of `angles` takes a value in the range: `(-pi, pi]`.
449///
450/// Sequences: `angles[0]` ---> `angles[1]` ---> `angles[2]`
451///
452/// # Singularity
453///
454/// ## RotationType::Intrinsic
455///
456/// For Proper Euler angles (ZXZ, XYX, YZY, ZYZ, XZX, YXY), the singularity is reached
457/// when the sine of the second rotation angle is 0 (angle = 0, ±π, ...), and for
458/// Tait-Bryan angles (XYZ, YZX, ZXY, XZY, ZYX, YXZ), the singularity is reached when
459/// the cosine of the second rotation angle is 0 (angle = ±π/2).
460///
461/// At the singularity, the third rotation angle is set to 0\[rad\].
462///
463/// ## RotationType::Extrinsic
464///
465/// As in the case of Intrinsic rotation, for Proper Euler angles, the singularity occurs
466/// when the sine of the second rotation angle is 0 (angle = 0, ±π, ...), and for
467/// Tait-Bryan angles, the singularity occurs when the cosine of the second rotation angle
468/// is 0 (angle = ±π/2).
469///
470/// At the singularity, the first rotation angle is set to 0\[rad\].
471///
472/// # Examples
473///
474/// Depending on the rotation angle of each axis, it may not be possible to recover the
475/// same rotation angle as the original. However, they represent the same rotation in 3D space.
476///
477/// ```
478/// # use quaternion_core::{from_euler_angles, to_euler_angles, point_rotation};
479/// # let PI = std::f64::consts::PI;
480/// use quaternion_core::{RotationType::*, RotationSequence::XYZ};
481///
482/// let angles = [PI/6.0, PI/4.0, PI/3.0];
483///
484/// // ---- Intrinsic (X-Y-Z) ---- //
485/// let q_in = from_euler_angles(Intrinsic, XYZ, angles);
486/// let e_in = to_euler_angles(Intrinsic, XYZ, q_in);
487/// assert!( (angles[0] - e_in[0]).abs() < 1e-12 );
488/// assert!( (angles[1] - e_in[1]).abs() < 1e-12 );
489/// assert!( (angles[2] - e_in[2]).abs() < 1e-12 );
490///
491/// // ---- Extrinsic (X-Y-Z) ---- //
492/// let q_ex = from_euler_angles(Extrinsic, XYZ, angles);
493/// let e_ex = to_euler_angles(Extrinsic, XYZ, q_ex);
494/// assert!( (angles[0] - e_ex[0]).abs() < 1e-12 );
495/// assert!( (angles[1] - e_ex[1]).abs() < 1e-12 );
496/// assert!( (angles[2] - e_ex[2]).abs() < 1e-12 );
497/// ```
498#[inline]
499pub fn to_euler_angles<T>(rt: RotationType, rs: RotationSequence, q: Quaternion<T>) -> Vector3<T>
500where T: Float + FloatConst {
501 match rt {
502 RotationType::Intrinsic => euler::to_intrinsic_euler_angles(rs, q),
503 RotationType::Extrinsic => euler::to_extrinsic_euler_angles(rs, q),
504 }
505}
506
507/// Convert Rotation vector to Versor.
508///
509/// The Rotation vector itself represents the axis of rotation,
510/// and the norm represents the angle \[rad\] of rotation around the axis.
511///
512/// Maximum range of the norm of the rotation vector: `[0, 2pi]`
513///
514/// # Examples
515///
516/// ```
517/// # use quaternion_core::{from_rotation_vector, scale, point_rotation};
518/// # let PI = std::f64::consts::PI;
519/// let angle = PI / 2.0;
520/// let axis = [1.0, 0.0, 0.0];
521///
522/// // This represents a rotation of pi/2 around the x-axis.
523/// let rot_vec = scale(angle, axis); // Rotation vector
524///
525/// // Rotation vector ---> Quaternion
526/// let q = from_rotation_vector(rot_vec);
527///
528/// let r = point_rotation(q, [1.0, 1.0, 0.0]);
529///
530/// assert!( (r[0] - 1.0).abs() < 1e-12 );
531/// assert!( (r[1] - 0.0).abs() < 1e-12 );
532/// assert!( (r[2] - 1.0).abs() < 1e-12 );
533/// ```
534#[inline]
535pub fn from_rotation_vector<T>(r: Vector3<T>) -> Quaternion<T>
536where T: Float {
537 let half: T = pfs::cast(0.5);
538 let half_theta = half * norm(r);
539 (half_theta.cos(), scale(half * pfs::sinc(half_theta), r))
540}
541
542/// Convert Versor to Rotation vector.
543///
544/// The Rotation vector itself represents the axis of rotation,
545/// and the norm represents the angle of rotation around the axis.
546///
547/// Norm range of the calculation result: `[0, pi]`
548///
549/// # Examples
550///
551/// ```
552/// # use quaternion_core::{from_axis_angle, to_rotation_vector, scale};
553/// # let PI = std::f64::consts::PI;
554/// let angle = PI / 2.0;
555/// let axis = [1.0, 0.0, 0.0];
556///
557/// // These represent the same rotation.
558/// let rv = scale(angle, axis); // Rotation vector
559/// let q = from_axis_angle(axis, angle); // Quaternion
560///
561/// // Quaternion ---> Rotation vector
562/// let q2rv = to_rotation_vector(q);
563///
564/// assert!( (rv[0] - q2rv[0]).abs() < 1e-12 );
565/// assert!( (rv[1] - q2rv[1]).abs() < 1e-12 );
566/// assert!( (rv[2] - q2rv[2]).abs() < 1e-12 );
567/// ```
568#[inline]
569pub fn to_rotation_vector<T>(q: Quaternion<T>) -> Vector3<T>
570where T: Float {
571 // half_thetaをasinで求めるとhalf_theta=±pi/2のときに精度低下するのでatanを使う.
572 let half_theta = (norm(q.1) / q.0).atan(); // [-pi/2, pi/2]
573 let mut coef = pfs::cast::<T>(2.0) / pfs::sinc(half_theta); // [2, pi]
574 if q.0 < T::zero() {
575 coef = -coef; // sinc関数は偶関数なので,half_thetaに対する符号操作はここで行う必要がある.
576 }
577 scale(coef, q.1)
578}
579
580/// Product of DCM and Vector3
581///
582/// This is the product of a 3x3 matrix and a 3D vector.
583/// It is used to apply the rotation represented by the DCM to the vector.
584///
585/// # Examples
586///
587/// ```
588/// # use quaternion_core::{Vector3, Quaternion, matrix_product};
589/// # let PI = std::f64::consts::PI;
590/// let theta = PI / 2.0;
591/// let rot_x = [
592/// [1.0, 0.0, 0.0],
593/// [0.0, theta.cos(), -theta.sin()],
594/// [0.0, theta.sin(), theta.cos()]
595/// ];
596/// let v = [0.0, 1.0, 0.0];
597///
598/// let r = matrix_product(rot_x, v);
599/// assert!( (r[0] - 0.0).abs() < 1e-12 );
600/// assert!( (r[1] - 0.0).abs() < 1e-12 );
601/// assert!( (r[2] - 1.0).abs() < 1e-12 );
602/// ```
603#[inline]
604pub fn matrix_product<T>(m: DCM<T>, v: Vector3<T>) -> Vector3<T>
605where T: Float {
606 [
607 dot(m[0], v),
608 dot(m[1], v),
609 dot(m[2], v),
610 ]
611}
612
613/// Calculate the sum of each element of a quaternion (or vector).
614///
615/// # Examples
616///
617/// ```
618/// # use quaternion_core::{Vector3, Quaternion, sum};
619/// // --- Vector3 --- //
620/// let v: Vector3<f64> = [1.0, 2.0, 3.0];
621///
622/// assert!( (6.0 - sum(v)).abs() < 1e-12 );
623///
624/// // --- Quaternion --- //
625/// let q: Quaternion<f64> = (1.0, [2.0, 3.0, 4.0]);
626///
627/// assert!( (10.0 - sum(q)).abs() < 1e-12 );
628/// ```
629#[inline]
630pub fn sum<T, U>(a: U) -> T
631where T: Float, U: QuaternionOps<T> {
632 a.sum()
633}
634
635/// Addition of two quaternions (or vectors): `a + b`
636///
637/// Calculate the addiction of each element of Quaternion or Vector3.
638///
639/// # Examples
640///
641/// ```
642/// # use quaternion_core::{Vector3, Quaternion, add};
643/// // --- Vector3 --- //
644/// let v1: Vector3<f64> = [1.0, 2.0, 3.0];
645/// let v2: Vector3<f64> = [0.1, 0.2, 0.3];
646/// let v_result = add(v1, v2);
647///
648/// assert!( (1.1 - v_result[0]).abs() < 1e-12 );
649/// assert!( (2.2 - v_result[1]).abs() < 1e-12 );
650/// assert!( (3.3 - v_result[2]).abs() < 1e-12 );
651///
652/// // --- Quaternion --- //
653/// let q1: Quaternion<f64> = (1.0, [2.0, 3.0, 4.0]);
654/// let q2: Quaternion<f64> = (0.1, [0.2, 0.3, 0.4]);
655/// let q_result = add(q1, q2);
656///
657/// assert!( (1.1 - q_result.0).abs() < 1e-12 );
658/// assert!( (2.2 - q_result.1[0]).abs() < 1e-12 );
659/// assert!( (3.3 - q_result.1[1]).abs() < 1e-12 );
660/// assert!( (4.4 - q_result.1[2]).abs() < 1e-12 );
661/// ```
662#[inline]
663pub fn add<T, U>(a: U, b: U) -> U
664where T: Float, U: QuaternionOps<T> {
665 a.add(b)
666}
667
668/// Subtraction of two quaternions (or vectors): `a - b`
669///
670/// # Examples
671///
672/// ```
673/// # use quaternion_core::{Vector3, Quaternion, sub};
674/// // --- Vector3 --- //
675/// let v1: Vector3<f64> = [1.0, 2.0, 3.0];
676/// let v2: Vector3<f64> = [0.1, 0.2, 0.3];
677/// let v_result = sub(v1, v2);
678///
679/// assert!( (0.9 - v_result[0]).abs() < 1e-12 );
680/// assert!( (1.8 - v_result[1]).abs() < 1e-12 );
681/// assert!( (2.7 - v_result[2]).abs() < 1e-12 );
682///
683/// // --- Quaternion --- //
684/// let q1: Quaternion<f64> = (1.0, [2.0, 3.0, 4.0]);
685/// let q2: Quaternion<f64> = (0.1, [0.2, 0.3, 0.4]);
686/// let q_result = sub(q1, q2);
687///
688/// assert!( (0.9 - q_result.0).abs() < 1e-12 );
689/// assert!( (1.8 - q_result.1[0]).abs() < 1e-12 );
690/// assert!( (2.7 - q_result.1[1]).abs() < 1e-12 );
691/// assert!( (3.6 - q_result.1[2]).abs() < 1e-12 );
692/// ```
693#[inline]
694pub fn sub<T, U>(a: U, b: U) -> U
695where T: Float, U: QuaternionOps<T> {
696 a.sub(b)
697}
698
699/// Multiplies each component of the quaternion (or vector) by a given real number, scaling the entire quaternion uniformly: `s * a`.
700///
701/// # Examples
702///
703/// ```
704/// # use quaternion_core::{Vector3, Quaternion, scale};
705/// // --- Vector3 --- //
706/// let v: Vector3<f64> = [1.0, 2.0, 3.0];
707/// let v_result = scale(2.0, v);
708///
709/// assert!( (2.0 - v_result[0]).abs() < 1e-12 );
710/// assert!( (4.0 - v_result[1]).abs() < 1e-12 );
711/// assert!( (6.0 - v_result[2]).abs() < 1e-12 );
712///
713/// // --- Quaternion --- //
714/// let q: Quaternion<f64> = (1.0, [2.0, 3.0, 4.0]);
715/// let q_result = scale(2.0, q);
716///
717/// assert!( (2.0 - q_result.0).abs() < 1e-12 );
718/// assert!( (4.0 - q_result.1[0]).abs() < 1e-12 );
719/// assert!( (6.0 - q_result.1[1]).abs() < 1e-12 );
720/// assert!( (8.0 - q_result.1[2]).abs() < 1e-12 );
721/// ```
722#[inline]
723pub fn scale<T, U>(s: T, a: U) -> U
724where T: Float, U: QuaternionOps<T> {
725 a.scale(s)
726}
727
728/// Scaling and addition in one step: `s * a + b`
729///
730/// If the `fma` feature is enabled, the FMA calculation is performed using
731/// the `mul_add` method (`s.mul_add(a, b)`).
732/// If not enabled, it's computed by unfused multiply-add (`s * a + b`).
733///
734/// # Examples
735///
736/// ```
737/// # use quaternion_core::{Vector3, Quaternion, scale_add};
738/// // --- Vector3 --- //
739/// let v1: Vector3<f64> = [1.0, 2.0, 3.0];
740/// let v2: Vector3<f64> = [0.1, 0.2, 0.3];
741/// let v_result = scale_add(2.0, v1, v2);
742///
743/// assert!( (2.1 - v_result[0]).abs() < 1e-12 );
744/// assert!( (4.2 - v_result[1]).abs() < 1e-12 );
745/// assert!( (6.3 - v_result[2]).abs() < 1e-12 );
746///
747/// // --- Quaternion --- //
748/// let q1: Quaternion<f64> = (1.0, [2.0, 3.0, 4.0]);
749/// let q2: Quaternion<f64> = (0.1, [0.2, 0.3, 0.4]);
750/// let q_result = scale_add(2.0, q1, q2);
751///
752/// assert!( (2.1 - q_result.0).abs() < 1e-12 );
753/// assert!( (4.2 - q_result.1[0]).abs() < 1e-12 );
754/// assert!( (6.3 - q_result.1[1]).abs() < 1e-12 );
755/// assert!( (8.4 - q_result.1[2]).abs() < 1e-12 );
756/// ```
757#[inline]
758pub fn scale_add<T, U>(s: T, a: U, b: U) -> U
759where T: Float, U: QuaternionOps<T> {
760 a.scale_add(s, b)
761}
762
763/// Calculate the element-wise product of two quaternions (or vectors)
764///
765/// # Examples
766///
767/// ```
768/// # use quaternion_core::{Vector3, Quaternion, hadamard};
769/// // --- Vector3 --- //
770/// let v1: Vector3<f64> = [1.0, 2.0, 3.0];
771/// let v2: Vector3<f64> = [0.1, 0.2, 0.3];
772/// let v_result = hadamard(v1, v2);
773///
774/// assert!( (0.1 - v_result[0]).abs() < 1e-12 );
775/// assert!( (0.4 - v_result[1]).abs() < 1e-12 );
776/// assert!( (0.9 - v_result[2]).abs() < 1e-12 );
777///
778/// // --- Quaternion --- //
779/// let q1: Quaternion<f64> = (1.0, [2.0, 3.0, 4.0]);
780/// let q2: Quaternion<f64> = (0.1, [0.2, 0.3, 0.4]);
781/// let q_result = hadamard(q1, q2);
782///
783/// assert!( (0.1 - q_result.0).abs() < 1e-12 );
784/// assert!( (0.4 - q_result.1[0]).abs() < 1e-12 );
785/// assert!( (0.9 - q_result.1[1]).abs() < 1e-12 );
786/// assert!( (1.6 - q_result.1[2]).abs() < 1e-12 );
787/// ```
788#[inline]
789pub fn hadamard<T, U>(a: U, b: U) -> U
790where T: Float, U: QuaternionOps<T> {
791 a.hadamard(b)
792}
793
794/// Hadamard product and addition in one step.
795///
796/// If the `fma` feature is enabled, the FMA calculation is performed using
797/// the `mul_add` method (`s.mul_add(a, b)`).
798/// If not enabled, it's computed by unfused multiply-add (`s * a + b`).
799///
800/// # Examples
801///
802/// ```
803/// # use quaternion_core::{Vector3, Quaternion, hadamard_add};
804/// // --- Vector3 --- //
805/// let v1: Vector3<f64> = [1.0, 2.0, 3.0];
806/// let v2: Vector3<f64> = [0.1, 0.2, 0.3];
807/// let v3: Vector3<f64> = [0.4, 0.5, 0.6];
808/// let v_result = hadamard_add(v1, v2, v3);
809///
810/// assert!( (0.5 - v_result[0]).abs() < 1e-12 );
811/// assert!( (0.9 - v_result[1]).abs() < 1e-12 );
812/// assert!( (1.5 - v_result[2]).abs() < 1e-12 );
813///
814/// // --- Quaternion --- //
815/// let q1: Quaternion<f64> = (1.0, [2.0, 3.0, 4.0]);
816/// let q2: Quaternion<f64> = (0.1, [0.2, 0.3, 0.4]);
817/// let q3: Quaternion<f64> = (0.5, [0.6, 0.7, 0.8]);
818/// let q_result = hadamard_add(q1, q2, q3);
819///
820/// assert!( (0.6 - q_result.0).abs() < 1e-12 );
821/// assert!( (1.0 - q_result.1[0]).abs() < 1e-12 );
822/// assert!( (1.6 - q_result.1[1]).abs() < 1e-12 );
823/// assert!( (2.4 - q_result.1[2]).abs() < 1e-12 );
824/// ```
825#[inline]
826pub fn hadamard_add<T, U>(a: U, b: U, c: U) -> U
827where T: Float, U: QuaternionOps<T> {
828 a.hadamard_add(b, c)
829}
830
831/// Dot product of two quaternions (or vectors): `a · b`
832///
833/// # Examples
834///
835/// ```
836/// # use quaternion_core::{Vector3, Quaternion, dot};
837/// // --- Vector3 --- //
838/// let v1: Vector3<f64> = [1.0, 2.0, 3.0];
839/// let v2: Vector3<f64> = [0.1, 0.2, 0.3];
840///
841/// assert!( (1.4 - dot(v1, v2)).abs() < 1e-12 );
842///
843/// // --- Quaternion --- //
844/// let q1: Quaternion<f64> = (1.0, [2.0, 3.0, 4.0]);
845/// let q2: Quaternion<f64> = (0.1, [0.2, 0.3, 0.4]);
846///
847/// assert!( (3.0 - dot(q1, q2)).abs() < 1e-12 );
848/// ```
849#[inline]
850pub fn dot<T, U>(a: U, b: U) -> T
851where T: Float, U: QuaternionOps<T> {
852 a.dot(b)
853}
854
855/// Cross product of two quaternions (or vectors): `a × b`
856///
857/// The product order is `a × b (!= b × a)`
858///
859/// # Examples
860///
861/// ```
862/// # use quaternion_core::{Vector3, scale, cross};
863/// let v1: Vector3<f64> = [0.5, -1.0, 0.8];
864/// let v2: Vector3<f64> = scale(2.0, v1);
865/// let v_result = cross(v1, v2);
866///
867/// // The cross product of parallel vectors is a zero vector.
868/// assert!( v_result[0].abs() < 1e-12 );
869/// assert!( v_result[1].abs() < 1e-12 );
870/// assert!( v_result[2].abs() < 1e-12 );
871/// ```
872#[inline]
873pub fn cross<T>(a: Vector3<T>, b: Vector3<T>) -> Vector3<T>
874where T: Float {
875 [
876 a[1]*b[2] - a[2]*b[1],
877 a[2]*b[0] - a[0]*b[2],
878 a[0]*b[1] - a[1]*b[0],
879 ]
880}
881
882/// Calculate L2 norm of Vector3 or Quaternion.
883///
884/// Compared to `dot(a, a).sqrt()`, this function is less likely
885/// to cause overflow and underflow.
886///
887/// When the `norm-sqrt` feature is enabled, the default
888/// implementation is compiled with `dot(a, a).sqrt()` instead.
889///
890/// # Examples
891///
892/// ```
893/// # use quaternion_core::{Vector3, Quaternion, sum, dot, norm};
894/// // --- Vector3 --- //
895/// let v: Vector3<f64> = [1.0, 2.0, 3.0];
896/// assert!( (14.0_f64.sqrt() - norm(v)).abs() < 1e-12 );
897///
898/// // --- Quaternion --- //
899/// let q: Quaternion<f64> = (1.0, [2.0, 3.0, 4.0]);
900/// assert!( (30.0_f64.sqrt() - norm(q)).abs() < 1e-12 );
901///
902/// // --- Check about overflow --- //
903/// let v: Vector3<f32> = [1e15, 2e20, -3e15];
904/// assert_eq!( dot(v, v).sqrt(), f32::INFINITY ); // Oh...
905///
906/// #[cfg(not(feature = "norm-sqrt"))]
907/// assert_eq!( norm(v), 2e20 ); // Excellent!
908/// ```
909#[inline]
910pub fn norm<T, U>(a: U) -> T
911where T: Float, U: QuaternionOps<T> {
912 a.norm()
913}
914
915/// Normalization of Vector3 or Quaternion.
916///
917/// # Examples
918///
919/// ```
920/// # use quaternion_core::{Vector3, Quaternion, norm, normalize};
921/// // --- Vector3 --- //
922/// // This norm is not 1.
923/// let v: Vector3<f64> = [1.0, 2.0, 3.0];
924/// assert!( (1.0 - norm(v)).abs() > 1e-12 );
925///
926/// // Now that normalized, this norm is 1!
927/// let v_n = normalize(v);
928/// assert!( (1.0 - norm(v_n)).abs() < 1e-12 );
929///
930/// // --- Quaternion --- //
931/// // This norm is not 1.
932/// let q: Quaternion<f64> = (1.0, [2.0, 3.0, 4.0]);
933/// assert!( (1.0 - norm(q)).abs() > 1e-12 );
934///
935/// // Now that normalized, this norm is 1!
936/// let q_n = normalize(q);
937/// assert!( (1.0 - norm(q_n)).abs() < 1e-12 );
938/// ```
939#[inline]
940pub fn normalize<T, U>(a: U) -> U
941where T: Float, U: QuaternionOps<T> {
942 scale(norm(a).recip(), a)
943}
944
945/// Invert the sign of a Vector3 or Quaternion.
946///
947/// # Examples
948///
949/// ```
950/// # use quaternion_core::{Vector3, Quaternion, negate};
951/// // --- Vector3 --- //
952/// let v: Vector3<f64> = [1.0, 2.0, 3.0];
953/// let v_n = negate(v);
954///
955/// assert_eq!(-v[0], v_n[0]);
956/// assert_eq!(-v[1], v_n[1]);
957/// assert_eq!(-v[2], v_n[2]);
958///
959/// // --- Quaternion --- //
960/// let q: Quaternion<f64> = (1.0, [2.0, 3.0, 4.0]);
961/// let q_n = negate(q);
962///
963/// assert_eq!(-q.0, q_n.0);
964/// assert_eq!(-q.1[0], q_n.1[0]);
965/// assert_eq!(-q.1[1], q_n.1[1]);
966/// assert_eq!(-q.1[2], q_n.1[2]);
967/// ```
968#[inline]
969pub fn negate<T, U>(a: U) -> U
970where T: Float, U: QuaternionOps<T> {
971 a.negate()
972}
973
974/// Multiplication of two quaternions (or vectors).
975///
976/// This is an operation also known as the Hamilton product.
977/// In this operation, the vector is treated as a pure quaternoin (which is a quaternion with zero real part).
978///
979/// The product order is `ab (!= ba)`
980///
981/// # Examples
982///
983/// ```
984/// # use quaternion_core::{Vector3, Quaternion, inv, mul};
985/// // ---- Pure Quaternion (Vector3) ---- //
986/// let v: Vector3<f64> = [1.0, 2.0, 3.0];
987///
988/// // Identity quaternion
989/// let id = mul( v, inv(v) ); // = mul( inv(v), v );
990///
991/// assert!( (1.0 - id.0).abs() < 1e-12 );
992/// assert!( id.1[0].abs() < 1e-12 );
993/// assert!( id.1[1].abs() < 1e-12 );
994/// assert!( id.1[2].abs() < 1e-12 );
995///
996/// // ---- Quaternion ---- //
997/// let q: Quaternion<f64> = (1.0, [2.0, 3.0, 4.0]);
998///
999/// // Identity quaternion
1000/// let id = mul( q, inv(q) ); // = mul( inv(q), q );
1001///
1002/// assert!( (1.0 - id.0).abs() < 1e-12 );
1003/// assert!( id.1[0].abs() < 1e-12 );
1004/// assert!( id.1[1].abs() < 1e-12 );
1005/// assert!( id.1[2].abs() < 1e-12 );
1006/// ```
1007#[inline]
1008pub fn mul<T, U>(a: U, b: U) -> Quaternion<T>
1009where T: Float, U: QuaternionOps<T> {
1010 a.mul(b)
1011}
1012
1013/// Calculate the conjugate of Quaternion.
1014///
1015/// # Examples
1016///
1017/// ```
1018/// # use quaternion_core::{Quaternion, conj};
1019/// let q: Quaternion<f64> = (1.0, [2.0, 3.0, 4.0]);
1020/// let q_conj = conj(q);
1021///
1022/// assert_eq!( q.0, q_conj.0);
1023/// assert_eq!(-q.1[0], q_conj.1[0]);
1024/// assert_eq!(-q.1[1], q_conj.1[1]);
1025/// assert_eq!(-q.1[2], q_conj.1[2]);
1026/// ```
1027#[inline]
1028pub fn conj<T>(q: Quaternion<T>) -> Quaternion<T>
1029where T: Float {
1030 ( q.0, negate(q.1) )
1031}
1032
1033/// Calculate the inverse of Quaternion or Pure Quaternion (Vector3).
1034///
1035/// # Examples
1036///
1037/// ```
1038/// # use quaternion_core::{Vector3, Quaternion, inv, mul};
1039/// // ---- Pure Quaternion (Vector3) ---- //
1040/// let v: Vector3<f64> = [1.0, 2.0, 3.0];
1041///
1042/// // Identity quaternion
1043/// let id = mul( v, inv(v) ); // = mul( inv(v), v );
1044///
1045/// assert!( (id.0 - 1.0).abs() < 1e-12 );
1046/// assert!( id.1[0].abs() < 1e-12 );
1047/// assert!( id.1[1].abs() < 1e-12 );
1048/// assert!( id.1[2].abs() < 1e-12 );
1049///
1050/// // ---- Quaternion ---- //
1051/// let q: Quaternion<f64> = (1.0, [2.0, 3.0, 4.0]);
1052///
1053/// // Identity quaternion
1054/// let id = mul( q, inv(q) ); // = mul( inv(q), q );
1055///
1056/// assert!( (id.0 - 1.0).abs() < 1e-12 );
1057/// assert!( id.1[0].abs() < 1e-12 );
1058/// assert!( id.1[1].abs() < 1e-12 );
1059/// assert!( id.1[2].abs() < 1e-12 );
1060/// ```
1061#[inline]
1062pub fn inv<T, U>(a: U) -> U
1063where T: Float, U: QuaternionOps<T> {
1064 a.inv()
1065}
1066
1067// acosは[-pi/2, pi/2]の範囲でしか値を返さないので、qのとり方によってはlnで完全に復元できない。
1068// q == ln(exp(q)) が成り立つのはcos(norm(q.1))が[-pi/2, pi/2]の範囲内にある場合のみ。
1069/// Exponential function of Quaternion or Pure Quaternion (Vector3).
1070///
1071/// # Examples
1072///
1073/// ```
1074/// # use quaternion_core::{Vector3, Quaternion, scale, exp, ln};
1075/// // ---- Pure Quaternion (Vector3) ---- //
1076/// let v: Vector3<f64> = [0.1, 0.2, 0.3];
1077/// let v_r = ln( exp(v) );
1078///
1079/// assert!( v_r.0.abs() < 1e-12 );
1080/// assert!( (v[0] - v_r.1[0]).abs() < 1e-12 );
1081/// assert!( (v[1] - v_r.1[1]).abs() < 1e-12 );
1082/// assert!( (v[2] - v_r.1[2]).abs() < 1e-12 );
1083///
1084/// // ---- Quaternion ---- //
1085/// let q: Quaternion<f64> = (0.1, [0.2, 0.3, 0.4]);
1086/// let q_r = ln( exp(q) );
1087///
1088/// assert!( (q.0 - q_r.0).abs() < 1e-12 );
1089/// assert!( (q.1[0] - q_r.1[0]).abs() < 1e-12 );
1090/// assert!( (q.1[1] - q_r.1[1]).abs() < 1e-12 );
1091/// assert!( (q.1[2] - q_r.1[2]).abs() < 1e-12 );
1092///
1093/// // The relationship between exp(q) and exp(q.1)
1094/// let exp_q = exp(q);
1095/// let exp_check = scale( q.0.exp(), exp(q.1) );
1096/// assert!( (exp_q.0 - exp_check.0).abs() < 1e-12 );
1097/// assert!( (exp_q.1[0] - exp_check.1[0]).abs() < 1e-12 );
1098/// assert!( (exp_q.1[1] - exp_check.1[1]).abs() < 1e-12 );
1099/// assert!( (exp_q.1[2] - exp_check.1[2]).abs() < 1e-12 );
1100/// ```
1101#[inline]
1102pub fn exp<T, U>(a: U) -> Quaternion<T>
1103where T: Float, U: QuaternionOps<T> {
1104 a.exp()
1105}
1106
1107// acosは[-pi/2, pi/2]の範囲でしか値を返さないので、qのとり方によってはlnで完全に復元できない。
1108// q == ln(exp(q)) が成り立つのはcos(norm(q.1))が[-pi/2, pi/2]の範囲内にある場合のみ。
1109/// Natural logarithm of Quaternion.
1110///
1111/// # Examples
1112///
1113/// ```
1114/// # use quaternion_core::{Vector3, Quaternion, exp, ln};
1115/// let q: Quaternion<f64> = (0.1, [0.2, 0.3, 0.4]);
1116/// let q_r = ln( exp(q) );
1117///
1118/// assert!( (q.0 - q_r.0).abs() < 1e-12 );
1119/// assert!( (q.1[0] - q_r.1[0]).abs() < 1e-12 );
1120/// assert!( (q.1[1] - q_r.1[1]).abs() < 1e-12 );
1121/// assert!( (q.1[2] - q_r.1[2]).abs() < 1e-12 );
1122/// ```
1123#[inline]
1124pub fn ln<T>(q: Quaternion<T>) -> Quaternion<T>
1125where T: Float {
1126 let norm_v = norm(q.1);
1127 let norm_q = pfs::norm2(q.0, norm_v);
1128 let coef = (q.0 / norm_q).acos() / norm_v;
1129 ( norm_q.ln(), scale(coef, q.1) )
1130}
1131
1132// exp(q)の結果がVersorとなる条件は,qのスカラー部が0(つまりqが純虚四元数).
1133//
1134/// Natural logarithm of Versor.
1135///
1136/// If the argument `q` is guaranteed to be a Versor,
1137/// it is less calculation cost than the `ln(...)` function.
1138///
1139/// Only the vector part is returned since the real part is always zero.
1140///
1141/// # Examples
1142///
1143/// ```
1144/// # use quaternion_core::{Vector3, exp, ln_versor};
1145/// let v: Vector3<f64> = [0.1, 0.2, 0.3];
1146/// let r = ln_versor( exp(v) );
1147///
1148/// assert!( (v[0] - r[0]).abs() < 1e-12 );
1149/// assert!( (v[1] - r[1]).abs() < 1e-12 );
1150/// assert!( (v[2] - r[2]).abs() < 1e-12 );
1151/// ```
1152#[inline]
1153pub fn ln_versor<T>(q: Quaternion<T>) -> Vector3<T>
1154where T: Float {
1155 scale( q.0.acos() / norm(q.1), q.1)
1156}
1157
1158/// Power function of Quaternion.
1159///
1160/// # Examples
1161///
1162/// ```
1163/// # use quaternion_core::{Quaternion, mul, inv, pow, sqrt};
1164/// let q: Quaternion<f64> = (1.0, [2.0, 3.0, 4.0]);
1165///
1166/// let q_q = mul(q, q);
1167/// let q_pow_2 = pow(q, 2.0);
1168/// assert!( (q_q.0 - q_pow_2.0).abs() < 1e-12 );
1169/// assert!( (q_q.1[0] - q_pow_2.1[0]).abs() < 1e-12 );
1170/// assert!( (q_q.1[1] - q_pow_2.1[1]).abs() < 1e-12 );
1171/// assert!( (q_q.1[2] - q_pow_2.1[2]).abs() < 1e-12 );
1172///
1173/// let q_sqrt = sqrt(q);
1174/// let q_pow_0p5 = pow(q, 0.5);
1175/// assert!( (q_sqrt.0 - q_pow_0p5.0).abs() < 1e-12 );
1176/// assert!( (q_sqrt.1[0] - q_pow_0p5.1[0]).abs() < 1e-12 );
1177/// assert!( (q_sqrt.1[1] - q_pow_0p5.1[1]).abs() < 1e-12 );
1178/// assert!( (q_sqrt.1[2] - q_pow_0p5.1[2]).abs() < 1e-12 );
1179///
1180/// let q_inv = inv(q);
1181/// let q_pow_m1 = pow(q, -1.0);
1182/// assert!( (q_inv.0 - q_pow_m1.0).abs() < 1e-12 );
1183/// assert!( (q_inv.1[0] - q_pow_m1.1[0]).abs() < 1e-12 );
1184/// assert!( (q_inv.1[1] - q_pow_m1.1[1]).abs() < 1e-12 );
1185/// assert!( (q_inv.1[2] - q_pow_m1.1[2]).abs() < 1e-12 );
1186/// ```
1187#[inline]
1188pub fn pow<T>(q: Quaternion<T>, t: T) -> Quaternion<T>
1189where T: Float {
1190 let norm_v = norm(q.1);
1191 let norm_q = pfs::norm2(q.0, norm_v);
1192 let omega = (q.0 / norm_q).acos();
1193 let (sin, cos) = (t * omega).sin_cos();
1194 let coef = norm_q.powf(t);
1195 ( coef * cos, scale((coef / norm_v) * sin, q.1) )
1196}
1197
1198/// Power function of Versor.
1199///
1200/// If the argument `q` is guaranteed to be a Versor,
1201/// it is less calculation cost than the `pow(...)` function.
1202///
1203/// # Examples
1204///
1205/// ```
1206/// # use quaternion_core::{Quaternion, normalize, mul, inv, pow_versor, sqrt};
1207/// let q: Quaternion<f64> = normalize( (1.0, [2.0, 3.0, 4.0]) );
1208///
1209/// let q_q = mul(q, q);
1210/// let q_pow_2 = pow_versor(q, 2.0);
1211/// assert!( (q_q.0 - q_pow_2.0).abs() < 1e-12 );
1212/// assert!( (q_q.1[0] - q_pow_2.1[0]).abs() < 1e-12 );
1213/// assert!( (q_q.1[1] - q_pow_2.1[1]).abs() < 1e-12 );
1214/// assert!( (q_q.1[2] - q_pow_2.1[2]).abs() < 1e-12 );
1215///
1216/// let q_sqrt = sqrt(q);
1217/// let q_pow_0p5 = pow_versor(q, 0.5);
1218/// assert!( (q_sqrt.0 - q_pow_0p5.0).abs() < 1e-12 );
1219/// assert!( (q_sqrt.1[0] - q_pow_0p5.1[0]).abs() < 1e-12 );
1220/// assert!( (q_sqrt.1[1] - q_pow_0p5.1[1]).abs() < 1e-12 );
1221/// assert!( (q_sqrt.1[2] - q_pow_0p5.1[2]).abs() < 1e-12 );
1222///
1223/// let q_inv = inv(q);
1224/// let q_pow_m1 = pow_versor(q, -1.0);
1225/// assert!( (q_inv.0 - q_pow_m1.0).abs() < 1e-12 );
1226/// assert!( (q_inv.1[0] - q_pow_m1.1[0]).abs() < 1e-12 );
1227/// assert!( (q_inv.1[1] - q_pow_m1.1[1]).abs() < 1e-12 );
1228/// assert!( (q_inv.1[2] - q_pow_m1.1[2]).abs() < 1e-12 );
1229/// ```
1230#[inline]
1231pub fn pow_versor<T>(q: Quaternion<T>, t: T) -> Quaternion<T>
1232where T: Float {
1233 let (sin, cos) = (t * q.0.acos()).sin_cos();
1234 ( cos, scale(sin / norm(q.1), q.1) )
1235}
1236
1237/// Square root of Quaternion.
1238///
1239/// # Examples
1240///
1241/// ```
1242/// # use quaternion_core::{Quaternion, mul, sqrt};
1243/// let q: Quaternion<f64> = (1.0, [2.0, 3.0, 4.0]);
1244/// let q_sqrt = sqrt(q);
1245///
1246/// let result = mul(q_sqrt, q_sqrt);
1247/// assert!( (q.0 - result.0).abs() < 1e-12 );
1248/// assert!( (q.1[0] - result.1[0]).abs() < 1e-12 );
1249/// assert!( (q.1[1] - result.1[1]).abs() < 1e-12 );
1250/// assert!( (q.1[2] - result.1[2]).abs() < 1e-12 );
1251/// ```
1252#[inline]
1253pub fn sqrt<T>(q: Quaternion<T>) -> Quaternion<T>
1254where T: Float {
1255 let half = pfs::cast(0.5);
1256 let norm_v = norm(q.1);
1257 let norm_q = pfs::norm2(q.0, norm_v);
1258 let coef = ((norm_q - q.0) * half).sqrt() / norm_v;
1259 ( ((norm_q + q.0) * half).sqrt(), scale(coef, q.1) )
1260}
1261
1262/// Square root of Versor.
1263///
1264/// If the argument `q` is guaranteed to be a Versor,
1265/// it is less calculation cost than the `sqrt(...)` function.
1266///
1267/// # Examples
1268///
1269/// ```
1270/// # use quaternion_core::{Quaternion, normalize, mul, sqrt_versor};
1271/// let q: Quaternion<f64> = normalize( (1.0, [2.0, 3.0, 4.0]) );
1272/// let q_sqrt = sqrt_versor(q);
1273///
1274/// let result = mul(q_sqrt, q_sqrt);
1275/// assert!( (q.0 - result.0).abs() < 1e-12 );
1276/// assert!( (q.1[0] - result.1[0]).abs() < 1e-12 );
1277/// assert!( (q.1[1] - result.1[1]).abs() < 1e-12 );
1278/// assert!( (q.1[2] - result.1[2]).abs() < 1e-12 );
1279/// ```
1280#[inline]
1281pub fn sqrt_versor<T>(q: Quaternion<T>) -> Quaternion<T>
1282where T: Float {
1283 let half = pfs::cast(0.5);
1284 let coef = (half - q.0 * half).sqrt() / norm(q.1);
1285 ( pfs::mul_add(q.0, half, half).sqrt(), scale(coef, q.1) )
1286}
1287
1288/// Point rotation by quaternion (Point Rotation - Frame Fixed)
1289///
1290/// `q v q* (||q|| = 1)`
1291///
1292/// Since it is implemented with an optimized formula,
1293/// it can be calculated with the amount of operations shown in the table below:
1294///
1295/// | Operation | Num |
1296/// |:------------:|:---:|
1297/// | Multiply | 18 |
1298/// | Add/Subtract | 12 |
1299///
1300/// # Examples
1301///
1302/// ```
1303/// # use quaternion_core::{from_axis_angle, point_rotation, mul, conj};
1304/// # let PI = std::f64::consts::PI;
1305/// // Make these as you like.
1306/// let v = [1.0, 0.5, -8.0];
1307/// let q = from_axis_angle([0.2, 1.0, -2.0], PI);
1308///
1309/// let r = point_rotation(q, v);
1310///
1311/// // This makes a lot of wasted calculations.
1312/// let r_check = mul( mul(q, (0.0, v)), conj(q) ).1;
1313///
1314/// assert!( (r[0] - r_check[0]).abs() < 1e-12 );
1315/// assert!( (r[1] - r_check[1]).abs() < 1e-12 );
1316/// assert!( (r[2] - r_check[2]).abs() < 1e-12 );
1317/// ```
1318#[inline]
1319pub fn point_rotation<T>(q: Quaternion<T>, v: Vector3<T>) -> Vector3<T>
1320where T: Float {
1321 let tmp = scale_add(q.0, v, cross(q.1, v));
1322 scale_add(pfs::cast(2.0), cross(q.1, tmp), v)
1323}
1324
1325/// Frame rotation by quaternion (Frame Rotation - Point Fixed)
1326///
1327/// `q* v q (||q|| = 1)`
1328///
1329/// Since it is implemented with an optimized formula,
1330/// it can be calculated with the amount of operations shown in the table below:
1331///
1332/// | Operation | Num |
1333/// |:------------:|:---:|
1334/// | Multiply | 18 |
1335/// | Add/Subtract | 12 |
1336///
1337/// # Examples
1338///
1339/// ```
1340/// # use quaternion_core::{from_axis_angle, point_rotation, mul, conj};
1341/// # let PI = std::f64::consts::PI;
1342/// // Make these as you like.
1343/// let v = [1.0, 0.5, -8.0];
1344/// let q = from_axis_angle([0.2, 1.0, -2.0], PI);
1345///
1346/// let r = point_rotation(q, v);
1347///
1348/// // This makes a lot of wasted calculations.
1349/// let r_check = mul( mul(conj(q), (0.0, v)), q ).1;
1350///
1351/// assert!( (r[0] - r_check[0]).abs() < 1e-12 );
1352/// assert!( (r[1] - r_check[1]).abs() < 1e-12 );
1353/// assert!( (r[2] - r_check[2]).abs() < 1e-12 );
1354/// ```
1355#[inline]
1356pub fn frame_rotation<T>(q: Quaternion<T>, v: Vector3<T>) -> Vector3<T>
1357where T: Float {
1358 let tmp = scale_add(q.0, v, cross(v, q.1));
1359 scale_add(pfs::cast(2.0), cross(tmp, q.1), v)
1360}
1361
1362/// Calculate the versor to rotate from vector `a` to vector `b` (Without singularity!).
1363///
1364/// This function calculates `q` satisfying `b = point_rotation(q, a)` when `norm(a) = norm(b)`.
1365///
1366/// If `norm(a) > 0` and `norm(b) > 0`, then `q` can be calculated with good
1367/// accuracy no matter what the positional relationship between `a` and `b` is.
1368/// However, this function does not guarantee what the axis of rotation will be.
1369/// If you want the rotation axis to be orthogonal to vectors `a` and `b`, you can use `rotate_a_to_b_shotest`.
1370///
1371/// If you enter a zero vector either `a` or `b`, it returns `None`.
1372///
1373/// # Examples
1374///
1375/// ```
1376/// # use quaternion_core::{Vector3, cross, rotate_a_to_b, point_rotation, normalize};
1377/// let a: Vector3<f64> = [1.5, -0.5, 0.2];
1378/// let b: Vector3<f64> = [0.1, 0.6, 1.0];
1379///
1380/// let q = rotate_a_to_b(a, b).unwrap();
1381/// let b_check = point_rotation(q, a);
1382///
1383/// let b_u = normalize(b);
1384/// let b_check_u = normalize(b_check);
1385/// assert!( (b_u[0] - b_check_u[0]).abs() < 1e-12 );
1386/// assert!( (b_u[1] - b_check_u[1]).abs() < 1e-12 );
1387/// assert!( (b_u[2] - b_check_u[2]).abs() < 1e-12 );
1388/// ```
1389#[inline]
1390pub fn rotate_a_to_b<T>(a: Vector3<T>, b: Vector3<T>) -> Option<Quaternion<T>>
1391where T: Float {
1392 let norm_inv_a = norm(a).recip();
1393 let norm_inv_b = norm(b).recip();
1394 if norm_inv_a.is_infinite() || norm_inv_b.is_infinite() {
1395 return None;
1396 }
1397 let a = scale(norm_inv_a, a);
1398 let b = scale(norm_inv_b, b);
1399
1400 let a_add_b = add(a, b);
1401 let dot_a_add_b = dot(a_add_b, a_add_b);
1402 if dot_a_add_b >= T::one() { // arccos(a・b) = 120degで切り替え
1403 Some( (T::zero(), scale(dot_a_add_b.sqrt().recip(), a_add_b)) )
1404 } else {
1405 let norm_a_sub_b = (pfs::cast::<T>(4.0) - dot_a_add_b).sqrt();
1406 let axis_a2mb = scale(norm_a_sub_b.recip(), sub(a, b)); // a ==> -b
1407 let axis_mb2b = pfs::orthogonal_vector(b); // -b ==> b
1408 Some( mul(axis_mb2b, axis_a2mb) )
1409 }
1410}
1411
1412/// Calculate the versor to rotate from vector `a` to vector `b` by the shortest path.
1413///
1414/// This function calculates `q` satisfying `b = point_rotation(q, a)` when `norm(a) = norm(b)`.
1415/// The rotation axis of `q` is always perpendicular to `a` and `b`, and the rotation angle around
1416/// the axis ranges from -Pi to +Pi radians.
1417///
1418/// If `norm(a) > 0` and `norm(b) > 0`, `q` can be calculated with high accuracy regardless of the
1419/// relative positions of `a` and `b`.
1420/// However, if `a` and `b` are parallel and in opposite directions, the direction of the rotation
1421/// axis is not determined in principle, so there is no guarantee what the rotation axis will be
1422/// in this case (it is guaranteed that it is perpendicular to `a` and `b`).
1423///
1424/// The parameter `t` adjusts the amount of movement from `a` to `b`.
1425/// When `t = 1`, `a` moves completely to position `b`.
1426///
1427/// If you enter a zero vector either `a` or `b`, it returns `None`.
1428///
1429/// This function is slightly more computationally intensive when the angle between `a` and `b`
1430/// is close to PI, so it is recommended to use the `rotate_a_to_b` function if it is okay for
1431/// the rotation axis to not be orthogonal to `a` and `b`.
1432///
1433/// # Examples
1434///
1435/// ```
1436/// # use quaternion_core::{Vector3, cross, rotate_a_to_b_shortest, point_rotation, normalize};
1437/// let a: Vector3<f64> = [1.5, -0.5, 0.2];
1438/// let b: Vector3<f64> = [0.1, 0.6, 1.0];
1439///
1440/// let q = rotate_a_to_b_shortest(a, b, 1.0).unwrap();
1441/// let b_check = point_rotation(q, a);
1442///
1443/// let b_u = normalize(b);
1444/// let b_check_u = normalize(b_check);
1445/// assert!( (b_u[0] - b_check_u[0]).abs() < 1e-12 );
1446/// assert!( (b_u[1] - b_check_u[1]).abs() < 1e-12 );
1447/// assert!( (b_u[2] - b_check_u[2]).abs() < 1e-12 );
1448/// ```
1449#[inline]
1450pub fn rotate_a_to_b_shortest<T>(a: Vector3<T>, b: Vector3<T>, t: T) -> Option<Quaternion<T>>
1451where T: Float {
1452 let norm_inv_a = norm(a).recip();
1453 let norm_inv_b = norm(b).recip();
1454 if norm_inv_a.is_infinite() || norm_inv_b.is_infinite() {
1455 return None;
1456 }
1457 let a = scale(norm_inv_a, a);
1458 let b = scale(norm_inv_b, b);
1459
1460 let one = T::one();
1461 let half = pfs::cast::<T>(0.5);
1462 let a_dot_b = dot(a, b); // == cos(theta)
1463 let q_a2b = if a_dot_b > pfs::cast(-0.94) { // theta < 160 deg
1464 let q_s = (half * (one + a_dot_b)).sqrt(); // == cos(theta/2)
1465 (q_s, scale(half / q_s, cross(a, b))) // a --> b
1466 } else {
1467 let b_cross_a = cross(b, a);
1468 let q_s = (half * (one - a_dot_b)).sqrt(); // == cos((pi-theta)/2)
1469 let q_a2mb = (q_s, scale(half / q_s, b_cross_a)); // a --> -b
1470 let r_o = pfs::orthogonal_vector(b);
1471
1472 let c = sub(b_cross_a, r_o);
1473 let norm_c = norm(c); // norm_c > 0
1474 let r_o_cross_c = cross(r_o, c);
1475 let mut sin_rho = norm(r_o_cross_c) / norm_c; // (-1, 1)
1476 if dot(r_o_cross_c, b) < T::zero() {
1477 sin_rho = -sin_rho;
1478 }
1479 let cos_rho = (one - sin_rho * sin_rho).sqrt(); // (0, 1)
1480
1481 // r_o と b_cross_a の間の角度lambdaを求める
1482 let numer = norm_c * sin_rho;
1483 let denom = one - norm_c * cos_rho;
1484 let lambda = numer.atan2(denom); // (-pi, pi]
1485
1486 let (sin, cos) = (half * lambda).sin_cos();
1487 let q_b = (cos, scale(sin, b));
1488 let r = point_rotation(q_b, r_o); // -b --> a
1489
1490 let q_a2b_s = -dot(r, q_a2mb.1);
1491 let q_a2b_v = scale_add(q_a2mb.0, r, cross(r, q_a2mb.1));
1492 (q_a2b_s, q_a2b_v) // a --> b
1493 };
1494
1495 // 特異点を避けるために回転ベクトルを経由する
1496 let r = to_rotation_vector(q_a2b);
1497 let q_a2b = from_rotation_vector(scale(t, r));
1498
1499 Some( q_a2b )
1500}
1501
1502/// Lerp (Linear interpolation)
1503///
1504/// Generate a Versor that interpolate the shortest path from `a` to `b`.
1505/// The argument `t (0 <= t <= 1)` is the interpolation parameter.
1506///
1507/// The arguments `a` and `b` must be Versor.
1508///
1509/// Normalization is not performed internally because
1510/// it increases the computational complexity.
1511#[inline]
1512pub fn lerp<T>(a: Quaternion<T>, b: Quaternion<T>, t: T) -> Quaternion<T>
1513where T: Float {
1514 // 最短経路で補間する
1515 if dot(a, b).is_sign_negative() {
1516 // bの符号を反転
1517 scale_add(-t, add(a, b), a)
1518 } else {
1519 scale_add( t, sub(b, a), a)
1520 }
1521}
1522
1523/// Slerp (Spherical linear interpolation)
1524///
1525/// Generate a Versor that interpolate the shortest path from `a` to `b`.
1526/// The argument `t (0 <= t <= 1)` is the interpolation parameter.
1527///
1528/// The arguments `a` and `b` must be Versor.
1529#[inline]
1530pub fn slerp<T>(a: Quaternion<T>, mut b: Quaternion<T>, t: T) -> Quaternion<T>
1531where T: Float {
1532 // 最短経路で補間する
1533 let mut dot = dot(a, b);
1534 if dot.is_sign_negative() {
1535 b = negate(b);
1536 dot = -dot;
1537 }
1538 // If the distance between quaternions is close enough, use lerp.
1539 if dot > pfs::cast(0.9995) { // Approximation error < 0.017%
1540 scale_add(t, sub(b, a), a) // lerp
1541 } else {
1542 let omega = dot.acos(); // Angle between the two quaternions.
1543 let tmp = t * omega;
1544 let s1 = (omega - tmp).sin();
1545 let s2 = tmp.sin();
1546 let coef = (T::one() - dot*dot).sqrt().recip();
1547 let term1 = scale(s1 * coef, a);
1548 let term2 = scale(s2 * coef, b);
1549 add(term1, term2)
1550 }
1551}