Compare commits

...

6 Commits

Author SHA1 Message Date
Starbeamrainbowlabs 45f69eb8f9
Vector3.rotate3d: clarity in comment 2023-11-29 00:36:50 +00:00
Starbeamrainbowlabs 6d5f2033e1
rotate: initial UNTESTED implementation
It doesn't have a chat command interface yet.

.....I REALLY need to learn Quaternions, but they don't currently make sense to me
2023-11-29 00:36:23 +00:00
Starbeamrainbowlabs e28c428ef7
vector3: doc comment layout 2023-11-28 22:38:26 +00:00
Starbeamrainbowlabs 26fd756321
reference: fix typos 2023-11-28 22:38:11 +00:00
Starbeamrainbowlabs 709b27b519
settings.json: add spellings 2023-11-28 22:38:05 +00:00
Starbeamrainbowlabs 4eee7c66d7
revolve: TODOs 2023-11-28 22:30:04 +00:00
5 changed files with 182 additions and 5 deletions

56
.vscode/settings.json vendored
View File

@ -6,7 +6,63 @@
"cast-local-type"
],
"cSpell.words": [
"airlike",
"bakedclay",
"bonemealed",
"clearcut",
"cloudwand",
"conv",
"cubeapply",
"dolower",
"doraise",
"ellipsoidapply",
"erbose",
"farwand",
"fixlight",
"goldblock",
"hollowcylinder",
"hollowellipsoid",
"hollowtorus",
"liquidlike",
"maxdiff",
"maxdist",
"mcount",
"meselamp",
"mfacing",
"minetestiscool",
"moretrees",
"ngroups",
"noconv",
"nodeapply",
"nodename",
"noiseapply",
"offsetx",
"offsety",
"offsetz",
"ollow",
"perlinmt",
"replacemix",
"saplingaliases",
"scalex",
"scaley",
"scalez",
"scentre",
"scloud",
"scol",
"scube",
"sculptlist",
"sfac",
"smake",
"smoothadv",
"snowblock",
"spop",
"spush",
"srect",
"srel",
"sshift",
"sstack",
"steelblock",
"stonebrick",
"weacmd",
"WEASCHEM"
],

View File

@ -1281,7 +1281,7 @@ While other server commands can be executed while a `//subdivide` is running, `/
```weacmd
//subdivide 10 10 10 set dirt
//subdivice 25 25 25 fixlight
//subdivide 25 25 25 fixlight
```
@ -1426,7 +1426,7 @@ Here are some more examples:
### `//listentities`
Lists all currently loaded ObjectRefs. Displays their IDs, Names (if possible), and possitions.
Lists all currently loaded ObjectRefs. Displays their IDs, Names (if possible), and positions.
This command is intended for development and modding. You will not normally need to use this command using WorldEditAdditions.

View File

@ -9,8 +9,9 @@ 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.
-- 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.
-- TODO: implement support for stairs, and slabs when we get arbitrary axis rotation support done.
-- @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.

View File

