多边形填充算法

C/C++ code
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; 
#include #include #include #include #include //////////////////////////////////////////////////////////////functions///////////////////////////////////////////////// void swap(float &m,float &n) { float temp=n; n=m; m=temp; } int sign(float a,float b)//sign() { int t; if(a>b) { t=1;} else if(adx) { swap(dx,dy); Flag=1; } else Flag=0; float Nerror=2*dy-dx; for(int i=1;i=0) { if(Flag) { x=x+sx;} else y=y+sy; Nerror=Nerror-2*dx; } if(Flag) { y=y+sy;} else x=x+sx; Nerror=Nerror+2*dy; } } ///////////////////////////////////四连通种子填充/////////////////////////////////////////////////// void BoundaryFill4(HDC hdc,int x,int y,int FilledColor,int BoundaryColor) { int CurrentColor; CurrentColor=GetPixel(hdc,x,y); if(CurrentColor!=BoundaryColor&&CurrentColor!=FilledColor) { SetPixel(hdc,x,y,FilledColor); BoundaryFill4(hdc,x+1,y,FilledColor,BoundaryColor); BoundaryFill4(hdc,x-1,y,FilledColor,BoundaryColor); BoundaryFill4(hdc,x,y+1,FilledColor,BoundaryColor); BoundaryFill4(hdc,x,y-1,FilledColor,BoundaryColor); } } ////////////////////////////////////////扫描线填充/////////////////////////////////////////////////// //DrawLine()函数:在(x1,y)和(x2,y)两点之间画一条颜色为FilledColor的横线(用来扫描填充) void drawline(HDC hdc, int x1, int x2,int y0, int FilledColor) { for(int n=x1+1;n<x2;n++) { SetPixel(hdc,n,y0,FilledColor); } } //Scan()函数:扫描线函数,将扫描线与图形的交点坐标存在数组中 //数组中同行的点即为该行扫描线与图形的交点(一般为2个) //数组中的行代表扫描线的纵坐标 void scan(HDC hdc, int boundarycolor) { int currentcolor; int a[300][2]={0}; for (int j=0;j<300;j++) { for(int i=300;i<700;i++) { currentcolor=GetPixel(hdc,i,j); if((currentcolor==boundarycolor)&&(GetPixel(hdc,i+1,j)!=boundarycolor)&&(i500)) {a[j][1]=i;} } } //利用循环调用DrawLine函数逐行填充两交点之间的点 for(int k=0;k<300;k++) { if((a[k][0]!=0)&&(a[k][1]!=0)) drawline(hdc,a[k][0],a[k][1],k,RGB(255,0,0));} } ///////////////////////////////////////////////边界填充////////////////////////////////////// //Contrary()取反函数:如果点的颜色为白,则将点置为填充色;如果点的颜色为填充色,则将点置为白色 //忽略了边界色,即不对边界点作颜色处理 void contrary(HDC hdc, int x, int y,int FilledColor) { for(int h=x;h<280;h++) { if(GetPixel(hdc,h,y)==RGB(255,255,255)) { SetPixel(hdc,h,y,FilledColor); } else if(GetPixel(hdc,h,y)==FilledColor) { SetPixel(hdc,h,y,RGB(255,255,255)); } } } //borderline()边线函数: 先找出图形的边界 左边和右边,从右到左的顺序调用contrary()函数进行填充 void borderline(HDC hdc, int boundarycolor) { for(int j=280;j<499;j++) { for(int i=80;i100)) { contrary(hdc,i,j,RGB(0,0,255)); } } } for(int m=280;m<499;m++) { for(int n=80;n<280;n++) { int currentcolor=GetPixel(hdc,n,m); if((currentcolor==boundarycolor)&&(GetPixel(hdc,n+1,m)!=boundarycolor)&&(GetPixel(hdc,n-1,m)!=boundarycolor)&&(n<101)) { contrary(hdc,n,m,RGB(0,0,255)); } } } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LuckyJiang.2021

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值