• 直线的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
  • 相关阅读:
    js问题记录
    css问题记录
    vscode配置java+gradle开发环境
    js插件
    nginx笔记
    vue刷新当前路由
    koa踩坑记录
    react踩坑笔记
    ts踩坑笔记
    vue源码阅读笔记
  • 原文地址:https://www.cnblogs.com/weiweishuo/p/2951425.html
Copyright © 2020-2023  润新知