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)
-- Calculate the area we want to modify
local pos1 = vector.add(start_pos, { x = radius, y = 0, z = radius })
local pos2 = vector.subtract(start_pos, { x = radius, y = radius, z = radius })
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
local manip, area = worldedit.manip_helpers.init(pos1, pos2)
local data = manip:get_data()
-- 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 replace_id = minetest.get_content_id(replace_node)
minetest.log("action", "ids: " .. search_id .. " -> " .. replace_id)
local radius_sq = radius*radius
local count = 0
local remaining_nodes = Queue.new()
@ -94,27 +77,37 @@ function worldedit.floodfill(start_pos, radius, replace_node)
-- Check all the nearby nodes
-- We don't need to go upwards here, since we're filling in lake-style
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)
Queue.enqueue(remaining_nodes, xplus)
end
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)
Queue.enqueue(remaining_nodes, xminus)
end
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)
Queue.enqueue(remaining_nodes, zplus)
end
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)
Queue.enqueue(remaining_nodes, zminus)
end
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)
Queue.enqueue(remaining_nodes, yminus)
end

View file

@ -5,4 +5,7 @@
-- @license Mozilla Public License, 2.0
-- @author Starbeamrainbowlabs
worldeditadditions = {}
dofile(minetest.get_modpath("worldeditadditions") .. "/utils.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)
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)
worldedit.player_notify(name, nodes_replaced .. " replaced")
minetest.log("action", name .. "used floodfill at (" .. worldedit.pos1[name].x .. "," .. worldedit.pos1[name].y .. "," .. worldedit.pos1[name].z .. "), replacing " .. nodes_replaced .. " nodes")
worldedit.player_notify(name, nodes_replaced .. " nodes replaced in " .. (os.clock() - start_time) .. "s")
minetest.log("action", name .. " used floodfill at " .. worldeditadditions.vector.tostring(worldedit.pos1[name]) .. ", replacing " .. nodes_replaced .. " nodes in " .. (os.clock() - start_time) .. "s")
end
})