From 392708b1900ea401a90d30ae383819e01cd39af2 Mon Sep 17 00:00:00 2001
From: Starbeamrainbowlabs <sbrl@starbeamrainbowlabs.com>
Date: Sat, 21 Jan 2023 03:24:44 +0000
Subject: [PATCH] initial wea.revolve() implementation ....but it's not tested
 or hooked up yet. Next up: a chat command definition so we can test it.

---
 worldeditadditions/lib/revolve.lua            | 70 +++++++++++++++++++
 .../utils/table/table_reduce.lua              |  2 +-
 2 files changed, 71 insertions(+), 1 deletion(-)
 create mode 100644 worldeditadditions/lib/revolve.lua

diff --git a/worldeditadditions/lib/revolve.lua b/worldeditadditions/lib/revolve.lua
new file mode 100644
index 0000000..7007b8c
--- /dev/null
+++ b/worldeditadditions/lib/revolve.lua
@@ -0,0 +1,70 @@
+local wea_c = worldeditadditions_core
+local Vector3 = wea_c.Vector3
+
+-- ██████  ███████ ██    ██  ██████  ██      ██    ██ ███████ 
+-- ██   ██ ██      ██    ██ ██    ██ ██      ██    ██ ██      
+-- ██████  █████   ██    ██ ██    ██ ██      ██    ██ █████   
+-- ██   ██ ██       ██  ██  ██    ██ ██       ██  ██  ██      
+-- ██   ██ ███████   ████    ██████  ███████   ████   ███████ 
+
+--- Make <times> copies of the region defined by pos1-pos2 at equal angles around a circle.
+-- The defined region works best if it's a thin slice that's 1 or 2 blocks thick.
+-- For example, if one provided a times value of 3, copies would be rotated 0, 120, and 240 degrees.
+-- TODO: implement support to rotate around arbitrary axes.
+-- @param	pos1	Vector3		The first position defining the source region.
+-- @param	pos2	Vector3		The second position defining the source region.
+-- @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 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)),
+	}, 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 manip_target, area_target = worldedit.manip_helpers.init(pos1_target, pos2_target)
+	local data_target = manip:get_data()
+	
+	local changed = 0
+	for z = pos2_source.z, pos1_source.z, -1 do
+		for y = pos2_source.y, pos1_source.y, -1 do
+			for x = pos2_source.x, pos1_source.x, -1 do
+				for index, rotation in ipairs(rotation_radians) do
+					local pos_source = Vector3.new(x, y, z)
+					local pos_target = Vector3.rotate3d(
+						origin,
+						pos_source,
+						Vector3.new(0, 0, rotation) -- rotate on Z axis only
+					)
+					
+					local i_source = area_source:index(x, y, z)
+					local i_target = area_target:index(pos_target.x, pos_target.y, pos_target.z)
+					
+					-- TODO: Rotate notes as appropriate
+					data_target[i_target] = data_source[i_source]
+					changed = changed + 1
+				end
+			end
+		end
+	end
+	
+	-- Save the modified nodes back to disk & return
+	worldedit.manip_helpers.finish(manip_target, data_target)
+
+	return true, changed
+end
\ No newline at end of file
diff --git a/worldeditadditions_core/utils/table/table_reduce.lua b/worldeditadditions_core/utils/table/table_reduce.lua
index 639a188..3bc0bed 100644
--- a/worldeditadditions_core/utils/table/table_reduce.lua
+++ b/worldeditadditions_core/utils/table/table_reduce.lua
@@ -12,4 +12,4 @@ local function table_reduce(tbl, func, initial_value)
 	return acc
 end
 
-return table_reduce
\ No newline at end of file
+return table_reduce
