RosettaCodeData/Task/Bitmap-Flood-fill/E/bitmap-flood-fill-1.e
2023-07-01 13:44:08 -04:00

69 lines
1.9 KiB
Text

def floodFill(image, x, y, newColor) {
def matchColor := image[x, y]
def w := image.width()
def h := image.height()
/** For any given pixel x,y, this algorithm first fills a contiguous
horizontal line segment of pixels containing that pixel, then
recursively scans the two adjacent rows over the same horizontal
interval. Let this be invocation 0, and the immediate recursive
invocations be 1, 2, 3, ..., # be pixels of the wrong color, and
* be where each scan starts; the fill ordering is as follows:
--------------##########-------
-...1111111111*11####*33333...-
###########000*000000000000...-
-...2222222222*22222##*4444...-
--------------------##---------
Each invocation returns the x coordinate of the rightmost pixel it filled,
or x0 if none were.
Since it is recursive, this algorithm is unsuitable for large images
with small stacks.
*/
def fillScan(var x0, y) {
if (y >= 0 && y < h && x0 >= 0 && x0 < w) {
image[x0, y] := newColor
var x1 := x0
# Fill rightward
while (x1 < w - 1 && image.test(x1 + 1, y, matchColor)) {
x1 += 1
image[x1, y] := newColor # This could be replaced with a horizontal-line drawing operation
}
# Fill leftward
while (x0 > 0 && image.test(x0 - 1, y, matchColor)) {
x0 -= 1
image[x0, y] := newColor
}
if (x0 > x1) { return x0 } # Filled at most center
# x0..x1 is now a run of newly-filled pixels.
# println(`Filled $y $x0..$x1`)
# println(image)
# Scan the lines above and below
for ynext in [y - 1, y + 1] {
if (ynext >= 0 && ynext < h) {
var x := x0
while (x <= x1) {
if (image.test(x, ynext, matchColor)) {
x := fillScan(x, ynext)
}
x += 1
}
}
}
return x1
} else {
return x0
}
}
fillScan(x, y)
}