Entwickler-Ecke
Multimedia / Grafik - Einen Kreis pixelweise zeichnen -> Spline
F34r0fTh3D4rk - Sa 17.09.05 11:14
Titel: Einen Kreis pixelweise zeichnen -> Spline
Hallo, ich hatte vor einen Kreis, pixelweise zu zeichnen, also möglichst viele punkte zu berechnen:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9:
| procedure TForm1.Button1Click(Sender: TObject); var i: integer; r: integer; begin r := 5; for i := 1 to 360 do image1.Canvas.pixels[round(cos(i)*r), round(sin(i)*r)] end; |
nur ist jetzt kein kreis zu sehen, ich habe ja auch nicht die kontrolle über die position des kreises, wie ist das richtig ?
wenns fertig ist, soll es ne art spline werden, an dem dann ein objekt langwandert, vielleicht das wollte ich dann für jede iteration berechnen, halt so wie im mini beispiel oben. da stellt sich mir auch noch die frage wie ich das dann mit der geschwindigkeit mache, hat da jemand ahnung von ?
Raphael O. - Sa 17.09.05 11:24
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| procedure TForm1.Button1Click(Sender: TObject); var i: integer; r: integer; x,y:integer; begin x := 100; y := 100; r := 5; for i := 1 to 360 do image1.Canvas.pixels[x+round(cos(degtorad(i))*r), y+round(sin(degtorad(i))*r)] end; |
mit x = mittelpunkt in x-richtung und y = mittelpunkt in y-richtung
ungetestet, hoffe aber, dass es funktioniert..
wenn ich mich recht erinnere erwartet cos() und sin() gradangaben im bogenmaß, was durch degtorad() erreicht wird.
F34r0fTh3D4rk - Sa 17.09.05 11:41
ja so (oder so ähnlich) hab ich das auch schon getestet, geht leider net :(
Raphael O. - Sa 17.09.05 11:55
Delphi-Quelltext
1:
| image1.canvas.pixels[x,y]:=clBlack; |
weist du auch ne Farbe zu? ist oben in deinem Quelltext nicht der Fall
F34r0fTh3D4rk - Sa 17.09.05 12:10
LOL stimmt, wie dumm von mir :wink:
jetzt gehts auch:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9:
| procedure TForm1.Button1Click(Sender: TObject); var i: integer; r: integer; begin r := 15; for i := 1 to 360 do image1.Canvas.pixels[round(cos(i)*r) + r, round(sin(i)*r) + r] := clblack; end; |
ist das denn so auch korrekt mit den 360 ?
der kreis soll sich nämlich kreisförmig aufbauen, also der erste pixel oben bei 0° dann im uhrzeigersinn bis 360° Das tuts im moment net
Raphael O. - Sa 17.09.05 12:50
cos(0) = 1
sin(0) = 0
=> es fängt rechts an
wenns oben anfangen soll solltest du cos(i-90) und sin(i-90) nehmen
cos(-90)=0
sin(-90)=-1
F34r0fTh3D4rk - Sa 17.09.05 13:16
Raphael O. hat folgendes geschrieben: |
cos(0) = 1
sin(0) = 0
=> es fängt rechts an
wenns oben anfangen soll solltest du cos(i-90) und sin(i-90) nehmen
cos(-90)=0
sin(-90)=-1 |
macht er trotzdem nicht, das bild baut sich so zwischendrin stückweise auf, also mal hier n pixel, mal da, aber nicht linear.
Diabele$ - Sa 17.09.05 13:26
Das liegt daran, dass Delphi meint, dass die Winkelangaben im Bogenmaß stehen, und nicht im Gradmaß.
F34r0fTh3D4rk - Sa 17.09.05 13:54
hasse resch, so gehts:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16:
| procedure TForm1.Button1Click(Sender: TObject); var i: integer; r: integer; x,y:integer; begin x := 100; y := 100; r := 15; for i := 1 to 360 do begin image1.Canvas.pixels[x+round(cos(degtorad(i))*r), y+round(sin(degtorad(i))*r)] := clblack; application.processmessages; sleep(1); end; end; |
DANKE SCHÖN
alzaimar - So 18.09.05 08:40
Vielleicht sollte man sich mit Breshenham's Circle Algorithm beschäftigen. Der Zeichnet einen Kreis ohne floating point (sin, cos) arithmetik, sonder nur mit Hilfe von Integermathematik.
NCortex - So 18.09.05 15:23
schon, aber der baut den nicht kreisförmig auf...
sondern an 4 ecken.... (von dem kreis, is doof ich weiß)
alzaimar - Mo 19.09.05 16:43
Pruuuust. Zuerst dachte ich, du hättest'n Rad ab (4 Ecken bei einem KREIS???), aber dann habichs kapiert. Du willst den Kreis wirklich von 0-360° zeichnen. Die bisherigen Lösungen funktionieren nicht, wenn der Radius zu gross wird.
Ich würde folgendes machen:
Entweder gehst du zum 1.Punkt mit MoveTo und ab da zu den Folgepunkten mittels LineTo
Oder, Du baust Dir ein Array [0..460,0..1] Of Integer auf, packst da die Punkte rein und dann malst du es mit Canvas.Polygon oder so.
Oder, Du erstellst per Breshenham einen 1/8el Kreis als Punkteschar (1..n) und erstellst 8 Kopien davon, jeweils um 45° gedreht und abwechselnd gespiegelt, wenn Du verstehst, was ich meine.
uall@ogc - Mo 19.09.05 17:20
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20:
| const r = 50; mx = 100; my = 100; var x,y,y2: integer; begin form1.Canvas.Pen.Color := clblack; for x := 0 to r-1 do begin y := round(sqrt(r*r-x*x)); y2 := round(sqrt(r*r-(x+1)*(x+1))); form1.Canvas.MoveTo(x+mx, y+my); form1.Canvas.LineTo(x+1+mx, y2+my); form1.Canvas.MoveTo(-x+mx, y+my); form1.Canvas.LineTo(-x-1+mx, y2+my); form1.Canvas.MoveTo(x+mx, -y+my); form1.Canvas.LineTo(x+1+mx, -y2+my); form1.Canvas.MoveTo(-x+mx, -y+my); form1.Canvas.LineTo(-x-1+mx, -y2+my); end; end; |
mit hilfe des satzes des pythagoras
F34r0fTh3D4rk - Do 22.09.05 17:41
ihr habt glaube ich noch nicht ganz verstanden was ich vorhabe :lol: deshalb habs ichs auch eigentlich dazugeschrieben, das war ja nur testcode, so verwende ich das ganze:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130:
| unit UMain;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, DXDraws, DXClass, StdCtrls, math;
const Spark_Amount = 500; Radius = 150;
var Spark_Life: integer = 50; MouseControl: boolean = false; gPosi: integer = 0;
type TTarget = record x, y: real; end;
type TSpark = record x, y, sx, sy: real; age: integer; end;
type TForm1 = class(TForm) DXDraw1: TDXDraw; DXImageList1: TDXImageList; DXTimer1: TDXTimer; procedure FormCreate(Sender: TObject); procedure DXTimer1Timer(Sender: TObject; LagCount: Integer); procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); private Target: TTarget; Spark: array[0..Spark_Amount] of TSpark; public end;
var Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject); var i: integer; begin with Target do begin x := Clientwidth div 2; y := Clientheight div 2; end; for i := 0 To Spark_Amount do with Spark[i] Do begin x := Target.x; y := Target.y; age := random(Spark_Life); end; end;
procedure TForm1.DXTimer1Timer(Sender: TObject; LagCount: Integer); Var i: integer; r: TRect; str: string; fps, copyr: string; Begin inc(gposi); if gposi = 180 then gposi := 0; Target.x := clientwidth div 2 + round(cos(degtorad((gposi * 2) - 90)) * radius); Target.y := clientheight div 2 + round(sin(degtorad((gposi * 2) - 90)) * radius); if not DXDraw1.CanDraw then Exit; DXDraw1.Surface.Fill(0); for i := 0 To Spark_Amount Do with Spark[i] do begin dec(age); x := x + sx; y := y + sy; if (age <= 0) Or (x < 0) Or (x + DXImageList1.items.find('Spark').height > width) Or (y < 0) Or (y + DXImageList1.items.find('Spark').height > height) then begin x := Target.x; y := Target.y; sx := (random(10) - 5) / 5; sy := (random(10) - 5) / 5; age := random(Spark_Life); end; r := bounds(round(X), round(Y), DXImageList1.items.find('Spark').height, DXImageList1.items.find('Spark').height); DXImageList1.Items.Find('Spark').DrawAlpha(DXDraw1.Surface, R, 0, Spark[i].Age * 255 Div Spark_Life); end; str := 'Lebensdauer setzen mit + und -'; copyr := 'Seth 2005'; fps := 'FPS: ' + inttostr(DXTimer1.Framerate); with DXDraw1.Surface.Canvas do begin Font.Name := 'Arial'; Font.Size := 12; TextOut(0, 0, str); TextOut(0, clientheight - textheight(copyr), copyr); TextOut(clientwidth - textwidth(fps), 0, fps); Release; end; DXDraw1.flip; end;
procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin if key = vk_add then if Spark_Life < 1000 then inc(Spark_Life); if key = vk_subtract then if Spark_Life > 1 then dec(Spark_Life); end;
Initialization Randomize;
end. |
der markierte code ist entscheident, trotzdem wären verbesserungsvorschläge net schlecht ;)
alzaimar - Fr 23.09.05 13:37
F34r0fTh3D4rk hat folgendes geschrieben: |
ihr habt nich wirklich geschnallt was ich vorhab :lol: |
Du hast nicht wirklich gesagt, was Du vorhast :bawling:
Wenns läuft, dann is doch alles ok...
Verbesserungen:
Statt imm er dgposi := dgposi + 1 zu machen und dann in RAD umzurechnen, definier Dir doch einfach eine Konstante 'OneDegreeRAD = 2PI/360' oder was das ist und benutz das anstelle von '+1'. Dann sparst Du Dir schonmal das Umrechnen in rad.
Dann suchst Du 2x nach einem Image in der Imagelist... such sie nur 1x, das reicht.
Abschließend gehören solche Konstanten wie 180 etc. in den 'Const' Teil der Unit...
Letzte Verbesserung: Arbeite an Deiner Fähigkeit, Probleme zu artikulieren :mrgreen:
F34r0fTh3D4rk - Fr 23.09.05 16:22
Titel: Re: Einen Kreis pixelweise zeichnen -> Spline
F34r0fTh3D4rk hat folgendes geschrieben: |
wenns fertig ist, soll es ne art spline werden, an dem dann ein objekt langwandert, vielleicht das wollte ich dann für jede iteration berechnen, halt so wie im mini beispiel oben. da stellt sich mir auch noch die frage wie ich das dann mit der geschwindigkeit mache, hat da jemand ahnung von ? |
delfiphan - Fr 23.09.05 16:37
Geh ich richtig in der Annahme, dass du jetzt eine funktionierende Lösung hast? (Wieso posten alle weiter?)
F34r0fTh3D4rk - Fr 23.09.05 16:44
der beitrag ist auch schon als beantwortet markiert, schon längst :lol:
alzaimar - Fr 23.09.05 16:45
Touché :roll: , "so ne Art Spline".... Na nun, bleiben wir also bei einem Kreis, den ein Spline ist dann wieder etwas ganz Anderes. Du solltest Dir zuerst also überlegen, in welcher Schrittweite dein Ding rumwandern soll (von pixel zu pixel, oder wie). Dann erzeugst Du Dir den Pfad dazu als Array, z.B. Für pixelgenaue Bewegungen würde ich trotzdem den Bresenham nehmen. Der erzeugt zwar nur eine 8tel Kreis, aber, das kann man einfach spiegeln (und ein wenig rechnen). Also: Du erzeugst Dir ein X/Y-Array und wanderst einfach jeden Punkt in dem Array an.
Also, so würd' ich das wenigstens machen.
F34r0fTh3D4rk - So 25.09.05 15:03
alzaimar hat folgendes geschrieben: |
Touché :roll: , "so ne Art Spline".... Na nun, bleiben wir also bei einem Kreis, den ein Spline ist dann wieder etwas ganz Anderes. Du solltest Dir zuerst also überlegen, in welcher Schrittweite dein Ding rumwandern soll (von pixel zu pixel, oder wie). Dann erzeugst Du Dir den Pfad dazu als Array, z.B. Für pixelgenaue Bewegungen würde ich trotzdem den Bresenham nehmen. Der erzeugt zwar nur eine 8tel Kreis, aber, das kann man einfach spiegeln (und ein wenig rechnen). Also: Du erzeugst Dir ein X/Y-Array und wanderst einfach jeden Punkt in dem Array an.
Also, so würd' ich das wenigstens machen. |
nee, splines sind in der regel vektorgrafiken, bzw vektorpfade. und dazu gehört auch ein kreis.
delfiphan - So 25.09.05 15:17
Splines sind nicht einfach irgendwelche Vektorpfade. Es gibt viele verschiedene Splines. Spricht man aber von "Spline" ist häufig der "natürliche, kubische Spline" gemeint. Wenn du einen Pfad darstellen willst, brauchst du einen parametrischen Spline.
Aber egal welche Spline-Sorte: Soweit ich weiss, kann man keinen Kreis exakt durch Splines darstellen. Näherungsweise natürlich schon.
alzaimar - Mo 26.09.05 21:08
F34r0fTh3D4rk hat folgendes geschrieben: |
nee, splines sind in der regel vektorgrafiken, bzw vektorpfade. und dazu gehört auch ein kreis. |
Wie delfiphan schon sagte, splines hat nix mit kreisen zu tun. Wat is also ne spline?
Nimm Dir mal N (n>3, glaub ich) Punkte (X,Y), wobei zunächst Xi > X(i-1). Nun willst Du die durch eine glatte Kurve verbinden. Das kann man natürlich auf vielfältige Art und Weise machen. Eine Möglichkeit ist die, zwischen je zwei Punkten ein Polynom 3.Grades zu zeichnen. Zwischen P1 und P2 ist dann das Polynom C1, zwischen P" und P3 ist das Polynom C2 usw. Jedes Poynom ist durch 4 Parameter (a,b,c,d) gekennzeichnet. Nun ist nur noch zu klären, wie man die N-1 Polynome bekommt, sodass diese 'glatt' nebeneinander liegen. Klar, die erste Ableitung am Endpunkt von C1 muss = der 1.Ableitung am Anfangspunkt von C2 sein usw. Dann nur noch dafür sorgen, das die Y-Werte der Polynome gelten und schon hat ein Gleichungssystem, das man lösen kann. Man braucht nur noch die Anfangssteigungen bzw. die 2.Ableitung der Anfangs- und Endpunkte (P1 und Pn) vorgeben. Dann setzt man einen Gauss drauf an, bekommt für jedes Polynom die Coeffizienten und fertig.
Ausgleichsplines (Bezier-Kurven) gibt es auch noch. Dabei geht die Kurve nicht durch die Punkte, sondern glättet den Pfad zwischen den Punkten ("Ausgleichskurve").
Im Metafont-Programm von D.Knuth werden Bernsteinpolynome verwendet, das sie sehr leicht zu berechnen sind.
So viel zu dem 'Nee'.
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!