![]() |
Bezierkurven
Hallo Ihr lieben Delphianer,
Ich möchte mir z. Zt. aus reinem Interess ein Programm schreiben, welches eine quadratische Bezierkurve in eine PainBox zeichnen soll. Habe mich schon mühselig durch das halbe Forum (Achtung: übertrieben!) gesucht, aber leider nichts gefunden. Bräuchte wenigstens einen ersten Ansatzpunkt für die ganze Geschichte. Hier mal das von Wiki geklaute Bild zur Funktion einer B-Kurve: ![]() Bin für jeden hilfreichen Tipp Dankbar! LG, und ein (nachträglich) frohes Fest an alle! |
Re: Bezierkurven
Delphi-Quellcode:
So funzt es bei mir, vorrausgesetzt mein Grundansatz ist richtig (habs mir in den letzten 10 min schnell erarbeitet, aber es sieht wie ne bezierkurve aus und erscheint mir logisch).
i:integer;
p0,p1,p2:TPoint; self.Canvas.MoveTo(P0.x,P0.y); for i := 0 to 1000 do begin hx:=round(sqr(1-i/1000)*P0.X+2*i/1000*(1-i/1000)*P1.X+sqr(i/1000)*P2.X); hy:=round(sqr(1-i/1000)*P0.y+2*i/1000*(1-i/1000)*P1.y+sqr(i/1000)*P2.y); self.Canvas.LineTo(hx,hy); end; mfg, Ratte |
Re: Bezierkurven
danke, bin schonmal tausend denkschritte weiter :]
hm, bei mir zeichnet er nur eine lineare strecke von p0 nach (hx,hy) ??? hab ich da was falsch gemacht? |
Re: Bezierkurven
öhm. p0 ist der anfangspunkt, p1 der "hilfspunkt" und p2 der endpunkt. Also bei mir hats funktioniert.
EDIT: Hier mal etwas mehr QT:
Delphi-Quellcode:
durhc 3x klicken werden die Punkte festgelegt.
var
Form1: TForm1; state:byte; p0,p1,p2:TPoint; implementation {$R *.nfm} procedure TForm1.Neu1Click(Sender: TObject); //Neue Kurve zeichnen begin state:=0; end; procedure TForm1.FormCreate(Sender: TObject); begin state:=0; end; procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var i,hx,hy:integer; begin case state of 0: begin state:=1; P0.X:=X; P0.Y:=Y; end; 1: begin state:=2; P1.X:=X; P1.Y:=Y; end; 2: begin state:=3; P2.X:=X; P2.Y:=Y; self.Canvas.MoveTo(P0.x,P0.y); for i := 0 to 1000 do begin hx:=round(sqr(1-i/1000)*P0.X+2*i/1000*(1-i/1000)*P1.X+sqr(i/1000)*P2.X); hy:=round(sqr(1-i/1000)*P0.y+2*i/1000*(1-i/1000)*P1.y+sqr(i/1000)*P2.y); self.Canvas.LineTo(hx,hy); state:=0; end; end; end; end; |
Re: Bezierkurven
wow, super!
vielen dank für die hilfe! jetzt muss ich nur noch versuchen, nachzuvollziehen, wie du die formel umgeschrieben hast... ;) frohes fest noch! |
Re: Bezierkurven
i/1000 ist das t, und dann halt die Formel einmal für den x- und einmal für den y-Anteil.
|
Re: Bezierkurven
Béziers werden normalerweise per Casteljau-Algorithmus gezeichnet, wodurch sie beliebig genau dargestellt werden können. Aber auch bei der Parameterfunktion könntest du adaptiv vorgehen, d.h. die Schrittweite von t dort verringern, wo sonst die Abstände zu groß und die Kurve eckig wird. Die dritte Möglichkeit wäre dann noch die GDI+-API, in der eine Bézierfunktion schon enthalten ist. Eine dieser Möglichkeiten solltest du aber auf jeden Fall implementieren, sonst wird das Ergebnis ziemlich hässlich werden.
|
Re: Bezierkurven
hast du natürlich recht. Das Beispiel hatte ich ja auch nur schnell zusammengehackt und von dem anderen algorithmus hab ich keine Ahnung, während das hab ich sofort kapiert. :wink:
ich würde 1/2x(Abstand aller Punkte) als genauigkeit nehmen. Ist zwar zuviel, reicht aber folglich auf jeden Fall. |
Re: Bezierkurven
In meinem
![]() \\edith: Hier mal die wichtige Funktion
Delphi-Quellcode:
TBezierSet ist ein array[0..3] of TFloatPoint, wobei TFloatPoint ein record mit x,y:Double ist.function BezierPoint(pt: TBezierSet; t: Double): TFloatPoint; var t0, t1, t2, t3: Double; oneMt, tp2, oneMtp2: Double; begin oneMt := 1-t; tp2 := sqr(t); oneMtp2 := sqr(oneMt); t0 := oneMtp2*oneMt; t1 := 3*t*oneMtp2; t2 := 3*tp2*oneMt; t3 := tp2*t; result.x := t0 * pt[0].x + t1 * pt[1].x + t2 * pt[2].x + t3 * pt[3].x; result.y := t0 * pt[0].y + t1 * pt[1].y + t2 * pt[2].y + t3 * pt[3].y; end; In pt werden hier die 4 Kontrollpunkte der Kurve übergeben, und mit t (0..1) "wandert" man über die Kurve. Um das zu zeichnen muss man diese Funktion also nur in einer Schleife über t aufrufen, und die zurückgelieferten Punkte mit LineTo verbinden. Die Schrittgröße von t bestimmt somit die Genauigkeit (Eckigkeit) des Ergebnisses, und damit auch den Performancehunger :) \\edith2: *hust* naja, der De Casteljau isses ja garnicht so richtig. Viel mehr eine günstig zerlegte Variante der o.g. Formel. Wie viel schneller De Castelljau im Vergleich dazu ist, weiss ich leider nicht. Aber mir hat die Funktion zumindest bisher immer brav Beziér Kurven geliefert ^^ \\edit3: Eigentlich kann man mit Beziér Kurven über mehr als nur 4 Punkte annähern, nämlich beliebig vielen. Der Aufwand dafür ist, wenn ich mich recht erinnere, allerdings O(n²), und mit Algo nach De Casteljau O(n*log(n)). Man wählt jedoch oft die Darstellung durch 4 Kontrollpunkte, da sich damit die lokale Kontrolle in der Kurve deutlich verbessert, und stückelt mehrere 4-Punkt Kurven zu einer komplexeren zusammen, wobei der jeweils 2. und 3. Kontrollpunkt die Tangente in dem Anfangs- und Endpunkt erzeugt. Dadurch kann man auch bei gestückelten Kurven recht einfach weiche Übergänge erzielen. Wenn du aber nun tatsächlich Kurven über eine variable Anzahl von Kontrollpunkten möchtest, lohnt es sich sicher De Casteljau i.e.S. implementieren, und keine auf 4 Punkte spezialisierte Form. Dazu gibt es massig, und auch gute Infos im Netz (z.B. Wikipedia ist echt brauchbar in dem Punkt). |
Re: Bezierkurven
|
Re: Bezierkurven
wow das sind schöne lösungsmöglichkeiten :]
ich les mich mal durch alles durch, schonmal ein großes danke an alle! |
Alle Zeitangaben in WEZ +1. Es ist jetzt 12:42 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz