ComputerGraphics第四章多边形填充1多边形的定义多边形是由折线段组成的封闭图形。它由有序顶点的点集Pi(i=0,1,…,n-1)及有向边Ei(i=0,…,n-1)定义,n为多边形的顶点数或边数,且Ei=PiPi+1,i=0,…,n-1。这里Pn=P0,用以保证多边形的封闭性。2多边形的表示在计算机图形学中,多边形有两种示方法:顶点表示法和点阵表示法。图4-3多边形的顶点表示法P0P1P2P3P4P5图4-4多边形的点阵表示法3多边形的扫描转换将多边形的描述从顶点表示法变换到点阵表示法的过程,称为多边形的扫描转换。即从多边形的顶点信息出发,求出多边形内部的各个像素点信息。4-1多边形的填充这里的多边形是使用顶点表示法表示的多边形。多边形的填充是指从多边形的顶点信息出发,求出其覆盖的每个像素点,取为填充色,而将多边形外部的像素点保留为背景色。多边形填充的主要工作是确定穿越多边形内部的扫描线的覆盖区间。首先确定多边形覆盖的扫描线条数(y=ymin~ymax),对每一条扫描线,计算扫描线与多边形边界的交点区间(xmin~xmax),然后再将该区间内的像素赋予指定的颜色。在扫描线从多边形顶点的最小值ymin到多边形顶点的最大值ymax移动的过程中,重复上述工作,就可以完成多边形的填充。4-2区域填充区域是指一组具有相同属性的像素,可以理解为多边形的内部。区域的边界色和填充色不一致,填充算法只对区域内部进行填充。种子填充算法是从给定的种子位置开始,按填充颜色点亮种子的相邻像素直到颜色不同的边界像素为止、种子填充法主要有4邻接算法和8邻接算法。4.2有效边表填充算法填充原理多边形的有效边表填充算法的基本原理是按照扫描线从小到大的移动顺序,计算当前扫描线与多边形各边的交点,然后把这些交点按x值递增的顺序进行排序、配对,以确定填充区间,然后用指定颜色点亮填充区间内的所有像素,即完成填充工作。有效边表填充算法通过访问多边形覆盖区间内的每个像素,可以填充凸、凹多边形和环,已成为目前最为有效的多边形填充算法。边界像素的处理原则在多边形填充过程中,常采用“下闭上开”和“左闭右开”的原则对边界像素进行处理。极值点的处理原则对局部最高点,根据“下闭上开”的原则不予填充。对局部最低点的处理方法为,填充时设置一个逻辑变量(初始值为假),每访问一个结点,逻辑变量值取反一次,若逻辑变量值为真,则填充该区间,这样可以保证局部最低点处理正确。设多边形P的顶点为Pi=(xi,yi),i=0,1,…,n-1,这些顶点可以分为两类:极值点和非极值点。如果(yi-1-yi)(yi+1-yi)≥0,则称顶点Pi为极值点(如P0、P3、P5和P4点);否则称为非极值点(如P2点)。为使每一条扫描线与多边形P的边界的交点个数始终为偶数,规定当点是多边形P的极值点时,该点按两个交点计算,否则按一个交点计算。对于每一条扫描线,多边形的填充步骤为:①计算扫描线与多边形各边的交点,设交点个数为n。②把所有的交点按x值递增的顺序进行排列。③将排序后的第1个和第2个交点,第3个和第4个交点,…,第n-1个和第n个交点配对,每对交点就代表扫描线与多边形的一个相交区间。④把相交区间内的像素置成多边形的颜色,相交区间外的像素设置成背景色。多边形内与当前扫描线相交的边称为有效边。设有效边的斜率为k。假定有效边与当前扫描线yi的交点为(xi,yi),则有效边与下一条扫描线yi+1的交点为(xi+1,yi+1)。其中,xi+1=xi+1/k=xi+⊿x/⊿y,yi+1=yi+1。。(xi+1,yi+1)(xi,yi)1/k图4-11有效边交点相关性有效边把有效边按照与扫描线交点x坐标递增的顺序存放在一个链表中,称为有效边表,有效边表的结点如下:xymax1/knextx:当前扫描线与有效边的交点ymax:边所在的扫描线最大值1/k:斜率的倒数Next:指向下一条边的指针有效边表有效边表的数据结构:classCAET//有效边表类{public:CAET();//构造函数virtual~CAET();//析构函数doublex;intyMax;doublek;//程序中令k=⊿x/⊿yCAET*next;}边表是按照扫描线顺序管理边的出现情况的一个数据结构。首先,构造一个纵向扫描线链表,链表的长度为多边形所占有的最大扫描线数,链表的每个结点称为桶,对应多边形覆盖的每一条扫描线。将每条边的信息链入与该边最小y坐标(ymin)相对应的桶处。也就是说,若某边的较低端点为ymin,则该边就存放在相应的扫描线桶中。边表对于每一条扫描线,如果新增多条边,则按x|ymin坐标递增的顺序存放在一个链表中,若x|ymin相等,则按照1/k由小到大排序,这样就形成边表,如图4-14所示。x|yminymax1/knext图4-14边表结点其中,x为新增边低端的x|ymin值,用于判断边表在桶中的排序;ymax是该边所在的最大扫描线值,用于判断该边何时成为无效边。1/k是边在x方向的变化量和在y方向的变化量的比值,即△x/△y。边表是有效边表的特例,即该边的最低点处的有效边表,有效边表和边表可以使用同一个数据结构来表示。1211109876543211312345678910111213OyxP0P1P2P3P4P5P6图4-13示例多边形对于图4-13所示的多边形,顶点表示法为:P0(7,8),P1(3,12),P2(1,7),P3(3,1),P4(6,5),P5(8,1),P6(12,9)。边表37-1/3P2P3353/4P3P485-1/2P4P5891/2P5P6S=12S=2S=3S=4S=5S=6S=7S=8S=9S=10S=11S=11122/5P1P2712-1P0P1795P0P6图4-15边表算法设计(1)根据多边形顶点坐标值,计算扫描线的最大值ScanMax和最小值ScanMin.(2)用多边形覆盖的扫描线动态建立桶结点。(3)循环多边形的所有顶点,根据边的终点y值比起点y值高或边的终点y值比起点y值低两种情况(相等的情况属于扫描线,不考虑),计算每条边的ymin.在桶中寻找与该ymin相应的桶结点,计算该边表的x|ymin、ymax、k(代表1/k),并依次连接该边表结点到桶结点。(4)对每个桶结点连接的边表根据x|ymin值的大小进行排序,若x|ymin相等,则按照由小到大排序。(5)对每个桶结点进行循环,将桶内每个结点的边表合并为有效边表,并进行有效边表循环。(6)从有效边表中取出相邻两条边的交点对进行填充。填充时设置一个逻辑变量In(初始值为假),每访问一个结点,把In值取反一次,若In为真,则把从当前结点的x值开始到下一结点的x-1值结束的区间用指定颜色填充。(7)对下一桶结点进行循环,按照xi+1=xi+k(k值为1/k)修改有效边表,同时合并桶节点内的新边表,形成新的有效边表。(8)如果桶结点的扫描线值大于等于有效边表中某个结点的ymax值,则放弃该有效边表。(9)当桶结点不为空则转(5),否则删除桶结点和边结点的头结点,算法结束。多边形的7个顶点坐标为:P0(500,400),P1(350,600),P2(250,350),P3(350,50),P4(500,250),P5(600,50),P6(800,450)试用以下方法填充该多边形1有效边表填充算法2边缘填充算法3区域四邻接点填充算法多边形填充算法上机练习4.3边缘填充算法4.3.1填充原理4.3.2填充过程4.3.1填充原理边缘填充算法是求出多边形的每条边与扫描线的交点,然后将交点右侧的所有像素颜色全部取为反色。按任意顺序处理完多边形的所有边后,就完成了多边形的填充任务。4.3.2填充过程假定边的顺序为E0、E1、E2、E3、E4、E5、E6,如图4-16所示。填充过程如图4-17所示。图4-16边缘填充算法示例多边形P0(x0,y0)P1(x1,y1)E0E1E2E3E4E5E6图4-17边缘填充算法原理4.4区域填充算法4.4.1填充原理用点阵方法表示的多边形区域,如果其内部像素具有同一种颜色,而边界像素具有另一种颜色,可以使用种子算法进行填充。种子填充算法是从区域内任一个种子像素位置开始,由内向外将填充色扩散到整个多边形区域的填充过程。4.4.2四邻接点和八邻接点四邻接点对于多边形区域内部任意一个种子像素,其左、上、右、下这4个像素称为四邻接点。八邻接点对于多边形区域内部任意一个种子像素,其左、左上、上、右上、右、右下、下、左下这8个像素称为八邻接点。四邻接点定义八邻接点定义4.4.3四连通域和八连通域1四连通域定义从多边形区域内部任意一个种子像素出发,通过访问其左、上、右、下这4个邻接点可以遍历区域内的所有像素点,该多边形区域称为四连通域。四连通域的边界可以使用四连通边界和八连通边界。四连通域及其四连通边界四连通域及其八连通边界2八连通域定义从多边形区域内部任意一个种子像素出发,通过访问其左、左上、上、右上、右、右下、下、左下这8个邻接点可以遍历区域内的所有像素点,该多边形区域称为八连通域。八连通域的边界必须使用八连通边界。八连通域及其四连通边界八连通域及其八连通边界对如图所示的八连通域,假定种子像素位于多边形区域的左下部区域内,则四邻接点算法只能填充其左下部区域,不能进入其右上部区域。八邻接点算法则可以从其左下部区域进入右上部区域,填充完整个多边形区域。1算法定义从种子像素点开始,使用四邻接点方式搜索下一像素点的填充方式称为四邻接点填充算法。从种子像素点开始,使用八邻接点方式搜索下一像素点的填充方式称为八邻接点填充算法。四邻接点填充算法的缺点是不能通过狭窄区域,即不能填充八连通域。八邻接点填充算法既可以填充四连通域,也可以填充八连通域。4.4.4四邻接点填充算法和八邻接点填充算法2算法原理种子填充算法一般要求区域边界色和填充色不同,输入参数只有种子坐标位置和颜色。种子填充算法一般需要使用堆栈数据结构来实现。算法原理为,先将种子像素入栈,种子像素为栈底像素,如果栈不为空,执行如下操作:(1)栈顶像素出栈。(2)按填充色绘制出栈像素。(3)按左、上、右、下(左、左上、上、右上、右、右下、下、左下)顺序搜索与出栈像素相邻的四(八)个像素,若该像素的颜色不是边界色并且未置成填充色,则把该像素入栈;否则丢弃该像素。3扫描线种子填充算法种子填充算法会把大量的像素压入堆栈,有些像素甚至入栈多次,不但降低了算法的效率,而且占用了很大的存储空间。有效地改进方法是使用扫描线种子填充算法。算法原理为,先将种子像素入栈,种子像素为栈底像素,如果栈不为空,执行如下操作:(1)栈顶像素出栈。(2)沿扫描线对出栈像素的左右像素进行填充,直到遇到边界像素为止。同时记录该区间,其最左端像素记为xl,最右端像素记为xr。(3)在区间[xl,xr]上,检查与当前扫描线相邻的上下两条扫描线的有关像素是否全为边界色或填充色,若存在非边界且未填充的像素,则把上下扫描线的最右端像素取为种子像素入栈,该种子像素的横坐标为xr或xr-1。4.5小结本章主要讲解多边形的填充原理。有效边表算法可以访问多边形内的每个像素,是光照模型的基础。AET表示的是扫描线在一条边上的连贯性,ET表示的是最新边在扫描线上的插入位置,ET是AET的特例。种子填充算法主要包括四邻接点算法和八邻接点算法,特别要注意区分四连通域和八连通域。