Bézier-Kurve mit bleibig vielen Punkten...

Übersicht BlitzBasic Codearchiv

Neue Antwort erstellen

 

n-Halbleiter

Betreff: Bézier-Kurve mit bleibig vielen Punkten...

BeitragMo, Jul 13, 2009 1:48
Antworten mit Zitat
Benutzer-Profile anzeigen
... allerdings als fortlaufende Spline.
Arrow Was bitte heißt "fortlaufende Spline"? Ganz einfach, es gibt nur einen Start- und einen Endpunkt, alle anderen Punkte sind Kontrollpunkte. D.h., dass die Spline nicht, wie in anderen Beispielen, in Segmente unterteilt ist, sondern dass eben nur ein Segment existiert.

Damit dieses System verstehbar ist, sollte ein wenig Grundverständnis für Bézier-Kurven vorhanden sein. Wenn jemand nicht weiß, was los ist, gibt es den Wikipediaartikel zu Bézierkurven, ich möchte euch allerdings zusätzlich noch einen Artikel auf Gamedev.net (auf Englisch, lesenswert) ans Herz legen.

Der Dreh- und Angelpunkt des Lösungsansatzes beruht auf der Verallgemeinerung von binomischen Formeln mit dem Exponent n:
Zitat:
n
Sigma ( (n über i) * a^(n-i) * b^(i) ) = (a+b)^n
i=0


Es wird, denke ich, schon aufgefallen sein, dass bei den Bézier-Kurven genau solche binomischen Formeln eine Rolle spielen. Jedoch: Bei den Splines wird jedes Polynom noch mit der Koordinate ( x bzw. y) des Puntes i multipliziert, damit die Punkte ins Gewicht fallen.

Wenn man dies berücksichtigt, lässt sich daraus eine in BB umsetzbare Konstruktion finden:
Code: [AUSKLAPPEN]
   Local C,AXY#,a#=t,b#=1-t
   For C=0 To amount
      AXY=AXY+(P(C,F)*BinomialCoE(amount,C)*ToThePowerOf(a,amount-C)*ToThePowerOf(b,C))
   Next

Die Funktion "BinomialCoE" errechnet den Binomialkoeffizienten " "amount" über C ", "ToThePowerOf" ist eine Funktion, die eine Potenz berechnet (z.B. b^C (zweiter Aufruf)). Die For-Next-Schleife in Kombination der Addition des Wertes zu AXY umschreibt den Summenoperator.

Ein letztes Wort noch zur Technik, bevor es an den Code geht: Es gibt nur eine Funktion XY, welche sowohl die X- als auch die Y-Koordinate berechnen kann; Definiert, welche Koordinate berechnet werden soll, wird durch F (0 bedeutet X-Koordinate, 1 Y-Koordinate).

Der Code, ein Beispiel ist direkt dabei:
Code: [AUSKLAPPEN]
Graphics 1024,768,32,2
SeedRnd MilliSecs()
SetBuffer BackBuffer()
Global timer=CreateTimer(60),PosField=CreateBank()
;PosField ist die Bank, in der die Koordinaten aller Punkte gespeichert werden
Local C#,a#=1,C2
Global amount=Rand(2,8);Amount: Anzahl der Punkte (-1)

For C2=0 To amount;Genug Punkte erstellen (an sich amount+1)
   NewPos(Rand(50,700),Rand(50,700))
Next

ClsColor 100,100,100
Repeat
   ;Pfad malen
   Color 200,200,0
   For C=0 To 1 Step 0.005
      Plot XY(C,0),XY(C,1)
   Next
   
   ;Punkt an der aktuellen Position malen
   Color 0,0,255
   Rect XY(a,0)-1,XY(a,1)-1,2,2,1
   
   ;Die Punkte markieren
   For C2=0 To amount
      If C2=0 Or C2=amount
         Color 0,200,200
      Else
         Color 0,200,0
      EndIf
      Rect P(C2,0)-1,P(C2,1)-1,2,2,1
      Color 255,255,255
      Text P(C2,0),P(C2,1),C2+": "+P(C2,0)+","+P(C2,1),1
   Next
   
   Text 10,10,a
   
   a=a+0.005
   If a>=1 Then a=0
   
   Text 10,30,amount+1
   
   Flip 0
   WaitTimer timer
   Cls
