HBLogon.gif
Binomische Formel, Bezierkurven und andere schöne Dinge
Mit diesem Tutorial möchte ich allen Interessierten aber mathematisch ebenso wenig Bewanderten wie mich, einen Einblick in die Welt der binomischen Formeln und der Bezierkurven geben. Alle Mathegenies mögen mir die stümperhaften Erklärungen verzeihen, ich hatte nie das Vergnügen so etwas im Matheunterricht erklärt zu bekommen. Vielleicht verhilft es ja dem einen oder anderen zu einem besseren Verständnis und bei späteren, fachlich korrekten Erklärungen, zu einem Aha-Erlebnis.

Beginnen wir mit einem einfachen Beispiel.
Wir möchten eine Linie vom Punkt A nach Punkt B ziehen. Dazu geben wir die Koordinaten der beiden Punkte an und setzen diese in den Befehl LineXY() ein.

binom1

Das war einfach ^^
Nun möchten wir einen Punkt, nennen wir ihn Punkt X, auf der Linie ausrechnen, nehmen wir mal die Mitte.

binom2

Wie gehen wir vor?
Um die Mitte auszurechnen addieren wir die X-Koordinaten und die Y-Koordinaten und multiplizieren diese jeweils mit 0,5.
Also Punkt A x = 70 + Punkt B x = 200 macht 270 multipliziert mit 0,5 macht für Punkt Xx = 135.
Das gleiche mit den Y-Koordinaten. Ay = 200 + By = 70 macht 270 multipliziert mit 0,5 macht für Xy = 135.
Na super, die Koordinaten für X lauten also x = 135, y = 135. War ja kinderleicht!
Nun nehmen wir mal einen anderen Punkt auf der Linie. Nehmen wir den Punk am ersten Viertel der Linie.


binom3

Nach der Logik der vorherigen Rechnung müssten wir nun die Koordinaten mit 0,25 multiplizieren.
Ax = 70 * 0,25 = 17,5 und Bx = 200*0,25 = 50 macht zusammen 67,5 für Xx.
Ay = 200 * 0,25 = 50 und By = 70 * 0,25 = 17,5 macht zusammen 67,5 für Xy.
Wenn wir uns das Bild anschauen, erkennen wir sofort das hier etwas nicht stimmen kann.
Die ausgerechneten Koordinaten würde sich an diesem Punkt befinden.

binom4

Das Problem ist also erkannt. Daraus ergeben sich 2 Fragen:
Warum existiert das Problem?
Wie kann es gelöst werden?


Bei der ersten Rechnung haben wir beide Koordinaten mit 0,5 multiplizieren können weil beide Punkte gleich viel Einfluss auf die Koordinate in der Mitte hatten. Die Koordinaten von X mussten die Hälfte der Summe beider Koordinaten von A und B sein. An jedem anderen Punkt auf der Linie ist der Einfluss von A und B unterschiedlich. Wenn am Punkt A der Einfluss von A auf die Koordinaten am größten ist, also gleich 1, muss er am Punkt B am kleinsten sein, also 0. Für B gilt das Umgekehrte.
Wir benötigen also 2 Faktoren für die korrekte Berechnung und diese müssen gegenläufig sein.
Bezeichnen wir diese Faktoren mit den Kleinbuchstaben a und b.
Vom Punkt A ausgehend, wäre a = 1 und b = 1-a.
Wir kennen zwar die Koordinaten von Punkt A aber zur Kontrolle rechnen wir diese mal mit den neuen Faktoren a und b aus.
Xx = Ax * 1 + Bx * 0 = 70 (am Punkt A ist a = 1 und b = 1-1 also 0)
Xy = Ay * 1 + By * 0 = 200


Okay, so weit, so gut. Wie sieht es nun mit dem vorherigen Punkt X aus?
Xx = Ax * 0,75 + Bx * 0,25 = 102,5
Xy = Ay * 0,75 + Bx * 0,25 = 167,5
Schauen wir mal auf das Bild:

binom5

