From e942e4fb2ffb3758ee2e486705d26e00943f58ab Mon Sep 17 00:00:00 2001
From: Starbeamrainbowlabs <sbrl@starbeamrainbowlabs.com>
Date: Sun, 12 Feb 2023 01:40:29 +0000
Subject: [PATCH] Finish initial implementation of //revolve it's not quite
 done yet - got docs to go

---
 worldeditadditions/init.lua                   |  1 +
 worldeditadditions/lib/revolve.lua            | 28 ++++---
 .../commands/revolve.lua                      | 73 +++++++++++++++++++
 worldeditadditions_commands/init.lua          |  1 +
 4 files changed, 91 insertions(+), 12 deletions(-)
 create mode 100644 worldeditadditions_commands/commands/revolve.lua

diff --git a/worldeditadditions/init.lua b/worldeditadditions/init.lua
index 2d28c1a..e8ce070 100644
--- a/worldeditadditions/init.lua
+++ b/worldeditadditions/init.lua
@@ -31,6 +31,7 @@ dofile(wea.modpath.."/lib/spiral_square.lua")
 dofile(wea.modpath.."/lib/spiral_circle.lua")
 dofile(wea.modpath.."/lib/dome.lua")
 dofile(wea.modpath.."/lib/spline.lua")
+dofile(wea.modpath.."/lib/revolve.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/revolve.lua b/worldeditadditions/lib/revolve.lua
index 7007b8c..3201cba 100644
--- a/worldeditadditions/lib/revolve.lua
+++ b/worldeditadditions/lib/revolve.lua
@@ -16,29 +16,31 @@ local Vector3 = wea_c.Vector3
 -- @param	origin	Vector3		The pivot point to rotate around.
 -- @param	times	number		The number of equally-spaces copies to make.
 function worldeditadditions.revolve(pos1, pos2, origin, times)
-	local rotation_radians = wea_c.range(0, 1, 1 / times)
+	local rotation_radians = wea_c.table.filter(
+		wea_c.range(0, 1, 1 / times),
+		function (val) return val ~= 0 and val ~= 1 end
+	)
 	
 	local pos1_source, pos2_source = Vector3.sort(pos1, pos2)
 	
 	-- HACK: with some maths this could be much more efficient.
 	local pos1_target, pos2_target = wea_c.table.unpack(wea_c.table.reduce({
-		Vector3.rotate3d(origin, pos1_source, Vector3.new(0, 0, math.pi / 2)),
-		Vector3.rotate3d(origin, pos2_source, Vector3.new(0, 0, math.pi / 2)),
-		Vector3.rotate3d(origin, pos1_source, Vector3.new(0, 0, math.pi)),
-		Vector3.rotate3d(origin, pos2_source, Vector3.new(0, 0, math.pi)),
-		Vector3.rotate3d(origin, pos1_source, Vector3.new(0, 0, -math.pi / 2)),
-		Vector3.rotate3d(origin, pos2_source, Vector3.new(0, 0, -math.pi / 2)),
+		Vector3.rotate3d(origin, pos1_source, Vector3.new(0, math.pi / 2, 0)),
+		Vector3.rotate3d(origin, pos2_source, Vector3.new(0, math.pi / 2, 0)),
+		Vector3.rotate3d(origin, pos1_source, Vector3.new(0, math.pi, 0)),
+		Vector3.rotate3d(origin, pos2_source, Vector3.new(0, math.pi, 0)),
+		Vector3.rotate3d(origin, pos1_source, Vector3.new(0, -math.pi / 2, 0)),
+		Vector3.rotate3d(origin, pos2_source, Vector3.new(0, -math.pi / 2, 0)),
 	}, function(acc, next)
 		return { next:expand_region(acc[1], acc[2]) }
 	end, { pos1_source, pos2_source }))
 	
-	
 	-- Fetch the nodes in the specified area
 	local manip_source, area_source = worldedit.manip_helpers.init(pos1_source, pos2_source)
-	local data_source = manip:get_data()
+	local data_source = manip_source:get_data()
 	
 	local manip_target, area_target = worldedit.manip_helpers.init(pos1_target, pos2_target)
-	local data_target = manip:get_data()
+	local data_target = manip_target:get_data()
 	
 	local changed = 0
 	for z = pos2_source.z, pos1_source.z, -1 do
@@ -49,8 +51,10 @@ function worldeditadditions.revolve(pos1, pos2, origin, times)
 					local pos_target = Vector3.rotate3d(
 						origin,
 						pos_source,
-						Vector3.new(0, 0, rotation) -- rotate on Z axis only
-					)
+						-- rotate on Z axis only, convert 0..1 → radians
+						-- TEST on Y axis, 'cause I'm confused
+						Vector3.new(0, rotation * math.pi * 2, 0)
+					):floor()
 					
 					local i_source = area_source:index(x, y, z)
 					local i_target = area_target:index(pos_target.x, pos_target.y, pos_target.z)
