Draw a filled circle using ScanLine (Views: 30)
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. Answer: 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) R: radius 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); Determine some helpful values (singles) 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! |