1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
|
-- Fill clicked region with current drawing state.
-- Author: Andrew Trevorrow (andrew@trevorrow.com), Apr 2016.
local g = golly()
local gp = require "gplus"
-- avoid an unbounded fill
local minx, miny, maxx, maxy
if g.empty() then
if g.getwidth() == 0 or g.getheight() == 0 then
g.exit("You cannot fill an empty universe that is unbounded!")
end
else
-- set fill limits to the pattern's bounding box
-- (these will be extended below if the grid is bounded)
minx, miny, maxx, maxy = gp.getedges(g.getrect())
end
-- allow filling to extend to the edges of bounded grid
if g.getwidth() > 0 then
minx = -gp.int(g.getwidth() / 2)
maxx = minx + g.getwidth() - 1
end
if g.getheight() > 0 then
miny = -gp.int(g.getheight() / 2)
maxy = miny + g.getheight() - 1
end
--------------------------------------------------------------------------------
function floodfill()
local newstate = g.getoption("drawingstate")
local oldstate = newstate
local x, y
-- wait for user to click a cell
g.show("Click the region you wish to fill... (hit escape to abort)")
while oldstate == newstate do
local event = g.getevent()
if event:find("click") == 1 then
-- event is a string like "click 10 20 left none"
local evt, xstr, ystr, butt, mods = gp.split(event)
x = tonumber(xstr)
y = tonumber(ystr)
if x < minx or x > maxx or y < miny or y > maxy then
-- click is outside pattern's bounding box in unbounded universe
g.warn("Click within the pattern's bounding box\n"..
"otherwise the fill will be unbounded.")
else
-- note that user might have changed drawing state
newstate = g.getoption("drawingstate")
oldstate = g.getcell(x, y)
if oldstate == newstate then
g.warn("The clicked cell must have a different state\n"..
"to the current drawing state.")
end
end
else
g.doevent(event)
end
end
-- tell Golly to handle all further keyboard/mouse events
g.getevent(false)
g.show("Filling clicked region... (hit escape to stop)")
-- do flood fill starting with clicked cell using a scanline algorithm
local oldsecs = os.clock()
local clist = {}
clist[1] = {x, y}
while #clist > 0 do
-- remove cell from end of clist (much faster than removing from start)
x, y = table.unpack( table.remove(clist) )
local above = false
local below = false
while x >= minx and g.getcell(x, y) == oldstate do
x = x-1
end
x = x+1
while x <= maxx and g.getcell(x, y) == oldstate do
g.setcell(x, y, newstate)
if (not above) and y > miny and g.getcell(x, y-1) == oldstate then
clist[#clist+1] = {x, y-1}
above = true
elseif above and y > miny and g.getcell(x, y-1) ~= oldstate then
above = false
end
if (not below) and y < maxy and g.getcell(x, y+1) == oldstate then
clist[#clist+1] = {x, y+1}
below = true
elseif below and y < maxy and g.getcell(x, y+1) ~= oldstate then
below = false
end
x = x+1
end
local newsecs = os.clock()
if newsecs - oldsecs >= 0.5 then -- show changed pattern every half second
oldsecs = newsecs
g.update()
end
end
end
--------------------------------------------------------------------------------
oldcursor = g.getcursor()
g.setcursor("Draw")
local status, err = xpcall(floodfill, gp.trace)
if err then g.continue(err) end
-- the following code is executed even if error occurred or user aborted script
g.setcursor(oldcursor)
g.show(" ")
|