扫描线种子填充算法的基本过程如下:当给定种子点(x, y)时,首先分别向左和向右两个方向填充种子点所在扫描线上的位于给定区域的一个区段,同时记下这个区段的范围[xLeft, xRight],然后确定与这一区段相连通的上、下两条扫描线上位于给定区域内的区段,并依次保存下来。反复这个过程,直到填充结。
扫描线种子填充算法可由下列四个步骤实现:
(1) 初始化一个空的栈用于存放种子点,将种子点(x, y)入栈;
(2) 判断栈是否为空,如果栈为空则结束算法,否则取出栈顶元素作为当前扫描线的种子点(x, y),y是当前的扫描线;
(3) 从种子点(x, y)出发,沿当前扫描线向左、右两个方向填充,直到边界。分别标记区段的左、右端点坐标为xLeft和xRight;
(4) 分别检查与当前扫描线相邻的y - 1和y + 1两条扫描线在区间[xLeft, xRight]中的像素,从xLeft开始向xRight方向搜索,若存在非边界且未填充的像素点,则找出这些相邻的像素点中最右边的一个,并将其作为种子点压入栈中,然后返回第(2)步;
这个算法中最关键的是第(4)步,就是从当前扫描线的上一条扫描线和下一条扫描线中寻找新的种子点。并只检查新扫描线上区间[xLeft, xRight]中的像素
void fill(int x,int y,COLORREF color)
{
std::stack<Point>s;
s.push(Point(x,y));
while(!s.empty())
{
Point seed=s.top();
s.pop();
putPixel(seed.x,seed.y,color);
//左右填充
int x1=seed.x-1,x2=seed.x+1;
while(getColor(x1,seed.y)!=borderColor&&getColor(x1,sedd.y)!=color)
{
putPixel(x1,seed.y,color);
x1--;
}
while(getColor(x2,seed.y)!=borderColor&&getColor(x2,sedd.y)!=color)
{
putPixel(x2,seed.y,color);
x2++;
}
int left1=x1,right1=x2,
left2=left1,right2=right1;
//上下扫描
bool findNewSeed=false;//处理无效点
while(left1<=right1)
{
if(findNewSeed && (getColor(left1,seed.y-1)==borderColor || getColor(left1,sedd.y-1)==color)){
s.push(Point(left1-1,seed.y-1));
findNewSeed=false;
}
else if(!findNewSeed)
findNewSeed=true;
if(findNewSeed && left1==right1)
s.push(Point(left1,seed.y-1);
left1++;
}
findNewSeed=false;//处理无效点
while(left2<=right2)
{
if(findNewSeed && (getColor(left2,seed.y+1)==borderColor || getColor(left2,sedd.y+1)==color)){
s.push(Point(left2-1,seed.y+1));
findNewSeed=false;
}
else if(!findNewSeed)
findNewSeed=true;
if(findNewSeed && left2==right2)
s.push(Point(left2,seed.y+1);
left2++;
}
}
}