DDA算法和Bresenham算法

DDA算法和Bresenham算法

本文结构如下:

  • 1、DDA算法
  • 2、Bresenham算法
  • 3、代码实现核心部分


1、DDA算法

DDA算法是计算机图形学中最简单的绘制直线算法。其主要思想是由直线公式y = kx + b推导出来的。
我们已知直线段两个端点P0(x0,y0)和P1(x1,y1),就能求出 k 和 b 。

在k,b均求出的条件下,只要知道一个x值,我们就能计算出一个y值。如果x的步进为1(x每次加1,即x = x +1),那么y的步进就为k+b;同样知道一个y值也能计算出x值,此时y的步进为1,x的步进为(1-b)/k。根据计算出的x值和y值,向下取整,得到坐标(x’,y’),并在(x’,y’)处绘制直线段上的一点。

为进一步简化计算,通常可令b取0,将起点看作(0,0)。设当前点为(xi, yi)则用DDA算法求解(xi+1,yi+1)的计算公式可以概括为:

  • xi+1 = xi + xStep (1)
  • yi+1 = yi + yStep (2)

我们一般通过计算 Δx 和 Δy 来确定xStep和yStep:

  • 如果 Δx > Δy ,说明x轴的最大差值大于y轴的最大差值,x轴方向为步进的主方向,xStep = 1,yStep = k;
  • 如果 Δy> Δx,说明y轴的最大差值大于x轴的最大差值,y轴方向为步进的主方向,yStep = 1,xStep = 1 / k。

根据这个公式,就能通过(xi,yi)迭代计算出(xi+1、yi+1),然后在坐标系中绘制计算出的(x,y)坐标点。


2、Bresenham算法

Bresenham算法也是一种计算机图形学中常见的绘制直线的算法,其本质思想也是步进的思想,但由于避免了浮点运算,相当于DDA算法的一种改进算法。

设直线的斜率为k,当|k| <=1时,x方向为主步进方向;当|k| >1时,y方向为主步进方向。现以|k| <1时为例,推导Bresenham算法的原理。

这里写图片描述

Bresenham算法直线绘制示意图
图片来自:http://st251256589.blog.163.com/blog/static/16487644920114112817666/

图中绘制了一条直线,蓝色点表示该直线上的点,红色点表示光栅下绘制的点。
假设当前点是(xi,yi)
- 如果int(yi+0.5) = yi,则在点(xi, round(yi))处绘制.
- 如果int(yi+0.5) = yi + 1,则在点(xi, round(yi)+1)处绘制。

上述逻辑可简述为:当x方向是主要步进方向时,以每一小格的中点为界,如果当前的yi在中点(图中红色短线)下方,则y取round(yi); 如果当前的yi在中点上方,则y取rund(yi)+1。

引用部分:现考虑这种方法的误差,因为直线的起始点在像素中心,所以误差项d的初值d0=0。x下标每增加1,d的值相应递增。直线的斜率值k,即d=d+k。一旦d≥1,就把它减去1,这样保证d在0、1之间。当d≥0.5时,最接近于当前像素的右上方像素(x+1,y+1)而当d<0.5时,更接近于右方像素(x+1,y)为方便计算,令e=d-0.5,e的初值为-0.5,增量为k。当e≥0时,取当前像素(xi,yi)的右上方像素(x+1,y+1),而当e<0时,更接近于右方像素(x+1,y)可以改用整数以避免除法。由于算法中只用到误差项的符号,因此可作如下替换:
e1 = 2e * Δx。

参考:
http://blog.csdn.net/xdg_blog/article/details/52848891
http://www.cnblogs.com/weiweishuo/archive/2013/03/11/2954443.html


3、代码实现

1、DDA算法

void CGView::DrawDDALine(int startx,int starty, int endx, int endy)  
{   
    CDC* pDC = GetDC();
    DrawStandLine(pDC);//绘制标准直线
    int x0 = startx; 
    int y0 = starty ;
    int x1 = endx; 
    int y1 = endy; 
    int color=RGB(255,0,0);
    int x; 
    float dx,dy,y,k;
    dx = x1-x0, dy = y1-y0;
    k = dy / dx,y = y0;
    int x2 = startx; 
    int y2 = endx;
    for(x = x0;x <= x1;x++)
    {   //(20,360)是坐标轴的起点
        x2 = 20 + x * 30; //30是坐标轴的单位刻度
        pDC->Ellipse( x2 - 5, y2 - 5, x2 + 5, y2 + 5 );
        y = k * x + k;
        y = (int)(y+0.5);
        y2 = 360 - y * 30;
    }
}

