@gkucmierz/utils 5.1.0 → 5.4.0
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/main.mjs +23 -3
- package/package.json +2 -3
- package/src/developer-utils/grid-navigation.mjs +175 -0
- package/src/developer-utils/quorum.mjs +345 -0
- package/src/developer-utils/type.mjs +24 -0
- package/src/geometry/math3d.mjs +164 -0
- package/src/geometry/range-set.mjs +748 -0
- package/src/string-arrays/parse-heading.mjs +38 -0
- package/src/string-arrays/slugify.mjs +74 -0
package/src/geometry/math3d.mjs
CHANGED
|
@@ -70,3 +70,167 @@ export const getRotationMatrixFromVectors = (u, v) => {
|
|
|
70
70
|
return axisAngleToMatrix4(axis, angle);
|
|
71
71
|
};
|
|
72
72
|
|
|
73
|
+
export const normalizeQuat = (q) => {
|
|
74
|
+
const len = Math.hypot(q.w, q.x, q.y, q.z);
|
|
75
|
+
if (len === 0) return { w: 1, x: 0, y: 0, z: 0 };
|
|
76
|
+
return {
|
|
77
|
+
w: q.w / len,
|
|
78
|
+
x: q.x / len,
|
|
79
|
+
y: q.y / len,
|
|
80
|
+
z: q.z / len
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export const axisAngleToQuat = (axis, angle) => {
|
|
85
|
+
const [x, y, z] = normalize(axis);
|
|
86
|
+
const half = angle * 0.5;
|
|
87
|
+
const s = Math.sin(half);
|
|
88
|
+
return normalizeQuat({
|
|
89
|
+
w: Math.cos(half),
|
|
90
|
+
x: x * s,
|
|
91
|
+
y: y * s,
|
|
92
|
+
z: z * s
|
|
93
|
+
});
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
export const multiplyQuat = (a, b) => ({
|
|
97
|
+
w: a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z,
|
|
98
|
+
x: a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y,
|
|
99
|
+
y: a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x,
|
|
100
|
+
z: a.w * b.z + a.x * b.y - a.y * b.x + a.z * b.w
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
export const rotateVecByQuat = (v, q) => {
|
|
104
|
+
const [vx, vy, vz] = v;
|
|
105
|
+
const { w, x, y, z } = q;
|
|
106
|
+
const tx = 2 * (y * vz - z * vy);
|
|
107
|
+
const ty = 2 * (z * vx - x * vz);
|
|
108
|
+
const tz = 2 * (x * vy - y * vx);
|
|
109
|
+
return [
|
|
110
|
+
vx + w * tx + (y * tz - z * ty),
|
|
111
|
+
vy + w * ty + (z * tx - x * tz),
|
|
112
|
+
vz + w * tz + (x * ty - y * tx)
|
|
113
|
+
];
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
export const matToQuat = (m) => {
|
|
117
|
+
const trace = m[0] + m[5] + m[10];
|
|
118
|
+
let w, x, y, z;
|
|
119
|
+
if (trace > 0) {
|
|
120
|
+
const s = 0.5 / Math.sqrt(trace + 1);
|
|
121
|
+
w = 0.25 / s;
|
|
122
|
+
x = (m[6] - m[9]) * s;
|
|
123
|
+
y = (m[8] - m[2]) * s;
|
|
124
|
+
z = (m[1] - m[4]) * s;
|
|
125
|
+
} else if (m[0] > m[5] && m[0] > m[10]) {
|
|
126
|
+
const s = 2 * Math.sqrt(1 + m[0] - m[5] - m[10]);
|
|
127
|
+
w = (m[6] - m[9]) / s;
|
|
128
|
+
x = 0.25 * s;
|
|
129
|
+
y = (m[4] + m[1]) / s;
|
|
130
|
+
z = (m[8] + m[2]) / s;
|
|
131
|
+
} else if (m[5] > m[10]) {
|
|
132
|
+
const s = 2 * Math.sqrt(1 + m[5] - m[0] - m[10]);
|
|
133
|
+
w = (m[8] - m[2]) / s;
|
|
134
|
+
x = (m[4] + m[1]) / s;
|
|
135
|
+
y = 0.25 * s;
|
|
136
|
+
z = (m[6] + m[9]) / s;
|
|
137
|
+
} else {
|
|
138
|
+
const s = 2 * Math.sqrt(1 + m[10] - m[0] - m[5]);
|
|
139
|
+
w = (m[1] - m[4]) / s;
|
|
140
|
+
x = (m[8] + m[2]) / s;
|
|
141
|
+
y = (m[6] + m[9]) / s;
|
|
142
|
+
z = 0.25 * s;
|
|
143
|
+
}
|
|
144
|
+
return normalizeQuat({ w, x, y, z });
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
export const quatToMat = (q) => {
|
|
148
|
+
const { w, x, y, z } = normalizeQuat(q);
|
|
149
|
+
const xx = x * x, yy = y * y, zz = z * z;
|
|
150
|
+
const xy = x * y, xz = x * z, yz = y * z;
|
|
151
|
+
const wx = w * x, wy = w * y, wz = w * z;
|
|
152
|
+
return [
|
|
153
|
+
1 - 2 * (yy + zz), 2 * (xy + wz), 2 * (xz - wy), 0,
|
|
154
|
+
2 * (xy - wz), 1 - 2 * (xx + zz), 2 * (yz + wx), 0,
|
|
155
|
+
2 * (xz + wy), 2 * (yz - wx), 1 - 2 * (xx + yy), 0,
|
|
156
|
+
0, 0, 0, 1
|
|
157
|
+
];
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
export const slerp = (q1, q2, t) => {
|
|
161
|
+
let dot = q1.w * q2.w + q1.x * q2.x + q1.y * q2.y + q1.z * q2.z;
|
|
162
|
+
let q2n = q2;
|
|
163
|
+
if (dot < 0) {
|
|
164
|
+
q2n = { w: -q2.w, x: -q2.x, y: -q2.y, z: -q2.z };
|
|
165
|
+
dot = -dot;
|
|
166
|
+
}
|
|
167
|
+
if (dot > 0.9995) {
|
|
168
|
+
return normalizeQuat({
|
|
169
|
+
w: q1.w + t * (q2n.w - q1.w),
|
|
170
|
+
x: q1.x + t * (q2n.x - q1.x),
|
|
171
|
+
y: q1.y + t * (q2n.y - q1.y),
|
|
172
|
+
z: q1.z + t * (q2n.z - q1.z)
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
const theta = Math.acos(Math.max(-1, Math.min(1, dot)));
|
|
176
|
+
const sinTheta = Math.sin(theta);
|
|
177
|
+
const a = Math.sin((1 - t) * theta) / sinTheta;
|
|
178
|
+
const b = Math.sin(t * theta) / sinTheta;
|
|
179
|
+
return {
|
|
180
|
+
w: a * q1.w + b * q2n.w,
|
|
181
|
+
x: a * q1.x + b * q2n.x,
|
|
182
|
+
y: a * q1.y + b * q2n.y,
|
|
183
|
+
z: a * q1.z + b * q2n.z
|
|
184
|
+
};
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
export const matToEulerYXZ = (m) => {
|
|
188
|
+
if (!m || m.length < 16) return { pitch: 0, yaw: 0, roll: 0 };
|
|
189
|
+
const m11 = m[0], m13 = m[8];
|
|
190
|
+
const m21 = m[1], m22 = m[5], m23 = m[9];
|
|
191
|
+
const m31 = m[2], m33 = m[10];
|
|
192
|
+
|
|
193
|
+
const clamp = (v) => Math.max(-1, Math.min(1, v));
|
|
194
|
+
const x = Math.asin(-clamp(m23));
|
|
195
|
+
let y, z;
|
|
196
|
+
if (Math.abs(m23) < 0.9999999) {
|
|
197
|
+
y = Math.atan2(m13, m33);
|
|
198
|
+
z = Math.atan2(m21, m22);
|
|
199
|
+
} else {
|
|
200
|
+
y = Math.atan2(-m31, m11);
|
|
201
|
+
z = 0;
|
|
202
|
+
}
|
|
203
|
+
const radToDeg = 180 / Math.PI;
|
|
204
|
+
return {
|
|
205
|
+
pitch: x * radToDeg,
|
|
206
|
+
yaw: y * radToDeg,
|
|
207
|
+
roll: z * radToDeg
|
|
208
|
+
};
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
export const eulerYXZToQuat = (pitchDeg, yawDeg, rollDeg) => {
|
|
212
|
+
const degToRad = Math.PI / 180;
|
|
213
|
+
const hx = (pitchDeg * degToRad) * 0.5;
|
|
214
|
+
const hy = (yawDeg * degToRad) * 0.5;
|
|
215
|
+
const hz = (rollDeg * degToRad) * 0.5;
|
|
216
|
+
|
|
217
|
+
const c1 = Math.cos(hx), s1 = Math.sin(hx);
|
|
218
|
+
const c2 = Math.cos(hy), s2 = Math.sin(hy);
|
|
219
|
+
const c3 = Math.cos(hz), s3 = Math.sin(hz);
|
|
220
|
+
|
|
221
|
+
return normalizeQuat({
|
|
222
|
+
w: c1 * c2 * c3 + s1 * s2 * s3,
|
|
223
|
+
x: s1 * c2 * c3 + c1 * s2 * s3,
|
|
224
|
+
y: c1 * s2 * c3 - s1 * c2 * s3,
|
|
225
|
+
z: c1 * c2 * s3 - s1 * s2 * c3
|
|
226
|
+
});
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
export const applyScreenDragQuat = (currentQuat, dx, dy, sensitivity = 0.007) => {
|
|
230
|
+
const qY = axisAngleToQuat([0, 1, 0], dx * sensitivity);
|
|
231
|
+
const qX = axisAngleToQuat([1, 0, 0], dy * sensitivity);
|
|
232
|
+
const qDelta = multiplyQuat(qX, qY);
|
|
233
|
+
return normalizeQuat(multiplyQuat(qDelta, currentQuat));
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
|