Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Bezierkurven (https://www.delphipraxis.net/83055-bezierkurven.html)

rawsoul 26. Dez 2006 15:42


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:
http://upload.wikimedia.org/math/4/a...d1cd0be79c.png

Bin für jeden hilfreichen Tipp Dankbar!

LG, und ein (nachträglich) frohes Fest an alle!

Ratte 26. Dez 2006 16:09

Re: Bezierkurven
 
Delphi-Quellcode:
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;
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).
mfg,
Ratte

rawsoul 26. Dez 2006 16:17

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?

Ratte 26. Dez 2006 16:25

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:
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;
durhc 3x klicken werden die Punkte festgelegt.

rawsoul 26. Dez 2006 16:30

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!

Ratte 26. Dez 2006 16:45

Re: Bezierkurven
 
i/1000 ist das t, und dann halt die Formel einmal für den x- und einmal für den y-Anteil.

Khabarakh 26. Dez 2006 18:38

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.

Ratte 26. Dez 2006 19:05

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.

dizzy 27. Dez 2006 09:51

Re: Bezierkurven
 
In meinem Progrämmchen RiB habe ich den De Casteljau Algo recht flott implementiert. Sollte sich imho ganz gut daraus übernehmen lassen.

\\edith: Hier mal die wichtige Funktion
Delphi-Quellcode:

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;
TBezierSet ist ein array[0..3] of TFloatPoint, wobei TFloatPoint ein record mit x,y:Double ist.
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).

Hawkeye219 27. Dez 2006 14:06

Re: Bezierkurven
 
Hallo,

für eine kubische Bezier-Kurve könnte man auch Delphi-Referenz durchsuchenTCanvas.PolyBezier nutzen.

Gruß Hawkeye


Alle Zeitangaben in WEZ +1. Es ist jetzt 17:34 Uhr.
Seite 1 von 2  1 2      

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