就是最普通的dda算法,没有任何拓展:
View Code
1 void drawLine_dda_float(int x0,int y0,int x1,int y1){ 2 //1000*100次,66ms 3 int x0_x1=x1-x0; 4 int y0_y1=y1-y0; 5 if((x0_x1>0?x0_x1:-x0_x1)>(y0_y1>0?y0_y1:-y0_y1)){ 6 //直线趋于水平,故沿x轴逐点描画 7 //保证x0_x1指向x轴正方向 8 if(x0_x1<0){ 9 int temp=x0; 10 x0=x1; 11 x1=temp; 12 temp=y0; 13 y0=y1; 14 y1=temp; 15 } 16 float k=(float)y0_y1/(float)x0_x1;//BUG:x0=x1时会dive-error,但y0=y1是可以的,此时k=0,一条横线。 17 float y=y0; 18 for(int x=x0;x<=x1;x++){ 19 *(pt_memBuffer+(x<<2)+(int)(y+0.5)*5504)=0xff;//性能瓶颈在这儿 20 y+=k; 21 } 22 } 23 else{ 24 //直线趋于竖直,故沿y轴逐点描画 25 //确保y0_y1沿y正方向 26 if(y0_y1<0){ 27 int temp=x0; 28 x0=x1; 29 x1=temp; 30 temp=y0; 31 y0=y1; 32 y1=temp; 33 } 34 float dxdy=(float)x0_x1/(float)y0_y1;//BUG:y0=y1时dive-error,但x0=x1是允许的,此时dxdy=0,一条竖线 35 float x=x0; 36 for(int y=y0;y<=y1;y++){ 37 *(pt_memBuffer+((int)(x+0.5)<<2)+y*5504)=0xff;//pt_memBuffer是全局变量,这个直线算法只是绘制环境里的函数。 38 x+=dxdy; 39 } 40 } 41 }
我测过int->float的开销,大概5千万次耗时40ms(很粗略),上面代码for循环中的(int)转换是算法瓶颈,真正说浮点数的运算速度已经与整型差不太多了。
下面用定点数来替代浮点数,这样fixed->int只是移位操作,快的多。代码里用到的定点数是16.16格式,具体的宏贴在文章末尾。
View Code
void drawLine_dda_fixed(int x0,int y0,int x1,int y1){ int x0_x1=x1-x0; int y0_y1=y1-y0; if((x0_x1>0?x0_x1:-x0_x1)>(y0_y1>0?y0_y1:-y0_y1)){ //直线趋于水平,故沿x轴逐点描画 //保证x0_x1指向x轴正方向 if(x0_x1<0){ int temp=x0; x0=x1; x1=temp; temp=y0; y0=y1; y1=temp; } fixed k=(INT_TO_FIXED(y1)-INT_TO_FIXED(y0))/(x1-x0);//使用定点数来代替浮点数,是为了在下面的for循环里避开类型转换 fixed y=INT_TO_FIXED(y0); for(int x=x0;x<=x1;x++){ //32678就相当于定点数0.5 *(pt_memBuffer+(x<<2)+(FIXED_TO_INT(y+32768)*5504))=0xff; y+=k; } } else{ //直线趋于竖直,故沿y轴逐点描画 //确保y0_y1沿y正方向 if(y0_y1<0){ int temp=x0; x0=x1; x1=temp; temp=y0; y0=y1; y1=temp; } fixed dxdy=(INT_TO_FIXED(x1)-INT_TO_FIXED(x0))/(y1-y0);//使用顶点数来代替浮点数,是为了在下面的for循环里避开类型转换 fixed x=INT_TO_FIXED(x0); for(int y=y0;y<=y1;y++){ *(pt_memBuffer+(FIXED_TO_INT(x+32768)<<2)+y*5504)=0xff; x+=dxdy; } } }
同样是执行1000*100次,耗时33ms。看来类型转换确实很贵。
我想类型转换开销才是浮点数不适合直线算法的原因。
fixed_digit.h
1 #define INT_TO_FIXED(x) (x<<16) 2 //just ignore 0~15bit when convert FIXED to INT 3 #define FIXED_TO_INT(x) (x>>16) 4 // 5 #define FIXED_PLUS_INT(x_f,x_i) (x_f+(x_i<<16)) 6 #define FIXED_SUB_INT(x_f,x_i) (x_f-(x_i<<16)) 7 //avoid using mult,be careful of large-mult's causing overflowing,and be aware of precision-lost 8 #define FIXED_MULT_FIXED(x1_f,x2_f) ((x1_f>>8)*(x2_f>>8)) 9 //divide 懒得去想了,似乎很麻烦,除数的位数似乎不能为16位 10 #endif