The Bresenham Algorithm for Lines

From Gezel2

Jump to: navigation, search

The Bresenham family of algorithms are a classic in efficient raster-scan conversion of geometric shapes. In the line drawing algorithm, the objective is to turn on selected pixels from a raster scan display, when the starting point (x1, y1) and the target point (x2,y2) are given. The distinguishing feature of the Bresenham algorithms is that they only require simple integer computations, including addition, substraction and comparison.

[edit] bresen.fdl

dp bresen(in x1_in, y1_in, x2_in, y2_in : tc(12)) {
  reg x, y             : tc(12);  // current plot position
  reg e                : tc(12);  // accumulated error
  reg eol              : tc(1);  // end-of-loop flag
  reg einc1, einc2     : tc(12);  // increment values for straight/diagonal
  reg xinc1, xinc2     : tc(12);
  reg yinc1, yinc2     : tc(12);
  sig se, sdx, sdy     : tc(12); 
  sig asdx, asdy       : tc(12);
  sig stepx, stepy     : tc(12); 

  sfg init {
    // evaluate range of pixels and their absolute value
    sdx   = x2_in - x1_in;  asdx = (sdx < 0) ? -sdx : sdx;
    sdy   = y2_in - y1_in;  asdy = (sdy < 0) ? -sdy : sdy;

    // determine direction of x and y increments
    stepx = (sdx < 0) ? -1 : 1;
    stepy = (sdy < 0) ? -1 : 1; 

    // initial error
    se    = (asdx > asdy) ? 2 * asdy - asdx : 2 * asdx - asdy;

    // error increment for straight (einc1) and diagonal (einc2) step
    einc1 = (asdx > asdy) ? (asdy - asdx) : (asdx - asdy);
    einc2 = (asdx > asdy) ?  asdy         :  asdx; 

    // increment in x direction for straight and diagonal steps
    xinc1 = (asdx > asdy) ? stepx : stepx;
    xinc2 = (asdx > asdy) ? stepx : 0; 

    // increment in y direction for straight and diagonal step
    yinc1 = (asdx > asdy) ? stepy : stepy;
    yinc2 = (asdx > asdy) ? 0     : stepy;

    // initialize registers
    x    = x1_in;  y    = y1_in; 
    e    = se;
  }

  // simple end-of-loop test
  sfg looptest {
    eol   = ((x == x2_in) & (y == y2_in));
  }

  // loop body: adjust x, y and error accumulator
  //            use error value to decide straight or diagonal step
  sfg loop {
    x     = (e >= 0) ? x + xinc1 : x + xinc2;
    y     = (e >= 0) ? y + yinc1 : y + yinc2;
    e     = (e >= 0) ? e + einc1 : e + einc2;
    $display($hex, "Cycle: ", $cycle, " Plot point (", x, ",", y, ") ");
  }
}

// controller for bresenham algorithm
// initializes, draws one line and then waits in state s3
fsm f_bresen(bresen) {
  initial s0;
  state s1, s2, s3;
   @s0 (init)                         -> s1;
  @s1 (loop, looptest)               -> s2;
  @s2 if (eol) then (init)           -> s3;
               else (loop, looptest) -> s2;
  @s3 (init) -> s3;
} 

// testbench
dp test_bresen(out x1, y1, x2, y2 : tc(12)) {
  sig sx : tc(12);
  always {
    x1 = 5; x2 = 18; y1 = 2; y2 = 8;
  }    
} 

dp bresen_sys {
  sig x1, y1, x2, y2 : tc(12);
  use bresen(x1, y1, x2, y2);
  use test_bresen(x1, y1, x2, y2);
}

system S {
  bresen_sys;
}

[edit] Simulation output

> fdlsim bresen.fdl 20
Cycle: 1 Plot point (5/6,2/2) 
Cycle: 2 Plot point (6/7,2/3) 
Cycle: 3 Plot point (7/8,3/3) 
Cycle: 4 Plot point (8/9,3/4) 
Cycle: 5 Plot point (9/a,4/4) 
Cycle: 6 Plot point (a/b,4/5) 
Cycle: 7 Plot point (b/c,5/5) 
Cycle: 8 Plot point (c/d,5/6) 
Cycle: 9 Plot point (d/e,6/6) 
Cycle: 10 Plot point (e/f,6/7) 
Cycle: 11 Plot point (f/10,7/7) 
Cycle: 12 Plot point (10/11,7/8) 
Cycle: 13 Plot point (11/12,8/8) 
Cycle: 14 Plot point (12/13,8/8)