Initial commit

master
AndrejIT 2021-08-31 16:47:09 +03:00
commit 8fdcb6f32d
6 changed files with 418 additions and 0 deletions

26
README.md Normal file
View File

@ -0,0 +1,26 @@
# Relative coordinate helper functions
Helper library for Minetest game.
Main function is:
relative_coordinate_helper.get_pos_relative(pos, rel_pos, face_vector, down_vector)
You give vector rel_pos as coordinate relative to node and it's face and bottom.
x-FRONT/BACK, z-LEFT/RIGHT, y-UP/DOWN
And it gives you correct coordinates in the world!
relative_coordinate_helper.get_node_face_direction(pos)
relative_coordinate_helper.get_node_down_direction(pos)
MIT licence, so you can link to it, or copy it into your mod code.
Example will put fire in front of node:
local get_pos_relative = relative_coordinate_helper.get_pos_relative
local get_node_face_direction = relative_coordinate_helper.get_node_face_direction
local get_node_down_direction = relative_coordinate_helper.get_node_down_direction
local face_vector = get_node_face_direction(pos)
local down_vector = get_node_down_direction(pos)
minetest.set_node(get_pos_relative(pos, {x=1, y=0, z=0}, face_vector, down_vector), {name="fire:basic_flame"})

216
init.lua Normal file
View File

