直线的绘制(光栅化)
2.验证你所创建的类:在你的视区类的 OnDraw函数中,创建CLine类的若干对象, 并利用不同的方法绘制所创建的直线对象。
则di的计算仅包括整数运算,其符号与(d1-d2)的符号相同,可以作为判别 式。下一点的选取规则; 当di<0时,直线上理想位置与像素(xi+1,yi)更接近,应取右方像素; 当di>0时,像素(xi+1,yi+1)与直线上理想位置更接近; 当di=0时,两个像素与直线上理想位置一样接近,可约定取(xi+1,yi +1)。
第i+1个点(xi+1,yi+1), 令xi+1= xi+ x, 则yi+1=k(xi+ x)+b=yi+kx = yi+y, y= kx 当x =1时 yi+1 = yi+k
( i+1,int( i+1+0.5))
x
y
( i, i)
x y
( i+1, i+1)
x
y
( i,int( i+0.5))
实验二
1.创建一个类CLine, 成员变量包括: CPoint m_StartPoint; CPoint m_EndPoint; COLORREF m_Color; 均设置为私有成员变量。 成员函数(均为公有)包括: 构造函数: CLine (CPoint start, CPoint end, COLORREF color); 获取属性的函数: Get(CPoint &start, CPoint &end, COLORREF &color); 设置属性的函数: Set(CPoint start, CPoint end, COLORREF color); 直接利用MFC中的画线函数绘制该直线段的函数: void Draw(CDC *pDC); 利用DDA 算法绘制该直线段的函数: void DrawWithDDA (CDC *pDC); 利用Bresenham绘制该直线段的函数: void DrawWithBresenham(CDC *pDC);
第3章 基本光栅图形生成技术
3.1 本章的主要内容
本章介绍基本二维图形的绘制,包括直线、圆弧、 椭圆弧的生成,多边形的填充以及更一般区域的填充。 显示器是由离散像素组成的矩阵,在绘制具有连 续性质的直线、曲线或区域等基本图形时,需要确定 最佳逼近它们的像素,这个过程称为光栅化。当光栅 化按照扫描线的顺序进行时,它被称为扫描转换。
光栅化和扫描转换是光栅图形学的基本问题,其算 法的好坏对系统的效率有直接的关系。
3.2 线的生成算法
3.2.1 直线的生成算法
• 问题所在:
• 在数学上,直线是连续的,由无数个点构成的集 合。x,y坐标均为实数。 • 但在显示器上,只能用有限的像素表示,像素的 坐标是整数值。 • 因此,绘制时,需要将直线段离散化为有限的像 素,这些像素应该尽可能地连续、尽量避免出现锯齿, 并最佳逼近于给定的直线段。此外,绘制直线是非常 基本的绘图操作,一个图中往往包括成千上万条直线, 所以,算法应该尽可能地快。
数值微分(DDA)法
给定直线段的两个端点P0(x0,y0)和 P1(x1,y1),直线方程:
y kx b
画线过程从x的左端点x0开始,向x右端点步进,x+=x,计算相应 的y坐标: y=kx+b,取像素点 (round(x), round(y)) 作为当前点的坐 标。
设第i个点(xi,yi), yi= kxi+b
判别式(误差参数)的递推计算:
di x(d1 d 2 ) 2 y xi 2 x yi c
对于k+1步,误差参数为:
di1 2 y xi1 2 x yi1 c di1 di 2 y ( xi1 xi ) 2 x ( yi1 yi )
DDA算法与基本算法相比,减少了浮点乘法,提高了 效率。但是x与dx、y与dy用浮点数表示,每一步要 进行四舍五入后取整,不利于硬件实现,因而效率 仍有待提高。
Bresenham算法 Bresenham算法1965年提出,基本原理是:借助于一个误差量 (直线与当前实际绘制像素点的距离),来确定下一个像素点的 位置。算法的巧妙之处在于采用增量计算,使得对于每一列, 只要检查误差量的符号,就可以确定该下一列的像素位置。 如图3-3所示,对于直线斜率k在0~1之间的情况,从给定线段 的左端点P0(x0, y0)开始,逐步处理每个后续列(x位置),并在扫 描线y值最接近线段的像素上绘出一点。 假设当前直线上的像素坐标 为(xi, yi),那么下一步需要 在列xi+1上确定扫描线y的 值。y值要么不变,要么递 增1,可通过比较d1和d2来 决定。
设Δy=y1-y0, Δx=x1-x0,则k=Δy/Δx,代入上式,得; x(d1 d 2 ) 2yxi 2y 2bx 2 yi x x
2yxi 2 yi x c
c 2y x(2b 1) 是常量,与像素位置无关。令
di x( d1 d 2 )
此时参数c已经消去,且xi+1=xi+1,得:
如果选择右上方像素,即:yi1 yi 1,则: 如果选择右方像素,即:
di1 di 2 y 2 x ( yi1 yi )
di1 di 2y 2x
yi1 yi
,则:
di1 di 2y
x
y
图3-1 DDA算法基本原理
复杂度:加法+取整
上述采用的增量计算方法称为数值微分算法(Digital Differential Analyzer,简称DDA)。数值微分法的本质, 是用数值方法解微分方程,通过同时对x和y各增加一 个小增量,计算下一步的x、y值。
注意: x, y的选择.
void DDALine(int x0,int y0,int x1,int y1,int color) int i; float dx, dy, length,x,y; if (fabs(x1-x0)>=fabs(y1-y0)) length=fabs(x1-x0); else length=fabs(y1-y0); dx = (x1-x0)/length; dy=(y1-y0)/length; i=1;x= x0;y= y0; while(i<=length) { SetPixel (int(x+0.5), int(y+0.5), color); x=x+dx; y=y+dy; i++;
对于水平线、垂直线和45°线,选择哪些光栅元素是显而 易见的,而对于其它方向的直线,像素的选择较为困难。
直线绘制基本算法 给定直线段的两个端点P0(x0,y0)和 P1(x1,y1),斜率截距直线方程:
k yபைடு நூலகம்/ x ( y1 y0 ) /( x1 x0 )
y kx b
Yi +1 y
d2 d1
yi
xi xi+1 图3-3 根据误差量来确定理想的像素点
判别式(误差参数):
d1 y yi (k(xi 1) b) yi
d 2 ( yi 1) y yi 1 (k(xi 1) b)
d1 d 2 2[k ( xi 1) b] 2 yi 1 2kxi 2k 2b 2 yi 1
b y0 k x0
从起点到终点,x每次增加(或减少)1,用直线方程计 算对应的y值,再用SetPixel(x, int(y+0.5),color)输出该 像素。上述方法称为直线绘制基本算法。复杂度:乘 法+加法+取整
缺点:每步都需要一个浮点乘法运算和一个四舍五 入运算,所以效率太低。由于一个图中可以包含成 千上万条直线,所以要求绘制算法应尽可能的快。
对于每个整数x,从线段的坐标端点开始,循环的进行误差量的 计算。在起始像素(x0,y0)的参数d0为:
d0 2y x
以下是当0<k<1时的Bresenham画线算法程序: void Bresenham_Line (int x0,int y0,int x1, int y1,int color) { int dx,dy, det1,det2, i,x,y,e; dx=x1-x0; dy=y1-y0; det1=2*dy; det2=2*(dy-dx) ; x=x0;y=y0; e=2*dy-dx; for (i=0; i<=dx; i++) { SetPixel (x, y, color); x++; if (e>=0){ y++; e+=det2;} else e+=det1; } }
直线光栅化 算法
直线光栅化算法1. 概述直线光栅化算法是计算机图形学中常用的一种算法,用于将抽象的直线表示转化为具体的像素点绘制。
通过对直线的各个点进行逐一计算,可以将直线在屏幕上精确地表示出来。
本文将介绍直线光栅化算法的基本原理、具体实现过程以及一些常见优化方法。
2. 直线光栅化算法的原理直线光栅化算法的基本原理是利用数学公式计算直线上各个像素点的坐标,并将其绘制在屏幕上。
直线的坐标由两个点确定,即起点和终点。
下面是直线光栅化算法的基本步骤:2.1 计算斜率与步长首先,根据给定的起点和终点,需要计算直线的斜率和步长。
直线的斜率可以通过以下公式计算:斜率 = (终点的纵坐标 - 起点的纵坐标) / (终点的横坐标 - 起点的横坐标)步长指的是在横坐标上每前进一个单位,纵坐标需要前进多少单位。
步长的计算可以根据直线斜率的正负进行分类讨论。
2.2 根据步长逐点绘制直线在计算了直线的斜率和步长之后,可以按照以下步骤绘制直线:1.初始化当前点的坐标为起点的坐标;2.根据步长的正负,依次对当前点的横坐标和纵坐标进行加减操作,以逐点向终点绘制;3.在每个点的位置上绘制像素。
3. 直线光栅化算法的实现3.1 Bresenham算法Bresenham算法是直线光栅化算法的一种经典实现方式。
它的基本思想是通过递推方式,根据当前点的坐标和斜率来选择下一个像素点的位置。
下面是Bresenham算法的具体实现步骤:1.初始化起点的坐标和终点的坐标;2.计算直线的斜率和步长;3.计算像素点的位置,并绘制像素;4.根据当前点位置和斜率的大小关系,更新下一个像素点的坐标。
Bresenham算法的优点是计算简单,适用于直线斜率大致在0到1之间的情况。
3.2 DDA算法DDA算法是另一种常用的直线光栅化算法,它的基本思想是通过逐点增量的方式来计算直线上的像素点坐标。
下面是DDA算法的具体实现步骤:1.初始化起点的坐标和终点的坐标;2.计算直线的斜率和步长;3.根据步长逐点增量,计算下一个像素点的坐标;4.绘制像素点。
基本图形的光栅化算法
基本图形的光栅化算法如何在指定的输出设备上根据坐标描述构造基本⼆维⼏何图形(点、直线、圆、椭圆、多边形域、字符串及其相关属性等)。
图形⽣成的概念图形的⽣成:是在指定的输出设备上,根据坐标描述构造⼆维⼏何图形。
图形的扫描转换:在光栅显⽰器等数字设备上确定⼀个最佳逼近于图形的象素集的过程。
直线段的扫描转换直线的绘制要求(1)直线要直;(2)直线的端点要准确,⽆定向性⽆断裂;(3)直线的亮度、⾊泽要均匀;(4)画线的速度要快;(5)具有不同的⾊泽、亮度、线型等。
解决的问题:给定直线两端点P0(x0,y0)和P1(x1,y1),画出该直线。
逐点⽐较法:数值微分法(DDA法):增量算法直观、易实现不利于⽤硬件实现x(i+1) = x(i) + 1y(i+1) = y(i) + k中点Bresenhan算法:算法原理:根据直线的斜率确定或选择变量在x或y⽅向上每次递增⼀个单位,⽽另⼀⽅向的增量为1或0,它取决于实际直线与相邻象素点的距离,这⼀距离称为误差项。
中点Bresenham算法——算法步骤输⼊直线的两端点P0(x0,y0)和P1(x1,y1)。
计算初始值△x、△y、D=△x-2△y、x=x0、y=y0。
绘制点(x,y)。
判断D的符号。
若D<0,则(x,y)更新为(x+1,y+1),D更新为D+2△x-2△y;否则(x,y)更新为(x+1,y), D更新为D-2△y。
当直线没有画完时,重复上⼀步骤,否则结束。
改进的Bresenhan算法——算法步骤1.输⼊直线的两端点P0(x0,y0)和P1(x1,y1)。
2.计算初始值△x、△y、e=-△x、x=x0、y=y0。
3.绘制点(x,y)。
4.e更新为e+2△y,判断e的符号。
若e>0,则(x,y)更新为(x+1,y+1),同时将e更新为e-2△x;否则(x,y)更新为(x+1,y)。
5.当直线没有画完时,重复步骤3和4。
否则结束。
圆的扫描转换解决的问题:绘出圆⼼在原点,半径为整数R的圆x2+y2=R2。
光栅图形学(一):直线段的扫描转换算法
光栅图形学(⼀):直线段的扫描转换算法前⾔ 在数学上,理想的直线是没有宽度的,它是由⽆数个点构成的集合。
对直线进⾏光栅化时,只能在显⽰器说给定的有限个像素组成的矩阵中,确定最佳逼近于该直线的⼀组像素,并且按扫描线顺序。
本节介绍绘制线宽为⼀个像素的直线的三个常⽤算法:数值微分,中点画线和Bresenham算法。
数值微分法 已知过端点 P0(x0, y0),P1(x1, y1) 的直线段 L(P0, P1);直线斜率为 k = (y1 - y0) / (x1 - x0)。
于是 y i+1 = kx i+1 + b。
于是,x每增加1,y就增加k。
画点的时候还需要判断int(y+0.5)向下取整。
1// 数值微分法,伪代码2void DDAline(int x0, int y0, int x1, int y1) {3int dx, dy, x=x0, y=y0;4double k;5 dx = x0 - x1; dy = y0 - y1;6 k = dy / dx;7 draw(x, y)8while (x <= x1) {9 x += 1;10 y += k;11 draw(x, int(y+0.5));12 }13 } 效果图如下(0,1)(5, 4):中点画线法 假设线段 F(M) = ax + by + c = 0。
(a=y0-y1; b=x1-x0; c=x0y1-x1y0)。
中点画线法的思想就是对于点(x p,y p)的下⼀个点 M(x p+1,y+0.5),拿这个中点和实际点⽐较,如果实际点在中点上⽅(F(M) <0),则取(xp+1,yp+1)为下⼀个点。
如果实际点在中点下⽅(即中点代⼊直线⽅程的值⼤于0,F(M) >= 0),则取(xp+1, yp)。
为了加速计算,我们通常采⽤增量的⽅法。
假设从(x p,y p)开始画线,d的初值d0 = F(x0+1, y0+0.5)= F(x0,y0)+a+0.5。
第3章光栅扫描图形学
e=m-0.5;
P134例:用Bresenham画直线算法生成(0,0)到 (8,3)的直线段。
显示 (0,0), (1,0),(2,1),(3,1),(4,2),(5,2),(6,2),(7,3)
适合0<=m<1的第1象限直线的整数Bresenham算法 为便于硬件实现,需去掉除法运算:
令f=2*e* △x 则 f(xi+1)与f(xi)有何关系?
适合各种象限及各种斜率直线的一般Bresenham算法 Generalized-Integer-Bresenham-Line(x1,y1,x2,y2,color); int x1,y1,x2,y2,color; { int x,y, △x, △y,s1,s2,temp,interchange; x=x1; y=y1; △x=abs(x2-x1); △y=abs(y2-y1); s1=sign(x2-x1); s2=sign(y2-y1); if(△y> △x){temp= △x; △x= △y; △y=temp;interchange=1;} else interchange=0; e=2* △y- △x; for( i=1;i<= △x; i++) {putpixel(x,y,color); if(e>=0) { if(interchange=1)x=x+s1; else y=y+s2; e=e-2* △ x;} if(interchange=1)y=y+s2; else x=x+s1; e=e+2* △ y;} }
Inter.bresenham-Line(x1,y1,x2,y2,color) int x1,y1,x2,y2,color; { int x,y, △ x, △ y,e; x=x1; y=y1; △ x=x2-x1; △ y=y2-y1; e=2* △ y- △ x; for( i=1; i<= △ x; i++) { putpixel (x,y,color); if( e>=0) { y=y+1; e=e-2* △ x; } x=x+1; e=e+2* △ y; } }
直线光栅化代码
直线光栅化代码直线是计算机图形学中基础的图形元素之一,其栅化算法是计算机图形学中的重要基础部分。
本文将介绍两种直线栅化方法:DDA算法和Bresenham算法。
DDA算法DDA算法是最简单的直线栅化算法,它的基本思想是,将直线段分成N个区间,然后在每个区间中计算像素颜色值,从而得到直线的近似表示。
每个区间的斜率相同,因此只需求得一个斜率即可推导出整条直线的坐标。
DDA算法的基本步骤如下:(1)确定两点P1和P2的坐标(x1,y1)和(x2,y2),并计算出它们之间的水平和竖直距离dx和dy。
(2)计算斜率k,k=dy/dx,如果dx=0,则直线垂直于x轴。
(3)计算像素颜色值。
(4)将坐标设置为下一个像素的位置。
DDA算法的缺点是计算量较大,因为需要使用除法运算,而此类运算在大多数计算机上较为耗时。
Bresenham算法Bresenham算法是一种高效的直线栅化算法,其基本思想是利用斜率进行逐像素的计算,以确定直线上每个像素的颜色值。
(3)初始化p=2dy-dx,p是误差项。
如果p>0,则坐标y加一,并更新p=p+2dy-2dx;如果p<=0,则不变,并更新p=p+2dy。
(4)在每个步骤中,将x坐标加1,并更新p=p+2dy-2dx。
(5)重复步骤3和4直到x2被达到为止。
Bresenham算法的优点是计算量小且速度较快,因为只需要进行加法运算和比较运算。
它可以用于画出线条,圆和椭圆等图形。
总结DDA算法和Bresenham算法是计算机图形学中常用的直线栅化算法。
DDA算法基于斜率的概念,使用除法运算计算直线的坐标,适用于在小范围内完成直线栅化。
Bresenham算法利用误差项的概念进行逐像素的计算,适用于在大规模范围内完成直线栅化。
两种直线栅化算法均具有其优点和缺点,可以依据实际需求选用适当的算法。
Bresenham快速画直线算法
Bresenham快速画直线算法 现在的计算机的图像的都是⽤像素表⽰的,⽆论是点、直线、圆或其他图形最终都会以点的形式显⽰。
⼈们看到屏幕的直线只不过是模拟出来的,⼈眼不能分辨出来⽽已。
那么计算机是如何画直线的呢,其实有⽐较多的算法,这⾥讲的是Bresenham的算法,是光栅化的画直线算法。
直线光栅化是指⽤像素点来模拟直线,⽐如下图⽤蓝⾊的像素点来模拟红⾊的直线。
给定两个点起点P1(x1, y1), P2(x2, y2),如何画它们直连的直线呢,即是如何得到上图所⽰的蓝⾊的点。
假设直线的斜率0<k>0,直线在第⼀象限,Bresenham算法的过程如下:1.画起点(x1, y1).2.准备画下⼀个点,X坐标加1,判断如果达到终点,则完成。
否则找下⼀个点,由图可知要画的点要么为当前点的右邻接点,要么是当前点的右上邻接点。
2.1.如果线段ax+by+c=0与x=x1+1的交点y坐标⼤于(y+*y+1))/2则选右上那个点 2.2.否则选右下那个点。
3.画点4.跳回第2步5.结束 算法的具体过程是怎样的呢,其实就是在每次画点的时候选取与实现直线的交点y坐标的差最⼩的那个点,例如下图:关键是如何找最近的点,每次x都递增1,y则增1或者不增1,由上图,假设已经画了d1点,那么接下来x加1,但是选d2 还是u点呢,直观上可以知道d2与⽬标直线和x+1直线的交点⽐较近即纵坐标之差⼩也即与(x+1, y+1)点纵坐标差⼤于0.5,所当然是选d2,其他点了是这个道理。
⼀、算法原理简介:算法原理的详细描述及部分实现可参考:假设以(x, y)为绘制起点,⼀般情况下的直观想法是先求m = dy /dx(即x每增加1, y的增量),然后逐步递增x, 设新的点为x1 = x + j,则y1 = round(y + j * m)。
可以看到,这个过程涉及⼤量的浮点运算,效率上是⽐较低的(特别是在嵌⼊式应⽤中,DSP可以⼀周期内完成2次乘法,⼀次浮点却要上百个周期)。
03光栅图形生成算法
点相邻但又不属于该区域的像素组成了边界,不是 内点和边界的像素是外点.
光栅系统有两种区域填充算法:
扫描线填充算法:主要用于填充 多边形、圆、椭圆以及其它简单 曲线所围成的封闭区域。
种子填充算法:适用于具有复杂 形状边界的区域填充。
扫描线填充算法
本章讨论内容
直线生成算法 圆和圆弧的程序设计 区域填充算法 字符生成 反走样技术
圆的生成算法-中点圆生成算法
以单位间隔取样并在每个步长中确 定离指定圆最近的像素位置。
x2+y2-r2=0
对于给定半径r和屏幕中心(xc,yc),
运用平移:先给出计算中心在坐标原
点(0,0)圆的像素位置的算法,然后通 过将xc加到x和yc加到y而把每个计算出 的位置(x,y)移动到其适当的屏幕位置。
直线生成算法
Bresenham直线生成算法
基本原理:沿某一计长方向上,每次变化一个单 位步长,另一方向上的变化量通过计算获得。这 种方法在计算判别式时,计算量很小,生成的直 线光滑,因而应用广泛。
假设直线的斜率在0~1之间,k=△y/ △x,x的变 化率比y的变化率大,约定每次x方向变化一个像 素单位,相应y方向的变化量为0或1个像素单位。
计算判别式: 理论直线上点Q坐标为y= k(xi+1)+b;求s和t:
s=y-yi=k(xi+1)+b-yi; t=(yi+1)-y=(yi+1)-k(xi+1)-b
s-t=2k(xi+1)-2yi+2b-1 由于k=△y/△x, △x=x2-x1,△y=y2-y1,代入上式,得到
直线光栅化算法
直线光栅化算法光栅化算法是计算机图形学中的一种重要技术,用于将连续的几何图形转化为离散的光栅图像。
直线光栅化算法是其中最基础的一种,用于绘制直线段。
直线光栅化算法的基本原理是根据直线的斜率和截距,确定直线上的像素点,并将其填充为颜色。
传统的直线光栅化算法有很多,如步进法、中点画线法等。
本文将以中点画线法为例,介绍直线光栅化算法的实现原理。
中点画线法是一种比较高效的直线光栅化算法,通过计算每个像素点到直线的距离来决定是否填充该点。
具体步骤如下:1. 根据直线的起始点和终止点,计算直线的斜率k和截距b。
如果斜率大于1,则将坐标轴进行旋转,使得斜率变为小于1的情况。
这样可以统一处理所有斜率的直线。
2. 对于直线斜率在0到1之间的情况,从起始点开始,沿x轴逐个增加像素点的x坐标,然后根据直线方程计算出对应的y坐标。
计算出每个像素点与直线的距离d,如果d小于0.5,则填充该像素点。
然后根据d的值更新下一个像素点的y坐标。
3. 对于直线斜率大于1的情况,与步骤2类似,只是x和y的角色互换,即沿y轴逐个增加像素点的y坐标,然后根据直线方程计算出对应的x坐标。
通过以上步骤,可以将直线段转化为一系列的像素点,并填充相应的颜色,从而实现直线的绘制。
中点画线法的优势在于减少了浮点运算的次数,提高了绘制速度,适用于实时渲染等需要高效处理大量图形的场景。
除了中点画线法,还有其他的直线光栅化算法,如步进法和Bresenham算法。
步进法是直接根据斜率的值确定每个像素点的位置,然后进行填充。
Bresenham算法是一种更加精确的直线光栅化算法,通过对直线的误差进行累积和修正,保证了绘制的直线更加平滑。
总结起来,直线光栅化算法是计算机图形学中的重要技术,用于将直线段转化为离散的光栅图像。
中点画线法是一种高效的直线光栅化算法,通过计算像素点与直线的距离来确定是否填充该点。
除了中点画线法,还有步进法和Bresenham算法等其他直线光栅化算法,可以根据具体需求选择合适的算法。
计算机图形学实验一:画直线
贵州大学实验报告学院:计算机科学与技术专业:计算机科学与技术班级:计科131如果 d<0,则M在理想直线下方,选右上方P1点;如果 d=0,则M在理想直线上,选P1/ P2点。
由于d是xi和yi的线性函数,可采用增量计算提高运算效率。
1.如由pi点确定在是正右方P2点(d>0).,则新的中点M仅在x方向加1,新的d值为:d new=F(xi+2,yi+0.5)=a(xi+2)+b(yi+0.5)+c而 d old=F(xi+1,yi+0.5)=a(xi+1)+b(yi+0.5)+cd new=d old+a= d old-dy2.如由pi点确定是右上方P1点(d<0),则新的中点M在x和y方向都增加1,新的d值为d new=F(xi+2,yi+1.5)=a(xi+2)+b(yi+1.5)+c而 d old=F(xi+1,yi+0.5)=a(xi+1)+b(yi+0.5)+cd new=d old+a+b= d old-dy+dx在每一步中,根据前一次第二迭中计算出的d值的符号,在正右方和右上方的两个点中进行选择。
d的初始值: d0=F(x0+1,y0+0.5)=F(x0,y0)+a+b/2=a+b/2=-dy+dx/2 F(x0,y0)=0,(x0,y0)在直线上。
为了消除d的分数,重新定义 F(x,y)=2(ax+by+c)则每一步需要计算的d new 是简单的整数加法dy=y1-y0,dx=x1-x0d0=-2dy+dxd new=d old-2*dy,当 d old>=0d new=d old-2(dy-dx),当d old<0Bresenham画线算法算法原理:与DDA算法相似,Bresenham画线算法也要在每列象素中找到与理想直线最逼近的象素点。
根据直线的斜率来确定变量在x或y方向递增一个单实验内容#include"stdafx.h"#include<glut.h>#include<iostream>#include<cmath>#include<stdio.h>using namespace std;void init(){glClearColor(1.0, 1.0, 1.0, 1.0);glMatrixMode(GL_PROJECTION);glLoadIdentity();gluOrtho2D(0.0, 200.0, 0.0, 150.0);}void IntegerBresenhamline(){int x1 = 10, y1 = 10, x2 = 150, y2 = 100;int dx = abs(x2 - x1);int dy = abs(y2 - y1);int x, y;int e = -dx;if (x1 > x2){x = x2;y = y2;x2 = x1;}else{x = x1;y = y1;}glClear(GL_COLOR_BUFFER_BIT);glColor3f(1.0, 0.0, 0.0);glBegin(GL_LINES);glVertex2i(x, y);while (x < x2){if (e >= 0){y++;e = e - 2 * dx;}glVertex2i(x, y);x++; e += 2 * dy;}glEnd();glFlush();}void MidPointLine(){int x, y, x1 = 10, y1 = 10, x2 = 150, y2 = 100;int dy = y1 - y2;int dx = x2 - x1;int d = 2 * dy + dx;int dx1 = 2 * dy;int dx2 = 2 * (dx + dy);if (x1 > x2){x = x2;y = y2;x2 = x1;}else{x = x1;y = y1;}glClear(GL_COLOR_BUFFER_BIT);glColor3f(1.0, 0.0, 0.0);glBegin(GL_LINES);glVertex2i(x, y);while (x < x2){if (d<0){y++; x++;d += dx2;}else{x++, d += dx1;}glVertex2i(x, y);}glEnd();glFlush();}int main(int argc, char** argv){glutInit(&argc, argv);glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);glutInitWindowPosition(50, 100);glutInitWindowSize(400, 300);int choice;printf("输入你想画的直线 0代表Bresenham 1代表中点画线\n");while (1){scanf("%d", &choice);switch (choice){case 0:glutCreateWindow("Bresenham Draw Line");init();glutDisplayFunc(IntegerBresenhamline);glutMainLoop();break;case 1:glutCreateWindow("middle Point Line");init();glutDisplayFunc(MidPointLine);glFlush();glutMainLoop();break;default:printf("输入有误,请重新输入\n");break;}}return 0;}实验总结通过这次试验我对于中点生成算法和Bresenham生成算法有了进一步的了解,在平时上课的基础上对计算机图形学有了更深的认识,同时对课程内容也更加了解。
Bresenham算法-直线光栅化算法
Bresenham算法是计算机图形学典型的直线光栅化算法。
∙从另一个角度看直线光栅化显示算法的原理o由直线的斜率确定选择在x方向或y方向上每次递增(减)1个单位,另一变量的递增(减)量为0或1,它取决于实际直线与最近光栅网格点的距离,这个距离的最大误差为0.5。
∙1)Bresenham的基本原理o假定直线斜率k在0~1之间。
此时,只需考虑x方向每次递增1个单位,决定y方向每次递增0或1。
设直线当前点为(xi,y)直线当前光栅点为(xi,yi)则下一个直线的点应为(xi+1,y+k)下一个直线的光栅点或为右光栅点(xi+1,yi)(y方向递增量0)或为右上光栅点(xi+1,yi+1)(y方向递增量1)记直线与它垂直方向最近的下光栅点的误差为d,有:d=(y+k)–yi,且0≤d≤1当d<0.5:下一个象素应取右光栅点(xi+1,yi)当d≥0.5:下一个象素应取右上光栅点(xi+1,yi+1)如果直线的(起)端点在整数点上,误差项d的初值:d0=0,x坐标每增加1,d的值相应递增直线的斜率值k,即:d=d + k。
一旦d≥1,就把它减去1,保证d的相对性,且在0-1之间。
令e=d-0.5,关于d的判别式和初值可简化成:e的初值e0= -0.5,增量亦为k;e<0时,取当前象素(xi,yi)的右方象素(xi+1,yi);e>0时,取当前象素(xi,yi)的右上方象素(xi+1,yi+1);e=0时,可任取上、下光栅点显示。
Bresenham算法的构思巧妙:它引入动态误差e,当x方向每次递增1个单位,可根据e 的符号决定y方向每次递增 0 或 1。
e<0,y方向不递增e>0,y方向递增1x方向每次递增1个单位,e = e + k因为e是相对量,所以当e>0时,表明e的计值将进入下一个参考点(上升一个光栅点),此时须:e = e - 1∙2)Bresenham算法的实施——Rogers 版o通过(0,0)的所求直线的斜率大于0.5,它与x=1直线的交点离y=1直线较近,离y=0直线较远,因此取光栅点(1,1)比(1,0)更逼近直线;o如果斜率小于0.5,则反之;o当斜率等于0.5,没有确定的选择标准,但本算法选择(1,1)(程序)▪//Bresenham's line resterization algorithm for the first octal.▪//The line end points are (xs,ys) and (xe,ye) assumed not equal.▪// Round is the integer function.▪// x,y, ∆x, ∆y are the integer, Error is the real.▪//initialize variables▪x=xs▪y=ys▪∆x = xe -xs▪∆y = ye -ys▪//initialize e to compensate for a nonzero intercept▪Error =∆y/∆x-0.5▪//begin the main loop▪for i=1 to ∆x▪ WritePixel (x, y, value)▪if (Error ≥0) then▪ y=y+1▪ Error = Error -1▪ end if▪ x=x+1▪ Error = Error +∆y/∆x▪next i▪finish∙3)整数Bresenham算法o上述Bresenham算法在计算直线斜率和误差项时要用到浮点运算和除法,采用整数算术运算和避免除法可以加快算法的速度。
