====== 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.