博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
计算机图形学之扫描转换直线-DDA,Bresenham,中点画线算法
阅读量:4984 次
发布时间:2019-06-12

本文共 2959 字,大约阅读时间需要 9 分钟。

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;            }        }    }}

转载于:https://www.cnblogs.com/sufferingStriver/p/9030007.html

你可能感兴趣的文章
关于ubuntu的图形界面的关闭与开启
查看>>
Java 线程控制
查看>>
模块中的特殊变量
查看>>
谈谈Delph中的类和对象2---类可以理解成一种特殊的数据结构、类型转换
查看>>
egret 新建eui组件后无法读取组件内元素的解决办法
查看>>
firebug中启用控制台访问项目很卡很卡
查看>>
RabbitMQ消息队列(六)-消息任务分发与消息ACK确认机制(.Net Core版)
查看>>
mysql如何修改root用户的密码
查看>>
ASP.net参数传递总结
查看>>
超简单vue轮播组件
查看>>
图形的初级变化使用View
查看>>
Codeforces Round #400 E. The Holmes Children
查看>>
hdu 1759 Matrix Revolution(矩阵转BFS)
查看>>
LintCode-88.最近公共祖先
查看>>
WCF
查看>>
861. Score After Flipping Matrix
查看>>
青蛙的约会(扩展欧几里德)
查看>>
380. Insert Delete GetRandom O(1)
查看>>
6w5:第六周程序填空题2
查看>>
多线程——几中常用的线程池
查看>>