边界标志算法对多边形的每条边进行扫描并对该像素打上标志。然后再利用扫描线扫描该多边形,对于与多边形相交的扫描线依从左到右的顺序,逐个访问该扫描线上的像素。使用一个布尔值量inside来表示当前点是否在多边形内。Inside的初值为假,每当当前访问的像素是被打上边标志的点时,就把inside取反。对未标志的像素,inside不变。若访问当前像素时,inside为真,说明该像素在多边形内,则把该像素置为填充色。
伪代码如下:
Void edgeMark_fill(polydef,color){
对多边形的polydef每条边进行直线扫描转换;
For(每条与多边形polydef相交的扫描线y)
{
If像素x被打上标志
Inside=!inside
Ifinside
DrawPixel(x,y,color);
Else
DrawPixel(x,y,backgroundColor);
}
}
根据伪代码在C++中实现:
VOID CGraphicDlg::EdgeMarkFill(COLORREF edgeColor, COLORREF fillColor, int yMin, int yMax, int xMin, int xMax)
{
for (int i = yMin; i <= yMax; i++) {
bool inside = false;
//bool flag = false;
for (int j = xMin; j <= xMax; j++) {
bool res = CheckEdgeMark(j, i, edgeColor);
if (res) {
inside = !inside;
}
if (inside)
DrawRectange(j, i, 0, 0, fillColor);
}
}
return VOID();
}
效果图如下:
可以发现明显的“漏水”现象。
为什么呢?我们将边界图片放大观察,请看大图
可以看见图中连续的标志像素点。如果其为偶数,就会导致inside在这一边经历两次变换,如果在扫描到边界前是填充,再变换两次,还是填充,就导致了“漏水”现象。
为了解决这个问题
引入一个布尔值,flag,初始化为false
flag==true——即使当前点被标记为边界色,也不能改变inside。如果当前点不是边界,则改变flag为false
flag==false——当前点被标记为边界色,则会改变inside。如果当前点不是边界,则会改变inside,且flag变为true
改进后的代码如下:
VOID CGraphicDlg::EdgeMarkFill(COLORREF edgeColor, COLORREF fillColor, int yMin, int yMax, int xMin, int xMax)
{
for (int i = yMin; i <= yMax; i++) {
bool inside = false;
bool flag = false;
for (int j = xMin; j <= xMax; j++) {
bool res = CheckEdgeMark(j, i, edgeColor);
if (res && !flag) {
inside = !inside;
flag = true;
}
else if (!res&&flag) {
flag = false;
}
if (inside&&!res)
DrawRectange(j, i, 0, 0, fillColor);
}
}
return VOID();
}
效果图:
然而顶部密集的部分,还是漏了。至于这个问题,恳请高人指点啊。
最后放上两张放大图