@ -0,0 +1,119 @@
local weac = worldeditadditions_core
local Vector3 = weac.Vector3
-- ██████ ██████ ████████ █████ ████████ ███████
-- ██ ██ ██ ██ ██ ██ ██ ██ ██
-- ██████ ██ ██ ██ ███████ ██ █████
-- ██ ██ ██ ██ ██ ██ ██ ██ ██
-- ██ ██ ██████ ██ ██ ██ ██ ███████
--- Compiles a list of rotations into something we can iteratively pass to Vector3.rotate3d.
-- TODO Learn Quaternions.
-- @param rotlist table<{axis: string, rad: number}> The list of rotations. Rotations will be processed in order. Each rotation is a table with a SINGLE axis as a string (x, y, z, -x, -y, or -z; the axis parameter), and an amount in radians to rotate by (the rad parameter.
-- @returns Vector3[] The list of the compiled rotations, in a form that Vector3.rotate3d understands.
local function __compile_rotlist(rotlist)
return weac.table.map(rotlist, function(rot)
--- 1: Construct a Vector3 to represent which axis we want to rotate on
local rotval = Vector3.new(0, 0, 0)
if rot.axis:find("x", 1, true) then rotval.x = 1
elseif rot.axis:find("y", 1, true) then rotval.y = 1
elseif rot.axis:find("z", 1, true) then rotval.z = 1 end
if rot.axis:sub(1, 1) == "-" then
rotval = rotval * -1
end
--- 2: Rotate & apply amount of rotation to apply in radians
return rotval * rot.rad
end)
end
--- Rotates the given region around a given origin point using a set of rotations.
-- TODO Learn quaternions and make this more effiient.
-- @param pos1 Vector3 Position 1 of the defined region to rotate.
-- @param pos2 Vector3 Position 2 of the defined region to rotate.
-- @param origin Vector3 The coordinates of the origin point around which we should rotate the region defined by pos1..pos2.
-- @param rotlist table<{axis: string, rad: number}> The list of rotations. Rotations will be processed in order. Each rotation is a table with a SINGLE axis as a string (x, y, z, -x, -y, or -z; the axis parameter), and an amount in radians to rotate by (the rad parameter.
-- @returns bool,string|table<{changed: number}> A success boolean (true == success; false == failure), followed by either an error message as a string if success == false or a table of statistics if success == true.
--
-- Currently the only parameter in the statistics table is changed, which is a number representing the number of nodes that were rotated.
--
-- This is NOT NECESSARILY the number of nodes in the target region..... since rotations and roundings mean the target area the source region was rotated into could have slightly more or less nodes than the source region.
function worldeditadditions.rotate(pos1, pos2, origin, rotlist)
pos1, pos2 = Vector3.sort(pos1, pos2)
--- 1: Compile the rotation list
local rotlist_c = __compile_rotlist(rotlist)
--- 2: Find the target area we will be rotating into
-- First, rotate the defined region to find the target region
local pos1_rot, pos2_rot = pos1:clone(), pos2:clone()
for i, rot in ipairs(rotlist_c) do
pos1_rot = Vector3.rotate3d(origin, pos1_rot, rot)
pos2_rot = Vector3.rotate3d(origin, pos2_rot, rot)
end
-- Then, align it to the world axis so we can grab a VoxelManipulator
-- We add 1 node either side for safety just in case of rounding errors when actually rotating
local pos1_dstvm, pos2_dstvm = Vector3.sort(pos1_rot, pos2_rot)
pos1_dstvm = pos1_dstvm:floor() - Vector3.new(1, 1, 1)
pos2_dstvm = pos2_dstvm:ceil() + Vector3.new(1, 1, 1)
--- 3: Check out a VoxelManipulator for the source and target regions
local manip_src, area_src = worldedit.manip_helpers.init(pos1, pos2)
local data_src = manip_src:get_data()
local manip_dest, area_dest = worldedit.manip_helpers.init(pos1_dstvm, pos2_dstvm)
local data_dest = manip_dest:get_data()
-- TODO: Also carry param2 along for the ride
--- 4: Do the rotation operation
local count_rotated = 0
for z = pos2.z, pos1.z, -1 do
for y = pos2.y, pos1.y, -1 do
for x = pos2.x, pos1.x, -1 do
local cpos_src = Vector3.new(x, y, z)
local cpos_dest = cpos_src:clone()
-- TODO: This is very inefficient. If we could use quaternions here to stack up the rotations, it would be much more efficient.
for i, rot in ipairs(rotlist) do
cpos_dest = Vector3.rotate3d(origin, cpos_dest, rot)
end
cpos_dest = cpos_dest:round()
local i_src = area_src:index(cpos_src.x, cpos_src.y, cpos_src.z)
local i_dest = area_dest:index(cpos_dest.x, cpos_dest.y, cpos_dest.z)
data_dest[i_dest] = data_src[i_src]
count_rotated = count_rotated + 1
end
end
end
--- 5: Wipe the source area & save it back to disk
local id_air = minetest.get_content_id("air")
for z = pos2.z, pos1.z, -1 do
for y = pos2.y, pos1.y, -1 do
for x = pos2.x, pos1.x, -1 do
data_src[area_src:index(x, y, z)] = id_air
end
end
end
worldedit.manip_helpers.finish(manip_src, data_src)
manip_src, area_src, data_src = nil, nil, nil
--- 6: Save the destination back to disk
-- Note that this MUST be AFTER the source is saved to disk, since the rotated region needs to overwrite the WIPED source area to avoid leaving an unrotated copy behind
worldedit.manip_helpers.finish(manip_dest, data_dest)
--- 5: Return
return true, {
count_rotated = count_rotated
}
end

View File

@ -413,6 +413,7 @@ end
--- Rotate a given point around an origin point in 3d space.
-- Consider 3 axes (X, Y, and Z) that are centred on origin. This function
-- rotates point around these axes in the aforementioned order.
--
-- NOTE: This function is not as intuitive as it sounds.
-- A whiteboard and a head for mathematics is recommended before using this
-- function. Either that, or Blender 3 (https://blender.org/) is quite useful to visualise what's going on.
@ -420,7 +421,7 @@ end
-- @warning Not completely tested! Pending a thorough evaluation. Seems to basically work, after some tweaks to the fluff around the edges?
-- @param origin Vector3 The origin point to rotate around
-- @param point Vector3 The point to rotate.
-- @param rotate Vector3 Rotate this much around the 3 different axes, x, y, and z. Axial rotations are handled in this order: X→Y→Z.
-- @param rotate Vector3 Rotate this much around the 3 different axes, x, y, and z. Axial rotations are handled in this order: X→Y→Z. Values MUST be in radians!
-- @param x number Rotate this much around the X axis (yz plane), in radians.
-- @param y number Rotate this much around the Y axis (xz plane), in radians.
-- @param z number Rotate this much around the Z axis (xy plane), in radians.