com_croftsoft_core/math/axis/
mod.rs

1// =============================================================================
2//! - Axis-angle (used in 3D graphics)
3//!
4//! # Metadata
5//! - Copyright: © 2008 - 2022 [`CroftSoft Inc`]
6//! - Author: [`David Wallace Croft`]
7//! - Rust version: 2022-10-14
8//! - Rust since: 2022-10-10
9//! - Java version: 2008-05-09
10//! - Java since: 2008-05-09
11//!
12//! # History
13//! - Adapted from the Java package com.croftsoft.core.math.axis
14//!   - In the Java-based [`CroftSoft Core Library`]
15//!
16//! [`CroftSoft Core Library`]: https://www.croftsoft.com/library/code/
17//! [`CroftSoft Inc`]: https://www.croftsoft.com/
18//! [`David Wallace Croft`]: https://www.croftsoft.com/people/david/
19// =============================================================================
20
21use super::{matrix::structures::Matrix, quat::Quat};
22
23#[cfg(test)]
24mod test;
25
26#[derive(Clone, Copy, Debug, PartialEq)]
27pub struct AxisAngle {
28  pub radians: f64,
29  pub x: f64,
30  pub y: f64,
31  pub z: f64,
32}
33
34impl AxisAngle {
35  // ---------------------------------------------------------------------------
36  /// Distance from the origin
37  // ---------------------------------------------------------------------------
38  pub fn magnitude(&self) -> f64 {
39    let x = self.x;
40    let y = self.y;
41    let z = self.z;
42    (x * x + y * y + z * z).sqrt()
43  }
44
45  // ---------------------------------------------------------------------------
46  /// Returns false if any difference magnitude is greater than the tolerance.
47  ///
48  /// The tolerance should be a positive number.
49  // ---------------------------------------------------------------------------
50  pub fn matches_closely(
51    &self,
52    other: &Self,
53    tolerance: f64,
54  ) -> bool {
55    (self.radians - other.radians).abs() <= tolerance
56      && (self.x - other.x).abs() <= tolerance
57      && (self.y - other.y).abs() <= tolerance
58      && (self.z - other.z).abs() <= tolerance
59  }
60
61  // ---------------------------------------------------------------------------
62  /// Returns false if any field value of other differs from the value of self
63  // ---------------------------------------------------------------------------
64  pub fn matches_exactly(
65    &self,
66    other: &Self,
67  ) -> bool {
68    self.radians == other.radians
69      && self.x == other.x
70      && self.y == other.y
71      && self.z == other.z
72  }
73
74  // ---------------------------------------------------------------------------
75  /// Divides each entry by the magnitude and then returns a reference to self
76  // ---------------------------------------------------------------------------
77  pub fn normalize(&mut self) -> &mut Self {
78    let magnitude = self.magnitude();
79    self.x /= magnitude;
80    self.y /= magnitude;
81    self.z /= magnitude;
82    self
83  }
84}
85
86// Default ---------------------------------------------------------------------
87
88impl Default for AxisAngle {
89  fn default() -> Self {
90    Self {
91      radians: 0.0,
92      x: 1.0,
93      y: 0.0,
94      z: 0.0,
95    }
96  }
97}
98
99// From ------------------------------------------------------------------------
100
101impl From<AxisAngle> for Matrix<3, 3> {
102  fn from(axis_angle: AxisAngle) -> Self {
103    let AxisAngle {
104      radians,
105      x,
106      y,
107      z,
108    } = axis_angle;
109    let c = radians.cos();
110    let s = radians.sin();
111    // Lengyel, "Mathematics for 3D Game Programming & Computer Graphics",
112    // Second Edition, p80, equation 3.22.
113    Matrix {
114      rows: [
115        [
116          c + (1.0 - c) * x * x,
117          (1.0 - c) * x * y - s * z,
118          (1.0 - c) * x * z + s * y,
119        ],
120        [
121          (1.0 - c) * x * y + s * z,
122          c + (1.0 - c) * y * y,
123          (1.0 - c) * y * z - s * x,
124        ],
125        [
126          (1.0 - c) * x * z - s * y,
127          (1.0 - c) * y * z + s * x,
128          c + (1.0 - c) * z * z,
129        ],
130      ],
131    }
132  }
133}
134
135impl From<AxisAngle> for Quat {
136  fn from(axis_angle: AxisAngle) -> Self {
137    let half_radians = axis_angle.radians / 2.0;
138    let sin_half_radians = half_radians.sin();
139    Quat {
140      w: half_radians.cos(),
141      x: sin_half_radians * axis_angle.x,
142      y: sin_half_radians * axis_angle.y,
143      z: sin_half_radians * axis_angle.z,
144    }
145  }
146}