3D数组边界寻路算法咨询:密闭结构漏洞检测方案
需求说明
我需要一种可搜索3D数组的算法,能判断从单个点到数组任意边界的可行路径,核心需求是检测三维空间内的中空结构是否“密闭”——也就是内部物体能否通过漏洞逃逸。
我要的是计算成本最低的路径存在性验证方案,不需要最短路径。目前搜到的都是“最短路径”或“最小阻力路径”算法,不符合需求。我希望获取相关原理资料、文档或文章,不是直接的复制粘贴解决方案。
3D数组最大尺寸为[256,256,256],内部结构通常更小,数组中每个元素类似带6面墙的空房间。
更新:临时解决方案
还没找到理想算法,但整理出了一个临时思路:
研究发现flood-fill算法可以参考,但递归实现容易栈溢出(仅支持约18000深度,远小于256³的需求);之后了解到scan-line filling(扫描线填充),但只找到2D像素图形或3D点模型的实现,最终自己整合出3D扫描线填充算法,能在约2秒内完成256³区域的填充,以下是C#实现代码:
private void MyScanLine3DFill(int x, int y, int z) { Stack<Block> blocks = new Stack<Block>(); //创建栈 blocks.Push(grid[x, y, z]); //从指定起始位置初始化待检查栈 bool spanWest; bool spanEast; bool spanSouth; bool spanNorth; while (blocks.Count != 0) //栈非空时循环处理 { Block temp = blocks.Pop(); //取出栈顶的块 int y1 = temp.coords.Item2; //获取块的y坐标 while (y1 >= 0 && grid[temp.coords.Item1, y1, temp.coords.Item3].isSealed == false) //沿列向下直到遇到封闭块 { y1--; //向下移动一个块 } y1++; //向上回退一个块 spanWest = false; //重置当前循环的跨度标记 spanEast = false; spanSouth = false; spanNorth = false; while (y1 < maxY && grid[temp.coords.Item1, y1, temp.coords.Item3].isSealed == false) //沿列向上直到遇到封闭块 { grid[temp.coords.Item1, y1, temp.coords.Item3].isSealed = true; //标记当前块为已封闭 //检查西侧块 if (!spanWest && temp.coords.Item1 > 0 && grid[temp.coords.Item1 - 1, y1, temp.coords.Item3].isSealed == false) //如果西侧有未封闭块 { blocks.Push(new Block(airBlock, (temp.coords.Item1 - 1, y1, temp.coords.Item3))); //将西侧未封闭块入栈 spanWest = true; } else if (spanWest && temp.coords.Item1 - 1 == 0 && grid[temp.coords.Item1 - 1, y1, temp.coords.Item3].isSealed != false) //如果西侧是封闭块 { spanWest = false; } //检查东侧块 if (!spanEast && temp.coords.Item1 < maxX - 1 && grid[temp.coords.Item1 + 1, y1, temp.coords.Item3].isSealed == false) //如果东侧有未封闭块 { blocks.Push(new Block(airBlock, (temp.coords.Item1 + 1, y1, temp.coords.Item3))); //将东侧未封闭块入栈 spanEast = true; } else if (spanEast && temp.coords.Item1 < maxX - 1 && grid[temp.coords.Item1 + 1, y1, temp.coords.Item3].isSealed != false) //如果东侧是封闭块 { spanEast = false; } //检查南侧块 if (!spanSouth && temp.coords.Item3 > 0 && grid[temp.coords.Item1, y1, temp.coords.Item3 - 1].isSealed == false) //如果南侧有未封闭块 { blocks.Push(new Block(airBlock, (temp.coords.Item1, y1, temp.coords.Item3 - 1))); //将南侧未封闭块入栈 spanSouth = true; } else if (spanSouth && temp.coords.Item3 - 1 == 0 && grid[temp.coords.Item1, y1, temp.coords.Item3 - 1].isSealed != false) //如果南侧是封闭块 { spanSouth = false; } //检查北侧块 if (!spanNorth && temp.coords.Item3 < maxZ - 1 && grid[temp.coords.Item1, y1, temp.coords.Item3 + 1].isSealed == false) //如果北侧有未封闭块 { blocks.Push(new Block(airBlock, (temp.coords.Item1, y1, temp.coords.Item3 + 1))); //将北侧未封闭块入栈 spanNorth = true; } else if (spanNorth && temp.coords.Item3 < maxZ - 1 && grid[temp.coords.Item1, y1, temp.coords.Item3 + 1].isSealed != false) //如果北侧是封闭块 { spanNorth = false; } y1++; //向上移动一个块 } } //如果需要则刷新网格 }
内容的提问来源于stack exchange,提问作者David Martin
相关产品推荐
相关产品推荐

