From dc368f7a7ea07b4c7c6d293d21700a32f64f8e42 Mon Sep 17 00:00:00 2001 From: HybridDog Date: Sun, 1 Dec 2019 11:00:53 +0100 Subject: [PATCH] Add untested efficient flood fill algorithm http://www.adammil.net/blog/v126_A_More_Efficient_Flood_Fill.html --- adammil_flood_fill.lua | 116 +++++++++++++++++++++++++++++++++++++++++ init.lua | 27 ++++++---- 2 files changed, 132 insertions(+), 11 deletions(-) create mode 100644 adammil_flood_fill.lua diff --git a/adammil_flood_fill.lua b/adammil_flood_fill.lua new file mode 100644 index 0000000..b6ceed9 --- /dev/null +++ b/adammil_flood_fill.lua @@ -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 diff --git a/init.lua b/init.lua index be8e593..1303e3a 100644 --- a/init.lua +++ b/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