Entwickler-Ecke
Multimedia / Grafik - Außenkreisberechnung eines Kreises
IhopeonlyReader - Mo 28.01.13 20:55
Titel: Außenkreisberechnung eines Kreises
Guten Tag,
Ziel: Prozedure erstellen, die:
mit folgenden Parametern: Kreismittelpunkt (M), Radius (r), Canvas (BC)
folgendes tut:
- auf ein jetziges Canvas (z.B. Bitmap.Canvas woebei auf der bitmap ein sich bewegendes bild ist) den Umriss eines Kreises zeichnet...
- schneller als 5ms ist (bei einer Berechnung von einem radius bis zu 300 (pixeln))
Bis jetzt ist es meistens am 2ten gescheitert....
Folgendes habe ich ausprobiert:
Zuerst: normaler Kreis mit "durchsichtiger"/"weißer" farbe gefüllt und farbigen rand...
Problem: bei weißer mitte: bitmap im kreis überzeichnet bei durchsictiger mitte: mitübergebene canvas fehlte ebenfalls in dem kreis.. in dem kreis war mein desktophintergrund zu sehen
Danach: (siehe
http://de.wikipedia.org/wiki/Kreis_(Geometrie)#Koordinatengleichung)
2 Forschleifen,wobei die eine von m.x-r bis m.x+r und die andere (in der erstn) von m.y-r bis m.y+r geht... danach der entsprechende die strecke (Sr) von punkt (a|b) (a = durchlaufsvariable aus der ersten for-schleife (x-koordinate) (b= durchlaufsvariable aus der zweiten for-schleife (y-koordinate) zum mittelpunkt mit dem satz des pytagoras berechnet wird und wenn Sr = r dann wird der pixel an dem punkt (a|b) gezeichnet. .. (also viereck pixel für pixel durchgehen und berechnen ob der pixel die entfernung des pixels zum mittelpunkt = der radius ist)
Problem: dauert zu lang... klappt aber einwandfrei
Danach: (siehe
http://de.wikipedia.org/wiki/Bresenham-Algorithmus#Zeichnen_nicht-vollst.C3.A4ndiger_Oktanten)
Berechnung nach dem Ansatz nach der Methode von Horn.. (8 punkte berechnen (obem mitte, unten mitte, mitte rechts, links mitte und entsprechend wenn man r in 2 gleichlange seiten unterteilt (r^2 =sx^2+sy^2))
Problem: Es sind nur 8 Punkte , also ein 8 Eck... bei größeren radien (ab 100) sehr ungenau/unübersichtlich (starke abweichungen) wenn man geraden zwischen den punkten zieht
ERgänzung:
danach habe ich die Methode von Horn weiter verfolgt..
Horn hat nun diese 8 Punkte rotieren lassen (siehe "Kreisvariante des Algorithmus" (im link)) mit einer while schleife....
Problem: ich habe das Beispiel nicht ganz verstanden und damit falsch ungesetzt...
Letzter Versuch:
Punktberechnung und mit sinus den punkt, wie an einer schnur, um den mittelpunkt kreisen lassen...
Teilproblem: Mal hats mit dem 5 ms geklappt mal nicht... Sinus und Cosinus sind in Delphi sehr langsam in der Berechnung...
Könnt ihr mir bei der Methode von Horn oder bei meinem letzten Ansatz helfen?
Freue mich auf Ideenreiche antworten
Moderiert von
Narses: Topic aus Sonstiges (Delphi) verschoben am Mo 28.01.2013 um 22:41
Mathematiker - Mo 28.01.13 21:19
Hallo,
IhopeonlyReader hat folgendes geschrieben : |
- schneller als 5ms ist (bei einer Berechnung von einem radius bis zu 300 (pixeln)) |
Ich verstehe nicht richtig, was Du eigentlich meinst.
Bei einem Test habe ich 2000(!) Kreise mit Füllen in 200 ms auf den Bildschirm gezeichnet und dabei waren noch 6000 Random-Rufe inklusive. Mit durchsichtigem Brush waren es 80 ms.
IhopeonlyReader hat folgendes geschrieben : |
bei durchsictiger mitte: mitübergebene canvas fehlte ebenfalls in dem kreis.. in dem kreis war mein desktophintergrund zu sehen |
Und das verstehe ich gar nicht. Ein Kreis mit brush.style:=bsclear zeichnet den Rand, wie Du es ja wünschst.
Vielleicht zeigst Du einmal etwas Quelltext. Denn ich vermute, dass Problem liegt nicht beim Kreis.
Beste Grüße
Mathematiker
IhopeonlyReader - Mo 28.01.13 21:37
normale kreise ja :D wie gesagt hierbei lag das problem nicht bei der geschwindigkeit... sondern bei dem überzeichnen der mitte
5ms bei r=300 ... logisch was damit gemeint ist oder? es soll ein kreisumriss gezeichnet werden, bei dem r bis auf 300 hochgeht.. die zeichenzeit darf 5 ms nicht überschreiten..
durchsichtige mitte = transparent color (form durchsichtbarkeit) -> durchsichtige form
brush.style := bsclear
DAS ist das was ich suchte :).. ich hatte die brush.color auf die transparent color der form gesetzt (Form1.TransparentColor := True;
Form1.TransparentColorValue := clyellow; und dann brush.color := clyellow... wobei ich natürlich eine ungebräuchlichere farbe als gelb verwendet hatte...)
da ich brush.style := bsclear nicht kannte versuchte ich mir mit all den anderen formen und berechnungen zu helfen um den umriss herauszufinden
(auch wenn ich sagen muss meine methode mit den 2 for-schleifen liefert ein "runderen" kreis^^ (raidus = 250 pixel)
aber DANKE
Horst_H - Di 29.01.13 19:15
Hallo,
man kann Kreise auch anders zeichnen. Ich hatte mal Überlegungen, bei denen es geblieben ist, einen Stiftplotter zu bauen und da kann man Bresenham für Kreise nicht so wirklich anwenden.
Also habe ich eine gewisse Abweichung zugelassen und dann den Linienzug bestimmt, den man über Additionstheoreme von sin und cos sehr schnell berechnen kann.Es war mal für TurboPascal und ist hier auf eine Form mit einem Button umgesetzt.Natürlich ist das nicht so schnell, wie die Grafikarte via GDI+ oder DirectX das könnte, aber auch nicht extrem langsam. 8 Sekunden für 10000.
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: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189:
| unit Unit1;
{$mode objfpc}{$H+}
interface
uses Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls;
type
TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private public end;
var Form1: TForm1;
implementation
{$R *.lfm} type tKreisDat = record rcosPhi, rsinPhi,
dCosPhi, dSinPhi : double; r, x_m, y_m, next_x, next_y, countdown : word;
fertig : boolean; end;
function KreisInitLinie(x,y,r:word; phi_start,phi_end:double; delta:double=0.25): tKreisDat;
const DegToRad = pi/180; VollKreis = 360.0;var Phi, dPhi, DeltaPhi : double; begin result.r := r; with result do begin x_m := x; y_m := y; countDown := 0; deltaPhi := phi_end-Phi_start; IF ABS(deltaPhi) > VollKreis then IF deltaPhi > 0 then deltaPhi := Vollkreis else deltaPhi := -VollKreis;
deltaPhi := deltaPhi*DegToRad; Phi := phi_start*DegToRad;
if r> delta then begin rcosPhi := (r-delta)/(r+delta); rsinPhi := sqrt(1-sqr(rcosPhi)); dSinPhi := 2*rcosPhi*rsinPhi; dCosPhi := sqr(rcosPhi)-sqr(rsinPhi); IF dCosPhi > 0 then dPhi := ArcTan(dSinPhi/dCosPhi) else dPhi := pi/4;
countDown := round(ABS(deltaPhi)/dPhi+0.5); dPhi := deltaPhi/countdown; end else dphi := 2*pi;
dSinPhi := sin(dPhi); dCosPhi := cos(dPhi);
rCosPhi := r*cos(phi); rSinPhi := r*sin(phi);
next_x := x_m+round(rcosPhi); next_y := y_m-round(rsinPhi); fertig := r= 0; end; end;
procedure nextPunkt(var KreisDat:TKreisDat); var tmpCos : double; begin with kreisdat do begin if fertig then exit; tmpCos := rcosPhi; rcosPhi:= rcosPhi*dcosPhi-rsinPhi*dsinPhi; rsinPhi:= rsinPhi*dcosPhi+tmpCos*dsinPhi; next_x := x_m+round(rcosPhi); next_y := y_m-round(rsinPhi); dec(countdown); fertig := (countdown = 0); end; end;
Procedure KreisLinienweise(var Kreis:TKreisDat; cv : TCanvas; Kcolor: tColor); {$DEFINE LinienAbschnittesichtbar} begin cv.Pen.Color:= Kcolor; with Kreis do begin cv.Moveto(Next_x,Next_y); repeat NextPunkt(kreis); cv.Lineto(Next_x,Next_y); {$IFDEF LinienAbschnittesichtbar} Kcolor := Not KColor; cv.Pen.Color:= Kcolor; {$ENDIF} until fertig; end; end;
procedure TForm1.Button1Click(Sender: TObject); const von = 0; bis = 255-von; var Kreis : TKreisDat; xm,ym, i,j, delta,r : integer; begin j := von; delta := 1;
xm := Form1.ClientWidth DIV 2; ym := Form1.ClientHeight DIV 2;
r := xm; IF xm > ym then r := ym;
For i := 1 to 10000 do begin Button1.Caption := INtToSTr(i); Kreis := KreisInitLinie(xm,ym,r-round(0.5*r*random),0.0,72360.0); KreisLinienweise(Kreis,Form1.Canvas,j*(256*256+256+1)); inc(j,delta); IF (j <= von) or (j >= bis) then delta := -delta; end;
end; end. |
Eine Skizze wäre wohl angebracht ;-)
EDIT:
Hier sieht man, dass der Kosinus des halben Winkels einer Linie mit der maximalen Abweichung delta entsprechend so berechnet wird:
cos(dPhi/2) = (r-delta)/(r+delta)
Kostas - Do 07.02.13 17:02
Hallo,
nur als Ergänzung gedacht...
Wenn es um das Zeichnen geht, ähnlich einem CAD-System, gibt es die ImageEN Komponenten. Damit kannst du Verktoren zeichnen und hast ein Panel welches Zoomfähig ist.
Gruß Kostas
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!