计算机图形学 ———— 扫描线多边形填充算法 (讲解)

一.基本原理

           扫描线多边形区域填充算法是按扫描线顺序(由下到上),计算扫描线与多边形的相交区间,再用要求的颜色显示这些区间的象素,即完成填充工作。

                                       

           区间的端点可以通过计算扫描线与多边形边界线的交点获得。

           对于一条扫描线,多边形的填充过程可以分为四个步骤:

(1)求交:计算扫描线与多边形各边的交点;

(2)排序:把所有交点按x值递增顺序排序;

(3)配对:第一个与第二个,第三个与第四个等等;每对交点代表扫描线与多边形的一个相交区间;

(4)填色:把相交区间内的象素置成多边形颜色;

如图所示,扫描线 6 与多边形的边界 线交于四点A、B、C、D。
这四点把扫描线分 为五个区间 [0, 2],[2, 3.5],[3.5, 7],[7, 11], [11, 2]。
其中, [2, 3.5], [7, 11] 两个区间落在 多边形内,该区间内的象素应取多边形色。
其它区间内的象素取背景色。
这里的四个交点在计算时未必是按从左到 右的顺序获得。
例如,当多边形采用顶点序列 P1P2P3P4P5P6 表示时,把扫描线 6 分别与边 P1P2,P2P3,P3P4,P4P5,P5P6,P6P1 相 交,
得到交点序列D、C、B、A,必须经过排 序,才能得到从左到右,按 x 递增顺序排列的
交点 x 坐标序列。

二.问题

(1)当扫描线与多边形顶点相交时,交点 的取舍问题(保证交点正确配对):

     检查相交顶点的两条边的另外两个顶点的y值。按这两个y值中大于交点y值的个数是0,1,2来决定是取零个、一个、还是两个。

当扫描线与多边形顶点相交 时,会出现异常情况。例如图所示,扫描线 2 与 P1 相交。
按前述方法求得交点 ( x 坐标)序列:2,2,8。这将导致 [2, 8] 区间内的 象素取背景色,
而这个区间的象素正是属于多 边形内部,需要填充的。
所以,我们拟考虑当 扫描线与多边形的顶点相交时,相同的交点只 取一个。
这样,扫描线 2 与多边形的交点序列就成为 2,8。正是我们所希望的结果。
然而,按新的规定,扫描线 7 与多边形的 交点序列为 2,9,11。
这将导致错把[2,9]区间作为多边形内部来填充。
为了正确地进行交点取舍,必须对上述两种 情况区别对待。
在第一种情况,扫描线交于一顶 点,而共享顶点的两条边分别落在扫描线的两边 。
这时,交点只算一个。在第二种情况,共享交 点的两条边在扫描线的同一边,这时交点作为零个或两个,
取决于该点是多边形的局部最高点还是局部最低点。
具体实现时,只需检查顶点的两条边的另 外两个端点的 y 值。按这两个 y 值中大于交点 y 值的个数是 0,1,2 来决定是取零个、一 个、还是二个。
例如,扫描线 1 交于顶点 P2,由于共享该顶点的两条边的另外二个顶点 均高于扫描线,故取交点 P2 两次。
这使得 P2 象素用多边形颜色设置。
再考虑扫描线 2。在 P1 处,由于 P6 高于扫描线,而 P2 低于扫描 线,所以该交点只算一个。
而在 P6 处,由于 P1和P5均在下方,所以扫描线 7 与之相交时,交点算零个,该点不予填充。
//
(如果某一条边,平行于某一条扫描线;那这一条边,不予记录)///

(2)多边形边界上象素的取舍问题(避免填充扩大化):

对扫描线与多边形的相交区间取左闭右开。

例如,对左下角为 (1,1),右上角为(3,3)的正方形填充 时,若对边界上所有象素均进行填充,
被填充的象素覆盖的面积为 3×3 单位,而方形实际面积只有 2×2 单 位。显然,
这个扩大化问题是由于对边界上的所有象素进行填充引起的。
为了克服这个问 题,规定落在右/上边界的象素不予填充,而落在左/下边界的象素予以填充。
在具体实现时,只要对扫描线与多边形的 相交区间取*左闭右开*。
容易看出,我们在前面 一个问题所采用的方法,即扫描线与多边形顶
点相交时,交点的取舍方法,保证了多边形的 “下闭上开”——丢弃上方水平边以及上方非
水平边上作为局部最高点的顶点。
重合点的处理:当扫描线和边界相交于边界顶点时,同时产生两个交点,通常采用 “起闭终开”或“起开终闭” 。
水平边处理:水平边不参加求交计算,跳过。

