Minetest-WorldEditAdditions/worldeditadditions/lib/floodfill.lua

92 lines
3.6 KiB
Lua
Raw Normal View History

2022-09-19 01:18:03 +02:00
local wea_c = worldeditadditions_core
local Vector3 = wea_c.Vector3
--- Flood-fill command for complex lakes etc.
-- @param start_pos Vector3 The position to start floodfilling from.
-- @param radius number The maximum radius to limit the floodfill operation too.
-- @param replace_node string The (normalised) name of the node to replace with when floodfilling.
-- @returns number The number of nodes replaced.
2020-05-11 00:29:49 +02:00
function worldeditadditions.floodfill(start_pos, radius, replace_node)
2022-09-19 01:18:03 +02:00
start_pos = Vector3.clone(start_pos)
-- Calculate the area we want to modify
2022-09-19 01:18:03 +02:00
local pos1 = start_pos + Vector3.new(radius, 0, radius)
local pos2 = start_pos - Vector3.new(radius, radius, radius)
pos1, pos2 = Vector3.sort(pos1, pos2)
-- pos2 will always have the highest co-ordinates now
-- 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
2018-05-20 15:19:43 +02:00
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)
2018-05-20 15:19:43 +02:00
local radius_sq = radius*radius
if search_id == replace_id then
return false
end
local count = 0
2022-09-19 01:18:03 +02:00
local remaining_nodes = wea_c.Queue.new() remaining_nodes:enqueue(start_pos_index)
-- Do the floodfill
while remaining_nodes:is_empty() == false do
local cur = remaining_nodes:dequeue()
-- Replace this node
data[cur] = replace_id
count = count + 1
2018-05-20 14:05:03 +02:00
-- Check all the nearby nodes
-- We don't need to go upwards here, since we're filling in lake-style
2018-05-20 14:05:03 +02:00
local xplus = cur + 1 -- +X
2018-05-20 15:19:43 +02:00
if data[xplus] == search_id and
2022-09-19 01:18:03 +02:00
(Vector3.clone(area:position(xplus)) - start_pos):length_squared() < radius_sq and
not remaining_nodes:contains(xplus) then
2018-05-20 14:05:03 +02:00
-- minetest.log("action", "[floodfill] [+X] index " .. xplus .. " is a " .. data[xplus] .. ", searching for a " .. search_id)
remaining_nodes:enqueue(xplus)
end
2018-05-20 14:05:03 +02:00
local xminus = cur - 1 -- -X
2018-05-20 15:19:43 +02:00
if data[xminus] == search_id and
2022-09-19 19:41:27 +02:00
(Vector3.clone(area:position(xminus)) - start_pos):length_squared() < radius_sq and
not remaining_nodes:contains(xminus) then
2018-05-20 14:05:03 +02:00
-- minetest.log("action", "[floodfill] [-X] index " .. xminus .. " is a " .. data[xminus] .. ", searching for a " .. search_id)
remaining_nodes:enqueue(xminus)
end
2018-05-20 14:05:03 +02:00
local zplus = cur + area.zstride -- +Z
2018-05-20 15:19:43 +02:00
if data[zplus] == search_id and
2022-09-19 19:41:27 +02:00
(Vector3.clone(area:position(zplus)) - start_pos):length_squared() < radius_sq and
not remaining_nodes:contains(zplus) then
2018-05-20 14:05:03 +02:00
-- minetest.log("action", "[floodfill] [+Z] index " .. zplus .. " is a " .. data[zplus] .. ", searching for a " .. search_id)
remaining_nodes:enqueue(zplus)
end
2018-05-20 14:05:03 +02:00
local zminus = cur - area.zstride -- -Z
2018-05-20 15:19:43 +02:00
if data[zminus] == search_id and
2022-09-19 19:41:27 +02:00
(Vector3.clone(area:position(zminus)) - start_pos):length_squared() < radius_sq and
not remaining_nodes:contains(zminus) then
2018-05-20 14:05:03 +02:00
-- minetest.log("action", "[floodfill] [-Z] index " .. zminus .. " is a " .. data[zminus] .. ", searching for a " .. search_id)
remaining_nodes:enqueue(zminus)
end
2018-05-20 14:05:03 +02:00
local yminus = cur - area.ystride -- -Y
2018-05-20 15:19:43 +02:00
if data[yminus] == search_id and
2022-09-19 19:41:27 +02:00
(Vector3.clone(area:position(yminus)) - start_pos):length_squared() < radius_sq and
not remaining_nodes:contains(yminus) then
2018-05-20 14:05:03 +02:00
-- minetest.log("action", "[floodfill] [-Y] index " .. yminus .. " is a " .. data[yminus] .. ", searching for a " .. search_id)
remaining_nodes:enqueue(yminus)
end
2018-05-20 14:05:03 +02:00
count = count + 1
end
-- Save the modified nodes back to disk & return
worldedit.manip_helpers.finish(manip, data)
return count
end