Minetest-WorldEditAdditions/worldeditadditions/lib/spiral_square.lua
Starbeamrainbowlabs ad789d500a
Implement spiral square, but it's untested.
It would also be awesome to customise the directional plane upon which 
the spiral is generated. It might actually be possible without melting 
my brain I think....


Looking at http://www.mathematische-basteleien.de/spiral.htm it should 
be possible to go this for circles too. But there's 1 particular 
function in Vector2.js that we need to port to Vector3.lua that we 
haven't yet which we'd need for that.....
2021-10-30 02:46:25 +01:00

83 lines
3.3 KiB
Lua

local wea = worldeditadditions
local Vector3 = wea.Vector3
-- ███████ ██████ ██ ██████ █████ ██
-- ██ ██ ██ ██ ██ ██ ██ ██ ██
-- ███████ ██████ ██ ██████ ███████ ██
-- ██ ██ ██ ██ ██ ██ ██ ██
-- ███████ ██ ██ ██ ██ ██ ██ ███████
--
-- ███████ ██████ ██ ██ █████ ██████ ███████
-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
-- ███████ ██ ██ ██ ██ ███████ ██████ █████
-- ██ ██ ▄▄ ██ ██ ██ ██ ██ ██ ██ ██
-- ███████ ██████ ██████ ██ ██ ██ ██ ███████
-- ▀▀
--- Creates a square spiral that fills the defined region.
-- @param pos1 Vector3 The 1st position of the defined region.
-- @param pos2 Vector3 The 2nd position of the defined region.
-- @param target_node Vector3 The *normalised* name of the node to use to build the square spiral with.
-- @param interval number The distance between the walls of the spiral.
-- @param acceleration=0 number Increate the interval by this number every time we hit a corner of the square spiral.
-- @returns bool,number|string A success boolean value, followed by either the number of the nodes set or an error message string.
function worldeditadditions.spiral_square(pos1, pos2, target_node, interval, acceleration)
if not acceleration then acceleration = 0 end
pos1, pos2 = Vector3.sort(pos1, pos2)
local volume = pos2:subtract(pos1)
local volume_half = volume:divide(2)
print("DEBUG:spiral_square | pos1: "..pos1..", pos2: "..pos2..", target_node: "..target_node)
-- Fetch the nodes in the specified area
local manip, area = worldedit.manip_helpers.init(pos1, pos2)
local data = manip:get_data()
local node_id = minetest.get_content_id(target_node)
local count = 0 -- The number of nodes replaced
local centre = pos2:subtract(pos1):floor()
local pos_current = centre:clone()
local pos_corner_last = pos_current:clone()
local side_length = 0
local direction = Vector3.new(1, 0, 0)
local side_length_max = interval
while pos_current:is_contained(pos1, pos2) do
for y = pos2.y, pos1.y, -1 do
data[area:index(pos_current.x, y, pos_current.z)] = node_id
count = count + 1
end
pos_current = pos_current:add(direction)
side_length = side_length + 1
if side_length > side_length_max then
side_length_max = side_length_max + interval + acceleration
if direction.x == 0 and direction.z == 1 then
direction.x = 1
direction.z = 0
elseif direction.x == 1 and direction.z == 0 then
direction.x = 0
direction.z = -1
elseif direction.x == 0 and direction.z == -1 then
direction.x = -1
direction.z = 0
else
direction.x = 0
direction.z = 1
end
end
end
-- Save the modified nodes back to disk & return
worldedit.manip_helpers.finish(manip, data)
return true, count
end