直线的dda算法

  就是最普通的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

posted on 2013-03-09 12:01  weiweishuo  阅读(672)  评论(0编辑  收藏  举报

导航