`

【计算机图形学】基本图形元素:直线的生成算法

 
阅读更多

08年9月入学,12年7月毕业,结束了我在软件学院愉快丰富的大学生活。此系列是对四年专业课程学习的回顾,索引参见:http://blog.csdn.net/xiaowei_cqu/article/details/7747205

 

直线的DDA算法


【算法介绍】

设直线之起点为(x1,y1),终点为(x2,y2),则斜率m为:

直线中的每一点坐标都可以由前一点坐标变化一个增量(Dx, Dy)而得到,即表示为递归式:

并有关系:Dy = m • Dx。递归式的初值为直线的起点(x1, y1),这样,就可以用加法来生成一条直线。具体方法是:

直线方向的8个象限

按照直线从(x1,y1)到(x2,y2)的方向不同,分为8个象限。对于方向在第1a象限内的直线而言,D x=1,D y=m。对于方向在第1b象限内的直线而言,取值Dy=1,Dx=1/m。各象限中直线生成时Dx, Dy的取值列在下表之中。

 

 

  • 当|dx|>|dy|时,|D x|=1, |D y|=m;否则:Dx=1/m,|Dy|=1
  • Dx, Dy的符号与dx, dy的符号相同
这两条规律可以导致程序的简化

【算法流程图】




【相关代码】

void PaintArea::drawLineDDA(QPainter &painter,int x0, int y0, int xEnd, int yEnd)
{
    int dx=xEnd-x0,dy=yEnd-y0,steps,k;
    float xIncrement,yIncrement,x=x0,y=y0;
    if(fabs(dx)>fabs(dy))  steps=fabs(dx);
    else  steps=fabs(dy);
    xIncrement=float(dx)/float(steps);
    yIncrement=float(dy)/float(steps);
    painter.drawPoint(round(x),round(y));
    for(k=0;k<steps;k++){
        x+=xIncrement;
        y+=yIncrement;
        painter.drawPoint(round(x),round(y));
    }
}


直线的Bresenham算法

这个算法由Bresenham在1965年提出。设直线从起点(x1, y1)到终点(x2, y2)。直线可表示为方程y=mx+b。其中

我们的讨论先将直线方向限于1a象限在这种情况下,当直线光栅化时,x每次都增加1个单元,即

而y的相应增加应当小于1。为了光栅化,yi+1只可能选择如下两种位置之一(如图)。

i+1的位置选择yi-1=yi 或者 yi+1=yi+1
选择的原则是看精确值y与yi及yi+1的距离d1及d2的大小而定。计算式为:

如果d1-d2>0,则yi+1=yi+1,否则yi+1=yi。因此算法的关键在于简便地求出d1-d2的符号。将上公式得
d1-d2=2y-2yi-1=2 (xi+1)-2yi+2b-1
用dx乘等式两边,并以Pi=dx(d1-d2)代入上述等式,得
Pi=2xidy-2yidx+2dy+dx(2b-1)
d1-d2是我们用以判断符号的误差。由于在1a象限,dx总大于0,所以Pi仍旧可以用作判断符号的误差。Pi-1为:
Pi+1=Pi+2dy-2dx(yi+1-yi)
误差的初值P1,可将x1, y1,和b代入式(4)中的xi, yi而得到:
P1=2dy-dx

 

Bresenham算法的优点是:

  1. 不用浮点数,只用整数;
  2. 只做整数加减法和乘2运算,而乘2运算可以用硬件移位实现。
  3. Bresenham算法速度很快,并适于用硬件实现。

 

【算法流程图】

 

【相关代码】

void PaintArea::drawLineBresenham(QPainter &painter, int x0, int y0, int xEnd, int yEnd)
{
    int x,y,dx,dy,e;
    if(fabs(x0-xEnd)>fabs(y0-yEnd)){
        dx=xEnd-x0; dy=yEnd-y0; e=-dx;
        x=x0; y=y0;
        for(int i=0;i<=dx;i++)
        {painter.drawPoint(x,y);
         x=x+1; e=e+2*dy;
         if(e>=0) {y=y+1; e=e-2*dx; }}
    }
    else if(fabs(x0-xEnd)>fabs(y0-yEnd)){
        dx=xEnd-x0; dy=yEnd-y0; e=-dx;
        x=x0; y=y0;
        for(int i=0;i<=dx;i++)
        { painter.drawPoint(x,y);
         y=y+1; e=e+2*dx;
         if(e>=0) {x=x+1; e=e-2*dy; }}
    }
}

 

中点画线法

假定直线斜率k在0~1之间,当前象素点为(xp,yp),则下一个象素点有两种可选择点(xp+1,yp)或P2(xp+1,yp+1)。若P1与P2的中点(xp+1,yp+0.5)称为M,Q为理想直线与x=xp+1垂线的交点。当M在Q的下方时,则取P2应为下一个象素点;当M在Q的上方时,则取P1为下一个象素点。这就是中点画线法的基本原理。

 

【算法流程图】

 

 

【相关代码】

void PaintArea::drawLineMiddle(QPainter &painter, int x0, int y0, int xEnd, int yEnd)
{
    int a,b,d,x,y;
    if(fabs(x0-xEnd)>fabs(y0-yEnd)){
        a=y0-yEnd; b=xEnd-x0; d=2*a+b; x=x0; y=y0;
        painter.drawPoint(x,y);
        while(x<xEnd)
        {   if(d<0) {x++;y++;d+=2*(a+b); }
            else{x++;d+=2*a; }
            painter.drawPoint(x,y);
        }
    }
    else if(fabs(x0-xEnd)>fabs(y0-yEnd) &&(x0-xEnd))<0)){
        a=y0-yEnd; b=xEnd-x0; d=2*a+b; x=x0; y=y0;
        painter.drawPoint(x,y);
        while(x>xEnd)
        {   if(d<0) {x--;y--; d-=2*(a+b); }
            else{x--;d-=2*a; }
            painter.drawPoint(x,y);
        }
    }
    else if(fabs(x0-xEnd)<fabs(y0-yEnd)&&(x0-xEnd)<0){
        a=y0-yEnd; b=xEnd-x0; d=2*a+b; x=x0; y=y0;
        painter.drawPoint(x,y);
 while(y>yEnd)
        {   if(d<0) {y++;x++;d+=2*(a+b); }
            else{y++;d+=2*a; }
            painter.drawPoint(x,y);
        }
}
else if(fabs(x0-xEnd)<fabs(y0-yEnd) &&(x0-xEnd))>0)){
        a=y0-yEnd; b=xEnd-x0; d=2*a+b; x=x0; y=y0;
        painter.drawPoint(x,y);
        while(x>xEnd)
        {   if(d<0) {x--;y--; d-=2*(a+b); }
            else{x--;d-=2*a; }
            painter.drawPoint(x,y);
        }
    }
else if(fabs(x0-xEnd)<fabs(y0-yEnd)&&(x0-xEnd)>0){
        a=y0-yEnd; b=xEnd-x0; d=2*a+b; x=x0; y=y0;
        painter.drawPoint(x,y);
 while(y>yEnd)
        {   if(d<0) {y++;x++;d+=2*(a+b); }
            else{y++;d+=2*a; }
            painter.drawPoint(x,y);
        }  
    }  
}

 

软件截图

 

这个绘图软件是用QT写的,我会另外写一篇介绍编程结构,敬请期待~

 

结果分析

  • 此次实验自己真的倾注了很大的心血。
    因为很喜欢计算机图形学,所以很想做个像模像样的东西出来,于是就下定决心借实验的机会做个简易的windows画板。也是第一次正式的使用QT开发,摸索的过程使得整个实验拖了很长时间。最终的结果还是比较令自己满意的,至少基本功能都实现了,界面也还看得过去。
  • 过于注重表面,算法上功夫不足,有些“舍本逐末”
    我是把整个软件做差不多了,才开始细细得来研究图元的基本算法(开始都是调用qt自带的绘制函数)。调试算法的过程才深刻感觉这比整个软件更花时间(可能因为整个软件并没有很复杂的架构)。由于时间有限,很多地方没有细细改进。尤其是对于k的几种情况,就生生的写了很冗余的代码,实在是丑啊。
  • 以后再继续改进。
    要改进的地方还有很多。比如算法结构重构,不要写那么冗余。然后再尝试一些填充算法自己实现,还有自己会试着做做简单的图像处理,变形拉伸什么的。
    总之,坚持动手,学以致用。

转载请注明出处:http://blog.csdn.net/xiaowei_cqu/article/details/7762419


分享到:
评论

相关推荐

    计算机图形学课件第2讲:直线及圆生成算法.pptx

    5. 直线生成算法:直线生成算法是计算机图形学中的基本算法,包括数值微分法(DDA)、中点画线算法和Bresenham画线算法。这些算法可以生成直线、圆和其他图形。 6. 中点画线算法:中点画线算法是直线生成算法的一种...

    计算机图形学 直线DDA算法

    计算机图形学 直线DDA算法计算机图形学 直线DDA算法计算机图形学 直线DDA算法计算机图形学 直线DDA算法计算机图形学 直线DDA算法计算机图形学 直线DDA算法计算机图形学 直线DDA算法计算机图形学 直线DDA算法计算机...

    计算机图形学基本图形生成算法 MATLAB实现

    计算机图形学基本图形生成算法,MATLAB编程实现,其中包括直线生成算法,圆及椭圆生成算法,图形填充,变换等各种算法

    计算机图形学课件:3 基本二维图元的生成算法.ppt

    基本二维图元的生成算法是计算机图形学中最基础的部分,它们是构成图形图像的基本元素。这些图元的生成算法可以分为两步:首先,确定图形对应的象素集合及其颜色;其次,用图形的颜色或其他属性对象素进行写操作。...

    计算机图形学 直线生成算法实现.doc

    2. 掌握几种基本的直线生成算法:DDA 算法、Bresenham 画线法、中点画线法 3. 实现直线生成的,在屏幕上任意生成一条直线 三、实现程序: 本实验使用 C 语言编写,使用 Borland Graphics Interface(BGI)库来实现...

    计算机图形学-三种直线生成算法及圆的生成算法.doc

    在计算机图形学中,直线和圆是最基本的图形元素,本文将介绍三种直线生成算法和圆的生成算法。 一、DDA 直线生成算法 DDA 直线生成算法是一种简单的直线生成算法。该算法的基本思想是通过计算直线的斜率和截距来...

    vc 计算机图形学直线生成通用算法

    vc 计算机图形学直线生成通用算法 DDA算法

    计算机图形学 直线、圆及多种填充算法

    这段时间弄了很多图形学方面的算法,如DDA画直线算法,以及MidpointLine、BresenhamLine、还有画圆的BresenhamCircle、MidpointCircle以及多种 种子填充算法,如Floodfill、ScanlineSeedfill、ET边表的 Polygonfill...

    计算机图形学 直线各种生成算法

    计算机图形学直线的各种生成算法,特别适合学习计算机图形学的初学者学习交流,很好的代码,但是还是有很大的完善空间,大家一起努力吧

    计算机图形学直线的生成算法

    在光栅显示器的荧光屏上生成一个对象,实质上是...直线的DDA算法 DDA是数字微分分析式(Digital Differential Analyzer)的缩写。设直线之起点为(x1,y1),终点为(x2,y2),则斜率m为: m = (y2-y1)/(x2-x1)=dy/dx

    计算机图形学实验报告实验一 直线生成算法

    这是图形学实验 ,大学计科选修的一门专业, 这个实验关于直线生产算法

    计算机图形学.pdf

    计算机图形学的主要研究内容包括图形硬件、图形标准、图形交互技术、光栅图形生成算法、曲线曲面造型、实体造型、真实感图形计算与显示算法,以及科学计算可视化、计算机动画、自然景物仿真、虚拟现实等。...

    直线和圆的生成算法(2006级计算机图形学课程设计报告)

    计算机图形学的实验报告包括: 直线的DDA算法 直线的Bresenham算法 直线的中点算法 圆的DDA算法 ...配套的程序为"直线和圆的生成算法(2006级计算机图形学课程设计配套程序)"内含的程序运行环境为VC下的MFC

    计算机图形学DDA算法.pdf

    在计算机图形学中,DDA算法是一种常用的直线生成算法,广泛应用于各种图形应用程序中。该算法的优点是计算速度快、精度高、易于实现,使其成为计算机图形学中的一种重要算法。 在实际应用中,DDA算法可以用于生成...

    计算机图形学--第三讲 直线与圆生成算法.pdf

    计算机图形学--第三讲 直线与圆生成算法.pdf

    计算机图形学直线和园的生成算法

    直线和圆的生成算法,直线曲线都是点的集合 点是图形中最基本的图素,直线、曲线以及其它图元都是点的集合。

    java实现计算机图形学直线和圆的绘制算法

    java实现的计算机图形学直线和圆的绘制算法,包括DDA算法,中点直线算法,Bresenham算法以及中点画圆算法,集成在一个UI中,方便直观。

    直线和圆的生成算法(2006级计算机图形学课程设计配套程序)

    2006级计算机图形学课程设计配套程序包括: 直线的DDA算法 直线的Bresenham算法 直线的中点算法 ...该程序的配套报告为"直线和圆的生成算法(2006级计算机图形学课程设计报告)"程序运行环境为VC下的MFC

    计算机图形学直线的中点生成算法的实现

    本资源是计算机图形学直线的中点生成算法的实现,里面有详细的代码。

    计算机图形学第二版课后习题答案.pdf

    计算机图形学的基本算法包括直线生成算法、圆生成算法、曲线生成算法等。这些算法的实现可以使用数学公式、递推公式和_lookup table 等方法。例如,中点Bresenham算法是计算机图形学中常用的直线生成算法,使用递推...

Global site tag (gtag.js) - Google Analytics