James' answer is pretty cool, but as he commented, it skews the line a bit. Another simple modification of the original Bresenham draws a line without diagonal steps that is closer to the "real" line.
This is an implementation of the original Bresenham algorithm:
public void line(int x0, int y0, int x1, int y1, int value) {
int xDist = Math.abs(x1 - x0);
int yDist = -Math.abs(y1 - y0);
int xStep = (x0 < x1 ? +1 : -1);
int yStep = (y0 < y1 ? +1 : -1);
int error = xDist + yDist;
plot(x0, y0, value);
while (x0 != x1 || y0 != y1) {
if (2*error > yDist) {
// horizontal step
error += yDist;
x0 += xStep;
}
if (2*error < xDist) {
// vertical step
error += xDist;
y0 += yStep;
}
plot(x0, y0, value);
}
}
The modification is simply to do either a horizontal or vertical step, not both, depending on whether the error indicator is nearer to a horizontal or vertical step:
public void lineNoDiag(int x0, int y0, int x1, int y1, int value) {
int xDist = Math.abs(x1 - x0);
int yDist = -Math.abs(y1 - y0);
int xStep = (x0 < x1 ? +1 : -1);
int yStep = (y0 < y1 ? +1 : -1);
int error = xDist + yDist;
plot(x0, y0, value);
while (x0 != x1 || y0 != y1) {
if (2*error - yDist > xDist - 2*error) {
// horizontal step
error += yDist;
x0 += xStep;
} else {
// vertical step
error += xDist;
y0 += yStep;
}
plot(x0, y0, value);
}
}
This effectively chooses the kind of step that minimizes the error, thus resulting in a line that is closer to the real line.
The code is in Java, but it should be easily portable to PHP. I haven't thoroughly tested it, but it should work just as well as the original Bresenham. It may even be a tad faster.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…