@ -0,0 +1,216 @@
relative_coordinate_helper = {}
-- Relative position is left-handed (as is minetest coordinate system)
-- Position, relative to: x-FRONT/BACK, z-LEFT/RIGHT, y-UP/DOWN
-- I think, this code has to be this long (unless there are some trick with matrix operations). And it should be optimal enough.
-- x-FRONT/BACK, z-LEFT/RIGHT, y-UP/DOWN
function relative_coordinate_helper.get_pos_relative(position, rel_pos, face_vector, down_vector)
local pos = {x=position.x,y=position.y,z=position.z}
if not face_vector then
face_vector = {x=1, y=0, z=0}
-- assert(vector.length(face_vector) == 1, "Incorrect face vector")
end
-- oh no! "wallmounted" and "facedir" cannot store down vector. i choose defaults.
if not down_vector then
down_vector = {x=0, y=0, z=0}
if face_vector.y == 1 then
down_vector.x = 1
elseif face_vector.y == -1 then
down_vector.x = -1
else
down_vector.y = -1
end
end
assert(vector.length(down_vector) == 1, "Incorrect down vector")
assert(vector.length(vector.multiply(face_vector, down_vector)) == 0, "Down vector ".."x"..down_vector.x.."y"..down_vector.y.."z"..down_vector.z.." incompatible with face vector ".."x"..face_vector.x.."y"..face_vector.y.."z"..face_vector.z)
if rel_pos.x == 0 and rel_pos.y == 0 and rel_pos.z == 0 then
return {x=pos.x, y=pos.y, z=pos.z}
end
local fdir = face_vector
local ddir = down_vector
if fdir.x == 1 then -- NORD
pos.x = pos.x + rel_pos.x
if ddir.y == -1 then
pos.y = pos.y + rel_pos.y
pos.z = pos.z + rel_pos.z
elseif ddir.x == 1 then
assert(false, "Impossible vector combination!")
elseif ddir.x == -1 then
assert(false, "Impossible vector combination!")
elseif ddir.z == 1 then
pos.y = pos.y + rel_pos.z
pos.z = pos.z - rel_pos.y
elseif ddir.z == -1 then
pos.y = pos.y - rel_pos.z
pos.z = pos.z + rel_pos.y
elseif ddir.y == 1 then
pos.y = pos.y - rel_pos.y
pos.z = pos.z - rel_pos.z
end
elseif fdir.z == -1 then -- EAST
pos.z = pos.z - rel_pos.x
if ddir.y == -1 then
pos.y = pos.y + rel_pos.y
pos.x = pos.x + rel_pos.z
elseif ddir.x == 1 then
pos.y = pos.y + rel_pos.z
pos.x = pos.x - rel_pos.y
elseif ddir.x == -1 then
pos.y = pos.y - rel_pos.z
pos.x = pos.x + rel_pos.y
elseif ddir.z == 1 then
assert(false, "Impossible vector combination!")
elseif ddir.z == -1 then
assert(false, "Impossible vector combination!")
elseif ddir.y == 1 then
pos.y = pos.y - rel_pos.y
pos.x = pos.x - rel_pos.z
end
elseif fdir.x == -1 then -- SOUTH
pos.x = pos.x - rel_pos.x
if ddir.y == -1 then
pos.y = pos.y + rel_pos.y
pos.z = pos.z - rel_pos.z
elseif ddir.x == 1 then
assert(false, "Impossible vector combination!")
elseif ddir.x == -1 then
assert(false, "Impossible vector combination!")
elseif ddir.z == 1 then
pos.y = pos.y - rel_pos.z
pos.z = pos.z - rel_pos.y
elseif ddir.z == -1 then
pos.y = pos.y + rel_pos.z
pos.z = pos.z + rel_pos.y
elseif ddir.y == 1 then
pos.y = pos.y - rel_pos.y
pos.z = pos.z + rel_pos.z
end
elseif fdir.z == 1 then -- WEST
pos.z = pos.z + rel_pos.x
if ddir.y == -1 then
pos.y = pos.y + rel_pos.y
pos.x = pos.x - rel_pos.z
elseif ddir.x == 1 then
pos.y = pos.y - rel_pos.z
pos.x = pos.x - rel_pos.y
elseif ddir.x == -1 then
pos.y = pos.y + rel_pos.z
pos.x = pos.x + rel_pos.y
elseif ddir.z == 1 then
assert(false, "Impossible vector combination!")
elseif ddir.z == -1 then
assert(false, "Impossible vector combination!")
elseif ddir.y == 1 then
pos.y = pos.y - rel_pos.y
pos.x = pos.x + rel_pos.z
end
elseif fdir.y == 1 then -- UP
pos.y = pos.y + rel_pos.x
if ddir.y == -1 then
assert(false, "Impossible vector combination!")
elseif ddir.x == 1 then
pos.x = pos.x - rel_pos.y
pos.z = pos.z + rel_pos.z
elseif ddir.x == -1 then
pos.x = pos.x + rel_pos.y
pos.z = pos.z - rel_pos.z
elseif ddir.z == 1 then
pos.x = pos.x - rel_pos.z
pos.z = pos.z - rel_pos.y
elseif ddir.z == -1 then
pos.x = pos.x + rel_pos.z
pos.z = pos.z + rel_pos.y
elseif ddir.y == 1 then
assert(false, "Impossible vector combination!")
end
elseif fdir.y == -1 then -- DOWN
pos.y = pos.y - rel_pos.x
if ddir.y == -1 then
assert(false, "Impossible vector combination!")
elseif ddir.x == 1 then
pos.x = pos.x - rel_pos.y
pos.z = pos.z - rel_pos.z
elseif ddir.x == -1 then
pos.x = pos.x + rel_pos.y
pos.z = pos.z + rel_pos.z
elseif ddir.z == 1 then
pos.x = pos.x + rel_pos.z
pos.z = pos.z - rel_pos.y
elseif ddir.z == -1 then
pos.x = pos.x - rel_pos.z
pos.z = pos.z + rel_pos.y
elseif ddir.y == 1 then
assert(false, "Impossible vector combination!")
end
end
return pos
end
function relative_coordinate_helper.get_node_face_direction(pos)
local node = minetest.get_node(pos)
local node_reg = minetest.registered_nodes[node.name]
local face_vector = nil
if node_reg.paramtype2 == "wallmounted" then
-- face_vector = vector.multiply(minetest.wallmounted_to_dir(node.param2), -1)
local param2_n = node.param2 % 8
face_vector = ({[0]={x=0, y=-1, z=0}, [1]={x=0, y=1, z=0}, [2]={x=-1, y=0, z=0}, [3]={x=1, y=0, z=0}, [4]={x=0, y=0, z=-1}, [5]={x=0, y=0, z=1}, [6]={x=0, y=-1, z=0}, [7]={x=0, y=-1, z=0}})[param2_n]
elseif node_reg.paramtype2 == "facedir" then
-- face_vector = vector.multiply(minetest.facedir_to_dir(node.param2), -1)
local param2_n = math.floor((node.param2 % 24)/4)
local param2_m = node.param2 % 4 -- division remainder
face_vector = ({
[0] = {[0]={x=0, y=0, z=-1}, [1]={x=0, y=1, z=0}, [2]={x=0, y=-1, z=0}, [3]={x=0, y=0, z=-1}, [4]={x=0, y=0, z=-1}, [5]={x=0, y=0, z=-1}},
[1] = {[0]={x=-1, y=0, z=0}, [1]={x=-1, y=0, z=0}, [2]={x=1, y=0, z=0}, [3]={x=0, y=1, z=0}, [4]={x=0, y=-1, z=0}, [5]={x=-1, y=0, z=0}},
[2] = {[0]={x=0, y=0, z=1}, [1]={x=0, y=-1, z=0}, [2]={x=0, y=1, z=0}, [3]={x=0, y=0, z=1}, [4]={x=0, y=0, z=1}, [5]={x=0, y=0, z=1}},
[3] = {[0]={x=1, y=0, z=0}, [1]={x=1, y=0, z=0}, [2]={x=-1, y=0, z=0}, [3]={x=0, y=-1, z=0}, [4]={x=0, y=1, z=0}, [5]={x=1, y=0, z=0}},
})[param2_m][param2_n]
else
face_vector = vector.new(1,0,0)
end
return face_vector
end
function relative_coordinate_helper.get_node_down_direction(pos)
local node = minetest.get_node(pos)
local node_reg = minetest.registered_nodes[node.name]
local down_vector = nil
if node_reg.paramtype2 == "wallmounted" then
local param2_n = node.param2 % 8
top_vector = ({[0]={x=0, y=0, z=-1}, [1]={x=0, y=0, z=-1}, [2]={x=0, y=-1, z=0}, [3]={x=0, y=-1, z=0}, [4]={x=0, y=-1, z=0}, [5]={x=0, y=-1, z=0}, [6]={x=0, y=0, z=1}, [7]={x=0, y=0, z=1}})[param2_n]
down_vector = vector.multiply(top_vector, -1)
elseif node_reg.paramtype2 == "facedir" then
local param2_n = math.floor((node.param2 % 24)/4)
local top_vector = ({[0]={x=0, y=1, z=0}, [1]={x=0, y=0, z=1}, [2]={x=0, y=0, z=-1}, [3]={x=1, y=0, z=0}, [4]={x=-1, y=0, z=0}, [5]={x=0, y=-1, z=0}})[param2_n]
down_vector = vector.multiply(top_vector, -1)
else
down_vector = vector.new(0,-1,0)
end
return down_vector
end
-- -- Debug
-- -- n - top direction: +y +z -z +x -x -y
-- -- m - rotate: clocwise, start from -z, or from +y when top +z; -y when top -z
-- minetest.register_chatcommand("coord_test", {
-- description = "Test coordinate helper",
-- params = "Test function and also do some tests in world",
-- privs = {server=true},
-- func = function(name, text)
-- dofile(minetest.get_modpath("relative_coordinate_helper").."/tests.lua")
-- relative_coordinate_helper.get_pos_relative_test1()
-- relative_coordinate_helper.get_pos_relative_test2()
-- end,
-- })

