Inhaltsverzeichnis

std.quat — Quaternionen

Drehungen im Raum in Hamilton-Konvention: Produkt, Slerp, Achse und Winkel, Euler-Winkel, Rotationsmatrix.

→ Mathematik-Units · std.vector · std.mathx · std.linalg · std.matrix · std.coordinates.vec3

import std.quat;

Schicht 2, hängt an std.mathx. 38 Funktionen. Alle Beispiele mit lyxc 1.0.21A übersetzt und ausgeführt.


 
Die Struct-Rückgabe legt keinen Speicher mehr an (#1580 behoben). Vorher kostete jeder Aufruf zwei mmap ohne munmap — die Kopie bei der Rückgabe und, größer noch, die Deklaration var p: Pair; mit 4096 Byte. Nachgemessen mit 1.1.2E über 200 000 Rückgaben:

Laufzeit 0,05 s, Spitzenspeicher 6272 kB
mmap-Aufrufe insgesamt: 9   (Programmstart, nicht die Schleife)


Der frühere Rat, in Schleifen adressbasiert zu arbeiten, ist damit hinfällig.

Aufbau

Quat ist ein struct mit den Feldern w, x, y, z — Skalarteil zuerst, in Hamilton-Konvention. Auf die Felder wird direkt zugegriffen:

var q: Quat := QuatFromAxisAngle(0.0, 0.0, 1.0, PI / 2.0);
var v: Quat := QuatRotateVec3(q, 1.0, 0.0, 0.0);
// v.x, v.y, v.z sind die gedrehten Koordinaten

Ein Vektor wird ebenfalls als Quat geführt (mit w = 0) — QuatFromVec3 baut ihn.


Eine Drehung

unit main;
import std.io;
import std.string;
import std.math;
import std.math.constants;
import std.quat;

fn ZF(t: pchar, v: f64): void { Print(t); PrintF64(v); }

fn main(): int64 {
    var q: Quat := QuatFromAxisAngle(0.0, 0.0, 1.0, PI / 2.0);
    ZF("Norm             : ", QuatNorm(q));
    ZF("Angle (soll pi/2): ", QuatAngle(q));

    var v: Quat := QuatRotateVec3(q, 1.0, 0.0, 0.0);
    ZF("rot(1,0,0).x     : ", v.x);
    ZF("rot(1,0,0).y     : ", v.y);
    return 0;
}

Norm             : 0.999999
Angle (soll pi/2): 1.570796
rot(1,0,0).x     : 0.000000
rot(1,0,0).y     : 0.999999

Eine Vierteldrehung um die z-Achse führt (1, 0, 0) auf (0, 1, 0) — genau das steht da. Die Norm bleibt 1, wie es für eine Drehung sein muss.


Warum Quaternionen und nicht Euler-Winkel

 
Euler-Winkel haben eine Singularität. Steht die Nick-Achse senkrecht (pitch = ±90°), fallen Roll- und Gierachse zusammen — ein Freiheitsgrad geht verloren, und die Zuordnung wird mehrdeutig. In der Luftfahrt heißt das Gimbal Lock, und es tritt genau dann auf, wenn es am wenigsten gebraucht werden kann.

Quaternionen haben das Problem nicht. Der Preis ist, dass sie sich nicht ablesen lassen — deshalb gibt es QuatFromEuler, QuatRoll, QuatPitch und QuatYaw für die Ein- und Ausgabe an der Schnittstelle zum Menschen, während intern durchgehend mit Quaternionen gerechnet wird.
 
q und −q beschreiben dieselbe Drehung. Die Abbildung ist zweideutig: jede Orientierung hat zwei Quaternionen. Ein Vergleich mit QuatApproxEq meldet die beiden deshalb als verschieden, obwohl sie dasselbe bedeuten. Wer Orientierungen vergleicht, nimmt QuatSameRotation — das berücksichtigt beide Vorzeichen.

Interpolation

Der eigentliche Grund, warum Quaternionen sich in Animation und Robotik durchgesetzt haben: zwischen zwei Orientierungen lässt sich gleichmäßig interpolieren. Slerp läuft auf der Kugeloberfläche mit konstanter Winkelgeschwindigkeit — eine lineare Interpolation der Euler-Winkel dagegen erzeugt ruckelnde, gekrümmte Bewegungen.


Funktionsübersicht

Gruppe Funktionen
Erzeugen QuatNew · QuatIdentity · QuatZero · QuatCopy · QuatFromVec3
Rechnen QuatAdd · QuatSub · QuatNeg · QuatScale · QuatMul · QuatDiv · QuatDot
Betrag und Kehrwert QuatNorm · QuatNormSq · QuatNormalize · QuatConj · QuatInverse
Prüfen QuatIsZero · QuatIsUnit · QuatApproxEq · QuatSameRotation
Drehung setzen QuatFromAxisAngle · QuatFromEuler · QuatFromTo
Drehung ablesen QuatAngle · QuatAxis · QuatRoll · QuatPitch · QuatYaw
Anwenden QuatRotate · QuatRotateVec3
 
QuatMul ist nicht kommutativ. QuatMul(a, b) dreht erst mit b, dann mit a — wie bei Matrizen. Die vertauschte Reihenfolge ergibt eine andere Orientierung, und der Fehler fällt bei kleinen Winkeln kaum auf, bei großen sofort.

Nur Einheitsquaternionen beschreiben Drehungen. Nach vielen Multiplikationen weicht die Norm durch Rundung ab; QuatNormalize gehört regelmäßig dazwischen. QuatIsUnit(q, eps) prüft mit Toleranz.

QuatFromTo(ax, ay, az, bx, by, bz) liefert die Drehung, die einen Vektor auf einen anderen abbildet — die übliche Aufgabe beim Ausrichten eines Objekts an einer Richtung.


Offener Punkt

 
QuatExp und die Winkelfunktionen greifen weiterhin auf ExpF64/SinF64 aus std.math zurück statt auf die Fassungen in std.mathx. Die Abhängigkeit von der installierten Bibliotheksfassung ist weg (#1578): installierter Baum und Repository liefern dieselben Werte.

Der Unterschied zu std.mathx zeigt sich nur bei sehr großen Argumenten: dort liefert SinF64 seit #1829 ein nan (nachgemessen mit lyxc 1.2.2B), MxSin dagegen einen Wert. Für Drehungen mit üblichen Winkeln spielt das keine Rolle; eine Umstellung ist weiterhin vorgeschlagen, aber nicht entschieden.

Letzte Aktualisierung: 2026-09-05 (#1829, nachgemessen mit lyxc 1.2.2B) — offener Punkt präzisiert: SinF64 liefert bei sehr großen Argumenten nan.

Vorherige letzte Aktualisierung: 2026-08-16 · alle Beispiele mit lyxc 1.0.21A übersetzt und ausgeführt; die Drehung Koordinate für Koordinate geprüft, #1580 selbst nachgemessen.

Codebeispiele geprüft: gegen lyxc 1.2.5C übersetzt (Prüflauf 2026-09-08 über die gesamte Doku: 574 Vollprogramme, 0 echte Fehler; zusätzlich 5159 Aufrufe gegen die pub fn-Signaturen in aurum/std gehalten, 0 Abweichungen).