Hervorragend!
Wir haben nun also eine Formel entwickelt, mit der wir jeden Punkt auf der Linie ausrechnen können, abhängig von der Entfernung im Verhältnis zu der Gesamtstrecke.
X = A * a + B * b
Die entscheidenden Faktoren dabei waren a + b.

So gerüstet können wir uns jetzt ein neues Problem erdenken ^^.

Quadratische Bezierkurve
Nehmen wir an, wir möchten den Verlauf der Linie durch einen weiteren Faktor beeinflussen.
Warum?
Weil wir eine Kurve erzeugen möchten und wir dazu in der Lage sind!
Folgendes Szenario wird angenommen:

binom6

Den dritten Punkt nennen wir K wie Kontrollpunkt. Im Englischen wird er als C, wie Control, bezeichnet aber ich lass hier mal den Arminius raushängen und nenne ihn K, basta.
Wie können wir K in unsere Berechnungen einbeziehen?
Klar ist, das K, ebenso wie A und B, im Verlauf der Strecke an Bedeutung (Gewichtung) zu- bzw. abnimmt.
Macht es Sinn für K einen weiteren Faktor einzuführen? Wie sollte sich der verhalten?
(a + b)/2 ?
Ne, da die Summe von a und b immer 1 ist hätte der neue Faktor immer einen Wert von 0,5.
Ich glaub, wir müssen das Problem anders betrachten.
Unsere bisherige Strecke war eine gerade Linie von A nach B. Nun versuchen wir diese Streckenführung zu erweitern und haben dazu eine weitere Dimension hinzugefügt.
Man könnte das ungefähr so betrachten:

binom7

Wir können also sagen, das wir die Funktionsweise durch hinzufügen einer weiteren Größe quadriert haben!
Ausgehend von unseren ursprünglichen Faktoren, die für die Bestimmung des Einflusses der einzelnen Größen auf die Streckenführung maßgeblich waren, a + b, können wir diese nun umformulieren.
(a + b)²
Diese Formel nennt man auch die 1. binomische Formel:
Das ist so zwar logisch, erscheint mir aber etwas kryptisch. Wie sollen da die Größen A, B und K eingefügt werden?
Dazu müssen wir die Klammer zunächst auflösen.
(a + b)² = (a + b) * (a + b) = a² + ab + ab + b² = a² + 2ab + b²
Wir haben nun durch die Quadrierung eine Formel erhalten, in der 3 Komponenten miteinander addiert werden: a² + 2ab + b²
Setzen wir noch unsere gegebenen Größen ein: X = A * a² + K * 2 * a * b + B * b²
Übertragen wir das mal Testweise auf unser Beispiel und berechnen Punkt X mit den angegeben Werten für a = 0,3 und b=0,7.

binom8

Xx = 70 * 0,32 + 70 * 2 * 0,3 * 0,7 + 200 * 0,72 = 133,7
Xy = 200 * 0,32 + 70 * 2 * 0,3 * 0,7 + 70 * 0,72 = 81,7

Heureka, wir können nun sämtliche Punkte auf dieser Kurve berechnen!

Erstellen wir dafür mal ein kleines Codebeispiel:

; Beispiel Binomische Formel mit 3 Komponenten
Define A1.POINT, B1.POINT, K.POINT, X.POINT, a.f, b.f
A1\x = 70
A1\y = 200
B1\x = 200
B1\y = 70
K\x = 70
K\y = 70
a = 1
b = 1 - a

For i = 1 to 10 ; wir werden hier nur 10 Punkte berechnen

X\x = A1\x * (a*a) + K\x * (2*a*b) + B1\x * (b*b)
X\y = A1\y * (a*a) + K\y * (2*a*b) + B1\y * (b*b)

debug " Xx = " + Str(X\x)+ "und Xy = " + Str(X\y)

a = a - 0.1
b = 1 - a

next

Hierbei wurden exemplarisch nur 10 Punkte berechnet.
Es ist uns jetzt gelungen aus einer geraden Strecke, mit Hilfe eines Kontrollpunktes, eine Kurve zu berechnen.
Derart gestärkt, erschaffen wir uns noch ein neues Problem.

Kubische Bezierkurve

