【Computer Graphics】1.直线生成算法(DDA 算法)

前言

本人是计算机图形学的初学者,虽然说大学上了计算机图形学的课,但是只是半斤八两的程度,有的地方没懂也就算了,不会去思考,现在重新学一遍,有写的不好的地方,希望各路大神指教,本人一定改正。。

好了,让我们先来了解一些概念

1.图形的扫描转换

图形的扫描转换:确定一个像素集合,用于显示一个图形的过程

(ps:个人理解是图形变成一个个的像素点)

2.图形显示前需要做的工作:扫描转换 +裁剪
裁剪也就是将不在显示范围的部分删除
目前有两种方法:

①先裁剪,再扫描转换:最常用的方法,节约计算时间
②先扫描转换,再裁剪:这样比较耗时间,毕竟把不是范围内的也进行了扫描转换计算。。但是算法简单

3.直线的扫描转换:确定最佳逼近于该直线的一组像素,并且按扫描线顺序,对这些像素进行写操作

常用的直线扫描转换有:
① 数值微分法(DDA)
② 中点画线算法
③ Bresenham算法

本篇着重讲 数值微分法(DDA)

众所周知,两点确定一条直线,我们假设这两点的坐标都为整数P0(x0,y0) P1(x1,y1)

那么过这两点的直线的表达式可以为: y =kx+b
斜率 k = (y1 - y0)/(x1 - x0)
令 x = x0; x → x1变化
x =x+stepx;
通过y = kx+b计算y的值;
∴ 逼近直线的点为(x,round(y)) round在这的作用是四舍五入

我们设当前已经确定的点的坐标为(Xi,Yi),下一个点的坐标为(Xi+1,Yi+1) ,i和i+1为下标
那么由 y = kx+b得 Yi+1 = kXi+1 +b;

我们当前的点(Xi,Yi)已经在直线上了,所以Yi = kXi+b,所以我们可以转化:
Yi+1 = kXi+1 +b = k(Xi+△x)+b = kXi +k△x+b = Yi+k△x

当△x = 1 时,Yi+1 = Yi+k,即x每递增1,y递增k,即直线的斜率

上述过程只用于 |k| ≤ 1 的过程,x每增加1,y最多增加1;

当 |k| >1时,x,y互相交换。。。也就是将x = x+steps 换成y =y+ steps ,即△y = 1, 那么 x的增量为 1/k

这个算法可以概括为:

输入线段两个端点的像素位置,端点位置间的水平和垂直差值赋值给dx和dy。绝对值大的参数决定参数steps的值,从像素位置(x0,y0)开始,确定沿线段生成下一个像素位置的每一步所需要的偏移量,并玄幻上述过程的steps次。假如dx的绝对值大于dy的绝对值,且x0小于x1,那么x和y方向的增量值为1和m。加入x方向的变化较大,但x0大于x1,那么就采用减量 -1 和-k来生成线段上的每个点。。。在其他情况下,y方向使用单位增量(或减量),x方向使用1/k的增量(或减量)

ps:个人觉得有点像微积分的思想,就是x0→x1(或者y0→y1)微分,然后画点,成就一条直线

算法的具体内容

void DDALine(int x0,int y0,int x1,int y1)
{int dx = x1 - x0;int dy = y1 - y0;int steps, k;float xIcrement, yIcrement;float x = x0, y = y0;if (fabs(dx) > fabs(dy))steps = dx;elsesteps = dy;xIcrement = float(dx) / steps;yIcrement = float(dy) / steps;SetPixel(int(x+0.5), int(y+0.5));           for (k = 0; k < steps; k++){x += xIcrement;y += yIcrement;     SetPixel(int(x + 0.5), int(y + 0.5));       }   
}

稍稍解释一下:首先我们传入两个点,起始点(x0,y0)和结束点(x1,y1),判断dx和dy的绝对值,哪个大决定steps的值,xIcrement, yIcrement就是在决定了steps的情况下,每移动一次,x和y的增量,k表示次数,steps表示总共要执行的次数,SetPixel()表示画点,int(x + 0.5)表示四舍五入。。。

由算法可以看出DDA画直线的缺点:y和x必须是float,而且每计算一次就要进行四舍五入,在硬件上不利于实现


实战效果:
这里写图片描述

这是我在OpenGL的环境下画的,下面贴出源代码:

#include 
#include void Init()
{glClearColor(0.0,0.0,0.0,0.0);glMatrixMode(GL_PROJECTION);gluOrtho2D(-100, 100, -100, 100);
}void DDALine()
{GLint x0 = -50.0f, y0 = -50.0f, x1 = 50.0f, y1 = 50.0f;glClear(GL_COLOR_BUFFER_BIT);glColor3f(1.0f, 0.0f, 0.0f);GLint dx = x1 - x0;GLint dy = y1 - y0;GLint steps, k;GLfloat xIcrement, yIcrement;GLfloat x = x0, y = y0;if (fabs(dx) > fabs(dy))steps = dx;elsesteps = dy;xIcrement = float(dx) / steps;yIcrement = float(dy) / steps;glBegin(GL_POINTS);glVertex2i(int(x+0.5), int(y+0.5));     glEnd();for (k = 0; k < steps; k++){x += xIcrement;y += yIcrement;glBegin(GL_POINTS);glVertex2i(int(x + 0.5), int(y + 0.5));glEnd();}glFlush();
}void main(int argc, char** argv)
{GLint x0, y0, x1, y1;glutInit(&argc, argv);glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);glutInitWindowPosition(50, 100);glutInitWindowSize(500, 500);glutCreateWindow("DDALine");Init();glutDisplayFunc(DDALine);glutMainLoop();}

本篇内容到此为止,主要写了一些本人DDA算法的理解,请各路大神指教。。不喜勿喷


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部