三. 解决步骤

 为了计算每条扫描线与多边形各边的交点, 最简单的方法是把多边形的所有边放在一个表中。

这样处理效率很低。这是因为一条扫描线 往往只与少数几条边相交,甚至与整个多边形 都不相交。若在处理每条扫描线时,不分青红 皂白地把所有边都拿来与扫描线求交,则其中 决大多数计算都是徒劳无用的。

为了提高效率,在处理一条扫描线时,仅 对与它相交的多边形的边进行求交运算。我们 把与当前扫描线相交的边称为活性边,并把它 们按与扫描线交点 x 坐标递增的顺序存放在一个链表中,称此链表为活性边表(AET)。

 假定当前扫描线与多边形某一条边的交点的x坐标为x,则下一条扫描线与该边的交点不要重计算,只要加一个增量△x。(连贯性)

        设该边的直线方程为:ax+by+c=0;

        若y=yi,x=xi;则当y = yi+1时,

         xi+1=xi-b/a

       其中ΔX= -b/a为常数,

       另外使用增量法计算时,我们需要知道一条边何时不再与下一条扫描线相交,以便及时把它从活性边表中删除出去。

x i+1 = ( - by i+1 –c)/a = x i –b/a 其中△x = -b/a 为常量。△x 可以存放在对应 边的活性边表结点中。另外,使用增量法计算 时,我们需要知道一条边何时与下一条扫描线 相交,以便及时把它从活性边表中删除出去, 避免下一步进行无谓的计算。综上所述,活性边表的结点中至少应为对应边保存如下内容:

第1项存当前扫描线与边的交点坐标x值;

第2项存从当前扫描线到下一条扫描线间x的增量D x;

第3项存该边所交的最高扫描线号ymax;

第4项存指向下一条边的指针(Λ代表一条边的退出,即结束或抛弃);

                                   

扫描线6的活性边表  :

 扫描线7的活性边表:

 

 为了方便活性边表的建立与更新,我们为每一条扫描线建立一个新边表(NET,存放在该扫描线第一次出现的边。也就是说,若某边的较低端点为ymin,则该边就放在扫描线ymin的新边表中。

                            

1.这个结构实际上是一个指针数组,数组的每个变量是个指针,
这个指针指向所有的以这个y值作为起点的边。
2.把多边形所有的边全部填成这样的结构,插到这个指针数组里面来。
3.从上面这个指针数组里面就知道多边形是从哪里开始的。
在这个指针数组里只有1、2、3、5处有边,因此当从下往上进行扫描转换的时候,
从y=1开始做,而在1这条线上有两条边进来了,然后就把这两条边放进活性边表来处理。
4.当处理y=2这条扫描线时(活性边里有2条边),先看活性边表里是否有边要退出和加入,
实际上p1p2边要退出了(y=ymax),p1p6边要加入了。
退出的边要从活性边表里去掉,不退出的边要进行处理,即把x值加上一个增量。
(这时p1p2变后边需要加一个Λ)
5.后面持续步骤3,4,只到y=5这扫描线结束。
6.即每做一次新的扫描线时,要对已有的边进行三个处理:
一是否被去除掉;如果不被去除;
第二就要对它的数据进行更新,所谓更新数据就是要更新它的x值,即x+△x;
最后,就是有没有新的边进来,新的边在NET里,可以插入排序插进来。

四.算法描述

     这个算法过程从来没有求交,这套数据结构使得你不用求交点!避免了求交运算。

     扫描线多边形填充算法的主要步骤:

  1. 建立NET(NewEdgeList)
  2. 从最低扫描线开始到最高扫描线循环
  3. 建立或调整AET(ActiveEdgeList)
  4.  按照AET中的接点顺序填充
void polyfill (多边形  polygon, 颜色 color)
{ for (各条扫描线i )
  { 初始化新边表头指针NET [i];把ymin = i 的边放进边表NET [i];   }
   y = 最低扫描线号;
   初始化活性边表AET为空;
   for (各条扫描线i )
    { 把新边表NET[i]中的边结点用插入排序法插入AET表,使之按x坐标递增顺序排列;
      遍历AET表,把y max= i 的结点从AET表中删除,并把y max > i结点的x值递增D x;
      若允许多边形的边自相交,则用冒泡排序法对AET表重新排序;
      遍历AET表,把配对交点区间(左闭右开)上的象素(x, y),用drawpixel (x, y, color) 改写象素颜色值;
     }
}

 

  • 100
    点赞
  • 437
    收藏
    觉得还不错? 一键收藏
  • 11
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值