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}