technical_drawings/functions.lua

242 lines
7.2 KiB
Lua

local S = technical_drawings.translator
local drawing_index_move = 8;
if minetest.get_modpath("hades_core") then
drawing_index_move = 10;
end
function technical_drawings.tool_on_use(itemstack, user, pointed_thing)
if not user then
return itemstack;
end
local item_def = itemstack:get_definition();
local tool = item_def._technical_drawings_tool;
--print(dump(tool))
if tool then
local inv = user:get_inventory()
local drawing_item = inv:get_stack("main", user:get_wield_index()+drawing_index_move);
local drawing_def = drawing_item:get_definition();
local node = minetest.get_node(pointed_thing.under);
--print(drawing_def._technical_drawings_name)
local recipe_data = technical_drawings.get_recipe(drawing_def._technical_drawings_name, tool.category_name, node.name);
--print(dump(recipe_data))
if recipe_data then
local node_meta = minetest.get_meta(pointed_thing.under);
local timestamp = node_meta:get_int("timestamp");
local gametime = minetest:get_gametime();
--print(gametime);
if ((gametime-timestamp)<tool.interval) then
return itemstack;
end
local points = tool.power/recipe_data.resistance;
if points<1 then
itemstack:add_wear(tool.wear);
return itemstack;
end
itemstack:add_wear(math.ceil(tool.wear/points));
local done = node_meta:get_int("points_done")+points;
if (done>=recipe_data.work_points) then
node.name = recipe_data.output;
minetest.set_node(pointed_thing.under, node);
else
node_meta:set_int("timestamp", gametime);
node_meta:set_int("points_done", done);
--print("done: "..done)
local percent = math.floor((100*done)/recipe_data.work_points);
local hud_image = "technical_drawings_progress_bar.png^[lowpart:"..percent..":technical_drawings_progress_bar_full.png^[transformR270]]"
local hud = user:hud_add({
hud_elem_type = "image",
scale = {x = 80, y = 2},
text = hud_image,
position = {x=0.5, y=0.5},
alignment = {x = 0, y = 0},
})
minetest.after(tool.interval*1.1, function() user:hud_remove(hud) end)
end
return itemstack;
end
end
return itemstack;
end
-- comparing drawings
local function drawings_diff_core(A, B)
local ratio = A.res/B.res;
local check = math.modf(ratio);
-- palette conjuction table
local conjuction = {};
local valid_points = 0;
-- same size drawing
-- statistic comparation for palette conjuction point to point
-- different size of drawing
-- use method point to multiple point
-- should be done in good way, to prevent background to be identified as line. Is it possible?
-- what about shitch A and B? (multicolored drawing from player match to ideal, no match ideal to player)
for y=1,A.res do
local lineA = A.grid[y];
for x=1,A.res do
-- use next cycle for different resolution of drawing
local pA = lineA[x];
local pB = B.grid[math.ceil(y/ratio)][math.ceil(x/ratio)];
if (pA~=0) and (pB~=0) then -- ignore DO NOT MATTER palette indexes
local conjA = conjuction[pA];
if not conjA then
conjA = {
conj = {},
};
conjuction[pA] = conjA;
end
--[[
if conjA.conj[pB] then
conjA.conj[pB] = conjA.conj[pB] + 1;
else
conjA.conj[pB] = 1;
end--]]
conjA.conj[pB] = (conjA.conj[pB] or 0) + 1;
valid_points = valid_points + 1;
end
end
end
--print(dump(conjuction))
-- I have conjuction, so select the best matches
local convertion = {};
for orig_palette,conj in pairs(conjuction) do
local vmax = 0;
local pmax = 0;
for palette,count in pairs(conj.conj) do
if (count>vmax) then
vmax = count;
pmax = palette;
end
end
convertion[orig_palette] = pmax;
end
--print(dump(convertion))
local diff = 0;
for y=1,A.res do
local lineA = A.grid[y];
for x=1,A.res do
local pA = lineA[x];
local pB = B.grid[math.ceil(y/ratio)][math.ceil(x/ratio)];
if (pA~=0) and (pB~=0) then -- ignore DO NOT MATTER palette indexes
if (convertion[pA]~=pB) then
diff = diff + 1;
end
end
end
end
--return diff;
return diff/valid_points;
--return (diff/valid_points)*(A.res/B.res);
--return diff/(A.res*A.res);
--return (((diff/valid_points)+(diff/(A.res*A.res)))/2);
end
function technical_drawings.drawings_diff(A, B)
if (A.res>=B.res) then
return drawings_diff_core(A, B);
else
return drawings_diff_core(B, A);
end
end
local function HexToRGB(hex)
return {
r = tonumber(string.sub(hex, 1, 2), 16),
g = tonumber(string.sub(hex, 3, 4), 16),
b = tonumber(string.sub(hex, 5, 6), 16),
}
end
local function RGBToHex(color)
return string.format("%02x%02x%02x", color.r, color.g, color.b);
end
local function DiffRGB(color1, color2)
return math.abs(color1.r-color2.r)+math.abs(color1.g-color2.g)+math.abs(color1.b-color2.b);
end
function technical_drawings.drawing_to_palette(drawing, max_colors_diff)
local palette = {};
for _,line_data in pairs(drawing.grid) do
for _,point_data in pairs(line_data) do
local new_color = true;
for _,palette_color in pairs(palette) do
if (DiffRGB(palette_color.center_color, HexToRGB(point_data))<=max_colors_diff) then
new_color = false;
if palette_color.colors[point_data] then
palette_color.colors[point_data] = palette_color.colors[point_data] + 1;
else
palette_color.colors[point_data] = 1;
end
break;
end
end
if new_color then
table.insert(palette, {
center_color = HexToRGB(point_data),
colors = {[point_data] = 1}
});
end
end
end
--print(dump(palette))
-- reduce drawing
local paletted = {};
for _,line_data in pairs(drawing.grid) do
local new_line = {};
for _,point_data in pairs(line_data) do
for palette_index,palette_color in pairs(palette) do
if (DiffRGB(palette_color.center_color, HexToRGB(point_data))<=max_colors_diff) then
table.insert(new_line, palette_index);
break;
end
end
end
table.insert(paletted, new_line);
end
return {
res = drawing.res,
grid = paletted,
}
end
function technical_drawings.find_best_drawing_math(drawing)
local best_math = 1
local best_name = nil
for drawing_name, drawing_data in pairs(technical_drawings.drawings) do
local diff = technical_drawings.drawings_diff(drawing, drawing_data.drawing)
if (diff<best_math) then
best_math = diff
best_name = drawing_name
end
--print(drawing_name..": "..diff)
end
if best_name then
local stack = ItemStack("technical_drawings:"..best_name)
local meta = stack:get_meta()
local def = stack:get_definition()
local quality = (1/(1+best_math))^4
meta:set_float("quality", quality)
meta:set_string("drawing", best_name)
meta:set_string("description", def.description.."\n"..S("Quality: ")..math.floor(quality*100).."%")
return stack
end
return nil
end