1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
|
//
// 功能: 填充多边形
//
// 参数: lpPoints: 指向顶点坐标数组的指针,数组类型为POINT,多边形由它们顺次封闭连接得到
// nCount: 顶点的个数
// nColor: 填充的颜色 默认为黑色
// pDC: 设备句柄指针
//
// 返回: 无返回值
//
// 说明: 可以是边相交的多边形
//
//
void
FillPolygon(LPPOINT lpPoints,
int
nCount, CDC *pDC,
int
nColor
/*=0*/
)
{
// 检查参数合法性
ASSERT_VALID(pDC);
ASSERT(lpPoints);
ASSERT(nCount>2);
ASSERT(nColor>=0);
// 边结构数据类型
typedef
struct
Edge{
int
ymax;
// 边的最大y坐标
float
x;
// 与当前扫描线的交点x坐标
float
dx;
// 边所在直线斜率的倒数
struct
Edge * pNext;
// 指向下一条边
}Edge, * LPEdge;
int
i=0,j=0,k=0;
int
y0=0,y1=0;
// 扫描线的最大和最小y坐标
LPEdge pAET=NULL;
// 活化边表头指针
LPEdge * pET=NULL;
// 边表头指针
pAET=
new
Edge;
// 初始化表头指针,第一个元素不用
pAET->pNext=NULL;
// 获取y方向扫描线边界
y0=y1=lpPoints[0].y;
for
(i=1;i <nCount;i++)
{
if
(lpPoints[i].y <y0)
y0=lpPoints[i].y;
else
if
(lpPoints[i].y>y1)
y1=lpPoints[i].y;
}
if
(y0>=y1)
return
;
// 初始化边表,第一个元素不用
pET=
new
LPEdge[y1-y0+1];
for
(i=0;i <=y1-y0;i++)
{
pET[i]=
new
Edge;
pET[i]->pNext=NULL;
}
for
(i=0;i <nCount;i++)
{
j=(i+1)%nCount;
// 组成边的下一点
if
(lpPoints[i].y != lpPoints[j].y)
// 如果该边不是水平的则加入边表
{
LPEdge peg;
// 指向该边的指针
LPEdge ppeg;
// 指向边指针的指针
// 构造边
peg =
new
Edge;
k=(lpPoints[i].y>lpPoints[j].y)?i:j;
peg->ymax=lpPoints[k].y;
// 该边最大y坐标
k=(k==j)?i:j;
peg->x=(
float
)lpPoints[k].x;
// 该边与扫描线焦点x坐标
if
(lpPoints[i].y != lpPoints[j].y)
peg->dx=(
float
)(lpPoints[i].x-lpPoints[j].x)/(lpPoints[i].y-lpPoints[j].y);
// 该边斜率的倒数
peg->pNext=NULL;
// 插入边
ppeg=pET[lpPoints[k].y-y0];
while
(ppeg->pNext)
ppeg=ppeg->pNext;
ppeg->pNext=peg;
}
// end if
}
// end for i
// 扫描
for
(i=y0;i <=y1;i++)
{
LPEdge peg0=pET[i-y0]->pNext;
LPEdge peg1=pET[i-y0];
if
(peg0)
// 有新边加入
{
while
(peg1->pNext)
peg1=peg1->pNext;
peg1->pNext=pAET->pNext;
pAET->pNext=peg0;
}
// 按照x递增排序pAET
peg0=pAET;
while
(peg0->pNext)
{
LPEdge pegmax=peg0;
LPEdge peg1=peg0;
LPEdge pegi=NULL;
while
(peg1->pNext)
{
if
(peg1->pNext->x>pegmax->pNext->x)
pegmax=peg1;
peg1=peg1->pNext;
}
pegi=pegmax->pNext;
pegmax->pNext=pegi->pNext;
pegi->pNext=pAET->pNext;
pAET->pNext=pegi;
if
(peg0 == pAET)
peg0=pegi;
}
// 遍历活边表,画线
peg0=pAET;
while
(peg0->pNext)
{
if
(peg0->pNext->pNext)
{
DrawLine((
int
)peg0->pNext->x,i,(
int
)peg0->pNext->pNext->x,i,pDC,nColor);
peg0=peg0->pNext->pNext;
}
else
break
;
}
// 把ymax=i的节点从活边表删除并把每个节点的x值递增dx
peg0=pAET;
while
(peg0->pNext)
{
if
(peg0->pNext->ymax < i+2)
{
peg1=peg0->pNext;
peg0->pNext=peg0->pNext->pNext;
//删除
delete
peg1;
continue
;
}
peg0->pNext->x+=peg0->pNext->dx;
//把每个节点的x值递增dx
peg0=peg0->pNext;
}
}
// 删除边表
for
(i=0;i <y1-y0;i++)
if
(pET[i])
delete
pET[i];
if
(pAET)
delete
pAET;
if
(pET)
delete
[] pET;
}
|
多边形填充算法
最新推荐文章于 2024-01-01 17:46:56 发布