mirror of
https://github.com/sbrl/Minetest-WorldEditAdditions.git
synced 2024-11-26 00:53:00 +00:00
//convolve: update matrix & kernel to use Vector3
A lot of the maths remains in the old style, but at least it doesn't take a zero-indexed table
This commit is contained in:
parent
17cc91ba1c
commit
db5d25d1de
4 changed files with 68 additions and 44 deletions
|
@ -1,3 +1,5 @@
|
||||||
|
local Vector3 = worldeditadditions.Vector3
|
||||||
|
|
||||||
worldeditadditions.conv = {}
|
worldeditadditions.conv = {}
|
||||||
|
|
||||||
dofile(worldeditadditions.modpath.."/lib/conv/kernels.lua")
|
dofile(worldeditadditions.modpath.."/lib/conv/kernels.lua")
|
||||||
|
@ -41,14 +43,16 @@ end
|
||||||
function worldeditadditions.convolve(pos1, pos2, kernel, kernel_size)
|
function worldeditadditions.convolve(pos1, pos2, kernel, kernel_size)
|
||||||
pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
pos1, pos2 = worldedit.sort_pos(pos1, pos2)
|
||||||
|
|
||||||
local border_size = {}
|
local border_size = Vector3.new(
|
||||||
border_size[0] = (kernel_size[0]-1) / 2 -- height
|
(kernel_size.x-1) / 2, -- x = height
|
||||||
border_size[1] = (kernel_size[1]-1) / 2 -- width
|
0,
|
||||||
|
(kernel_size.z-1) / 2 -- z = width
|
||||||
|
)
|
||||||
|
|
||||||
pos1.z = pos1.z - border_size[0]
|
pos1.z = pos1.z - border_size.x
|
||||||
pos2.z = pos2.z + border_size[0]
|
pos2.z = pos2.z + border_size.x
|
||||||
pos1.x = pos1.x - border_size[1]
|
pos1.x = pos1.x - border_size.z
|
||||||
pos2.x = pos2.x + border_size[1]
|
pos2.x = pos2.x + border_size.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()
|
||||||
|
|
|
@ -1,31 +1,39 @@
|
||||||
|
local wea = worldeditadditions
|
||||||
|
local Vector3 = wea.Vector3
|
||||||
--[[
|
--[[
|
||||||
Convolves over a given 2D heightmap with a given matrix.
|
Convolves over a given 2D heightmap with a given matrix.
|
||||||
Note that this *mutates* the given heightmap.
|
Note that this *mutates* the given heightmap.
|
||||||
Note also that the dimensions of the matrix must *only* be odd.
|
Note also that the dimensions of the matrix must *only* be odd.
|
||||||
@param {number[]} heightmap The 2D heightmap to convolve over.
|
@param {number[]} heightmap The 2D heightmap to convolve over.
|
||||||
@param {[number,number]} heightmap_size The size of the heightmap as [ height, width ]
|
@param Vector3 heightmap_size The size of the heightmap as an X/Z Vector3 instance.
|
||||||
@param {number[]} matrix The matrix to convolve with.
|
@param {number[]} matrix The matrix to convolve with.
|
||||||
@param {[number, number]} matrix_size The size of the convolution matrix as [ height, width ]
|
@param Vector3 matrix_size The size of the convolution matrix as an X/Z Vector3 instance.
|
||||||
]]--
|
]]--
|
||||||
function worldeditadditions.conv.convolve(heightmap, heightmap_size, matrix, matrix_size)
|
function worldeditadditions.conv.convolve(heightmap, heightmap_size, matrix, matrix_size)
|
||||||
if matrix_size[0] % 2 ~= 1 or matrix_size[1] % 2 ~= 1 then
|
if matrix_size.x % 2 ~= 1 or matrix_size.z % 2 ~= 1 then
|
||||||
return false, "Error: The matrix size must contain only odd numbers (even number detected)"
|
return false, "Error: The matrix size must contain only odd numbers (even number detected)"
|
||||||
end
|
end
|
||||||
|
|
||||||
local border_size = {}
|
-- We need to reference a *copy* of the heightmap when convolving
|
||||||
border_size[0] = (matrix_size[0]-1) / 2 -- height
|
-- This is because we need the original values when we perform a
|
||||||
border_size[1] = (matrix_size[1]-1) / 2 -- width
|
-- convolution on a given pixel
|
||||||
-- print("[convolve] matrix_size", matrix_size[0], matrix_size[1])
|
local heightmap_copy = wea.table.shallowcopy(heightmap)
|
||||||
-- print("[convolve] border_size", border_size[0], border_size[1])
|
|
||||||
|
local border_size = Vector3.new(
|
||||||
|
(matrix_size.x-1) / 2, -- x = height
|
||||||
|
0,
|
||||||
|
(matrix_size.z-1) / 2 -- z = width
|
||||||
|
)
|
||||||
|
-- print("[convolve] matrix_size", matrix_size.x, matrix_size.z)
|
||||||
|
-- print("[convolve] border_size", border_size.x, border_size.z)
|
||||||
-- print("[convolve] heightmap_size: ", heightmap_size.z, heightmap_size.x)
|
-- print("[convolve] heightmap_size: ", heightmap_size.z, heightmap_size.x)
|
||||||
--
|
--
|
||||||
-- print("[convolve] z: from", (heightmap_size.z-border_size[0]) - 1, "to", border_size[0], "step", -1)
|
-- print("[convolve] z: from", (heightmap_size.z-border_size.x) - 1, "to", border_size.x, "step", -1)
|
||||||
-- print("[convolve] x: from", (heightmap_size.x-border_size[1]) - 1, "to", border_size[1], "step", -1)
|
-- print("[convolve] x: from", (heightmap_size.x-border_size.z) - 1, "to", border_size.z, "step", -1)
|
||||||
|
|
||||||
-- Convolve over only the bit that allows us to use the full convolution matrix
|
-- Convolve over only the bit that allows us to use the full convolution matrix
|
||||||
for z = (heightmap_size.z-border_size[0]) - 1, border_size[0], -1 do
|
for z = (heightmap_size.z-border_size.x) - 1, border_size.x, -1 do
|
||||||
for x = (heightmap_size.x-border_size[1]) - 1, border_size[1], -1 do
|
for x = (heightmap_size.x-border_size.z) - 1, border_size.z, -1 do
|
||||||
local total = 0
|
local total = 0
|
||||||
|
|
||||||
|
|
||||||
|
@ -33,21 +41,22 @@ function worldeditadditions.conv.convolve(heightmap, heightmap_size, matrix, mat
|
||||||
-- print("[convolve/internal] z", z, "x", x, "hi", hi)
|
-- print("[convolve/internal] z", z, "x", x, "hi", hi)
|
||||||
|
|
||||||
-- No continue statement in Lua :-/
|
-- No continue statement in Lua :-/
|
||||||
if heightmap[hi] ~= -1 then
|
if heightmap_copy[hi] ~= -1 then
|
||||||
for mz = matrix_size[0]-1, 0, -1 do
|
for mz = matrix_size.x-1, 0, -1 do
|
||||||
for mx = matrix_size[1]-1, 0, -1 do
|
for mx = matrix_size.z-1, 0, -1 do
|
||||||
local mi = (mz * matrix_size[1]) + mx
|
local mi = (mz * matrix_size.z) + mx
|
||||||
local cz = z + (mz - border_size[0])
|
local cz = z + (mz - border_size.x)
|
||||||
local cx = x + (mx - border_size[1])
|
local cx = x + (mx - border_size.z)
|
||||||
|
|
||||||
local i = (cz * heightmap_size.x) + cx
|
local i = (cz * heightmap_size.x) + cx
|
||||||
|
|
||||||
-- A value of -1 = nothing in this column (so we should ignore it)
|
-- A value of -1 = nothing in this column (so we should ignore it)
|
||||||
if heightmap[i] ~= -1 then
|
if heightmap_copy[i] ~= -1 then
|
||||||
total = total + (matrix[mi] * heightmap[i])
|
total = total + (matrix[mi] * heightmap_copy[i])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Rounding hack - ref https://stackoverflow.com/a/18313481/1460422
|
-- Rounding hack - ref https://stackoverflow.com/a/18313481/1460422
|
||||||
-- heightmap[hi] = math.floor(total + 0.5)
|
-- heightmap[hi] = math.floor(total + 0.5)
|
||||||
heightmap[hi] = math.ceil(total)
|
heightmap[hi] = math.ceil(total)
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
local Vector3 = worldeditadditions.Vector3
|
||||||
|
|
||||||
-- Test command: //multi //fp set1 1313 6 5540 //fp set2 1338 17 5521 //erode snowballs
|
-- Test command: //multi //fp set1 1313 6 5540 //fp set2 1338 17 5521 //erode snowballs
|
||||||
|
|
||||||
|
@ -132,7 +133,7 @@ function worldeditadditions.erode.snowballs(heightmap_initial, heightmap, height
|
||||||
if not params.noconv then
|
if not params.noconv then
|
||||||
local success, matrix = worldeditadditions.get_conv_kernel("gaussian", 3, 3)
|
local success, matrix = worldeditadditions.get_conv_kernel("gaussian", 3, 3)
|
||||||
if not success then return success, matrix end
|
if not success then return success, matrix end
|
||||||
local matrix_size = {} matrix_size[0] = 3 matrix_size[1] = 3
|
local matrix_size = Vector3.new(3, 0, 3)
|
||||||
worldeditadditions.conv.convolve(
|
worldeditadditions.conv.convolve(
|
||||||
heightmap, heightmap_size,
|
heightmap, heightmap_size,
|
||||||
matrix,
|
matrix,
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
local wea = worldeditadditions
|
||||||
|
local Vector3 = wea.Vector3
|
||||||
|
|
||||||
-- ██████ ██████ ███ ██ ██ ██ ██████ ██ ██ ██ ███████
|
-- ██████ ██████ ███ ██ ██ ██ ██████ ██ ██ ██ ███████
|
||||||
-- ██ ██ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
-- ██ ██ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
||||||
-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ █████
|
-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ █████
|
||||||
|
@ -11,8 +14,8 @@ worldedit.register_command("convolve", {
|
||||||
parse = function(params_text)
|
parse = function(params_text)
|
||||||
if not params_text then params_text = "" end
|
if not params_text then params_text = "" end
|
||||||
|
|
||||||
-- local parts = worldeditadditions.split(params_text, "%s+", false)
|
-- local parts = wea.split(params_text, "%s+", false)
|
||||||
local parts = worldeditadditions.split_shell(params_text)
|
local parts = wea.split_shell(params_text)
|
||||||
|
|
||||||
local kernel_name = "gaussian"
|
local kernel_name = "gaussian"
|
||||||
local width = 5
|
local width = 5
|
||||||
|
@ -23,7 +26,7 @@ worldedit.register_command("convolve", {
|
||||||
kernel_name = parts[1]
|
kernel_name = parts[1]
|
||||||
end
|
end
|
||||||
if #parts >= 2 then
|
if #parts >= 2 then
|
||||||
local parts_dimension = worldeditadditions.split(parts[2], ",%s*", false)
|
local parts_dimension = wea.split(parts[2], ",%s*", false)
|
||||||
width = tonumber(parts_dimension[1])
|
width = tonumber(parts_dimension[1])
|
||||||
if not width then
|
if not width then
|
||||||
return false, "Error: Invalid width (it must be a positive odd integer)."
|
return false, "Error: Invalid width (it must be a positive odd integer)."
|
||||||
|
@ -50,26 +53,33 @@ worldedit.register_command("convolve", {
|
||||||
return worldedit.volume(worldedit.pos1[name], worldedit.pos2[name])
|
return worldedit.volume(worldedit.pos1[name], worldedit.pos2[name])
|
||||||
end,
|
end,
|
||||||
func = function(name, kernel_name, kernel_width, kernel_height, sigma)
|
func = function(name, kernel_name, kernel_width, kernel_height, sigma)
|
||||||
local start_time = worldeditadditions.get_ms_time()
|
local start_time = wea.get_ms_time()
|
||||||
|
|
||||||
local success, kernel = worldeditadditions.get_conv_kernel(kernel_name, kernel_width, kernel_height, sigma)
|
local success, kernel = wea.get_conv_kernel(kernel_name, kernel_width, kernel_height, sigma)
|
||||||
if not success then return success, kernel end
|
if not success then return success, kernel end
|
||||||
|
|
||||||
local kernel_size = {}
|
local kernel_size = Vector3.new(
|
||||||
kernel_size[0] = kernel_height
|
kernel_height,
|
||||||
kernel_size[1] = kernel_width
|
0,
|
||||||
|
kernel_width
|
||||||
|
)
|
||||||
|
|
||||||
|
local pos1, pos2 = Vector3.sort(
|
||||||
|
worldedit.pos1[name],
|
||||||
|
worldedit.pos2[name]
|
||||||
|
)
|
||||||
|
|
||||||
local stats
|
local stats
|
||||||
success, stats = worldeditadditions.convolve(
|
success, stats = wea.convolve(
|
||||||
worldedit.pos1[name], worldedit.pos2[name],
|
pos1, pos2,
|
||||||
kernel, kernel_size
|
kernel, kernel_size
|
||||||
)
|
)
|
||||||
if not success then return success, stats end
|
if not success then return success, stats end
|
||||||
|
|
||||||
local time_taken = worldeditadditions.get_ms_time() - start_time
|
local time_taken = wea.get_ms_time() - start_time
|
||||||
|
|
||||||
|
|
||||||
minetest.log("action", name.." used //convolve at "..worldeditadditions.vector.tostring(worldedit.pos1[name]).." - "..worldeditadditions.vector.tostring(worldedit.pos2[name])..", adding "..stats.added.." nodes and removing "..stats.removed.." nodes in "..time_taken.."s")
|
minetest.log("action", name.." used //convolve at "..pos1.." - "..pos2..", adding "..stats.added.." nodes and removing "..stats.removed.." nodes in "..time_taken.."s")
|
||||||
return true, "Added "..stats.added.." and removed "..stats.removed.." nodes in " .. worldeditadditions.format.human_time(time_taken)
|
return true, "Added "..stats.added.." and removed "..stats.removed.." nodes in " .. wea.format.human_time(time_taken)
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in a new issue