quaternion_core/
lib.rs

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