@lakuna/umath 1.3.9 → 1.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (162) hide show
  1. package/README.md +1 -1
  2. package/dist/algorithms/approx.d.ts +9 -0
  3. package/dist/algorithms/approx.d.ts.map +1 -0
  4. package/dist/algorithms/approx.js +12 -0
  5. package/dist/algorithms/approx.js.map +1 -0
  6. package/dist/algorithms/approxRelative.d.ts +9 -0
  7. package/dist/algorithms/approxRelative.d.ts.map +1 -0
  8. package/dist/algorithms/approxRelative.js +12 -0
  9. package/dist/algorithms/approxRelative.js.map +1 -0
  10. package/dist/algorithms/combinations.d.ts +2 -1
  11. package/dist/algorithms/combinations.d.ts.map +1 -1
  12. package/dist/algorithms/combinations.js +2 -1
  13. package/dist/algorithms/combinations.js.map +1 -1
  14. package/dist/algorithms/degreesToRadians.d.ts +3 -2
  15. package/dist/algorithms/degreesToRadians.d.ts.map +1 -1
  16. package/dist/algorithms/degreesToRadians.js +5 -3
  17. package/dist/algorithms/degreesToRadians.js.map +1 -1
  18. package/dist/algorithms/factorial.d.ts +2 -1
  19. package/dist/algorithms/factorial.d.ts.map +1 -1
  20. package/dist/algorithms/factorial.js +2 -1
  21. package/dist/algorithms/factorial.js.map +1 -1
  22. package/dist/algorithms/fibonacci.d.ts +2 -1
  23. package/dist/algorithms/fibonacci.d.ts.map +1 -1
  24. package/dist/algorithms/fibonacci.js +6 -2
  25. package/dist/algorithms/fibonacci.js.map +1 -1
  26. package/dist/algorithms/greatestCommonDivisor.d.ts +4 -2
  27. package/dist/algorithms/greatestCommonDivisor.d.ts.map +1 -1
  28. package/dist/algorithms/greatestCommonDivisor.js +5 -2
  29. package/dist/algorithms/greatestCommonDivisor.js.map +1 -1
  30. package/dist/algorithms/hypergeometricPmf.d.ts +3 -2
  31. package/dist/algorithms/hypergeometricPmf.d.ts.map +1 -1
  32. package/dist/algorithms/hypergeometricPmf.js +3 -2
  33. package/dist/algorithms/hypergeometricPmf.js.map +1 -1
  34. package/dist/algorithms/isPrime.d.ts +2 -1
  35. package/dist/algorithms/isPrime.d.ts.map +1 -1
  36. package/dist/algorithms/isPrime.js +2 -1
  37. package/dist/algorithms/isPrime.js.map +1 -1
  38. package/dist/algorithms/permutations.d.ts +2 -1
  39. package/dist/algorithms/permutations.d.ts.map +1 -1
  40. package/dist/algorithms/permutations.js +2 -1
  41. package/dist/algorithms/permutations.js.map +1 -1
  42. package/dist/algorithms/primeFactorization.d.ts +2 -1
  43. package/dist/algorithms/primeFactorization.d.ts.map +1 -1
  44. package/dist/algorithms/primeFactorization.js +2 -1
  45. package/dist/algorithms/primeFactorization.js.map +1 -1
  46. package/dist/algorithms/radiansToDegrees.d.ts +3 -2
  47. package/dist/algorithms/radiansToDegrees.d.ts.map +1 -1
  48. package/dist/algorithms/radiansToDegrees.js +5 -3
  49. package/dist/algorithms/radiansToDegrees.js.map +1 -1
  50. package/dist/algorithms/summation.d.ts +2 -1
  51. package/dist/algorithms/summation.d.ts.map +1 -1
  52. package/dist/algorithms/summation.js +2 -1
  53. package/dist/algorithms/summation.js.map +1 -1
  54. package/dist/linalg/DualQuaternion.d.ts +102 -32
  55. package/dist/linalg/DualQuaternion.d.ts.map +1 -1
  56. package/dist/linalg/DualQuaternion.js +243 -272
  57. package/dist/linalg/DualQuaternion.js.map +1 -1
  58. package/dist/linalg/Matrix.d.ts +14 -10
  59. package/dist/linalg/Matrix.d.ts.map +1 -1
  60. package/dist/linalg/Matrix2.d.ts +74 -51
  61. package/dist/linalg/Matrix2.d.ts.map +1 -1
  62. package/dist/linalg/Matrix2.js +95 -171
  63. package/dist/linalg/Matrix2.js.map +1 -1
  64. package/dist/linalg/Matrix3.d.ts +122 -72
  65. package/dist/linalg/Matrix3.d.ts.map +1 -1
  66. package/dist/linalg/Matrix3.js +186 -355
  67. package/dist/linalg/Matrix3.js.map +1 -1
  68. package/dist/linalg/Matrix4.d.ts +266 -149
  69. package/dist/linalg/Matrix4.d.ts.map +1 -1
  70. package/dist/linalg/Matrix4.js +512 -852
  71. package/dist/linalg/Matrix4.js.map +1 -1
  72. package/dist/linalg/Quaternion.d.ts +252 -34
  73. package/dist/linalg/Quaternion.d.ts.map +1 -1
  74. package/dist/linalg/Quaternion.js +436 -166
  75. package/dist/linalg/Quaternion.js.map +1 -1
  76. package/dist/linalg/SlowMatrix.d.ts +10 -9
  77. package/dist/linalg/SlowMatrix.d.ts.map +1 -1
  78. package/dist/linalg/SlowMatrix.js +10 -9
  79. package/dist/linalg/SlowMatrix.js.map +1 -1
  80. package/dist/linalg/SlowSquareMatrix.d.ts +10 -9
  81. package/dist/linalg/SlowSquareMatrix.d.ts.map +1 -1
  82. package/dist/linalg/SlowSquareMatrix.js +10 -9
  83. package/dist/linalg/SlowSquareMatrix.js.map +1 -1
  84. package/dist/linalg/SquareMatrix.d.ts +6 -5
  85. package/dist/linalg/SquareMatrix.d.ts.map +1 -1
  86. package/dist/linalg/Vector.d.ts +8 -4
  87. package/dist/linalg/Vector.d.ts.map +1 -1
  88. package/dist/linalg/Vector2.d.ts +82 -31
  89. package/dist/linalg/Vector2.d.ts.map +1 -1
  90. package/dist/linalg/Vector2.js +112 -154
  91. package/dist/linalg/Vector2.js.map +1 -1
  92. package/dist/linalg/Vector3.d.ts +93 -41
  93. package/dist/linalg/Vector3.d.ts.map +1 -1
  94. package/dist/linalg/Vector3.js +171 -282
  95. package/dist/linalg/Vector3.js.map +1 -1
  96. package/dist/linalg/Vector4.d.ts +71 -21
  97. package/dist/linalg/Vector4.d.ts.map +1 -1
  98. package/dist/linalg/Vector4.js +121 -195
  99. package/dist/linalg/Vector4.js.map +1 -1
  100. package/dist/types/AxisAngle.d.ts +4 -1
  101. package/dist/types/AxisAngle.d.ts.map +1 -1
  102. package/dist/types/FieldOfView.d.ts +4 -1
  103. package/dist/types/FieldOfView.d.ts.map +1 -1
  104. package/dist/utility/BigNumber.d.ts +4 -1
  105. package/dist/utility/BigNumber.d.ts.map +1 -1
  106. package/dist/utility/BigNumber.js +4 -1
  107. package/dist/utility/BigNumber.js.map +1 -1
  108. package/dist/utility/MagnitudeError.d.ts +4 -1
  109. package/dist/utility/MagnitudeError.d.ts.map +1 -1
  110. package/dist/utility/MagnitudeError.js +4 -1
  111. package/dist/utility/MagnitudeError.js.map +1 -1
  112. package/dist/utility/MatrixSizeError.d.ts +4 -1
  113. package/dist/utility/MatrixSizeError.d.ts.map +1 -1
  114. package/dist/utility/MatrixSizeError.js +4 -1
  115. package/dist/utility/MatrixSizeError.js.map +1 -1
  116. package/dist/utility/PartialMatrixError.d.ts +4 -1
  117. package/dist/utility/PartialMatrixError.d.ts.map +1 -1
  118. package/dist/utility/PartialMatrixError.js +4 -1
  119. package/dist/utility/PartialMatrixError.js.map +1 -1
  120. package/dist/utility/SingularMatrixError.d.ts +2 -1
  121. package/dist/utility/SingularMatrixError.d.ts.map +1 -1
  122. package/dist/utility/SingularMatrixError.js +2 -1
  123. package/dist/utility/SingularMatrixError.js.map +1 -1
  124. package/dist/utility/epsilon.d.ts +4 -1
  125. package/dist/utility/epsilon.d.ts.map +1 -1
  126. package/dist/utility/epsilon.js +4 -1
  127. package/dist/utility/epsilon.js.map +1 -1
  128. package/package.json +11 -11
  129. package/src/algorithms/approx.ts +12 -0
  130. package/src/algorithms/approxRelative.ts +12 -0
  131. package/src/algorithms/combinations.ts +2 -1
  132. package/src/algorithms/degreesToRadians.ts +6 -3
  133. package/src/algorithms/factorial.ts +3 -1
  134. package/src/algorithms/fibonacci.ts +7 -2
  135. package/src/algorithms/greatestCommonDivisor.ts +9 -4
  136. package/src/algorithms/hypergeometricPmf.ts +3 -2
  137. package/src/algorithms/isPrime.ts +2 -1
  138. package/src/algorithms/permutations.ts +2 -1
  139. package/src/algorithms/primeFactorization.ts +2 -1
  140. package/src/algorithms/radiansToDegrees.ts +6 -3
  141. package/src/algorithms/summation.ts +2 -1
  142. package/src/linalg/DualQuaternion.ts +424 -289
  143. package/src/linalg/Matrix.ts +14 -10
  144. package/src/linalg/Matrix2.ts +141 -188
  145. package/src/linalg/Matrix3.ts +400 -375
  146. package/src/linalg/Matrix4.ts +1083 -905
  147. package/src/linalg/Quaternion.ts +706 -188
  148. package/src/linalg/SlowMatrix.ts +10 -9
  149. package/src/linalg/SlowSquareMatrix.ts +10 -9
  150. package/src/linalg/SquareMatrix.ts +6 -5
  151. package/src/linalg/Vector.ts +8 -4
  152. package/src/linalg/Vector2.ts +146 -173
  153. package/src/linalg/Vector3.ts +293 -326
  154. package/src/linalg/Vector4.ts +227 -215
  155. package/src/types/AxisAngle.ts +4 -1
  156. package/src/types/FieldOfView.ts +4 -1
  157. package/src/utility/BigNumber.ts +6 -3
  158. package/src/utility/MagnitudeError.ts +4 -1
  159. package/src/utility/MatrixSizeError.ts +4 -1
  160. package/src/utility/PartialMatrixError.ts +4 -1
  161. package/src/utility/SingularMatrixError.ts +2 -1
  162. package/src/utility/epsilon.ts +4 -1
@@ -1,22 +1,38 @@
1
- import { type Matrix3Like, createMatrix3Like } from "./Matrix3.js";
2
1
  import {
3
- add,
4
- copy,
5
- dot,
6
- equals,
7
- exactEquals,
8
- fromValues,
9
- getMagnitude,
10
- getSquaredMagnitude,
11
- lerp,
12
- normalize,
13
- scale
2
+ type Matrix3Like,
3
+ createMatrix3Like,
4
+ fromValues as matrix3FromValues
5
+ } from "./Matrix3.js";
6
+ import Vector3, {
7
+ type Vector3Like,
8
+ createVector3Like,
9
+ cross as vector3Cross,
10
+ dot as vector3Dot,
11
+ fromValues as vector3FromValues,
12
+ getMagnitude as vector3GetMagnitude,
13
+ normalize as vector3Normalize
14
+ } from "./Vector3.js";
15
+ import {
16
+ add as vector4Add,
17
+ copy as vector4Copy,
18
+ dot as vector4Dot,
19
+ exactEquals as vector4ExactEquals,
20
+ fromValues as vector4FromValues,
21
+ getMagnitude as vector4GetMagnitude,
22
+ getSquaredMagnitude as vector4GetSquaredMagnitude,
23
+ lerp as vector4Lerp,
24
+ normalize as vector4Normalize,
25
+ scale as vector4Scale
14
26
  } from "./Vector4.js";
15
27
  import type AxisAngle from "../types/AxisAngle.js";
16
- import type { Vector3Like } from "./Vector3.js";
17
28
  import epsilon from "../utility/epsilon.js";
29
+ import radiansToDegrees from "../algorithms/radiansToDegrees.js";
18
30
 
19
- /** A complex number that is commonly used to describe rotations. */
31
+ /**
32
+ * A complex number that is commonly used to describe rotations.
33
+ * @see {@link https://en.wikipedia.org/wiki/Quaternion | Quaternion}
34
+ * @public
35
+ */
20
36
  export interface QuaternionLike extends Record<number, number> {
21
37
  /** The first component of this quaternion. */
22
38
  0: number;
@@ -34,26 +50,167 @@ export interface QuaternionLike extends Record<number, number> {
34
50
  /**
35
51
  * Create a quaternion-like object.
36
52
  * @returns A quaternion-like object.
53
+ * @public
37
54
  */
38
- export const createQuaternionLike = () => {
55
+ export const createQuaternionLike = (): Float32Array & QuaternionLike => {
39
56
  return new Float32Array(4) as Float32Array & QuaternionLike;
40
57
  };
41
58
 
59
+ /**
60
+ * Create a quaternion with the given values.
61
+ * @param x - The first component.
62
+ * @param y - The second component.
63
+ * @param z - The third component.
64
+ * @param w - The fourth component.
65
+ * @param out - The quaternion to store the result in.
66
+ * @returns A new quaternion.
67
+ * @public
68
+ */
69
+ export const fromValues: <T extends QuaternionLike>(
70
+ x: number,
71
+ y: number,
72
+ z: number,
73
+ w: number,
74
+ out: T
75
+ ) => T = vector4FromValues;
76
+
77
+ /**
78
+ * Add two quaternions.
79
+ * @param a - The first quaternion
80
+ * @param b - The second quaternion.
81
+ * @param out - The quaternion to store the result in.
82
+ * @returns The sum of the quaternions.
83
+ * @public
84
+ */
85
+ export const add: <T extends QuaternionLike>(
86
+ a: QuaternionLike,
87
+ b: QuaternionLike,
88
+ out: T
89
+ ) => T = vector4Add;
90
+
91
+ /**
92
+ * Copy the values from one quaternion to another.
93
+ * @param quaternion - The quaternion to copy.
94
+ * @param out - The quaternion to store the result in.
95
+ * @returns The copy.
96
+ * @public
97
+ */
98
+ export const copy: <T extends QuaternionLike>(
99
+ quaternion: QuaternionLike,
100
+ out: T
101
+ ) => T = vector4Copy;
102
+
103
+ /**
104
+ * Calculate the dot product of two quaternions.
105
+ * @param a - The first quaternion
106
+ * @param b - The second quaternion.
107
+ * @returns The dot product.
108
+ * @public
109
+ */
110
+ export const dot: (a: QuaternionLike, b: QuaternionLike) => number = vector4Dot;
111
+
112
+ /**
113
+ * Determine whether or not two unit quaternions point in roughly the same direction.
114
+ * @param a - The first unit quaternion.
115
+ * @param b - The second unit quaternion.
116
+ * @returns Whether or not the unit quaternions point in the same direction.
117
+ * @public
118
+ */
119
+ export const equals = (a: QuaternionLike, b: QuaternionLike): boolean =>
120
+ Math.abs(dot(a, b)) >= 1 - epsilon;
121
+
122
+ /**
123
+ * Determine whether or not two quaternions are exactly equivalent.
124
+ * @param a - The first quaternion.
125
+ * @param b - The second quaternion.
126
+ * @returns Whether or not the quaternions are equivalent.
127
+ * @public
128
+ */
129
+ export const exactEquals: (a: QuaternionLike, b: QuaternionLike) => boolean =
130
+ vector4ExactEquals;
131
+
132
+ /**
133
+ * Calculate the magnitude (length) of a quaternion.
134
+ * @param quaternion - The quaternion.
135
+ * @returns The magnitude.
136
+ * @public
137
+ */
138
+ export const getMagnitude: (quaternion: QuaternionLike) => number =
139
+ vector4GetMagnitude;
140
+
141
+ /**
142
+ * Calculate the squared magnitude (length) of a quaternion.
143
+ * @param quaternion - The quaternion.
144
+ * @returns The squared magnitude.
145
+ * @public
146
+ */
147
+ export const getSquaredMagnitude: (quaternion: QuaternionLike) => number =
148
+ vector4GetSquaredMagnitude;
149
+
150
+ /**
151
+ * Perform a linear interpolation between two quaternions.
152
+ * @param a - The first quaternion.
153
+ * @param b - The second quaternion.
154
+ * @param t - The interpolation amount (in `[0,1]`).
155
+ * @param out - The quaternion to store the result in.
156
+ * @returns The interpolated quaternion.
157
+ * @see {@link https://en.wikipedia.org/wiki/Linear_interpolation | Linear interpolation}
158
+ * @public
159
+ */
160
+ export const lerp: <T extends QuaternionLike>(
161
+ a: QuaternionLike,
162
+ b: QuaternionLike,
163
+ t: number,
164
+ out: T
165
+ ) => T = vector4Lerp;
166
+
167
+ /**
168
+ * Normalize a quaternion.
169
+ * @param quaternion - The quaternion.
170
+ * @param out - The quaternion to store the result in.
171
+ * @returns The normalized quaternion.
172
+ * @public
173
+ */
174
+ export const normalize: <T extends QuaternionLike>(
175
+ vector: QuaternionLike,
176
+ out: T
177
+ ) => T = vector4Normalize;
178
+
179
+ /**
180
+ * Scale a quaternion by a scalar.
181
+ * @param quaternion - The multiplier.
182
+ * @param scalar - The multiplicand.
183
+ * @param out - The quaternion to store the result in.
184
+ * @returns The product.
185
+ * @public
186
+ */
187
+ export const scale: <T extends QuaternionLike>(
188
+ vector: QuaternionLike,
189
+ scalar: number,
190
+ out: T
191
+ ) => T = vector4Scale;
192
+
42
193
  /**
43
194
  * Create a quaternion from a three-by-three rotation matrix.
44
195
  * @param matrix - The matrix.
45
196
  * @param out - The quaternion to store the result in.
46
- * @returns The quaternion.
47
- * @see [Rotation matrix](https://en.wikipedia.org/wiki/Rotation_matrix)
197
+ * @returns The quaternion (not normalized).
198
+ * @see {@link https://en.wikipedia.org/wiki/Rotation_matrix | Rotation matrix}
199
+ * @see Ken Shoemake. Quaternion calculus and fast animation. SIGGRAPH Course Notes, 10:101-121, 1987.
200
+ * @public
48
201
  */
49
202
  export const fromMatrix3 = <T extends QuaternionLike>(
50
203
  matrix: Matrix3Like,
51
204
  out: T
52
205
  ): T => {
53
- const fTrace = matrix[0] + matrix[4] + matrix[8];
206
+ const m0 = matrix[0];
207
+ const m4 = matrix[4];
208
+ const m8 = matrix[8];
209
+
210
+ const fTrace = m0 + m4 + m8;
54
211
  if (fTrace > 0) {
55
212
  let fRoot = Math.sqrt(fTrace + 1);
56
- out[3] = 0.5 * fRoot;
213
+ out[3] = fRoot / 2;
57
214
  fRoot = 0.5 / fRoot;
58
215
  out[0] = (matrix[5] - matrix[7]) * fRoot;
59
216
  out[1] = (matrix[6] - matrix[2]) * fRoot;
@@ -62,10 +219,10 @@ export const fromMatrix3 = <T extends QuaternionLike>(
62
219
  }
63
220
 
64
221
  let i = 0 as 0 | 1 | 2;
65
- if (matrix[4] > matrix[0]) {
222
+ if (m4 > m0) {
66
223
  i = 1;
67
224
  }
68
- if (matrix[8] > matrix[(i * 3 + i) as 0 | 4]) {
225
+ if (m8 > matrix[(i * 3 + i) as 0 | 4]) {
69
226
  i = 2;
70
227
  }
71
228
  const j = ((i + 1) % 3) as 1 | 2 | 0;
@@ -77,7 +234,7 @@ export const fromMatrix3 = <T extends QuaternionLike>(
77
234
  matrix[(k * 3 + k) as 7 | 0 | 4] +
78
235
  1
79
236
  );
80
- out[i] = 0.5 * fRoot;
237
+ out[i] = fRoot / 2;
81
238
  fRoot = 0.5 / fRoot;
82
239
  out[3] =
83
240
  (matrix[(j * 3 + k) as 5 | 6 | 1] - matrix[(k * 3 + j) as 7 | 2 | 3]) *
@@ -91,26 +248,68 @@ export const fromMatrix3 = <T extends QuaternionLike>(
91
248
  return out;
92
249
  };
93
250
 
251
+ const ratio = Math.PI / 360;
252
+
94
253
  /**
95
- * Create a quaternion from equivalent X-Y-Z Tait-Bryan angles
96
- * @param x - The X angle.
97
- * @param y - The Y angle.
98
- * @param z - The Z angle.
254
+ * Create a quaternion from equivalent x-y'-z" (intrinsic) Tait-Bryan angles.
255
+ * @param x - The X angle in degrees.
256
+ * @param y - The Y angle in degrees.
257
+ * @param z - The Z angle in degrees.
99
258
  * @param out - The quaternion to store the result in.
100
259
  * @returns The quaternion.
101
- * @see [Euler angles](https://en.wikipedia.org/wiki/Euler_angles)
260
+ * @see {@link https://en.wikipedia.org/wiki/Euler_angles | Euler angles}
261
+ * @public
102
262
  */
103
- export const fromEuler = <T extends QuaternionLike>(
263
+ export const fromEulerXyz = <T extends QuaternionLike>(
104
264
  x: number,
105
265
  y: number,
106
266
  z: number,
107
267
  out: T
108
268
  ): T => {
109
- const r = (0.5 * Math.PI) / 180;
269
+ const x2 = x * ratio;
270
+ const y2 = y * ratio;
271
+ const z2 = z * ratio;
272
+
273
+ const sx = Math.sin(x2);
274
+ const cx = Math.cos(x2);
275
+ const sy = Math.sin(y2);
276
+ const cy = Math.cos(y2);
277
+ const sz = Math.sin(z2);
278
+ const cz = Math.cos(z2);
110
279
 
111
- const x2 = x * r;
112
- const y2 = y * r;
113
- const z2 = z * r;
280
+ const sxcy = sx * cy;
281
+ const cxsy = cx * sy;
282
+ const cxcy = cx * cy;
283
+ const sxsy = sx * sy;
284
+
285
+ return fromValues(
286
+ sxcy * cz - cxsy * sz,
287
+ cxsy * cz + sxcy * sz,
288
+ cxcy * sz - sxsy * cz,
289
+ cxcy * cz + sxsy * sz,
290
+ out
291
+ );
292
+ };
293
+
294
+ /**
295
+ * Create a quaternion from equivalent x-z'-y" (intrinsic) Tait-Bryan angles.
296
+ * @param x - The X angle in degrees.
297
+ * @param z - The Z angle in degrees.
298
+ * @param y - The Y angle in degrees.
299
+ * @param out - The quaternion to store the result in.
300
+ * @returns The quaternion.
301
+ * @see {@link https://en.wikipedia.org/wiki/Euler_angles | Euler angles}
302
+ * @public
303
+ */
304
+ export const fromEulerXzy = <T extends QuaternionLike>(
305
+ x: number,
306
+ z: number,
307
+ y: number,
308
+ out: T
309
+ ): T => {
310
+ const x2 = x * ratio;
311
+ const y2 = y * ratio;
312
+ const z2 = z * ratio;
114
313
 
115
314
  const sx = Math.sin(x2);
116
315
  const cx = Math.cos(x2);
@@ -119,60 +318,297 @@ export const fromEuler = <T extends QuaternionLike>(
119
318
  const sz = Math.sin(z2);
120
319
  const cz = Math.cos(z2);
121
320
 
122
- out[0] = sx * cy * cz - cx * sy * sz;
123
- out[1] = cx * sy * cz + sx * cy * sz;
124
- out[2] = cx * cy * sz - sx * sy * cz;
125
- out[3] = cx * cy * cz + sx * sy * sz;
126
- return out;
321
+ const sxcy = sx * cy;
322
+ const cxsy = cx * sy;
323
+ const cxcy = cx * cy;
324
+ const sxsy = sx * sy;
325
+
326
+ return fromValues(
327
+ sxcy * cz - cxsy * sz,
328
+ cxsy * cz - sxcy * sz,
329
+ cxcy * sz + sxsy * cz,
330
+ cxcy * cz + sxsy * sz,
331
+ out
332
+ );
333
+ };
334
+
335
+ /**
336
+ * Create a quaternion from equivalent y-x'-z" (intrinsic) Tait-Bryan angles.
337
+ * @param y - The Y angle in degrees.
338
+ * @param x - The X angle in degrees.
339
+ * @param z - The Z angle in degrees.
340
+ * @param out - The quaternion to store the result in.
341
+ * @returns The quaternion.
342
+ * @see {@link https://en.wikipedia.org/wiki/Euler_angles | Euler angles}
343
+ * @public
344
+ */
345
+ export const fromEulerYxz = <T extends QuaternionLike>(
346
+ y: number,
347
+ x: number,
348
+ z: number,
349
+ out: T
350
+ ): T => {
351
+ const x2 = x * ratio;
352
+ const y2 = y * ratio;
353
+ const z2 = z * ratio;
354
+
355
+ const sx = Math.sin(x2);
356
+ const cx = Math.cos(x2);
357
+ const sy = Math.sin(y2);
358
+ const cy = Math.cos(y2);
359
+ const sz = Math.sin(z2);
360
+ const cz = Math.cos(z2);
361
+
362
+ const sxcy = sx * cy;
363
+ const cxsy = cx * sy;
364
+ const cxcy = cx * cy;
365
+ const sxsy = sx * sy;
366
+
367
+ return fromValues(
368
+ sxcy * cz + cxsy * sz,
369
+ cxsy * cz - sxcy * sz,
370
+ cxcy * sz - sxsy * cz,
371
+ cxcy * cz + sxsy * sz,
372
+ out
373
+ );
374
+ };
375
+
376
+ /**
377
+ * Create a quaternion from equivalent y-z'-x" (intrinsic) Tait-Bryan angles.
378
+ * @param y - The Y angle in degrees.
379
+ * @param z - The Z angle in degrees.
380
+ * @param x - The X angle in degrees.
381
+ * @param out - The quaternion to store the result in.
382
+ * @returns The quaternion.
383
+ * @see {@link https://en.wikipedia.org/wiki/Euler_angles | Euler angles}
384
+ * @public
385
+ */
386
+ export const fromEulerYzx = <T extends QuaternionLike>(
387
+ y: number,
388
+ z: number,
389
+ x: number,
390
+ out: T
391
+ ): T => {
392
+ const x2 = x * ratio;
393
+ const y2 = y * ratio;
394
+ const z2 = z * ratio;
395
+
396
+ const sx = Math.sin(x2);
397
+ const cx = Math.cos(x2);
398
+ const sy = Math.sin(y2);
399
+ const cy = Math.cos(y2);
400
+ const sz = Math.sin(z2);
401
+ const cz = Math.cos(z2);
402
+
403
+ const sxcy = sx * cy;
404
+ const cxsy = cx * sy;
405
+ const cxcy = cx * cy;
406
+ const sxsy = sx * sy;
407
+
408
+ return fromValues(
409
+ sxcy * cz + cxsy * sz,
410
+ cxsy * cz + sxcy * sz,
411
+ cxcy * sz - sxsy * cz,
412
+ cxcy * cz - sxsy * sz,
413
+ out
414
+ );
415
+ };
416
+
417
+ /**
418
+ * Create a quaternion from equivalent z-x'-y" (intrinsic) Tait-Bryan angles.
419
+ * @param z - The Z angle in degrees.
420
+ * @param x - The X angle in degrees.
421
+ * @param y - The Y angle in degrees.
422
+ * @param out - The quaternion to store the result in.
423
+ * @returns The quaternion.
424
+ * @see {@link https://en.wikipedia.org/wiki/Euler_angles | Euler angles}
425
+ * @public
426
+ */
427
+ export const fromEulerZxy = <T extends QuaternionLike>(
428
+ z: number,
429
+ x: number,
430
+ y: number,
431
+ out: T
432
+ ): T => {
433
+ const x2 = x * ratio;
434
+ const y2 = y * ratio;
435
+ const z2 = z * ratio;
436
+
437
+ const sx = Math.sin(x2);
438
+ const cx = Math.cos(x2);
439
+ const sy = Math.sin(y2);
440
+ const cy = Math.cos(y2);
441
+ const sz = Math.sin(z2);
442
+ const cz = Math.cos(z2);
443
+
444
+ const sxcy = sx * cy;
445
+ const cxsy = cx * sy;
446
+ const cxcy = cx * cy;
447
+ const sxsy = sx * sy;
448
+
449
+ return fromValues(
450
+ sxcy * cz - cxsy * sz,
451
+ cxsy * cz + sxcy * sz,
452
+ cxcy * sz + sxsy * cz,
453
+ cxcy * cz - sxsy * sz,
454
+ out
455
+ );
456
+ };
457
+
458
+ /**
459
+ * Create a quaternion from equivalent z-y'-x" (intrinsic) Tait-Bryan angles.
460
+ * @param z - The Z angle (yaw) in degrees.
461
+ * @param y - The Y angle (pitch) in degrees.
462
+ * @param x - The X angle (roll) in degrees.
463
+ * @param out - The quaternion to store the result in.
464
+ * @returns The quaternion.
465
+ * @see {@link https://en.wikipedia.org/wiki/Euler_angles | Euler angles}
466
+ * @public
467
+ */
468
+ export const fromEulerZyx = <T extends QuaternionLike>(
469
+ z: number,
470
+ y: number,
471
+ x: number,
472
+ out: T
473
+ ): T => {
474
+ const x2 = x * ratio;
475
+ const y2 = y * ratio;
476
+ const z2 = z * ratio;
477
+
478
+ const sx = Math.sin(x2);
479
+ const cx = Math.cos(x2);
480
+ const sy = Math.sin(y2);
481
+ const cy = Math.cos(y2);
482
+ const sz = Math.sin(z2);
483
+ const cz = Math.cos(z2);
484
+
485
+ const sxcy = sx * cy;
486
+ const cxsy = cx * sy;
487
+ const cxcy = cx * cy;
488
+ const sxsy = sx * sy;
489
+
490
+ return fromValues(
491
+ sxcy * cz - cxsy * sz,
492
+ cxsy * cz + sxcy * sz,
493
+ cxcy * sz - sxsy * cz,
494
+ cxcy * cz + sxsy * sz,
495
+ out
496
+ );
497
+ };
498
+
499
+ /**
500
+ * Create a quaternion from equivalent z-y'-x" (intrinsic) Tait-Bryan angles.
501
+ * @param z - The Z angle (roll) in degrees.
502
+ * @param y - The Y angle (pitch) in degrees.
503
+ * @param x - The X angle (yaw) in degrees.
504
+ * @param out - The quaternion to store the result in.
505
+ * @returns The quaternion.
506
+ * @see {@link https://en.wikipedia.org/wiki/Euler_angles | Euler angles}
507
+ * @public
508
+ */
509
+ export const fromEuler: <T extends QuaternionLike>(
510
+ z: number,
511
+ y: number,
512
+ x: number,
513
+ out: T
514
+ ) => T = fromEulerZyx;
515
+
516
+ // Used in `toEuler`.
517
+ const halfEpsilon = 0.5 - epsilon;
518
+ const doubleRatio = 360 / Math.PI;
519
+
520
+ /**
521
+ * Convert a quaternion to equivalent z-y'-x" (intrinsic) Tait-Bryan angles.
522
+ * @param quaternion - The quaternion.
523
+ * @param out - The vector in which to store the Tait-Bryan angles.
524
+ * @returns The Tait-Bryan angles in degrees in roll (z), pitch (y'), yaw (x") order.
525
+ * @public
526
+ */
527
+ export const toEuler = <T extends Vector3Like>(
528
+ quaternion: QuaternionLike,
529
+ out: T
530
+ ): T => {
531
+ const x = quaternion[0];
532
+ const y = quaternion[1];
533
+ const z = quaternion[2];
534
+ const w = quaternion[3];
535
+
536
+ const y2 = y * y;
537
+ const z2 = z * z;
538
+ const w2 = w * w;
539
+
540
+ const test = x * w - y * z;
541
+
542
+ const heu = halfEpsilon * (x * x + y2 + z2 + w2);
543
+
544
+ if (test > heu) {
545
+ return vector3FromValues(90, Math.atan2(y, x) * doubleRatio, 0, out);
546
+ }
547
+
548
+ if (test < -heu) {
549
+ return vector3FromValues(-90, Math.atan2(y, x) * doubleRatio, 0, out);
550
+ }
551
+
552
+ return vector3FromValues(
553
+ radiansToDegrees(Math.asin(2 * (x * z - w * y))),
554
+ radiansToDegrees(Math.atan2(2 * (x * w + y * z), 1 - 2 * (z2 + w2))),
555
+ radiansToDegrees(Math.atan2(2 * (x * y + z * w), 1 - 2 * (y2 + z2))),
556
+ out
557
+ );
127
558
  };
128
559
 
129
560
  // Stores intermediary values for some functions.
130
- const intermediary = createMatrix3Like();
561
+ const im3 = createMatrix3Like();
131
562
 
132
563
  /**
133
- * Create a quaternion with values corresponding to the given orthonormal set of vectors.
134
- * @param view - The vector representing the viewing direction.
135
- * @param right - The vector representing the local "right" direction.
136
- * @param up - The vector representing the local "up" direction.
564
+ * Create a quaternion with values corresponding to the given orthonormal set of unit vectors.
565
+ * @param view - The unit vector representing the viewing direction.
566
+ * @param right - The unit vector representing the local "right" direction.
567
+ * @param up - The unit vector representing the local "up" direction.
137
568
  * @param out - The quaternion to store the result in.
138
569
  * @returns The quaternion.
570
+ * @public
139
571
  */
140
572
  export const fromAxes = <T extends QuaternionLike>(
141
573
  view: Vector3Like,
142
574
  right: Vector3Like,
143
575
  up: Vector3Like,
144
576
  out: T
145
- ): T => {
146
- intermediary[0] = right[0];
147
- intermediary[3] = right[1];
148
- intermediary[6] = right[2];
149
- intermediary[1] = up[0];
150
- intermediary[4] = up[1];
151
- intermediary[7] = up[2];
152
- intermediary[2] = -view[0];
153
- intermediary[5] = -view[1];
154
- intermediary[8] = -view[2];
155
- return normalize(fromMatrix3(intermediary, out), out);
156
- };
577
+ ): T =>
578
+ normalize(
579
+ fromMatrix3(
580
+ matrix3FromValues(
581
+ right[0],
582
+ up[0],
583
+ -view[0],
584
+ right[1],
585
+ up[1],
586
+ -view[1],
587
+ right[2],
588
+ up[2],
589
+ -view[2],
590
+ im3
591
+ ),
592
+ out
593
+ ),
594
+ out
595
+ );
157
596
 
158
597
  /**
159
598
  * Set a quaternion to the identity.
160
599
  * @param out - The quaternion to store the result in.
161
600
  * @returns This quaternion.
601
+ * @public
162
602
  */
163
- export const identity = <T extends QuaternionLike>(out: T): T => {
164
- out[0] = 0;
165
- out[1] = 0;
166
- out[2] = 0;
167
- out[3] = 1;
168
- return out;
169
- };
603
+ export const identity = <T extends QuaternionLike>(out: T): T =>
604
+ fromValues(0, 0, 0, 1, out);
170
605
 
171
606
  /**
172
607
  * Calculate the axis and angle that represent a quaternion.
173
608
  * @param quaternion - The quaternion.
174
609
  * @param out - The axis and angle to store the result in.
175
610
  * @returns The axis and angle.
611
+ * @public
176
612
  */
177
613
  export const getAxisAngle = <T extends AxisAngle>(
178
614
  quaternion: QuaternionLike,
@@ -181,10 +617,17 @@ export const getAxisAngle = <T extends AxisAngle>(
181
617
  const r = Math.acos(quaternion[3]) * 2;
182
618
  const s = Math.sin(r / 2);
183
619
 
184
- out.axis =
185
- s > epsilon
186
- ? [quaternion[0] / s, quaternion[1] / s, quaternion[2] / s]
187
- : [1, 0, 0];
620
+ if (s > epsilon) {
621
+ vector3FromValues(
622
+ quaternion[0] / s,
623
+ quaternion[1] / s,
624
+ quaternion[2] / s,
625
+ out.axis
626
+ );
627
+ } else {
628
+ vector3FromValues(1, 0, 0, out.axis);
629
+ }
630
+
188
631
  out.angle = r;
189
632
  return out;
190
633
  };
@@ -194,19 +637,16 @@ export const getAxisAngle = <T extends AxisAngle>(
194
637
  * @param axisAngle - The axis and angle.
195
638
  * @param out - The quaternion to store the result in.
196
639
  * @returns The quaternion.
640
+ * @public
197
641
  */
198
642
  export const setAxisAngle = <T extends QuaternionLike>(
199
- axisAngle: AxisAngle,
643
+ { angle, axis }: AxisAngle,
200
644
  out: T
201
645
  ): T => {
202
- const r = axisAngle.angle * 0.5;
646
+ const r = angle / 2;
203
647
  const s = Math.sin(r);
204
648
 
205
- out[0] = s * axisAngle.axis[0];
206
- out[1] = s * axisAngle.axis[1];
207
- out[2] = s * axisAngle.axis[2];
208
- out[3] = Math.cos(r);
209
- return out;
649
+ return fromValues(axis[0] * s, axis[1] * s, axis[2] * s, Math.cos(r), out);
210
650
  };
211
651
 
212
652
  /**
@@ -214,6 +654,7 @@ export const setAxisAngle = <T extends QuaternionLike>(
214
654
  * @param a - The first unit quaternion.
215
655
  * @param b - The second unit quaternion.
216
656
  * @returns The angular distance in radians.
657
+ * @public
217
658
  */
218
659
  export const getAngle = (a: QuaternionLike, b: QuaternionLike): number => {
219
660
  const dp = dot(a, b);
@@ -226,6 +667,7 @@ export const getAngle = (a: QuaternionLike, b: QuaternionLike): number => {
226
667
  * @param b - The multiplicand.
227
668
  * @param out - The quaternion to store the result in.
228
669
  * @returns The product.
670
+ * @public
229
671
  */
230
672
  export const multiply = <T extends QuaternionLike>(
231
673
  a: QuaternionLike,
@@ -242,11 +684,13 @@ export const multiply = <T extends QuaternionLike>(
242
684
  const bz = b[2];
243
685
  const bw = b[3];
244
686
 
245
- out[0] = ax * bw + aw * bx + ay * bz - az * by;
246
- out[1] = ay * bw + aw * by + az * bx - ax * bz;
247
- out[2] = az * bw + aw * bz + ax * by - ay * bx;
248
- out[3] = aw * bw - ax * bx - ay * by - az * bz;
249
- return out;
687
+ return fromValues(
688
+ ax * bw + aw * bx + ay * bz - az * by,
689
+ ay * bw + aw * by + az * bx - ax * bz,
690
+ az * bw + aw * bz + ax * by - ay * bx,
691
+ aw * bw - ax * bx - ay * by - az * bz,
692
+ out
693
+ );
250
694
  };
251
695
 
252
696
  /**
@@ -255,27 +699,29 @@ export const multiply = <T extends QuaternionLike>(
255
699
  * @param radians - The angle in radians.
256
700
  * @param out - The quaternion to store the result in.
257
701
  * @returns The rotated quaternion.
702
+ * @public
258
703
  */
259
704
  export const rotateX = <T extends QuaternionLike>(
260
705
  quaternion: QuaternionLike,
261
706
  radians: number,
262
707
  out: T
263
708
  ): T => {
264
- const r = radians * 0.5;
265
-
266
709
  const ax = quaternion[0];
267
710
  const ay = quaternion[1];
268
711
  const az = quaternion[2];
269
712
  const aw = quaternion[3];
270
713
 
271
- const bx = Math.sin(r);
272
- const bw = Math.cos(r);
273
-
274
- out[0] = ax * bw + aw * bx;
275
- out[1] = ay * bw + az * bx;
276
- out[2] = az * bw - ay * bx;
277
- out[3] = aw * bw - ax * bx;
278
- return out;
714
+ const r = radians / 2;
715
+ const s = Math.sin(r);
716
+ const c = Math.cos(r);
717
+
718
+ return fromValues(
719
+ ax * c + aw * s,
720
+ ay * c + az * s,
721
+ az * c - ay * s,
722
+ aw * c - ax * s,
723
+ out
724
+ );
279
725
  };
280
726
 
281
727
  /**
@@ -284,27 +730,29 @@ export const rotateX = <T extends QuaternionLike>(
284
730
  * @param radians - The angle in radians.
285
731
  * @param out - The quaternion to store the result in.
286
732
  * @returns The rotated quaternion.
733
+ * @public
287
734
  */
288
735
  export const rotateY = <T extends QuaternionLike>(
289
736
  quaternion: QuaternionLike,
290
737
  radians: number,
291
738
  out: T
292
739
  ): T => {
293
- const r = radians * 0.5;
294
-
295
740
  const ax = quaternion[0];
296
741
  const ay = quaternion[1];
297
742
  const az = quaternion[2];
298
743
  const aw = quaternion[3];
299
744
 
300
- const by = Math.sin(r);
301
- const bw = Math.cos(r);
302
-
303
- out[0] = ax * bw - az * by;
304
- out[1] = ay * bw + aw * by;
305
- out[2] = az * bw + ax * by;
306
- out[3] = aw * bw - ay * by;
307
- return out;
745
+ const r = radians / 2;
746
+ const s = Math.sin(r);
747
+ const c = Math.cos(r);
748
+
749
+ return fromValues(
750
+ ax * c - az * s,
751
+ ay * c + aw * s,
752
+ az * c + ax * s,
753
+ aw * c - ay * s,
754
+ out
755
+ );
308
756
  };
309
757
 
310
758
  /**
@@ -313,34 +761,37 @@ export const rotateY = <T extends QuaternionLike>(
313
761
  * @param radians - The angle in radians.
314
762
  * @param out - The quaternion to store the result in.
315
763
  * @returns The rotated quaternion.
764
+ * @public
316
765
  */
317
766
  export const rotateZ = <T extends QuaternionLike>(
318
767
  quaternion: QuaternionLike,
319
768
  radians: number,
320
769
  out: T
321
770
  ): T => {
322
- const r = radians * 0.5;
323
-
324
771
  const ax = quaternion[0];
325
772
  const ay = quaternion[1];
326
773
  const az = quaternion[2];
327
774
  const aw = quaternion[3];
328
775
 
329
- const bz = Math.sin(r);
330
- const bw = Math.cos(r);
331
-
332
- out[0] = ax * bw + ay * bz;
333
- out[1] = ay * bw - ax * bz;
334
- out[2] = az * bw + aw * bz;
335
- out[3] = aw * bw - az * bz;
336
- return out;
776
+ const r = radians / 2;
777
+ const s = Math.sin(r);
778
+ const c = Math.cos(r);
779
+
780
+ return fromValues(
781
+ ax * c + ay * s,
782
+ ay * c - ax * s,
783
+ az * c + aw * s,
784
+ aw * c - az * s,
785
+ out
786
+ );
337
787
  };
338
788
 
339
789
  /**
340
790
  * Calculate the fourth component of a unit quaternion from the first three, ignoring the existing fourth component.
341
- * @param quaternion - The quaternion.
791
+ * @param quaternion - The unit quaternion.
342
792
  * @param out - The quaternion to store the result in.
343
793
  * @returns The quaternion.
794
+ * @public
344
795
  */
345
796
  export const calculateW = <T extends QuaternionLike>(
346
797
  quaternion: QuaternionLike,
@@ -350,18 +801,22 @@ export const calculateW = <T extends QuaternionLike>(
350
801
  const y = quaternion[1];
351
802
  const z = quaternion[2];
352
803
 
353
- out[0] = x;
354
- out[1] = y;
355
- out[2] = z;
804
+ if (quaternion !== out) {
805
+ out[0] = x;
806
+ out[1] = y;
807
+ out[2] = z;
808
+ }
809
+
356
810
  out[3] = Math.sqrt(Math.abs(1 - x * x - y * y - z * z));
357
811
  return out;
358
812
  };
359
813
 
360
814
  /**
361
815
  * Calculate the exponential of a unit quaternion.
362
- * @param quaternion - The quaternion.
816
+ * @param quaternion - The unit quaternion.
363
817
  * @param out - The quaternion to store the result in.
364
818
  * @returns The exponential.
819
+ * @public
365
820
  */
366
821
  export const exp = <T extends QuaternionLike>(
367
822
  quaternion: QuaternionLike,
@@ -370,24 +825,20 @@ export const exp = <T extends QuaternionLike>(
370
825
  const x = quaternion[0];
371
826
  const y = quaternion[1];
372
827
  const z = quaternion[2];
373
- const w = quaternion[3];
374
828
 
375
- const r = Math.sqrt(x * x + y * y + z * z);
376
- const et = Math.exp(w);
829
+ const r = Math.sqrt(x * x + y * y + z * z); // `Math.hypot` is slower.
830
+ const et = Math.exp(quaternion[3]);
377
831
  const s = r > 0 ? (et * Math.sin(r)) / r : 0;
378
832
 
379
- out[0] = x * s;
380
- out[1] = y * s;
381
- out[2] = z * s;
382
- out[3] = et * Math.cos(r);
383
- return out;
833
+ return fromValues(x * s, y * s, z * s, et * Math.cos(r), out);
384
834
  };
385
835
 
386
836
  /**
387
837
  * Calculate the natural logarithm of a unit quaternion.
388
- * @param quaternion - The quaternion.
838
+ * @param quaternion - The unit quaternion.
389
839
  * @param out - The quaternion to store the result in.
390
840
  * @returns The natural logarithm.
841
+ * @public
391
842
  */
392
843
  export const ln = <T extends QuaternionLike>(
393
844
  quaternion: QuaternionLike,
@@ -398,30 +849,26 @@ export const ln = <T extends QuaternionLike>(
398
849
  const z = quaternion[2];
399
850
  const w = quaternion[3];
400
851
 
401
- const r = Math.sqrt(x * x + y * y + z * z);
852
+ const xyz2 = x * x + y * y + z * z;
853
+ const r = Math.sqrt(xyz2); // `Math.hypot` is slower.
402
854
  const t = r > 0 ? Math.atan2(r, w) / r : 0;
403
855
 
404
- out[0] = x * t;
405
- out[1] = y * t;
406
- out[2] = z * t;
407
- out[3] = 0.5 * Math.log(x * x + y * y + z * z + w * w);
408
- return out;
856
+ return fromValues(x * t, y * t, z * t, Math.log(xyz2 + w * w) / 2, out);
409
857
  };
410
858
 
411
859
  /**
412
- * Calculate a power of a unit quaternion.
413
- * @param quaternion - The quaternion.
860
+ * Calculate a scalar power of a unit quaternion.
861
+ * @param quaternion - The unit quaternion.
414
862
  * @param scalar - The amount to scale the quaternion by.
415
863
  * @param out - The quaternion to store the result in.
416
- * @returns The power.
864
+ * @returns The scalar power.
865
+ * @public
417
866
  */
418
867
  export const pow = <T extends QuaternionLike>(
419
868
  quaternion: QuaternionLike,
420
869
  scalar: number,
421
870
  out: T
422
- ): T => {
423
- return exp(scale(ln(quaternion, out), scalar, out), out);
424
- };
871
+ ): T => exp(scale(ln(quaternion, out), scalar, out), out);
425
872
 
426
873
  /**
427
874
  * Perform a spherical linear interpolation between two quaternions.
@@ -430,7 +877,8 @@ export const pow = <T extends QuaternionLike>(
430
877
  * @param t - The interpolation amount in `[0,1]`.
431
878
  * @param out - The quaternion to store the result in.
432
879
  * @returns The interpolated quaternion.
433
- * @see [Slerp](https://en.wikipedia.org/wiki/Slerp)
880
+ * @see {@link https://en.wikipedia.org/wiki/Slerp | Slerp}
881
+ * @public
434
882
  */
435
883
  export const slerp = <T extends QuaternionLike>(
436
884
  a: QuaternionLike,
@@ -472,31 +920,37 @@ export const slerp = <T extends QuaternionLike>(
472
920
  scale1 = t;
473
921
  }
474
922
 
475
- out[0] = scale0 * ax + scale1 * bx;
476
- out[1] = scale0 * ay + scale1 * by;
477
- out[2] = scale0 * az + scale1 * bz;
478
- out[3] = scale0 * aw + scale1 * bw;
479
- return out;
923
+ return fromValues(
924
+ ax * scale0 + bx * scale1,
925
+ ay * scale0 + by * scale1,
926
+ az * scale0 + bz * scale1,
927
+ aw * scale0 + bw * scale1,
928
+ out
929
+ );
480
930
  };
481
931
 
932
+ const pi2 = Math.PI * 2;
933
+
482
934
  /**
483
935
  * Set a quaternion to a random unit quaternion.
484
936
  * @param out - The quaternion to store the result in.
485
937
  * @returns The quaternion.
938
+ * @public
486
939
  */
487
940
  export const random = <T extends QuaternionLike>(out: T): T => {
488
- const u1 = Math.random();
489
- const u2 = Math.random();
490
- const u3 = Math.random();
491
-
492
- const sqrt1MinusU1 = Math.sqrt(1 - u1);
493
- const sqrtU1 = Math.sqrt(u1);
494
-
495
- out[0] = sqrt1MinusU1 * Math.sin(2 * Math.PI * u2);
496
- out[1] = sqrt1MinusU1 * Math.cos(2 * Math.PI * u2);
497
- out[2] = sqrtU1 * Math.sin(2 * Math.PI * u3);
498
- out[3] = sqrtU1 * Math.cos(2 * Math.PI * u3);
499
- return out;
941
+ const rand = Math.random();
942
+ const sqInvRand = Math.sqrt(1 - rand);
943
+ const sqRand = Math.sqrt(rand);
944
+ const pi2u2 = pi2 * Math.random();
945
+ const pi2u3 = pi2 * Math.random();
946
+
947
+ return fromValues(
948
+ sqInvRand * Math.sin(pi2u2),
949
+ sqInvRand * Math.cos(pi2u2),
950
+ sqRand * Math.sin(pi2u3),
951
+ sqRand * Math.cos(pi2u3),
952
+ out
953
+ );
500
954
  };
501
955
 
502
956
  /**
@@ -504,6 +958,7 @@ export const random = <T extends QuaternionLike>(out: T): T => {
504
958
  * @param quaternion - The quaternion.
505
959
  * @param out - The quaternion to store the result in.
506
960
  * @returns The inverse.
961
+ * @public
507
962
  */
508
963
  export const invert = <T extends QuaternionLike>(
509
964
  quaternion: QuaternionLike,
@@ -517,19 +972,9 @@ export const invert = <T extends QuaternionLike>(
517
972
  const aDotA = a0 * a0 + a1 * a1 + a2 * a2 + a3 * a3;
518
973
  const invDot = aDotA ? 1 / aDotA : 0;
519
974
 
520
- if (aDotA === 0) {
521
- out[0] = 0;
522
- out[1] = 0;
523
- out[2] = 0;
524
- out[3] = 0;
525
- return out;
526
- }
527
-
528
- out[0] = -a0 * invDot;
529
- out[1] = -a1 * invDot;
530
- out[2] = -a2 * invDot;
531
- out[3] = a3 * invDot;
532
- return out;
975
+ return aDotA === 0 ?
976
+ fromValues(0, 0, 0, 0, out)
977
+ : fromValues(-a0 * invDot, -a1 * invDot, -a2 * invDot, a3 * invDot, out);
533
978
  };
534
979
 
535
980
  /**
@@ -537,17 +982,19 @@ export const invert = <T extends QuaternionLike>(
537
982
  * @param quaternion - The quaternion.
538
983
  * @param out - The quaternion to store the result in.
539
984
  * @returns The conjugate.
985
+ * @public
540
986
  */
541
987
  export const conjugate = <T extends QuaternionLike>(
542
988
  quaternion: QuaternionLike,
543
989
  out: T
544
- ): T => {
545
- out[0] = -quaternion[0];
546
- out[1] = -quaternion[1];
547
- out[2] = -quaternion[2];
548
- out[3] = quaternion[3];
549
- return out;
550
- };
990
+ ): T =>
991
+ fromValues(
992
+ -quaternion[0],
993
+ -quaternion[1],
994
+ -quaternion[2],
995
+ quaternion[3],
996
+ out
997
+ );
551
998
 
552
999
  // Used to store intermediate values for some functions.
553
1000
  const controlPointOne = createQuaternionLike();
@@ -562,7 +1009,8 @@ const controlPointTwo = createQuaternionLike();
562
1009
  * @param t - The interpolation amount in `[0,1]`.
563
1010
  * @param out - The quaternion to store the result in.
564
1011
  * @returns The interpolated value.
565
- * @see [Slerp](https://en.wikipedia.org/wiki/Slerp)
1012
+ * @see {@link https://en.wikipedia.org/wiki/Slerp | Slerp}
1013
+ * @public
566
1014
  */
567
1015
  export const sqlerp = <T extends QuaternionLike>(
568
1016
  a: QuaternionLike,
@@ -571,15 +1019,59 @@ export const sqlerp = <T extends QuaternionLike>(
571
1019
  d: QuaternionLike,
572
1020
  t: number,
573
1021
  out: T
1022
+ ): T =>
1023
+ slerp(
1024
+ slerp(a, d, t, controlPointOne),
1025
+ slerp(b, c, t, controlPointTwo),
1026
+ 2 * t * (1 - t),
1027
+ out
1028
+ );
1029
+
1030
+ // The unit three-dimensional vector that represents the X-axis.
1031
+ const xAxis = vector3FromValues(1, 0, 0, createVector3Like());
1032
+
1033
+ // The unit three-dimensional vector that represents the Y-axis.
1034
+ const yAxis = vector3FromValues(0, 1, 0, createVector3Like());
1035
+
1036
+ // Used to store intermediary values for some functions.
1037
+ const iv3 = createVector3Like();
1038
+
1039
+ /**
1040
+ * Create a unit quaternion that represents the shortest rotation from one unit vector to another.
1041
+ * @param a - The first unit vector.
1042
+ * @param b - The second unit vector.
1043
+ * @param out - The quaternion to store the result in.
1044
+ * @returns The unit quaternion.
1045
+ * @public
1046
+ */
1047
+ export const fromRotationTo = <T extends QuaternionLike>(
1048
+ a: Vector3Like,
1049
+ b: Vector3Like,
1050
+ out: T
574
1051
  ): T => {
575
- slerp(a, d, t, controlPointOne);
576
- slerp(b, c, t, controlPointTwo);
577
- return slerp(controlPointOne, controlPointTwo, 2 * t * (1 - t), out);
1052
+ const dp = vector3Dot(a, b);
1053
+
1054
+ if (dp < epsilon - 1) {
1055
+ vector3Cross(xAxis, a, iv3);
1056
+ if (vector3GetMagnitude(iv3) < epsilon) {
1057
+ vector3Cross(yAxis, a, iv3);
1058
+ }
1059
+ vector3Normalize(iv3, iv3);
1060
+ return setAxisAngle({ angle: Math.PI, axis: iv3 }, out);
1061
+ }
1062
+
1063
+ if (dp > 1 - epsilon) {
1064
+ return fromValues(0, 0, 0, 1, out);
1065
+ }
1066
+
1067
+ vector3Cross(a, b, iv3);
1068
+ return normalize(fromValues(iv3[0], iv3[1], iv3[2], 1 + dp, out), out);
578
1069
  };
579
1070
 
580
1071
  /**
581
1072
  * A complex number that is commonly used to describe rotations.
582
- * @see [Quaternion](https://en.wikipedia.org/wiki/Quaternion)
1073
+ * @see {@link https://en.wikipedia.org/wiki/Quaternion | Quaternion}
1074
+ * @public
583
1075
  */
584
1076
  export default class Quaternion extends Float32Array implements QuaternionLike {
585
1077
  /**
@@ -587,7 +1079,7 @@ export default class Quaternion extends Float32Array implements QuaternionLike {
587
1079
  * @param matrix - The matrix.
588
1080
  * @param out - The quaternion to store the result in.
589
1081
  * @returns The quaternion.
590
- * @see [Rotation matrix](https://en.wikipedia.org/wiki/Rotation_matrix)
1082
+ * @see {@link https://en.wikipedia.org/wiki/Rotation_matrix | Rotation matrix}
591
1083
  */
592
1084
  public static fromMatrix3<T extends QuaternionLike = Quaternion>(
593
1085
  matrix: Matrix3Like,
@@ -597,21 +1089,21 @@ export default class Quaternion extends Float32Array implements QuaternionLike {
597
1089
  }
598
1090
 
599
1091
  /**
600
- * Create a quaternion from equivalent x-y-z Tait-Bryan angles
601
- * @param x - The x angle.
602
- * @param y - The y angle.
603
- * @param z - The z angle.
1092
+ * Create a quaternion from equivalent z-y'-x" (intrinsic) Tait-Bryan angles.
1093
+ * @param z - The z (roll) angle.
1094
+ * @param y - The y (pitch) angle.
1095
+ * @param x - The x (yaw) angle.
604
1096
  * @param out - The quaternion to store the result in.
605
1097
  * @returns The quaternion.
606
- * @see [Euler angles](https://en.wikipedia.org/wiki/Euler_angles)
1098
+ * @see {@link https://en.wikipedia.org/wiki/Euler_angles | Euler angles}
607
1099
  */
608
1100
  public static fromEuler<T extends QuaternionLike = Quaternion>(
609
- x: number,
610
- y: number,
611
1101
  z: number,
1102
+ y: number,
1103
+ x: number,
612
1104
  out: T = new Quaternion() as Quaternion & T
613
1105
  ): T {
614
- return fromEuler(x, y, z, out);
1106
+ return fromEuler(z, y, x, out);
615
1107
  }
616
1108
 
617
1109
  /**
@@ -650,9 +1142,24 @@ export default class Quaternion extends Float32Array implements QuaternionLike {
650
1142
  return fromAxes(view, right, up, out);
651
1143
  }
652
1144
 
1145
+ /**
1146
+ * Create a unit quaternion that represents the shortest rotation from one unit vector to another.
1147
+ * @param a - The first unit vector.
1148
+ * @param b - The second unit vector.
1149
+ * @param out - The quaternion to store the result in.
1150
+ * @returns The unit quaternion.
1151
+ */
1152
+ public static fromRotationTo<T extends QuaternionLike = Quaternion>(
1153
+ a: Vector3Like,
1154
+ b: Vector3Like,
1155
+ out: T = new Quaternion() as Quaternion & T
1156
+ ): T {
1157
+ return fromRotationTo(a, b, out);
1158
+ }
1159
+
653
1160
  /**
654
1161
  * Create an identity quaternion.
655
- * @see [Quaternion](https://en.wikipedia.org/wiki/Quaternion)
1162
+ * @see {@link https://en.wikipedia.org/wiki/Quaternion | Quaternion}
656
1163
  */
657
1164
  public constructor() {
658
1165
  super(4);
@@ -810,7 +1317,7 @@ export default class Quaternion extends Float32Array implements QuaternionLike {
810
1317
  * @param t - The interpolation amount in `[0,1]`.
811
1318
  * @param out - The quaternion to store the result in.
812
1319
  * @returns The interpolated quaternion.
813
- * @see [Slerp](https://en.wikipedia.org/wiki/Slerp)
1320
+ * @see {@link https://en.wikipedia.org/wiki/Slerp | Slerp}
814
1321
  */
815
1322
  public slerp<T extends QuaternionLike = Quaternion>(
816
1323
  quaternion: QuaternionLike,
@@ -967,7 +1474,7 @@ export default class Quaternion extends Float32Array implements QuaternionLike {
967
1474
  * @param t - The interpolation amount in `[0,1]`.
968
1475
  * @param out - The quaternion to store the result in.
969
1476
  * @returns The interpolated value.
970
- * @see [Slerp](https://en.wikipedia.org/wiki/Slerp)
1477
+ * @see {@link https://en.wikipedia.org/wiki/Slerp | Slerp}
971
1478
  */
972
1479
  public sqlerp<T extends QuaternionLike = Quaternion>(
973
1480
  a: QuaternionLike,
@@ -978,4 +1485,15 @@ export default class Quaternion extends Float32Array implements QuaternionLike {
978
1485
  ): T {
979
1486
  return sqlerp(this, a, b, quaternion, t, out);
980
1487
  }
1488
+
1489
+ /**
1490
+ * Convert this quaternion to equivalent z-y'-x" (intrinsic) Tait-Bryan angles.
1491
+ * @param out - The vector in which to store the Tait-Bryan angles.
1492
+ * @returns The Tait-Bryan angles in degrees in roll (z), pitch (y'), yaw (x") order.
1493
+ */
1494
+ public toEuler<T extends Vector3Like = Vector3>(
1495
+ out: T = new Vector3() as Vector3 & T
1496
+ ): T {
1497
+ return toEuler(this, out);
1498
+ }
981
1499
  }