OMG, Sqrt/ArcCos within the inner cycle!
http://cboard.cprogramming.com/game-...algorithm.html
OMG, Sqrt/ArcCos within the inner cycle!
http://cboard.cprogramming.com/game-...algorithm.html
But your link does not refer to a filled circle algorithm. You see in my first post I had a solution without sqrt. But it was awfully slow.
I came to this, which is fast and does not overlap anymore (this can be seen when drawing alphablended):
Code:procedure fillcircle (cx,cy,r:integer); var x,y,r2,dx:integer; begin if r = 0 then begin r:=1; end; r2 := r * r; for x := r downto 0 do begin y := round(sqrt(r2 - x*x)); dx := cx - x; line(dx-1, cy-y, dx-1, cy+y); dx := cx + x; line(dx, cy-y, dx, cy+y); end; end;
Best regards,
Cybermonkey
well I suppose that works but what if you want a 6 sided circle or an ellipse or a half circle. might be better to use a more conventual routine with a fill routine.
Sometimes, but fill routine makes it much slower. It is checking for pixels on every draw to find where the borders are, and could also be allocating dynamic arrays for point data, depending on algorithm. You can modify algorithms to make filled half circle etc. And if you need to draw the circle on top of a complex drawing, fill no longer works. And it's in addition that you would use sin/cos/sqrt for outline anyway
Here's algorithm for above given function translated, filled and non-filled circle. (Drawing to TForm.canvas directly was bad idea, i know... but it showed it at least.)
Also as far as i see, the fill function may draw some pixels overlapped. Not perfectly optimal this way.Code:procedure DrawPixel(x, y: longint; color: TColor); begin form1.Canvas.Pixels[x, y]:=color; end; procedure DrawLine(x1, x2, y: longint; color: TColor); var x: integer; begin for x:=x1 to x2 do form1.Canvas.Pixels[x, y]:=color; end; procedure retro_circle(xc, yc, r: longint; color: TColor); var x, y, d: longint; begin x:=0; y:=r; d:=1 - r; while x < y do begin if d < 0 then d:=d + 2*x + 3 else begin d:=d + 2*x - 2*y + 5; dec(y); end; DrawPixel(xc + x, yc - y, color); // Top DrawPixel(xc - x, yc - y, color); DrawPixel(xc + y, yc - x, color); // Upper middle DrawPixel(xc - y, yc - x, color); DrawPixel(xc + y, yc + x, color); // Lower middle DrawPixel(xc - y, yc + x, color); DrawPixel(xc + x, yc + y, color); // Bottom DrawPixel(xc - x, yc + y, color); inc(x); end; end; procedure retro_fill_circle(xc, yc, r: longint; color: TColor); var x, y, d: longint; begin x:=0; y:=r; d:=1 - r; while x < y do begin if d < 0 then d:=d + 2*x + 3 else begin d:=d + 2*x - 2*y + 5; dec(y); end; DrawLine(xc - x, xc + x, yc - y, color); DrawLine(xc - y, xc + y, yc - x, color); DrawLine(xc - y, xc + y, yc + x, color); DrawLine(xc - x, xc + x, yc + y, color); inc(x); end; end;
Last edited by User137; 13-11-2013 at 10:49 PM. Reason: Didn't need those n variables
That's exactly what i did. But i now decided to go back to it a little and optimize it. No more overlapped pixels. Also screenshot to let you see the areas it makes with different colors.
edit: Actually the real ratio might close into sin(45 degree) ~ 0.707. There is 2 pixel-lines overlapped still when drawing with 250 radius. We aren't talking of any significant performance difference though. But if drawing blended pixels you want absolute precision.Code:... adding previous code... procedure DrawVLine(x, y1, y2: longint; color: TColor); var y: integer; begin for y:=y1 to y2 do form1.Canvas.Pixels[x, y]:=color; end; // Optimized fill circle procedure retro_fill_circle(xc, yc, r: longint; color: TColor); var x, y, d, y1, y2: longint; begin x:=0; y:=r; d:=1 - r; y1:=r*7 div 10; // I found this 7/10 ratio just by testing and testing a little... // It is the Y coordinate where the drawing sections separate y2:=yc+y1; y1:=yc-y1; while x < y do begin if d < 0 then d:=d + 2*x + 3 else begin d:=d + 2*x - 2*y + 5; dec(y); end; DrawVLine(xc - x, yc - y, y1, color); // Top DrawVLine(xc + x, yc - y, y1, color); DrawLine(xc - y, xc + y, yc - x, color); // Upper middle DrawLine(xc - y, xc + y, yc + x, color); // Lower middle DrawVLine(xc - x, y2, yc + y, color); // Bottom DrawVLine(xc + x, y2, yc + y, color); inc(x); end; end;
Last edited by User137; 13-11-2013 at 10:47 PM.
Bookmarks