Es sollen die Koordinaten eines Schnittpunktes einer Geraden mit einer Ebene berechnet werden. Die Gleichungen für die Gerade und die Ebene lauten:
(1) |
|
Geraden-Gleichung | ||||||||||||
(2) |
|
Ebenen-Gleichung | ||||||||||||
wobei' |
|
Ich kann den Schnittpunkt mit zwei unterschiedlichen Methoden berechnen.
Die hier vorgestellte Methode (2) erweist sich als einfacher und effizienter (20 Operationen pro Schnittpunkt) als die Methode des Lösens eines Gleichungssystems (ca. 60 Operationen pro Schnittpunkt).
Die Idee ist folgende: Die Ebene kann als Koordinatensystem aufgefasst werden, welches durch die Einheits-Vektoren
Ich gehe davon aus, dass die beiden Vektoren
Die Gerade wird in das Koordinatensystem der Ebene transformiert, indem die Skalarprodukte der Geraden-Vektoren
Da der Ebenenpunkt
(3) |
Der Punkt
(4) |
Der Richtungsvektor
(5) |
Die Vektoren der Ebene im Ebenen-Koordinatensystem sind trivial:
(6) |
Beschreiben wir nun die Ebene und Gerade bezüglich des Ebenen-Koordinatensystems:
(7) |
Geradengleichung | |
(8) |
Ebenengleichung |
Der Schnittpunkt
(9) |
Etwas Umstellen ergibt:
(10) |
Ausschreiben der Vektoren ergibt das Gleichungssystem:
(11) |
Einsetzen der Zahlenwerte für die Vektoren ergibt (
(12) |
Aus der letzten Zeile dieses Gleichungssystems können wir direkt den Wert a berechnen:
(13) |
Wenn a bekannt ist, können wir den Schnittpunkt im Ebenen-Koordinatensystem berechnen:
(14) |
Die Rücktransformtion ins ursprüngliche Koordinatensystem erfolgt über die Basisvektoren
(15) |
Da wir immer mit Einheitsvektoren und orthogonalen Basis-Vektoren gerechnet haben ist der Parameter a in beiden Koordinatensystemen identisch. So können wir den Schnittpunkt auch direkt berechnen:
(16) |
Wenn wir den oben aufgezeigten Weg zusammenfassen, erkennen wir, dass viele Berechnungen eingespart werden konnten. Die verbliebenen Berechnungen fasse ich hier nochmals zusammen:
Zunächst benötigen wir den Normalenvektor auf die Ebene:
(17) |
|
Diese Vektoren bilden die Basis des Ebenen-Koordinatensystems. Um die Vektoren der Geraden in diesem System auszudrücken können wir das komponentenweise Skalarprodukt der Vektoren mit den Basisvektoren verwenden wie in (4) und (5) gezeigt. Wir benötigen jedoch nur die 3. Komponente für die Berechnung von a:
(18) |
|
Damit können wir den parameter a berechnen:
(19) |
|
und erhalten den Schnittpunkt:
(20) |
|
Beachte: Wenn die Richtung der Geraden, ausgedrückt durch den Vektor
// some vector functions function VectProd( u, v ) { // Vector Product: return = u x v // u, v: [ x, y, z ] // return: [ x, y, z ] return [ u[1] * v[2] - u[2] * v[1], u[2] * v[0] - u[0] * v[2], u[0] * v[1] - u[1] * v[0] ]; } function VectScalProd( u, v ) { // Scalar Product: return = u dot v // u, v: [ x, y, z ] // return: number return u[0] * v[0] + u[1] * v[1] + u[2] * v[2]; } function VectAdd( u, v ) { // Vector addition: return = u + v // u, v: [ x, y, z ] // return: [ x, y, z ] return [ u[0] + v[0], u[1] + v[1], u[2] + v[2] ]; } function VectSub( u, v ) { // Vector subtraction: u - v // u, v: [ x, y, z ] // return: [ x, y, z ] return [ u[0] - v[0], u[1] - v[1], u[2] - v[2] ]; } function VectScale( v, s ) { // Vector scaling: s * vec v // v: [ x, y, z ] // s: number // return: [ sx, sy, sz ] return [ s * v[0], s * v[1], s * v[2] ]; } function IntersectPlaneLine( Q, u, v, P, r ) { // All parameters are Arrays [ x, y, z ] // Q = point on plane // u, v = orthogonal unit vectors on plane // P = point on line // r = direction of line // return = intersection point [ x, y, z] or null var n = VectProd( u, v ); var r3 = VectScalProd( r, n ); if (r3 == 0) return null; var P3 = VectScalProd( VectSub( P, Q ), n ); var a = -P3 / r3; var S = VectAdd( P, VectScale( r, a ) ); return S; }
Wenn man einen Algorythmus zum Clippen eines Polygons schreibt, wird man vor dem Berechnen des Schnittpunktes testen, ob sich zwei Punkte des Polygons auf verschiedenen Seiten der Fläche befinden, also ob es einen Schnittpunkt gibt. Durch Rundungsfehler kann es passieren, dass der Test zurückgibt, dass zwei Punkte auf verschiedenen Seiten der Fläche sind, aber beim Berechnen des Schnittpunktes festgestellt wird, dass es keinen Schnittpunkt gibt, so dass IntersectPlaneLine() null zurückgibt.
Dieser Fall muss unbedingt behandelt werden, da es sonst zu Exceptions kommen kann. Eine Möglichkeit ist, die beiden Punkte als auf derselben Seite zu betrachten.
In der folgenden Animation wird die obige JavaScript Funktion für die Berechnung des Schnittpunktes (grün) verwendet. Durch Klicken in die Animation werden zufällige Werte für eine neue Konfiguration generiert.
Eine allgemeinere Methode den Schnittpunkt von Gerade und Ebene zu berechnen ist das Aufstellen und Lösen eines Gleichungssystems:
Für den Schnittpunkt
(21) |
|
Geraden-Gleichung | |
(22) |
|
Ebenen-Gleichung |
Setzen wir also Gleichung (19) gleich (20) und schreiben diese für jede Koordinate einzeln:
(23) |
für i = 1...3 |
Wir stellen die Gleichung (23) so um, dass alle Terme mit den Unbekannten a, b, c auf der linken Seite und alle anderen Terme auf der rechten Seite des Gleichheitszeichens stehen:
(24) | |
(25) | |
(26) |
Dieses lineare Gleichungssystem mit 3 Gleichungen für die 3 Unbekannten a, b, c können wir in Matrixschreibweise notieren:
(27) |
Auf der Seite Lösen linearer Gleichungssysteme wird berschrieben, wie ein solches Gleichungssystem per JavaScript gelöst werden kann. Wenn a berechnet ist, kann der Schnittpunkt durch Einsetzen in die Geradengleichung (21) vektoriell berechnet werden.