mirror of
https://github.com/HybridDog/vector_extras.git
synced 2024-11-26 09:23:47 +01:00
Add untested efficient flood fill algorithm
http://www.adammil.net/blog/v126_A_More_Efficient_Flood_Fill.html
This commit is contained in:
parent
8d78f3cb9b
commit
dc368f7a7e
116
adammil_flood_fill.lua
Normal file
116
adammil_flood_fill.lua
Normal file
@ -0,0 +1,116 @@
|
||||
-- http://www.adammil.net/blog/v126_A_More_Efficient_Flood_Fill.html
|
||||
|
||||
local can_go
|
||||
local marked_places
|
||||
local function calc_2d_index(x, y)
|
||||
return (y + 32768) * 65536 + x + 32768
|
||||
end
|
||||
local function mark(x, y)
|
||||
marked_places[calc_2d_index(x, y)] = true
|
||||
end
|
||||
|
||||
local _fill
|
||||
local function fill(x, y)
|
||||
if can_go(x, y) then
|
||||
_fill(x, y)
|
||||
end
|
||||
end
|
||||
|
||||
local corefill
|
||||
function _fill(x, y)
|
||||
while true do
|
||||
local ox = x
|
||||
local oy = y
|
||||
while can_go(x, y-1) do
|
||||
y = y-1
|
||||
end
|
||||
while can_go(x-1, y) do
|
||||
x = x-1
|
||||
end
|
||||
if x == ox
|
||||
and y == oy then
|
||||
break
|
||||
end
|
||||
end
|
||||
corefill(x, y)
|
||||
end
|
||||
|
||||
function corefill(x, y)
|
||||
local lastcnt = 0
|
||||
repeat
|
||||
local cnt = 0
|
||||
local sx = x
|
||||
if lastcnt ~= 0
|
||||
and not can_go(y, x) then
|
||||
-- go right to find the x start
|
||||
repeat
|
||||
lastcnt = lastcnt-1
|
||||
if lastcnt == 0 then
|
||||
return
|
||||
end
|
||||
x = x+1
|
||||
until can_go(x, y)
|
||||
sx = x
|
||||
else
|
||||
-- go left if possible, and mark and _fill above
|
||||
while can_go(x-1, y) do
|
||||
x = x-1
|
||||
mark(x, y)
|
||||
if can_go(x, y-1) then
|
||||
_fill(x, y-1)
|
||||
end
|
||||
cnt = cnt+1
|
||||
lastcnt = lastcnt+1
|
||||
end
|
||||
end
|
||||
|
||||
-- go right if possible, and mark
|
||||
while can_go(sx, y) do
|
||||
mark(sx, y)
|
||||
cnt = cnt+1
|
||||
sx = sx+1
|
||||
end
|
||||
|
||||
if cnt < lastcnt then
|
||||
local e = x + lastcnt
|
||||
sx = sx+1
|
||||
while sx < e do
|
||||
if can_go(sx, y) then
|
||||
corefill(sx, y)
|
||||
end
|
||||
sx = sx+1
|
||||
end
|
||||
elseif cnt > lastcnt then
|
||||
local ux = x + lastcnt + 1
|
||||
while ux < sx do
|
||||
if can_go(ux, y-1) then
|
||||
_fill(ux, y-1)
|
||||
end
|
||||
ux = ux+1
|
||||
end
|
||||
end
|
||||
lastcnt = cnt
|
||||
y = y+1
|
||||
until lastcnt == 0
|
||||
end
|
||||
|
||||
local function apply_fill(go_test, x0, y0, allow_revisit)
|
||||
if allow_revisit then
|
||||
can_go = go_test
|
||||
else
|
||||
local visited = {}
|
||||
can_go = function(x, y)
|
||||
local vi = calc_2d_index(x, y)
|
||||
if visited[vi] then
|
||||
return false
|
||||
end
|
||||
visited[vi] = true
|
||||
return go_test(x, y)
|
||||
end
|
||||
end
|
||||
marked_places = {}
|
||||
fill(x0, y0)
|
||||
return marked_places
|
||||
end
|
||||
|
||||
return apply_fill
|
27
init.lua
27
init.lua
@ -1,4 +1,4 @@
|
||||
local load_time_start = minetest.get_us_time()
|
||||
local path = minetest.get_modpath"vector_extras"
|
||||
|
||||
local funcs = {}
|
||||
|
||||
@ -399,6 +399,21 @@ function funcs.from_number(i)
|
||||
return {x=i, y=i, z=i}
|
||||
end
|
||||
|
||||
local adammil_fill = dofile(path .. "/adammil_flood_fill.lua")
|
||||
function funcs.search_2d(go_test, x0, y0, allow_revisit, give_map)
|
||||
marked_places = adammil_fill(go_test, x0, y0, allow_revisit)
|
||||
if give_map then
|
||||
return marked_places
|
||||
end
|
||||
local l = {}
|
||||
for vi in pairs(marked_places) do
|
||||
local x = (vi % 65536) - 32768
|
||||
local y = (math.floor(x / 65536) % 65536) - 32768
|
||||
l[#l+1] = {x, y}
|
||||
end
|
||||
return l
|
||||
end
|
||||
|
||||
local explosion_tables = {}
|
||||
function funcs.explosion_table(r)
|
||||
local table = explosion_tables[r]
|
||||
@ -961,7 +976,6 @@ end
|
||||
|
||||
vector_extras_functions = funcs
|
||||
|
||||
local path = minetest.get_modpath"vector_extras"
|
||||
dofile(path .. "/legacy.lua")
|
||||
--dofile(minetest.get_modpath("vector_extras").."/vector_meta.lua")
|
||||
|
||||
@ -976,12 +990,3 @@ for name,func in pairs(funcs) do
|
||||
vector[name] = func
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local time = (minetest.get_us_time() - load_time_start) / 1000000
|
||||
local msg = "[vector_extras] loaded after ca. " .. time .. " seconds."
|
||||
if time > 0.01 then
|
||||
print(msg)
|
||||
else
|
||||
minetest.log("info", msg)
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user