diff --git a/worldeditadditions_commands/commands/revolve.lua b/worldeditadditions_commands/commands/revolve.lua
new file mode 100644
index 0000000..304439e
--- /dev/null
+++ b/worldeditadditions_commands/commands/revolve.lua
@@ -0,0 +1,73 @@
+local wea_c = worldeditadditions_core
+local Vector3 = wea_c.Vector3
+
+
+
+-- ██████  ███████ ██    ██  ██████  ██      ██    ██ ███████ 
+-- ██   ██ ██      ██    ██ ██    ██ ██      ██    ██ ██      
+-- ██████  █████   ██    ██ ██    ██ ██      ██    ██ █████   
+-- ██   ██ ██       ██  ██  ██    ██ ██       ██  ██  ██      
+-- ██   ██ ███████   ████    ██████  ███████   ████   ███████ 
+worldeditadditions_core.register_command("revolve", {
+	params = "<times> [<pivot_point_number=last_point>]",
+	description = "Creates a number of copies of the defined region rotated at equal intervals.",
+	privs = { worldedit = true },
+	require_pos = 2,
+	parse = function (params_text)
+		if not params_text then params_text = "" end
+		local parts = wea_c.split_shell(params_text)
+		
+		if #parts < 1 then
+			return false, "Error: No number of times specified. times should be a positive integer greater than 1"
+		end
+		
+		local times = tonumber(parts[1])
+		local origin = -1 -- -1 = last point
+		
+		if not times or times < 2 then
+			return false, "Error: Invalid number of times. The value for times must be a positive integer greater than 1."
+		end
+		
+		if #parts > 1 then
+			origin = tonumber(parts[2])
+			if not origin then
+				return false, "Error: Invalid pivot point number. The pivot point number must be a positive integer greater than 2."
+			end
+			if origin == 1 or origin == 2 then
+				return false, "Error: Point numbers 1 and 2 are reserved for defining the region that should be cloned."
+			end
+		end
+		
+		return true, times, origin
+	end,
+	nodes_needed = function(name, times)
+		-- TODO: Calculate the bounding box for everything, since we'll be grabbing a VoxelManip for the for entire area and then operating on that
+		return worldedit.volume(worldedit.pos1[name], worldedit.pos2[name]) * times
+	end,
+	func = function(name, times, origin_point_number)
+		local start_time = wea_c.get_ms_time()
+		local pos1, pos2 = Vector3.sort(worldedit.pos1[name], worldedit.pos2[name])
+		
+		local pos_count = wea_c.pos.count(name)
+		if pos_count < origin_point_number then
+			return false, "Error: You only have "..pos_count.." points defined, yet requested the origin/pivot point be point "..origin_point_number.."."
+		end
+		
+		if origin_point_number == -1 then
+			origin_point_number = pos_count
+		end
+		local origin = wea_c.pos.get(name, origin_point_number)
+		
+		local success, changed = worldeditadditions.revolve(
+			pos1, pos2,
+			origin,
+			times
+		)
+		if not success then return success, changed end
+		
+		local time_taken = wea_c.get_ms_time() - start_time
+		
+		minetest.log("action", name .. " used //revolve at "..pos1.." - "..pos2.." with origin "..origin..", replacing "..changed.." nodes in "..time_taken.."s")
+		return true, changed.." nodes replaced in "..wea_c.format.human_time(time_taken)
+	end
+})
diff --git a/worldeditadditions_commands/init.lua b/worldeditadditions_commands/init.lua
index a6d25c5..7ca4c5e 100644
--- a/worldeditadditions_commands/init.lua
+++ b/worldeditadditions_commands/init.lua
@@ -37,6 +37,7 @@ dofile(wea_cmd.modpath.."/commands/metaball.lua")
 dofile(wea_cmd.modpath.."/commands/count.lua")
 dofile(wea_cmd.modpath.."/commands/sculpt.lua")
 dofile(wea_cmd.modpath.."/commands/spline.lua")
+dofile(wea_cmd.modpath.."/commands/revolve.lua")
 
 -- Meta Commands
 dofile(wea_cmd.modpath.."/commands/meta/init.lua")
