2009. szeptember 26., szombat

Draw an antialiased line


Problem/Question/Abstract:

How to draw an antialiased line

Answer:

Here's a procedure that uses a modified version of Gupta-Sproull anti-aliasing:

procedure DrawLine(Canvas: TCanvas; x1, y1, x2, y2: integer);

  procedure DrawPixel(x, y: integer; Distance: double);
  var
    Alpha: integer;
  begin
    Alpha := 255 - Trunc(255 * Sqr(1 - Distance * 2 / 3));
    Canvas.Pixels[x, y] := Alpha or (Alpha shl 8) or (Alpha shl 16);
  end;

var
  i, deltax, deltay, numpixels, d, dinc1, dinc2, x, xinc1, xinc2, y, yinc1, yinc2:
    Integer;
  du: Integer;
  twovdu: Integer;
  invD: Double;
  invD2du: Double;
  vincx, vincy: Integer;
begin
  {Calculate deltax and deltay for initialisation}
  deltax := abs(x2 - x1);
  deltay := abs(y2 - y1);
  {Initialize all vars based on which is the independent variable}
  if deltax >= deltay then
  begin
    {x is independent variable}
    numpixels := deltax + 1;
    d := (2 * deltay) - deltax;
    dinc1 := deltay shl 1;
    dinc2 := (deltay - deltax) shl 1;
    xinc1 := 1;
    xinc2 := 1;
    yinc1 := 0;
    yinc2 := 1;
    du := deltax;
    vincx := 0;
    vincy := 1;
  end
  else
  begin
    {y is independent variable}
    numpixels := deltay + 1;
    d := (2 * deltax) - deltay;
    dinc1 := deltax shl 1;
    dinc2 := (deltax - deltay) shl 1;
    xinc1 := 0;
    xinc2 := 1;
    yinc1 := 1;
    yinc2 := 1;
    du := deltay;
    vincx := 1;
    vincy := 0;
  end;
  twovdu := 0;
  invD := 1 / (2 * sqrt(deltax * deltax + deltay * deltay));
  invD2du := 2 * (du * invD);
  {Make sure x and y move in the right directions}
  if x1 > x2 then
  begin
    xinc1 := -xinc1;
    xinc2 := -xinc2;
    vincx := -vincx;
  end;
  if y1 > y2 then
  begin
    yinc1 := -yinc1;
    yinc2 := -yinc2;
    vincy := -vincy;
  end;
  {Start drawing at [x1, y1]}
  x := x1;
  y := y1;
  {Draw the pixels}
  for i := 1 to numpixels do
  begin
    DrawPixel(x, y, twovdu * invD);
    DrawPixel(x + vincx, y + vincy, invD2du - twovdu * invD);
    DrawPixel(x - vincx, y - vincy, invD2du + twovdu * invD);
    if d < 0 then
    begin
      twovdu := d + du;
      d := d + dinc1;
      x := x + xinc1;
      y := y + yinc1;
    end
    else
    begin
      twovdu := d - du;
      d := d + dinc2;
      x := x + xinc2;
      y := y + yinc2;
    end;
  end;
end;

Nincsenek megjegyzések:

Megjegyzés küldése