Add optimised radius checking

This commit is contained in:
Starbeamrainbowlabs 2018-05-20 14:19:43 +01:00
parent 7288347479
commit 9412a1bf30
Signed by: sbrl
GPG key ID: 1BE5172E637709C2
4 changed files with 32 additions and 28 deletions

View file

@ -43,39 +43,22 @@ end
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
-- These really should be in a utilities file, but Lua is being stupid and preventing access to it (and minetest is also being stupid, as we can't modularise our code the way you ought to be able to - or at least the documentation on dofile() is so poor I've no idea at this point)
local function vector2string(v)
return "(" .. v.x ..", " .. v.y ..", " .. v.z ..")"
end
local clock = os.clock
function sleep(n) -- seconds
local t0 = clock()
while clock() - t0 <= n do end
end
function worldedit.floodfill(start_pos, radius, replace_node) function worldedit.floodfill(start_pos, radius, replace_node)
-- Calculate the area we want to modify -- Calculate the area we want to modify
local pos1 = vector.add(start_pos, { x = radius, y = 0, z = radius }) local pos1 = vector.add(start_pos, { x = radius, y = 0, z = radius })
local pos2 = vector.subtract(start_pos, { x = radius, y = radius, z = radius }) local pos2 = vector.subtract(start_pos, { x = radius, y = radius, z = radius })
pos1, pos2 = worldedit.sort_pos(pos1, pos2) -- Just in case pos1, pos2 = worldedit.sort_pos(pos1, pos2) -- Just in case
minetest.log("action", "radius: " .. radius)
minetest.log("action", "pos1: " .. vector2string(pos1))
minetest.log("action", "pos2: " .. vector2string(pos2))
-- Fetch the nodes in the specified area -- Fetch the nodes in the specified area
local manip, area = worldedit.manip_helpers.init(pos1, pos2) local manip, area = worldedit.manip_helpers.init(pos1, pos2)
local data = manip:get_data() local data = manip:get_data()
-- Setup for the floodfill operation itself -- Setup for the floodfill operation itself
local start_pos_index = area:index(start_pos.x, start_pos.y, start_pos.z); local start_pos_index = area:index(start_pos.x, start_pos.y, start_pos.z)
local search_id = data[start_pos_index] local search_id = data[start_pos_index]
local replace_id = minetest.get_content_id(replace_node) local replace_id = minetest.get_content_id(replace_node)
local radius_sq = radius*radius
minetest.log("action", "ids: " .. search_id .. " -> " .. replace_id)
local count = 0 local count = 0
local remaining_nodes = Queue.new() local remaining_nodes = Queue.new()
@ -94,27 +77,37 @@ function worldedit.floodfill(start_pos, radius, replace_node)
-- Check all the nearby nodes -- Check all the nearby nodes
-- We don't need to go upwards here, since we're filling in lake-style -- We don't need to go upwards here, since we're filling in lake-style
local xplus = cur + 1 -- +X local xplus = cur + 1 -- +X
if data[xplus] == search_id and not Queue.contains(remaining_nodes, xplus) then if data[xplus] == search_id and
worldeditadditions.vector.lengthsquared(vector.subtract(area:position(xplus), start_pos)) < radius_sq and
not Queue.contains(remaining_nodes, xplus) then
-- minetest.log("action", "[floodfill] [+X] index " .. xplus .. " is a " .. data[xplus] .. ", searching for a " .. search_id) -- minetest.log("action", "[floodfill] [+X] index " .. xplus .. " is a " .. data[xplus] .. ", searching for a " .. search_id)
Queue.enqueue(remaining_nodes, xplus) Queue.enqueue(remaining_nodes, xplus)
end end
local xminus = cur - 1 -- -X local xminus = cur - 1 -- -X
if data[xminus] == search_id and not Queue.contains(remaining_nodes, xminus) then if data[xminus] == search_id and
worldeditadditions.vector.lengthsquared(vector.subtract(area:position(xminus), start_pos)) < radius_sq and
not Queue.contains(remaining_nodes, xminus) then
-- minetest.log("action", "[floodfill] [-X] index " .. xminus .. " is a " .. data[xminus] .. ", searching for a " .. search_id) -- minetest.log("action", "[floodfill] [-X] index " .. xminus .. " is a " .. data[xminus] .. ", searching for a " .. search_id)
Queue.enqueue(remaining_nodes, xminus) Queue.enqueue(remaining_nodes, xminus)
end end
local zplus = cur + area.zstride -- +Z local zplus = cur + area.zstride -- +Z
if data[zplus] == search_id and not Queue.contains(remaining_nodes, zplus) then if data[zplus] == search_id and
worldeditadditions.vector.lengthsquared(vector.subtract(area:position(zplus), start_pos)) < radius_sq and
not Queue.contains(remaining_nodes, zplus) then
-- minetest.log("action", "[floodfill] [+Z] index " .. zplus .. " is a " .. data[zplus] .. ", searching for a " .. search_id) -- minetest.log("action", "[floodfill] [+Z] index " .. zplus .. " is a " .. data[zplus] .. ", searching for a " .. search_id)
Queue.enqueue(remaining_nodes, zplus) Queue.enqueue(remaining_nodes, zplus)
end end
local zminus = cur - area.zstride -- -Z local zminus = cur - area.zstride -- -Z
if data[zminus] == search_id and not Queue.contains(remaining_nodes, zminus) then if data[zminus] == search_id and
worldeditadditions.vector.lengthsquared(vector.subtract(area:position(zminus), start_pos)) < radius_sq and
not Queue.contains(remaining_nodes, zminus) then
-- minetest.log("action", "[floodfill] [-Z] index " .. zminus .. " is a " .. data[zminus] .. ", searching for a " .. search_id) -- minetest.log("action", "[floodfill] [-Z] index " .. zminus .. " is a " .. data[zminus] .. ", searching for a " .. search_id)
Queue.enqueue(remaining_nodes, zminus) Queue.enqueue(remaining_nodes, zminus)
end end
local yminus = cur - area.ystride -- -Y local yminus = cur - area.ystride -- -Y
if data[yminus] == search_id and not Queue.contains(remaining_nodes, yminus) then if data[yminus] == search_id and
worldeditadditions.vector.lengthsquared(vector.subtract(area:position(yminus), start_pos)) < radius_sq and
not Queue.contains(remaining_nodes, yminus) then
-- minetest.log("action", "[floodfill] [-Y] index " .. yminus .. " is a " .. data[yminus] .. ", searching for a " .. search_id) -- minetest.log("action", "[floodfill] [-Y] index " .. yminus .. " is a " .. data[yminus] .. ", searching for a " .. search_id)
Queue.enqueue(remaining_nodes, yminus) Queue.enqueue(remaining_nodes, yminus)
end end

