diff --git a/worldeditadditions/init.lua b/worldeditadditions/init.lua index 8233a7f..8138a04 100644 --- a/worldeditadditions/init.lua +++ b/worldeditadditions/init.lua @@ -51,6 +51,7 @@ dofile(wea.modpath.."/lib/scale_up.lua") dofile(wea.modpath.."/lib/scale_down.lua") dofile(wea.modpath.."/lib/scale.lua") dofile(wea.modpath.."/lib/spiral_square.lua") +dofile(wea.modpath.."/lib/spiral_circle.lua") dofile(wea.modpath.."/lib/conv/conv.lua") dofile(wea.modpath.."/lib/erode/erode.lua") dofile(wea.modpath.."/lib/noise/init.lua") diff --git a/worldeditadditions/lib/spiral_circle.lua b/worldeditadditions/lib/spiral_circle.lua new file mode 100644 index 0000000..c1da6d8 --- /dev/null +++ b/worldeditadditions/lib/spiral_circle.lua @@ -0,0 +1,86 @@ +local wea = worldeditadditions +local Vector3 = wea.Vector3 + +-- ███████ ██████ ██ ██████ █████ ██ +-- ██ ██ ██ ██ ██ ██ ██ ██ ██ +-- ███████ ██████ ██ ██████ ███████ ██ +-- ██ ██ ██ ██ ██ ██ ██ ██ +-- ███████ ██ ██ ██ ██ ██ ██ ███████ +-- +-- ██████ ██ ██████ ██████ ██ ███████ +-- ██ ██ ██ ██ ██ ██ ██ +-- ██ ██ ██████ ██ ██ █████ +-- ██ ██ ██ ██ ██ ██ ██ +-- ██████ ██ ██ ██ ██████ ███████ ███████ + + +--- Creates a circular 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_initial 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_circle(pos1, pos2, target_node, interval_initial, 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, "interval_initial:", interval_initial, "acceleration", acceleration) + + interval_initial = interval_initial + 1 + + -- 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():divide(2):add(pos1) + + local pos_current = centre:clone():floor() + local interval = interval_initial + local radius = 1 + local angle = 0 + -- local sides_acc = 0 + + while pos_current:is_contained(pos1, pos2) do + + for y = pos2.y, pos1.y, -1 do + data[area:index( + math.floor(pos_current.x), + y, + math.floor(pos_current.z) + )] = node_id + count = count + 1 + end + + -- print("DEBUG:spiral_circle centre", centre, "bearing", Vector3.fromBearing(angle, 0, radius)) + pos_current = centre:add(Vector3.fromBearing(angle, 0, radius)) + + local circumference_now = 2 * math.pi * radius + local step = (math.pi*2)/(circumference_now*2) + if angle < math.pi then step = step / 10 end + angle = angle + (step) + + local acceleration_constant = 0 + if angle > math.pi / 2 then + acceleration_constant = (interval/angle * acceleration) * step + end + radius = 1 + interval*(angle / (math.pi*2)) + interval = interval_initial + acceleration_constant + + + print("DEBUG cpos", pos_current:multiply(1000):floor():divide(1000), "angle", math.deg(angle), "step", wea.round(math.deg(step), 3), "radius", wea.round(radius, 3), "interval", wea.round(interval, 3), "accel_const", acceleration_constant) + + end + + -- Save the modified nodes back to disk & return + worldedit.manip_helpers.finish(manip, data) + + return true, count +end diff --git a/worldeditadditions/utils/vector3.lua b/worldeditadditions/utils/vector3.lua index 5733279..b860079 100644 --- a/worldeditadditions/utils/vector3.lua +++ b/worldeditadditions/utils/vector3.lua @@ -361,6 +361,22 @@ function Vector3.max(pos1, pos2) ) end +--- Given 2 angles and a length, return a Vector3 pointing in that direction. +-- Consider a sphere, with the 2 angles defining a point on the sphere's surface. +-- This function returns that point as a Vector3. +-- @source https://math.stackexchange.com/a/1881767/221181 +-- @param angle_x number The X angle. +-- @param angle_y number The Y angle. +-- @param length number The radius of the sphere in question. +-- @returns Vector3 The point on the sphere defined by the aforementioned parameters. +function Vector3.fromBearing(angle_x, angle_y, length) + return Vector3.new( -- X and Y swapped + length * math.cos(angle_x), + length * math.sin(angle_x) * math.sin(angle_y), + length * math.sin(angle_x) * math.cos(angle_y) + ) +end + -- ██████ ██████ ███████ ██████ █████ ████████ ██████ ██████