219 lines
4.7 KiB
Lua
219 lines
4.7 KiB
Lua
vcnlib.geometry = {}
|
|
|
|
--Short-hand used throughout this file
|
|
local geo = vcnlib.geometry
|
|
|
|
--Commanly used functions are assigned local values - to reduce access times
|
|
local abs = math.abs
|
|
local floor = math.floor
|
|
local hash_pos = minetest.hash_node_position
|
|
|
|
--[[
|
|
Manhattan distance to a point is the sum of the horizontal
|
|
and vertical distance to the point (2d)
|
|
|
|
4|3|2|3|4
|
|
3|2|1|2|3 This distance metric produces diamond shapes
|
|
2|1|0|1|2 when used on a single point
|
|
3|2|1|2|3
|
|
4|3|2|3|4
|
|
|
|
This is the distance metric that light sources use to spread in
|
|
minetest and minecraft
|
|
--]]
|
|
geo.manhattan = {
|
|
_2d = function(a,b)
|
|
local x=abs(a.x-b.x)
|
|
local z=abs(a.z-b.z)
|
|
return x+z
|
|
end,
|
|
_3d = function(a,b)
|
|
local x=abs(a.x-b.x)
|
|
local y=abs(a.y-b.y)
|
|
local z=abs(a.z-b.z)
|
|
return x+y+z
|
|
end,
|
|
}
|
|
|
|
--Helper function for chebyshev geometery
|
|
local function greatest(x,y,z)
|
|
if x>y then
|
|
if x>z then
|
|
return x
|
|
else
|
|
return z
|
|
end
|
|
else
|
|
if y>z then
|
|
return y
|
|
else
|
|
return z
|
|
end
|
|
end
|
|
end
|
|
|
|
--[[
|
|
The Chebyshev distance to a point is the longest distance out
|
|
of the horizontal and vertical distance (2d)
|
|
|
|
2|2|2|2|2
|
|
2|1|1|1|2 This distance metric produces squares when used
|
|
2|1|0|1|2 on a single point
|
|
2|1|1|1|2
|
|
2|2|2|2|2
|
|
--]]
|
|
geo.chebyshev = {
|
|
_2d = function(a,b)
|
|
local x=abs(a.x-b.x)
|
|
local z=abs(a.z-b.z)
|
|
return greatest(x,0,z)
|
|
end,
|
|
_3d = function(a,b)
|
|
local x=abs(a.x-b.x)
|
|
local y=abs(a.y-b.y)
|
|
local z=abs(a.z-b.z)
|
|
return greatest(x,y,z)
|
|
end,
|
|
}
|
|
|
|
--[[
|
|
The euclidean distance metric is the "real" distance to a point
|
|
This is the method of measuring distance taught in schools
|
|
|
|
This distance metric produces circles when used on a single point
|
|
|
|
The fast functions are used where only a comparison of distances
|
|
is needed - this allows for the expensive square root function to
|
|
be skipped
|
|
--]]
|
|
geo.euclidean = {
|
|
_2d = function(a,b)
|
|
local x=abs(a.x-b.x)
|
|
local z=abs(a.z-b.z)
|
|
return math.sqrt((x*x)+(z*z))
|
|
end,
|
|
_2d_fast = function(a,b)
|
|
local x=abs(a.x-b.x)
|
|
local z=abs(a.z-b.z)
|
|
return (x*x)+(z*z)
|
|
end,
|
|
_3d = function(a,b)
|
|
local x=abs(a.x-b.x)
|
|
local y=abs(a.y-b.y)
|
|
local z=abs(a.z-b.z)
|
|
return math.sqrt((x*x)+(y*y)+(z*z))
|
|
end,
|
|
_3d_fast = function(a,b)
|
|
local x=abs(a.x-b.x)
|
|
local y=abs(a.y-b.y)
|
|
local z=abs(a.z-b.z)
|
|
return (x*x)+(y*y)+(z*z)
|
|
end,
|
|
}
|
|
|
|
--[[
|
|
The oddprod distance metric is not a recognised distance metric which
|
|
was created for the interesting noise patterns it creates
|
|
|
|
It is defined entirely by the code below - but in short:
|
|
|
|
The distance to a point is the product of the horizontal
|
|
and vertical distance to the point.(2d)
|
|
|
|
Any axies which are less than 1 are set to one - this is to
|
|
avoid infinitely long formations if a point is aligned to a
|
|
node (i.e the distance is zero regardless of the real distance)
|
|
|
|
9|6|3|3|3|6|9
|
|
6|4|2|2|2|4|6
|
|
3|2|1|1|1|2|3 This distance metric produces a cross when used on
|
|
3|2|1|1|1|2|3 a single point
|
|
3|2|1|1|1|2|3
|
|
6|4|2|2|2|4|6
|
|
9|6|3|3|3|6|9
|
|
--]]
|
|
geo.oddprod = {
|
|
_2d = function(a,b)
|
|
local x=abs(a.x-b.x)
|
|
local z=abs(a.z-b.z)
|
|
if x <= 1 then
|
|
x=1
|
|
end
|
|
if z <= 1 then
|
|
z=1
|
|
end
|
|
return abs(x*z)
|
|
end,
|
|
_3d = function(a,b)
|
|
local x=abs(a.x-b.x)
|
|
local y=abs(a.y-b.y)
|
|
local z=abs(a.z-b.z)
|
|
if x <= 1 then
|
|
x=1
|
|
end
|
|
if y <= 1 then
|
|
y=1
|
|
end
|
|
if z <= 1 then
|
|
z=1
|
|
end
|
|
return abs(x*y*z)
|
|
end,
|
|
}
|
|
|
|
--[[
|
|
Helper function which returns the correct, full function for
|
|
calculating distance in that metric
|
|
|
|
This does not return the fast distance metric for comparison
|
|
is one exists (euclidean)
|
|
--]]
|
|
local get_distance_function = function (geometry, dimensions)
|
|
if geo[geometry] then
|
|
if dimensions == 3 then
|
|
return geo[geometry]._3d
|
|
else
|
|
return geo[geometry]._2d
|
|
end
|
|
else
|
|
return nil
|
|
end
|
|
end
|
|
|
|
vcnlib.get_distance_function = get_distance_function
|
|
|
|
--[[
|
|
Helper function which returns a function which produces
|
|
numbers which have correct comparisons for that distance
|
|
metric
|
|
|
|
e.g. Euclidean distance has to be calculated with a square root
|
|
at the end.
|
|
Taking the square root of two numbers doesn't change the
|
|
comparison of those two numbers - so this can be skipped
|
|
if you don't need the real value.
|
|
|
|
4 < 9 < 16 -> 2 < 3 < 4
|
|
--]]
|
|
local get_fast_distance_function = function (geometry, dimensions)
|
|
if geo[geometry] then
|
|
if dimensions == 3 then
|
|
--The fast distance metric is optional - so check it
|
|
--exists
|
|
if geo[geometry]._3d_fast then
|
|
return geo[geometry]._3d_fast
|
|
end
|
|
else
|
|
if geo[geometry]._2d then
|
|
return geo[geometry]._2d
|
|
end
|
|
end
|
|
--If no fast function exists, return the normal one
|
|
return get_distance_function(geometry, dimensions)
|
|
else
|
|
return nil
|
|
end
|
|
end
|
|
|
|
vcnlib.get_fast_distance_function = get_fast_distance_function
|