ОК, у меня есть несколько разных способов выполнения FloodFill.Все они вызывают проблемы.Я перечислю 3 метода и объясню, что происходит с каждым из них.Если бы кто-нибудь мог дать мне несколько советов, это было бы здорово.Я видел несколько подобных постов, но ни один из них не был для C #, Java или VB.net (единственные языки, которые я знаю).
Для этого есть то, что у меня есть класс с именем PixelData, который хранитЦвет в переменной-члене CellColor.У меня есть массив размером 50x50 объектов PixelData, называемый «пикселями».У меня также есть константа с именем CANVAS_SIZE, которая в данном случае равна 50.Вот три метода, которые я пытался использовать.
Этот рекурсивный.Это ЧРЕЗВЫЧАЙНО склонно к переполнению стека.Я попытался настроить таймер, который включил член CanFill после завершения этого метода.Это все еще не предотвращает переполнения:
private void FloodFill(Point node, Color targetColor, Color replaceColor)
{
//perform bounds checking X
if ((node.X >= CANVAS_SIZE) || (node.X < 0))
return; //outside of bounds
//perform bounds checking Y
if ((node.Y >= CANVAS_SIZE) || (node.Y < 0))
return; //ouside of bounds
//check to see if the node is the target color
if (pixels[node.X, node.Y].CellColor != targetColor)
return; //return and do nothing
else
{
pixels[node.X, node.Y].CellColor = replaceColor;
//recurse
//try to fill one step to the right
FloodFill(new Point(node.X + 1, node.Y), targetColor, replaceColor);
//try to fill one step to the left
FloodFill(new Point(node.X - 1, node.Y), targetColor, replaceColor);
//try to fill one step to the north
FloodFill(new Point(node.X, node.Y - 1), targetColor, replaceColor);
//try to fill one step to the south
FloodFill(new Point(node.X, node.Y + 1), targetColor, replaceColor);
//exit method
return;
}
}
Далее у меня есть метод, который использует заполнение на основе очереди.Этот метод вызывает исключения OutOfMemory во время выполнения и является ОЧЕНЬ медленным при заполнении всего холста.Если просто заполнить небольшую часть холста, это несколько эффективно:
private void QueueFloodFill(Point node, Color targetColor, Color replaceColor)
{
Queue<Point> points = new Queue<Point>();
if (pixels[node.X, node.Y].CellColor != targetColor)
return;
points.Enqueue(node);
while (points.Count > 0)
{
Point n = points.Dequeue();
if (pixels[n.X, n.Y].CellColor == targetColor)
pixels[n.X, n.Y].CellColor = replaceColor;
if (n.X != 0)
{
if (pixels[n.X - 1, n.Y].CellColor == targetColor)
points.Enqueue(new Point(n.X - 1, n.Y));
}
if (n.X != CANVAS_SIZE - 1)
{
if (pixels[n.X + 1, n.Y].CellColor == targetColor)
points.Enqueue(new Point(n.X + 1, n.Y));
}
if (n.Y != 0)
{
if (pixels[n.X, n.Y - 1].CellColor == targetColor)
points.Enqueue(new Point(n.X, n.Y - 1));
}
if (n.Y != CANVAS_SIZE - 1)
{
if (pixels[n.X, n.Y + 1].CellColor == targetColor)
points.Enqueue(new Point(n.X, n.Y + 1));
}
}
DrawCanvas();
return;
}
Последний метод, который я пробовал, также использует заливку на основе очереди.Этот метод НАМНОГО быстрее, чем предыдущая заливка на основе очереди, но также в конечном итоге вызывает исключения OutOfMemory во время выполнения.Снова, я попытался установить таймер FillDelay, который препятствовал бы быстрому щелчку пользователя, но это все еще не останавливает возникновение исключений.Еще одна ошибка, связанная с этим, заключается в том, что ему трудно правильно заполнять небольшие области.Я не вижу смысла исправлять это до тех пор, пока не смогу заставить его не разбиться.
private void RevisedQueueFloodFill(Point node, Color targetColor, Color replaceColor)
{
Queue<Point> q = new Queue<Point>();
if (pixels[node.X, node.Y].CellColor != targetColor)
return;
q.Enqueue(node);
while (q.Count > 0)
{
Point n = q.Dequeue();
if (pixels[n.X, n.Y].CellColor == targetColor)
{
Point e = n;
Point w = n;
while ((w.X != 0) && (pixels[w.X, w.Y].CellColor == targetColor))
{
pixels[w.X, w.Y].CellColor = replaceColor;
w = new Point(w.X - 1, w.Y);
}
while ((e.X != CANVAS_SIZE - 1) && (pixels[e.X, e.Y].CellColor == targetColor))
{
pixels[e.X, e.Y].CellColor = replaceColor;
e = new Point(e.X + 1, e.Y);
}
for (int i = w.X; i <= e.X; i++)
{
Point x = new Point(i, e.Y);
if (e.Y + 1 != CANVAS_SIZE - 1)
{
if (pixels[x.X, x.Y + 1].CellColor == targetColor)
q.Enqueue(new Point(x.X, x.Y + 1));
}
if (e.Y - 1 != -1)
{
if (pixels[x.X, x.Y - 1].CellColor == targetColor)
q.Enqueue(new Point(x.X, x.Y - 1));
}
}
}
}
}
Спасибо всем за помощь!Все эти методы основаны на псевдокоде в Википедии.
РЕДАКТИРОВАТЬ:
Я выбрал RevisedQueueFloodFill и изменил, как предложено, чтобы в циклах не объявлялись переменные.OutOfMemory все еще генерируется.Даже с таймером заполнения.
private void RevisedQueueFloodFill(Point node, Color targetColor, Color replaceColor)
{
Queue<Point> q = new Queue<Point>();
if (pixels[node.X, node.Y].CellColor != targetColor)
return;
q.Enqueue(node);
Point n, e, w, x;
while (q.Count > 0)
{
n = q.Dequeue();
if (pixels[n.X, n.Y].CellColor == targetColor)
{
e = n;
w = n;
while ((w.X != 0) && (pixels[w.X, w.Y].CellColor == targetColor))
{
pixels[w.X, w.Y].CellColor = replaceColor;
w = new Point(w.X - 1, w.Y);
}
while ((e.X != CANVAS_SIZE - 1) && (pixels[e.X, e.Y].CellColor == targetColor))
{
pixels[e.X, e.Y].CellColor = replaceColor;
e = new Point(e.X + 1, e.Y);
}
for (int i = w.X; i <= e.X; i++)
{
x = new Point(i, e.Y);
if (e.Y + 1 != CANVAS_SIZE - 1)
{
if (pixels[x.X, x.Y + 1].CellColor == targetColor)
q.Enqueue(new Point(x.X, x.Y + 1));
}
if (e.Y - 1 != -1)
{
if (pixels[x.X, x.Y - 1].CellColor == targetColor)
q.Enqueue(new Point(x.X, x.Y - 1));
}
}
}
}
}