454 lines
10 KiB
Lua
454 lines
10 KiB
Lua
|
|
-- Copyright (C) 2017-2020 DBotThePony
|
|
|
|
-- Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
-- of this software and associated documentation files (the "Software"), to deal
|
|
-- in the Software without restriction, including without limitation the rights
|
|
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
-- of the Software, and to permit persons to whom the Software is furnished to do so,
|
|
-- subject to the following conditions:
|
|
|
|
-- The above copyright notice and this permission notice shall be included in all copies
|
|
-- or substantial portions of the Software.
|
|
|
|
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
|
-- INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
|
-- PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
|
-- FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
|
-- OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
-- DEALINGS IN THE SOFTWARE.
|
|
|
|
DLib.vector = DLib.vector or {}
|
|
local vector = DLib.vector
|
|
local assert = assert
|
|
local error = error
|
|
local math = math
|
|
local ipairs = ipairs
|
|
local Vector = Vector
|
|
local LVector = LVector
|
|
local type = type
|
|
local setmetatable = setmetatable
|
|
|
|
function vector.FindCenter2D(min, max)
|
|
return max - (max - min) * 0.5
|
|
end
|
|
|
|
--[[
|
|
@doc
|
|
@fname DLib.vector.FindPlaneCentre
|
|
@args Vector mins, Vector maxs
|
|
|
|
@returns
|
|
Vector: centre
|
|
]]
|
|
-- It differs from vector.Centre by checking whenever surface is the surface
|
|
function vector.FindPlaneCentre(mins, maxs)
|
|
if mins.y == maxs.y then
|
|
local x1 = mins.x
|
|
local x2 = maxs.x
|
|
local y1 = mins.z
|
|
local y2 = maxs.z
|
|
|
|
return Vector((x2 - x1) * 0.5, mins.y, (y2 - y1) * 0.5)
|
|
elseif mins.x == maxs.x then
|
|
local x1 = mins.y
|
|
local x2 = maxs.y
|
|
local y1 = mins.z
|
|
local y2 = maxs.z
|
|
|
|
return Vector(mins.x, (x2 - x1) * 0.5, (y2 - y1) * 0.5)
|
|
elseif mins.z == maxs.z then
|
|
local x1 = mins.x
|
|
local x2 = maxs.x
|
|
local y1 = mins.y
|
|
local y2 = maxs.y
|
|
|
|
return Vector((x2 - x1) * 0.5, (y2 - y1) * 0.5, mins.z)
|
|
end
|
|
|
|
error('One or both of arguments is not a 2D plane!')
|
|
end
|
|
|
|
--[[
|
|
@doc
|
|
@fname DLib.vector.LFindPlaneCentre
|
|
@args LVector mins, LVector maxs
|
|
|
|
@returns
|
|
LVector: centre
|
|
]]
|
|
function vector.LFindPlaneCentre(mins, maxs)
|
|
if mins.y == maxs.y then
|
|
local x1 = mins.x
|
|
local x2 = maxs.x
|
|
local y1 = mins.z
|
|
local y2 = maxs.z
|
|
|
|
return LVector((x2 - x1) * 0.5, mins.y, (y2 - y1) * 0.5)
|
|
elseif mins.x == maxs.x then
|
|
local x1 = mins.y
|
|
local x2 = maxs.y
|
|
local y1 = mins.z
|
|
local y2 = maxs.z
|
|
|
|
return LVector(mins.x, (x2 - x1) * 0.5, (y2 - y1) * 0.5)
|
|
elseif mins.z == maxs.z then
|
|
local x1 = mins.x
|
|
local x2 = maxs.x
|
|
local y1 = mins.y
|
|
local y2 = maxs.y
|
|
|
|
return LVector((x2 - x1) * 0.5, (y2 - y1) * 0.5, mins.z)
|
|
end
|
|
|
|
error('One or both of arguments is not a 2D plane!')
|
|
end
|
|
|
|
--[[
|
|
vector.ExtractFaces: Table {
|
|
Face:
|
|
V1
|
|
V2
|
|
V3
|
|
V4
|
|
Normal
|
|
...
|
|
}
|
|
]]
|
|
|
|
--[[
|
|
@doc
|
|
@fname DLib.vector.ExtractFaces
|
|
@args Vector mins, Vector maxs
|
|
|
|
@returns
|
|
table: {{vertex1, vertex2, vertex3, vertex4, normal}, {vertex1, ...}}
|
|
]]
|
|
|
|
--[[
|
|
@doc
|
|
@fname DLib.vector.LExtractFaces
|
|
@args LVector mins, LVector maxs
|
|
|
|
@returns
|
|
table: {{vertex1, vertex2, vertex3, vertex4, normal}, {vertex1, ...}}
|
|
]]
|
|
function vector.ExtractFaces(mins, maxs)
|
|
return {
|
|
{
|
|
Vector(mins.x, mins.y, mins.z),
|
|
Vector(mins.x, mins.y, maxs.z),
|
|
Vector(mins.x, maxs.y, maxs.z),
|
|
Vector(mins.x, maxs.y, mins.z),
|
|
Vector(-1, 0, 0)
|
|
},
|
|
{
|
|
Vector(mins.x, mins.y, mins.z),
|
|
Vector(maxs.x, mins.y, mins.z),
|
|
Vector(maxs.x, mins.y, maxs.z),
|
|
Vector(mins.x, mins.y, maxs.z),
|
|
Vector(0, -1, 0)
|
|
},
|
|
{
|
|
Vector(mins.x, maxs.y, mins.z),
|
|
Vector(maxs.x, maxs.y, mins.z),
|
|
Vector(maxs.x, maxs.y, maxs.z),
|
|
Vector(mins.x, maxs.y, maxs.z),
|
|
Vector(0, 1, 0)
|
|
},
|
|
{
|
|
Vector(maxs.x, mins.y, mins.z),
|
|
Vector(maxs.x, mins.y, maxs.z),
|
|
Vector(maxs.x, maxs.y, maxs.z),
|
|
Vector(maxs.x, maxs.y, mins.z),
|
|
Vector(1, 0, 0)
|
|
},
|
|
{
|
|
Vector(mins.x, mins.y, maxs.z),
|
|
Vector(maxs.x, mins.y, maxs.z),
|
|
Vector(maxs.x, maxs.y, maxs.z),
|
|
Vector(mins.x, maxs.y, maxs.z),
|
|
Vector(0, 0, 1)
|
|
},
|
|
{
|
|
Vector(mins.x, mins.y, mins.z),
|
|
Vector(maxs.x, mins.y, mins.z),
|
|
Vector(maxs.x, maxs.y, mins.z),
|
|
Vector(mins.x, maxs.y, mins.z),
|
|
Vector(0, 0, -1)
|
|
},
|
|
}
|
|
end
|
|
|
|
function vector.LExtractFaces(mins, maxs)
|
|
return {
|
|
{
|
|
LVector(mins.x, mins.y, mins.z),
|
|
LVector(mins.x, mins.y, maxs.z),
|
|
LVector(mins.x, maxs.y, maxs.z),
|
|
LVector(mins.x, maxs.y, mins.z),
|
|
LVector(-1, 0, 0)
|
|
},
|
|
{
|
|
LVector(mins.x, mins.y, mins.z),
|
|
LVector(maxs.x, mins.y, mins.z),
|
|
LVector(maxs.x, mins.y, maxs.z),
|
|
LVector(mins.x, mins.y, maxs.z),
|
|
LVector(0, -1, 0)
|
|
},
|
|
{
|
|
LVector(mins.x, maxs.y, mins.z),
|
|
LVector(maxs.x, maxs.y, mins.z),
|
|
LVector(maxs.x, maxs.y, maxs.z),
|
|
LVector(mins.x, maxs.y, maxs.z),
|
|
LVector(0, 1, 0)
|
|
},
|
|
{
|
|
LVector(maxs.x, mins.y, mins.z),
|
|
LVector(maxs.x, mins.y, maxs.z),
|
|
LVector(maxs.x, maxs.y, maxs.z),
|
|
LVector(maxs.x, maxs.y, mins.z),
|
|
LVector(1, 0, 0)
|
|
},
|
|
{
|
|
LVector(mins.x, mins.y, maxs.z),
|
|
LVector(maxs.x, mins.y, maxs.z),
|
|
LVector(maxs.x, maxs.y, maxs.z),
|
|
LVector(mins.x, maxs.y, maxs.z),
|
|
LVector(0, 0, 1)
|
|
},
|
|
{
|
|
LVector(mins.x, mins.y, mins.z),
|
|
LVector(maxs.x, mins.y, mins.z),
|
|
LVector(maxs.x, maxs.y, mins.z),
|
|
LVector(mins.x, maxs.y, mins.z),
|
|
LVector(0, 0, -1)
|
|
},
|
|
}
|
|
end
|
|
|
|
--[[
|
|
vector.ExtractFacesAndCentre: Table {
|
|
Face:
|
|
V1
|
|
V2
|
|
V3
|
|
V4
|
|
Normal
|
|
Centre
|
|
...
|
|
}
|
|
]]
|
|
|
|
--[[
|
|
@doc
|
|
@fname DLib.vector.ExtractFacesAndCentre
|
|
@args Vector mins, Vector maxs
|
|
|
|
@returns
|
|
table: {{vertex1, vertex2, vertex3, vertex4, normal, centre}, {vertex1, ...}}
|
|
]]
|
|
function vector.ExtractFacesAndCentre(mins, maxs)
|
|
local find = vector.ExtractFaces(mins, maxs)
|
|
|
|
for i, data in ipairs(find) do
|
|
data[6] = vector.Centre(data[1], data[3])
|
|
end
|
|
|
|
return find
|
|
end
|
|
|
|
--[[
|
|
@doc
|
|
@fname DLib.vector.FindQuadSize
|
|
@args Vector V1, Vector V2, Vector V3, Vector V4
|
|
|
|
@returns
|
|
number
|
|
]]
|
|
function vector.FindQuadSize(V1, V2, V3, V4)
|
|
if math.equal(V1.x, V2.x, V3.x, V4.x) then
|
|
local minX = math.min(V1.y, V2.y, V3.y, V4.y)
|
|
local maxX = math.max(V1.y, V2.y, V3.y, V4.y)
|
|
local minY = math.min(V1.z, V2.z, V3.z, V4.z)
|
|
local maxY = math.max(V1.z, V2.z, V3.z, V4.z)
|
|
|
|
return maxX - minX, maxY - minY
|
|
elseif math.equal(V1.y, V2.y, V3.y, V4.y) then
|
|
local minX = math.min(V1.x, V2.x, V3.x, V4.x)
|
|
local maxX = math.max(V1.x, V2.x, V3.x, V4.x)
|
|
local minY = math.min(V1.z, V2.z, V3.z, V4.z)
|
|
local maxY = math.max(V1.z, V2.z, V3.z, V4.z)
|
|
|
|
return maxX - minX, maxY - minY
|
|
elseif math.equal(V1.z, V2.z, V3.z, V4.z) then
|
|
local minX = math.min(V1.x, V2.x, V3.x, V4.x)
|
|
local maxX = math.max(V1.x, V2.x, V3.x, V4.x)
|
|
local minY = math.min(V1.y, V2.y, V3.y, V4.y)
|
|
local maxY = math.max(V1.y, V2.y, V3.y, V4.y)
|
|
|
|
return maxX - minX, maxY - minY
|
|
end
|
|
|
|
error('No proper flat surface detected!')
|
|
end
|
|
|
|
--[[
|
|
@doc
|
|
@fname DLib.vector.Centre
|
|
@args Vector mins, Vector maxs
|
|
|
|
@returns
|
|
Vector
|
|
]]
|
|
|
|
--[[
|
|
@doc
|
|
@fname DLib.vector.LCentre
|
|
@args LVector mins, LVector maxs
|
|
|
|
@returns
|
|
LVector
|
|
]]
|
|
function vector.Centre(mins, maxs)
|
|
local deltax = maxs.x - mins.x
|
|
local deltay = maxs.y - mins.y
|
|
local deltaz = maxs.z - mins.z
|
|
return Vector(mins.x + deltax * 0.5, mins.y + deltay * 0.5, mins.z + deltaz * 0.5)
|
|
end
|
|
|
|
function vector.LCentre(mins, maxs)
|
|
local deltax = maxs.x - mins.x
|
|
local deltay = maxs.y - mins.y
|
|
local deltaz = maxs.z - mins.z
|
|
return LVector(mins.x + deltax * 0.5, mins.y + deltay * 0.5, mins.z + deltaz * 0.5)
|
|
end
|
|
|
|
--[[
|
|
@doc
|
|
@fname DLib.vector.CalculateSurfaceFromTwoPoints
|
|
@args Vector mins, Vector maxs, Vector zero
|
|
|
|
@desc
|
|
Give two vectors (e.g. mins and maxs) and origin position
|
|
origin position is Vector(0, 0, 0) if mins and maxs are WORLDSPACE vectors
|
|
if mins and maxs are local vectors, origin is probably position of entity
|
|
which these vectors are belong to
|
|
This function will return a table that represent `Ax + By + Cz + D = 0`
|
|
@enddesc
|
|
|
|
@returns
|
|
table: `{A, B, C, D}`
|
|
]]
|
|
function vector.CalculateSurfaceFromTwoPoints(mins, maxs, zero)
|
|
zero = zero or LVector(0, 0, 0)
|
|
|
|
local x0, y0, z0 = zero.x, zero.y, zero.z
|
|
local x1, y1, z1 = mins.x, mins.y, mins.z
|
|
local x2, y2, z2 = maxs.x, maxs.y, maxs.z
|
|
|
|
local a1 = -x0
|
|
local a2 = -y0
|
|
local a3 = -z0
|
|
|
|
local b1 = x1
|
|
local b2 = y1
|
|
local b3 = z1
|
|
|
|
local c1 = x2
|
|
local c2 = y2
|
|
local c3 = z2
|
|
|
|
local m1 = b2 * c3
|
|
local m2 = b1 * c2
|
|
local m3 = b3 * c1
|
|
local m4 = b2 * c1
|
|
local m5 = b3 * c2
|
|
local m6 = b1 * c3
|
|
|
|
local X, Y, Z, D = 0, 0, 0, 0
|
|
|
|
-- m1
|
|
X = X + m1
|
|
D = D + a1 * m1
|
|
|
|
-- m2
|
|
Z = Z + m2
|
|
D = D + a3 * m2
|
|
|
|
-- m3
|
|
Y = Y + m3
|
|
D = D + a2 * m3
|
|
|
|
-- m4
|
|
Z = Z - m4
|
|
D = D - a3 * m4
|
|
|
|
-- m5
|
|
X = X - m5
|
|
D = D - a1 * m5
|
|
|
|
-- m6
|
|
Y = Y - m6
|
|
D = D - a2 * m6
|
|
|
|
return {X, Y, Z, D}
|
|
end
|
|
|
|
--[[
|
|
@doc
|
|
@fname DLib.vector.DistanceFromPointToSurface
|
|
@args Vector point, table surface
|
|
|
|
@desc
|
|
surface is `{A, B, C, D}`
|
|
@enddesc
|
|
|
|
@returns
|
|
number
|
|
]]
|
|
function vector.DistanceFromPointToSurface(point, surfaceTable)
|
|
local A, B, C, D = surfaceTable[1], surfaceTable[2], surfaceTable[3], surfaceTable[4]
|
|
local Mx, My, Mz = point.x, point.y, point.z
|
|
local toDivide = math.abs(A * Mx + B * My + C * Mz + D)
|
|
local square = math.sqrt(math.pow(A, 2) + math.pow(B, 2) + math.pow(C, 2))
|
|
return toDivide / square
|
|
end
|
|
|
|
--[[
|
|
@doc
|
|
@fname DLib.vector.DistanceFromPointToPlane
|
|
@args Vector point, Vector mins, Vector maxs
|
|
|
|
@desc
|
|
minimal possible distance from point to plane
|
|
@enddesc
|
|
|
|
@returns
|
|
number
|
|
]]
|
|
function vector.DistanceFromPointToPlane(point, mins, maxs)
|
|
return vector.DistanceFromPointToSurface(point, vector.CalculateSurfaceFromTwoPoints(mins, maxs))
|
|
end
|
|
|
|
--[[
|
|
@doc
|
|
@fname DLib.vector.IsPositionInsideBox
|
|
@args Vector point, Vector mins, Vector maxs
|
|
|
|
@deprecated
|
|
|
|
@desc
|
|
use `Vector:WithinAABox` and `LVector:WithinAABox`
|
|
@enddesc
|
|
|
|
@returns
|
|
boolean
|
|
]]
|
|
function vector.IsPositionInsideBox(pos, mins, maxs)
|
|
return pos.x >= mins.x and pos.x <= maxs.x and
|
|
pos.y >= mins.y and pos.y <= maxs.y and
|
|
pos.z >= mins.z and pos.z <= maxs.z
|
|
end
|
|
|
|
return vector
|