Until KeyHit(1)
End

;Gibt die Komponente F der Spline zum Zeitpunkt t zurück
Function XY#(t#,F)
   Local C,AXY#,a#=t,b#=1-t
   For C=0 To amount
      AXY=AXY+(P(C,F)*BinomialCoE(amount,C)*ToThePowerOf(a,amount-C)*ToThePowerOf(b,C))
   Next
   Return AXY
End Function

;Fügt einen neuen Punkt zu Punktliste hinzu
Function NewPos(X#,Y#)
   Local size=BankSize(PosField)
   ResizeBank(PosField,size+8)
   PokeFloat(PosField,size,X)
   PokeFloat(PosField,size+4,Y)
End Function

;Gibt vom Punkt C die Komponente F (0:x, 1:y) zurück
Function P#(C,F=0)
   Return PeekFloat(PosField,(C Shl 3)+(F Shl 2))
End Function

;Mathematische Funktionen, die benötigt werden
;Potenz a^x
Function ToThePowerOf#(Basis#,Exponent)
   Local Ergebnis#=1
   Local Faktor#=Basis#
   If Exponent<0 Then Exponent=-Exponent:Faktor=1/Faktor
   While Exponent
      If (Exponent And 1) Then Ergebnis=Ergebnis*Faktor
      Exponent=Exponent Shr 1
      Faktor=Faktor*Faktor
   Wend
   Return Ergebnis
End Function

;Fakultät von x
Function Factorial(x)
   ;Spezialfallberücksichtigung
   If x<0
      Return 0
   ElseIf x=0
      Return 1
   EndIf
   Local C,ret=1
   For C=2 To x
      ret=ret*C
   Next
   Return ret
End Function

;Binomialkoeffizient ("n über k")
Function BinomialCoE(n,k)
   Return Factorial(n)/(Factorial(k)*Factorial(n-k))
End Function


Falls sich Fragen ergeben, fragt.

P.S.: Der Code ist realtimefähig. Allerdings gibt es, wie auch sonst, irgendwann eine Marke an Aufrufen, die bei Überschreiten in unschönen FPS-Zahlen resultieren. Wink

EDIT: Der Code wurde ein wenig verändert; man sieht jetzt an den Stellen, an denen die Punkte sind, kleine Rechtecke unterschiedlicher Färbung (abhängig davon, ob sie Start- und Endpunkte oder Kontrollpunkte sind).

EDIT2: Ich habe (dazu vielen Dank an mpmxyz) die Potenzfunktion verbessert. Wink Sie ist jetzt mit kleineren Zahlen langsamer, dafür mit größeren leicht schneller. Ich denke, dieser Kompromiss ist okay, da es ja eine unbegrenzte Anzahl Kontrollpunkte geben kann. Wink
mfg, Calvin
Maschine: Intel Core2 Duo E6750, 4GB DDR2-Ram, ATI Radeon HD4850, Win 7 x64 und Ubuntu 12.04 64-Bit
Ploing!
Blog

"Die Seele einer jeden Ordnung ist ein großer Papierkorb." - Kurt Tucholsky (09.01.1890 - 21.12.1935)
  • Zuletzt bearbeitet von n-Halbleiter am Mo, Jul 13, 2009 11:48, insgesamt 2-mal bearbeitet

Nova

BeitragMo, Jul 13, 2009 2:07
Antworten mit Zitat
Benutzer-Profile anzeigen
Und was ist das ganze jetzt? Ich sehe da nur eine weiche Kurve, wie bei Sinus und Cosinus.
Wikipedia ist da viel zu kompliziert für eine Erklärung.

Was bringt diese Kurve? Und wieso ist die so gepunktet? Und warum läuft auf der Kurve so ein blauer Punkt rum der jede Sekunde eine Stelle weiter rückt?
AMD Athlon II 4x3,1GHz, 8GB Ram DDR3, ATI Radeon HD 6870, Win 7 64bit

BladeRunner

Moderator

BeitragMo, Jul 13, 2009 2:09
Antworten mit Zitat
Benutzer-Profile anzeigen
Eine bezierkurve ist eine mathematische Beschreibung einer fast beliebigen kurve die durch einige Fixpunkte läuft. Sehr sinnige sache, denn so kann man mit wenigen bytes an Info sehr komplexe Muster speichern.
Zu Diensten, Bürger.
Intel T2300, 2.5GB DDR 533, Mobility Radeon X1600 Win XP Home SP3
Intel T8400, 4GB DDR3, Nvidia GF9700M GTS Win 7/64
B3D BMax MaxGUI

Stolzer Gewinner des BAC#48, #52 & #92
 

n-Halbleiter

BeitragMo, Jul 13, 2009 2:15
Antworten mit Zitat
Benutzer-Profile anzeigen
Es ist eine weiche Kurve. Das ist ja auch der Sinn von Splines, nämlich, Strecken zu interpolieren. Die Wikipedia-Erklärung ist in der Tat viel zu kompliziert, um schnell heruaszufinden, was los ist, weshalb ich noch den Artikel auf Gamedev.net dazugeschrieben habe. Wenn du keine Lust hast, dir den Artikel durchzulesen, oder ihn nicht verstehst, kann ich noch zum Tutoral dazu schreiben/raussuchen.

Diese Kurve wäre zum Beispiel für einen fliegenden Kundschafter in einem Strategiespiel nützlich, wenn er in einem Flug eine bestimmte endliche Anzahl Punkte abfahren soll. Es ist zwar auch anders möglich, aber mir gefällt diese Methode, und ich wollte sie als Möglichkeit offerieren. Wink

Die gepunktete Kurve ist eine Annäherung an die Spline. Die Nähe kannst du in der Zeile "For C=0 To 1 Step 0.005" verändern, dazu musst du eben den Step verändern. Doch Vorsicht: eine höhere Genauigkeit heißt auch längere Rechenzeit. Der blaue Punkt ist quasi der aktuelle Stand nach dem Zähler. Das habe ich lediglich aus Jux eingefügt. Es ist übrigens nicht jede Sekunde eine Erhöhung zu vermerken, sondern jeden Frame um 0,005 (in der Zeile "a=a+0.005" zu finden, hier ist es ebenfalls möglich, den Wert zu verändern).
mfg, Calvin
Maschine: Intel Core2 Duo E6750, 4GB DDR2-Ram, ATI Radeon HD4850, Win 7 x64 und Ubuntu 12.04 64-Bit
Ploing!
Blog

"Die Seele einer jeden Ordnung ist ein großer Papierkorb." - Kurt Tucholsky (09.01.1890 - 21.12.1935)

Nova

BeitragMo, Jul 13, 2009 3:22
Antworten mit Zitat
Benutzer-Profile anzeigen
Okay. Dann hätte ich nur einen Verbesserungsvorschlag: Die Fixpunkte, auf denen die Linie verläuft, anscheinend drei, sollten markiert werden.

Wenn du den Link zu dem Tutorial schreiben könntest wäre das sehr nett! Very Happy
AMD Athlon II 4x3,1GHz, 8GB Ram DDR3, ATI Radeon HD 6870, Win 7 64bit
 

n-Halbleiter

BeitragMo, Jul 13, 2009 3:48
Antworten mit Zitat
Benutzer-Profile anzeigen
Nova hat Folgendes geschrieben:
Die Fixpunkte, auf denen die Linie verläuft, anscheinend drei, sollten markiert werden.


Änderung: Die (beliebig vielen, die maximale Anzahl an Punkten ist theoretisch unbegrenzt) Punkte werden nun farbig markiert (siehe Einstiegspost).

Achtung: Die Kurve verläuft nicht auf ihnen, sondern nähert sich ihnen, bedingt durch die Anzahl sonstiger Punkte & der Entfernung zu ebenjenen, nur an. Es ist allerdings möglich, eine "Kollision" zu erzugen, jedoch sind solche Situationen nicht die Regel, sondern nur durch wirkliche Linien zu erreichen, da eine Abweichung von einer Einheit schon eine Krümmung besagt. Das musste mal gesagt werden. Wink
mfg, Calvin
Maschine: Intel Core2 Duo E6750, 4GB DDR2-Ram, ATI Radeon HD4850, Win 7 x64 und Ubuntu 12.04 64-Bit
Ploing!
Blog

"Die Seele einer jeden Ordnung ist ein großer Papierkorb." - Kurt Tucholsky (09.01.1890 - 21.12.1935)

mpmxyz

BeitragMo, Jul 13, 2009 11:13
Antworten mit Zitat
Benutzer-Profile anzeigen
Moin!

Zitat:
Code: [AUSKLAPPEN]
Function ToThePowerOf#...


Hattest du Langeweile oder warum hast du eine neue, noch optimierbare Potenzfunktion geschieben?

So viel ich weiß, hat BB schon eine. Smile
Ist die etwa schneller als diese?

Aber ich finde den Code interessant.
Es ist nur so, dass Splines, die durch die Punkte gehen, lieber mag. Wink

mfG
mpmxyz
Moin Moin!
Projekte: DBPC CodeCruncher Mandelbrot-Renderer
 

n-Halbleiter

BeitragMo, Jul 13, 2009 11:17
Antworten mit Zitat
Benutzer-Profile anzeigen
mpmxyz hat Folgendes geschrieben:
Hattest du Langeweile oder warum hast du eine neue, noch optimierbare Potenzfunktion geschieben?

So viel ich weiß, hat BB schon eine. Smile
Ist die etwa schneller als diese?


Ich habe schon einen Test angestellt, meine Funktion ist schneller, allerdings versagt sie bei negativen Exponenten. Aber für diesen Test reicht es. Wink

mpmxyz hat Folgendes geschrieben:
Aber ich finde den Code interessant.
Es ist nur so, dass Splines, die durch die Punkte gehen, lieber mag. Wink


Es gibt für beide Typen ihre Anwendungsmöglichkeiten. ^^
mfg, Calvin
Maschine: Intel Core2 Duo E6750, 4GB DDR2-Ram, ATI Radeon HD4850, Win 7 x64 und Ubuntu 12.04 64-Bit
Ploing!
Blog

"Die Seele einer jeden Ordnung ist ein großer Papierkorb." - Kurt Tucholsky (09.01.1890 - 21.12.1935)

mpmxyz

BeitragMo, Jul 13, 2009 11:43
Antworten mit Zitat
Benutzer-Profile anzeigen
Das mit der Geschwindigkeit ist seltsam...
Aber ich vermute mal, dass das daran liegt, dass in der Standardfunktion der Exponent eine Float ist.

Aber du hast dich wirklich bemüht.

Ich habe eine eigene Funktion in Informatik kennengelernt:

Code: [AUSKLAPPEN]
Function Potenz#(Basis#,Exponent)
   Local Ergebnis#=1
   Local Faktor#=Basis#
   If Exponent<0 Then Exponent=-Exponent:Faktor=1/Faktor
   While Exponent
      If (Exponent And 1) Then Ergebnis=Ergebnis*Faktor
      Exponent=Exponent Shr 1
      Faktor=Faktor*Faktor
   Wend
   Return Ergebnis
End Function


Besonders bei goßen Linien kann das die Geschwindigkeit erhöhen.
mfG
mpmxyz
Moin Moin!
Projekte: DBPC CodeCruncher Mandelbrot-Renderer
  • Zuletzt bearbeitet von mpmxyz am Mo, Jul 13, 2009 11:47, insgesamt einmal bearbeitet
 

n-Halbleiter

BeitragMo, Jul 13, 2009 11:45
Antworten mit Zitat
Benutzer-Profile anzeigen
DAS war der Code, an den ich mich nicht mehr erinnern konnte. Wink Ich war ja in besagter Stunde bei euch in Info dabei.^^

Also, danke, ich habe ihn eingebaut. Smile
mfg, Calvin
Maschine: Intel Core2 Duo E6750, 4GB DDR2-Ram, ATI Radeon HD4850, Win 7 x64 und Ubuntu 12.04 64-Bit
Ploing!
Blog

"Die Seele einer jeden Ordnung ist ein großer Papierkorb." - Kurt Tucholsky (09.01.1890 - 21.12.1935)

Neue Antwort erstellen


Übersicht BlitzBasic Codearchiv

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group