第3章生成算法
- 格式:doc
- 大小:112.50 KB
- 文档页数:11
55 01e r =− (3-39) 这样,由于判别式的初值为整数,增量也为整数,因此判别式始终为整数,即中点画圆算法可用整数加减运算来计算圆周上所有像素的位置。
中点画圆算法的描述如下。
(1)输入圆的半径r 和圆心坐标(x c , y c ),先计算以原点为圆心、r 为半径的圆周上的点,令初始点为00(,)(0,)x y r =。
(2)求初始判别式d ,1d r =−。
(3)在每一个x n 的位置,从n = 0开始,进行下列检测:如果d <0,则圆心在原点的圆的下一个点为(x n +1, y n ),且23n d d x =++;否则,圆的下一个点为(x n +1, y n −1),且2()5nn d dx y =+−+。
(4)确定(x n+1, y n +1)在其余7个八分圆中的对称点位置。
(5)将计算出的每个像素位置(x , y )平移到圆心位于(x c , y c )的圆的轨迹上,即分别沿水平和垂直方向平移x c 和y c ,平移后的坐标值为(x', y' ),c x x x ′=+,c y y y ′=+。
(6)重复第(3)至(5)步,直到x ≥y 时为止。
下面以半径r = 10、圆心在原点的圆为例来说明按上述算法计算第一八分圆上的像素位置的过程。
首先求出初始点(x 0, y 0) = (0, 10),判别式d 0 = 1−r =1−10 = −9,其后续的判别式计算结果和生成的像素位置如表3-1所示。
经过计算最后生成的从(x 0, y 0)到(x 7, y 7)第一八分圆上的8个像素位置如图3-8所示。
表3-1以原点为圆心r =10的第一八分圆的判别式的值和像素位置 n d 2x n + 32x n − 2y n + 5 (x n , y n ) 0 −9 3- (0, 10) 1 −6 5- (1, 10) 2 −1 7- (2, 10) 3 6 -−9 (3, 10) 4 −3 11- (4, 9) 5 8 -−3 (5, 9) 6 5 -1 (6, 8) 7 6 - - (7, 7)3.2.4 Bresenham 画圆算法与中点画圆算法一样,Bresenham 画圆算法也是先考虑圆心在原点、半径为r 的第一四分圆的生成,即取(0, r )为起点,按顺时针方向生成第一四分圆,然后根据圆的对称特性通过对称变换生成整圆。
头歌数据结构与算法课程设计-算法与竞赛(第3章)-C++与算法基础⼆Algorithm 中⽂意思是算法,是⼀个计算的具体步骤,常⽤于数据处理、计算以及⾃动推理。
它作为 C++ 标准模版库 STL 中最重要的头⽂件之⼀,其提供了⼤量⾮成员模版函数,例如排序操作、⼆分查找操作、集合操作以及堆操作等。
同时可以通过迭代器或指针访问任何对象序列,例如 STL 容器数组或实例。
更多的了解请参考。
本实训主要设置了四个关卡:第⼀关和第⼆关介绍了 Algorithm 中的⼆分搜索操作 binary_search 及其相关搜索操作;第三关是修改序列操作 Modifying sequence operations ;第四关讲的是⾮修改序列操作 Non-modifying sequence operations 。
最后在每个关卡都设置了实例,考察学员对所讲内容的理解和在线编程能⼒。
第1关:⼆分查找:在N个⽆序整数⾥⾯查找M个指定整数任务描述本关任务:给定包含 N 个整数的⽆序序列 S(a1,a2,..,aN),以及 M 次查询序列 Q(b1,b2,..,bM),判定 bj是否在序列 S 中。
相关知识为了完成本关任务,你需要掌握:1.解题思路,2.快速排序算法,3.⼆分查找算法。
解题思路本关卡问题清晰,解法简单:对于每次查询bj,在序列S中遍历ai是否等于bj。
虽然该解法实现简单,但是执⾏效率低,运算复杂度⾼O(N×M)。
⾼效解法:⾸先运⽤快速排序算法,将⽆序序列变为有序(升序),然后对每次查找操作,使⽤⼆分查找算法判断元素是否存在。
该解法实现稍微有点复杂,但是执⾏效率⾼,运算复杂度低O(N×logN+M×logN)。
快速排序算法快速排序算法的背景和原理前⾯已有很多实训介绍过了,为了⽅便实现,⼀般使⽤ algorithm 中模板函数 sort ,请认真参考的第三个关卡,之后的实训将不再对sort进⾏讲解。
第3章自适应波束形成及算法(3.2自适应波朿形成的几种典型算法)3.2自适应波朿形成的几种典型算法自适应波束形成技术的核心内容就是自适应算法。
U前已提出很多著名算法,非盲的算法中主要是基于期望信号和基于DOA的算法。
常见的基于期望信号的算法有最小均方误差(MMSE)算法、小均方(LMS)算法、递归最小二乘(RLS)算法,基于DOA算法中的最小方差无畸变响应(MVDR)算法、特征子空间(ESB)算法等叫3.2.1基于期望信号的波束形成算法自适应算法中要有期望信号的信息,对于通信系统来讲,这个信息通常是通过发送训练序列来实现的。
根据获得的期望信号的信息,再利用MMSE算法、LMS算法等进行最优波束形成。
1.最小均方误差算法(MMSE) 最小均方误差准则就是滤波器的输出信号与需要信号之差的均方值最小,求得最佳线性滤波器的参数,是一种应用最为广泛的最佳准则。
阵输入矢量为:兀(“)=[召(“),...,心(n)f(3-24)对需要信号d(n)进行估计,并取线性组合器的输出信号y(”)为需要信号〃(“)的估计值d(n)f即d(n) = y(n) = w H x(n) = x' (n)w(3-25)估计误差为:e(〃)= = d(n)-w n x(n)(3-26)最小均方误差准则的性能函数为:§ = £{le⑴鬥(3-27)式中纠}表示取统计平均值。
最佳处理器问题归结为,使阵列输出y(n) = w T X(n)与参考信号〃⑴的均方误差最小,即:MinE{ I ⑴门(3-28)式(3-28)也就是求最佳权的最小均方准则。
由式(3-26)〜(3-28)得:§ = E{ I e(/) I2 ) = E{e(ii)e\n)} =E{ I d(n)f}-2 Re[vr7r v J + w HR^w(3-29)其中,Re表示取实部,并且:= E[x(n)x n (n)](3-30)为输入矢量x(“)的自相关矩阵。
65 3.4.3 有序边表算法1.简单的有序边表算法由于3.4.2小节介绍的一般多边形的扫描线填充算法是建立在按扫描顺序对多边形的边与扫描线交点进行排序的基础上的,所以称为有序边表算法。
将简单的有序边表算法描述如下。
(1)数据准备。
① 求出多边形各条边与中心扫描线的交点,并将各交点坐标(x , y +0.5)存入表中。
② 按扫描线以及扫描线上交点x 值的递增顺序对该表中存放的交点进行排序,形成有序边表。
(2)扫描转换。
① 按(x 1, y 1)和(x 2, y 2)成对地取出有序边表中的交点坐标值,表的构造保证有y = y 1 = y 2及 x 1≤ x 2。
② 在扫描线y 上激活那些x 的整数值满足x 1≤ x +0.5≤ x 2关系的像素。
2.简单有序边表算法的效率问题及解决方法简单的有序边表算法存在3个问题:一是需要生成一个很大的交点表,而且需要对整张表排序;二是求交计算中含有乘除法运算,运算复杂;三是交点计算的次数多,这是因为在计算交点时,相当于是把多边形的所有边放在一个表中,按顺序依次取出,计算该边与当前扫描线的交点,而事实上并非所有的边都与当前扫描线有交点,因此增加了许多不必要的求交计算量。
可见,求交和交点排序的计算量大是影响该算法效率的最主要的因素,为了提高算法的效率,应该尽量减少和简化求交计算。
那么如何减少和简化求交计算呢?采用活性边表的有序边表算法可以有效解决这个问题。
采用活性边表的有序边表算法与简单有序边表算法的不同之处在于,它对每条扫描线都建立一个活性边表。
那么什么是活性边和活性边表呢?我们把与当前扫描线有交点的边,称为活性边,而把用于存储活性边的表称为活性边表。
在每一个活性边表中,活性边按与扫描线交点x 坐标递增的顺序存放在一个链表中。
因此,采用活性边表后,不仅节省了求交的时间,而且还节省了交点排序的时间。
下面的问题是,在活性边表中应该存储活性边的哪些信息呢?由于存储活性边的目的是要保证存储的这些信息对计算活性边与扫描线的交点有用。
第三章 基本图形生成算法(书P107)本章讲直线、圆弧的生成及多边形填充的算法。
一.概念◆ 基本图形元素:指构成图形的基本元素,例如:点、直线、圆弧等。
◆ 象素:屏幕上的光点,它是最小的屏幕显示单位,其大小取决于显示器的尺寸和分辨率。
用坐标表示。
◆ 生成图形:确定最佳逼近于图形的象素,用图形颜色对象素进行写操作。
这称为图形的扫描转换。
◆ 生成直线的质量要求:①直线要直。
②直线的端点要准确,即无定向性和断裂情况。
③直线的亮度、色泽均匀。
④画线的速度要快。
二.直线生成算法下面介绍画一个象素宽的直线的三种常用算法:1.数值微分法(DDA )所谓DDA 法就是先计算出直线的斜率K=xy ∆∆(其中Δy =y 1- y 0 , Δx= x 1- x 0 ,而(x 0 ,y 0)和(x 1 ,y 1)分别是直线的起点和终点),然后从直线的起点开始,确定最佳逼近于直线的y 坐标,让x 从起点到终点变化,x 每递增1,计算对应的y 坐标。
令y=kx+b, 当x i+1 =x i +Δx 时y i+1=kx i+1+b=k(x i +Δx)+b= kx i +Δxk+b= kx i +b+Δxk= y i +Δxk= y i +k算法如下:DDAline(x0,y0,x1,y1,color)int x0,y0,x1,y1,color;{int x;float dx,dy,k,y;dx=x1-x0;dy=y1-y0;k=dy/dx; 注意+0.5y=y0;for (x=x0;x<=x1;x++){putpixel (x,(int)(y+0.5),color); y=y+k;} 网格的交点表示象素}注意上述算法仅适用于│k│<=1的情况,见程序linedda.c 。
若│k│>1,必须把x,y 的角色互换,y 每增加1,x 相应增加1/k 。
书P108 的算法(DDA.c )综合了各种情况。
2.中点画线法则y方向上的增量只能是0或1。
如图中假设P与直线最接近的象素已确定,其坐标为(x p ,y p),那么下一个与直线最近的象素只能是P1(x p +1¸ y p)或P2(x p +1¸ y p+1)两者之一。
用M表示P1与P2的中点,即M=(x i +1¸ y i+0.5)。
若M在直线上方,则取P1 ;否则取P2。
这就是中点画线法的基本原理。
下面讨论中点画线法的实现。
设直线的起点和终点分别为(x0 ,y0)和(x1 ,y1),则直线方程为:F (x,y)= y-kx-b=0 其中,k为斜率,b为截距。
对于直线上的点F(x,y)=0; 对于直线上方的点F(x,y)>0; 对于直线下方的点F(x,y)<0。
因此要判断上图中Q(直线与垂直线的交点)在中点M的上方还是下方,只要把M代入F(x,y),并判断它的符号。
即F(M)=F(xi +1,yi +0.5)= yi +0.5–k(xi +1)–b,当F(M)<0时,M在直线的下方(即在Q的下方),故应取右上方的P2作为下一个象素。
而当F(M)>0时,则应取正右方的P1作为下一个象素。
当F(M)=0时,二者一样合适,可任选一个。
算法如下:MidpointLine(x0,y0,x1,y1,color)int x0,y0,x1,y1,color;{ int x,y;float mid,k,b;k=(y1-y0)/(x1-x0);b=y0- k* x0;x=x0;y=y0;putpixel(x,y,color);do{ mid= y+0.5– k*(x+1)-b;if (mid<0) y++;x++;putpixel(x,y,color);} while (x<x1);}注:0<=k<=1。
为提高运算效率,可计算出mid的递推关系式,推导过程如下:在mid>=0的情况下,取正右方象素P1,欲判断再下一个象素应取那个,递推关系式为:F(x i+2 ,y i+0.5)= y i +0.5 -k(x i +2)-b= y i +0.5-k(x i +1)-b-k;= mid-k;在mid<0的情况下,则取右上方象素P2,要判断再下一个象素,则要计算F(x i+2 ,y i+1.5)= y i +1.5-k(x i +2)-b= y i +0.5-k(x i +1)-b+1-k=mid+1-k;F(M)的初始值为:F(x 0 +1,y 0 +0.5)= y 0 +0.5-k (x 0 +1)-b= y 0 -kx 0 - b + 0.5-k= F(x 0 ,y 0)+0.5-k=0.5-k由于(x 0 ,y 0 )在直线上,故F(x 0 ,y 0 )=0。
这样算法改为:MidpointLine(x0,y0,x1,y1,color)int x0,y0,x1,y1,color;{ int x,y,mid,dx,dy,d_up,d_down;dy=y1-y0;dx=x1-x0;mid=dx-2*dy; /*mid 应该为0.5-k , 为了摆脱实数运算扩大2dx 倍*/d_up =2*dx - 2*dy;d_down = -2*dy; /*注意扩大了2dx 倍*/x=x0;y=y0;while (x<=x1){ putpixel(x,y,color);x++;if (mid<0) {y++;mid=mid+d_up;}else mid=mid+ d_down;}}作业1:用中点画线法光栅化一条连接两点(0,0)和(5,3) 的一条直线。
3.Bresenham 画线算法Bresenham 也是通过在每列象素中确定与理想直线最近的象素来进行画线的。
该算法是最为流行的画线方法,它将直线方程转换成一个迭代过程。
与中点画线法类似,只是判中点的方法不同。
如下图所示,只要判直线与垂线的交点到网格线的距离d ,当d>0.5往右上方走一步(当x i+1 =x i +1时, y i+1 =y i +1) ;当d<0.5时,往正右方走一步(当x i+1 =x i +1时, y i+1 =y i )。
从上图可得:⎩⎨⎧>-+<+=+时当时当5.015.01i ii i i d k d d kd d 为计算方便,令e=d-0.5, 所以有:⎩⎨⎧>-+=--+<+=-+=+时当时当015.0105.01i i i i i i i e k e k d e k e k d e初始的e 0= -0.5. 即有:⎪⎩⎪⎨⎧⎩⎨⎧>+<=+=++)()(010111i i i i i i i e y e y y x x这种方法比中点画线法简单。
算法如下:BrsenhamLine(x0,y0,x1,y1,color)int x0,y0,x1,y1,color;{int x,y,dx,dy,i;float k,e;dx=x1-x0;dy=y1-y0;k=dy/dx;e=-0.5;x=x0;y=y0;for(i=0;i<=dx;i++){ putpixel(x,y,color);x++; e=e+k;if (e>0){y++;e=e-1;}}}此算法适用于0<=k<=1。
此算法中用到除法,改进后见P113。
作业2:从键盘输入封闭多边形的端点坐标(任意斜率),试分别采用中点画线算法和Bresenham 算法画出该多边形。
(上机实现)三.圆的生成算法画圆的方法很多。
在本节中,主要讨论三种生成圆的算法一般方法有:直角坐标法:根据圆的方程x 2+y 2=R 2 来生成,如x i+1=x i +1, y=(int)(212+-i x R +0.5)。
极坐标法:用圆的极坐标方程(参数方程)圆x2+y2=R2的参数方程为:x=R*cosθy=R*sinθ 0<=θ<=360#include<graphics.h>#include<math.h>#define pi 3.14159main(){int driver,mode,x,y,maxx,maxy,r=60;float t;driver=DETECT;initgraph(&driver,&mode,"");maxx=getmaxx();maxy=getmaxy();line(0,maxy/2,maxx,maxy/2);line(maxx/2,0,maxx/2,maxy);for (t=0;t<=2*pi;t+=0.01){ x=maxx/2+r*cos(t);y=maxy/2+r*sin(t);if (t==0)moveto(x,y);lineto(x,y);}getch();closegraph();}1.绘圆的正负法设所要画的圆的圆心在(a,b),半径为R,则圆的方程为:F(x,y)= (x- a)2 +(y- b)2-R2=0,当点(x,y)在圆内时,F(x,y)<0;当点(x,y)在圆外时,F(x,y)>0。
现以画第一四分之一圆弧(第一象限)为例说明正负画圆算法。
设P i (x i,y j)是已求得的象素点,那么找下一个点P i+1的原则为:当F(x i,y j)<=0时,取x i+1 = x i +1,y i+1 = y i当F(x i,y j)>0时,取x i+1 = x i,y i+1 = y i–1F(x i,y j)<0说明P i在圆内,要向右走一步得P i+1,即向圆外方向走去;F(x i,y j)>0, 说明P i在圆外,要向下走一步得P i+1,即向圆内方向走去。
向圆内或圆外走是取决于F(x,y)的正负,因此称为正负法。
设F(x i,y j)的值已经算出,在计算F(x i+1,y j+1)时有下列两种情况:当F(x i,y j)<=0时,F(x i+1,y j+1)= F(x i+1,y j)=(x i+1-a)2+(y i-b)2–R2=(x i-a)2+(y i-b)2–R2 +2(x i -a)+1= F(x i,y j) +2(x i -a)+1当F(x i,y j)>0时,F(x i+1,y j+1)= F(x i,y j-1)=(x i-a)2+(y i-1-b)2–R2=(x i-a)2+(y i-b)2–R2 -2(y i -b)+1= F(x i,y j)- 2(y i -b)+1具体算法如下:PMcircle(a,b,r,color)int a,b,r,color;{int x,y,f;x=a,y=b+r;f=0;while (x<=a+r){putpixel(x,y,color);if(f<=0){f+=2*(x-a)+1;x++;}else {f=f-2*(y-b)+1;y--;}}}见程序circle1.c下面只讨论圆的中心在坐标的原点(0,0),半径为整数R的圆,圆的方程为x2 +y2= R2。