Faster Bresenham's Algorithm
Bresenham’s Algorithm Revisit
The Bresenham’s algorithm is the most representative method to rasterize line segments, which uses only integer addition and subtraction. For convenience, assume that each point is the center of the pixel, not the lower left corner of the pixel. In other words, each element of the two endpoints and of a line segment is an integer, and the line segment connects the centers of these two pixels. Also, only consider lines where and and the slope is between and . This is because it can be easily applied to other cases.
The line defined by two points and can be expressed as follows. Let and .
Here, when the slope value, which is a rational number, is multiplied by on both sides to change it to an integer and then rearranged, it is expressed as the following implicit function.
The advantage of an implicit function is that when a point is substituted into , if the value is 0, it means that the point is on the line. Also, if the value is positive, it means that it is below the line, and if it is negative, it means that it is above the line.
As shown in the figure above, say that is currently selected. Since only lines with slopes between 0 and 1 are considered, the next pixel to be selected is either E or NE. In order to decide which pixel to select, it would be reasonable to consider whether the line passes above or below the point M, which is the midpoint between N and NE. The figure above shows a situation in which NE must be selected.
More Specifically, the point M can be put into as follows.
Here, is called a decision variable. If its value is positive, pixel NE must be selected, and if it is negative, pixel E must be selected. If it is 0, either pixel can be selected. However, computing for the next selection at each iteration is unnecessary. This approach is the core of the Bresenham’s algorithm, which is to derive the relationship with the next decision variable.
First, consider the case where E is currently selected. That is, is selected, so the next decision variable must be calculated for the point .
Second, if NE is selected, can be calculated in a similar way as follows.
Therefore, if and are defined in advance, can be obtained from one of them by simply performing integer addition.
The initial decision variable is also needed, which can be computed explicitly via the point , but this computation requires an integer division operation.
Note that because the point is on the line. A very simple workaround to avoid the division operation is to multiply both sides of by . As a result, the decision variables are updated as follows:
void drawLine(int x0, int y0, int x1, int y1)
{
int y = y0;
const int dx = x1 - x0;
const int dy = y1 - y0;
const int c_e = dy + dy;
int d = c_e - dx;
const int c_ne = d - dx;
for (int x = x0; x < x1; ++x) {
setPixel( x, y );
if (d <= 0) d += c_e;
else {
y++;
d += c_ne;
}
}
}
Double Speed Bresenham’s Algorithm
While Bresenham’s algorithm selects one next pixel, this can be improved in order to select the next two pixels. While Bresenham’s algorithm selects one next pixel, this can be improved in order to select the next two pixels. To obtain this efficiency, more cases should be considered than the original. That is, this time, only consider lines where the slope is between and . And the rest cases can be easily applied from this case.
As previous, is currently selected pixel. Since the slope is between and , the decisions that can be made are all 3 as above. As such, the two decision variables are needed due to considering the next two pixels. More specifically, the point M1 and the point M2 should be put into .
Note that the practically required decision variable is only one, , to make two decisions. With this, in order to derive the relationship with the next decision variable, the following cases should be considered.
First, consider the case where EE is currently selected. That is, is selected, so the next decision variable is from the point .
Second, if NEE is selected, can be calculated in a similar way as follows.
So, the predefined and can be used this time. Besides, the initial decision variable can also be obtained via the point .
If multiplying both sides of by to avoid the division operation, the decision variables are finally updated as follows:
void drawLine(int x0, int y0, int x1, int y1)
{
int y = y0;
const int dx = x1 - x0;
const int dy = y1 - y0;
const int c = dy + dy;
const int c_ee = c + c;
int d = c_ee - dx;
const int c_nee = d - dx;
const int end = x0 + ((dx >> 1) << 1);
for (int x = x0; x < end; x += 2) {
setPixel( x, y );
if (d <= 0) {
setPixel( x + 1, y );
d += c_ee;
}
else {
if (d <= c) setPixel( x + 1, y );
else setPixel( x + 1, y + 1 );
y++;
d += c_nee;
}
}
if (end != x1) setPixel( end, y );
}
Symmetry
Since lines are symmetric about the center, it is possible to make this algorithm more faster by plotting from both ends simultaneously. However, while the above algorithms draw lines in the exclusive range, the code below uses symmetry in the inclusive range. Besides, this algorithm may not exactly match the results from the above ones because of rounding. Although this algorithm considers only slopes between and , this algorithm can be updated in a similar manner for any slopes outside this range.
void drawLineSymmetry(int x0, int y0, int x1, int y1)
{
const int dx = x1 - x0;
const int dy = y1 - y0;
const int c = dy + dy;
const int c_ee = c + c;
int d = c_ee - dx;
const int c_nee = d - dx;
const int pairs = (dx + 1) >> 2;
for (int i = 0; i < pairs; ++i) {
setPixel( x0++, y0 );
setPixel( x1--, y1 );
if (d <= 0) {
setPixel( x0++, y0 );
setPixel( x1--, y1 );
d += c_ee;
}
else {
if (d <= c) {
setPixel( x0++, y0++ );
setPixel( x1--, y1-- );
}
else {
setPixel( x0++, ++y0 );
setPixel( x1--, --y1 );
}
d += c_nee;
}
}
const int remaining = dx + 1 - (pairs << 2);
if (remaining > 0) setPixel( x0++, y0 );
if (remaining > 1) setPixel( x1, y1 );
if (remaining > 2) {
if (d <= c) setPixel( x0, y0 );
else setPixel( x0, ++y0 );
}
}
References
[1] 3D Graphics Programming Using OpenGL: Introduction
[2] Andrew S. Glassner (Ed.). 1990. Graphics gems. Academic Press Professional, Inc., USA.