2010. október 26., kedd

Draw a filled circle using ScanLine


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)
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);

{ ... }
  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
    {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
      {Inside inner circle?}
      if sqdist < RMF1 then
        {Inside the inner circle.. just give the scanline the new color}
        P[x] := 255
        {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;
    { ... }

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

Nincsenek megjegyzések:

Megjegyzés küldése