Bresenham线算法 - 决策参数来自哪里?

时间:2013-10-04 18:29:34

标签: algorithm opengl

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*dy2*dy - 2*dx

2 个答案:

答案 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和ady/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;
    }
}

现在,我们拥有我们想要的东西:只有整数。 (但有一点需要注意:从floatint,我们会自动将线的端点“捕捉”到整数坐标 - 具有整数端点是(和限制)的一些先决条件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是常数,因此被忽略。 自己尝试。