Angenommen wird die folgende Konstellation:

binom9

Was will ich damit erreichen?
Unter Zuhilfenahme eines weiteren Kontrollpunktes ist es mit einem Segment, so nennen wir jetzt die Strecke zwischen A und B, möglich, jegliche Art von Kurve innerhalb dieses Segments zu erstellen. Man nennt diese Art von Kurven auch Bezierkurven.
Grundlegend gehört bei dieser Kurvenart zu jedem Anfangs- oder Endpunkt ein Kontrollpunkt.
Da unsere Punkte hier A und B heißen, nenne ich die Kontrollpunkte dementsprechend Ka und Kb.
Die letzte Formel haben wir aus der Erkenntnis heraus entwickelt, das mit der Einführung einer weiteren Größe die Grundformel quadriert werden musste.
Logisch wäre jetzt also, die Formel, bei noch einer weiteren Größe, in ihrer Potenz zu erhöhen.

Aus (a + b)² wird also (a + b)³.

Um vernünftig mit dieser Formel arbeiten zu können, müssen wir sie wieder auflösen.
(a + b)³ = (a + b) * (a + b) * (a + b) = a³ + 3*a²*b + 3*a*b² + b³

Nun erkennt unser geschultes Auge sofort die vier Komponentenblöcke, die durch Addition miteinander verbunden sind.
Setzen wir unsere Größen in diese Formel ein:

X = A * a³ + Ka * 3*a²*b + Kb * 3*a*b² + B * b³

Um die Tragfähigkeit dieser, auf den ersten Blick doch recht verwirrenden, Formel zu überprüfen, werden wir sie an einem konkretem Beispiel testen.

Gegeben sei:

Ax = 70, Ay = 200, Bx = 200, By = 70
Kax = 70, Kay = 70, Kbx = 200, Kby = 100

Das Codebeispiel:


; Beispiel Binomische Formel mit 4 Komponenten

If InitSprite() = 0 Or InitKeyboard() = 0
MessageRequester("Error", "Can't open DirectX 7 or later", 0)
End
EndIf


Define A1.POINT, B1.POINT, Ka.POINT, Kb.POINT, X.POINT, a.f, b.f

A1\x = 70
A1\y = 200
B1\x = 200
B1\y = 70
Ka\x = 70
Ka\y = 70
Kb\x = 200
Kb\y = 100
a = 1
b = 1 - a


hwnd = OpenWindow(0, 0, 0, 300, 300, "test", #PB_Window_ScreenCentered | #PB_Window_SystemMenu)
If OpenWindowedScreen(hwnd,0,0,300,300,0,0,0)


For i = 1 to 20 ; wir werden hier 20 Punkte berechnen

X\x = A1\x*(a*a*a) + Ka\x*(3*(a*a)*b)+ Kb\x*3*a*(b*b) + B1\x*(b*b*b)
X\y = A1\y*(a*a*a) + Ka\y*(3*(a*a)*b)+ Kb\y*3*a*(b*b) + B1\y*(b*b*b)

;debug " Xx = " + Str(Xx)+ " und Xy = " + Str(Xy)

StartDrawing(ScreenOutput())
Plot(X\x, X\y,$FFFFFF)
StopDrawing()

a = a - 0.05
b = 1 - a

next

FlipBuffers()

Repeat

Repeat
Select WindowEvent ()
Case #PB_Event_CloseWindow
End
Case #Null
Break
EndSelect
ForEver

ExamineKeyboard()

Until Event = #PB_Event_CloseWindow Or KeyboardPushed(#PB_Key_Escape)

End

Else

MessageRequester("Fehler","Konnte Screen nicht öffnen")
End
EndIf


Ich liebe es, wenn ein Plan funktioniert.

Ich hoffe damit ein wenig Licht in dieses schwierige Thema gebracht zu haben. Die gesamte Materie war mir selber bis vor kurzem völlig unbekannt und es freut mich riesig auf diesen Weg meine bescheidenen Kenntnisse etwas erweitert zu haben.


Vielen Dank für die geschätzte Aufmerksamkeit, es war mir ein Vergnügen!