View file

@ -5,4 +5,7 @@
-- @license Mozilla Public License, 2.0 -- @license Mozilla Public License, 2.0
-- @author Starbeamrainbowlabs -- @author Starbeamrainbowlabs
worldeditadditions = {}
dofile(minetest.get_modpath("worldeditadditions") .. "/utils.lua")
dofile(minetest.get_modpath("worldeditadditions") .. "/floodfill.lua") dofile(minetest.get_modpath("worldeditadditions") .. "/floodfill.lua")

View file

@ -0,0 +1,9 @@
worldeditadditions.vector = {}
function worldeditadditions.vector.tostring(v)
return "(" .. v.x ..", " .. v.y ..", " .. v.z ..")"
end
function worldeditadditions.vector.lengthsquared(v)
return v.x*v.x + v.y*v.y + v.z*v.z
end

View file

@ -24,11 +24,10 @@ minetest.register_chatcommand("/floodfill", {
replace_node = worldedit.normalize_nodename(replace_node) replace_node = worldedit.normalize_nodename(replace_node)
minetest.log("action", "Floodfill settings - node: " .. replace_node .. ", radius: " .. radius) local start_time = os.clock()
local nodes_replaced = worldedit.floodfill(worldedit.pos1[name], radius, replace_node) local nodes_replaced = worldedit.floodfill(worldedit.pos1[name], radius, replace_node)
worldedit.player_notify(name, nodes_replaced .. " replaced") worldedit.player_notify(name, nodes_replaced .. " nodes replaced in " .. (os.clock() - start_time) .. "s")
minetest.log("action", name .. "used floodfill at (" .. worldedit.pos1[name].x .. "," .. worldedit.pos1[name].y .. "," .. worldedit.pos1[name].z .. "), replacing " .. nodes_replaced .. " nodes") minetest.log("action", name .. " used floodfill at " .. worldeditadditions.vector.tostring(worldedit.pos1[name]) .. ", replacing " .. nodes_replaced .. " nodes in " .. (os.clock() - start_time) .. "s")
end end
}) })