mirror of
https://github.com/sbrl/Minetest-WorldEditAdditions.git
synced 2024-11-22 15:33:00 +00:00
//scale: fix more bugs, and also update the worldedit region after scaling
This commit is contained in:
parent
a63923fec9
commit
3f871e01f5
4 changed files with 79 additions and 26 deletions
|
@ -2,12 +2,17 @@
|
||||||
--- Scales the defined region by the given scale factor in the given anchors.
|
--- Scales the defined region by the given scale factor in the given anchors.
|
||||||
-- Scale factor vectors containing both scale up and scale down operations are
|
-- Scale factor vectors containing both scale up and scale down operations are
|
||||||
-- split into 2 different scale operations automatically.
|
-- split into 2 different scale operations automatically.
|
||||||
|
-- Scale up operations are always performed before scale down operations to
|
||||||
|
-- preserve detail. If performance is important, you should split the scale
|
||||||
|
-- operations up manually!
|
||||||
-- @param pos1 Vector Position 1 of the defined region,
|
-- @param pos1 Vector Position 1 of the defined region,
|
||||||
-- @param pos2 Vector Position 2 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 scale Vector The scale factor - as a vector - by which to scale (values between -1 and 1 are considered a scale down operation).
|
||||||
-- @param anchor Vector The anchor to scale in - as a vector. e.g. { x = -1, y = 1, z = -1 } would mean scale in the negative x, positive y, and negative z directions.
|
-- @param anchor Vector The anchor to scale in - as a vector. e.g. { x = -1, y = 1, z = -1 } would mean scale in the negative x, positive y, and negative 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.
|
-- @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, anchor)
|
function worldeditadditions.scale(pos1, pos2, scale, anchor)
|
||||||
|
pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||||
|
|
||||||
if scale.x == 0 or scale.y == 0 or scale.z == 0 then
|
if scale.x == 0 or scale.y == 0 or scale.z == 0 then
|
||||||
return false, "A component of the scale factoro was 0."
|
return false, "A component of the scale factoro was 0."
|
||||||
end
|
end
|
||||||
|
@ -32,13 +37,20 @@ function worldeditadditions.scale(pos1, pos2, scale, anchor)
|
||||||
stats_total.updated = stats.updated
|
stats_total.updated = stats.updated
|
||||||
stats_total.operations = stats_total.operations + 1
|
stats_total.operations = stats_total.operations + 1
|
||||||
stats_total.scale_down = stats.scale
|
stats_total.scale_down = stats.scale
|
||||||
|
pos1 = stats.pos1
|
||||||
|
pos2 = stats.pos2
|
||||||
end
|
end
|
||||||
if scale_down.x ~= 1 or scale_down.y ~= 1 or scale_down.z ~= 1 then
|
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, anchor)
|
success, stats = worldeditadditions.scale_down(pos1, pos2, scale_down, anchor)
|
||||||
if not success then return success, stats end
|
if not success then return success, stats end
|
||||||
stats_total.updated = stats_total.updated + stats.updated
|
stats_total.updated = stats_total.updated + stats.updated
|
||||||
stats_total.operations = stats_total.operations + 1
|
stats_total.operations = stats_total.operations + 1
|
||||||
|
pos1 = stats.pos1
|
||||||
|
pos2 = stats.pos2
|
||||||
end
|
end
|
||||||
|
|
||||||
|
stats_total.pos1 = pos1
|
||||||
|
stats_total.pos2 = pos2
|
||||||
|
|
||||||
return true, stats_total
|
return true, stats_total
|
||||||
end
|
end
|
||||||
|
|
|
@ -24,8 +24,18 @@ function worldeditadditions.scale_down(pos1, pos2, scale, anchor)
|
||||||
y = math.floor(1 / scale.y),
|
y = math.floor(1 / scale.y),
|
||||||
z = math.floor(1 / scale.z)
|
z = math.floor(1 / scale.z)
|
||||||
}
|
}
|
||||||
print("[DEBUG] scale_down", worldeditadditions.vector.tostring(scale_down))
|
|
||||||
local size = vector.subtract(pos2, pos1)
|
local size = vector.subtract(pos2, pos1)
|
||||||
|
print("[DEBUG] scale_down", worldeditadditions.vector.tostring(scale_down), "size", size)
|
||||||
|
|
||||||
|
if size.x < scale_down.x or size.y < scale_down.y or size.z < scale.z then
|
||||||
|
return false, "Error: Area isn't big enough to apply scale down by "..worldeditadditions.vector.tostring(scale).."."
|
||||||
|
end
|
||||||
|
|
||||||
|
local size_small = {
|
||||||
|
x = math.floor(size.x / scale_down.x),
|
||||||
|
y = math.floor(size.y / scale_down.y),
|
||||||
|
z = math.floor(size.z / scale_down.z)
|
||||||
|
}
|
||||||
|
|
||||||
local manip, area = worldedit.manip_helpers.init(pos1, pos2)
|
local manip, area = worldedit.manip_helpers.init(pos1, pos2)
|
||||||
local data = manip:get_data()
|
local data = manip:get_data()
|
||||||
|
@ -34,7 +44,7 @@ function worldeditadditions.scale_down(pos1, pos2, scale, anchor)
|
||||||
local node_id_air = minetest.get_content_id("air")
|
local node_id_air = minetest.get_content_id("air")
|
||||||
|
|
||||||
|
|
||||||
local stats = { updated = 0, scale = "scale_down" }
|
local stats = { updated = 0, scale = scale_down, pos1 = pos1, pos2 = vector.add(pos1, size_small) }
|
||||||
-- Zero out the area we're scaling down into
|
-- Zero out the area we're scaling down into
|
||||||
for i in area:iterp(pos1, pos2) do
|
for i in area:iterp(pos1, pos2) do
|
||||||
data_copy[i] = node_id_air
|
data_copy[i] = node_id_air
|
||||||
|
@ -48,8 +58,14 @@ function worldeditadditions.scale_down(pos1, pos2, scale, anchor)
|
||||||
for x = pos2.x, pos1.x, -1 do
|
for x = pos2.x, pos1.x, -1 do
|
||||||
local posi_rel = vector.subtract({ x = x, y = y, z = z }, pos1)
|
local posi_rel = vector.subtract({ x = x, y = y, z = z }, pos1)
|
||||||
|
|
||||||
local posi_copy = worldeditadditions.shallowcopy(posi_rel)
|
-- local posi_copy = worldeditadditions.shallowcopy(posi_rel)
|
||||||
posi_copy = vector.floor(vector.divide(scale_down))
|
-- posi_copy = vector.floor(vector.divide(posi_rel/*, scale_down*/))
|
||||||
|
|
||||||
|
local posi_copy = {
|
||||||
|
x = math.floor(posi_rel.x / scale_down.x),
|
||||||
|
y = math.floor(posi_rel.y / scale_down.y),
|
||||||
|
z = math.floor(posi_rel.z / scale_down.z)
|
||||||
|
}
|
||||||
|
|
||||||
if anchor.x < 0 then posi_copy.x = size.x - posi_copy.x end
|
if anchor.x < 0 then posi_copy.x = size.x - posi_copy.x end
|
||||||
if anchor.y < 0 then posi_copy.y = size.y - posi_copy.y end
|
if anchor.y < 0 then posi_copy.y = size.y - posi_copy.y end
|
||||||
|
@ -73,5 +89,5 @@ function worldeditadditions.scale_down(pos1, pos2, scale, anchor)
|
||||||
-- Save the modified nodes back to disk & return
|
-- Save the modified nodes back to disk & return
|
||||||
worldedit.manip_helpers.finish(manip, data_copy)
|
worldedit.manip_helpers.finish(manip, data_copy)
|
||||||
|
|
||||||
return true, changes
|
return true, stats
|
||||||
end
|
end
|
||||||
|
|
|
@ -34,7 +34,7 @@ function worldeditadditions.scale_up(pos1, pos2, scale, anchor)
|
||||||
|
|
||||||
local size_big = vector.add(vector.subtract(pos2_big, pos1_big), 1)
|
local size_big = vector.add(vector.subtract(pos2_big, pos1_big), 1)
|
||||||
|
|
||||||
print("scale_up: scaling "..wea.vector.tostring(pos1).." to "..wea.vector.tostring(pos2).." (volume "..worldedit.volume(pos1, pos2).."; size "..wea.vector.tostring(size)..") to "..wea.vector.tostring(pos1_big).." to "..wea.vector.tostring(pos2_big).." (volume "..worldedit.volume(pos1_big, pos2_big).."; size "..wea.vector.tostring(size_big)..")")
|
-- print("scale_up: scaling "..wea.vector.tostring(pos1).." to "..wea.vector.tostring(pos2).." (volume "..worldedit.volume(pos1, pos2).."; size "..wea.vector.tostring(size)..") to "..wea.vector.tostring(pos1_big).." to "..wea.vector.tostring(pos2_big).." (volume "..worldedit.volume(pos1_big, pos2_big).."; size "..wea.vector.tostring(size_big)..")")
|
||||||
|
|
||||||
local manip_small, area_small = worldedit.manip_helpers.init(pos1, pos2)
|
local manip_small, area_small = worldedit.manip_helpers.init(pos1, pos2)
|
||||||
local manip_big, area_big = worldedit.manip_helpers.init(pos1_big, pos2_big)
|
local manip_big, area_big = worldedit.manip_helpers.init(pos1_big, pos2_big)
|
||||||
|
@ -43,7 +43,7 @@ function worldeditadditions.scale_up(pos1, pos2, scale, anchor)
|
||||||
|
|
||||||
local node_id_air = minetest.get_content_id("air")
|
local node_id_air = minetest.get_content_id("air")
|
||||||
|
|
||||||
local changes = { updated = 0, scale = "scale_up" }
|
local stats = { updated = 0, scale = scale, pos1 = pos1_big, pos2 = pos2_big }
|
||||||
for z = pos2.z, pos1.z, -1 do
|
for z = pos2.z, pos1.z, -1 do
|
||||||
for y = pos2.y, pos1.y, -1 do
|
for y = pos2.y, pos1.y, -1 do
|
||||||
for x = pos2.x, pos1.x, -1 do
|
for x = pos2.x, pos1.x, -1 do
|
||||||
|
@ -55,11 +55,11 @@ function worldeditadditions.scale_up(pos1, pos2, scale, anchor)
|
||||||
z = pos1_big.z + (posi_rel.z * scale.z) + (scale.z - 1)
|
z = pos1_big.z + (posi_rel.z * scale.z) + (scale.z - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
print(
|
-- print(
|
||||||
"posi", wea.vector.tostring(vector.new(x, y, z)),
|
-- "posi", wea.vector.tostring(vector.new(x, y, z)),
|
||||||
"posi_rel", wea.vector.tostring(posi_rel),
|
-- "posi_rel", wea.vector.tostring(posi_rel),
|
||||||
"kern_anchor", wea.vector.tostring(kern_anchor)
|
-- "kern_anchor", wea.vector.tostring(kern_anchor)
|
||||||
)
|
-- )
|
||||||
|
|
||||||
local source_val = data_source[area_small:index(x, y, z)]
|
local source_val = data_source[area_small:index(x, y, z)]
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ function worldeditadditions.scale_up(pos1, pos2, scale, anchor)
|
||||||
for ky = kern_anchor.y, kern_anchor.y - scale.y + 1, -1 do
|
for ky = kern_anchor.y, kern_anchor.y - scale.y + 1, -1 do
|
||||||
for kx = kern_anchor.x, kern_anchor.x - scale.x + 1, -1 do
|
for kx = kern_anchor.x, kern_anchor.x - scale.x + 1, -1 do
|
||||||
data_target[area_big:index(kx, ky, kz)] = source_val
|
data_target[area_big:index(kx, ky, kz)] = source_val
|
||||||
changes.updated = changes.updated + 1
|
stats.updated = stats.updated + 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -79,5 +79,5 @@ function worldeditadditions.scale_up(pos1, pos2, scale, anchor)
|
||||||
-- Save the region back to disk & return
|
-- Save the region back to disk & return
|
||||||
worldedit.manip_helpers.finish(manip_big, data_target)
|
worldedit.manip_helpers.finish(manip_big, data_target)
|
||||||
|
|
||||||
return true, changes
|
return true, stats
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,3 +1,22 @@
|
||||||
|
local function parse_scale_component(val)
|
||||||
|
local result = tonumber(val)
|
||||||
|
if result then return true, result end
|
||||||
|
if string.find(val, "/") then
|
||||||
|
local parts = worldeditadditions.split(val, "/", true)
|
||||||
|
local a = tonumber(parts[1])
|
||||||
|
local b = tonumber(parts[2])
|
||||||
|
if not b then return false, "Invalid number after the forward slash in scale component." end
|
||||||
|
if not a then return false, "Invalid number before the forward slash in scale component." end
|
||||||
|
return true, a / b
|
||||||
|
end
|
||||||
|
if string.find(val, "%%") then
|
||||||
|
local part = tonumber(string.sub(val, 1, -2))
|
||||||
|
if not part then return false, "We thought a scale component was a percentage, but failed to parse percentage as number." end
|
||||||
|
return true, part / 100
|
||||||
|
end
|
||||||
|
return false, "Failed to parse scale component (unrecognised format - we support things like '3', '0.5', '1/10', or '33%' without quotes)."
|
||||||
|
end
|
||||||
|
|
||||||
-- ███████ ██████ █████ ██ ███████
|
-- ███████ ██████ █████ ██ ███████
|
||||||
-- ██ ██ ██ ██ ██ ██
|
-- ██ ██ ██ ██ ██ ██
|
||||||
-- ███████ ██ ███████ ██ █████
|
-- ███████ ██ ███████ ██ █████
|
||||||
|
@ -22,8 +41,8 @@ worldedit.register_command("scale", {
|
||||||
return false, "Error: Got 2 arguments, but the first doesn't look like the name of an axis."
|
return false, "Error: Got 2 arguments, but the first doesn't look like the name of an axis."
|
||||||
end
|
end
|
||||||
local axis = parts[1]
|
local axis = parts[1]
|
||||||
local factor = tonumber(parts[2])
|
local success, factor = parse_scale_component(parts[2])
|
||||||
if not factor then return false, "Error: Invalid scale factor." end
|
if not success then return success, "Error: Invalid scale factor. Details: "..factor end
|
||||||
|
|
||||||
if axis:sub(1, 1) == "-" then
|
if axis:sub(1, 1) == "-" then
|
||||||
axis = axis:sub(2, 2)
|
axis = axis:sub(2, 2)
|
||||||
|
@ -32,19 +51,21 @@ worldedit.register_command("scale", {
|
||||||
|
|
||||||
scale[axis] = factor
|
scale[axis] = factor
|
||||||
elseif #parts >= 3 then
|
elseif #parts >= 3 then
|
||||||
local val = tonumber(parts[1])
|
local success, val = parse_scale_component(parts[1])
|
||||||
if not val then return false, "Error: x axis scale factor wasn't a number." end
|
if not success then return false, "Error: x axis scale factor wasn't a number. Details: "..val end
|
||||||
scale.x = val
|
scale.x = val
|
||||||
val = tonumber(parts[2])
|
|
||||||
if not val then return false, "Error: y axis scale factor wasn't a number." end
|
success, val = parse_scale_component(parts[2])
|
||||||
|
if not success then return false, "Error: y axis scale factor wasn't a number. Details: "..val end
|
||||||
scale.y = val
|
scale.y = val
|
||||||
val = tonumber(parts[3])
|
|
||||||
if not val then return false, "Error: z axis scale factor wasn't a number." end
|
success, val = parse_scale_component(parts[3])
|
||||||
|
if not success then return false, "Error: z axis scale factor wasn't a number. Details: "..val end
|
||||||
scale.z = val
|
scale.z = val
|
||||||
else
|
else
|
||||||
local val = tonumber(parts[1])
|
local success, val = parse_scale_component(parts[1])
|
||||||
if not val then
|
if not success then
|
||||||
return false, "Error: scale factor wasn't a number."
|
return false, "Error: scale factor wasn't a number. Details: "..val
|
||||||
end
|
end
|
||||||
scale.x = val
|
scale.x = val
|
||||||
scale.y = val
|
scale.y = val
|
||||||
|
@ -93,6 +114,10 @@ worldedit.register_command("scale", {
|
||||||
)
|
)
|
||||||
if not success then return success, stats end
|
if not success then return success, stats end
|
||||||
|
|
||||||
|
worldedit.pos1[name] = stats.pos1
|
||||||
|
worldedit.pos2[name] = stats.pos2
|
||||||
|
worldedit.marker_update(name)
|
||||||
|
|
||||||
local time_taken = worldeditadditions.get_ms_time() - start_time
|
local time_taken = worldeditadditions.get_ms_time() - start_time
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue