glmaths 0.0.1
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.
- package/README.md +952 -0
- package/benchmark.js +747 -0
- package/dist/cjs/glmaths.d.ts +12053 -0
- package/dist/cjs/glmaths.js +6496 -0
- package/dist/cjs/glmaths.js.map +1 -0
- package/dist/cjs/glmaths.min.js +2 -0
- package/dist/cjs/glmaths.min.js.map +1 -0
- package/dist/esm/glmaths.d.ts +12053 -0
- package/dist/esm/glmaths.js +6453 -0
- package/dist/esm/glmaths.js.map +1 -0
- package/dist/esm/glmaths.min.js +2 -0
- package/dist/esm/glmaths.min.js.map +1 -0
- package/dist/glmaths.d.ts +12053 -0
- package/dist/glmaths.js +6501 -0
- package/dist/glmaths.js.map +1 -0
- package/dist/glmaths.min.js +2 -0
- package/dist/glmaths.min.js.map +1 -0
- package/docs.js +64 -0
- package/package.json +37 -0
- package/rollup.config.js +70 -0
- package/src/index.ts +19 -0
- package/src/internalUtils.ts +78 -0
- package/src/mat2.ts +324 -0
- package/src/mat2x3.ts +328 -0
- package/src/mat3.ts +629 -0
- package/src/mat4.ts +1319 -0
- package/src/quat.ts +819 -0
- package/src/quat2.ts +412 -0
- package/src/utils.ts +248 -0
- package/src/vec2.ts +798 -0
- package/src/vec3.ts +1069 -0
- package/src/vec4.ts +810 -0
- package/tests/mat2.test.ts +277 -0
- package/tests/mat2x3.test.ts +217 -0
- package/tests/mat3.test.ts +306 -0
- package/tests/mat4.test.ts +586 -0
- package/tests/quat.test.ts +418 -0
- package/tests/quat2.test.ts +222 -0
- package/tests/utils.test.ts +115 -0
- package/tests/vec2.test.ts +617 -0
- package/tests/vec3.test.ts +649 -0
- package/tests/vec4.test.ts +390 -0
- package/tsconfig.json +17 -0
- package/tsconfig.test.json +8 -0
package/src/quat2.ts
ADDED
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
import glm from '.'
|
|
2
|
+
import { equals } from './internalUtils'
|
|
3
|
+
import { Vec3 } from './vec3'
|
|
4
|
+
import { Quat } from './quat'
|
|
5
|
+
import { Mat4 } from './mat4'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Dual Quaternion for rigid body transformations (rotation + translation)
|
|
9
|
+
* Stored as [real.x, real.y, real.z, real.w, dual.x, dual.y, dual.z, dual.w]
|
|
10
|
+
* @extends Float32Array
|
|
11
|
+
*/
|
|
12
|
+
export class Quat2 extends Float32Array {
|
|
13
|
+
|
|
14
|
+
static get identity() { return new Quat2(0, 0, 0, 1, 0, 0, 0, 0) }
|
|
15
|
+
static get Identity() { return new Quat2(0, 0, 0, 1, 0, 0, 0, 0) }
|
|
16
|
+
static get IDENTITY() { return new Quat2(0, 0, 0, 1, 0, 0, 0, 0) }
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Creates a new dual quaternion
|
|
20
|
+
*
|
|
21
|
+
* @param {Number} x1 real X component, defaults to 0
|
|
22
|
+
* @param {Number} y1 real Y component, defaults to 0
|
|
23
|
+
* @param {Number} z1 real Z component, defaults to 0
|
|
24
|
+
* @param {Number} w1 real W component, defaults to 1
|
|
25
|
+
* @param {Number} x2 dual X component, defaults to 0
|
|
26
|
+
* @param {Number} y2 dual Y component, defaults to 0
|
|
27
|
+
* @param {Number} z2 dual Z component, defaults to 0
|
|
28
|
+
* @param {Number} w2 dual W component, defaults to 0
|
|
29
|
+
*/
|
|
30
|
+
constructor(x1 = 0, y1 = 0, z1 = 0, w1 = 1, x2 = 0, y2 = 0, z2 = 0, w2 = 0) {
|
|
31
|
+
super(8)
|
|
32
|
+
this[0] = x1; this[1] = y1; this[2] = z1; this[3] = w1
|
|
33
|
+
this[4] = x2; this[5] = y2; this[6] = z2; this[7] = w2
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Get the real part as a Quat
|
|
38
|
+
*
|
|
39
|
+
* @param {Quat} out the receiving quaternion, defaults to quat()
|
|
40
|
+
* @returns {Quat} out
|
|
41
|
+
*/
|
|
42
|
+
getReal(out = new Quat()): Quat {
|
|
43
|
+
out[0] = this[0]; out[1] = this[1]; out[2] = this[2]; out[3] = this[3]
|
|
44
|
+
return out
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Get the dual part as a Quat
|
|
49
|
+
*
|
|
50
|
+
* @param {Quat} out the receiving quaternion, defaults to quat()
|
|
51
|
+
* @returns {Quat} out
|
|
52
|
+
*/
|
|
53
|
+
getDual(out = new Quat()): Quat {
|
|
54
|
+
out[0] = this[4]; out[1] = this[5]; out[2] = this[6]; out[3] = this[7]
|
|
55
|
+
return out
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Set the real part from a quaternion
|
|
60
|
+
*
|
|
61
|
+
* @param {Quat} q the source quaternion
|
|
62
|
+
* @returns {Quat2} this
|
|
63
|
+
*/
|
|
64
|
+
setReal(q: Quat) {
|
|
65
|
+
this[0] = q[0]; this[1] = q[1]; this[2] = q[2]; this[3] = q[3]
|
|
66
|
+
return this
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Set the dual part from a quaternion
|
|
71
|
+
*
|
|
72
|
+
* @param {Quat} q the source quaternion
|
|
73
|
+
* @returns {Quat2} this
|
|
74
|
+
*/
|
|
75
|
+
setDual(q: Quat) {
|
|
76
|
+
this[4] = q[0]; this[5] = q[1]; this[6] = q[2]; this[7] = q[3]
|
|
77
|
+
return this
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Get the translation component
|
|
82
|
+
*
|
|
83
|
+
* @param {Vec3} out the receiving vector, defaults to vec3()
|
|
84
|
+
* @returns {Vec3} out
|
|
85
|
+
*/
|
|
86
|
+
getTranslation(out = new Vec3()): Vec3 {
|
|
87
|
+
const ax = this[4], ay = this[5], az = this[6], aw = this[7]
|
|
88
|
+
const bx = -this[0], by = -this[1], bz = -this[2], bw = this[3]
|
|
89
|
+
out[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2
|
|
90
|
+
out[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2
|
|
91
|
+
out[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2
|
|
92
|
+
return out
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Create from rotation quaternion and translation vector
|
|
97
|
+
*
|
|
98
|
+
* @param {Quat} q the rotation quaternion
|
|
99
|
+
* @param {Vec3} t the translation vector
|
|
100
|
+
* @param {Quat2} out the receiving dual quaternion, defaults to quat2()
|
|
101
|
+
* @returns {Quat2} out
|
|
102
|
+
*/
|
|
103
|
+
static fromRotationTranslation(q: Quat, t: Vec3, out = new Quat2()): Quat2 {
|
|
104
|
+
const ax = t[0] * 0.5, ay = t[1] * 0.5, az = t[2] * 0.5
|
|
105
|
+
const bx = q[0], by = q[1], bz = q[2], bw = q[3]
|
|
106
|
+
out[0] = bx; out[1] = by; out[2] = bz; out[3] = bw
|
|
107
|
+
out[4] = ax * bw + ay * bz - az * by
|
|
108
|
+
out[5] = ay * bw + az * bx - ax * bz
|
|
109
|
+
out[6] = az * bw + ax * by - ay * bx
|
|
110
|
+
out[7] = -ax * bx - ay * by - az * bz
|
|
111
|
+
return out
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Create from translation only
|
|
116
|
+
*
|
|
117
|
+
* @param {Vec3} t the translation vector
|
|
118
|
+
* @param {Quat2} out the receiving dual quaternion, defaults to quat2()
|
|
119
|
+
* @returns {Quat2} out
|
|
120
|
+
*/
|
|
121
|
+
static fromTranslation(t: Vec3, out = new Quat2()): Quat2 {
|
|
122
|
+
out[0] = 0; out[1] = 0; out[2] = 0; out[3] = 1
|
|
123
|
+
out[4] = t[0] * 0.5; out[5] = t[1] * 0.5; out[6] = t[2] * 0.5; out[7] = 0
|
|
124
|
+
return out
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Create from rotation only
|
|
129
|
+
*
|
|
130
|
+
* @param {Quat} q the rotation quaternion
|
|
131
|
+
* @param {Quat2} out the receiving dual quaternion, defaults to quat2()
|
|
132
|
+
* @returns {Quat2} out
|
|
133
|
+
*/
|
|
134
|
+
static fromRotation(q: Quat, out = new Quat2()): Quat2 {
|
|
135
|
+
out[0] = q[0]; out[1] = q[1]; out[2] = q[2]; out[3] = q[3]
|
|
136
|
+
out[4] = 0; out[5] = 0; out[6] = 0; out[7] = 0
|
|
137
|
+
return out
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Create from a 4x4 matrix
|
|
142
|
+
*
|
|
143
|
+
* @param {Mat4} m the source matrix
|
|
144
|
+
* @param {Quat2} out the receiving dual quaternion, defaults to quat2()
|
|
145
|
+
* @returns {Quat2} out
|
|
146
|
+
*/
|
|
147
|
+
static fromMat4(m: Mat4, out = new Quat2()): Quat2 {
|
|
148
|
+
const r = m.getRotation()
|
|
149
|
+
const t = m.getTranslation()
|
|
150
|
+
return Quat2.fromRotationTranslation(r, t, out)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Creates a copy of this dual quaternion
|
|
155
|
+
*
|
|
156
|
+
* @returns {Quat2} a new dual quaternion
|
|
157
|
+
*/
|
|
158
|
+
clone() {
|
|
159
|
+
return new Quat2(this[0], this[1], this[2], this[3], this[4], this[5], this[6], this[7])
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Multiply two dual quaternions
|
|
164
|
+
*
|
|
165
|
+
* @param {Quat2} b the second operand
|
|
166
|
+
* @param {Quat2} out the receiving dual quaternion, defaults to this
|
|
167
|
+
* @returns {Quat2} out
|
|
168
|
+
*/
|
|
169
|
+
// @ts-ignore
|
|
170
|
+
multiply = (b: Quat2, out = glm.ALWAYS_COPY ? new Quat2() : this): Quat2 => {
|
|
171
|
+
const ax0 = this[0], ay0 = this[1], az0 = this[2], aw0 = this[3]
|
|
172
|
+
const bx1 = b[4], by1 = b[5], bz1 = b[6], bw1 = b[7]
|
|
173
|
+
const ax1 = this[4], ay1 = this[5], az1 = this[6], aw1 = this[7]
|
|
174
|
+
const bx0 = b[0], by0 = b[1], bz0 = b[2], bw0 = b[3]
|
|
175
|
+
|
|
176
|
+
out[0] = ax0 * bw0 + aw0 * bx0 + ay0 * bz0 - az0 * by0
|
|
177
|
+
out[1] = ay0 * bw0 + aw0 * by0 + az0 * bx0 - ax0 * bz0
|
|
178
|
+
out[2] = az0 * bw0 + aw0 * bz0 + ax0 * by0 - ay0 * bx0
|
|
179
|
+
out[3] = aw0 * bw0 - ax0 * bx0 - ay0 * by0 - az0 * bz0
|
|
180
|
+
|
|
181
|
+
out[4] = ax0 * bw1 + aw0 * bx1 + ay0 * bz1 - az0 * by1 +
|
|
182
|
+
ax1 * bw0 + aw1 * bx0 + ay1 * bz0 - az1 * by0
|
|
183
|
+
out[5] = ay0 * bw1 + aw0 * by1 + az0 * bx1 - ax0 * bz1 +
|
|
184
|
+
ay1 * bw0 + aw1 * by0 + az1 * bx0 - ax1 * bz0
|
|
185
|
+
out[6] = az0 * bw1 + aw0 * bz1 + ax0 * by1 - ay0 * bx1 +
|
|
186
|
+
az1 * bw0 + aw1 * bz0 + ax1 * by0 - ay1 * bx0
|
|
187
|
+
out[7] = aw0 * bw1 - ax0 * bx1 - ay0 * by1 - az0 * bz1 +
|
|
188
|
+
aw1 * bw0 - ax1 * bx0 - ay1 * by0 - az1 * bz0
|
|
189
|
+
return out
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Translate by a Vec3
|
|
194
|
+
*
|
|
195
|
+
* @param {Vec3} v the translation vector
|
|
196
|
+
* @param {Quat2} out the receiving dual quaternion, defaults to this
|
|
197
|
+
* @returns {Quat2} out
|
|
198
|
+
*/
|
|
199
|
+
translate(v: Vec3, out = glm.ALWAYS_COPY ? new Quat2() : this): Quat2 {
|
|
200
|
+
const ax1 = this[0], ay1 = this[1], az1 = this[2], aw1 = this[3]
|
|
201
|
+
const bx1 = v[0] * 0.5, by1 = v[1] * 0.5, bz1 = v[2] * 0.5
|
|
202
|
+
const ax2 = this[4], ay2 = this[5], az2 = this[6], aw2 = this[7]
|
|
203
|
+
out[0] = ax1; out[1] = ay1; out[2] = az1; out[3] = aw1
|
|
204
|
+
out[4] = aw1 * bx1 + ay1 * bz1 - az1 * by1 + ax2
|
|
205
|
+
out[5] = aw1 * by1 + az1 * bx1 - ax1 * bz1 + ay2
|
|
206
|
+
out[6] = aw1 * bz1 + ax1 * by1 - ay1 * bx1 + az2
|
|
207
|
+
out[7] = -ax1 * bx1 - ay1 * by1 - az1 * bz1 + aw2
|
|
208
|
+
return out
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Calculates the conjugate of a dual quaternion
|
|
213
|
+
*
|
|
214
|
+
* @param {Quat2} out the receiving dual quaternion, defaults to this
|
|
215
|
+
* @returns {Quat2} out
|
|
216
|
+
*/
|
|
217
|
+
conjugate(out = glm.ALWAYS_COPY ? new Quat2() : this): Quat2 {
|
|
218
|
+
out[0] = -this[0]; out[1] = -this[1]; out[2] = -this[2]; out[3] = this[3]
|
|
219
|
+
out[4] = -this[4]; out[5] = -this[5]; out[6] = -this[6]; out[7] = this[7]
|
|
220
|
+
return out
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Calculates the inverse of a dual quaternion
|
|
225
|
+
*
|
|
226
|
+
* @param {Quat2} out the receiving dual quaternion, defaults to this
|
|
227
|
+
* @returns {Quat2} out
|
|
228
|
+
*/
|
|
229
|
+
invert(out = glm.ALWAYS_COPY ? new Quat2() : this): Quat2 {
|
|
230
|
+
const sqlen = this.squaredLength()
|
|
231
|
+
out[0] = -this[0] / sqlen; out[1] = -this[1] / sqlen
|
|
232
|
+
out[2] = -this[2] / sqlen; out[3] = this[3] / sqlen
|
|
233
|
+
out[4] = -this[4] / sqlen; out[5] = -this[5] / sqlen
|
|
234
|
+
out[6] = -this[6] / sqlen; out[7] = this[7] / sqlen
|
|
235
|
+
return out
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Squared length of the real part
|
|
240
|
+
*
|
|
241
|
+
* @returns {Number} squared length
|
|
242
|
+
*/
|
|
243
|
+
squaredLength() {
|
|
244
|
+
const x = this[0], y = this[1], z = this[2], w = this[3]
|
|
245
|
+
return x * x + y * y + z * z + w * w
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Length of the real part
|
|
250
|
+
*
|
|
251
|
+
* @returns {Number} length
|
|
252
|
+
*/
|
|
253
|
+
len() {
|
|
254
|
+
return Math.sqrt(this.squaredLength())
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Normalize the dual quaternion
|
|
259
|
+
*
|
|
260
|
+
* @param {Quat2} out the receiving dual quaternion, defaults to this
|
|
261
|
+
* @returns {Quat2} out
|
|
262
|
+
*/
|
|
263
|
+
normalize(out = glm.ALWAYS_COPY ? new Quat2() : this): Quat2 {
|
|
264
|
+
let magnitude = this.squaredLength()
|
|
265
|
+
if (magnitude > 0) {
|
|
266
|
+
magnitude = Math.sqrt(magnitude)
|
|
267
|
+
const a0 = this[0] / magnitude, a1 = this[1] / magnitude
|
|
268
|
+
const a2 = this[2] / magnitude, a3 = this[3] / magnitude
|
|
269
|
+
const b0 = this[4], b1 = this[5], b2 = this[6], b3 = this[7]
|
|
270
|
+
const a_dot_b = a0 * b0 + a1 * b1 + a2 * b2 + a3 * b3
|
|
271
|
+
out[0] = a0; out[1] = a1; out[2] = a2; out[3] = a3
|
|
272
|
+
out[4] = (b0 - a0 * a_dot_b) / magnitude
|
|
273
|
+
out[5] = (b1 - a1 * a_dot_b) / magnitude
|
|
274
|
+
out[6] = (b2 - a2 * a_dot_b) / magnitude
|
|
275
|
+
out[7] = (b3 - a3 * a_dot_b) / magnitude
|
|
276
|
+
}
|
|
277
|
+
return out
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Dot product of the real parts of two dual quaternions
|
|
282
|
+
*
|
|
283
|
+
* @param {Quat2} a the first operand
|
|
284
|
+
* @param {Quat2} b the second operand
|
|
285
|
+
* @returns {Number} dot product
|
|
286
|
+
*/
|
|
287
|
+
static dot(a: Quat2, b: Quat2) {
|
|
288
|
+
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Performs a linear interpolation between two dual quaternions
|
|
293
|
+
*
|
|
294
|
+
* @param {Quat2} a the first operand
|
|
295
|
+
* @param {Quat2} b the second operand
|
|
296
|
+
* @param {Number} t interpolation amount, in the range [0-1]
|
|
297
|
+
* @param {Quat2} out the receiving dual quaternion, defaults to quat2()
|
|
298
|
+
* @returns {Quat2} out
|
|
299
|
+
*/
|
|
300
|
+
static lerp(a: Quat2, b: Quat2, t: number, out = new Quat2()): Quat2 {
|
|
301
|
+
const mt = 1 - t
|
|
302
|
+
if (Quat2.dot(a, b) < 0) t = -t
|
|
303
|
+
out[0] = a[0] * mt + b[0] * t
|
|
304
|
+
out[1] = a[1] * mt + b[1] * t
|
|
305
|
+
out[2] = a[2] * mt + b[2] * t
|
|
306
|
+
out[3] = a[3] * mt + b[3] * t
|
|
307
|
+
out[4] = a[4] * mt + b[4] * t
|
|
308
|
+
out[5] = a[5] * mt + b[5] * t
|
|
309
|
+
out[6] = a[6] * mt + b[6] * t
|
|
310
|
+
out[7] = a[7] * mt + b[7] * t
|
|
311
|
+
return out
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Adds two dual quaternions
|
|
316
|
+
*
|
|
317
|
+
* @param {Quat2} b the second operand
|
|
318
|
+
* @param {Quat2} out the receiving dual quaternion, defaults to this
|
|
319
|
+
* @returns {Quat2} out
|
|
320
|
+
*/
|
|
321
|
+
plus(b: Quat2, out = glm.ALWAYS_COPY ? new Quat2() : this): Quat2 {
|
|
322
|
+
out[0] = this[0] + b[0]; out[1] = this[1] + b[1]
|
|
323
|
+
out[2] = this[2] + b[2]; out[3] = this[3] + b[3]
|
|
324
|
+
out[4] = this[4] + b[4]; out[5] = this[5] + b[5]
|
|
325
|
+
out[6] = this[6] + b[6]; out[7] = this[7] + b[7]
|
|
326
|
+
return out
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Scales a dual quaternion by a scalar
|
|
331
|
+
*
|
|
332
|
+
* @param {Number} s the scalar to scale by
|
|
333
|
+
* @param {Quat2} out the receiving dual quaternion, defaults to this
|
|
334
|
+
* @returns {Quat2} out
|
|
335
|
+
*/
|
|
336
|
+
scale(s: number, out = glm.ALWAYS_COPY ? new Quat2() : this): Quat2 {
|
|
337
|
+
out[0] = this[0] * s; out[1] = this[1] * s
|
|
338
|
+
out[2] = this[2] * s; out[3] = this[3] * s
|
|
339
|
+
out[4] = this[4] * s; out[5] = this[5] * s
|
|
340
|
+
out[6] = this[6] * s; out[7] = this[7] * s
|
|
341
|
+
return out
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Returns whether two dual quaternions are approximately equal
|
|
346
|
+
*
|
|
347
|
+
* @param {Quat2} b the second operand
|
|
348
|
+
* @returns {Boolean} true if the dual quaternions are approximately equal
|
|
349
|
+
*/
|
|
350
|
+
equals(b: Quat2) {
|
|
351
|
+
return (
|
|
352
|
+
equals(this[0], b[0]) && equals(this[1], b[1]) &&
|
|
353
|
+
equals(this[2], b[2]) && equals(this[3], b[3]) &&
|
|
354
|
+
equals(this[4], b[4]) && equals(this[5], b[5]) &&
|
|
355
|
+
equals(this[6], b[6]) && equals(this[7], b[7])
|
|
356
|
+
)
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Returns whether two dual quaternions are exactly equal
|
|
361
|
+
*
|
|
362
|
+
* @param {Quat2} b the second operand
|
|
363
|
+
* @returns {Boolean} true if the dual quaternions are exactly equal
|
|
364
|
+
*/
|
|
365
|
+
exactEquals(b: Quat2) {
|
|
366
|
+
return (
|
|
367
|
+
this[0] === b[0] && this[1] === b[1] && this[2] === b[2] && this[3] === b[3] &&
|
|
368
|
+
this[4] === b[4] && this[5] === b[5] && this[6] === b[6] && this[7] === b[7]
|
|
369
|
+
)
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Returns a string representation of a dual quaternion
|
|
374
|
+
*
|
|
375
|
+
* @returns {String} string representation of the dual quaternion
|
|
376
|
+
*/
|
|
377
|
+
toString() {
|
|
378
|
+
const fmt = (v: number, suffix: string) => {
|
|
379
|
+
if (v === 0) return ''
|
|
380
|
+
const abs = Math.abs(v)
|
|
381
|
+
const s = abs === 1 && suffix ? suffix : `${abs}${suffix}`
|
|
382
|
+
return v < 0 ? ` - ${s}` : ` + ${s}`
|
|
383
|
+
}
|
|
384
|
+
const qStr = (w: number, x: number, y: number, z: number) => {
|
|
385
|
+
const parts = [
|
|
386
|
+
w !== 0 ? `${w}` : '',
|
|
387
|
+
fmt(x, 'i'),
|
|
388
|
+
fmt(y, 'j'),
|
|
389
|
+
fmt(z, 'k')
|
|
390
|
+
].join('').trim().replace(/^\+ /, '') || '0'
|
|
391
|
+
return parts
|
|
392
|
+
}
|
|
393
|
+
const real = qStr(this[3], this[0], this[1], this[2])
|
|
394
|
+
const dual = qStr(this[7], this[4], this[5], this[6])
|
|
395
|
+
return `(${real}) + \u03B5(${dual})`
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
export interface Quat2 {
|
|
399
|
+
sqrLen: () => number
|
|
400
|
+
str: () => string
|
|
401
|
+
add: (b: Quat2, out?: Quat2) => Quat2
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// @aliases
|
|
405
|
+
Quat2.prototype.sqrLen = Quat2.prototype.squaredLength
|
|
406
|
+
Quat2.prototype.str = Quat2.prototype.toString
|
|
407
|
+
Quat2.prototype.add = Quat2.prototype.plus
|
|
408
|
+
|
|
409
|
+
export const quat2 = Object.assign(
|
|
410
|
+
(x1 = 0, y1 = 0, z1 = 0, w1 = 1, x2 = 0, y2 = 0, z2 = 0, w2 = 0) => new Quat2(x1, y1, z1, w1, x2, y2, z2, w2),
|
|
411
|
+
Quat2
|
|
412
|
+
)
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import { Vec2 } from './vec2'
|
|
2
|
+
import { Vec3 } from './vec3'
|
|
3
|
+
import { Vec4 } from './vec4'
|
|
4
|
+
import { Quat } from './quat'
|
|
5
|
+
import { Quat2 } from './quat2'
|
|
6
|
+
import { Mat2 } from './mat2'
|
|
7
|
+
import { Mat2x3 } from './mat2x3'
|
|
8
|
+
import { Mat3 } from './mat3'
|
|
9
|
+
import { Mat4 } from './mat4'
|
|
10
|
+
|
|
11
|
+
export type Vec = Vec2 | Vec3 | Vec4
|
|
12
|
+
export type Vector = Vec
|
|
13
|
+
export type Mat = Mat2 | Mat2x3 | Mat3 | Mat4
|
|
14
|
+
export type GenType = Vec | Mat | Quat | Quat2
|
|
15
|
+
|
|
16
|
+
function makeArr<T extends GenType>(a: T): T {
|
|
17
|
+
if (a instanceof Vec2) return new Vec2() as unknown as T
|
|
18
|
+
if (a instanceof Vec3) return new Vec3() as unknown as T
|
|
19
|
+
if (a instanceof Vec4) return new Vec4() as unknown as T
|
|
20
|
+
if (a instanceof Mat2) return new Mat2() as unknown as T
|
|
21
|
+
if (a instanceof Mat2x3) return new Mat2x3() as unknown as T
|
|
22
|
+
if (a instanceof Mat3) return new Mat3() as unknown as T
|
|
23
|
+
if (a instanceof Mat4) return new Mat4() as unknown as T
|
|
24
|
+
if (a instanceof Quat) return new Quat() as unknown as T
|
|
25
|
+
if (a instanceof Quat2) return new Quat2() as unknown as T
|
|
26
|
+
if (a instanceof Float32Array) return new Float32Array() as unknown as T
|
|
27
|
+
throw `unknown type`
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function calc1<T extends number | GenType>(
|
|
31
|
+
fn: (x: number, i: number) => number,
|
|
32
|
+
x: T,
|
|
33
|
+
out?: T extends GenType ? T : never
|
|
34
|
+
) {
|
|
35
|
+
if (typeof x === 'number')
|
|
36
|
+
return fn(x, 0)
|
|
37
|
+
const xArr = x as GenType
|
|
38
|
+
const outArr = (out && out.length === xArr.length ? out : makeArr(xArr)) as GenType
|
|
39
|
+
for (let i = 0; i < xArr.length; ++i)
|
|
40
|
+
outArr[i] = fn(xArr[i], i)
|
|
41
|
+
return outArr as T
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Converts degrees to radians
|
|
46
|
+
*
|
|
47
|
+
* @param {Number} degrees angle in degrees
|
|
48
|
+
* @returns {Number} angle in radians
|
|
49
|
+
*/
|
|
50
|
+
export function radians(degrees: number): number
|
|
51
|
+
export function radians<T extends GenType>(degrees: T, out?: T): T
|
|
52
|
+
export function radians<T extends number | GenType>(degrees: T, out?: T extends GenType ? T : never) {
|
|
53
|
+
return calc1<T>(x => x / 180.0 * Math.PI, degrees, out)
|
|
54
|
+
}
|
|
55
|
+
export const rad = radians
|
|
56
|
+
export const toRadians = radians
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Converts radians to degrees
|
|
60
|
+
*
|
|
61
|
+
* @param {Number} radians angle in radians
|
|
62
|
+
* @returns {Number} angle in degrees
|
|
63
|
+
*/
|
|
64
|
+
export function degrees(radians: number): number
|
|
65
|
+
export function degrees<T extends GenType>(radians: T, out?: T): T
|
|
66
|
+
export function degrees<T extends number | GenType>(radians: T, out?: T extends GenType ? T : never) {
|
|
67
|
+
return calc1<T>(x => x / Math.PI * 180.0, radians, out)
|
|
68
|
+
}
|
|
69
|
+
export const deg = degrees
|
|
70
|
+
export const toDegrees = degrees
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Rounds a number to the nearest integer, with half-values rounding away from zero
|
|
74
|
+
*
|
|
75
|
+
* @param {Number} x the value to round
|
|
76
|
+
* @returns {Number} the rounded value
|
|
77
|
+
*/
|
|
78
|
+
export function round(x: number): number
|
|
79
|
+
export function round<T extends GenType>(x: T, out?: T): T
|
|
80
|
+
export function round<T extends number | GenType>(x: T, out?: T extends GenType ? T : never) {
|
|
81
|
+
return calc1<T>(x => x >= 0 ? Math.round(x) : x % 0.5 === 0 ? Math.floor(x) : Math.round(x), x, out)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Clamps a number between a minimum and maximum value
|
|
86
|
+
*
|
|
87
|
+
* @param {Number} x the value to clamp
|
|
88
|
+
* @param {Number} min the minimum value
|
|
89
|
+
* @param {Number} max the maximum value
|
|
90
|
+
* @returns {Number} the clamped value
|
|
91
|
+
*/
|
|
92
|
+
export function clamp(x: number, min: number, max: number): number
|
|
93
|
+
export function clamp<T extends GenType>(x: T, min: number, max: number, out?: T): T
|
|
94
|
+
export function clamp<T extends number | GenType>(
|
|
95
|
+
x: T,
|
|
96
|
+
min: number, max: number,
|
|
97
|
+
out?: T extends GenType ? T : never
|
|
98
|
+
) {
|
|
99
|
+
return calc1<T>(x => Math.min(Math.max(x, min), max), x, out)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Clamps a number between 0 and 1
|
|
104
|
+
*
|
|
105
|
+
* @param {Number} x the value to clamp
|
|
106
|
+
* @returns {Number} the clamped value in the range [0, 1]
|
|
107
|
+
*/
|
|
108
|
+
export function clamp01(x: number): number
|
|
109
|
+
export function clamp01<T extends GenType>(x: T, out?: T): T
|
|
110
|
+
export function clamp01<T extends number | GenType>(
|
|
111
|
+
x: T,
|
|
112
|
+
out?: T extends GenType ? T : never
|
|
113
|
+
) {
|
|
114
|
+
return calc1<T>(x => Math.min(Math.max(x, 0), 1), x, out)
|
|
115
|
+
}
|
|
116
|
+
export const saturate = clamp01
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Performs a linear interpolation between two values
|
|
120
|
+
*
|
|
121
|
+
* @param {Number | Float32Array} x the first value
|
|
122
|
+
* @param {Number | Float32Array} y the second value
|
|
123
|
+
* @param {Number} a interpolation amount in the range [0, 1]
|
|
124
|
+
* @param {Float32Array} out if given Float32Array, puts result in out
|
|
125
|
+
* @returns {Number | Float32Array} the interpolated value
|
|
126
|
+
*/
|
|
127
|
+
export function mix(x: number, y: number, a: number): number
|
|
128
|
+
export function mix<T extends GenType>(x: T, y: T, a: number, out?: T): T
|
|
129
|
+
export function mix<T extends number | GenType>(
|
|
130
|
+
x: T, y: T, t: number,
|
|
131
|
+
out?: T extends GenType ? T : never
|
|
132
|
+
) {
|
|
133
|
+
if (typeof x === 'number')
|
|
134
|
+
return x * (1 - t) + (y as number) * t
|
|
135
|
+
const xArr = x as GenType
|
|
136
|
+
const yArr = y as GenType
|
|
137
|
+
const outArr = (out && out.length === xArr.length ? out : makeArr(xArr)) as GenType
|
|
138
|
+
if (xArr.length !== yArr.length)
|
|
139
|
+
throw `${xArr.length} length != ${yArr} length`
|
|
140
|
+
for (let i = 0; i < xArr.length; ++i)
|
|
141
|
+
outArr[i] = xArr[i] * (1 - t) + yArr[i] * t
|
|
142
|
+
return outArr
|
|
143
|
+
}
|
|
144
|
+
export const lerp = mix
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Returns 0 if x is less than edge, otherwise returns 1
|
|
148
|
+
*
|
|
149
|
+
* @param {Number} edge the threshold value
|
|
150
|
+
* @param {Number} x the value to test
|
|
151
|
+
* @returns {Number} 0 or 1
|
|
152
|
+
*/
|
|
153
|
+
export function step(edge: number, x: number): number
|
|
154
|
+
export function step<T extends GenType>(edge: number, x: T, out?: T): T
|
|
155
|
+
export function step<T extends GenType>(edge: T, x: T, out?: T): T
|
|
156
|
+
export function step<T extends number | GenType>(edge: T, x: T, out?: T extends GenType ? T : never) {
|
|
157
|
+
if (typeof x === 'number' && typeof edge === 'number')
|
|
158
|
+
return x < edge ? 0 : 1
|
|
159
|
+
const xArr = x as GenType
|
|
160
|
+
const outArr = (out && out.length === xArr.length ? out : makeArr(xArr)) as GenType
|
|
161
|
+
if (typeof edge === 'number') {
|
|
162
|
+
for (let i = 0; i < xArr.length; ++i)
|
|
163
|
+
outArr[i] = xArr[i] < edge ? 0 : 1
|
|
164
|
+
return outArr as T
|
|
165
|
+
}
|
|
166
|
+
const edgeArr = edge as GenType
|
|
167
|
+
if (xArr.length !== edgeArr.length)
|
|
168
|
+
throw `${xArr.length} length != ${edgeArr} length`
|
|
169
|
+
for (let i = 0; i < xArr.length; ++i)
|
|
170
|
+
outArr[i] = xArr[i] < edgeArr[i] ? 0 : 1
|
|
171
|
+
return outArr as T
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Performs Hermite interpolation between two values
|
|
176
|
+
*
|
|
177
|
+
* @param {Number} edge0 the lower edge of the Hermite function
|
|
178
|
+
* @param {Number} edge1 the upper edge of the Hermite function
|
|
179
|
+
* @param {Number} x the source value for interpolation
|
|
180
|
+
* @returns {Number} the interpolated value in the range [0, 1]
|
|
181
|
+
*/
|
|
182
|
+
export function smoothstep(edge0: number, edge1: number, x: number): number
|
|
183
|
+
export function smoothstep<T extends GenType>(edge0: T, edge1: T, x: number, out?: T): T
|
|
184
|
+
export function smoothstep<T extends GenType>(edge0: T, edge1: T, x: T, out?: T): T
|
|
185
|
+
export function smoothstep<T extends number | GenType>(edge0: T, edge1: T, x: T, out?: T extends GenType ? T : never) {
|
|
186
|
+
if (typeof edge0 === 'number' && typeof x === 'number') {
|
|
187
|
+
const t = clamp((x - edge0) / (edge1 as number - edge0), 0, 1)
|
|
188
|
+
return t * t * (3 - 2 * t)
|
|
189
|
+
}
|
|
190
|
+
const aArr = edge0 as GenType
|
|
191
|
+
const bArr = edge1 as GenType
|
|
192
|
+
if (aArr.length !== bArr.length)
|
|
193
|
+
throw `${aArr.length} length != ${bArr} length`
|
|
194
|
+
const outArr = (out && out.length === aArr.length ? out : makeArr(aArr)) as GenType
|
|
195
|
+
if (typeof x === 'number') {
|
|
196
|
+
for (let i = 0; i < aArr.length; ++i) {
|
|
197
|
+
const a = aArr[i]
|
|
198
|
+
const t = clamp((x - a) / (bArr[i] - a), 0, 1)
|
|
199
|
+
outArr[i] = t * t * (3 - 2 * t)
|
|
200
|
+
}
|
|
201
|
+
return outArr as T
|
|
202
|
+
}
|
|
203
|
+
const xArr = x as GenType
|
|
204
|
+
if (xArr.length !== aArr.length)
|
|
205
|
+
throw `${xArr.length} length != ${aArr} length`
|
|
206
|
+
for (let i = 0; i < aArr.length; ++i) {
|
|
207
|
+
const a = aArr[i]
|
|
208
|
+
const t = clamp((xArr[i] - a) / (bArr[i] - a), 0, 1)
|
|
209
|
+
outArr[i] = t * t * (3 - 2 * t)
|
|
210
|
+
}
|
|
211
|
+
return outArr as T
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Returns the fractional part of a number
|
|
216
|
+
*
|
|
217
|
+
* @param {Number} x the value
|
|
218
|
+
* @returns {Number} the fractional part of x
|
|
219
|
+
*/
|
|
220
|
+
export function fract(x: number): number
|
|
221
|
+
export function fract<T extends GenType>(x: T, out?: T): T
|
|
222
|
+
export function fract<T extends number | GenType>(x: T, out?: T extends GenType ? T : never) {
|
|
223
|
+
return calc1<T>(x => x - Math.floor(x), x, out)
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Returns the sign of a number
|
|
228
|
+
*
|
|
229
|
+
* @param {Number} x the value
|
|
230
|
+
* @returns {Number} -1, 0, or 1
|
|
231
|
+
*/
|
|
232
|
+
export function sign(x: number): number
|
|
233
|
+
export function sign<T extends GenType>(x: T, out?: T): T
|
|
234
|
+
export function sign<T extends number | GenType>(x: T, out?: T extends GenType ? T : never) {
|
|
235
|
+
return calc1<T>(x => x > 0 ? 1 : x < 0 ? -1 : 0, x, out)
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Returns the absolute value of the components of a number or vector
|
|
240
|
+
*
|
|
241
|
+
* @param {Number} x the value
|
|
242
|
+
* @returns {Number} -1, 0, or 1
|
|
243
|
+
*/
|
|
244
|
+
export function abs(x: number): number
|
|
245
|
+
export function abs<T extends GenType>(x: T, out?: T): T
|
|
246
|
+
export function abs<T extends number | GenType>(x: T, out?: T extends GenType ? T : never) {
|
|
247
|
+
return calc1<T>(x => Math.abs(x), x, out)
|
|
248
|
+
}
|