计算机图形学之扫描转换直线-DDA,Bresenham,中点画线算法
Posted sufferingStriver
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了计算机图形学之扫描转换直线-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; } } } }
以上是关于计算机图形学之扫描转换直线-DDA,Bresenham,中点画线算法的主要内容,如果未能解决你的问题,请参考以下文章