区域的填充可以根据区域的填充,采用不同的填充算法,而其中有扫描线类算法和种子填充算法。这里,先介绍扫描线类算法之有序边表的扫描线算法。其他什么种子填充、边界标志算法、4连通区域的递归算法、8连通区域的递归算法、扫描线种子填充算法比较简单。
其实有序边表其实领会了也好理解,关键是将思想转化为代码。
先介绍算法思想:
1.根据给出的多边形顶点坐标,建立ET表(同时计算ymax和ymin)
2.初始化AET表,使之为空
3.使用扫描线yi值作为循环变量,使之初始值为ymin
重复做以下操作:
(1)如果ET表中yi桶非空,则合并到AET中
(2)对AET表中记录按x值从小到大排序
(3)依次取出表中记录,两两配对填充
(4)如果AET表中某记录的ymax=yi,则删除该记录
(5)对仍在AET中的记录,修改x值,x=x+1/m (m为斜率)
现在,关键要细节的处理与代码实现。
1.顶点坐标,由于无法确定顶点数,所以我们用一个数组保存。创建一个填充函数
void regionfill(HDC hdc,Point1 *p,int len,int ymin,int ymax)
我们需要创建EdgeTable类,通过分析,这个结构很像我们数据结构的图(邻接表表示)
代码如下:
/*
*author qyl
*date 2012/4/7
*purpose 边表结构
*version 1.1
*/
#include"LList.h"
#include"Point1.h"
class Edge{
public:
float x;
float increment;
float ymax;
Edge(){x=-1;increment=0;ymax=-1;}
Edge(float x0,float incr,float y0)
{
x=x0;
increment=incr;
ymax=y0;
}
friend bool operator<(Edge &a,Link<Edge> &b)
{
return a.x<b.element.x;
}
friend bool operator>(Edge &a,Edge &b)
{
return a.x>b.x;
}
};
class EdgeTable
{
private:
int numberLine;
int numberEdge;
LList<Edge> **vertex;
public:
EdgeTable(int numLine)
{
int i;
numberLine=numLine;
numberEdge=0;
vertex=(LList<Edge>**) new LList<Edge>*[numberLine];
for(i=0;i<numberLine;i++)
vertex[i]=new LList<Edge>();
}
~EdgeTable()
{
for(int i=0;i<numberLine;i++)
delete [] vertex[i];
delete [] vertex;
}
int numberLines(){return numberLine;}
int numberEdges(){return numberEdge;}
bool isEmptyInLine(int pos)
{
return vertex[pos]->isEmpty();
}
LList<Edge>* getValue(int pos)
{
Edge it;
LList<Edge>* l=new LList<Edge>();
for(vertex[pos]->setStart();vertex[pos]->getValue(it);vertex[pos]->next())
{
l->insert(it);
}
return l;
}
void setEdge(int pos,Edge e)
{
Edge curr;
for(vertex[pos]->setStart();vertex[pos]->getValue(curr);vertex[pos]->next())
{
if(curr.x<=e.x)
break;
}
numberEdge++;
vertex[pos]->insert(e);
}
void delEdge(int pos,Edge e)
{
Edge curr;
for(vertex[pos]->setStart();vertex[pos]->getValue(curr);vertex[pos]->next())
{
if(curr.ymax==e.ymax)
{
vertex[pos]->remove(curr);
numberEdge--;
}
}
}
void deleteAll(int pos)
{
numberEdge-=vertex[pos]->removeAll();
}
void createTableEdge(Point1 * p,int len,int ymin,int ymax)
{
Edge* e;
/*version 1.2
*改进版本
*/
//计算各个顶点是否为奇异点,对每个顶点进行标记
/*
int *flag=new int[len];
for(int i=0;i<len;i++)
{
if(i==0)
{
if(p[1].getY()>p[0].getY() && p[len-1].getY()>p[0].getY())
*(flag+i)=2;
else if(p[1].getY()<p[0].getY() && p[len-1].getY()<p[0].getY())
*(flag+i)=0;
else if(p[1].getY()<p[0].getY() && p[len-1].getY()>p[0].getY())
*(flag+i)=1;
else if(p[(i+1)%len].getY()>p[i].getY() && p[len-1].getY()<p[i].getY())