根据维基百科关于Bresenham线路算法的文章,我实现了那里描述的simplified version,我的Java实现看起来像这样:
int dx = Math.abs(x2 - x1);
int dy = Math.abs(y2 - y1);
int sx = (x1 < x2) ? 1 : -1;
int sy = (y1 < y2) ? 1 : -1;
int err = dx - dy;
while (true) {
framebuffer.setPixel(x1, y1, Vec3.one);
if (x1 == x2 && y1 == y2) {
break;
}
int e2 = 2 * err;
if (e2 > -dy) {
err = err - dy;
x1 = x1 + sx;
}
if (e2 < dx) {
err = err + dx;
y1 = y1 + sy;
}
}
现在我明白err
控制x轴上的步骤与y轴上的步骤之间的比例 - 但现在我应该记录代码正在做什么我没有清楚表达,它是什么,为什么完全 if-statements是什么,它们是怎样的,以及为什么err
以代码中所见的方式被改变。
维基百科没有指出任何更详细的解释或来源,所以我想知道:
err
究竟做了什么以及为什么dx
和dy
以完全显示的方式使用此简化版本来保持水平和垂直步骤之间的正确比例Bresenham的线算法?
答案 0 :(得分:14)
一条线有各种形式的方程式,其中最常见的是y=m*x+b
。现在,如果m=dy/dx
和c = dx*b
,则dx*y = dy*x + c
。写f(x) = dy*x - dx*y + c
,我们f(x,y) = 0
iff (x,y)
是给定行上的一个点。
如果您提前x
个单位,则f(x,y)
更改dy
;如果您提前y
个单位,f(x,y)
更改dx
。
在您的代码中,err
表示线性函数f(x,y)
的当前值,以及语句序列
err = err - dy;
x1 = x1 + sx;
和
err = err + dx;
y1 = y1 + sy;
代表推进x
或y
一个单位(sx
或sy
方向),从而对函数值产生影响。如前所述,对于线上的点,f(x,y)
为零;对于线的一侧的点是正的,对另一侧的点是负的。 if
测试确定推进x
是否会比推进y
更接近所需的行,反之亦然,或者两者兼而有之。
初始化err = dx - dy;
旨在最大限度地减少偏移误差;如果你炸掉你的绘图比例,你会看到你的计算线可能不会在具有不同初始化的所需线上居中。
答案 1 :(得分:1)
只想在jwpat的优秀答案中添加一点“为什么”的信息。
使用f(x) = dy*x - dx*y + c
公式的目的是加快计算速度。这个公式使用整数运算(更快),而传统的y = mx + b
公式使用浮点运算(更慢)。