Reputation: 37
I'm trying to implement the pseudocode for flood fill algorithm. I took it from Graphics Gemes 1.
Here is the pseudocode:
Unfortunateley, when I implemented it in JavaScript, it hangs when I use my floodfill tool. Here is my code:
function inside(x, y) {
const q = 4 * (x + y * that.w);
const color = [img.data[q], img.data[q + 1], img.data[q + 2], img.data[q + 3]];
return color[0] === toolColor[0] &&
color[1] === toolColor[1] &&
color[2] === toolColor[2];
}
function set(x, y) {
const q = 4 * (x + y * that.w);
img.data[q] = that.color.r;
img.data[q + 1] = that.color.g;
img.data[q + 2] = that.color.b;
img.data[q + 3] = that.color.a;
}
function doFloodFill(x, y) {
let skip = false, x1, x2, dy, start;
const s = [];
s.push([y, x, x, 1]);
s.push([y + 1, x, x, -1]);
while (s.length > 0) {
const n = s.pop();
y = n[3] + n[0];
x1 = n[1];
x2 = n[2];
dy = n[3];
x = x1;
while (x >= 0 && inside(x, y)) {
set(x, y);
x--;
}
if (x >= x1) {
//skip
skip = true;
}
if (!skip) {
start = x + 1;
if (start < x1) {
s.push([y, start, x1 - 1, -dy]);
}
x = x1 + 1;
}
do {
if (!skip) {
while (x <= that.w && inside(x, y)) {
set(x, y);
x++;
}
s.push([y, start, x - 1, dy]);
if (x > x2 + 1) {
s.push([y, x2 + 1, x - 1, -dy]);
}
}
//skip
x++;
while (x <= x2 && !inside(x, y)) {
x++;
}
skip = false;
} while (x < x2);
start = x;
}
}
img.data
is a flat array later displayed in the browser.
toolColor
is 4-element array containing color for area to be filled with.
What I'm doing wrong?
Other more simple algorithms works with inside and set functions so they seem to be ok.
If You need more of the code I can send it privately.
Edit: I updated the code and now it fills only part of area.
Upvotes: 0
Views: 186
Reputation: 37
Ok, I fixed the code. It is very fast. Maybe someone will make use of it.
Here is updated code:
function inside(x, y) {
const q = 4 * (x + y * that.w);
const color = [img.data[q], img.data[q + 1], img.data[q + 2], img.data[q + 3]];
return color[0] === toolColor[0] &&
color[1] === toolColor[1] &&
color[2] === toolColor[2];
}
function set(x, y) {
const q = 4 * (x + y * that.w);
img.data[q] = that.color.r;
img.data[q + 1] = that.color.g;
img.data[q + 2] = that.color.b;
img.data[q + 3] = that.color.a;
}
function doFloodFill(x, y) {
let skip = false, x1, x2, dy, start;
const s = [];
s.push([y, x, x, 1]);
s.push([y + 1, x, x, -1]);
while (s.length > 0) {
const n = s.pop();
y = n[3] + n[0];
x1 = n[1];
x2 = n[2];
dy = n[3];
x = x1;
while (x >= 0 && inside(x, y)) {
set(x, y);
x--;
}
if (x >= x1) {
//skip
skip = true;
}
if (!skip) {
start = x + 1;
if (start < x1) {
s.push([y, start, x1 - 1, -dy]);
}
x = x1 + 1;
}
do {
if (!skip) {
while (x <= that.w && inside(x, y)) {
set(x, y);
x++;
}
s.push([y, start, x - 1, dy]);
if (x > x2 + 1) {
s.push([y, x2 + 1, x - 1, -dy]);
}
}
//skip
x++;
while (x <= x2 && !inside(x, y)) {
x++;
}
start = x;
skip = false;
} while (x < x2);
}
}
I made a basic mistake. skip value was outside the last loop, but it should be inside.
Moreover, y value was incorrectly initialized in loop, should be: y = n[3] + n[0];
instead of y = n[0];
The code on English Wikipedia related to this algorithm seems to be incorrect.
I made speed tests of this algorithm. My implementation is about 1.5 times faster than the code on Wikipedia.
Upvotes: 1