ducki
Version:
Simple CLI for working with KiCad projects.
97 lines (96 loc) • 2.94 kB
JavaScript
// Single-shot ChatGPT; absurd this works out of the box. AI will eat us all.
function quatMul(a, b) {
const [aw, ax, ay, az] = a;
const [bw, bx, by, bz] = b;
return [
aw * bw - ax * bx - ay * by - az * bz,
aw * bx + ax * bw + ay * bz - az * by,
aw * by - ax * bz + ay * bw + az * bx,
aw * bz + ax * by - ay * bx + az * bw,
];
}
function quatNormalize(q) {
const [w, x, y, z] = q;
const n = Math.hypot(w, x, y, z);
return [w / n, x / n, y / n, z / n];
}
function quatFromAxisAngle(axis, angleRad) {
const [ax, ay, az] = axis;
const half = angleRad * 0.5;
const s = Math.sin(half);
return quatNormalize([
Math.cos(half),
ax * s,
ay * s,
az * s,
]);
}
// Intrinsic XYZ (local X, then Y, then Z)
function quatFromEulerXYZ(x, y, z) {
const qx = quatFromAxisAngle([1, 0, 0], x);
const qy = quatFromAxisAngle([0, 1, 0], y);
const qz = quatFromAxisAngle([0, 0, 1], z);
return quatNormalize(quatMul(quatMul(qx, qy), qz));
}
function quatToEulerXYZ(q) {
const [w, x, y, z] = q;
// Rotation matrix elements
const r00 = 1 - 2 * (y * y + z * z);
const r01 = 2 * (x * y - w * z);
const r02 = 2 * (x * z + w * y);
const r12 = 2 * (y * z - w * x);
const r22 = 1 - 2 * (x * x + y * y);
// Clamp for numerical safety
const clamped = Math.max(-1, Math.min(1, r02));
const yAngle = Math.asin(clamped);
const xAngle = Math.atan2(-r12, r22);
const zAngle = Math.atan2(-r01, r00);
return [xAngle, yAngle, zAngle];
}
// ==============================
// Main generator
// ==============================
export function generateSpinFrames(rot, // [x, y, z] degrees
totalSpinDeg, // degrees
frames) {
const deg2rad = (d) => d * Math.PI / 180;
const rad2deg = (r) => r * 180 / Math.PI;
const [x0, y0, z0] = [rot.x, rot.y, rot.z].map(deg2rad);
const q0 = quatFromEulerXYZ(x0, y0, z0);
const result = [];
for (let i = 0; i < frames; i++) {
const t = frames > 1 ? i / (frames - 1) : 0;
const spinRad = deg2rad(totalSpinDeg * t);
// Local Y rotation (post-multiply)
const qSpinY = quatFromAxisAngle([0, 1, 0], spinRad);
const q = quatNormalize(quatMul(q0, qSpinY));
const [xr, yr, zr] = quatToEulerXYZ(q);
result.push({
x: rad2deg(xr),
y: rad2deg(yr),
z: rad2deg(zr),
});
}
return result;
}
// ==============================
// Example usage
// ==============================
/*
const frames = generateLocalYSpinFrames({
initialEulerDeg: [20, 30, 0], // initial board orientation
totalSpinDeg: 360, // full local-Y spin
frames: 120,
});
// Print first few frames
for (let i = 0; i < 5; i++) {
const [x, y, z] = frames[i];
console.log(
i,
x.toFixed(2),
y.toFixed(2),
z.toFixed(2)
);
}
*/
//# sourceMappingURL=quat.js.map