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}