2

Consider this snippet from Rosetta Code (in the C language):

void line(int x0, int y0, int x1, int y1) {

  int dx = abs(x1-x0), sx = x0<x1 ? 1 : -1;
  int dy = abs(y1-y0), sy = y0<y1 ? 1 : -1; 
  int err = (dx>dy ? dx : -dy)/2, e2;

  for(;;){
    setPixel(x0,y0);
    if (x0==x1 && y0==y1) break;
    e2 = err;
    if (e2 >-dx) { err -= dy; x0 += sx; }
    if (e2 < dy) { err += dx; y0 += sy; }
  }
}

I understand how the Bresenham algorithm works when X is the driving axis. In that case, we just keep track of the y error and when we increment x, we increment the y error proportionally. If it goes above a certain threshold, we also increase y and update the error accordingly. Using some simple algebraic changes, the whole can be done in integer arithmetic

But I just can't make heads or tails of this particular code. How can one variable track two errors at the same time?

Marco Merlini
  • 875
  • 7
  • 29
  • I think this may just be a fancy way to avoid flipping the coordinate system depending on the octant, as is often done with the basic algorithm, according to https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm#All_cases – גלעד ברקן Nov 25 '17 at 14:00
  • I suspect this algorithm is quite different. For example, in the method outlined on the Wikipedia page, there is only one threshold on the error value, whereas in this code there are two thresholds. The error variable could be updated twice in one iteration – Marco Merlini Nov 26 '17 at 06:11
  • I wonder if this might help: https://stackoverflow.com/questions/32251437/please-explain-this-bresenham-line-drawing-code-for-me – גלעד ברקן Nov 26 '17 at 21:56
  • Thank you for your research. I read that post closely, however I still suspect the rosetta code version (in my original question) is still quite different. This is for the same reasons as in my previous comment. – Marco Merlini Nov 27 '17 at 01:10

1 Answers1

0

I am not sure this is the right way to clarify your problem.let's start form there.

The code can solve problems with different direction by deciding sx and sy first. Another convenient point it brings out is that it can draw that four kinds of slope(k) image1-1: different slope in coordinate system

like 1-1 shows the other 6 blue lines can project on the k>1 and 0<=k<=1 bold blue lines. so in this case, we only need to deal with k>1 and 0<=k<=1 case.

Now Let's see the formula about different slope(k) value. image1-2: formula about different slope(k) value

  • 1 .

When 0<=k<=1 which is dx>dy, we choose err = dx/2

e2 < dy
e2-dy < 0

  (e2 - dy)/dx
= e2/dx - dy/dx    (∵e2 = dx/2
= (dx/2)/dx - dy/dx
= 1/2 - k
[follow the image1-2 can know that it is exactly the initial value of error term: 0.5 - k]

What about e2 >-dx in this case? You can draw a coordinate system to simulate the process. For example : (0,0)-->(6,2) . The err = 3 in the beginning. The distance between point (3,0)(the pos of e2 in x coordinate)to point(-3,0)(the pos of -dx in x coordinate) is longer than the distance between point(0,3)(the pos of e2 in y coordinate) to (0,2)(the pos of dy in y coordinate)

this could mean, while err -= dy let err descrease each time, in a not precise way to put this : e2 hits the boundary in y coordinate(e2 < dy) faster than (e2 <= -dx), so when err nearly or already hit the boundary in x coordinate, you go into the if case(e2 < dy) it let err increase dx. save for next loop.

// inside if(e2 > -dx)
err -= dy;
err = err - dy;
err/dx = err/dx - dy/dx;
err/dx = err/dx - k;
//it is exactly: di+1 = di - k

//inside if(e2 < dy)
err += dx;
err/dx = err/dx + dx/dx;
//it is exactly: di+1 = di + 1

so each time in for loop you go into the first if case, and when e2 < dy you go into the second if-case makes it di+1 = di -k + 1 and move your y.

  • 2.

When k>1 which is dy > dx, we choose err = -dy/2

e2 > -dx
e2+dx > 0

  (e2 + dx)/dx
= e2/dx + dx/dx    (∵e2 = -dy/2
= (-dy/2)/dx - dx/dx
= -k/2 + 1
[follow the image1-2 can know that it is exactly the initial value of error term: 1 - 0.5k]

The rest is like the former one with 0<=k<=1, except we going into the second if-case each time, and decide whether we will go to the first if case to move our x.