计算机图形学——直线的三种扫描转换算法

计算机图形学是算比较抽象的一门课程吧,而且内容也比较枯燥,如果没有比较好的耐心,一时半会儿是看不见计算机图形学究竟有什么作用的,但是其中有些内容呢跟C语言有关联,比如直线的扫描转换算法。大部分时候C语言常常以控制台面板、文字、字母示人,但是计算机图形学中的小程序就常常以图形表现了。

直线的三种扫描转换算法:

  • 数值微分算法(Digital Differential Analyzer,简称DDA)
  • 中点画线法
  • Bresenham算法

注意:我使用的是VC++ 6.0,但是我们在程序中添加的graphics.h是没有包含在库当中的,所以我们要手动添加这个头文件。否则是没有办法显示图形的。大家可以在网络上搜索到这个文件的安装方式,操作很简单。


数值微分算法(DDA)

数值微分法是最基础的直线扫描转换算法,所以需要掌握。

这个算法要求先算出直线的斜率,然后从起点开始,确定最佳逼近于直线的y坐标。假设起点的坐标为整数,直线方程为y=kx+b,k的取值在0到1之间,x每递增1,y相应地递增k

“数值微分算法的本质,是用数值方法解微分方程,通过同时对x和y各增加一个小增量,计算下一步的x、y值。在一个迭代算法中,如果每一步的x、y值是用前一步的值加上一个增量来获得的,那么,这种算法就称为增量算法。因此,DDA算法是一个增量算法。“

说白了,我们计算每一个点不是代入坐标值通过直线方程”硬算“的,而是我们明确了直线有一个规律x每递增1,y相应地递增k,每次计算点的坐标,我只需要x+1,y+k就行了,避免了乘除,而只有加减。

但是这里有一个问题,实际的直线并不是和像素点完全重合的,只能取离实际点最近的那个像素点。这里就有了一个判别的过程,但是下面的程序我认为很巧妙的一个地方就是它利用了C/C++的一个特点,如代码行(1),C/C++对小数的取整不是小学学习的四舍五入,而是直接把小数部分全部去掉,无论是0.1还是0.9。利用这个特性,在实际点的y坐标上加上0.5,然后再取整,就能够实现”四舍五入“。

/***************************************************
 *Authors       :Philip
 *Email         :cf20090901@outlook.com
 *Last modified :2016-11-10 18:34
 *Filename      :DDALine.cpp
 *Desciption    :用数值微分法画一条直线
 *               
 *               
 ***************************************************
*/

#include<iostream.h>
#include<graphics.h>
#include<conio.h>
//using namespace std;
void DDALine(int x0,int y0,int x1,int y1,int color)
{
    int x;
    float dx,dy,y,k;
    dx=x1-x0;
    dy=y1-y0;
    k=dy/dx;
    y=y0;
    for(x=x0;x<=x1;x++)
    {
        putpixel(x,int(y+0.5),color);//(1)
        y=y+k;
    }
}
//===================================
void main()
{
    initgraph(400,400);
    DDALine(0,0,400,400,GREEN);
    getch();
    closegraph();
    cout<<"OK"<<endl;
}

中点画线法

所有的算法最关键的部分就是怎么取离直线最近的点,实际上就是一个判断的过程。

中点画线算法关键在于它的名字——中点。上下两个像素点连线的中心就是中点,直线在经过像素点的连线的时候形成的交点就是实际的点,只需要判断这个实际点在”中点“的上方还是下方,如果在上方那么取上面的像素点,如果在下方就取下方的像素点。

/***************************************************
 *Authors       :Philip
 *Email         :cf20090901@outlook.com
 *Last modified :2016-11-10 19:56
 *Filename      :DDALine.cpp
 *Desciption    :用中点画线法画一条直线
 *               
 *               
 ***************************************************
*/

#include<iostream.h>
#include<graphics.h>
#include<conio.h>
void MindpointLine(int x0,int y0,int x1,int y1,int color)
{
    int a,b,d1,d2,d,x,y;
    b=x1-x0;
    a=y0-y1;
    d=2*a+b;
    d1=2*a;
    d2=2*(a+b);
    x=x0;
    y=y0;
    putpixel(x,y,color);
    while(x<x1)
    {
        if(d<0)
        {x++,y++,d+=d2;}
        else
        {x++,d+=d1;}
        putpixel(x,y,color);
    }
}
//===================================
void main()
{
    initgraph(800,600);
    MindpointLine(10,50,400,400,RED);
    getch();
    closegraph();
}

Bresenham算法

Bresenham算法”其实“比较像数值微分法,也是增量算法,但是相对来说更利于硬件实现。

这里引入了一个误差项,判断误差项的正负就可以判断如何取点。

/***************************************************
 *Authors       :Philip
 *Email         :cf20090901@outlook.com
 *Last modified :2016-11-10 14:09
 *Filename      :IntegerBresenhamLine.cpp
 *Desciption    :用Bresenham算法画一条直线
 *               
 *               
 ***************************************************
*/

#include<iostream.h>
#include<graphics.h>
#include<conio.h>
void IntegerBresenhamline(int x0,int y0,int x1,int y1,int color)
{
    int x,y,dx,dy,e,i;
    dx=x1-x0;
    dy=y1-y0;
    e=-dx;
    x=x0;
    y=y0;
    for(i=0;i<=dx;i++)
    {
        putpixel(x,y,color);
        x++;
        e=e+2*dy;
        if(e>=0){y++;e=e-2*dx;}
    }
}
//===================================
void main()
{
    initgraph(800,600);
    IntegerBresenhamline(56,56,400,100,RED);
    getch();
    closegraph();
}

经验不足,水平有限,有错误或者可以优化的地方欢迎大家指证。谢谢。

  • 8
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值