图形学(5)多边形的扫描转换(下)

来源:互联网 发布:大数据用什么语言最好 编辑:程序博客网 时间:2024/05/16 07:57

本模块内容绝大部分是在慕课上看中国农业大学网客时的笔记,因此算作转载,在此鸣谢赵明、李振波两位老师,感谢他们录制该门课程供大家学习!

X-扫描线改进算法

由于X-扫描线算法的效率问题,下面给出如何巧妙地避免算法中的求交运算从而提高效率。

 

重要思想

进行改进之前首先我们要再提一提两个图形学中重要的思想

  1. 扫描线:用扫描线扫描的方法处理图形图像
  2. 增量:利用直线等图形的几何特性尽量避免乘法而改为简单的加法运算

改进思路

接下来,我们考虑求交过程是否也能用增量思想进行简化、如何简化。思考的思路有以下几个方面

  1. 在处理一条扫描线时,仅对与它相交的边(有效边)求交
  2. 考虑扫描线的连贯性:当前扫描线的交点顺序与下一条扫描线与各边的交点顺序很可能相同或非常相似
  3. 考虑多边形的连贯性:某条边与当前扫描线相交时,很可能也与下一条扫描线相交
于是,我们对多边形边的表述方式进行改进,引进一套特殊的数据结构来表达它们

数据结构

活性边表(Active Edge Table,AET)

定义:

把与当前扫描线相交的边称为活性边,把它们按照与扫描线交点x坐标递增的顺序存放在一个链表中,就构成了活性边表。

节点内容:

X-->Δx-->ymax-->next

x表示当前扫描线与边的交点坐标

Δx表示从当前扫描线到下一扫描线,交点x值的变化量

ymax表示该边所交的最高扫描线的坐标值

蕴含思想:

  1. 由于多边形的边是直线,因此Δx的值一般是定值。即x7=x6+1/k,Δx=1/k这样(须注意考虑斜率为0的情况)
  2. 保存ymax是希望知道该边什么时候不再与下一条扫描线相交,以便及时将它从有效边表中移除,避免下一步进行不必要的运算

新边表(New Edge Table,NET)

为了方便活性边表的建立与更新,我们构造一个新边表协助存放多边形信息。

NET节点信息:

  • 该边的ymax,
  • 该边较低点的x坐标xmin,
  • 该边的斜率倒数1/k,
  • 指向下一条具有相同较低y坐标的边的指针next

NET的构造步骤:


  • 构造一个纵向链表,链表长度为多边形所占的最大扫描线数,该链表的每个节点成为一个“吊桶”,对应多边形覆盖的每一条扫描线
  • NET挂在与该边低端y值相同的扫描线吊桶中,换句话讲就是,存放在第一次扫到它的扫描线处

 

每做一次新的扫描时,我们需要对已有的边进行三个处理:

  1. 是否被去除掉
  2. 如果不被去除,就需要对其进行数据更新,更新它的x值:x+=1/k
  3. 看有没有新的边进来,新的边在NET中,可以通过插入排序插进来

 

算法逻辑:

  1. 初始化NET表为空
  2. 按扫描线顺序构建NET表,即将ymin=i的边放入NET[i]
  3. 初始化AET表为空,进行如下操作
    1. a) 按扫描线顺序将NET表中的边节点NET[i]用插入排序法插入到AET表中,按x坐标递增顺序排列
    2. b) 遍历AET表,将配对交点区间填色
    3. c) 遍历AET表,将ymax=i的节点从AET表中删除,将ymax>i节点的x值递增Δx
*注:若允许多边形的边自相交,c)之后要用冒泡排序法对AET表重新排序

 

多边形扫描转换算法小结

扫描线算法可以实现已知任意多边形域边界的填充,该填充算法是按扫描线的顺序,计算扫描线与多边形相交出的“内”区间进行填充。

为了解决效率问题,我们用到了增量思想,连贯性思想,还建立了一套特殊的数据结构来避免求交运算。

其不足之处在于,它无法对未知边界的多边形进行填充,也就是说想用这套算法,必须首先得到多边形的几何信息

 

多边形填充算法扩展

边缘填充算法

边缘填充算法基本思想是按任意顺序处理多边形的每条边,对处理的边用扫描线扫描,将交点右侧所有像素取补,以此代替交点的排序、配对。根据“像素点颜色经过偶数次取补运算后颜色不变”,因此待所有边处理完毕后,即可完成填充。过程如图:

 

其不足之处在于有些像素可能被访问多次,其效率比有效边算法低得多。因此我们一般不直接去用它,但它所蕴含的思想确实很精妙,下面的算法多少都对其有所借鉴。

 

栅栏填充算法

栅栏填充算法借鉴边缘填充算法的思想并对其改进,其原理是用栅栏(一条过多边形顶点并与扫描线垂直的直线)将多边形分成两部分,然后用扫描线与多边形的边求交,将所有交点依次与栅栏的中间部分取补,从而提高效率

 

(图来自新浪博客)

 

边界标志算法

边界标志算法其原理是对多边形的每条边进行扫描,并对边界像素打上标志。然后再利用扫描线扫描该多边形,对于与多边形相交的扫描线依从左到右的顺序,逐个访问该扫描线上的像素。用一个boolean类型inside来表示当前点是否在多边形内。Inside的初值为假,每当当前访问的像素是被打上边标志的点时,就把inside取反。对未标志的像素,inside不变,然后对像素进行填色。若inside为真,说明该像素在多边形内。

这个算法的优点在于其不需建立维护边表,当然也不用对它进行排序,更适合硬件实现,这时它的速度比有序边表快一两个数量级。

需注意的是,如果一条扫描线上有两个边界点,就会出现“偶数次取补颜色不变”的问题,需要附加专门的代码进行判断以避免该情况发生


原创粉丝点击