我正在做计算机图形学的作业。
我们需要使用floodfill
来绘制区域,但是无论我如何更改Visual Studio的reserve stack
,它总是会跳出stackoverflow
。
void Polygon_FloodFill(HDC hdc, int x0, int y0, int fillColor, int borderColor) {
int interiorColor;
interiorColor = GetPixel(hdc, x0, y0);
if ((interiorColor != borderColor) && (interiorColor != fillColor)) {
SetPixel(hdc, x0, y0, fillColor);
Polygon_FloodFill(hdc, x0 + 1, y0, fillColor, borderColor);
Polygon_FloodFill(hdc, x0, y0 + 1, fillColor, borderColor);
Polygon_FloodFill(hdc, x0 - 1 ,y0, fillColor, borderColor);
Polygon_FloodFill(hdc, x0, y0 - 1, fillColor, borderColor);
}
答案 0 :(得分:1)
您可能要填充的区域太大,这会导致递归调用占用程序中的所有执行堆栈。
您的选择:
答案 1 :(得分:0)
什么导致堆栈溢出?
x0
的范围是多少? +/- 2,000,000,000?那就是您的堆栈深度潜力。
除非GetPixel(out-of-range)
返回不匹配值,否则代码显然不会阻止超出范围。
该如何解决?
代码在递归调用上需要更具选择性。
如果可以设置一行像素,则无需递归。
然后检查该行的邻居,并仅在邻居不需要持续进行设置时递归。
一种有前途的方法将处理中间问题,然后查看4个基本方向。
// Pseudo code
Polygon_FloodFill(x,y,c)
if (pixel(x,y) needs filling) {
set pixel(x,y,c);
for each of the 4 directions
// example: east
i = 1;
// fill the east line first
while (pixel(x+i,y) needs filling) {
i++;
set pixel(x,y,c);
}
// now examine the line above the "east" line
recursed = false;
for (j=1; j<i; j++) {
if (pixel(x+j, y+j) needs filling) {
if (!recursed) {
recursed = true;
Polygon_FloodFill(x+j,y+j,c)
} else {
// no need to call Polygon_FloodFill as will be caught with previous call
}
} else {
recursed = false;
}
}
// Same for line below the "east" line
// do same for south, west, north.
}
答案 2 :(得分:0)
要填充多少像素?每个像素都在递归深度一级,您会得到很多局部变量和递归函数的操作数+返回值和地址,因此对于到达像素,您可以存储以下变量:
void Polygon_FloodFill(HDC hdc, int x0, int y0, int fillColor, int borderColor) {
int interiorColor;
在32位环境中,我以[字节]为单位对此进行了估算:
4 Polygon_FloodFill return address
4 HDC hdc ?
4 int x0
4 int y0
4 int fillColor
4 int borderColor
4 int interiorColor
-------------------
~ 7*4 = 28 Bytes
可能还有更多取决于 C 引擎和调用顺序。
现在,如果您的填充区域具有256x256
像素,那么您需要:
7*4*256*256 = 1.75 MByte
堆栈/堆上的内存。您获得多少内存取决于编译/链接所使用的设置,因此转到项目选项并查找内存堆栈/堆限制...
如何处理?
降低堆栈/堆垃圾
仅对flood_fill
不使用操作数,而是将它们移动到全局变量:
HDC floodfill_hdc;
int floodfill_x0,floodfill_y0,floodfill_fillColor,floodfill_borderColor;
void _Polygon_FloodFill()
{
// here your original filling code
int interiorColor;
...
}
void PolygonFloodFill(HDC hdc, int x0, int y0, int fillColor, int borderColor) // this is what you call when want to fill something
{
floodfill_hdc=hdc;
floodfill_x0=x0;
floodfill_y0=y0;
floodfill_fillColor=fillColor;
floodfill_borderColor=borderColor;
_Polygon_FloodFill();
}
这将允许填充约14倍大的区域。
限制递归深度
有时也称为优先级que ...您只需添加一个全局计数器即可计算实际的递归深度,如果命中极限值,则不允许递归。而是将像素位置添加到实际递归停止后将要处理的某些列表。
将填充从像素更改为线条
这只是消除了从sqrt(n)
到n
递归的粗略估计中的许多递归调用……您只需从起点到预定方向填充整行,直到碰到边界..因此,您只需要每行而不是每个像素进行递归调用。下面是示例(请参见[edit2]):
但是函数名称Polygon_FloodFill
表示您获得了矢量形式的边界多边形。如果使用填充栅格,比使用以下栅格栅格化技术会更快更快:
但是,该多边形必须是凸多边形,因此,如果不是这样,则需要首先进行三角剖分或分解为凸多边形(例如,使用耳朵剪裁)。