Add histogram

This commit is contained in:
Wuzzy 2022-04-16 23:48:35 +02:00
parent a55b50622b
commit 8f261ad354

143
init.lua
View File

@ -28,6 +28,8 @@ local FORMSPEC_BOX_COLOR = "#00000080"
-- Color for the section titles in the formspec
local FORMSPEC_HEADER_COLOR = "#000000FF"
local HISTOGRAM_BUCKETS = 10
local S = minetest.get_translator("perlin_explorer")
local F = minetest.formspec_escape
@ -404,7 +406,16 @@ local update_map = function(pos, set_nodes)
stats = {}
stats.avg = 0
local sum_of_values = 0
local value_count = 0
stats.value_count = 0
stats.histogram = {}
local min_possible, max_possible = analyze_noiseparams(current_perlin.noiseparams)
local cutoff_points = {}
for d=1,HISTOGRAM_BUCKETS do
cutoff_points[d] = min_possible + ((max_possible-min_possible) / HISTOGRAM_BUCKETS) * d
stats.histogram[d] = 0
end
for x=0, endpos.x - startpos.x do
for y=0, y_max do
for z=0, endpos.z - startpos.z do
@ -433,8 +444,15 @@ local update_map = function(pos, set_nodes)
elseif perlin_value > stats.max then
stats.max = perlin_value
end
-- Histogram
for c=1, HISTOGRAM_BUCKETS do
if perlin_value < cutoff_points[c] or c >= HISTOGRAM_BUCKETS then
stats.histogram[c] = stats.histogram[c] + 1
break
end
end
sum_of_values = sum_of_values + perlin_value
value_count = value_count + 1
stats.value_count = stats.value_count + 1
-- Calculate color (param2) for node
local zeropoint = 0
@ -478,7 +496,8 @@ local update_map = function(pos, set_nodes)
end
end
end
stats.avg = sum_of_values / value_count
stats.avg = sum_of_values / stats.value_count
stats.histogram_points = cutoff_points
if set_nodes then
-- Set vmanip, return stats
@ -516,28 +535,28 @@ local create_perlin = function(pos, options)
local set_nodes = options.set_nodes ~= false
local stats = update_map(mpos, set_nodes)
-- Show a particle in the center of the newly generated area
local center = vector.new()
center.x = mpos.x + options.size/2
if current_perlin.dimensions == 2 then
center.y = mpos.y + 3
else
center.y = mpos.y + options.size/2
if set_nodes then
-- Show a particle in the center of the newly generated area
local center = vector.new()
center.x = mpos.x + options.size/2
if current_perlin.dimensions == 2 then
center.y = mpos.y + 3
else
center.y = mpos.y + options.size/2
end
center.z = mpos.z + options.size/2
minetest.add_particle({
pos = center,
expirationtime = 4,
size = 16,
texture = "perlin_explorer_new_noisechunk.png",
glow = minetest.LIGHT_MAX,
})
end
center.z = mpos.z + options.size/2
minetest.add_particle({
pos = center,
expirationtime = 4,
size = 16,
texture = "perlin_explorer_new_noisechunk.png",
glow = minetest.LIGHT_MAX,
})
if stats then
minetest.log("info", "[perlin_explorer] Perlin noise generated at %s! Stats: min. value=%.3f, max. value=%.3f, avg. value=%.3f", minetest.pos_to_string(mpos), stats.min, stats.max, stats.avg)
local fo = function(str)
return string.format("%.3f", str)
end
return S("Perlin noise generated at @1! Stats: min. value=@2, max. value=@3, avg. value=@4", minetest.pos_to_string(mpos), fo(stats.min), fo(stats.max), fo(stats.avg))
return S("Perlin noise generated at @1!", minetest.pos_to_string(mpos)), stats
else
minetest.log("error", "[perlin_explorer] Could not get stats!")
return false
@ -692,6 +711,58 @@ minetest.register_chatcommand("perlin_generate", {
end,
})
local show_histogram_formspec = function(player, stats)
local txt = ""
local maxh = 6.0
local boxes = ""
for h=1, HISTOGRAM_BUCKETS do
local count = stats.histogram[h]
local ratio = (stats.histogram[h] / stats.value_count)
local perc = ratio * 100
local perc_f = string.format("%.1f", perc)
local x = (h-1) * 0.9
local height = maxh * ratio
local coords = x..","..maxh-height..";0.8,"..height
local box = ""
if count > 0 then
box = box .. "box["..coords..";#00FF00FF]"
box = box .. "tooltip["..coords..";"..count.."]"
end
box = box .. "label["..x..",6.3;"..F(S("@1%", perc_f)).."]"
local min, max
if h <= 1 then
min = ""
else
min = F(S(">= @1", stats.histogram_points[h-1]))
end
if h >= HISTOGRAM_BUCKETS then
max = ""
else
max = F(S("< @1", stats.histogram_points[h]))
end
box = box .. "label["..x..",6.8;"..max.."\n"..min.."]"
boxes = boxes .. box
end
local labels = "label[0,0;"..F(S("Values calculated: @1", stats.value_count)).."]"
local form = [[
formspec_version[4]size[10,11]
container[0.25,0.25]
box[0,0;9.5,10;]]..FORMSPEC_BOX_COLOR..[[]
box[0,0;9.5,0.4;]]..FORMSPEC_HEADER_COLOR..[[]
label[0.25,0.2;]]..F(S("Noise Parameter Histogram"))..[[]
container[0.25,0.8]
]]..labels..[[
]]..boxes..[[
container_end[]
container_end[]
]]
minetest.show_formspec(player:get_player_name(), "perlin_explorer:histogram", form)
end
-- Analyzes the given noise params and shows the result in a pretty-printed formspec to player
local analyze_noiseparams_and_show_formspec = function(player, noiseparams)
local min, max, waves = analyze_noiseparams(noiseparams)
@ -725,7 +796,8 @@ local analyze_noiseparams_and_show_formspec = function(player, noiseparams)
label[0.25,2.5;]]..F(S("Y wavelengths: @1", print_waves(waves.y)))..[[]
label[0.25,3;]]..F(S("Z wavelengths: @1", print_waves(waves.z)))..[[]
button[3,3.75;3,0.75;done;]]..F(S("Done"))..[[]
button[2,3.75;3,0.75;done;]]..F(S("Done"))..[[]
button[5,3.75;3,0.75;deep_analyze;]]..F(S("Deep analyze"))..[[]
container_end[]
--]]
@ -903,12 +975,29 @@ local fix_noiseparams = function(noiseparams)
end
minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname == "perlin_explorer:analyze" and fields.done then
local noiseparams = formspec_states[player:get_player_name()].noiseparams
show_noise_formspec(player, noiseparams)
return
-- Analysis window
if formname == "perlin_explorer:analyze" then
if fields.done then
local noiseparams = formspec_states[player:get_player_name()].noiseparams
show_noise_formspec(player, noiseparams)
return
elseif fields.deep_analyze then
local pos = vector.zero()
local size
if current_perlin.dimensions == 2 then
size = 2048
else -- 3 dimensions
size = 162 -- 163^3 is roughly equal to 2048
end
local _, stats = create_perlin(pos, {dimensions=current_perlin.dimensions, size=size, set_nodes=false})
if stats then
show_histogram_formspec(player, stats)
end
return
end
end
-- Creator window
if formname ~= "perlin_explorer:creator" then
return
end