引言:前几天做的一个笔试,设计一个自动填充闭合回路像素的程序,笔试时没写完,下来后把整个程序写出来了。
文章末尾有源工程项目地址,先看下源工程项目演示:
闭合环检测+填充-CSDN直播Unity实现https://live.csdn.net/v/231924
总共分两个部分:
一:基于并查集检测回路
首先要填充像素,要先检测是否有回路,即底下黑色的环,这边以八连通算回路标准。
我们考虑用并查集算法思想进行检测。
///检测闭合环算法
void InitA()
{
for (int i = 0; i < 101; i++)
{
a[i] = i;
}
}
int FindNum(int x)
{
if (a[x] == x)
{
return x;
}
else
{
a[x] = FindNum(a[x]);
return a[x];
}
}
bool isUnion(int x, int y)
{
int fx = FindNum(x);
int fy = FindNum(y);
if (fx != fy)
{
a[fx] = fy;
return true;
}
return false;
}
bool isHuan()
{
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
if (i > 0 && numArray[i, j] == 1 && numArray[i - 1, j] == 1)
{ //当前格子上方
if (!isUnion(i * 10 + j, (i - 1) * 10 + j))
{
return true;
}
}
if (j > 0 && numArray[i, j] == 1 && numArray[i, j - 1] == 1)
{ //当前格子左边
if (!isUnion(i * 10 + j, i * 10 + j - 1))
{
return true;
}
}
}
}
return false;
}
二:判断当前格子是否在闭合环里面
一开始想的常规思路用向固定方向发出一条射线检测与边的交点个数来判断,具体看多边形边缘填充算法。但是很关键的是有个特殊情况如下
此时这种情况如果是向左发出射线的,那么1和2的检测情况是相同的,思来想去,发出一条射线检测还不够,考虑向上下左右四个方向发出射线,如果能走到红色边界如下,表示当前格子不在闭合环内。
算法如下
/// <summary>
/// 检测当前网格是否在闭合环里
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
bool isInside(int x,int y){
int curX=x;
int curY=y;
while(x>=-1){
if(x==-1){
return false;
}
if(numArray[x,y]==1){
break;
}
x--;
}
x=curX;
while(x<=10){
if(x==10){
return false;
}
if(numArray[x,y]==1){
break;
}
x++;
}
x=curX;
while(y>=-1){
if(y==-1){
return false;
}
if(numArray[x,y]==1){
break;
}
y--;
}
y=curY;
while(y<=10){
if(y==10){
return false;
}
if(numArray[x,y]==1){
break;
}
y++;
}
y=curY;
return true;
}
注意事项:
目前有个bug,因为基于并查集,只要检测到有环,他就会去填充,而不会去记录环,像以下这种情况。
我现在能想到的比较好的思路是这样:不用并查集,使用深搜或宽搜去记录有效环,把多余的像”树枝“的给去掉,但这个思路没有实现无法论证,希望有大佬可以给个建议。
项目地址:
源工程按F1运行,按F5刷新页面
Unity源工程链接百度网盘:
链接:https://pan.baidu.com/s/1wqaZek82NcuO9T4umvZykw
提取码:1212