2、Bresenham算法

void CGView::DrawBresenham(int startx,int starty, int endx, int endy)
{
    CDC* pDC = GetDC();
    DrawStandLine(pDC);//绘制标准直线
    int x0, y0, x1, y1;
    x0 = startx; 
    y0 =starty;
    x1 = endx; 
    y1 = endy;
    int x, y, dx, dy;  
    dx = x1-x0, dy = y1- y0; 
    x = x0;
    y = y0;
    double k = dy / dx;
    //如果 >1,则y方向是主要步进方向,需要转换坐标系方向
    if(abs(k)>1){
       Swap(startx,starty,endx,endy);
    }
    int e = -dx; int x2 = 20, y2 = 360; //(20,360)是坐标轴的起点
    for (int x=x0; x<=x1; x++)
    { 
        pDC->Ellipse( x2 - 5, y2 - 5, x2 + 5, y2 + 5 );
        x2 += 30;
        e += 2 * dy;
        if (e > 0)
        { 
            y++;
            y2 -= 30; //30是坐标轴的单位刻度
            e -= 2*dx;
        }
    }
}

两种算法的运行结果情况如下图所示,从图中可已看出,两种算法都能绘制出直线段,但是在细节稍有不同,当x=4时,DDA算法的y值为3,而Bresenham的算法y为2。在不过从效率上看,由于Bresenham避免了浮点运算,所以效率更高。

这里写图片描述

本文参考了网上的资料,包括图片、文字等。在文中均给出了链接。时间太久了,代码已经找不到出处了。如有疏漏,请指出。

这里写图片描述

首先,我们先来介绍一下DDA算法Bresenham算法DDA算法是一种简单的数字微分方法,它的基本思想是将线段分成n个单位长度的小线段,然后根据每个小线段的斜率决定它的下一个像素点,从而逐步绘制出整条线段。 Bresenham算法是一种更加高效的算法,它利用了计算机中的位运算来实现快速的计算,相比于DDA算法Bresenham算法能够更加快速地绘制出图形。 下面是DDA算法Bresenham算法分别画圆的代码和算法流程图。 DDA算法画圆代码实现: ```python import turtle # DDA算法画圆 def draw_circle_dda(x0, y0, r): x = r y = 0 step = 1 / r while x >= y: turtle.goto(x + x0, y + y0) turtle.goto(y + x0, x + y0) turtle.goto(-x + x0, y + y0) turtle.goto(-y + x0, x + y0) turtle.goto(-x + x0, -y + y0) turtle.goto(-y + x0, -x + y0) turtle.goto(x + x0, -y + y0) turtle.goto(y + x0, -x + y0) y += step if (x * x + y * y) > r * r: x -= step ``` DDA算法画圆的算法流程图: ![DDA算法画圆的算法流程图](https://img-blog.csdn.net/20180414141452615?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2hpdGdwYXJhbWVudA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/q/50) Bresenham算法画圆代码实现: ```python import turtle # Bresenham算法画圆 def draw_circle_bresenham(x0, y0, r): x = 0 y = r d = 3 - 2 * r while x <= y: turtle.goto(x + x0, y + y0) turtle.goto(y + x0, x + y0) turtle.goto(-x + x0, y + y0) turtle.goto(-y + x0, x + y0) turtle.goto(-x + x0, -y + y0) turtle.goto(-y + x0, -x + y0) turtle.goto(x + x0, -y + y0) turtle.goto(y + x0, -x + y0) if d < 0: d = d + 4 * x + 6 else: d = d + 4 * (x - y) + 10 y -= 1 x += 1 ``` Bresenham算法画圆的算法流程图: ![Bresenham算法画圆的算法流程图](https://img-blog.csdn.net/20180414141507222?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2hpdGdwYXJhbWVudA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/q/50)
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值