第 4 章 二维填充图元的生成

78
1 计计计计 计计计计计计 计计计计计计 计4计 计计计计计计计计计

Upload: alvis

Post on 24-Jan-2016

171 views

Category:

Documents


6 download

DESCRIPTION

第 4 章 二维填充图元的生成. 本章目标. 掌握如何绘制填充图元(矩形、多边形等) 扫面转换算法(扫描线算法) 填充算法 学会使用 OpenGL 的绘制函数. 主要内容. 填充图元 扫描转换矩形 扫描转换多边形 扫描转换扇形区域 区域填充 以图像填充区域 字符的表示与输出 OpenGL 相关函数. 4.1 填充图元. 填充( Filling ) 矩形 (Rectangle) 多边形 (Polygon) 扇形 (Ellipse Arc) 步骤 确定那些像素位于填充图元的内部 用指定颜色绘制这些像素 两类方法 - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: 第 4 章 二维填充图元的生成

1

计通学院 计算机科学系

计算机图形学

第 4 章 二维填充图元的生成

Page 2: 第 4 章 二维填充图元的生成

2

本章目标掌握如何绘制填充图元(矩形、多边形等)

扫面转换算法(扫描线算法) 填充算法

学会使用 OpenGL 的绘制函数

Page 3: 第 4 章 二维填充图元的生成

3

主要内容填充图元扫描转换矩形扫描转换多边形扫描转换扇形区域区域填充以图像填充区域字符的表示与输出 OpenGL 相关函数

Page 4: 第 4 章 二维填充图元的生成

4

4.1 填充图元填充( Filling )

矩形 (Rectangle) 多边形 (Polygon) 扇形 (Ellipse Arc)

步骤 确定那些像素位于填充图元的内部 用指定颜色绘制这些像素

两类方法 扫描转换( Scan Converting ) : 参数- > 点阵 填充( Filling ) : 点阵- > 点阵

Page 5: 第 4 章 二维填充图元的生成

5

4.2 扫描转换矩形含义

用指定颜色填充矩形内部区域定义矩形的参数

左下角坐标 (xmin, ymin) 右上角坐标 (xmax, ymax)

void FillRectangle(Rectangle *rect,int color)

{ int x,y;

for(y = rect->ymin; y <= rect->ymax; y++)

for(x = rect->xmin; x <= rect->xmax; x++)

SetPixel(x, y, color);

}/*end of FillRectangle() */

(xmin, ymin)

(xmax, ymax)

Page 6: 第 4 章 二维填充图元的生成

6

4.2 扫描转换矩形问题

矩形是简单的多边形,那么为什么要单独处理矩形?比一般多边形可简化计算应用非常多,如窗口系统

共享边界如何处理?原则:左闭右开,下闭上开

属于谁?

Page 7: 第 4 章 二维填充图元的生成

7

4.3 扫描转换多边形 多边形的表示方法

顶点表示顶点序列 P0P1P2…Pn

点阵表示 扫描转换多边形:将顶点表示形式转换成点阵表示形式 三种方法:逐点判断法;扫描线算法;边缘填充法

多边形分类(只考虑:简单多边形,即多边形边不自相交) 凸多边形 (convex) :内角小于 180 度 凹多边形 (concave) :存在内角大于 180 度

Page 8: 第 4 章 二维填充图元的生成

8

4.3 扫描转换多边形 如何识别多边形的凸凹性

方法 1 :观察多边形边的延长线是否划分顶点在两侧方法 2 :向量的叉积每条边建立一个向量,测试相邻边的叉积 z 坐标的正负( 1 )如果叉积同号,那么是凸多边形( 2 )如果叉积不同号,那么是凹多边形

(E1×E2 )z > 0(E2×E3 )z > 0(E3×E4 )z < 0

(E4×E5 )z > 0(E5×E6 )z > 0(E6×E1 )z > 0

Page 9: 第 4 章 二维填充图元的生成

9

4.3 扫描转换多边形向量叉积( Cross Product of Two Vector )

kji

kji

