三种直线扫描转换算法简单比较(0<k<1)
数值微分法(DDA):
代码实现:
void DDALine(int x0, int y0, int x1, int y1, int color) {
int x;
float dx, dy, y, k;
dx = x1 - x0, dy = y1 - y0;
k = dy / dx;//求k
y = y0;
for (x = x0; x < x1; x++) {
putpixel(x, (int)(y + 0.5), color);
y = y + k;
}
}
中点画线法:
代码实现:
void MidPointLine(int x0, int y0, int x1, int y1, int color) {
int a, b, d1, d2, d, x, y;
a = y0 - y1, b = x1 - x0, d = 2 * a + b;
d1 = 2 * a, d2 = 2 * (a + b);
x = x0, y = y0;
putpixel(x, y, color);
while (x < x1) {
if (d < 0) {
x++, y++, d += d2;
}else {
x++, d += d1;
}
putpixel(x, y, color);
}
}
Bresenham算法:
代码实现:
void BresenhamLine(int x0, int y0, int x1, int y1, int color) {
int x, y;
float dx, dy;
float k, e;
dx = x1 - x0;
dy = y1 - y0;
k = dy / dx;
e = -0.5, x = x0, y = y0;
for (int i = 0; i < dx; i++) {
putpixel(x,y,color);
x++, e = e + k;
if (e >= 0) {
y++;
e = e - 1;
}
}
}
三种算法比较
时间花费:
测试代码:(测试说明:连续画500条线)
#include<graphics.h> #include<conio.h> #include<iostream> #include<time.h> #include<stdlib.h> void main() { initgraph(900, 900);//创建窗口 setbkcolor(GREEN); clock_t startTime, endTime;//开始时间 startTime = clock(); int x = 200, y = 100;//初始点 for (int i = 0; i < 500; i++) { DDALine(0, 0, x++, y++, RED); //MidPointLine(0, 0, x++, y++, RED); //BresenhamLine(0, 0, x++, y++, RED); } endTime = clock(); cout << "DDA running time:" << endTime - startTime << endl;//结束时间 _getch(); closegraph(); }
结果:
结果三种算法时间分别为:
DDA 中点画线 Bresenham 时间(clock_t) 438 438 435 可知三种算法在时间花费上十分接近
与理想直线误差:
通过测试实际点与理论点的差距来判断:
测试代码:
float result2 = DDALine(0, 763, 2804, 1804, RED, 0); float result3 = MidPointLine(0, 763, 2804, 1804, RED, 0); float result4 = BresenhamLine(0, 763, 2804, 1804, RED, 0); cout << "DDA 误差为:" << result2<< endl; cout << "MidPoint 误差为:" << result3 << endl; cout << "Bresenham 误差为:" << result4 << endl; //计算与理想点差距 //DDA error += absf((int)(y + 0.5) - ((y1 - k * x1) + k * x)); error/(x1 - x0); //MidPoint和Bresenham error += absf(y - ((y1 - k * x1) + k * x)); error/(x1 - x0);
结果:
结果解释:
DDA算法与MidPoint和Bresenham两个的画直线方法思想不同,
DDA是y每次递增k,并加上0.5向下取整
而MidPoint和Bresenham算法是判断右边点和右上点哪一个更为接近理想点,所以最后效果两者是一样的,故误差也一样。
DDA的误差之所以大一些,是因为对于下一个要画的点,它并不是与理想点比较,而是在上一个点的基础上选择下一个点,而只有第一个点是理想点,所以随着点数的增大,误差越来越大。
对DDA算法所以随着点数的增大,误差越来越大的验证:
验证代码:
for (int i = 1; i <= 30; i++) { float result = DDALine(0, 763+i*200, 3804+i*200, 1804+i*200, RED, 0); cout << "第" << i << "次结果 "; cout << "DDA 误差为:" << result << endl; }
结果:
整体上误差是越来越大。
再看一下其他两种算法:
代码:
for (int i = 1; i <= 30; i++) { float result1 = MidPointLine(0, 763+i*200, 3804+i*200, 1804+i*200, RED, 0); float result2 = BresenhamLine(0, 763 + i * 200, 3804 + i * 200, 1804 + i * 200, RED, 0); cout << "第" << i << "次结果 "; cout << "MidPoint 误差为:" << result1 << " "; cout << "Bresenham 误差为:" << result1 << endl; }
结果:
基本趋近于0.25
比较结论:
三种算法时间花费上基本一致,但其中DDA不利于硬件实现。
在误差分析上,DDA随着点数增大,有误差越来越大的趋势,而MidPoint和Bresenham平均误差为0.25,且不会随点数增大而增大。