## 2010. október 26., kedd

### Draw a filled circle using ScanLine

Problem/Question/Abstract:

I am looking for some code to draw a filled circle on a bitmap or change colors of pixels within a circle on it, using Bitmap.Scanline. Any suggestions or ideas on how to do this, the edges need to be perfect and it has to be fast.

Perfect edges mean you will have to work with an alpha channel and do anti-aliasing. This means, that you either have to use a 32-bit bitmap (see e.g. Graphics32) or you have to first draw the background image in the bitmap and directly blend it when rendering the circle. Next question: do you want to use integer precision or floating point precision for the circle properties like center point and diameter? If you use integer, you only have to draw 1/8 of the circle and the rest can be copied/mirrored/flipped around. Assuming floating point, and a grayscale bitmap, here's an approach:

CX, CY: center of circle (single)
F: feather size (the number of pixels used as blend area, usually 1 pix) (single)

Determine bounds in Y (integers):
LX := floor(CX - R - F * 0.5);
RX := ceil(CX + R + F * 0.5);
LY := floor(CY - R - F * 0.5);
RY := ceil(CY + R + F * 0.5);

RPF2 = sqr(R + F/2);
RMF2 = sqr(R - F/2);

{ ... }
var
P: PByteArray
sqdist: single;
{ ... }
{Loop through Y values}
{for y := LY to RY do begin -> not very safe}
for y := max(LY, 0) to Min(RY, Bitmap.Height - 1) do
P := Bitmap.Scanline[y];
{Loop through X values}
for x := Max(LX, 0) to Min(RX, Bitmap.Width - 1) do
begin
{Determine squared distance from center for this pixel}
sqdist := sqr(y - CY) + sqr(x - CX); {Or use hypot() function}
{Inside outer circle?}
if sqdist < RPF2 then
begin
{Inside inner circle?}
if sqdist < RMF1 then
{Inside the inner circle.. just give the scanline the new color}
P[x] := 255
else
begin
{We are inbetween the inner and outer bound, now mix the color}
Fact := Max(0, Min(255, round(((R - sqrt(sqdist)) * 2 / F) * 128 + 128)));
P[x] := (255 - Fact) * P[x] + Fact;
end;
end;
{ ... }

This algorithm is optimized a bit but could be made faster probably. Untested!