ba

)()()( xyyxzxxzyzzy

zyx

zyx

babababababa

bbb

aaa

当 a 与 b 为二维向量时, a×b 矢量中 x , y 分量为 0

Page 10: 第 4 章 二维填充图元的生成

10

4.3.1 逐点判断法基本原理

判断绘图窗口内的像素是否位于多边形内,若是,则用指定颜色绘制该像素

问题 如何判断点在多边形的内外关系?

射线法累计角度法 *编码法 *

P1

P2

(xmin, ymin)

(xmax, ymax)

Page 11: 第 4 章 二维填充图元的生成

11

4.3.1 逐点判断法算法

假设判断点是否在多边形内的函数为 IsInside ()

void FillPolygon(Polygon *P, int polygonColor){ int x,y;

for(y = ymin;y <= ymax;y++) for(x = xmin;x <= xmax;x++)

if(IsInside(P,x,y)) SetPixel(x, y, polygonColor);else SetPixel(x,y,backgroundColor);

}/*end of FillPolygonPbyP() */

#define MAX 100typedef struct { // 多边形顶点个数 int PolygonNum; // 多边形顶点数组 Point vertexces[MAX]} Polygon; // 多边形结构

Page 12: 第 4 章 二维填充图元的生成

12

4.3.1 逐点判断法判断点是否在多边形内-射线法 步骤

从待判别点 v 发出射线 求与多边形交点个数 k k 的奇偶性决定了点与多边形的内外关系

偶数:外奇数:内

v1

p2

p1

p3

v2

Page 13: 第 4 章 二维填充图元的生成

13

4.3.1 逐点判断法判断点是否在多边形内-射线法 奇异情况

射线在边上:无数个点 判断是否与边同线 交点为顶点:算几个?

异侧: 1 个同侧: 2 个

Page 14: 第 4 章 二维填充图元的生成

14

4.3.1 逐点判断法逐点判断扫描转换方法

特点程序简单测试点是否在多边形内的算法速度太慢,效率低

改进逐点判断法孤立考虑各个像素与多边形的内外关系利用内部点的连续性

Page 15: 第 4 章 二维填充图元的生成

15

4.3.1 逐点判断法思考题

下图是某油田油井分布图,已知每口油井的位置( x, y坐标值)和产油量,如何求任意多边形(虚线所示)中的总产油量?

油井

利用射线法判断油井是否在多边形内?

Page 16: 第 4 章 二维填充图元的生成

16

4.3.2 扫描线算法英文: Scan-Line Algorithm目标

利用相邻像素之间的连贯性,提高算法效率处理对象:简单多边形

非自交多边形 (边与边之间除了顶点外无其它交点)扫描线 (Scanning Line)

平行于坐标轴的直线 一般取平行于 X 轴 区间:扫描线与边的交点间的线段

Page 17: 第 4 章 二维填充图元的生成

17

4.3.2 扫描线算法连贯性 (Coherence)

边的连贯性 (Edge Coherence)某条边与当前扫描线相交,也可能与下一条扫描线相交

扫描线的连贯性 (Scan-line Coherence)当前扫描线与各边的交点顺序与 下一条扫描线与各边的交点顺序可能相同或类似

区间的连贯性 (Span Coherence)同一区间上的像素取同一颜色属性

Page 18: 第 4 章 二维填充图元的生成

18

4.3.2 扫描线算法基本原理

将整个绘图窗口内扫描多边形的问题分解到一条条扫描线,只要完成每条扫描线的绘制就实现了多边形的扫描转换

一条扫描线与多边形的边有偶数个交点,每 2 个点形成一区间

步骤 ( 对于每一条扫描线 )(1) 计算扫描线与边的交点(2) 交点按 x 坐标从小到大排序(3) 交点两两配对,填充区间

Page 19: 第 4 章 二维填充图元的生成

19

4.3.2 扫描线算法计算交点

分类第一类交点:位于同一条边上的后继交点 --(P2, P4)

第二类交点:新出现的边与扫描线的交点 --(P3)

计算:由扫描线 y = e 与多边形的交点递推计算扫描线

y = e + 1 的交点第一类交点: x’ = x + 1/m第二类交点: 线段的下端点即为交点

P3 P4

P0

P2

P1

Page 20: 第 4 章 二维填充图元的生成

20

4.3.2 扫描线算法计算交点(续)

交点取整规则:要求:使生成的像素全部位于多边形之内用于线画图元扫描转换的四舍五入原则导致部分像素位于多边形之外,从而不可用

扫描转换 位于多边形内

Page 21: 第 4 章 二维填充图元的生成

21

4.3.2 扫描线算法 取整规则

假定非水平变与扫描线 y=e 相交,交点的横坐标为x规则 1

X 为小数,即交点落于扫描线上两个相邻像素之间 (a) 交点位于左边之上,向右取整 (b) 交点位于右边之上,向左取整

Page 22: 第 4 章 二维填充图元的生成

22

4.3.2 扫描线算法规则 2

落在右上边界的像素不予填充。

具体实现时,只要对扫描线与多边形的相交区间左闭右开

Page 23: 第 4 章 二维填充图元的生成

23

4.3.2 扫描线算法规则 3

扫描线与多边形的顶点相交时,采用上开下闭及右开左闭取交点,保证交点正确配对。

检查两相邻边在扫描线的哪一侧。 只要检查顶点的两条边的另外两个端点的 Y 值,两个 Y值中大于交点 Y 值的个数是 0 , 1 , 2 ,来决定取 0 , 1 ,2 个交点

Page 24: 第 4 章 二维填充图元的生成

24

4.3.2 扫描线算法计算交点(续)

水平边不考虑

排序 扫描线连贯性 采用插入排序

交点两两配对与区间绘制 区间连续性 连续绘制区间上的像素

H

F

A B

C D

G

J

A , B 算交点C 不算, D算I 不算, H算G , F 不算

Y

Page 25: 第 4 章 二维填充图元的生成

25

4.3.2 扫描线算法算法实现-数据结构

( 1 )边的分类表 ET ( Edge Table )(又称新边表)按照边的下端点 y 坐标,对非水平边进行分类的链表下端点 y 坐标值等于 i 的边属于第 i 类作用:避免盲目求交

Page 26: 第 4 章 二维填充图元的生成

26

4.3.2 扫描线算法 ET 定义

每条扫描线,对应一个链表链表中每个结点的结构

typedef struct {int ymax; float x, deltax; Edge *nextEdge; }Edge;

ET 的结点信息:ymax: 边的上端点的 y 坐标值x :边的下端点的 x 坐标deltax :边的斜率的倒数nextEdge: 下一条边的指针

Page 27: 第 4 章 二维填充图元的生成

27

4.3.2 扫描线算法结点结构解释

typedef struct {int ymax; float x, deltax; Edge *nextEdge; }Edge;

float x, deltax; 用于递推计算交点 x’ = x +1/mint ymax ;当扫描线 y = e+1 == ymax ,说明下一条扫描线与此边不相交

Page 28: 第 4 章 二维填充图元的生成

28

4.3.2 扫描线算法( 2 )活性边表 AEL(Active Edge List)

存放活性边的顺序链表,且按交点 x 的值从小到大排序 活性边:与当前扫描线相交的边 边结构定义:typedef struct {int ymax; float x, deltax; Edge *nextEdge; }Edge;

AEL 的结点信息:ymax: 所交边的最高扫描线号x :当前扫描线与边的交点的 x 坐标deltax :边的斜率的倒数nextEdge: 下一条边的指针

Page 29: 第 4 章 二维填充图元的生成

29

4.3.2 扫描线算法实例

(a) Y=6 对应的活性边表

(b) Y=7 对应的活性边表

Page 30: 第 4 章 二维填充图元的生成

30

4.3.2 扫描线算法 算法 (Scan-Line Algorithm)

1 、建立 ET;2 、将扫描线纵坐标 y 的初值置为 ET 中非空 元素的最小序号,如图中, y=1;3 、置 AEL 为空;4 、执行下列步骤直至 ET 和 AEL都为空.4.1 、如 ET 中的第 y 类非空,则将其中的所有 边取出并插入 AEL 中;4.2 、如果有新边插入 AEL ,则对 AEL 中各边排序;4.3 、对 AEL 中的边两两配对,( 1 和 2 为一对, 3 和 4 为一对,…),将每对边中 x 坐标按规则取整,获得有效的填充区段,再填充.

4.4 、将当前扫描线纵坐标 y 值递值 1;4.5 、将 AEL 中满足 y = ymax 边删去(因为每条边被看作下闭上开

的);4.6 、对 AEL 中剩下的每一条边的 x递增 deltax ,即 x = x+deltax.

Page 31: 第 4 章 二维填充图元的生成

31

4.3.2 扫描线算法4.3.2 扫描线算法例子

y=5 y=6 y=7

y=8

AET:y=1 y=2 y=3

y=4

4 4 -1

5 7 5/4 ^

4 5 -1

5 33/4 5/4 ^

5 19/2 5/4 ^ 4 3 -1

8 2 0 5 43/4 5/4 ^

8 2 0

8 2 0

8 2 0

11 12 0 1̂1 12 0 ^8 7 -5

11 7 5/4 11 12 0 ^11 33/4 5/4 11 12 0

^

Page 32: 第 4 章 二维填充图元的生成

32

4.3.2 扫描线算法 思考问题

算法如何体现连贯性? 对凸多边形而言,算法是否可以简化?如何简化? 对三角形而言,算法如何简化?

三角形广泛应用于物体建模

Page 33: 第 4 章 二维填充图元的生成

33

思考题思考问题 如何高效计算平面上 n 条线段的交点?

利用扫描线和边的连贯性,时间复杂性 m×n’ ( m 为扫描线条数 , n’ 为与扫描线相交边的平均条数, n’ << n )

一般方法:两两求交点,时间复杂性 n2

Page 34: 第 4 章 二维填充图元的生成

34

4.3.3 边缘填充算法 *写像素的逻辑操作

主要包括:拷贝、异或(求余)等 写模型:像素的颜色与源像素及像素当前颜色相关

Page 35: 第 4 章 二维填充图元的生成

35

4.3.3 边缘填充算法 *求余运算

假定 A 为一个正整数,则 M 的余定义为 A – M, 记为

求余运算可用异或逻辑运算实现

性质

11Xor001Xor1

Xor

AMMAM

00110110

11111111

11001001

Xor

11001001

11111111

00110110

Xor

MM

M

Page 36: 第 4 章 二维填充图元的生成

36

4.3.3 边缘填充算法 *求余运算(续)

应用:光标移动、橡皮筋线和加亮菜单等操作 如:交互绘制线段时的橡皮筋线

交互方式:( 1 )点击鼠标左键输入线段的一个端点( 2 )点击右键(或左键)输入另一端点( 3 )鼠标移动过程中绘制瞬时线段

注意:不能采用直接绘制(复制、拷贝)方法

Page 37: 第 4 章 二维填充图元的生成

37

4.3.3 边缘填充算法 *

边缘填充算法 光栅图形中,如果某区域已着上值为 M 的颜色值后,做偶数次求余运算,该区域颜色不变;而做奇数次求余运算,则该区域颜色变为值为 的颜色

这一规律应用于多边形扫描转换,称为边缘填充算法。算法基本思想

对于每条扫描线和每条多边形边的交点,将该扫描线上交点右方的所有像素取余

M 为填充色, A 为当前背景色

M

Page 38: 第 4 章 二维填充图元的生成

38

4.3.3 边缘填充算法 *

算法 1 (以扫描线为中心的边缘填充算法) 1 、将当前扫描线上的所有像素着上值为 颜色; 2 、求余: for(i=0; i<=m; i++) 在当前扫描线上,从横坐标为 xi的交点向右求余;

M

图中次序: x0, x1, x2, x3 次序可以任意

Page 39: 第 4 章 二维填充图元的生成

39

4.3.3 边缘填充算法 *

算法 2 (以边为中心的边缘填充算法)1 、将绘图窗口的背景色置为 ;2 、对多边形的每一条非水平边做:

从该边上的每个像素开始向右求余

M

Page 40: 第 4 章 二维填充图元的生成

40

特点 适合用于具有帧缓存的图形系统。处理后,按扫描线顺序读出帧缓存的内容,送入显示设备

优点:算法简单 缺点:对于复杂图形,每一像素可能被访问多次,输入 /输出的量比扫描线算法大得多

4.3.3 边缘填充算法 *

Page 41: 第 4 章 二维填充图元的生成

41

扇形区域的描述 圆的半径 R 起始角度: 1

终止角度: 2

原理:同扫描转换多边形 对每条扫描线,首先计算与扇形区域边界的交点,再用指定颜色绘制绘制配对交点间的像素

问题 如何确定扫描线与直线段和圆弧段的交点及相交顺序?

4.4 扫描转换扇形区域

Page 42: 第 4 章 二维填充图元的生成

42

方法:分类 按点 P1(x, y) 和 P2(x, y) 点所处象限的不同,需要将扇形区域分成 4×4=16 种情况

假设 P1 点落在第一象限 扫描线和区域边界只有 2 个交点扇形区域的扫描转换分四种情况(1) P2落在第一象限区域: OP1A 和 AP1P2

4.4 扫描转换扇形区域

Page 43: 第 4 章 二维填充图元的生成

43

(2)P2落在第二象限,此时又分为两种情况 当 时

三个区域: OAP1 、 AP1BP2 和 P2BC

当 时

三个区域: OAP2 、 AP1BP2 和 P1BC

4.4 扫描转换扇形区域

y y1 2

21 yy

),(),( 222

12

21

2yyRBy

y

xyA

),(),( 122

21

12

1yyRBy

y

xyA

Page 44: 第 4 章 二维填充图元的生成

44

(3) P2 落在第三象限

三个区域: P1CA 、 BOP1A 和 P2OB

(4) P2落在第四象限

三个区域: AP1D 、 BOP1 A 、 CP2OB

和 CEP2

4.4 扫描转换扇形区域

),0()0,(),( 121

2 RCRByyRA

),0()0,(

),(),( 222

21

21

2

RDRC

yyRByyRA

Page 45: 第 4 章 二维填充图元的生成

45

遗留问题:当 P1 落在其它区域时 ? P1 落在第二、三、四象限时,将扇形区域绕坐标原点顺时针旋转 90 度( 180 , 270 ),使 P1 落在第 1 象限

扫描转换 再逆时针旋转 90 度( 180 , 270 )

4.4 扫描转换扇形区域

P1P2P2

P1

P1落在第四象限

P2P1

P1落在第一象限

P1

P2

P1落在第四象限

旋转 270 度 扫描转换逆旋转 270度

Page 46: 第 4 章 二维填充图元的生成

46

区域:点阵表示的图形,像素集合表示方法:内点表示、边界表示内点表示

枚举出区域内部的所有像素 内部的所有像素为同一个颜色 边界像素与内部像素的颜色不同

边界表示 枚举出边界上所有的像素 边界上的所有像素为同一颜色 内部像素与边界像素的颜色不同

4.5 区域填充

Page 47: 第 4 章 二维填充图元的生成

47

种子填充法 对区域重新着色的过程 将指定的颜色从种子点开始扩展到整个区域 区域填充算法要求区域是连通的

4.5 区域填充

Page 48: 第 4 章 二维填充图元的生成

48

连通性 4 连通区域:区域中任意两点可通过上下左右四个方向互

相 到达 8 连通区域:区域中任意两点可通过上下左右和对角线八 个方向互相到达

4.5 区域填充

Page 49: 第 4 章 二维填充图元的生成

49

4.5 区域填充4 连通与 8 连通区域的区别

连通性: 4 连通可看作 8 连通区域,但对边界有要求不同

依据区域内点能否访问到区域外的点,对边界的要求是4 连通区域,边界只要 8 连通即可8 连通区域,边界必须是 4 连通

例:如左图( 1 ) 4 连通区域,边界为 像素( 2 ) 8 连通区域,边界为 和 像素

Page 50: 第 4 章 二维填充图元的生成

50

4.5.1 种子填充法种子填充算法(泛滥填充: flood-fill ) ( 1 )内点表示的 4 连通区域

种子 P(x,y) ,原色 oldColor ,新颜色 newColor

方法:先判断 P(x, y) 的颜色,若其值不等于 oldColor ,说明该像素位于区域外,或已设置为 newColor ,算法结束;

否则,置像素颜色为 newColor ,再对其相邻的上下左右四个像素分别作为种子作上述递归处理。

void FloodFill4(int x,int y,int oldColor,int newColor){ if(GetPixel(x,y) == oldColor) { SetPixel(x,y,newColor); FloodFill4(x,y+1,oldColor,newColor); FloodFill4(x,y-1,oldColor,newColor); FloodFill4(x-1,y,oldColor,newColor); FloodFill4(x+1,y,oldColor,newColor); }}/*end of FloodFill4() */

Page 51: 第 4 章 二维填充图元的生成

51

4.5.1 种子填充法

①FloodFill4(x, y+1, oldColor, newColor);②FloodFill4(x, y-1, oldColor, newColor);③FloodFill4(x-1, y, oldColor, newColor);④FloodFill4(x+1, y, oldColor, newColor);

Page 52: 第 4 章 二维填充图元的生成

52

( 2 )边界表示的 4 连通区域

4.5.1 种子填充法

void BoundaryFill4(int x, int y, int oldColor, int newColor){//oldColor 边界像素颜色 int color;

color = GetPixel(x, y); if((color != oldColor) && (color != newColor)) { SetPixel(x, y, newColor); BoundaryFill4(x,y+1,oldColor,newColor); BoundaryFill4(x,y-1,oldColor,newColor); BoundaryFill4(x-1,y,oldColor,newColor); BoundaryFill4(x+1,y,oldColor,newColor); }}/*end of BoundaryFill4( ) */

Page 53: 第 4 章 二维填充图元的生成

53

缺点 有些像素需要重复判断,降低算法效率 栈结构占空间 递归执行,算法简单,但效率不高,区域内每一像素都引起一次递归,进 / 出栈,费时费内存

改进 减少递归次数,提高效率 方法之一使用扫描线填充算法

4.5.1 种子填充法

Page 54: 第 4 章 二维填充图元的生成

54

4.5.2 扫描线算法 *

扫描线算法 目标:减少递归层次 适用于内点表示的 4 连通区域 基本过程:

当给定种子点时,首先填充种子点所在的扫描线上的位于给定区域的一个区段,然后确定与这一区段相通的上下两条扫描线上位于给定区域内的区段,并依次保存下来。反复这个过程,直到填充结束

Page 55: 第 4 章 二维填充图元的生成

55

4.5.2 扫描线算法 *

算法步骤 1 、初始化 :将种子区段压入堆栈 2 、出栈:如果堆栈为空,则算法结束;

否则取栈顶元素 (x,y)作为种子点 3 、区段填充:从种子点 (x, y) 开始沿纵坐标为 y 的扫描行向左右两个方向逐个像素填色,直到边界为止

4 、定范围:以 [xLeft, xRight] 为 (3)得到的区段 5 、进栈:分别在与当前扫描线相邻的上下扫描线上,确定位于区间 [xLeft, xRight] 内的区段。

如果区段内的像素颜色值为 newColor 或 boundaryColor ,则转到( 2 )

区段压入堆栈,转到( 2 )

Page 56: 第 4 章 二维填充图元的生成

56

• 例

4.5.2 扫描线算法 *

像素中的序号标指它所在区段位于堆栈中的位置

Page 57: 第 4 章 二维填充图元的生成

57

多边形扫描转换与区域填充方法比较 基本思想不同

前者:顶点表示转换成点阵表示后者:只改变区域内填充颜色,没有改变表示方法

对边界的要求不同前者:扫描线与多边形边界交点个数为偶数后者:区域封闭,防止递归填充跨界

基本的条件不同前者:从边界顶点信息出发后者:区域内种子点

4.5.3 扫描转换与区域填充的比较

Page 58: 第 4 章 二维填充图元的生成

58

填充方式 ( 1 )均匀着色( 2 )位图不透明 (3) 位图透明 (4) 像素图填充 在确定区域内的像素后,查询它对应的位图或图像中的单元,再以该单元的值按填充方式的不同显示该像素

方法 (1)均匀着色方法:将图元内部像素置成同一颜色 (2) 位图不透明:若像素对应的位图单元为 1 ,则以前景色显示

该像素;若为 0 ,则以背景色显示该像素; (3) 位图透明:若像素对应的位图单元为 1 ,则以前景色显示该

像素;若为 0 ,则不做任何处理。 (4) 像素图填充:以像素对应的像素图单元的颜色值显示该像素。

4.6 以图像填充区域

Page 59: 第 4 章 二维填充图元的生成

59

基本问题 建立区域与图像间的对应关系方法 1 :建立整个绘图空间与图像空间的 1-1映射

4.6 以图像填充区域

图像(纹理) 绘图空间

Page 60: 第 4 章 二维填充图元的生成

60

适用:动画中漫游图像,如透过车窗看外景

4.6 以图像填充区域

Page 61: 第 4 章 二维填充图元的生成

61

方法 2 :建立区域局部坐标空间与图像空间的 1-1映射

4.6 以图像填充区域

适用:图像作为区域表面属性的情况,例如,桌面与其上的木纹

Page 62: 第 4 章 二维填充图元的生成

62

字符集 ASCII 码: 128 个字符 GB2312 - 80 :汉字 6763 个, 682 个图形符号

点阵字体 存储(压缩与非压缩) 显示:检索与写缓冲

矢量字体 表示:笔画组成曲线(参数) 扫描转换:参数到点阵 显示: 1 、由编码检索 2 、扫描转换 存储:空间少 ( windows 下的仿宋体库: SIMFANG.TTF 为 3904

K )

4.7 字符的表示与输出

Page 63: 第 4 章 二维填充图元的生成

63

4.8 OpenGL相关函数区域函数(填充作用)

矩形函数: glRect[i|s|f|d]{v}() glBegin() 中的参数 GL_POLYGON 、 GL_TRIANGLES 、

GL_TRIANGLE_STRIP 、 GL_TRIANGLE_FAN

三角形的三种绘制参数int p1[]={20,100},p2[]={50,50};int p3[]={110,50},p4[]={140,100};int p5[]={110,150},p6[]={50,150};

glBegin(GL_TRIANGLES); glVertex2iv(p1); glVertex2iv(p2); glVertex2iv(p3); glVertex2iv(p4); glVertex2iv(p5); glVertex2iv(p6);glEnd();

GL_TRIANGLE_STRIP

GL_TRIANGLES

GL_TRIANGLE_FAN

p1

p1

p1

Page 64: 第 4 章 二维填充图元的生成

64

菜单函数 int glutCreateMenu(void (*func)(int value));//创建菜单 void glutAddMenuEntry(char *name, int value);//添加菜单项 void glutAddSubMenu(char *name, int menu);//添加子菜单 glutAttachMenu(int button);

例:

4.8 OpenGL相关函数

void MenuInit(){ int sub_menu1 = glutCreateMenu(objectMenu);

glutAddMenuEntry(" 直线 ",11); glutAddMenuEntry(" 多边形 ",12); glutCreateMenu(topMenu); glutAddSubMenu(" 图形 ",sub_menu1); glutAddMenuEntry(" 退出 ",2); glutAttachMenu(GLUT_RIGHT_BUTTON);}

void objectMenu(int id){ if (id==11) GraphicsType = 11; else if (id==12) GraphicsType = 12; else GraphicsType = 0;}void topMenu(int id){ if (id==2) exit(0);}

Page 65: 第 4 章 二维填充图元的生成

65

线框图与填充图 函数: glPloygonMode(face , displayMode) face :指定前后面。可选值: GL_FRONT 、 GL_BACK 和

GL_FRONT_AND_BACK displayMode : GL_FILL 和 GL_LINE

4.8 OpenGL相关函数

void display (void){ glClearColor (1.0, 1.0, 1.0, 0.0); glClear (GL_COLOR_BUFFER_BIT); glPolygonMode(GL_FRONT, GL_LINE); glBegin(GL_POLYGON); glColor3f(1.0,0,0); glVertex2f(0.5,0); glVertex2f(-0.5,0.5); glVertex2f(-0.5,-0.5); glVertex2f(0.6,-0.5); glEnd();

glFlush();}

前向面:顶点序列逆时针顺序排列

Page 66: 第 4 章 二维填充图元的生成

66

颜色插值模式 函数: glShadeModel(mode) Mode: GL_FLAT 和 GL_SMOOTH 例:

4.8 OpenGL相关函数

void display (void){ glClearColor (1.0, 1.0, 1.0, 0.0); glClear (GL_COLOR_BUFFER_BIT); glShadeModel(GL_FLAT);// 默认为 GL_SMOOTH glBegin(GL_POLYGON); glColor3f(1,0,0); glVertex2f(-0.5,0.5); glColor3f(0,1,0); glVertex2f(-0.5,-0.5); glColor3f(0,0,1); glVertex2f(0.5,-0.5); glColor3f(1,1,1); glVertex2f(0.5,0.5); glEnd();

glFlush();}

GL_FLAT 方式下以第 1 个点颜色填充

Page 67: 第 4 章 二维填充图元的生成

67

顶点数组 原因:复杂图形需要很多坐标描述,导致函数调用量大增,影响程序的执行效率

采用顶点数组减少函数调用 方法

调用函数 glEnableClientState(GL_VERTEX_ARRAY), 激活顶点数组特性

调用 glVertexPointer 指定顶点坐标的位置和数据格式 使用与数组相关的函数绘制图形

4.8 OpenGL相关函数

Page 68: 第 4 章 二维填充图元的生成

68

例:glClear (GL_COLOR_BUFFER_BIT);

glColor3f (1.0, 0.0, 0.0);

vertex2 pt[]={{20,100},{50,50},{110,50},{140,100},{110,150},{50,150}};

glEnableClientState(GL_VERTEX_ARRAY);

glVertexPointer(2,GL_INT,0,pt);

GLubyte vertIndex[]={0,1,2,3,4,5};

glDrawElements(GL_TRIANGLES,24,GL_UNSIGNED_BYTE, vertIndex);

glFlush ( );

4.8 OpenGL相关函数

Page 69: 第 4 章 二维填充图元的生成

69

4.8 OpenGL相关函数写像素模式

16 种,默认方式为 GL_COPY 模式改变时,需要调用

glEnable ( GL_COLOR_LOGIC_OP ) 设置模式: glLogicOp ( GL_XOR ) 例:异或模式

00000000 11111111 11111111

000000001111111100000000

000000000000000011111111

00000000 11111111 00000000

000000001111111100000000

000000000000000000000000

Xor

Xor背景

正方形

Page 70: 第 4 章 二维填充图元的生成

70

4.8 OpenGL相关函数填充图案函数

启用函数: glEnable ( GL_POLYGON_STIPPLE ) 关闭函数: glDisable ( GL_POLYGON_STIPPLE ) 设置掩模( mask ): glPolygonStipple ( fillPattern ) 注意: filePattern 类型为 GLubyte ,大小为 32×32

GLubyte fillPattern[]= {0x96,0x96,0x96,0x96, 0x84,0x84,0x84,0x84,

0x48,0x48,0x48,0x48, 0x20,0x20,0x20,0x20, 0x10,0x10,0x10,0x10, 0x10,0x10,0x10,0x10, 0x18,0x18,0x18,0x18, 0x64,0x64,0x64,0x64,

。。。。 ( 重复 3 次 ) }

Page 71: 第 4 章 二维填充图元的生成

71

4.8 OpenGL相关函数 OpenGL 位图函数

void glRasterPos{234}{SIFD}[V](TYPE x, TYPE y,

TYPE z, TYPE w);

设置当前所画位图或图像的原点 glBitmap(width, height, x0,y0,xOffset,yOffset,bitShape)

设定当前光栅位置 该函数显示二值位图。 bitShape 中的元素值为 0 或 1 ,当为 1时,用设定的颜色绘制对应的像素,否则对应像素不受影响

位图的存储模式:字节 glPixelStorei (

GL_UNPACK_ALIGNMENT, 1 ) ;

Page 72: 第 4 章 二维填充图元的生成

72

4.8 OpenGL相关函数程序 void display()

{ // 最好放在初始化函数中 glPixelStorei (GL_UNPACK_ALIGNMENT, 1);

glColor3f (0.0, 0.0, 0.0); glRasterPos2i (100, 200); glBitmap (8, 12, 0.0, 0.0, 20.0, 20.0, rasters);

glColor3f (1.0, 0.0, 0.0); glRasterPos2i (120, 220); glBitmap (8, 12, 0.0, 0.0, 0.0, 0.0, rasters);

glColor3f (0.0, 0.0, 1.0); glRasterPos2i (150, 200); glBitmap (8, 12, 0.0, 0.0, 0.0, 0.0, rasters);

glFlush ( );}

rasters

Page 73: 第 4 章 二维填充图元的生成

73

4.8 OpenGL相关函数绘制字符

OpenGL 基本库:位图方法,需要自己创建字库 GLUT工具包:位图和轮廓字体 位图字符函数: glutBitmapCharacter(font, character)

font: 指定字型,常量(如 GLUT_BITMAP_8_BY_13 ) Character :字符的 ASCII 码值

轮廓字符函数: glutStrokeCharacter(font, character) font: 指定字型,常量(如 GLUT_STROKE_ROMAN ) Character :字符的 ASCII 码值

位图和轮廓字符比较前者速度快,后者放大缩小不变形

Page 74: 第 4 章 二维填充图元的生成

74

4.8 OpenGL相关函数程序

void display(){ glColor3f (1.0, 0.0, 0.0); glRasterPos2i (50, 50); glutBitmapCharacter (GLUT_BITMAP_9_BY_15,66); glRasterPos2i (80, 50); glutBitmapCharacter (GLUT_BITMAP_TIMES_ROMAN_10,66);

glColor3f (0.0, 0.0, 1.0); glPushMatrix(); glTranslatef(50,100,0);glScalef(0.2,0.2,1); glutStrokeCharacter(GLUT_STROKE_ROMAN,66); glPopMatrix();

glTranslatef(100,100,0); glScalef(0.6,0.6,1); glutStrokeCharacter(GLUT_STROKE_ROMAN,66); glutSwapBuffers();}

Page 75: 第 4 章 二维填充图元的生成

75

小结多边形的扫描转换

点是否在区域内的判断方法(射线法) 扫描线算法(思想、步骤和算法实现)

多边形的区域填充 种子填充(连通性)

扇形区域的扫描转换字符的绘制方法 OpenGL 函数

Page 76: 第 4 章 二维填充图元的生成

76

作业1 、多边形扫描转换的扫描线算法利用了扫描线的连贯性和边

的连贯性,在数据结构和算法中各体现在何处?2 、一个多边形的顶点坐标如下图所示。 ( a )写出边的分类表 ( b )说明扫描线 y = 6 , 7 , 8 , 9 和 10 时,哪些边

是活性边。并给出活性边表。

Page 77: 第 4 章 二维填充图元的生成

77

作业3 、内点表示的区域和边界表示的区域在填充时有什么不同?

4 、根据三角形的特殊性,如何简化扫描转换三角形的扫描线算法。

Page 78: 第 4 章 二维填充图元的生成

78

上机题 1:补充添加填充图元的功能

填充多边形 多边形交互输入、颜色定义和填充