用OPENGL图形接口实现三种画直线算法,并用鼠标在屏幕上点击画线。
数值微分法-DDA
给定两点,算出直线的斜率K,根据步长,x每变化1步,y增加k,判断y的大小与下一个点的距离远近,取相应的像素点。根据K大小不同,选取不同的变化方向。
void DDALine(Point p1,Point p2){
glBegin(GL_POINTS);
float dx, dy, y, k,x;
dx = p1.x - p2.x, dy = p1.y - p2.y;
k = dy / dx;
if (k >= -1 && k <= 1){
if (p1.x > p2.x)swapPoint(p1, p2);
y = p1.y;
for (x = p1.x; x <= p2.x; x++)
{
glVertex2d(x, int(y + 0.5));
y = y + k;
}
}
else{
if (p1.y > p2.y)swapPoint(p1, p2);
x = p1.x;
for (y = p1.y; y <= p2.y; y++)
{
glVertex2d(x + 0.5, y);
x += 1 / k;
}
}
glEnd();
glFlush();
}
中点画线法
根据直线的函数f(x,y) = a*x + b*y + c= 0判断。
将(x+1,y+0.5)带入函数去计算:
- 如果大于0则该点在直线上方,取(x+1,y)为下一个点,再取(x+2,y+0.5)进去判断。
- 如果小于0则该点在直线下方,取(x+1,y+1)为下一个点,再取(x+2,y+1.5)进去判断。
将其改写为增量表达式,其他情况类似分析,实现代码如下:
void midPoint(Point p1, Point p2){
glBegin(GL_POINTS);
if (p1.x > p2.x) swapPoint(p1, p2);
int a, b, c, d1, d2, d, x, y;
a = p1.y - p2.y, b = p2.x - p1.x;
x = p1.x, y = p1.y;
glVertex2d(x, y);
if (a*b > 0){
if (a / b < 1){
d = 2 * a - b;
d1 = 2 * a, d2 = 2 * (a - b);
while (x < p2.x)
{
if (d > 0)
{
x++, y--;
d += d2;
}
else
x++, d += d1;
glVertex2d(x, y);
}
}
if (a / b >= 1){
d = a - 2 * b;
d1 = -2 * b, d2 = 2 * (a - b);
while (y > p2.y)
{
if (d < 0)
{
x++, y--;
d += d2;
}
else
y--, d += d1;
glVertex2d(x, y);
}
}
}
else if (a*b <= 0) {
if (a / b > -1){
d = 2 * a + b;
d1 = 2 * a, d2 = 2 * (a + b);
while (x < p2.x)
{
if (d < 0)
{
x++, y++;
d += d2;
}
else
x++, d += d1;
glVertex2d(x, y);
}
}
if (a / b <= -1){
d = a + 2 * b;
d1 = 2 * b, d2 = 2 * (a + b);
while (y < p2.y)
{
if (d > 0)
{
x++, y++;
d += d2;
}
else
y++, d += d1;
glVertex2d(x, y);
}
}
}
glEnd();
glFlush();
}
Bresenham算法
与DDA算法不同,算出两直线的K值之后,设定一个误差项e,与k进行增量计算。由于只是用到了误差项e的符号,可以替换后免去除法和小数。
误差项e初值为-dx,e的增量为2dy,如果e>0,e = e - 2dx。
void Bresenham(Point p1, Point p2){
glBegin(GL_POINTS);
if (p1.x > p2.x) swapPoint(p1, p2);
int x, y, dx, dy, e;
dx = p2.x - p1.x;
dy = p2.y - p1.y;
x = p1.x, y = p1.y;
if (dy*dx > 0 && dy < dx){
e = -dx;
for (int i = 0; i <= dx; i++){
glVertex2d(x, y);
x++, e += 2 * dy;
if (e >= 0){ y++; e -= 2 * dx; }
}
}
else if (dy*dx > 0 && dy >= dx){
e = -dy;
for (int i = 0; i <= dy; i++){
glVertex2d(x, y);
y++, e += 2 * dx;
if (e >= 0){ x++; e -= 2 * dy; }
}
}
else if (dy*dx <= 0 && dy / dx > -1){
e = dx;
for (int i = 0; i <= dx; i++){
glVertex2d(x, y);
x++, e += 2 * dy;
if (e <= 0){ y--; e += 2 * dx; }
}
}
else if (dy*dx <= 0 && dy / dx <= -1){
e = dy;
for (int i = 0; i >= dy; i--){
glVertex2d(x, y);
y--, e += 2 * dx;
if (e >= 0){ x++; e += 2 * dy; }
}
}
glEnd();
glFlush();
}