• 计算机图形学之扫描转换直线-DDA,Bresenham,中点画线算法


    1.DDA算法

    DDA(Digital Differential Analyer):数字微分法

    DDA算法思想:增量思想

    公式推导:

    效率:采用了浮点加法和浮点显示是需要取整

    代码:

    void lineDDA(int x0, int y0, int x1, int y1, int color){
        int x;
        float dy, dx, y, m;
        dx = x1 - x0;
        dy = y1 - y0;
        m = dy / dx;
        y = y0;
        for (x = x0; x <= x1; x++){
            putpixel(x, (int)(y + 0.5), color);
            y += m;
        }
    }

    2.中点画线法

    采用了直线的一般式:Ax+By+C=0

    当k在(0,1]中时,每次在x方向上加1,y方向上加1或不变:

    当Q在M上方时,取Pu点;

    当Q在M下方时,取Pd点。

    接下来:

    然后中点画线的计算:

    di需要两个乘法和四个加法算,比DDA差的多,但是di可以用增量法求

    当d<0时

    当d>=0时

    d的初始值d0:

    中点算法计算为:

    如果将d换成2d,就只有整数运算,优于DDA算法。

    最终公式:

    代码:

    void lineMidPoint(int x0, int y0, int x1, int y1, int color){
        int x = x0, y = y0;
        int a = y0 - y1, b = x1 - x0;
        int cx = (b >= 0 ? 1 : (b = -b, -1));
        int cy = (a <= 0 ? 1 : (a = -a, -1));
    
        putpixel(x, y, color);
    
        int d, d1, d2;
        if (-a <= b)     // 斜率绝对值 <= 1  
        {
            d = 2 * a + b;
            d1 = 2 * a;
            d2 = 2 * (a + b);
            while (x != x1)
            {
                if (d < 0)
                    y += cy, d += d2;
                else
                    d += d1;
                x += cx;
                putpixel(x, y, color);
            }
        }
        else                // 斜率绝对值 > 1  
        {
            d = 2 * b + a;
            d1 = 2 * b;
            d2 = 2 * (a + b);
            while (y != y1)
            {
                if (d < 0)
                    d += d1;
                else
                    x += cx, d += d2;
                y += cy;
                putpixel(x, y, color);
            }
        }
    }

    3.Bresenham算法

    DDA使画直线每步只有一个加法。

    中点画线法使画直线每步只有一个整数加法。

    Bresenham算法提供一个更一般的算法,使适用范围增大。

    该算法的思想是通过各行、各列像素中心构造一组虚拟网格线,按照直线起点到终点的顺序,计算直线与各垂直网格线的交点,然后根据误差项的符号确定该列象素中与此交点最近的象素。

    假设每次x+1,y的递增(减)量为0或1,它取决于实际直线与最近光栅网格点的距离,这个距离的最大误差为0.5。

    误差项d的初值d 0=0,d=d+k,一旦d≥1,就把它减去1,保证d的相对性,且在0、1之间。

    然后有下面计算公式:

    怎么提升到整数算法?

    答案是让e=d-0.5

    e0=-0.5

    每循环一次:e = e+k
    if (e>0) then e = e-1

    e+k这还是一个浮点加法

    因为k=△y/△x

    因为用误差项的符号,可以用e*2*△x来替换 e:

    e0=-△x

    每循环一次:e = e+2△y
    if (e>0) then e = e-2△x

    这已经变成为整数加法

    算法步骤:

    算法步骤为:
    1.输入直线的两端点P 0(x 0,y 0)和P 1(x 1,y 1)。
    2.计算初始值△x、△y、 e=-△x、x=x 0、y=y 0。
    3.绘制点(x,y)。
    4.e更新为 e+2△y,判断e的符号。若e>0,则(x,y)更新为
    (x+1,y+1),同时将e更新为 e-2△x;否则(x,y)更新为
    (x+1,y)。
    5.当直线没有画完时,重复步骤3和4。否则结束。

    代码:

    void lineBresenham1(int x0, int y0, int x1, int y1, long color)
    {
        int dx = abs(x1 - x0);
        int dy = abs(y1 - y0);
        int x = x0;
        int y = y0;
        int stepX = 1;
        int stepY = 1;
        if (x0 > x1)  //从右向左画  
            stepX = -1;
        if (y0 > y1)
            stepY = -1;
    
        if (dx > dy)  //沿着最长的那个轴前进  
        {
            int e = dy * 2 - dx;
            for (int i = 0; i <= dx; i++)
            {
                putpixel(x, y, color);
                x += stepX;
                e += dy;
                if (e >= 0)
                {
                    y += stepY;
                    e -= dx;
                }
            }
        }
        else
        {
            int e = 2 * dx - dy;
            for (int i = 0; i <= dy; i++)
            {
                putpixel(x, y, color);
                y += stepY;
                e += dx;
                if (e >= 0)
                {
                    x += stepX;
                    e -= dy;
                }
            }
        }
    }
  • 相关阅读:
    【性能诊断】十一、性能问题综合分析(案例2,windbg、wireshark)
    SQL Server常用的性能诊断语句
    Oracle常用的性能诊断语句
    【性能诊断】五、并发场景的性能分析(windbg简介及dump抓取)
    数据库管理与开发工具推荐---DBeaver
    DM达梦数据库---执行计划查看
    DM达梦数据库索引失效的处理---强制更新统计信息
    jProfiler、jMAT等工具注意设置启动的Xmx参数
    JVM启动参数建议
    Linux环境jcmd抓取进程信息及内存dump
  • 原文地址:https://www.cnblogs.com/sufferingStriver/p/9030007.html
Copyright © 2020-2023  润新知