====== std.quat — Quaternionen ======
Drehungen im Raum in Hamilton-Konvention: Produkt, Slerp, Achse und Winkel, Euler-Winkel, Rotationsmatrix.
→ [[lyx_-_programmiersprache:units:mathematik|Mathematik-Units]] · [[lyx_-_programmiersprache:units:vector|std.vector]] · [[lyx_-_programmiersprache:units:mathx|std.mathx]] · [[lyx_-_programmiersprache:units:linalg|std.linalg]]
import std.quat;
Schicht 2, hängt an [[lyx_-_programmiersprache:units:mathx|std.mathx]]. 38 Funktionen. Alle Beispiele mit ''lyxc 1.0.21A'' übersetzt und ausgeführt.
----
> **Die Struct-Rückgabe legt keinen Speicher mehr an** ([[https://github.com/SEOLizer/LyX-Compiler/issues/1580|#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 teilweise noch auf ''ExpF64''/''SinF64'' aus ''std.math'' zurück statt auf die genaueren Fassungen in [[lyx_-_programmiersprache:units:mathx|std.mathx]]. Damit hängt das Ergebnis davon ab, welche Fassung der Standardbibliothek eingebunden ist (→ [[https://github.com/SEOLizer/LyX-Compiler/issues/1578|#1578]]). Eine Umstellung ist vorgeschlagen, aber nicht entschieden.
----
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.