void line()
{
int x1 = 10, y1 = 10, x2 = 300, y2 = 500 , x, y;
int dx, dy, //deltas
e; // decision parameter
glClear(GL_COLOR_BUFFER_BIT);
glColor3f( 1 ,0, 0);
setPixel(x1, y1); //plot first point
// difference between starting and ending points
dx = x2 - x1;
dy = y2 - y1;
e = 2 * dy - dx;
x = x1; y = y1;
for(int k = 0; k < dx - 1; ++k)
{
if(e < 0)
{
//next pixel: (x+1, y)
e = e + 2*dy;
}
else
{
//next pixel: (x+1, y+1)
e = e + 2*dy - 2*dx;
++y;
}
++x;
setPixel(x, y);
}
glFlush();
}
e = 2*dy - dx
来自哪里?为什么我们会将其增加2*dy
或2*dy - 2*dx
?
答案 0 :(得分:7)
Bresenham算法仅使用整数运算。关键思想是最小化线方程增量评估的计算。
算法非常简单。让我们从线方程
开始f(x) = y = a*x +b
(现在假设0 <= a <1)。 当我们向右移动一个像素时,我们得到:
f(x+1) = a * (x+1) + b = f(x) + a
但是a和y都不是典型行的整数。
所以我们只是介绍一个“错误”。我们总是去找对方的邻居。在这样做时,我们通过不上升来使a
出错。如果我们的误差超过半个像素(0.5),我们就会上升(因此再次将误差值减少一个像素)
float e=a;
float y=y1;
int x=x1;
while(x<=x2) {
SetPixel(x,y);
x++;
if (e > 0.5) {
y++;
e=e+a-1;
} else {
e=e+a;
}
}
(请注意,我们最初已将错误e
设置为a
而不是零,因为我们总是在绘制像素后做出决定,而我们无需检查条件在绘制第一个像素之前,因为那个像素总是完全在线上。)
现在,我们已经接近了。但是有两件事阻止我们使用整数:0.5和a
是dy/dx
。但是:我们可以通过一个任意因子来缩放误差值(和条件),而不会改变任何东西。想一想:到目前为止我们已经测量了像素的误差(因为这看起来很直观),但是这个算法可以使用任意单位来表示误差值 - 半像素,双像素,pi像素。
所以,让我们按2*dx
缩放它,以消除上面公式中的两个分数! (在某种程度上,它们的关键技巧是我们测量误差值的“单位”在算法中不是常数,而是线的函数)。
int e=2*dy;
int y=y1;
int x=x1;
while(x<=x2) {
SetPixel(x,y);
x++;
if (e > dx) {
y++;
e=e+2*dy - 2*dx;
} else {
e=e+2*dy;
}
}
现在,我们拥有我们想要的东西:只有整数。
(但有一点需要注意:从float
到int
,我们会自动将线的端点“捕捉”到整数坐标 - 具有整数端点是(和限制)的一些先决条件Bresenham算法)。
还有一个额外的技巧:条件包含一个变量。如果我们测试一个常量,理想情况下是零,那就更有效了(因为仅根据符号或零标志进行分支可以节省比较操作)。我们可以通过移动我们的错误值来实现这一目标。以与以前相同的方式,不仅可以任意选择误差值的比例,还可以选择原点。
由于我们目前正在测试e > dx
,因此将错误移至-dx
将允许我们对0
进行测试(而0
现在意味着dx
的含义之前,即0.5像素)。此移位仅影响e
的初始值,并且条件,所有增量保持与以前相同:
int e=2*dy-dx;
int y=y1;
int x=x1;
while(x<=x2) {
SetPixel(x,y);
x++;
if (e > 0) {
y++;
e=e+2*dy - 2*dx;
} else {
e=e+2*dy;
}
}
Voila,2*dy-dx
一词突然出现......;)
答案 1 :(得分:0)
术语2dy-dx是在我们在公式(2dy•xk-2dx•yk + 2dy +(2b-1))中填充xk = yk = 0之后出现的,因为对于第一个参数,我们假定线的起点位于原点,即(0,0)。 b是常数,因此被忽略。 自己尝试。