mapgen_rivers/terrainlib_lua/gaussian.lua

103 lines
2.1 KiB
Lua
Raw Normal View History

-- gaussian.lua
local function get_box_size(sigma, n)
local v = sigma^2 / n
local r_ideal = ((12*v + 1) ^ 0.5 - 1) / 2
local r_down = math.floor(r_ideal)
local r_up = math.ceil(r_ideal)
local v_down = ((2*r_down+1)^2 - 1) / 12
local v_up = ((2*r_up+1)^2 - 1) / 12
local m_ideal = (v - v_down) / (v_up - v_down) * n
local m = math.floor(m_ideal+0.5)
local sizes = {}
for i=1, n do
sizes[i] = i<=m and 2*r_up+1 or 2*r_down+1
end
return sizes
end
local function box_blur_1d(map, size, first, incr, len, map2)
local n = math.ceil(size/2)
first = first or 1
incr = incr or 1
len = len or math.floor((#map-first)/incr)+1
local last = first + (len-1)*incr
local nth = first+(n-1)*incr
local sum = 0
for i=first, nth, incr do
if i == first then
sum = sum + map[i]
else
sum = sum + 2*map[i]
end
end
local i_left = nth
local incr_left = -incr
local i_right = nth
local incr_right = incr
map2 = map2 or {}
for i=first, last, incr do
map2[i] = sum / size
i_right = i_right + incr_right
sum = sum - map[i_left] + map[i_right]
i_left = i_left + incr_left
if i_left == first then
incr_left = incr
end
if i_right == last then
incr_right = -incr
end
end
return map2
end
local function box_blur_2d(map1, size, map2)
local X, Y = map1.X, map1.Y
map2 = map2 or {}
for y=1, Y do
box_blur_1d(map1, size, (y-1)*X+1, 1, X, map2)
end
for x=1, X do
box_blur_1d(map2, size, x, X, Y, map1)
end
return map1
end
--[[local function gaussian_blur(map, std, tail)
local exp = math.exp
local kernel_mid = math.ceil(std*tail) + 1
local kernel_size = kernel_mid * 2 - 1
local kernel = {}
local cst1 = 1/(std*(2*math.pi)^0.5)
local cst2 = -1/(2*std^2)
for i=1, kernel_size do
kernel[i] = cst1 * exp((i-kernel_mid)^2 * cst2)
end
]]
local function gaussian_blur_approx(map, sigma, n, map2)
map2 = map2 or {}
local sizes = get_box_size(sigma, n)
for i=1, n do
box_blur_2d(map, sizes[i], map2)
end
return map
end
return {
get_box_size = get_box_size,
box_blur_1d = box_blur_1d,
box_blur_2d = box_blur_2d,
gaussian_blur_approx = gaussian_blur_approx,
}