x-axis justierung: lines 3

This commit is contained in:
chk
2026-06-10 20:41:42 +02:00
parent fa91a36da9
commit 74a3cfada2
5 changed files with 257 additions and 1 deletions

View File

@@ -389,3 +389,102 @@ export async function assignMarkerId(robotPath, { markerId, set, link, extraMark
change: { action: 'added', markerId: id, oldLink: null, oldSet: '', newLink: link, newSet: set ?? '' },
};
}
// ── Aktion 5: X-Achse übernehmen ─────────────────────────────────────────────
/**
* Rotiert alle Marker-Positionen in robot.json so, dass die übergebene Richtung
* zur neuen X-Achse [1,0,0] wird. Rotation um den Schwerpunkt aller A0-Marker
* (Origin bleibt erhalten).
*
* direction: [vx, vy, vz] gemessene Ist-X-Richtung in Roboter-Koordinaten
*
* Algorithmus:
* 1. Normalisiere direction, ggf. Vorzeichen so dass vx > 0
* 2. Baue Orthonormalbasis: x_new = v,
* z_new = Gram-Schmidt([0,0,1] gegen v),
* y_new = cross(z_new, x_new)
* 3. Rotationsmatrix R (old→new): Zeilen = [x_new, y_new, z_new]
* 4. p_new = origin + R * (p_old origin)
*/
export async function adoptXAxis(robotPath, { direction }) {
const [vx, vy, vz] = direction.map(Number);
const len = Math.sqrt(vx * vx + vy * vy + vz * vz);
if (len < 1e-9) throw new Error('Richtungsvektor zu klein (fast Null-Vektor).');
// Normalisieren, immer positive X-Komponente
let nx = vx / len, ny = vy / len, nz = vz / len;
if (nx < 0) { nx = -nx; ny = -ny; nz = -nz; }
// ── Orthonormalbasis ──────────────────────────────────────────────────────
// Z_new: Gram-Schmidt von [0,0,1] gegen x_new
const dotZ = nz; // dot([0,0,1], [nx,ny,nz])
let zx = -dotZ * nx, zy = -dotZ * ny, zz = 1 - dotZ * nz;
let zlen = Math.sqrt(zx * zx + zy * zy + zz * zz);
if (zlen < 1e-9) {
// Sonderfall: x_new fast parallel zu Z Fallback auf [0,1,0]
const dotY = ny;
zx = -dotY * nx; zy = 1 - dotY * ny; zz = -dotY * nz;
zlen = Math.sqrt(zx * zx + zy * zy + zz * zz);
}
zx /= zlen; zy /= zlen; zz /= zlen;
// Y_new = cross(z_new, x_new) [rechte-Hand-Regel: ẑ × x̂ = ŷ]
const yx = zy * nz - zz * ny;
const yy = zz * nx - zx * nz;
const yz = zx * ny - zy * nx;
// Rotationsfunktion: p_rot = R * p (R hat Zeilen = neue Achsen in alten Koordinaten)
function rotVec(px, py, pz) {
return [
nx * px + ny * py + nz * pz, // neue X-Komponente
yx * px + yy * py + yz * pz, // neue Y-Komponente
zx * px + zy * py + zz * pz, // neue Z-Komponente
];
}
const robot = await readRobot(robotPath);
const links = robot.links ?? {};
// ── Ursprung: Schwerpunkt aller A0-Marker ────────────────────────────────
const a0Pos = [];
for (const ld of Object.values(links)) {
for (const m of (ld.markers ?? [])) {
if (m.set === 'A0' && Array.isArray(m.position) && m.position.length >= 3) {
a0Pos.push(m.position.map(Number));
}
}
}
let ox = 0, oy = 0, oz = 0;
if (a0Pos.length > 0) {
for (const [px, py, pz] of a0Pos) { ox += px; oy += py; oz += pz; }
ox /= a0Pos.length; oy /= a0Pos.length; oz /= a0Pos.length;
}
// ── Alle Marker rotieren ──────────────────────────────────────────────────
let numChanged = 0;
for (const ld of Object.values(links)) {
for (const m of (ld.markers ?? [])) {
if (!Array.isArray(m.position) || m.position.length < 3) continue;
const [px, py, pz] = m.position.map(Number);
const [rx, ry, rz] = rotVec(px - ox, py - oy, pz - oz);
m.position = [
Math.round((ox + rx) * 100) / 100,
Math.round((oy + ry) * 100) / 100,
Math.round((oz + rz) * 100) / 100,
];
numChanged++;
}
}
robot.links = links;
await writeRobot(robotPath, robot);
return {
numChanged,
origin: [ox, oy, oz].map(v => Math.round(v * 10) / 10),
newXAxis: [nx, ny, nz].map(v => Math.round(v * 10000) / 10000),
angleXYdeg: Math.round(Math.atan2(ny, nx) * 18000 / Math.PI) / 100,
angleXZdeg: Math.round(Math.atan2(nz, nx) * 18000 / Math.PI) / 100,
};
}