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

来源:互联网 发布:sql 2005 sp4 x86 编辑:程序博客网 时间:2024/04/29 15:21

前言

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

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

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;    else        steps = 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 <GL\glut.h>#include <cmath>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;    else        steps = 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算法的理解,请各路大神指教。。不喜勿喷

0 0
原创粉丝点击