mirror of
https://github.com/sbrl/Minetest-WorldEditAdditions.git
synced 2024-11-30 19:13:53 +01:00
Start working on //scale, but it isn't finished yet.
This commit is contained in:
parent
03afd7e75c
commit
ad9e5a26b1
@ -30,6 +30,9 @@ dofile(worldeditadditions.modpath.."/lib/replacemix.lua")
|
|||||||
dofile(worldeditadditions.modpath.."/lib/maze2d.lua")
|
dofile(worldeditadditions.modpath.."/lib/maze2d.lua")
|
||||||
dofile(worldeditadditions.modpath.."/lib/maze3d.lua")
|
dofile(worldeditadditions.modpath.."/lib/maze3d.lua")
|
||||||
dofile(worldeditadditions.modpath.."/lib/hollow.lua")
|
dofile(worldeditadditions.modpath.."/lib/hollow.lua")
|
||||||
|
dofile(worldeditadditions.modpath.."/lib/scale_up.lua")
|
||||||
|
dofile(worldeditadditions.modpath.."/lib/scale_down.lua")
|
||||||
|
dofile(worldeditadditions.modpath.."/lib/scale.lua")
|
||||||
dofile(worldeditadditions.modpath.."/lib/conv/conv.lua")
|
dofile(worldeditadditions.modpath.."/lib/conv/conv.lua")
|
||||||
dofile(worldeditadditions.modpath.."/lib/erode/erode.lua")
|
dofile(worldeditadditions.modpath.."/lib/erode/erode.lua")
|
||||||
|
|
||||||
|
44
worldeditadditions/lib/scale.lua
Normal file
44
worldeditadditions/lib/scale.lua
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
|
||||||
|
--- Scales the defined region by the given scale factor in the given directions.
|
||||||
|
-- Scale factor vectors containing both scale up and scale down operations are
|
||||||
|
-- split into 2 different scale operations automatically.
|
||||||
|
-- @param pos1 Vector Position 1 of the defined region,
|
||||||
|
-- @param pos2 Vector Position 2 of the defined region.
|
||||||
|
-- @param scale Vector The scale factor - as a vector - by which to scale (values between -1 and 1 are considered a scale down operation).
|
||||||
|
-- @param direction Vector The direction to scale in - as a vector. e.g. { x = -1, y = 1, z = -1 } would mean scale in the negative x, positive y, and nevative z directions.
|
||||||
|
-- @return boolean, string|table Whether the operation was successful or not. If not, then an error messagea as a string is also passed. If it was, then a statistics object is returned instead.
|
||||||
|
function worldeditadditions.scale(pos1, pos2, scale, direction)
|
||||||
|
if scale.x == 0 or scale.y == 0 or scale.z == 0 then
|
||||||
|
return false, "A component of the scale factoro was 0."
|
||||||
|
end
|
||||||
|
|
||||||
|
local scale_down = vector.new(1, 1, 1)
|
||||||
|
local scale_up = vector.new(1, 1, 1)
|
||||||
|
|
||||||
|
if scale.x > -1 and scale.x < 1 then scale_down.x = scale.x end
|
||||||
|
if scale.y > -1 and scale.y < 1 then scale_down.y = scale.y end
|
||||||
|
if scale.z > -1 and scale.z < 1 then scale_down.z = scale.z end
|
||||||
|
|
||||||
|
if scale.x > 1 or scale.x < -1 then scale_up.x = scale.x end
|
||||||
|
if scale.y > 1 or scale.y < -1 then scale_up.y = scale.y end
|
||||||
|
if scale.z > 1 or scale.z < -1 then scale_up.z = scale.z end
|
||||||
|
|
||||||
|
local stats_total = { updated = 0, operations = 0 }
|
||||||
|
|
||||||
|
local success, stats
|
||||||
|
if scale_up.x ~= 1 or scale_up.y ~= 1 or scale_up.z ~= 1 then
|
||||||
|
success, stats = worldeditadditions.scale_up(pos1, pos2, scale_up, direction)
|
||||||
|
if not success then return success, stats end
|
||||||
|
stats_total.updated = stats.updated
|
||||||
|
stats_total.operations = stats_total.operations + 1
|
||||||
|
stats_total.scale_down = stats.scale
|
||||||
|
end
|
||||||
|
if scale_down.x ~= 1 or scale_down.y ~= 1 or scale_down.z ~= 1 then
|
||||||
|
success, stats = worldeditadditions.scale_down(pos1, pos2, scale_down, direction)
|
||||||
|
if not success then return success, stats end
|
||||||
|
stats_total.updated = stats_total.updated + stats.updated
|
||||||
|
stats_total.operations = stats_total.operations + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
return true, stats_total
|
||||||
|
end
|
78
worldeditadditions/lib/scale_down.lua
Normal file
78
worldeditadditions/lib/scale_down.lua
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
-- ███████ ██████ █████ ██ ███████ ██████ ██████ ██ ██ ███ ██
|
||||||
|
-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██
|
||||||
|
-- ███████ ██ ███████ ██ █████ ██ ██ ██ ██ ██ █ ██ ██ ██ ██
|
||||||
|
-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ███ ██ ██ ██ ██
|
||||||
|
-- ███████ ██████ ██ ██ ███████ ███████ ███████ ██████ ██████ ███ ███ ██ ████
|
||||||
|
|
||||||
|
--- Scales the defined region down by the given scale factor in the given directions.
|
||||||
|
-- @param pos1 Vector Position 1 of the defined region,
|
||||||
|
-- @param pos2 Vector Position 2 of the defined region.
|
||||||
|
-- @param scale Vector The scale factor - as a vector - by which to scale down.
|
||||||
|
-- @param direction Vector The direction to scale in - as a vector. e.g. { x = -1, y = 1, z = -1 } would mean scale in the negative x, positive y, and nevative z directions.
|
||||||
|
-- @return boolean, string|table Whether the operation was successful or not. If not, then an error messagea as a string is also passed. If it was, then a statistics object is returned instead.
|
||||||
|
function worldeditadditions.scale_down(pos1, pos2, scale, direction)
|
||||||
|
pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||||
|
if scale.x > 1 or scale.y > 1 or scale.z > 1 or scale.x < -1 or scale.y < -1 or scale.z < -1 then
|
||||||
|
return false, "Error: Scale factor vectors may not mix values -1 < factor < 1 and (1 < factor or factor < -1) - in other words, you can't scale both up and down at the same time (try worldeditadditions.scale, which automatically applies such scale factor vectors as 2 successive operations)"
|
||||||
|
end
|
||||||
|
if direction.x == 0 or direction.y == 0 or direction.z == 0 then
|
||||||
|
return false, "Error: One of the components of the direction vector was 0 (direction components should either be greater than or less than 0 to indicate the direction to scale in.)"
|
||||||
|
end
|
||||||
|
|
||||||
|
local scale_down = {
|
||||||
|
x = math.floor(1 / scale.x),
|
||||||
|
y = math.floor(1 / scale.y),
|
||||||
|
z = math.floor(1 / scale.z)
|
||||||
|
}
|
||||||
|
print("[DEBUG] scale_down", worldeditadditions.vector.tostring(scale_down))
|
||||||
|
local size = vector.subtract(pos2, pos1)
|
||||||
|
|
||||||
|
local data = manip:get_data()
|
||||||
|
local data_copy = worldeditadditions.shallowcopy(data)
|
||||||
|
|
||||||
|
local node_id_air = minetest.get_content_id("air")
|
||||||
|
|
||||||
|
|
||||||
|
local count = 0 -- The number of nodes replaced
|
||||||
|
|
||||||
|
local stats = { updated = 0, scale = scale_down }
|
||||||
|
-- Zero out the area we're scaling down into
|
||||||
|
for i in area:iterp(pos1, pos2) do
|
||||||
|
data_copy[i] = node_id_air
|
||||||
|
-- We update the entire area, even though we're scaling down
|
||||||
|
-- ....because we fill in the area we left behind with air
|
||||||
|
stats.updated = stats.updated + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
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 posi_rel = vector.subtract({ x = x, y = y, z = z }, pos1)
|
||||||
|
|
||||||
|
local posi_copy = worldeditadditions.shallowcopy(posi_rel)
|
||||||
|
posi_copy = vector.floor(vector.divide(scale_down))
|
||||||
|
|
||||||
|
if direction.x < 0 then posi_copy.x = size.x - posi_copy.x end
|
||||||
|
if direction.y < 0 then posi_copy.y = size.y - posi_copy.y end
|
||||||
|
if direction.z < 0 then posi_copy.z = size.z - posi_copy.z end
|
||||||
|
|
||||||
|
local posi_copy = vector.add(pos1, posi_copy)
|
||||||
|
|
||||||
|
local i_source = area:index(x, y, z)
|
||||||
|
local i_target = area:index(posi_copy.x, posi_copy.y, posi_copy.z)
|
||||||
|
|
||||||
|
-- Technically we could save some operations here by not setting
|
||||||
|
-- the target multiple times per copy, but the calculations
|
||||||
|
-- above are probably a lot more taxing
|
||||||
|
-- TODO Be more intelligent about deciding what node to replace with here
|
||||||
|
data_copy[i_target] = data[i_source]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Save the modified nodes back to disk & return
|
||||||
|
worldedit.manip_helpers.finish(manip, data_copy)
|
||||||
|
|
||||||
|
return true, changes
|
||||||
|
end
|
75
worldeditadditions/lib/scale_up.lua
Normal file
75
worldeditadditions/lib/scale_up.lua
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
-- ███████ ██████ █████ ██ ███████ ██ ██ ██████
|
||||||
|
-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
||||||
|
-- ███████ ██ ███████ ██ █████ ██ ██ ██████
|
||||||
|
-- ██ ██ ██ ██ ██ ██ ██ ██ ██
|
||||||
|
-- ███████ ██████ ██ ██ ███████ ███████ ███████ ██████ ██
|
||||||
|
|
||||||
|
--- Scales the defined region down by the given scale factor in the given directions.
|
||||||
|
-- @param pos1 Vector Position 1 of the defined region,
|
||||||
|
-- @param pos2 Vector Position 2 of the defined region.
|
||||||
|
-- @param scale Vector The scale factor - as a vector - by which to scale down.
|
||||||
|
-- @param direction Vector The direction to scale in - as a vector. e.g. { x = -1, y = 1, z = -1 } would mean scale in the negative x, positive y, and nevative z directions.
|
||||||
|
-- @return boolean, string|table Whether the operation was successful or not. If not, then an error messagea as a string is also passed. If it was, then a statistics object is returned instead.
|
||||||
|
function worldeditadditions.scale_up(pos1, pos2, scale, direction)
|
||||||
|
return false, "Error: Scaling up isn't implemented yet."
|
||||||
|
-- pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||||
|
-- if scale.x > 1 or scale.y > 1 or scale.z > 1 or scale.x < -1 or scale.y < -1 or scale.z < -1 then
|
||||||
|
-- return false, "Error: Scale factor vectors may not mix values -1 < factor < 1 and (1 < factor or factor < -1) - in other words, you can't scale both up and down at the same time (try worldeditadditions.scale, which automatically applies such scale factor vectors as 2 successive operations)"
|
||||||
|
-- end
|
||||||
|
-- if direction.x == 0 or direction.y == 0 or direction.z == 0 then
|
||||||
|
-- return false, "Error: One of the components of the direction vector was 0 (direction components should either be greater than or less than 0 to indicate the direction to scale in.)"
|
||||||
|
-- end
|
||||||
|
--
|
||||||
|
-- local scale_down = {
|
||||||
|
-- x = math.floor(1 / scale.x),
|
||||||
|
-- y = math.floor(1 / scale.y),
|
||||||
|
-- z = math.floor(1 / scale.z)
|
||||||
|
-- }
|
||||||
|
-- local size = vector.subtract(pos2, pos1)
|
||||||
|
--
|
||||||
|
-- local data = manip:get_data()
|
||||||
|
-- local data_copy = worldeditadditions.shallowcopy(data)
|
||||||
|
--
|
||||||
|
-- local node_id_air = minetest.get_content_id("air")
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- local count = 0 -- The number of nodes replaced
|
||||||
|
--
|
||||||
|
-- -- Zero out the area we're scaling down into
|
||||||
|
-- for i in area:iterp(pos1, pos2) do
|
||||||
|
-- data_copy[i] = node_id_air
|
||||||
|
-- end
|
||||||
|
--
|
||||||
|
-- local changes = { replaced = 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 posi_rel = vector.subtract({ x = x, y = y, z = z }, pos1)
|
||||||
|
--
|
||||||
|
-- local posi_copy = worldeditadditions.shallowcopy(posi_rel)
|
||||||
|
-- posi_copy = vector.floor(vector.divide(scale_down))
|
||||||
|
--
|
||||||
|
-- if direction.x < 0 then posi_copy.x = size.x - posi_copy.x end
|
||||||
|
-- if direction.y < 0 then posi_copy.y = size.y - posi_copy.y end
|
||||||
|
-- if direction.z < 0 then posi_copy.z = size.z - posi_copy.z end
|
||||||
|
--
|
||||||
|
-- local posi_copy = vector.add(pos1, posi_copy)
|
||||||
|
--
|
||||||
|
-- local i_source = area:index(x, y, z)
|
||||||
|
-- local i_target = area:index(posi_copy.x, posi_copy.y, posi_copy.z)
|
||||||
|
--
|
||||||
|
-- -- Technically we could save some operations here by not setting
|
||||||
|
-- -- the target multiple times per copy, but the calculations
|
||||||
|
-- -- above are probably a lot more taxing
|
||||||
|
-- -- TODO Be more intelligent about deciding what node to replace with here
|
||||||
|
-- data_copy[i_target] = data[i_source]
|
||||||
|
-- end
|
||||||
|
-- end
|
||||||
|
-- end
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- -- Save the modified nodes back to disk & return
|
||||||
|
-- worldedit.manip_helpers.finish(manip, data_copy)
|
||||||
|
--
|
||||||
|
-- return true, changes
|
||||||
|
end
|
98
worldeditadditions_commands/commands/scale.lua
Normal file
98
worldeditadditions_commands/commands/scale.lua
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
-- ███████ ██████ █████ ██ ███████
|
||||||
|
-- ██ ██ ██ ██ ██ ██
|
||||||
|
-- ███████ ██ ███████ ██ █████
|
||||||
|
-- ██ ██ ██ ██ ██ ██
|
||||||
|
-- ███████ ██████ ██ ██ ███████ ███████
|
||||||
|
worldedit.register_command("scale", {
|
||||||
|
params = "<axis> <scale_factor> | <factor_x> [<factor_y> <factor_z> [<anchor_x> <anchor_y> <anchor_z>]]",
|
||||||
|
description = "Combined scale up / down. Takes either an axis name + a scale factor (e.g. y 3 or -z 2; negative values swap the anchor point for the scale operation), or 3 scale factor values for x, y, and z respectively. In the latter mode, a set of anchors can also be specified, which indicate which size the scale operation should be anchored to.",
|
||||||
|
privs = { worldedit = true },
|
||||||
|
require_pos = 2,
|
||||||
|
parse = function(params_text)
|
||||||
|
if not params_text then params_text = "" end
|
||||||
|
|
||||||
|
local parts = worldeditadditions.split(params_text, "%s+", false)
|
||||||
|
|
||||||
|
local scale = vector.new(1, 1, 1)
|
||||||
|
local direction = vector.new(1, 1, 1)
|
||||||
|
|
||||||
|
if #parts == 2 then
|
||||||
|
if parts[1] ~= "x" or parts[1] ~= "y" or parts[1] ~= "z"
|
||||||
|
or parts[1] ~= "-x" or parts[1] ~= "-y" or parts[1] ~= "-z" then
|
||||||
|
return false, "Error: Got 2 arguments, but the first doesn't look like the name of an axis."
|
||||||
|
end
|
||||||
|
local axis = parts[1]
|
||||||
|
local factor = tonumber(parts[2])
|
||||||
|
if not factor then return false, "Error: Invalid scale factor." end
|
||||||
|
|
||||||
|
if axis:sub(1, 1) == "-" then
|
||||||
|
axis = axis:sub(2, 2)
|
||||||
|
direction[axis] = -1
|
||||||
|
end
|
||||||
|
|
||||||
|
scale[axis] = factor
|
||||||
|
elseif #parts >= 3 then
|
||||||
|
local val = tonumber(parts[1])
|
||||||
|
if not val then return false, "Error: x axis scale factor wasn't a number." end
|
||||||
|
scale.x = val
|
||||||
|
val = tonumber(parts[2])
|
||||||
|
if not val then return false, "Error: y axis scale factor wasn't a number." end
|
||||||
|
scale.y = val
|
||||||
|
val = tonumber(parts[3])
|
||||||
|
if not val then return false, "Error: z axis scale factor wasn't a number." end
|
||||||
|
scale.z = val
|
||||||
|
else
|
||||||
|
local val = tonumber(parts[1])
|
||||||
|
if not val then
|
||||||
|
return false, "Error: scale factor wasn't a number."
|
||||||
|
end
|
||||||
|
scale.x = val
|
||||||
|
scale.y = val
|
||||||
|
scale.z = val
|
||||||
|
end
|
||||||
|
|
||||||
|
if #parts == 6 then
|
||||||
|
local val = tonumber(parts[4])
|
||||||
|
if not val then return false, "Error: x axis anchor wasn't a number." end
|
||||||
|
direction.x = val
|
||||||
|
val = tonumber(parts[5])
|
||||||
|
if not val then return false, "Error: y axis anchor wasn't a number." end
|
||||||
|
direction.y = val
|
||||||
|
val = tonumber(parts[6])
|
||||||
|
if not val then return false, "Error: z axis anchor wasn't a number." end
|
||||||
|
direction.z = val
|
||||||
|
end
|
||||||
|
|
||||||
|
if scale.x == 0 then return false, "Error: x scale factor was 0" end
|
||||||
|
if scale.y == 0 then return false, "Error: y scale factor was 0" end
|
||||||
|
if scale.z == 0 then return false, "Error: z scale factor was 0" end
|
||||||
|
|
||||||
|
if direction.x == 0 then return false, "Error: x axis anchor was 0" end
|
||||||
|
if direction.y == 0 then return false, "Error: y axis anchor was 0" end
|
||||||
|
if direction.z == 0 then return false, "Error: z axis anchor was 0" end
|
||||||
|
|
||||||
|
return true, scale, direction
|
||||||
|
end,
|
||||||
|
nodes_needed = function(name, scale, direction)
|
||||||
|
local volume = worldedit.volume(worldedit.pos1[name], worldedit.pos2[name])
|
||||||
|
local factor = math.ceil(math.abs(scale.x))
|
||||||
|
* math.ceil(math.abs(scale.y))
|
||||||
|
* math.ceil(math.abs(scale.z))
|
||||||
|
return volume * factor
|
||||||
|
end,
|
||||||
|
func = function(name, scale, direction)
|
||||||
|
local start_time = worldeditadditions.get_ms_time()
|
||||||
|
|
||||||
|
local success, stats = worldeditadditions.scale(pos1, pos2, scale, direction)
|
||||||
|
if not success then return success, stats end
|
||||||
|
|
||||||
|
-- TODO read stats here
|
||||||
|
|
||||||
|
|
||||||
|
local time_taken = worldeditadditions.get_ms_time() - start_time
|
||||||
|
|
||||||
|
|
||||||
|
minetest.log("action", name.." used //scale at "..worldeditadditions.vector.tostring(worldedit.pos1[name]).." - "..worldeditadditions.vector.tostring(worldedit.pos2[name])..", updating "..stats.updated.." nodes in "..time_taken.."s")
|
||||||
|
return true, stats.updated.." nodes updated in " .. worldeditadditions.human_time(time_taken)
|
||||||
|
end
|
||||||
|
})
|
@ -32,6 +32,7 @@ dofile(we_c.modpath.."/commands/replacemix.lua")
|
|||||||
dofile(we_c.modpath.."/commands/convolve.lua")
|
dofile(we_c.modpath.."/commands/convolve.lua")
|
||||||
dofile(we_c.modpath.."/commands/erode.lua")
|
dofile(we_c.modpath.."/commands/erode.lua")
|
||||||
dofile(we_c.modpath.."/commands/hollow.lua")
|
dofile(we_c.modpath.."/commands/hollow.lua")
|
||||||
|
dofile(we_c.modpath.."/commands/scale.lua")
|
||||||
|
|
||||||
dofile(we_c.modpath.."/commands/count.lua")
|
dofile(we_c.modpath.."/commands/count.lua")
|
||||||
dofile(we_c.modpath.."/commands/saplingaliases.lua")
|
dofile(we_c.modpath.."/commands/saplingaliases.lua")
|
||||||
|
Loading…
Reference in New Issue
Block a user