convolve: fix a bunch of bugs.

It's still behaving reeaallllly strangely though
This commit is contained in:
Starbeamrainbowlabs 2020-06-09 22:00:56 +01:00
parent 868052f945
commit 2dbbeef9c9
Signed by: sbrl
GPG key ID: 1BE5172E637709C2
8 changed files with 37 additions and 19 deletions

View file

@ -21,6 +21,7 @@ dofile(worldeditadditions.modpath.."/lib/walls.lua")
dofile(worldeditadditions.modpath.."/lib/replacemix.lua") 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/conv/convolution.lua")
dofile(worldeditadditions.modpath.."/lib/count.lua") dofile(worldeditadditions.modpath.."/lib/count.lua")

View file

@ -66,10 +66,10 @@ function worldeditadditions.convolve(pos1, pos2, kernel, kernel_size)
local hi = z*heightmap_size[1] + x local hi = z*heightmap_size[1] + x
local diff = heightmap_conv[hi] - heightmap[hi] local diff = heightmap_conv[hi] - heightmap[hi]
-- Lua doesn't have a continue statement :-/ -- Lua doesn't have a continue statement :-/
if diff ~= 0 then if diff ~= 0 then
local node_id = data[area:index(pos1.x + x, pos1.y + heightmap[hi], pos1.z + z)] -- We subtract one because the heightmap starts at 1 (i.e. 1 = 1 node in the column), but the selected region is inclusive
local node_id = data[area:index(pos1.x + x, pos1.y + (heightmap[hi] - 1), pos1.z + z)]
if diff > 0 then if diff > 0 then
stats.added = stats.added + diff stats.added = stats.added + diff
for y = pos1.y + heightmap[hi], pos1.y + heightmap_conv[hi], 1 do for y = pos1.y + heightmap[hi], pos1.y + heightmap_conv[hi], 1 do

View file

@ -8,34 +8,41 @@ Note also that the dimensions of the matrix must *only* be odd.
@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 {[number, number]} matrix_size The size of the convolution matrix as [ height, width ]
]]-- ]]--
function worldeditadditions.conv.convole(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[0] % 2 ~= 1 or matrix_size[1] % 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 = { local border_size = {}
(matrix_size[0]-1) / 2, -- height border_size[0] = (matrix_size[0]-1) / 2 -- height
(matrix_size[1]-1) / 2 -- width border_size[1] = (matrix_size[1]-1) / 2 -- width
} print("[convolve] matrix_size", matrix_size[0], matrix_size[1])
print("[convolve] border_size", border_size[0], border_size[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 y = heightmap_size[0] - border_size[0], border_size[0], -1 do for y = (heightmap_size[0]-border_size[0]) - 1, border_size[0], -1 do
for x = heightmap_size[1] - border_size[1], border_size[1], -1 do for x = (heightmap_size[1]-border_size[1]) - 1, border_size[1], -1 do
local total = 0 local total = 0
for my = matrix_size[0], 0, -1 do
for mx = matrix_size[1], 0, -1 do for my = matrix_size[0]-1, 0, -1 do
for mx = matrix_size[1]-1, 0, -1 do
local mi = (my * matrix_size[1]) + mx local mi = (my * matrix_size[1]) + mx
local cy = y + (my - border_size[0]) local cy = y + (my - border_size[0])
local cx = x + (mx - border_size[1]) local cx = x + (mx - border_size[1])
local i = (cy * heightmap_size[1]) + cx local i = (cy * heightmap_size[1]) + cx
total = total + matrix[mi] * heightmap[i] -- print("[convolve] i", i, "mi", mi, "matrix[mi]", matrix[mi], "heightmap[i]", heightmap[i])
-- A value of -1 = nothing in this column (so we should ignore it)
if heightmap[i] ~= -1 then
total = total + (matrix[mi] * heightmap[i])
end
end end
end end
heightmap[(y * heightmap_size[1]) + x] = total -- Rounding hack - ref https://stackoverflow.com/a/18313481/1460422
heightmap[(y * heightmap_size[1]) + x] = math.floor(total + 0.5)
end end
end end

View file

@ -63,20 +63,23 @@ function worldeditadditions.make_heightmap(pos1, pos2, manip, area, data)
for x = pos1.x, pos2.x, 1 do for x = pos1.x, pos2.x, 1 do
local found_node = false local found_node = false
-- Scan each column top to bottom -- Scan each column top to bottom
for y = pos2.y, pos1.y, -1 do for y = pos2.y+1, pos1.y, -1 do
local i = area:index(x, y, z) local i = area:index(x, y, z)
if not worldeditadditions.is_airlike(data[i]) then if not worldeditadditions.is_airlike(data[i]) then
-- It's the first non-airlike node in this column -- It's the first non-airlike node in this column
heightmap[hi] = pos1.y - y -- Start heightmap values from 1 (i.e. there's at least 1 node in the column)
heightmap[hi] = (y - pos1.y) + 1
found_node = true found_node = true
break break
end end
end end
if not found_node then heightmap[hi] = -1 end if not found_node then heightmap[hi] = -1 end
i = i + 1 hi = hi + 1
end end
end end
worldeditadditions.print_2d(heightmap, (pos2.z - pos1.z) + 1)
return heightmap return heightmap
end end

View file

@ -86,9 +86,14 @@ end
-- @param tbl number[] The ZERO-indexed list of numbers -- @param tbl number[] The ZERO-indexed list of numbers
-- @param width number The width of 2D array. -- @param width number The width of 2D array.
function worldeditadditions.print_2d(tbl, width) function worldeditadditions.print_2d(tbl, width)
local display_width = 1
for _i,value in pairs(tbl) do
display_width = math.max(display_width, #tostring(value))
end
display_width = display_width + 2
local next = {} local next = {}
for i=0, #tbl do for i=0, #tbl do
table.insert(next, tbl[i]) table.insert(next, worldeditadditions.str_padstart(tostring(tbl[i]), display_width))
if #next == width then if #next == width then
print(table.concat(next, "\t")) print(table.concat(next, "\t"))
next = {} next = {}

View file

@ -25,7 +25,8 @@ worldedit.register_command("convolve", {
end end
if #parts >= 2 then if #parts >= 2 then
local parts_dimension = worldeditadditions.split(parts[2], ",%s*", false) local parts_dimension = worldeditadditions.split(parts[2], ",%s*", false)
width = tonumber(parts[1]) print("[convolve] [str]width", parts_dimension[1], "[str]height", parts_dimension[2])
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)."
end end
@ -50,9 +51,10 @@ worldedit.register_command("convolve", {
nodes_needed = function(name) nodes_needed = function(name)
return worldedit.volume(worldedit.pos1[name], worldedit.pos2[name]) return worldedit.volume(worldedit.pos1[name], worldedit.pos2[name])
end, end,
func = function(kernel_name, kernel_width, kernel_height, sigma) func = function(name, kernel_name, kernel_width, kernel_height, sigma)
local start_time = os.clock() local start_time = os.clock()
print("[exec] kernel_width", kernel_width, "kernel_height", kernel_height)
local success, kernel = worldeditadditions.get_conv_kernel(kernel_name, kernel_width, kernel_height, sigma) local success, kernel = worldeditadditions.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