@pawells/math-extended 1.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/LICENSE +21 -0
- package/README.md +319 -0
- package/build/angles.d.ts +31 -0
- package/build/angles.d.ts.map +1 -0
- package/build/angles.js +85 -0
- package/build/angles.js.map +1 -0
- package/build/angles.spec.d.ts +2 -0
- package/build/angles.spec.d.ts.map +1 -0
- package/build/angles.spec.js +147 -0
- package/build/angles.spec.js.map +1 -0
- package/build/clamp.d.ts +17 -0
- package/build/clamp.d.ts.map +1 -0
- package/build/clamp.js +19 -0
- package/build/clamp.js.map +1 -0
- package/build/clamp.spec.d.ts +2 -0
- package/build/clamp.spec.d.ts.map +1 -0
- package/build/clamp.spec.js +19 -0
- package/build/clamp.spec.js.map +1 -0
- package/build/documentation-validation.spec.d.ts +11 -0
- package/build/documentation-validation.spec.d.ts.map +1 -0
- package/build/documentation-validation.spec.js +401 -0
- package/build/documentation-validation.spec.js.map +1 -0
- package/build/index.d.ts +8 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +8 -0
- package/build/index.js.map +1 -0
- package/build/interpolation.d.ts +175 -0
- package/build/interpolation.d.ts.map +1 -0
- package/build/interpolation.js +369 -0
- package/build/interpolation.js.map +1 -0
- package/build/interpolation.spec.d.ts +2 -0
- package/build/interpolation.spec.d.ts.map +1 -0
- package/build/interpolation.spec.js +480 -0
- package/build/interpolation.spec.js.map +1 -0
- package/build/matrices/arithmetic.d.ts +411 -0
- package/build/matrices/arithmetic.d.ts.map +1 -0
- package/build/matrices/arithmetic.js +954 -0
- package/build/matrices/arithmetic.js.map +1 -0
- package/build/matrices/arithmetic.spec.d.ts +2 -0
- package/build/matrices/arithmetic.spec.d.ts.map +1 -0
- package/build/matrices/arithmetic.spec.js +915 -0
- package/build/matrices/arithmetic.spec.js.map +1 -0
- package/build/matrices/asserts.d.ts +306 -0
- package/build/matrices/asserts.d.ts.map +1 -0
- package/build/matrices/asserts.js +396 -0
- package/build/matrices/asserts.js.map +1 -0
- package/build/matrices/asserts.spec.d.ts +2 -0
- package/build/matrices/asserts.spec.d.ts.map +1 -0
- package/build/matrices/asserts.spec.js +565 -0
- package/build/matrices/asserts.spec.js.map +1 -0
- package/build/matrices/core.d.ts +168 -0
- package/build/matrices/core.d.ts.map +1 -0
- package/build/matrices/core.js +457 -0
- package/build/matrices/core.js.map +1 -0
- package/build/matrices/core.spec.d.ts +2 -0
- package/build/matrices/core.spec.d.ts.map +1 -0
- package/build/matrices/core.spec.js +634 -0
- package/build/matrices/core.spec.js.map +1 -0
- package/build/matrices/decompositions.d.ts +326 -0
- package/build/matrices/decompositions.d.ts.map +1 -0
- package/build/matrices/decompositions.js +816 -0
- package/build/matrices/decompositions.js.map +1 -0
- package/build/matrices/decompositions.spec.d.ts +2 -0
- package/build/matrices/decompositions.spec.d.ts.map +1 -0
- package/build/matrices/decompositions.spec.js +195 -0
- package/build/matrices/decompositions.spec.js.map +1 -0
- package/build/matrices/index.d.ts +9 -0
- package/build/matrices/index.d.ts.map +1 -0
- package/build/matrices/index.js +9 -0
- package/build/matrices/index.js.map +1 -0
- package/build/matrices/linear-algebra.d.ts +64 -0
- package/build/matrices/linear-algebra.d.ts.map +1 -0
- package/build/matrices/linear-algebra.js +253 -0
- package/build/matrices/linear-algebra.js.map +1 -0
- package/build/matrices/linear-algebra.spec.d.ts +2 -0
- package/build/matrices/linear-algebra.spec.d.ts.map +1 -0
- package/build/matrices/linear-algebra.spec.js +355 -0
- package/build/matrices/linear-algebra.spec.js.map +1 -0
- package/build/matrices/normalization.d.ts +62 -0
- package/build/matrices/normalization.d.ts.map +1 -0
- package/build/matrices/normalization.js +167 -0
- package/build/matrices/normalization.js.map +1 -0
- package/build/matrices/normalization.spec.d.ts +2 -0
- package/build/matrices/normalization.spec.d.ts.map +1 -0
- package/build/matrices/normalization.spec.js +335 -0
- package/build/matrices/normalization.spec.js.map +1 -0
- package/build/matrices/transformations.d.ts +484 -0
- package/build/matrices/transformations.d.ts.map +1 -0
- package/build/matrices/transformations.js +592 -0
- package/build/matrices/transformations.js.map +1 -0
- package/build/matrices/transformations.spec.d.ts +2 -0
- package/build/matrices/transformations.spec.d.ts.map +1 -0
- package/build/matrices/transformations.spec.js +755 -0
- package/build/matrices/transformations.spec.js.map +1 -0
- package/build/matrices/types.d.ts +134 -0
- package/build/matrices/types.d.ts.map +1 -0
- package/build/matrices/types.js +6 -0
- package/build/matrices/types.js.map +1 -0
- package/build/quaternions/asserts.d.ts +77 -0
- package/build/quaternions/asserts.d.ts.map +1 -0
- package/build/quaternions/asserts.js +175 -0
- package/build/quaternions/asserts.js.map +1 -0
- package/build/quaternions/asserts.spec.d.ts +2 -0
- package/build/quaternions/asserts.spec.d.ts.map +1 -0
- package/build/quaternions/asserts.spec.js +320 -0
- package/build/quaternions/asserts.spec.js.map +1 -0
- package/build/quaternions/conversions.d.ts +73 -0
- package/build/quaternions/conversions.d.ts.map +1 -0
- package/build/quaternions/conversions.js +179 -0
- package/build/quaternions/conversions.js.map +1 -0
- package/build/quaternions/conversions.spec.d.ts +2 -0
- package/build/quaternions/conversions.spec.d.ts.map +1 -0
- package/build/quaternions/conversions.spec.js +344 -0
- package/build/quaternions/conversions.spec.js.map +1 -0
- package/build/quaternions/core.d.ts +203 -0
- package/build/quaternions/core.d.ts.map +1 -0
- package/build/quaternions/core.js +374 -0
- package/build/quaternions/core.js.map +1 -0
- package/build/quaternions/core.spec.d.ts +2 -0
- package/build/quaternions/core.spec.d.ts.map +1 -0
- package/build/quaternions/core.spec.js +294 -0
- package/build/quaternions/core.spec.js.map +1 -0
- package/build/quaternions/index.d.ts +7 -0
- package/build/quaternions/index.d.ts.map +1 -0
- package/build/quaternions/index.js +7 -0
- package/build/quaternions/index.js.map +1 -0
- package/build/quaternions/interpolation.d.ts +54 -0
- package/build/quaternions/interpolation.d.ts.map +1 -0
- package/build/quaternions/interpolation.js +201 -0
- package/build/quaternions/interpolation.js.map +1 -0
- package/build/quaternions/interpolation.spec.d.ts +2 -0
- package/build/quaternions/interpolation.spec.d.ts.map +1 -0
- package/build/quaternions/interpolation.spec.js +64 -0
- package/build/quaternions/interpolation.spec.js.map +1 -0
- package/build/quaternions/predefined.d.ts +36 -0
- package/build/quaternions/predefined.d.ts.map +1 -0
- package/build/quaternions/predefined.js +42 -0
- package/build/quaternions/predefined.js.map +1 -0
- package/build/quaternions/predefined.spec.d.ts +2 -0
- package/build/quaternions/predefined.spec.d.ts.map +1 -0
- package/build/quaternions/predefined.spec.js +35 -0
- package/build/quaternions/predefined.spec.js.map +1 -0
- package/build/quaternions/types.d.ts +55 -0
- package/build/quaternions/types.d.ts.map +1 -0
- package/build/quaternions/types.js +7 -0
- package/build/quaternions/types.js.map +1 -0
- package/build/random.d.ts +66 -0
- package/build/random.d.ts.map +1 -0
- package/build/random.js +115 -0
- package/build/random.js.map +1 -0
- package/build/random.spec.d.ts +2 -0
- package/build/random.spec.d.ts.map +1 -0
- package/build/random.spec.js +267 -0
- package/build/random.spec.js.map +1 -0
- package/build/vectors/asserts.d.ts +182 -0
- package/build/vectors/asserts.d.ts.map +1 -0
- package/build/vectors/asserts.js +285 -0
- package/build/vectors/asserts.js.map +1 -0
- package/build/vectors/asserts.spec.d.ts +2 -0
- package/build/vectors/asserts.spec.d.ts.map +1 -0
- package/build/vectors/asserts.spec.js +260 -0
- package/build/vectors/asserts.spec.js.map +1 -0
- package/build/vectors/core.d.ts +507 -0
- package/build/vectors/core.d.ts.map +1 -0
- package/build/vectors/core.js +825 -0
- package/build/vectors/core.js.map +1 -0
- package/build/vectors/core.spec.d.ts +2 -0
- package/build/vectors/core.spec.d.ts.map +1 -0
- package/build/vectors/core.spec.js +343 -0
- package/build/vectors/core.spec.js.map +1 -0
- package/build/vectors/index.d.ts +6 -0
- package/build/vectors/index.d.ts.map +1 -0
- package/build/vectors/index.js +6 -0
- package/build/vectors/index.js.map +1 -0
- package/build/vectors/interpolation.d.ts +404 -0
- package/build/vectors/interpolation.d.ts.map +1 -0
- package/build/vectors/interpolation.js +585 -0
- package/build/vectors/interpolation.js.map +1 -0
- package/build/vectors/interpolation.spec.d.ts +2 -0
- package/build/vectors/interpolation.spec.d.ts.map +1 -0
- package/build/vectors/interpolation.spec.js +378 -0
- package/build/vectors/interpolation.spec.js.map +1 -0
- package/build/vectors/predefined.d.ts +191 -0
- package/build/vectors/predefined.d.ts.map +1 -0
- package/build/vectors/predefined.js +191 -0
- package/build/vectors/predefined.js.map +1 -0
- package/build/vectors/predefined.spec.d.ts +2 -0
- package/build/vectors/predefined.spec.d.ts.map +1 -0
- package/build/vectors/predefined.spec.js +333 -0
- package/build/vectors/predefined.spec.js.map +1 -0
- package/build/vectors/types.d.ts +62 -0
- package/build/vectors/types.d.ts.map +1 -0
- package/build/vectors/types.js +6 -0
- package/build/vectors/types.js.map +1 -0
- package/package.json +75 -0
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
import { QuaternionIdentity, QuaternionEquals, QuaternionNormalize } from './core.js';
|
|
2
|
+
import { QuaternionRotationX, QuaternionRotationY, QuaternionRotationZ } from './predefined.js';
|
|
3
|
+
import { QuaternionError } from './asserts.js';
|
|
4
|
+
import { DegreesToRadians } from '../angles.ts';
|
|
5
|
+
import { IsValidRotationMatrix, QuaternionFromRotationMatrix, QuaternionFromTransformationMatrix, QuaternionToRotationMatrix, QuaternionToTransformationMatrix } from './conversions.js';
|
|
6
|
+
import { AssertMatrixRow, AssertMatrixValue } from '../matrices/asserts.ts';
|
|
7
|
+
describe('Quaternion Conversions', () => {
|
|
8
|
+
const TOLERANCE = 1e-6;
|
|
9
|
+
describe('QuaternionToRotationMatrix', () => {
|
|
10
|
+
test('should convert identity quaternion to identity matrix', () => {
|
|
11
|
+
const quaternion = QuaternionIdentity();
|
|
12
|
+
const matrix = QuaternionToRotationMatrix(quaternion);
|
|
13
|
+
const expectedMatrix = [
|
|
14
|
+
[1, 0, 0],
|
|
15
|
+
[0, 1, 0],
|
|
16
|
+
[0, 0, 1],
|
|
17
|
+
];
|
|
18
|
+
expect(matrix).toEqual(expectedMatrix);
|
|
19
|
+
});
|
|
20
|
+
test('should convert 90-degree rotation around X-axis', () => {
|
|
21
|
+
const quaternion = QuaternionRotationX(DegreesToRadians(90));
|
|
22
|
+
const matrix = QuaternionToRotationMatrix(quaternion);
|
|
23
|
+
// 90° rotation around X should transform Y to Z and Z to -Y
|
|
24
|
+
expect(matrix[0][0]).toBeCloseTo(1, 5);
|
|
25
|
+
expect(matrix[0][1]).toBeCloseTo(0, 5);
|
|
26
|
+
expect(matrix[0][2]).toBeCloseTo(0, 5);
|
|
27
|
+
expect(matrix[1][0]).toBeCloseTo(0, 5);
|
|
28
|
+
expect(matrix[1][1]).toBeCloseTo(0, 5);
|
|
29
|
+
expect(matrix[1][2]).toBeCloseTo(-1, 5);
|
|
30
|
+
expect(matrix[2][0]).toBeCloseTo(0, 5);
|
|
31
|
+
expect(matrix[2][1]).toBeCloseTo(1, 5);
|
|
32
|
+
expect(matrix[2][2]).toBeCloseTo(0, 5);
|
|
33
|
+
});
|
|
34
|
+
test('should convert 90-degree rotation around Y-axis', () => {
|
|
35
|
+
const quaternion = QuaternionRotationY(DegreesToRadians(90));
|
|
36
|
+
const matrix = QuaternionToRotationMatrix(quaternion);
|
|
37
|
+
// 90° rotation around Y should transform X to -Z and Z to X
|
|
38
|
+
expect(matrix[0][0]).toBeCloseTo(0, 5);
|
|
39
|
+
expect(matrix[0][1]).toBeCloseTo(0, 5);
|
|
40
|
+
expect(matrix[0][2]).toBeCloseTo(1, 5);
|
|
41
|
+
expect(matrix[1][0]).toBeCloseTo(0, 5);
|
|
42
|
+
expect(matrix[1][1]).toBeCloseTo(1, 5);
|
|
43
|
+
expect(matrix[1][2]).toBeCloseTo(0, 5);
|
|
44
|
+
expect(matrix[2][0]).toBeCloseTo(-1, 5);
|
|
45
|
+
expect(matrix[2][1]).toBeCloseTo(0, 5);
|
|
46
|
+
expect(matrix[2][2]).toBeCloseTo(0, 5);
|
|
47
|
+
});
|
|
48
|
+
test('should convert 90-degree rotation around Z-axis', () => {
|
|
49
|
+
const quaternion = QuaternionRotationZ(DegreesToRadians(90));
|
|
50
|
+
const matrix = QuaternionToRotationMatrix(quaternion);
|
|
51
|
+
// 90° rotation around Z should transform X to Y and Y to -X
|
|
52
|
+
expect(matrix[0][0]).toBeCloseTo(0, 5);
|
|
53
|
+
expect(matrix[0][1]).toBeCloseTo(-1, 5);
|
|
54
|
+
expect(matrix[0][2]).toBeCloseTo(0, 5);
|
|
55
|
+
expect(matrix[1][0]).toBeCloseTo(1, 5);
|
|
56
|
+
expect(matrix[1][1]).toBeCloseTo(0, 5);
|
|
57
|
+
expect(matrix[1][2]).toBeCloseTo(0, 5);
|
|
58
|
+
expect(matrix[2][0]).toBeCloseTo(0, 5);
|
|
59
|
+
expect(matrix[2][1]).toBeCloseTo(0, 5);
|
|
60
|
+
expect(matrix[2][2]).toBeCloseTo(1, 5);
|
|
61
|
+
});
|
|
62
|
+
test('should throw for non-normalized quaternion', () => {
|
|
63
|
+
const nonNormalized = [1, 1, 1, 1];
|
|
64
|
+
expect(() => QuaternionToRotationMatrix(nonNormalized)).toThrow(QuaternionError);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
describe('QuaternionFromRotationMatrix', () => {
|
|
68
|
+
test('should convert identity matrix to identity quaternion', () => {
|
|
69
|
+
const identityMatrix = [
|
|
70
|
+
[1, 0, 0],
|
|
71
|
+
[0, 1, 0],
|
|
72
|
+
[0, 0, 1],
|
|
73
|
+
];
|
|
74
|
+
const quaternion = QuaternionFromRotationMatrix(identityMatrix);
|
|
75
|
+
const expected = QuaternionIdentity();
|
|
76
|
+
expect(QuaternionEquals(quaternion, expected, TOLERANCE, true)).toBe(true);
|
|
77
|
+
});
|
|
78
|
+
test('should convert 90-degree X rotation matrix', () => {
|
|
79
|
+
const matrix = [
|
|
80
|
+
[1, 0, 0],
|
|
81
|
+
[0, 0, -1],
|
|
82
|
+
[0, 1, 0],
|
|
83
|
+
];
|
|
84
|
+
const quaternion = QuaternionFromRotationMatrix(matrix);
|
|
85
|
+
const expected = QuaternionRotationX(DegreesToRadians(90));
|
|
86
|
+
expect(QuaternionEquals(quaternion, expected, TOLERANCE, true)).toBe(true);
|
|
87
|
+
});
|
|
88
|
+
test('should convert 90-degree Y rotation matrix', () => {
|
|
89
|
+
const matrix = [
|
|
90
|
+
[0, 0, 1],
|
|
91
|
+
[0, 1, 0],
|
|
92
|
+
[-1, 0, 0],
|
|
93
|
+
];
|
|
94
|
+
const quaternion = QuaternionFromRotationMatrix(matrix);
|
|
95
|
+
const expected = QuaternionRotationY(DegreesToRadians(90));
|
|
96
|
+
expect(QuaternionEquals(quaternion, expected, TOLERANCE, true)).toBe(true);
|
|
97
|
+
});
|
|
98
|
+
test('should convert 90-degree Z rotation matrix', () => {
|
|
99
|
+
const matrix = [
|
|
100
|
+
[0, -1, 0],
|
|
101
|
+
[1, 0, 0],
|
|
102
|
+
[0, 0, 1],
|
|
103
|
+
];
|
|
104
|
+
const quaternion = QuaternionFromRotationMatrix(matrix);
|
|
105
|
+
const expected = QuaternionRotationZ(DegreesToRadians(90));
|
|
106
|
+
expect(QuaternionEquals(quaternion, expected, TOLERANCE, true)).toBe(true);
|
|
107
|
+
});
|
|
108
|
+
test('should handle matrix with largest diagonal element in different positions', () => {
|
|
109
|
+
// Test case where m11 is largest
|
|
110
|
+
const matrix = [
|
|
111
|
+
[0, 0, 1],
|
|
112
|
+
[0, 1, 0],
|
|
113
|
+
[-1, 0, 0],
|
|
114
|
+
];
|
|
115
|
+
const quaternion = QuaternionFromRotationMatrix(matrix);
|
|
116
|
+
expect(quaternion).toHaveLength(4);
|
|
117
|
+
expect(Math.abs(Math.sqrt((quaternion[0] ** 2) + (quaternion[1] ** 2) + (quaternion[2] ** 2) + (quaternion[3] ** 2)) - 1)).toBeLessThan(TOLERANCE);
|
|
118
|
+
});
|
|
119
|
+
test('should handle matrix with largest diagonal element m22', () => {
|
|
120
|
+
// Test case where m22 is largest
|
|
121
|
+
const matrix = [
|
|
122
|
+
[0, 1, 0],
|
|
123
|
+
[-1, 0, 0],
|
|
124
|
+
[0, 0, 1],
|
|
125
|
+
];
|
|
126
|
+
const quaternion = QuaternionFromRotationMatrix(matrix);
|
|
127
|
+
expect(quaternion).toHaveLength(4);
|
|
128
|
+
expect(Math.abs(Math.sqrt((quaternion[0] ** 2) + (quaternion[1] ** 2) + (quaternion[2] ** 2) + (quaternion[3] ** 2)) - 1)).toBeLessThan(TOLERANCE);
|
|
129
|
+
});
|
|
130
|
+
test('should throw for invalid matrix dimensions', () => {
|
|
131
|
+
const invalidMatrix = [[1, 0], [0, 1]];
|
|
132
|
+
expect(() => QuaternionFromRotationMatrix(invalidMatrix)).toThrow();
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
describe('QuaternionToTransformationMatrix', () => {
|
|
136
|
+
test('should convert identity quaternion to 4x4 identity matrix', () => {
|
|
137
|
+
const quaternion = QuaternionIdentity();
|
|
138
|
+
const matrix4x4 = QuaternionToTransformationMatrix(quaternion);
|
|
139
|
+
const expected = [
|
|
140
|
+
[1, 0, 0, 0],
|
|
141
|
+
[0, 1, 0, 0],
|
|
142
|
+
[0, 0, 1, 0],
|
|
143
|
+
[0, 0, 0, 1],
|
|
144
|
+
];
|
|
145
|
+
expect(matrix4x4).toEqual(expected);
|
|
146
|
+
});
|
|
147
|
+
test('should convert rotation quaternion to 4x4 transformation matrix', () => {
|
|
148
|
+
const quaternion = QuaternionRotationZ(DegreesToRadians(90));
|
|
149
|
+
const matrix4x4 = QuaternionToTransformationMatrix(quaternion);
|
|
150
|
+
// Should be a 4x4 matrix
|
|
151
|
+
expect(matrix4x4).toHaveLength(4);
|
|
152
|
+
expect(matrix4x4[0]).toHaveLength(4);
|
|
153
|
+
// Last row should be [0, 0, 0, 1]
|
|
154
|
+
expect(matrix4x4[3][0]).toBeCloseTo(0, 5);
|
|
155
|
+
expect(matrix4x4[3][1]).toBeCloseTo(0, 5);
|
|
156
|
+
expect(matrix4x4[3][2]).toBeCloseTo(0, 5);
|
|
157
|
+
expect(matrix4x4[3][3]).toBeCloseTo(1, 5);
|
|
158
|
+
// Translation elements should be 0
|
|
159
|
+
expect(matrix4x4[0][3]).toBeCloseTo(0, 5);
|
|
160
|
+
expect(matrix4x4[1][3]).toBeCloseTo(0, 5);
|
|
161
|
+
expect(matrix4x4[2][3]).toBeCloseTo(0, 5);
|
|
162
|
+
});
|
|
163
|
+
test('should maintain rotation properties in 4x4 matrix', () => {
|
|
164
|
+
const quaternion = QuaternionRotationX(DegreesToRadians(45));
|
|
165
|
+
const matrix4x4 = QuaternionToTransformationMatrix(quaternion);
|
|
166
|
+
// Extract 3x3 rotation part
|
|
167
|
+
const rotationMatrix = [
|
|
168
|
+
[matrix4x4[0][0], matrix4x4[0][1], matrix4x4[0][2]],
|
|
169
|
+
[matrix4x4[1][0], matrix4x4[1][1], matrix4x4[1][2]],
|
|
170
|
+
[matrix4x4[2][0], matrix4x4[2][1], matrix4x4[2][2]],
|
|
171
|
+
];
|
|
172
|
+
expect(IsValidRotationMatrix(rotationMatrix)).toBe(true);
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
describe('QuaternionFromTransformationMatrix', () => {
|
|
176
|
+
test('should extract rotation from 4x4 identity matrix', () => {
|
|
177
|
+
const matrix4x4 = [
|
|
178
|
+
[1, 0, 0, 0],
|
|
179
|
+
[0, 1, 0, 0],
|
|
180
|
+
[0, 0, 1, 0],
|
|
181
|
+
[0, 0, 0, 1],
|
|
182
|
+
];
|
|
183
|
+
const quaternion = QuaternionFromTransformationMatrix(matrix4x4);
|
|
184
|
+
const expected = QuaternionIdentity();
|
|
185
|
+
expect(QuaternionEquals(quaternion, expected, TOLERANCE, true)).toBe(true);
|
|
186
|
+
});
|
|
187
|
+
test('should extract rotation ignoring translation', () => {
|
|
188
|
+
const matrix4x4 = [
|
|
189
|
+
[1, 0, 0, 5], // Translation in X
|
|
190
|
+
[0, 1, 0, 10], // Translation in Y
|
|
191
|
+
[0, 0, 1, 15], // Translation in Z
|
|
192
|
+
[0, 0, 0, 1],
|
|
193
|
+
];
|
|
194
|
+
const quaternion = QuaternionFromTransformationMatrix(matrix4x4);
|
|
195
|
+
const expected = QuaternionIdentity();
|
|
196
|
+
expect(QuaternionEquals(quaternion, expected, TOLERANCE, true)).toBe(true);
|
|
197
|
+
});
|
|
198
|
+
test('should extract rotation with translation present', () => {
|
|
199
|
+
// Create a Z-rotation matrix with translation
|
|
200
|
+
const cos90 = Math.cos(DegreesToRadians(90));
|
|
201
|
+
const sin90 = Math.sin(DegreesToRadians(90));
|
|
202
|
+
const matrix4x4 = [
|
|
203
|
+
[cos90, -sin90, 0, 100],
|
|
204
|
+
[sin90, cos90, 0, 200],
|
|
205
|
+
[0, 0, 1, 300],
|
|
206
|
+
[0, 0, 0, 1],
|
|
207
|
+
];
|
|
208
|
+
const quaternion = QuaternionFromTransformationMatrix(matrix4x4);
|
|
209
|
+
const expected = QuaternionRotationZ(DegreesToRadians(90));
|
|
210
|
+
expect(QuaternionEquals(quaternion, expected, TOLERANCE, true)).toBe(true);
|
|
211
|
+
});
|
|
212
|
+
test('should throw for invalid matrix structure', () => {
|
|
213
|
+
const invalidMatrix = [[1, 0], [0, 1]];
|
|
214
|
+
expect(() => QuaternionFromTransformationMatrix(invalidMatrix)).toThrow();
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
describe('IsValidRotationMatrix', () => {
|
|
218
|
+
test('should validate identity matrix', () => {
|
|
219
|
+
const identityMatrix = [
|
|
220
|
+
[1, 0, 0],
|
|
221
|
+
[0, 1, 0],
|
|
222
|
+
[0, 0, 1],
|
|
223
|
+
];
|
|
224
|
+
expect(IsValidRotationMatrix(identityMatrix)).toBe(true);
|
|
225
|
+
});
|
|
226
|
+
test('should validate proper rotation matrices', () => {
|
|
227
|
+
// 90-degree rotation around Z-axis
|
|
228
|
+
const rotationZ = [
|
|
229
|
+
[0, -1, 0],
|
|
230
|
+
[1, 0, 0],
|
|
231
|
+
[0, 0, 1],
|
|
232
|
+
];
|
|
233
|
+
expect(IsValidRotationMatrix(rotationZ)).toBe(true);
|
|
234
|
+
});
|
|
235
|
+
test('should reject non-orthogonal matrix', () => {
|
|
236
|
+
const nonOrthogonal = [
|
|
237
|
+
[1, 1, 0], // Not orthogonal
|
|
238
|
+
[0, 1, 0],
|
|
239
|
+
[0, 0, 1],
|
|
240
|
+
];
|
|
241
|
+
expect(IsValidRotationMatrix(nonOrthogonal)).toBe(false);
|
|
242
|
+
});
|
|
243
|
+
test('should reject matrix with non-unit column vectors', () => {
|
|
244
|
+
const nonUnit = [
|
|
245
|
+
[2, 0, 0], // Column 1 has length 2, not 1
|
|
246
|
+
[0, 1, 0],
|
|
247
|
+
[0, 0, 1],
|
|
248
|
+
];
|
|
249
|
+
expect(IsValidRotationMatrix(nonUnit)).toBe(false);
|
|
250
|
+
});
|
|
251
|
+
test('should reject matrix with determinant -1 (reflection)', () => {
|
|
252
|
+
const reflection = [
|
|
253
|
+
[-1, 0, 0], // Reflection, det = -1
|
|
254
|
+
[0, 1, 0],
|
|
255
|
+
[0, 0, 1],
|
|
256
|
+
];
|
|
257
|
+
expect(IsValidRotationMatrix(reflection)).toBe(false);
|
|
258
|
+
});
|
|
259
|
+
test('should respect custom tolerance', () => {
|
|
260
|
+
const almostValid = [
|
|
261
|
+
[1.0001, 0, 0], // Slightly off from 1
|
|
262
|
+
[0, 1, 0],
|
|
263
|
+
[0, 0, 1],
|
|
264
|
+
];
|
|
265
|
+
expect(IsValidRotationMatrix(almostValid, 1e-6)).toBe(false);
|
|
266
|
+
expect(IsValidRotationMatrix(almostValid, 1e-3)).toBe(true);
|
|
267
|
+
});
|
|
268
|
+
test('should validate complex rotation matrix', () => {
|
|
269
|
+
// 45-degree rotation around Y-axis
|
|
270
|
+
const cos45 = Math.cos(DegreesToRadians(45));
|
|
271
|
+
const sin45 = Math.sin(DegreesToRadians(45));
|
|
272
|
+
const rotationY = [
|
|
273
|
+
[cos45, 0, sin45],
|
|
274
|
+
[0, 1, 0],
|
|
275
|
+
[-sin45, 0, cos45],
|
|
276
|
+
];
|
|
277
|
+
expect(IsValidRotationMatrix(rotationY)).toBe(true);
|
|
278
|
+
});
|
|
279
|
+
});
|
|
280
|
+
describe('Round-trip conversions', () => {
|
|
281
|
+
test('quaternion -> matrix -> quaternion should preserve rotation', () => {
|
|
282
|
+
const originalQuaternion = QuaternionRotationX(DegreesToRadians(45));
|
|
283
|
+
const matrix = QuaternionToRotationMatrix(originalQuaternion);
|
|
284
|
+
const convertedQuaternion = QuaternionFromRotationMatrix(matrix);
|
|
285
|
+
expect(QuaternionEquals(originalQuaternion, convertedQuaternion, TOLERANCE, true)).toBe(true);
|
|
286
|
+
});
|
|
287
|
+
test('matrix -> quaternion -> matrix should preserve matrix', () => {
|
|
288
|
+
const originalMatrix = [
|
|
289
|
+
[0, -1, 0],
|
|
290
|
+
[1, 0, 0],
|
|
291
|
+
[0, 0, 1],
|
|
292
|
+
];
|
|
293
|
+
const quaternion = QuaternionFromRotationMatrix(originalMatrix);
|
|
294
|
+
const convertedMatrix = QuaternionToRotationMatrix(quaternion);
|
|
295
|
+
// Compare each element
|
|
296
|
+
for (let i = 0; i < 3; i++) {
|
|
297
|
+
const originalRow = originalMatrix[i];
|
|
298
|
+
AssertMatrixRow(originalRow);
|
|
299
|
+
const convertedRow = convertedMatrix[i];
|
|
300
|
+
AssertMatrixRow(convertedRow);
|
|
301
|
+
for (let j = 0; j < 3; j++) {
|
|
302
|
+
const originalValue = originalRow[j];
|
|
303
|
+
AssertMatrixValue(originalValue);
|
|
304
|
+
const convertedValue = convertedRow[j];
|
|
305
|
+
AssertMatrixValue(convertedValue);
|
|
306
|
+
expect(convertedValue).toBeCloseTo(originalValue, 5);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
});
|
|
310
|
+
test('quaternion -> 4x4 matrix -> quaternion should preserve rotation', () => {
|
|
311
|
+
const originalQuaternion = QuaternionRotationY(DegreesToRadians(60));
|
|
312
|
+
const matrix4x4 = QuaternionToTransformationMatrix(originalQuaternion);
|
|
313
|
+
const convertedQuaternion = QuaternionFromTransformationMatrix(matrix4x4);
|
|
314
|
+
expect(QuaternionEquals(originalQuaternion, convertedQuaternion, TOLERANCE, true)).toBe(true);
|
|
315
|
+
});
|
|
316
|
+
});
|
|
317
|
+
describe('Edge cases and error conditions', () => {
|
|
318
|
+
test('should handle zero quaternion input for conversion functions', () => {
|
|
319
|
+
const zeroQuaternion = [0, 0, 0, 0];
|
|
320
|
+
expect(() => QuaternionToRotationMatrix(zeroQuaternion)).toThrow(QuaternionError);
|
|
321
|
+
});
|
|
322
|
+
test('should handle very small quaternion components', () => {
|
|
323
|
+
const smallQuaternion = QuaternionNormalize([1e-10, 1e-10, 1e-10, 1e-10]);
|
|
324
|
+
const matrix = QuaternionToRotationMatrix(smallQuaternion);
|
|
325
|
+
const convertedBack = QuaternionFromRotationMatrix(matrix);
|
|
326
|
+
expect(QuaternionEquals(smallQuaternion, convertedBack, TOLERANCE, true)).toBe(true);
|
|
327
|
+
});
|
|
328
|
+
test('should handle matrices from known quaternion conversions', () => {
|
|
329
|
+
// Test all the branch conditions in QuaternionFromRotationMatrix
|
|
330
|
+
const testQuaternions = [
|
|
331
|
+
QuaternionRotationX(DegreesToRadians(30)),
|
|
332
|
+
QuaternionRotationY(DegreesToRadians(60)),
|
|
333
|
+
QuaternionRotationZ(DegreesToRadians(120)),
|
|
334
|
+
QuaternionNormalize([0.5, 0.5, 0.5, 0.5]),
|
|
335
|
+
];
|
|
336
|
+
for (const quaternion of testQuaternions) {
|
|
337
|
+
const matrix = QuaternionToRotationMatrix(quaternion);
|
|
338
|
+
const convertedBack = QuaternionFromRotationMatrix(matrix);
|
|
339
|
+
expect(QuaternionEquals(quaternion, convertedBack, TOLERANCE, true)).toBe(true);
|
|
340
|
+
}
|
|
341
|
+
});
|
|
342
|
+
});
|
|
343
|
+
});
|
|
344
|
+
//# sourceMappingURL=conversions.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conversions.spec.js","sourceRoot":"","sources":["../../src/quaternions/conversions.spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core quaternion mathematics operations for rotation and orientation calculations.
|
|
3
|
+
* Provides comprehensive quaternion operations with conversion utilities and interpolation.
|
|
4
|
+
*/
|
|
5
|
+
import { TVector3 } from '../vectors/types.js';
|
|
6
|
+
import { TQuaternion, TEulerAngles, TAxisAngle } from './types.js';
|
|
7
|
+
/**
|
|
8
|
+
* Creates an identity quaternion representing no rotation.
|
|
9
|
+
* The identity quaternion is [0, 0, 0, 1] (x, y, z, w).
|
|
10
|
+
*
|
|
11
|
+
* @returns Identity quaternion [0, 0, 0, 1]
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* const identity = QuaternionIdentity();
|
|
15
|
+
* console.log(identity); // [0, 0, 0, 1]
|
|
16
|
+
*/
|
|
17
|
+
export declare function QuaternionIdentity(): TQuaternion;
|
|
18
|
+
/**
|
|
19
|
+
* Creates a deep copy of a quaternion.
|
|
20
|
+
* Essential for avoiding mutations during operations.
|
|
21
|
+
*
|
|
22
|
+
* @param quaternion - The quaternion to clone
|
|
23
|
+
* @returns A new quaternion with identical components
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* const original = [0, 0, 0.707, 0.707];
|
|
27
|
+
* const copy = QuaternionClone(original);
|
|
28
|
+
* copy[0] = 1; // original remains unchanged
|
|
29
|
+
*/
|
|
30
|
+
export declare function QuaternionClone(quaternion: TQuaternion): TQuaternion;
|
|
31
|
+
/**
|
|
32
|
+
* Compares two quaternions for equality with optional tolerance.
|
|
33
|
+
* Note: Quaternions q and -q represent the same rotation, but this function
|
|
34
|
+
* checks for exact component equality unless checkEquivalence is true.
|
|
35
|
+
*
|
|
36
|
+
* @param a - First quaternion to compare
|
|
37
|
+
* @param b - Second quaternion to compare
|
|
38
|
+
* @param tolerance - Maximum allowed difference between components (default: 1e-6)
|
|
39
|
+
* @param checkEquivalence - If true, also check if quaternions represent the same rotation (default: false)
|
|
40
|
+
* @returns True if quaternions are equal within tolerance
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* const q1 = [0, 0, 0, 1];
|
|
44
|
+
* const q2 = [0, 0, 0, -1];
|
|
45
|
+
* console.log(QuaternionEquals(q1, q2)); // false (different components)
|
|
46
|
+
* console.log(QuaternionEquals(q1, q2, 1e-6, true)); // true (same rotation)
|
|
47
|
+
*/
|
|
48
|
+
export declare function QuaternionEquals(a: TQuaternion, b: TQuaternion, tolerance?: number, checkEquivalence?: boolean): boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Calculates the magnitude (length) of a quaternion.
|
|
51
|
+
* For unit quaternions (valid rotations), this should be 1.
|
|
52
|
+
*
|
|
53
|
+
* @param quaternion - The quaternion to measure
|
|
54
|
+
* @returns The magnitude of the quaternion
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* const q = [0, 0, 0, 1];
|
|
58
|
+
* console.log(QuaternionMagnitude(q)); // 1
|
|
59
|
+
*/
|
|
60
|
+
export declare function QuaternionMagnitude(quaternion: TQuaternion): number;
|
|
61
|
+
/**
|
|
62
|
+
* Normalizes a quaternion to unit length.
|
|
63
|
+
* Essential for ensuring quaternions represent valid rotations.
|
|
64
|
+
*
|
|
65
|
+
* @param quaternion - The quaternion to normalize
|
|
66
|
+
* @returns A normalized quaternion with magnitude 1
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* const q = [1, 1, 1, 1];
|
|
70
|
+
* const normalized = QuaternionNormalize(q);
|
|
71
|
+
* console.log(QuaternionMagnitude(normalized)); // 1
|
|
72
|
+
*/
|
|
73
|
+
export declare function QuaternionNormalize(quaternion: TQuaternion): TQuaternion;
|
|
74
|
+
/**
|
|
75
|
+
* Calculates the conjugate of a quaternion.
|
|
76
|
+
* The conjugate of [x, y, z, w] is [-x, -y, -z, w].
|
|
77
|
+
* For unit quaternions, the conjugate represents the inverse rotation.
|
|
78
|
+
*
|
|
79
|
+
* @param quaternion - The quaternion to conjugate
|
|
80
|
+
* @returns The conjugate quaternion
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* const q = [0.5, 0.5, 0.5, 0.5];
|
|
84
|
+
* const conjugate = QuaternionConjugate(q);
|
|
85
|
+
* console.log(conjugate); // [-0.5, -0.5, -0.5, 0.5]
|
|
86
|
+
*/
|
|
87
|
+
export declare function QuaternionConjugate(quaternion: TQuaternion): TQuaternion;
|
|
88
|
+
/**
|
|
89
|
+
* Calculates the inverse of a quaternion.
|
|
90
|
+
* For unit quaternions, the inverse equals the conjugate.
|
|
91
|
+
* For non-unit quaternions, the inverse is conjugate divided by magnitude squared.
|
|
92
|
+
*
|
|
93
|
+
* @param quaternion - The quaternion to invert
|
|
94
|
+
* @returns The inverse quaternion
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* const q = [0, 0, 0.707, 0.707]; // 90° rotation around Z
|
|
98
|
+
* const inverse = QuaternionInverse(q); // -90° rotation around Z
|
|
99
|
+
*/
|
|
100
|
+
export declare function QuaternionInverse(quaternion: TQuaternion): TQuaternion;
|
|
101
|
+
/**
|
|
102
|
+
* Multiplies two quaternions.
|
|
103
|
+
* Quaternion multiplication represents composition of rotations.
|
|
104
|
+
* Note: Quaternion multiplication is not commutative (order matters).
|
|
105
|
+
*
|
|
106
|
+
* @param a - First quaternion (applied second in rotation order)
|
|
107
|
+
* @param b - Second quaternion (applied first in rotation order)
|
|
108
|
+
* @returns The product quaternion representing the combined rotation
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* const rotX = QuaternionFromAxisAngle([1, 0, 0], Math.PI/2); // 90° around X
|
|
112
|
+
* const rotY = QuaternionFromAxisAngle([0, 1, 0], Math.PI/2); // 90° around Y
|
|
113
|
+
* const combined = QuaternionMultiply(rotX, rotY); // Y rotation then X rotation
|
|
114
|
+
*/
|
|
115
|
+
export declare function QuaternionMultiply(a: TQuaternion, b: TQuaternion): TQuaternion;
|
|
116
|
+
/**
|
|
117
|
+
* Creates a quaternion from an axis-angle representation.
|
|
118
|
+
* The axis should be normalized, and the angle is in radians.
|
|
119
|
+
*
|
|
120
|
+
* @param axis - The rotation axis as a normalized 3D vector
|
|
121
|
+
* @param angle - The rotation angle in radians
|
|
122
|
+
* @returns A quaternion representing the rotation
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* const axis = [0, 1, 0]; // Y-axis
|
|
126
|
+
* const angle = Math.PI / 2; // 90 degrees
|
|
127
|
+
* const q = QuaternionFromAxisAngle(axis, angle);
|
|
128
|
+
*/
|
|
129
|
+
export declare function QuaternionFromAxisAngle(axis: TVector3, angle: number): TQuaternion;
|
|
130
|
+
/**
|
|
131
|
+
* Creates a quaternion from an axis-angle representation (4-component version).
|
|
132
|
+
*
|
|
133
|
+
* @param axisAngle - The axis-angle as [x, y, z, angle] where xyz is the axis and angle is in radians
|
|
134
|
+
* @returns A quaternion representing the rotation
|
|
135
|
+
*/
|
|
136
|
+
export declare function QuaternionFromAxisAngleVector(axisAngle: TAxisAngle): TQuaternion;
|
|
137
|
+
/**
|
|
138
|
+
* Converts a quaternion to axis-angle representation.
|
|
139
|
+
*
|
|
140
|
+
* @param quaternion - The quaternion to convert
|
|
141
|
+
* @returns The axis-angle representation as [x, y, z, angle]
|
|
142
|
+
*
|
|
143
|
+
* @example
|
|
144
|
+
* const q = [0, 0.707, 0, 0.707]; // 90° around Y-axis
|
|
145
|
+
* const axisAngle = QuaternionToAxisAngle(q);
|
|
146
|
+
* console.log(axisAngle); // [0, 1, 0, π/2]
|
|
147
|
+
*/
|
|
148
|
+
export declare function QuaternionToAxisAngle(quaternion: TQuaternion): TAxisAngle;
|
|
149
|
+
/**
|
|
150
|
+
* Creates a quaternion from Euler angles (in radians).
|
|
151
|
+
* Uses the ZYX rotation order (yaw-pitch-roll).
|
|
152
|
+
*
|
|
153
|
+
* @param euler - Euler angles as [x, y, z] in radians
|
|
154
|
+
* @returns A quaternion representing the rotation
|
|
155
|
+
*
|
|
156
|
+
* @example
|
|
157
|
+
* const euler = [0, Math.PI/4, 0]; // 45° pitch
|
|
158
|
+
* const q = QuaternionFromEuler(euler);
|
|
159
|
+
*/
|
|
160
|
+
export declare function QuaternionFromEuler(euler: TEulerAngles): TQuaternion;
|
|
161
|
+
/**
|
|
162
|
+
* Converts a quaternion to Euler angles (in radians).
|
|
163
|
+
* Uses the ZYX rotation order (yaw-pitch-roll).
|
|
164
|
+
*
|
|
165
|
+
* @param quaternion - The quaternion to convert
|
|
166
|
+
* @returns Euler angles as [x, y, z] in radians
|
|
167
|
+
*
|
|
168
|
+
* @example
|
|
169
|
+
* const q = [0, 0.383, 0, 0.924]; // ~45° around Y-axis
|
|
170
|
+
* const euler = QuaternionToEuler(q);
|
|
171
|
+
* console.log(euler); // [0, π/4, 0]
|
|
172
|
+
*/
|
|
173
|
+
export declare function QuaternionToEuler(quaternion: TQuaternion): TEulerAngles;
|
|
174
|
+
/**
|
|
175
|
+
* Rotates a 3D vector by a quaternion.
|
|
176
|
+
* This is equivalent to converting the quaternion to a rotation matrix and multiplying.
|
|
177
|
+
*
|
|
178
|
+
* @param quaternion - The rotation quaternion (must be normalized)
|
|
179
|
+
* @param vector - The 3D vector to rotate
|
|
180
|
+
* @returns The rotated vector
|
|
181
|
+
*
|
|
182
|
+
* @example
|
|
183
|
+
* const q = QuaternionFromAxisAngle([0, 0, 1], Math.PI/2); // 90° around Z
|
|
184
|
+
* const v = [1, 0, 0]; // Point along X-axis
|
|
185
|
+
* const rotated = QuaternionRotateVector(q, v); // Should point along Y-axis
|
|
186
|
+
*/
|
|
187
|
+
export declare function QuaternionRotateVector(quaternion: TQuaternion, vector: TVector3): TVector3;
|
|
188
|
+
/**
|
|
189
|
+
* Performs spherical linear interpolation (SLERP) between two quaternions.
|
|
190
|
+
* SLERP provides smooth rotation interpolation with constant angular velocity.
|
|
191
|
+
*
|
|
192
|
+
* @param a - Start quaternion
|
|
193
|
+
* @param b - End quaternion
|
|
194
|
+
* @param t - Interpolation parameter (0 = a, 1 = b)
|
|
195
|
+
* @returns Interpolated quaternion
|
|
196
|
+
*
|
|
197
|
+
* @example
|
|
198
|
+
* const q1 = QuaternionIdentity();
|
|
199
|
+
* const q2 = QuaternionFromAxisAngle([0, 1, 0], Math.PI/2);
|
|
200
|
+
* const halfway = QuaternionSLERP(q1, q2, 0.5); // 45° rotation
|
|
201
|
+
*/
|
|
202
|
+
export declare function QuaternionSLERP(a: TQuaternion, b: TQuaternion, t: number): TQuaternion;
|
|
203
|
+
//# sourceMappingURL=core.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../src/quaternions/core.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAE/C,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAMnE;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,IAAI,WAAW,CAEhD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,WAAW,GAAG,WAAW,CAGpE;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,WAAW,EAAE,SAAS,GAAE,MAAa,EAAE,gBAAgB,GAAE,OAAe,GAAG,OAAO,CAcrI;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,WAAW,GAAG,MAAM,CAGnE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,WAAW,GAAG,WAAW,CAGxE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,WAAW,GAAG,WAAW,CAKxE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,WAAW,GAAG,WAAW,CAiBtE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,WAAW,GAAG,WAAW,CAa9E;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,WAAW,CAYlF;AAED;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAAC,SAAS,EAAE,UAAU,GAAG,WAAW,CAKhF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,WAAW,GAAG,UAAU,CAwBzE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,YAAY,GAAG,WAAW,CAiBpE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,WAAW,GAAG,YAAY,CAoBvE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,GAAG,QAAQ,CAsB1F;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,MAAM,GAAG,WAAW,CAwCtF"}
|