直线生成算法——Bresenham法
Bresenham 画线算法
生成直线的bresenham算法
生成直线的bresenham算法
Bresenham算法是由Jack E. Bresenham在1962年提出的一种用于生成直线图形的算法。
它可以根据两个点的坐标来计算出中间所有点的位置,即通过这两个端点可以确定出整条直线的像素点。
Bresenham算法的核心思想是,沿着已知的两个点之间的点,从起点开始向终点靠近,沿途计算斜率的误差,依据误差大小判断是选择水平方向或者垂直方向上的点,从而确定最终的直线图形。
具体步骤如下:
(1)根据两个点坐标计算出斜率dx和dy;
(2)令x0=x1, y0=y1;
(3)计算当前点处斜率误差p,公式为:p=2dy-dx;
(4)根据p的大小,决定下一步是沿水平方向还是垂直方向:
(a)p>0时,下一步沿垂直方向前进,即y++;
(b)p<=0时,下一步沿水平方向前进,即x++;
(5)重复步骤3、4,直到到达终点。
直线生成算法——Bresenham法
直线生成算法——Bresenham法最近的研究涉及在像素图上作直线,自己也不想花时间摸索,于是在网上找到了Bresenham的直线生成算法,有一篇博客讲得清晰明了,但是算法上有些问题,我进行了改进和移植,下面讲解Bresenham的直线生成算法时也是参考这篇博文。
1.算法简介图1算法思想:图1中,连接M点和N点的直线经过点B,由于是像素图,所以实际上B 点应该由A点或者C点代替。
当B点更靠近A点时,选择点A(x+1,y+1);当B点更靠近C点时,选择点C(x+1,y)。
因此,当ε+m < 0.5时,绘制(x + 1, y)点,否则绘制(x + 1, y + 1)点,这里ε为累加误差,表达式为:式中:表示在第n次计算时的值,表示在第n+1次计算时的值;m就是直线的斜率。
由于斜率m的值有正有负,有可能为0,也可能为∞,为了避免分别讨论这些情况,将上述公式两边都乘以dx, 并将ε*dx用ξ表示,则有式中:表示在第n次计算时的值,表示在第n+1次计算时的值;dx为起点和终点横坐标之差,dy为起点和终点纵坐标之差。
还需说明一点,由直线斜率的定义故值得注意的是,现在我们只考虑dx > dy,且x,y的增量均为正的情况,但实际上有8种不同的情况(但是算法思想不变),如图2所示如图22.算法程序前文提到的那篇博文提出了一种方法,能将这8种情况都考虑,很巧妙。
但是实际应用时发现程序运行结果不是完全对,多次检查之后将程序进行了修改。
修改后的算法VB程序如下‘**************************************************************************** Type mypos '自定义数据类型x As Integery As IntegerEnd Type‘**************************************************************************** Function Bresenham(arr() As mypos, x1, y1, x2, y2)Dim x!, y!, dx!, dy!, ux%, uy%, eps!Dim cnt%ReDim arr(100)dx = x2 - x1dy = y2 - y1If dx >= 0 Then ux = 1If dx < 0 Then ux = -1If dy >= 0 Then uy = 1If dy < 0 Then uy = -1x = x1y = y1eps = 0dx = Abs(dx): dy = Abs(dy)cnt = 0If dx >= dy ThenFor x = x1 To x2 Step uxcnt = cnt + 1If 2 * (eps + dy) < dx Theneps = eps + dyarr(cnt).x = xarr(cnt).y = yElseeps = eps + dy - dxIf cnt >= 2 Then y = y + uy 'cnt大于2才执行y = y + uy,即排除起始坐标点,否则造成错误结果arr(cnt).x = xarr(cnt).y = yEnd IfNext xElseFor y = y1 To y2 Step uycnt = cnt + 1If 2 * (eps + dx) < dy Theneps = eps + dxarr(cnt).x = xarr(cnt).y = yElseeps = eps + dx - dyIf cnt >= 2 Then x = x + ux 'cnt大于2才执行x = x + ux,即排除起始坐标点,否则造成错误结果arr(cnt).x = xarr(cnt).y = yEnd IfNext yEnd Ifarr(0).x = cnt’记录元素个数End Function如果大家有不同看法,还希望共同讨论3.程序运行结果(VB+ OpenGL)图3图4绘制y=x,0≤x≤10,图3是原程序运行结果,图4时修改后的程序运行结果,原程序运行得到的起点是(0,1),但实际应该是(0,0)图5图6绘制直线[第1个坐标为起点,第2个坐标为终点](5,5)-(15,15)、(5,10)-(15,15)、(5,15)-(15,15)、(5,20)-(15,15)、(5,25)-(15,15);(25,5)-(15,15)、(25,10)-(15,15)、(25,15)-(15,15)、(25,20)-(15,15)、(25,25)-(15,15);(5,5)-(15,15)、(10,5)-(15,15)、(15,5)-(15,15)、(20,5)-(15,15)、(25,5)-(15,15);(5,25)-(15,15)、(10,25)-(15,15)、(15,25)-(15,15)、(20,25)-(15,15)、(25,25)-(15,15);图5是原程序运行结果,图6是修改后的程序运行结果。
分别解释直线生成算法dda法,中点画线法和bresenham法的基本原理
分别解释直线生成算法dda法,中点画线法和
bresenham法的基本原理
直线生成算法DDA法、中点画线法和Bresenham法的基本原理如下:
1. DDA直线生成算法:基于差分运算的直线生成算法。
通过将直线分割成
若干个相邻的像素点,并按照一定的步长进行逐点绘制,实现直线的绘制。
算法主要涉及到线性插值的思想,即根据已知的两点坐标,通过计算它们之间的差值,然后根据这个差值和步长来确定新的像素点的位置。
2. 中点画线法:一种线段绘制算法,从线段的起点和终点出发,按照一定的规则向终点逐步逼近,并在途中以控制变量的方式得出每个像素点的坐标,从而绘制出所需的线条。
具体实现中,通过计算线段斜率的变化情况,分为斜率小于1和大于等于1两种情况,并采用Bresenham的对称性原理,以中点的颜色来控制每个像素点的生长方向,从而获得较高的绘制效率和图像质量表现。
3. Bresenham算法:通过一系列的迭代来确定一个像素点是否应该被绘制。
对于一条从点(x1,y1)到点(x2,y2)的直线,首先计算出斜率k。
然后,通过比较每个像素点的y值到直线上的y值,来决定哪些像素点应该被绘制。
当斜率k大于等于1时,在x方向上迭代,而对于每个x值,计算出y值,并将像素点(x,y)绘制。
当斜率k小于1时,在y方向上迭代,而对于每个y值,计算出x值,并将像素点(x,y)绘制。
以上内容仅供参考,如需更多信息,建议查阅相关文献或咨询数学专业人士。
直线的Bresenham算法
生成直线的B resenham算法从上面介绍的DDA算法可以看到,由于在循环中涉及实型数据的加减运算,因此直线的生成速度较慢。
在生成直线的算法中,B resenham算法是最有效的算法之一。
B resenham算法是一种基于误差判别式来生成直线的方法。
一、直线Bresenham算法描述:它也是采用递推步进的办法,令每次最大变化方向的坐标步进一个象素,同时另一个方向的坐标依据误差判别式的符号来决定是否也要步进一个象素。
我们首先讨论m=△y/△x,当0≤m≤1且x1<x2时的B resenham算法。
从DDA直线算法可知这些条件成立时,公式(2-2)、(2-3)可写成:x i+1=x i+△x(2-2)y i+1=y i+△y(2-3)x i+1=x i+1 (2-6)y i+1=y i+m(2-7)有两种B resenham算法思想,它们各自从不同角度介绍了B resenham算法思想,得出的误差判别式都是一样的。
二、直线B resenham算法思想之一:由于显示直线的象素点只能取整数值坐标,可以假设直线上第i个象素点坐标为(x i,y i),它是直线上点(x i,y i)的最佳近似,并且x i=x i(假设m<1),如下图所示。
那么,直线上下一个象素点的可能位置是(x i+1,y i)或(x i+1,y i+1)。
由图中可以知道,在x=x i+1处,直线上点的y值是y=m(x i+1)+b,该点离象素点(x i+1,y i)和象素点(x i+1,y i+1)的距离分别是d1和d2:这两个距离差是我们来分析公式(2-10):(1)当此值为正时,d1>d2,说明直线上理论点离(x i+1,y i+1)象素较近,下一个象素点应取(x i+1,y i+1)。
(2)当此值为负时,d1<d2,说明直线上理论点离(x i+1,y i)象素较近,则下一个象素点应取(x i+1,y i)。
直线生成算法DDA、Midpoint、Bresenham
1、直线生成算法1.算法分析1)DDA设直线两端点:P1(x1,y1)及 P0(x0,y0),dx=x1-x0,dy=y1-y0直线斜率:k=dy/dx直线方程: y=k*x+b有:y1=k*x1+b=k*x0+k*dx+b=y0+k*dx当dx=1时,有y1=y0+k算法复杂度:加法+取整优点:避免了y=k*x+b 方程中的浮点乘法,比直接用点斜式画线快 缺点:需浮点数加法及取整运算,不利于硬件实现.2)Midpoint当前像素点为P(xP,yP),下一个像素点有两种可选择点P1(xP+1,yP),P2(xP+1,yP+1)。
若M=(xP+1,yP+0.5)为P1与P2的中点,Q 为理想直线与x=xP+1垂线的交点。
x Pi=(xi, yi ) M Q P1 p2y当M 在Q 的上方时,应取P1为下一点;当M 在Q 的下方时,应取P2为下一点;直线段L (P0(x0,y0),P1(x1,y1)),用方程F (x,y )=ax+by+c=0表示 a=y0-y1,b=x1-x0,c=x0y1-x1y0有点与L 的关系:线上:F (x,y )=0上方:F (x,y )>0下方:F (x,y )<0判别式:d=F(M)=F(xP+1,yP+0.5)=a(xP+1)+b(yP+0.5)+cD 是xP,yP 的线性函数,可采用增量计算,提高运算效率:1)若d>=0,取P1,d1=d+a,增量为a2)若d<=,取P2,d2=d+a+b,增量为a+b可用2d 代替d 来摆脱浮点运算,写出仅含整数运算的算法3)Bresenhamy x F(x,y)=0 F(x,y)>0 F(x,y)<0 (x1,y1)(x0,y0)设直线方程为y=kx+b,有y1=y0+k(x-x0)=y0+k是否增1取决于误差项d的值,初始值d0=0X每增加1,有d=d+k令e=d-0.5,e0=-0.5,增量为k当e>=0时,取当前像素(xi,yi)的右上方像素(xi+1,yi+1),e 减小1;当e<0时,更接近于右方像素(xi+1,yi)。
Bresenham算法
Course PagePage 1 of 6课程首页 > 第二章 二维图形的生成 > 2.1 直线的生成 > 2.1.2 生成直线的Bresenham算法全部隐藏2.1.2 生成直线的Bresenham算法从上面介绍的DDA算法可以看到,由于在循环中涉及实型数据的加减运算,因此直线的生成速度较慢。
在生成直线的算法中,Bresenham算法是最有效的算法之一。
Bresenham算法是一种基于误差判别式来生成直线的方法。
一、直线Bresenham算法描述: 它也是采用递推步进的办法,令每次最大变化方向的坐标步进一个象素,同时另一个方向的坐标依据误差判别式的符号来决定是否也要步进一 个象素。
我们首先讨论m=△ y/△x,当0≤m≤1且x1<x2时的Bresenham算法。
从DDA直线算法可知这些条件成立时,公式(2-2)、(2-3)可写成: xi+1=x i+1 yi+1=y i+m (2-6) (2-7)有两种Bresenham算法思想,它们各自从不同角度介绍了Bresenham算法思想,得出的误差判别式都是一样的。
二、直线Bresenham算法思想之一: 由于显示直线的象素点只能取整数值坐标,可以假设直线上第i个象素点坐标为(xi,yi),它是直线上点(xi,yi)的最佳近似,并且xi=xi(假设 m<1),如下图所示。
那么,直线上下一个象素点的可能位置是(xi+1,yi)或(xi+1,yi+1)。
由图中可以知道,在x=xi+1处,直线上点的y值是y=m(xi+1)+b,该点离象素点(xi+1,yi)和象素点(xi+1,yi+1)的距离分别是d1和d2:d1=y-yi=m(xi+1)+b-yi d2=(yi+1)-y=(yi+1)-m(xi+1)-b 这两个距离差是 d1-d2=2m(xi+1)-2yi+2b-1(2-8) (2-9)(2-10)我们来分析公式(2-10): (1)当此值为正时,d1>d2,说明直线上理论点离(xi+1,yi+1)象素较近,下一个象素点应取(xi+1,yi+1)。
分别解释直线生成算法dda法、中点画线法和bresenham法的基本原理
分别解释直线生成算法dda法、中点画线法和bresenham法的基本原理DDA直线生成算法、中点画线法和Bresenham法都是计算机图形学中用于生成直线的算法。
以下是这三种算法的基本原理:1.DDA直线生成算法(Digital Differential Analyzer):DDA算法是一种基于差分运算的直线生成算法。
其基本原理是,通过计算直线起点和终点之间的差值(横向差值dx 和纵向差值dy),并根据步长来决定下一个像素点的位置。
算法首先确定差值中绝对值较大的一方作为基准,步长设为1,另一方则按比例进行调整,以保持线段的斜率不变。
在实现过程中,DDA算法需要遍历每一个像素点,根据差值的正负和大小来确定新像素点的位置。
2.中点画线法:中点画线法的基本原理是,通过计算线段上当前像素点与相邻两个像素点构成的线段与理想直线的距离,来决定下一个像素点的位置。
具体实现时,设定线段的中点为M,理想直线与线段的交点为Q。
通过比较M和Q的位置关系来确定下一个像素点:若M在Q上方,则取上方的像素点为下一个点;若M在Q下方,则取下方的像素点为下一个点;若M与Q重合,则可任意选择上方或下方的像素点。
中点画线法以中点M作为判别标志,逐点生成直线。
3.Bresenham法:Bresenham算法的原理是基于直线的斜率和截距来计算每个像素点的位置。
在计算机屏幕上,每个像素点都有一个坐标值。
Bresenham算法通过计算直线上每个像素点的坐标值来绘制直线,避免了使用浮点数运算,从而提高了计算效率。
在实现过程中,Bresenham算法根据直线的斜率以及当前像素点的位置,计算出下一个像素点的位置,并逐点绘制出直线。
布雷森汉姆直线算法
布雷森汉姆直线算法布雷森汉姆直线算法(Bresenham's Line Algorithm)是一种计算机图形学中常用的直线绘制算法,其通过在离散的像素格上选择最接近实际直线路径的点来实现高效绘制直线的目的。
该算法由Jack Elton Bresenham在1962年首次提出,被广泛应用于图形显示、打印机及数码扫描仪等领域。
布雷森汉姆直线算法的核心思想是利用整数运算来代替浮点运算,从而提高计算效率。
该算法通过仅使用加法、减法和位移等基本运算,不需要乘法运算和浮点数运算,从而适用于资源有限的嵌入式系统和低成本的图形设备。
算法的基本步骤如下:1. 根据起点P1(x1,y1)和终点P2(x2,y2)确定直线斜率k。
2. 如果|k|≤1,则沿x轴方向递增遍历起点P1到终点P2,并在每个像素上绘制。
若k>1,则沿y轴方向递增遍历P1到P2,绘制每个像素。
3. 对于每一步,根据递增的方向选择相应的像素。
4. 根据斜率k来决定误差累积量,调整绘制位置,保证直线的连续性。
该算法的优势在于其简单而高效的原理,使得绘制直线的速度非常快。
与传统的基于浮点运算的算法相比,布雷森汉姆直线算法的计算开销较小,而且能够得到非常接近实际直线路径的结果,几乎没有明显的视觉差异。
这使得该算法在计算资源有限的场景下非常有用,例如在嵌入式系统中,可以利用该算法绘制图形界面的边界、线条等。
然而,布雷森汉姆直线算法也存在一些局限性。
由于只考虑了整数坐标,因此绘制出来的直线可能会有些锯齿状,这在一些高精度要求的场景下可能会表现出明显的视觉噪点。
此外,该算法仅适用于绘制直线,并不能直接应用于曲线、圆等其他形状的绘制。
总之,布雷森汉姆直线算法是一种非常经典和实用的绘制直线的算法。
它通过巧妙地利用整数计算来取代浮点计算,以提高效率和减少计算资源开销。
虽然存在一些局限性,但在大多数场景下,它仍然是一种高效且精确的绘制直线的选择,对于计算机图形学的发展和应用有着重要的指导意义。
bresenham算法计算步骤
bresenham算法计算步骤Bresenham算法是一种经典的线段生成算法,其原理是利用递增的整数计算来逼近直线的路径,从而快速高效地绘制线段。
本文将详细介绍Bresenham算法的计算步骤。
1. 确定起点和终点我们需要确定线段的起点和终点的坐标。
假设起点为(x0, y0),终点为(x1, y1)。
2. 计算斜率接下来,我们需要计算线段的斜率。
斜率可以通过以下公式来计算:m = (y1 - y0) / (x1 - x0)其中m表示斜率。
3. 判断斜率绝对值是否小于1判断斜率的绝对值是否小于1,如果小于1,则说明直线在x方向上变化的幅度更大;反之,如果斜率的绝对值大于等于1,则说明直线在y方向上变化的幅度更大。
4. 计算增量根据斜率的值,我们可以计算出在每个步骤中需要增加的x和y的值。
如果斜率的绝对值小于1,则每次x增加1,y增加斜率m;反之,如果斜率的绝对值大于等于1,则每次y增加1,x增加1/斜率m。
5. 计算初始误差计算初始误差值,初始误差值为0。
初始误差用于判断应该向x方向还是y方向进行绘制。
6. 迭代绘制线段根据初始误差值和增量,使用迭代的方式来绘制线段。
具体步骤如下:- 根据初始误差值,判断当前点应该绘制在哪个像素上。
如果误差大于等于0,则绘制在下一个像素上,同时误差减去1;反之,如果误差小于0,则绘制在当前像素上。
- 根据斜率的绝对值大小,更新初始误差的值。
如果斜率的绝对值小于1,则初始误差加上y的增量;反之,如果斜率的绝对值大于等于1,则初始误差加上x的增量。
- 根据斜率的绝对值大小,更新x和y的值。
如果斜率的绝对值小于1,则x加上1;反之,如果斜率的绝对值大于等于1,则y加上1。
7. 绘制结果将线段绘制在屏幕上,直到终点被绘制到。
通过以上步骤,我们可以使用Bresenham算法快速高效地绘制直线。
这个算法的优点是计算简单、速度快,并且不需要浮点运算,因此非常适合在计算能力较弱的设备上使用。
直线的Bresenham算法
直线的Bresenham算法在实验课上⽤⾃⼰的算法画直线被diss效率低花了半天时间看了下Bresenham算法真总结⼀下其中的精妙之处Bresebham直线⽣成算法的基本原理是,每次在最⼤位移⽅向上⾛⼀步,⽽另⼀个⽅向是⾛步还是不⾛步取决于误差项的判别。
声明k为斜率在0≤k<1的情况下,假设当前点是P(x1,y1),则下⼀个点在P u(x1+1,y1+1)与P d(x1+1,y1)中选⼀。
以M表⽰P u与P d的中点,即M(x1+1,y1+0.5)。
设Q是理想直线与x=x i+1的交点;显然,若M在Q的下⽅,则P u(x1+1,y1+1)离直线较近,应取为下⼀个像素;否则应取P d(x1+1,y1)。
理解并不难主要在于实现依据该算法的原理基本能够实现窝先试着⾃⼰写了⼀会如果要实现各个⽅向的⼆维直线绘制需要考虑多种情况写出来很不美观教材上给出了更好的解决⽅案:同样以0≤k<1为例每次选取下个点时理想直线的y坐标都步进k个单位长度累加值即为误差项d i当d i⼤于0.5时选取P u否则选取P d并使d i-1令e i=d i-0.5则e i>0时选取P u否则选取P d经过改进,算法的效率⼤幅提升但其中在计算斜率与误差项时会⽤到⼩数和除法并且下⼀步的选择只与误差项的符号有关因此可以进⼀步改进:可知e i的值由三种值组成:e i=-1/2(初始值)+(n个)y/x(步进值)-(m个)1(调整值)...同乘2x即得2*x*e i=-x+(n个)2*y-(m个)2*x....这样即可得到仅由整数构成的算法以上仅为对0≤k<1情况下的讨论其余的情况类似附⼀段杂乱⽆章的代码1 point<Type> now_point = start;2 point<Type> e_step, point_step;3 e_step.x = abs(step.x);4 e_step.y = abs(step.y);5 glBegin(GL_POINTS);6if (step.x == 0 && step.y == 0) //No Step7return;8 point_step.x = (step.x == 0) ? 1 : step.x / e_step.x;9 point_step.y = (step.y == 0) ? 1 : step.y / e_step.y;10if (step.x == 0) { // k is endless11do{12 glVertex2i(now_point.x, now_point.y);13 now_point.y += point_step.y;14 } while (now_point.y != end.y);15 }16else if (step.y == 0) { //k is zero17do {18 glVertex2i(now_point.x, now_point.y);19 now_point.x += point_step.x;20 } while (now_point.x != end.x);21 }22else if (abs(step.y / step.x) == 0) { // |k| < 1 23 Type e = -e_step.x;24do {25 glVertex2i(now_point.x, now_point.y);26 e += 2 * e_step.y;27 now_point.x += point_step.x;28if (e > 0) {29 now_point.y += point_step.y;30 e -= 2 * e_step.x;31 }32 } while (now_point.x != end.x);33 }34else { // |k| >= 135 Type e = -e_step.y;36do {37 glVertex2i(now_point.x, now_point.y);38 e += 2 * e_step.x;39 now_point.y += point_step.y;40if (e > 0) {41 now_point.x += point_step.x;42 e -= 2 * e_step.y;43 }44 } while (now_point.y != end.y);45 }46 glEnd();47 glFlush();本菜鸡的辣鸡代码。
中点bresenham算法
中点bresenham算法中点bresenham算法原理由Bresenham提出的直线生成算法的基本原理是,每次在最大位移方向上走一步,而另一个方向是走步还是不走步取决于误差项的判别。
这时直线将平面分成三个区域:对于直线上的点,F(x,y)=0;对于直线上方的点,F(x,y)>0;对于直线下方的点,F(x,y)<0。
首先假设0≤k≤1,由于x是最大位移方向,因此每次在x方向上加1,y方向上或加1 或加0。
假定当前点是P(xi,yi),则下一个点在pu(xi+1,yi+1)与pd(xi+1,yi)中选一。
以M表示pu和pd的终点即M(xi+1,yi+0.5)。
又设Q是理想直线与垂直线x=xi+1的交点。
显然,若M在Q 的下方,则pu(xi+1,yi+1)离直线近,应取为下一个像素,否则应取Pd(xi+1,yi)。
所以如前所述,欲判断Q在M的上方还是下方,只要把M代入F(x,y),并判断它的符号即可。
如上构造判别式,当di<0时,M在直线下方,故应取Pu。
当di>0时,应取正右方的Pd。
当di=0时,两者一样合适,可以随便取一个。
所以现在根据上面的判别式对误差项进行递推。
当di<0时,取右上方像素Pu,欲判断再下一个像素应该取那个应计算此时di的增量为1-k。
当di≥0时,取右上方像素Pd,欲判断再下一个像素应该取那个应计算下面进行di的初值计算。
显然直线的第一个像素P(x0,y0)在直线上,因此响应的di的初始值计算如下但是这其中仍然有小数,由于我们使用的只是di的符号,因此可以用2di△x摆脱小数Bresenham算法对任意斜率的直线段具有通用性,对于斜率为整且大于1的直线段,只需要交换x和y之间的规则。
对于负斜率,除了一个坐标递减而另一个坐标地政外,其余程序是类似的。
直线中点Bresenham算法
{
InputDlg dlg;
if(dlg.DoModal()==IDOK)
{
AfxGetMainWnd()->SetWindowText(":直线中点Bresenham算法");
RedrawWindow();
Mbline(dlg.m_x0,dlg.m_y0,dlg.m_x1,dlg.m_y1);
1.输入直线的起点坐标P0(x0,y0)和终点坐标P1(x1,y1)。
2.定义直线当前点坐标x,y、定义中点偏差判别式d、定义直线斜率k、定义像素点颜色rgb。
3.x=x0,y=y0,计算d=0.5-k,k=(y1-y0)/(x1-x0),rgb=RGB(0,0,255)。
4.绘制点(x,y),判断d的符号。若d<0,则(x,y)更新为(x+1,y+1),d更新为d+1-k;否则(x,y)更新为(x+1,y),d更新为d-k。
x=x0;y=y0;k=(y1-y0)/(x1-x0);d=0.5-k;
for(x=x0;x<=x1;x++)
{
dc.SetPixel(ROUND(x),ROUND(y),rgb);
if(d<0)
{
y++;
d+=1-k;
}
else
d-=k;
}
}
运行结果:
}
}
void CTestView::Mbline(double x0, double y0,double x1,double y1) //直线中点BresenhaLORREF rgb=RGB(255,0,0); //定义直线颜色为红色
分别解释直线生成算法dda法、中点画线法和bresenham法的基本原理。
分别解释直线生成算法dda法、中点画线法和bresenham法
的基本原理。
一、DDA(Digital Differential Analyzer)法
DDA法是一种基于像素的直线生成算法,其基本原理是通过在直线的每个像素点上应用微分关系来计算出该点的位置。
具体来说,首先选择一个起始点,然后在直线上每隔一个像素点进行微分计算,得到该点相对于前一个点的增量。
在直线的终点处,由于没有前一个点的信息,需要使用特殊的方法进行处理。
DDA法生成的线条在视觉上较为平滑,且无需进行线条绘制。
二、中点画线法
中点画线法是一种基于连续点的直线生成算法,其基本原理是每隔一定数量的点在直线上绘制一个点,以生成直线。
该算法的优点是计算量较小,适用于实时性要求较高的场景。
但是,由于该算法生成的线条不够平滑,因此在一些对线条质量要求较高的场景下可能无法满足要求。
三、Bresenham法
Bresenham法是一种基于二进制运算的直线生成算法,其基本原理是通过比较相邻像素之间的灰度级差异来决定线条的绘制。
算法首先确定直线的起点和终点,然后根据灰度级差异的大小和二进制运算的特点,确定在直线上绘制点的位置。
Bresenham法生成的线条在视觉上较为清晰,且具有较好的连续性。
同时,由于该算法采用了二进制运算,因此在处理大量数据时具有较高的效率。
总结:DDA法、中点画线法和Bresenham法是常用的直线生成算法,每种算法都有其适用的场景和优缺点。
在实际应用中,需要根据具体需求和场景选择合适的算法,以达到最佳的直线生成效果。
Bresenham算法
Bresenham算法⼀ Bresenham 绘直线使⽤ Bresenham 算法,可以在显⽰器上绘制⼀直线段。
该算法主要思想如下:1 给出直线段上两个端点,根据端点求出直线在X,Y⽅向上变化速率;2 当时,X ⽅向上变化速率快于 Y ⽅向上变化速率,选择在 X ⽅向上迭代,在每次迭代中计算 Y 轴上变化;当时,Y ⽅向上变化速率快于 X ⽅向上变化速率,选择在 Y ⽅向上迭代,在每次迭代中计算 X 轴上变化;3 现在仅考虑情形,在情况下仅需要交换变量即可。
直线斜率,当 d = 0 时,为⼀条⽔平直线,当 d > 0 或 d < 0 时,需要分开讨论,如下图:⼆ Bresenham 绘圆使⽤ Bresenham 绘制圆形,只需要绘制四分之⼀圆即可,其他部分通过翻转图形即可得到。
假设圆⼼位于 (0, 0) 点,半径为 R,绘制第⼀象限四分之⼀圆形,如下图:根据图形可知,从出发,下⼀个可能的选择分别为:1)⽔平⽅向上;2)对⾓⽅向上;3)垂直⽅向上;下⾯计算,根据差值可判断⼤致圆弧位置:1)当时,圆环落在与之间,进⼀步计算圆弧到与的距离以判断应该落在哪个点上;2),由于,,上式可化简为,,将改写为得:,已知,可根据上式快速求解出,当时,下⼀点落在上,当时,下⼀点落在上;3)当时,圆环落在与之间,进⼀步计算圆弧到和的距离以判断应该落在哪个点上;4),可化简为:,将改写为得:,已知,可根据上式快速求解出,当时,下⼀点落在上,当时,下⼀点落在上;5)以上推导中,已知可以快速求解,同时,已知也可以快速推导出,以下分类讨论:a. 当时,有:,进⼀步整理得:;b. 当时,有:,进⼀步整理得:;c. 当时,有:,进⼀步整理得:。
以下给出 Bresenham 绘圆实现:1void Bresenham_Circle(PairS center, int radius, std::vector<PairS>& circle)2 {3 PairS start(0, radius);4int Delta = (start.x + 1) * (start.x + 1) +5 (start.y - 1) * (start.y - 1) - radius * radius;67 std::vector<PairS> tmp;8 tmp.push_back(start);910while (start.y > 0)11 {12int state = -1;1314if (Delta < 0)15 {16int delta = (Delta + start.y) * 2 - 1;17if (delta < 0)18 {19 start.x += 1;20 state = 0;21 }22else23 {24 start.x += 1;25 start.y -= 1;26 state = 1;27 }28 }29else30 {31int delta = (Delta - start.x) * 2 - 1;32if (delta < 0)33 {34 start.x += 1;35 start.y -= 1;36 state = 1;37 }38else39 {40 start.y -= 1;41 state = 2;42 }43 }4445if (state == 0)46 Delta = Delta + start.x * 2 + 1;47else if (state == 1)48 Delta = Delta + start.x * 2 - start.y * 2, +2;49else if (state == 2)50 Delta = Delta - start.y * 2 + 1;51else52break;5354 tmp.push_back(start);55 }5657 std::vector<PairS> tmp2;58for (int i = 0; i < tmp.size(); ++i)59 {60 PairS p(tmp[i].x, tmp[i].y);61 tmp2.push_back(p);62 }63for (int i = tmp.size() - 1; i >= 0; --i)64 {65 PairS p(tmp[i].x, -tmp[i].y);66 tmp2.push_back(p);67 }68for (int i = 0; i < tmp2.size(); ++i)69 {70 PairS p(tmp2[i].x, tmp2[i].y);71 circle.push_back(p);72 }7374for (int i = tmp2.size() - 1; i >= 0; --i)75 {76 PairS p(-tmp2[i].x, tmp2[i].y);77 circle.push_back(p);78 }7980for (int i = 0; i < circle.size(); ++i)81 {82 circle[i].x += center.x;83 circle[i].y += center.y;84 }85 }参考资料计算机图形学得算法基础 David E Rogers。
bresenham算法画直线例题
bresenham算法画直线例题摘要:1.介绍Bresenham算法2.Bresenham算法的原理3.使用Bresenham算法画直线的步骤4.Bresenham算法的应用示例5.总结Bresenham算法在计算机图形学中的重要性正文:Bresenham算法是一种计算几何中用于画直线的算法,由英国计算机科学家Jack Bresenham于1965年提出。
该算法广泛应用于计算机图形学、视频游戏和各种嵌入式系统。
Bresenham算法的核心思想是使用简单的加法和减法运算,以及位运算来计算直线上的每个点的坐标,从而实现画直线的目标。
Bresenham算法的原理基于对直线方程y = mx + b的观察。
当m为正数时,直线是从左下到右上的;当m为负数时,直线是从左上到右下的。
根据这个特点,Bresenham算法将画直线的过程分为两个阶段:第一阶段是向上扫描,第二阶段是向下扫描。
在每一阶段,算法仅使用简单的加法和减法运算来更新当前点的坐标。
使用Bresenham算法画直线的步骤如下:1.初始化x和y坐标,以及直线的斜率m和截距b。
2.判断m的正负性。
如果m为正,进入第一阶段;如果m为负,进入第二阶段。
3.在第一阶段,每次将y坐标加b,然后将x坐标加m,直到x坐标达到最大值或y坐标达到最小值。
4.在第二阶段,每次将y坐标加b,然后将x坐标减m,直到x坐标达到最小值或y坐标达到最大值。
5.如果需要,可以将画直线的过程进行迭代,以获得更高的精度。
Bresenham算法在计算机图形学中具有重要应用价值。
它不仅计算简单、速度快,而且可以在各种不同的硬件平台上实现。
下面给出一个使用Bresenham算法画直线的示例:```pythondef bresenham_line(x0, y0, x1, y1):m = (y1 - y0) / (x1 - x0)b = y0 - m * x0x = x0y = y0e = 0if m < 0:y = y0while x < x1:put_pixel(x, y)e = e + abs(m)if e > abs(b):x = x + 1e = e - abs(m)y = y + 1else:x = x0while y < y1:put_pixel(x, y)e = e + abs(m)if e > abs(b):y = y + 1e = e - abs(m)x = x + 1bresenham_line(0, 0, 10, 5)```总之,Bresenham算法是一种简单而有效的计算几何画直线方法。
Bresenham快速画直线算法
Bresenham快速画直线算法⼀、算法原理简介:算法原理的详细描述及部分实现可参考: Fig. 1假设以(x, y)为绘制起点,⼀般情况下的直观想法是先求m = dy /dx(即x每增加1, y的增量),然后逐步递增x, 设新的点为x1 = x + j,则y1 = round(y + j * m)。
可以看到,这个过程涉及⼤量的浮点运算,效率上是⽐较低的(特别是在嵌⼊式应⽤中,DSP可以⼀周期内完成2次乘法,⼀次浮点却要上百个周期)。
下⾯,我们来看⼀下Bresenham算法,如Fig. 1,(x, y +ε)的下⼀个点为(x, y + ε + m),这⾥ε为累加误差。
可以看出,当ε+m < 0.5时,绘制(x + 1, y)点,否则绘制(x + 1, y + 1)点。
每次绘制后,ε将更新为新值:ε = ε + m ,如果(ε + m) <0.5 (或表⽰为2*(ε + m) < 1)ε = ε + m – 1, 其他情况将上述公式都乘以dx, 并将ε*dx⽤新符号ξ表⽰,可得ξ = ξ + dy, 如果2*(ξ + dy) < dxξ = ξ + dy – dx, 其他情况可以看到,此时运算已经全变为整数了。
以下为算法的伪代码:ξ← 0, y ← y1For x ← x1 to x2 doPlot Point at (x, y)If (2(ξ + dy) < dx)ξ←ξ + dyElsey ← y + 1,ξ←ξ + dy – dxEnd IfEnd For⼆、算法的注意点:Fig. 2在实际应⽤中,我们会发现,当dy > dx或出现Fig.2 右图情况时时,便得不到想要的结果,这是由于我们只考虑dx > dy,且x, y的增量均为正的情况所致。
经过分析,需要考虑8种不同的情况,如Fig. 3所⽰:(Fig. 3)当然,如果直接在算法中对8种情况分别枚举,那重复代码便会显得⼗分臃肿,因此在设计算法时必须充分考虑上述各种情况的共性,后⾯将给出考虑了所有情况的实现代码。
Bresenham算法
举例:图3-4用Bresenham方法扫描转换连接两点P0(0,0)和 P1 (5,2)的直线段。△y = 2, △x = 5, d0 =-1。 Line: P0(0, 0), P1(5, 2) x y d 0 0 -1 1 0 3 2 1 -3 3 1 1 4 2 -5 5 2 -1
PLAY
2y x
以下是当0<k<1时的Bresenham画线算法程序: void Bresenham_Line (int x0,int y0,int x1, int y1,int color) { int dx,dy,d,i,x,y; 复杂度:加法。x每次注定 dx = x1-x0, dy = y1- y0, d=2*dy-dx; 前进1,对于0<k<1,y一定 x=x0, y=y0; 要么前进1,要么不变。如 for (i=0; i<=dx; i++) 果k的取值范围不在(0<k<1) { 之间,上述程序略作修改 SetPixel (x, y, color); 即可满足要求。例如,当 x++; if (d>=0) k>1时,y总是增1,再用 { Bresenham误差量判别式可 y++; 以确定x变量是否增加1。 d=d+2*dy-2*dx; 此时,上述程序只需交换x }else 和y的坐标即可实现。其次, d=d+2*dy; 当k<0,要考虑x或y不是递 } 增1,而是递减1。 }
c 2y x(2b 1) 是常量,与像素位置无关
令di x(d1 d 2 ) ,则di的符号与(d1-d2)的符号相同。
当di<0时,直线上理想位置与像素(xi+1,yi)更接近,应取 右方像素; 当di>0时,像素(xi+1,yi+1)与直线上理想位置更接近; 当di=0时,两个像素与直线上理想位置一样接近,可约定 取(xi+1,yi+1)。
Bresenham直线算法
Bresenham直线算法是用来描绘由两点所决定的直线的算法,它会算出一条线段在 n 维光栅上最接近的点。
这个算法只会用到较为快速的整数加法、减法和位元移位,常用于绘制电脑画面中的直线。
是计算机图形学中最先发展出来的算法。
经过少量的延伸之后,原本用来画直线的算法也可用来画圆。
且同样可用较简单的算术运算来完成,避免了计算二次方程式或三角函数,或递归地分解为较简单的步骤。
以上特性使其仍是一种重要的算法,并且用在绘图仪、绘图卡中的绘图芯片,以及各种图形程式库。
这个算法非常的精简,使它被实作于各种装置的固件,以及绘图芯片的硬件之中。
“Bresenham”至今仍经常作为一整个算法家族的名称,即使家族中绝大部份算法的实际开发者是其他人。
该家族的算法继承了 Bresenham 的基本方法并加以发展,详见参考资料。
目录[隐藏]∙ 1 演算方法∙ 2 一般化∙ 3 最佳化∙ 4 历史∙ 5 参考资料∙ 6 参阅∙7 外部链接[编辑]演算方法Bresenham直线算法描绘的直线。
假设我们需要由 (x0, y0) 这一点,绘画一直线至右下角的另一点(x1, y1),x,y分别代表其水平及垂直座标,并且x1 - x0 > y1 - y0。
在此我们使用电脑系统常用的座标系,即x座标值沿x轴向右增长,y座标值沿y轴向下增长。
因此x及y之值分别向右及向下增加,而两点之水平距离为x1−x0且垂直距离为y1-y0。
由此得之,该线的斜率必定介乎于1至0之间。
而此算法之目的,就是找出在x0与x1之间,第x行相对应的第y列,从而得出一像素点,使得该像素点的位置最接近原本的线。
对于由(x0, y0)及(x1, y1)两点所组成之直线,公式如下:因此,对于每一点的x,其y的值是因为x及y皆为整数,但并非每一点x所对应的y皆为整数,故此没有必要去计算每一点x所对应之y值。
反之由于此线之斜率介乎于1至0之间,故此我们只需要找出当x 到达那一个数值时,会使y上升1,若x尚未到此值,则y不变。
1.论述直线的bresenham算法的原理,方法和步骤。
论述直线的bresenham算法的原理,方法和步骤。
Bresenham算法是一种用于计算直线段的算法,它是一种基于中点画线思想的折线逼近算法。
该算法可以在二维平面中以最小的误差逼近直线。
B resenham算法的主要优点是它只需要计算整数坐标,而不需要使用浮点数计算,因此运行速度快,精度高。
Bresenham算法的原理是:从直线的一个端点开始,按照一定的方向和步长绘制一系列点,直到另一个端点为止。
这些点之间的间距逐渐减小,使得视觉效果上形成一条直线。
在这个过程中,通过计算每个点的坐标,可以得到一条近似于直线的折线。
Bresenham算法的方法如下:1. 初始化参数:设定直线的两个端点坐标(x1,y1)和(x2,y2),以及画线的方向变量k。
初始方向k等于两点横坐标之差与纵坐标之差的比值,即k = (y2 - y1) / (x2 - x1)。
2. 计算第一个点:根据初始方向k,计算第一个点的坐标。
第一个点的横坐标为x1 + k/2,纵坐标为y1。
3. 迭代计算后续点:从第二个点开始,每次迭代都将当前点的横坐标加上k,纵坐标加上1/k。
同时,检查当前点的横坐标是否超过终点坐标x2,如果是,则结束绘制。
4. 输出结果:将计算出的所有点按照顺序连接起来,形成一条折线,这条折线近似于原始直线。
Bresenham算法的步骤如下:1. 初始化参数:设置直线的两个端点坐标和方向k。
2. 计算第一个点:根据方向k,计算第一个点的坐标。
3. 迭代计算后续点:按照迭代公式,依次计算出所有点的位置。
4. 输出结果:将计算出的所有点连接起来,形成一条折线。
5. 终止条件:当计算出的点的横坐标超过终点坐标时,绘制过程结束。
通过以上方法和步骤,Bresenham算法可以高效地绘制出直线段,适用于各种图形绘制和计算场景。
在实际应用中,可以根据需要调整算法的参数和精度,以满足不同的需求。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
直线生成算法——Bresenham法
最近的研究涉及在像素图上作直线,自己也不想花时间摸索,于是在网上找到了Bresenham的直线生成算法,有一篇博客讲得清晰明了,但是算法上有些问题,我进行了改进和移植,下面讲解Bresenham的直线生成算法时也是参考这篇博文。
1.算法简介
图1
算法思想:图1中,连接M点和N点的直线经过点B,由于是像素图,所以实际上B 点应该由A点或者C点代替。
当B点更靠近A点时,选择点A(x+1,y+1);当B点更靠近C点时,选择点C(x+1,y)。
因此,当ε+m < 0.5时,绘制(x + 1, y)点,否则绘制(x + 1, y + 1)点,这里ε为累加误差,表达式为:
式中:表示在第n次计算时的值,表示在第n+1次计算时的值;m就是直线的
斜率。
由于斜率m的值有正有负,有可能为0,也可能为∞,为了避免分别讨论这些情况,
将上述公式两边都乘以dx, 并将ε*dx用ξ表示,则有
式中:表示在第n次计算时的值,表示在第n+1次计算时的值;dx为起
点和终点横坐标之差,dy为起点和终点纵坐标之差。
还需说明一点,由直线斜率的定义
故
值得注意的是,现在我们只考虑dx > dy,且x,y的增量均为正的情况,但实际上有8种不同的情况(但是算法思想不变),如图2所示
如图2
2.算法程序
前文提到的那篇博文提出了一种方法,能将这8种情况都考虑,很巧妙。
但是实际应用时发现程序运行结果不是完全对,多次检查之后将程序进行了修改。
修改后的算法VB程序如下
‘**************************************************************************** Type mypos '自定义数据类型
x As Integer
y As Integer
End Type
‘**************************************************************************** Function Bresenham(arr() As mypos, x1, y1, x2, y2)
Dim x!, y!, dx!, dy!, ux%, uy%, eps!
Dim cnt%
ReDim arr(100)
dx = x2 - x1
dy = y2 - y1
If dx >= 0 Then ux = 1
If dx < 0 Then ux = -1
If dy >= 0 Then uy = 1
If dy < 0 Then uy = -1
x = x1
y = y1
eps = 0
dx = Abs(dx): dy = Abs(dy)
cnt = 0
If dx >= dy Then
For x = x1 To x2 Step ux
cnt = cnt + 1
If 2 * (eps + dy) < dx Then
eps = eps + dy
arr(cnt).x = x
arr(cnt).y = y
Else
eps = eps + dy - dx
If cnt >= 2 Then y = y + uy 'cnt大于2才执行y = y + uy,即排除起始坐标点,否则造成错误结果
arr(cnt).x = x
arr(cnt).y = y
End If
Next x
Else
For y = y1 To y2 Step uy
cnt = cnt + 1
If 2 * (eps + dx) < dy Then
eps = eps + dx
arr(cnt).x = x
arr(cnt).y = y
Else
eps = eps + dx - dy
If cnt >= 2 Then x = x + ux 'cnt大于2才执行x = x + ux,即排除起始坐标点,否则造成错误结果
arr(cnt).x = x
arr(cnt).y = y
End If
Next y
End If
arr(0).x = cnt’记录元素个数
End Function
如果大家有不同看法,还希望共同讨论
3.程序运行结果(VB+ OpenGL)
图3
图4
绘制y=x,0≤x≤10,图3是原程序运行结果,图4时修改后的程序运行结果,原程序运行得到的起点是(0,1),但实际应该是(0,0)
图5
图6
绘制直线[第1个坐标为起点,第2个坐标为终点]
(5,5)-(15,15)、(5,10)-(15,15)、(5,15)-(15,15)、(5,20)-(15,15)、(5,25)-(15,15);
(25,5)-(15,15)、(25,10)-(15,15)、(25,15)-(15,15)、(25,20)-(15,15)、(25,25)-(15,15);
(5,5)-(15,15)、(10,5)-(15,15)、(15,5)-(15,15)、(20,5)-(15,15)、(25,5)-(15,15);
(5,25)-(15,15)、(10,25)-(15,15)、(15,25)-(15,15)、(20,25)-(15,15)、(25,25)-(15,15);
图5是原程序运行结果,图6是修改后的程序运行结果。