3
mod.conf Normal file
View File

@ -0,0 +1,3 @@
name = relative_coordinate_helper
optional_depends = default,fire
description = Helper functions to work with coordinates relative to node face and bottom (x-FRONT/BACK, z-LEFT/RIGHT, y-UP/DOWN).

BIN
screenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

BIN
screenshot2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

173
tests.lua Normal file
View File

@ -0,0 +1,173 @@
-- Tests if some relative coordinates are calculated correctly
-- Ideally it would be tests for all 6x4x26 combinations. But hopefully this will be enough for now.
function relative_coordinate_helper.get_pos_relative_test1()
local get_pos_relative = relative_coordinate_helper.get_pos_relative
local pos = {x=0, y=0, z=0}
local face_vector = {x=1, y=0, z=0}
local down_vector = {x=0, y=-1, z=0}
-- 0.
assert(
vector.equals( get_pos_relative(pos, {x=0, y=0, z=0}, face_vector, down_vector), {x=0, y=0, z=0} )
, "Test 0 failed")
minetest.chat_send_all('Test 0 done!')
-- 1. face forward
assert(
vector.equals( get_pos_relative(pos, {x=1, y=-1, z=1}, face_vector, down_vector), {x=1, y=-1, z=1} ) and
vector.equals( get_pos_relative(pos, {x=1, y=-1, z=0}, face_vector, down_vector), {x=1, y=-1, z=0} ) and
vector.equals( get_pos_relative(pos, {x=1, y=-1, z=-1}, face_vector, down_vector), {x=1, y=-1, z=-1} ) and
vector.equals( get_pos_relative(pos, {x=0, y=-1, z=1}, face_vector, down_vector), {x=0, y=-1, z=1} ) and
vector.equals( get_pos_relative(pos, {x=0, y=-1, z=0}, face_vector, down_vector), {x=0, y=-1, z=0} ) and
vector.equals( get_pos_relative(pos, {x=0, y=-1, z=-1}, face_vector, down_vector), {x=0, y=-1, z=-1} ) and
vector.equals( get_pos_relative(pos, {x=-1, y=-1, z=1}, face_vector, down_vector), {x=-1, y=-1, z=1} ) and
vector.equals( get_pos_relative(pos, {x=-1, y=-1, z=0}, face_vector, down_vector), {x=-1, y=-1, z=0} ) and
vector.equals( get_pos_relative(pos, {x=-1, y=-1, z=-1}, face_vector, down_vector), {x=-1, y=-1, z=-1} ) and
vector.equals( get_pos_relative(pos, {x=1, y=0, z=1}, face_vector, down_vector), {x=1, y=0, z=1} ) and
vector.equals( get_pos_relative(pos, {x=1, y=0, z=0}, face_vector, down_vector), {x=1, y=0, z=0} ) and
vector.equals( get_pos_relative(pos, {x=1, y=0, z=-1}, face_vector, down_vector), {x=1, y=0, z=-1} ) and
vector.equals( get_pos_relative(pos, {x=0, y=0, z=1}, face_vector, down_vector), {x=0, y=0, z=1} ) and
vector.equals( get_pos_relative(pos, {x=1, y=0, z=-1}, face_vector, down_vector), {x=1, y=0, z=-1} ) and
vector.equals( get_pos_relative(pos, {x=-1, y=0, z=1}, face_vector, down_vector), {x=-1, y=0, z=1} ) and
vector.equals( get_pos_relative(pos, {x=-1, y=0, z=0}, face_vector, down_vector), {x=-1, y=0, z=0} ) and
vector.equals( get_pos_relative(pos, {x=-1, y=0, z=-1}, face_vector, down_vector), {x=-1, y=0, z=-1} ) and
vector.equals( get_pos_relative(pos, {x=1, y=1, z=1}, face_vector, down_vector), {x=1, y=1, z=1} ) and
vector.equals( get_pos_relative(pos, {x=1, y=1, z=0}, face_vector, down_vector), {x=1, y=1, z=0} ) and
vector.equals( get_pos_relative(pos, {x=1, y=1, z=-1}, face_vector, down_vector), {x=1, y=1, z=-1} ) and
vector.equals( get_pos_relative(pos, {x=0, y=1, z=1}, face_vector, down_vector), {x=0, y=1, z=1} ) and
vector.equals( get_pos_relative(pos, {x=0, y=1, z=0}, face_vector, down_vector), {x=0, y=1, z=0} ) and
vector.equals( get_pos_relative(pos, {x=0, y=1, z=-1}, face_vector, down_vector), {x=0, y=1, z=-1} ) and
vector.equals( get_pos_relative(pos, {x=-1, y=1, z=1}, face_vector, down_vector), {x=-1, y=1, z=1} ) and
vector.equals( get_pos_relative(pos, {x=-1, y=1, z=0}, face_vector, down_vector), {x=-1, y=1, z=0} ) and
vector.equals( get_pos_relative(pos, {x=-1, y=1, z=-1}, face_vector, down_vector), {x=-1, y=1, z=-1} ) and
vector.equals( get_pos_relative(pos, {x=3, y=3, z=3}, face_vector, down_vector), {x=3, y=3, z=3} )
, "Test 1 failed")
minetest.chat_send_all('Test 1 done!')
-- 1.b face forward, tilt to the right
down_vector = {x=0, y=0, z=1}
assert(
vector.equals( get_pos_relative(pos, {x=-1, y=1, z=0}, face_vector, down_vector), {x=-1, y=0, z=-1} ) and
vector.equals( get_pos_relative(pos, {x=-1, y=1, z=-1}, face_vector, down_vector), {x=-1, y=-1, z=-1} ) and
vector.equals( get_pos_relative(pos, {x=3, y=3, z=3}, face_vector, down_vector), {x=3, y=3, z=-3} )
, "Test 1.b failed")
minetest.chat_send_all('Test 1.b done!')
-- 2. face to the right
face_vector = {x=0, y=0, z=-1}
down_vector = {x=0, y=-1, z=0}
assert(
vector.equals( get_pos_relative(pos, {x=-1, y=1, z=0}, face_vector, down_vector), {x=0, y=1, z=1} ) and
vector.equals( get_pos_relative(pos, {x=-1, y=1, z=-1}, face_vector, down_vector), {x=-1, y=1, z=1} ) and
vector.equals( get_pos_relative(pos, {x=3, y=3, z=3}, face_vector, down_vector), {x=3, y=3, z=-3} )
, "Test 2 failed")
minetest.chat_send_all('Test 2 done!')
-- 2.b face to the right, tilt to the right
face_vector = {x=0, y=0, z=-1}
down_vector = {x=1, y=0, z=0}
assert(
vector.equals( get_pos_relative(pos, {x=-1, y=1, z=0}, face_vector, down_vector), {x=-1, y=0, z=1} ) and
vector.equals( get_pos_relative(pos, {x=-1, y=1, z=-1}, face_vector, down_vector), {x=-1, y=-1, z=1} ) and
vector.equals( get_pos_relative(pos, {x=3, y=3, z=3}, face_vector, down_vector), {x=-3, y=3, z=-3} )
, "Test 2.b failed")
minetest.chat_send_all('Test 2.b done!')
-- 3.
face_vector = {x=-1, y=0, z=0}
down_vector = {x=0, y=-1, z=0}
assert(
vector.equals( get_pos_relative(pos, {x=3, y=3, z=3}, face_vector, down_vector), {x=-3, y=3, z=-3} )
, "Test 3 failed")
minetest.chat_send_all('Test 3 done!')
-- 4.
face_vector = {x=0, y=0, z=1}
down_vector = {x=0, y=-1, z=0}
assert(
vector.equals( get_pos_relative(pos, {x=3, y=3, z=3}, face_vector, down_vector), {x=-3, y=3, z=3} )
, "Test 4 failed")
minetest.chat_send_all('Test 4 done!')
-- 5. face up
face_vector = {x=0, y=1, z=0}
down_vector = {x=1, y=0, z=0}
assert(
vector.equals( get_pos_relative(pos, {x=-1, y=1, z=0}, face_vector, down_vector), {x=-1, y=-1, z=0} ) and
vector.equals( get_pos_relative(pos, {x=-1, y=1, z=-1}, face_vector, down_vector), {x=-1, y=-1, z=-1} ) and
vector.equals( get_pos_relative(pos, {x=3, y=3, z=3}, face_vector, down_vector), {x=-3, y=3, z=3} )
, "Test 5 failed")
minetest.chat_send_all('Test 5 done!')
-- 5.b face up, tilt to the right
face_vector = {x=0, y=1, z=0}
down_vector = {x=0, y=0, z=1}
assert(
vector.equals( get_pos_relative(pos, {x=-1, y=1, z=0}, face_vector, down_vector), {x=0, y=-1, z=-1} ) and
vector.equals( get_pos_relative(pos, {x=-1, y=1, z=-1}, face_vector, down_vector), {x=1, y=-1, z=-1} ) and
vector.equals( get_pos_relative(pos, {x=3, y=3, z=3}, face_vector, down_vector), {x=-3, y=3, z=-3} )
, "Test 5.b failed")
minetest.chat_send_all('Test 5.b done!')
-- 6. face down
face_vector = {x=0, y=-1, z=0}
down_vector = {x=-1, y=0, z=0}
assert(
vector.equals( get_pos_relative(pos, {x=1, y=-1, z=1}, face_vector, down_vector), {x=-1, y=-1, z=1} ) and
vector.equals( get_pos_relative(pos, {x=1, y=-1, z=0}, face_vector, down_vector), {x=-1, y=-1, z=0} ) and
vector.equals( get_pos_relative(pos, {x=1, y=-1, z=-1}, face_vector, down_vector), {x=-1, y=-1, z=-1} ) and
-- ...
vector.equals( get_pos_relative(pos, {x=3, y=3, z=3}, face_vector, down_vector), {x=3, y=-3, z=3} )
, "Test 6 failed")
minetest.chat_send_all('Test 6 done!')
-- ...
-- 6.c face down, tilt to the right two times
face_vector = {x=0, y=-1, z=0}
down_vector = {x=1, y=0, z=0}
assert(
vector.equals( get_pos_relative(pos, {x=1, y=-1, z=1}, face_vector, down_vector), {x=1, y=-1, z=-1} ) and
vector.equals( get_pos_relative(pos, {x=1, y=-1, z=0}, face_vector, down_vector), {x=1, y=-1, z=0} ) and
vector.equals( get_pos_relative(pos, {x=1, y=-1, z=-1}, face_vector, down_vector), {x=1, y=-1, z=1} ) and
-- ...
vector.equals( get_pos_relative(pos, {x=-1, y=1, z=0}, face_vector, down_vector), {x=-1, y=1, z=0} ) and
vector.equals( get_pos_relative(pos, {x=-1, y=1, z=-1}, face_vector, down_vector), {x=-1, y=1, z=1} ) and
vector.equals( get_pos_relative(pos, {x=3, y=3, z=3}, face_vector, down_vector), {x=-3, y=-3, z=-3} )
, "Test 6.c failed")
minetest.chat_send_all('Test 6.c done!')
-- 20.b face to the right, tilt to the right. different position.
face_vector = {x=0, y=0, z=-1}
down_vector = {x=1, y=0, z=0}
pos = {x=7, y=5, z=-7}
assert(
vector.equals( get_pos_relative(pos, {x=-1, y=1, z=0}, face_vector, down_vector), {x=6, y=5, z=-6} ) and
vector.equals( get_pos_relative(pos, {x=-1, y=1, z=-1}, face_vector, down_vector), {x=6, y=4, z=-6} ) and
vector.equals( get_pos_relative(pos, {x=3, y=3, z=3}, face_vector, down_vector), {x=4, y=8, z=-10} )
, "Test 20.b failed")
minetest.chat_send_all('Test 20.b done!')
minetest.chat_send_all('Looks like all tests completed succefuly!')
end
-- some testing in-world
function relative_coordinate_helper.get_pos_relative_test2()
local i = 0
for n = 0, 5, 1 do
for m = 0, 3, 1 do
local p = n * 4 + m
-- if m == 0 then
minetest.set_node({x=i, y=1, z=3}, {name="default:furnace", param2=p})
minetest.set_node({x=i, y=4, z=3}, {name="default:sign_wall", param2=p})
-- end
i = i + 2
end
end
local positions = minetest.find_nodes_in_area({x=-1, y=-1, z=-5}, {x=50, y=5, z=5}, {"default:furnace"})
local get_node_face_direction = relative_coordinate_helper.get_node_face_direction
local get_node_down_direction = relative_coordinate_helper.get_node_down_direction
local get_pos_relative = relative_coordinate_helper.get_pos_relative
for _, pos in ipairs(positions) do
local face_vector = get_node_face_direction(pos)
local down_vector = get_node_down_direction(pos)
minetest.set_node(get_pos_relative(pos, {x=1, y=0, z=0}, face_vector, down_vector), {name="fire:permanent_flame"})
end
minetest.chat_send_all("In-world test done.")
end