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}