425 lines
10 KiB
Lua
425 lines
10 KiB
Lua
-- EgtVector3d.lua by EgalTech s.r.l. 2022/01/11
|
|
|
|
-- Tavola per definizione modulo (serve ma non usata)
|
|
local EgtVector3d = {}
|
|
|
|
EgtOutLog( 'EgtVector3d started', 1)
|
|
|
|
-- Include
|
|
require( 'EgtConst')
|
|
--EnableDebug( false)
|
|
|
|
|
|
-- Definizione classe Vector3d
|
|
Vector3d = {}
|
|
Vector3d.__index = Vector3d
|
|
|
|
-- funzione di utilita' per identificazione tipo
|
|
function isVector3d( a)
|
|
return ( getmetatable( a) == Vector3d)
|
|
end
|
|
|
|
local function New( x, y, z)
|
|
local v3d = setmetatable( {0,0,0}, Vector3d)
|
|
if not x then
|
|
return nil
|
|
elseif isVector3d( x) then
|
|
v3d[1] = x[1]
|
|
v3d[2] = x[2]
|
|
v3d[3] = x[3]
|
|
elseif type(x) == 'table' and #x >= 3 then
|
|
v3d[1] = x[1]
|
|
v3d[2] = x[2]
|
|
v3d[3] = x[3]
|
|
elseif type( x) == 'number' and type( y) == 'number' and type( z) == 'number' then
|
|
v3d[1] = x
|
|
v3d[2] = y
|
|
v3d[3] = z
|
|
else
|
|
error( 'A parameter is wrong', 2)
|
|
end
|
|
return v3d
|
|
end
|
|
|
|
setmetatable( Vector3d, { __call = function( _, ...) return New(...) end })
|
|
|
|
-- opposto di un vettore (unary -)
|
|
function Vector3d:__unm()
|
|
return New( - self[1], - self[2], - self[3])
|
|
end
|
|
|
|
-- somma di due vettori (+)
|
|
function Vector3d.__add( a, b)
|
|
if isVector3d( a) and isVector3d( b) then
|
|
return New( a[1] + b[1], a[2] + b[2], a[3] + b[3])
|
|
else
|
|
error( 'A parameter is not a Vector3d', 2)
|
|
end
|
|
end
|
|
|
|
-- sottrazione di due vettori (-)
|
|
function Vector3d.__sub( a, b)
|
|
if isVector3d( a) and isVector3d( b) then
|
|
return New( a[1] - b[1], a[2] - b[2], a[3] - b[3])
|
|
else
|
|
error( 'A parameter is not a Vector3d', 2)
|
|
end
|
|
end
|
|
|
|
-- moltiplicazione di un vettore per uno scalare, di uno scalare per un vettore o prodotto scalare (*)
|
|
function Vector3d.__mul( a, b)
|
|
if type( a) == 'number' then
|
|
return New( a * b[1], a * b[2], a * b[3])
|
|
elseif type( b) == 'number' then
|
|
return New( a[1] * b, a[2] * b, a[3] * b)
|
|
elseif isVector3d( a) and isVector3d( b) then
|
|
return ( a[1] * b[1] + a[2] * b[2] + a[3] * b[3])
|
|
else
|
|
error( 'A parameter is wrong', 2)
|
|
end
|
|
end
|
|
|
|
-- prodotto vettoriale (^)
|
|
function Vector3d.__pow( a, b)
|
|
if isVector3d( a) and isVector3d( b) then
|
|
return New( a[2] * b[3] - a[3] * b[2],
|
|
a[3] * b[1] - a[1] * b[3],
|
|
a[1] * b[2] - a[2] * b[1])
|
|
else
|
|
error( 'A parameter is not a Vector3d', 2)
|
|
end
|
|
end
|
|
|
|
-- divisione di un vettore per un numero (/)
|
|
function Vector3d.__div( a, b)
|
|
if isVector3d( a) and type( b) == 'number' then
|
|
return New( a[1] / b, a[2] / b, a[3] / b)
|
|
else
|
|
error( 'A parameter is wrong', 2)
|
|
end
|
|
end
|
|
|
|
-- triplo prodotto (a ^ b) * c
|
|
function Vector3d.TripleProd( a, b, c)
|
|
if isVector3d( a) and isVector3d( b) and isVector3d( c) then
|
|
return ( a[1] * ( b[2] * c[3] - b[3] * c[2]) +
|
|
a[2] * ( b[3] * c[1] - b[1] * c[3]) +
|
|
a[3] * ( b[1] * c[2] - b[2] * c[1]))
|
|
else
|
|
error( 'A parameter is wrong', 2)
|
|
end
|
|
end
|
|
|
|
-- verifica di vettore quasi nullo
|
|
function Vector3d:isSmall()
|
|
return (( self[1] * self[1] + self[2] * self[2] + self[3] * self[3]) < GEO.EPS_SMALL * GEO.EPS_SMALL)
|
|
end
|
|
|
|
-- verifica di vettore nullo
|
|
function Vector3d:isZero()
|
|
return (( self[1] * self[1] + self[2] * self[2] + self[3] * self[3]) < GEO.EPS_ZERO * GEO.EPS_ZERO)
|
|
end
|
|
|
|
-- verifica di vettore normalizzato
|
|
function Vector3d:isNormalized()
|
|
return ( math.abs( 1.0 - ( self[1] * self[1] + self[2] * self[2] + self[3] * self[3])) < 2.0 * GEO.EPS_ZERO)
|
|
end
|
|
|
|
-- calcolo quadrato della lunghezza
|
|
function Vector3d:sqlen()
|
|
return ( self[1] * self[1] + self[2] * self[2] + self[3] * self[3])
|
|
end
|
|
|
|
-- calcolo lunghezza
|
|
function Vector3d:len()
|
|
return math.sqrt( self[1] * self[1] + self[2] * self[2] + self[3] * self[3])
|
|
end
|
|
|
|
-- normalizzazione
|
|
function Vector3d:normalize()
|
|
local sqlen = self[1] * self[1] + self[2] * self[2] + self[3] * self[3]
|
|
-- verifico se già normalizzato
|
|
if math.abs( 1.0 - sqlen) < 2.0 * GEO.EPS_ZERO then
|
|
return true
|
|
end
|
|
-- verifico se normalizzabile
|
|
if sqlen < GEO.EPS_SMALL * GEO.EPS_SMALL then
|
|
return false
|
|
end
|
|
-- eseguo la normalizzazione
|
|
local len = math.sqrt( sqlen)
|
|
local denom = 1 / len
|
|
self[1] = self[1] * denom
|
|
self[2] = self[2] * denom
|
|
self[3] = self[3] * denom
|
|
return true
|
|
end
|
|
|
|
-- rotazione
|
|
function Vector3d:rotate( vtAx, dAngDeg)
|
|
if not isVector3d( self) or not isVector3d( vtAx) or not type( dAngDeg) == 'number' then
|
|
return false
|
|
end
|
|
local bOk, vRot = EgtVectorRotate( self, vtAx, dAngDeg)
|
|
if bOk then
|
|
self[1] = vRot[1]
|
|
self[2] = vRot[2]
|
|
self[3] = vRot[3]
|
|
end
|
|
return bOk
|
|
end
|
|
|
|
-- mirror
|
|
function Vector3d:mirror( vtOn)
|
|
if not isVector3d( self) or not isVector3d( vtOn) then
|
|
return false
|
|
end
|
|
local bOk, vMir = EgtVectorMirror( self, vtOn)
|
|
if bOk then
|
|
self[1] = vMir[1]
|
|
self[2] = vMir[2]
|
|
self[3] = vMir[3]
|
|
end
|
|
return bOk
|
|
end
|
|
|
|
-- trasformazione di riferimento verso globale
|
|
function Vector3d:toGlob( fTool)
|
|
if not isVector3d( self) or not isFrame3d( fTool) then
|
|
return false
|
|
end
|
|
local bOk, vNew = EgtVectorToGlob( self, fTool)
|
|
if bOk then
|
|
self[1] = vNew[1]
|
|
self[2] = vNew[2]
|
|
self[3] = vNew[3]
|
|
end
|
|
return bOk
|
|
end
|
|
|
|
-- trasformazione di riferimento verso locale
|
|
function Vector3d:toLoc( fTool)
|
|
if not isVector3d( self) or not isFrame3d( fTool) then
|
|
return false
|
|
end
|
|
local bOk, vNew = EgtVectorToLoc( self, fTool)
|
|
if bOk then
|
|
self[1] = vNew[1]
|
|
self[2] = vNew[2]
|
|
self[3] = vNew[3]
|
|
end
|
|
return bOk
|
|
end
|
|
|
|
-- trasformazione di riferimento da locale a locale
|
|
function Vector3d:locToLoc( fOri, fDest)
|
|
if not isVector3d( self) or not isFrame3d( fOri) or not isFrame3d( fDest) then
|
|
return false
|
|
end
|
|
local bOk, vNew = EgtVectorLocToLoc( self, fOri, fDest)
|
|
if bOk then
|
|
self[1] = vNew[1]
|
|
self[2] = vNew[2]
|
|
self[3] = vNew[3]
|
|
end
|
|
return bOk
|
|
end
|
|
|
|
-- restituzione componenti
|
|
function Vector3d:getX()
|
|
return self[1]
|
|
end
|
|
|
|
function Vector3d:getY()
|
|
return self[2]
|
|
end
|
|
|
|
function Vector3d:getZ()
|
|
return self[3]
|
|
end
|
|
|
|
-- assegnazione componenti
|
|
function Vector3d:setX( dX)
|
|
self[1] = dX
|
|
end
|
|
|
|
function Vector3d:setY( dY)
|
|
self[2] = dY
|
|
end
|
|
|
|
function Vector3d:setZ( dZ)
|
|
self[3] = dZ
|
|
end
|
|
|
|
-- conversione in stringa (tostring)
|
|
function Vector3d:__tostring()
|
|
return "(" .. EgtNumToString( self[1], 6) .. ", "
|
|
.. EgtNumToString( self[2], 6) .. ", "
|
|
.. EgtNumToString( self[3], 6) .. ")"
|
|
end
|
|
|
|
-- Alcune funzioni di confronto
|
|
function AreSameVectorApprox( a, b)
|
|
if isVector3d( a) and isVector3d( b) then
|
|
return ( a - b):isSmall()
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
|
|
function AreSameVectorExact( a, b)
|
|
if isVector3d( a) and isVector3d( b) then
|
|
return ( a - b):isZero()
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
|
|
function AreOppositeVectorApprox( a, b)
|
|
if isVector3d( a) and isVector3d( b) then
|
|
return ( a + b):isSmall()
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
|
|
function AreOppositeVectorExact( a, b)
|
|
if isVector3d( a) and isVector3d( b) then
|
|
return ( a + b):isZero()
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
|
|
function AreSameOrOppositeVectorApprox( a, b)
|
|
if isVector3d( a) and isVector3d( b) then
|
|
return ( a - b):isSmall() or ( a + b):isSmall()
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
|
|
function AreSameOrOppositeVectorExact( a, b)
|
|
if isVector3d( a) and isVector3d( b) then
|
|
return ( a - b):isZero() or ( a + b):isZero()
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
|
|
-- Creazione di vettori da coordinate sferiche e polari
|
|
function VectorFromSpherical( dLen, dAngVertDeg, dAngOrizzDeg)
|
|
local dAngVertRad = math.rad( dAngVertDeg)
|
|
local dAngOrizzRad = math.rad( dAngOrizzDeg)
|
|
local dSinAngVert = math.sin( dAngVertRad) ;
|
|
return Vector3d( dLen * dSinAngVert * math.cos( dAngOrizzRad),
|
|
dLen * dSinAngVert * math.sin( dAngOrizzRad),
|
|
dLen * math.cos( dAngVertRad)) ;
|
|
end
|
|
|
|
function VectorFromPolar( dLen, dAngDeg)
|
|
local dAngRad = math.rad( dAngDeg)
|
|
return Vector3d( dLen * math.cos( dAngRad),
|
|
dLen * math.sin( dAngRad),
|
|
0)
|
|
end
|
|
|
|
-- Creazione di vettore perpendicolare a dato e massimamente verso l'alto
|
|
function VectorFromUprightOrtho( vtV)
|
|
local vtAx = Vector3d( vtV)
|
|
if not vtAx then return nil end
|
|
-- se vettore nullo, imposto asse Z+
|
|
if vtAx:isZero() then
|
|
return Z_AX()
|
|
end
|
|
-- se vettore coincidente con asse Z, imposto asse X+
|
|
if AreSameOrOppositeVectorExact( vtAx, Z_AX()) then
|
|
return X_AX()
|
|
end
|
|
-- caso generico
|
|
vtAx:setZ( 0)
|
|
vtAx:normalize()
|
|
vtAx:rotate( Z_AX(), 90)
|
|
return ( vtV ^ vtAx)
|
|
end
|
|
|
|
-- Creazione di vettore da altro vettore con rotazione
|
|
function VectorFromRotated( vtV, vtAx, dAngDeg)
|
|
local vtRot = Vector3d( vtV)
|
|
if not vtRot then return nil end
|
|
vtRot:rotate( vtAx, dAngDeg)
|
|
return vtRot
|
|
end
|
|
|
|
-- Creazione di vettore da stringa di tre numeri
|
|
function VectorFromString( sVal)
|
|
if not sVal then
|
|
return nil
|
|
end
|
|
local vsVal = EgtSplitString( sVal)
|
|
if not vsVal then
|
|
return nil
|
|
end
|
|
if #vsVal < 3 then
|
|
return nil
|
|
end
|
|
return Vector3d( tonumber( vsVal[1]), tonumber( vsVal[2]), tonumber( vsVal[3]))
|
|
end
|
|
|
|
-- Creazione di vettore da info di entità GeomDB
|
|
function VectorFromInfo( nId, sKey)
|
|
return VectorFromString( EgtGetInfo( nId, sKey))
|
|
end
|
|
|
|
-- Coordinate sferiche da vettore
|
|
function SphericalFromVector( vtV)
|
|
if not isVector3d( vtV) then
|
|
return nil
|
|
end
|
|
local dLen = vtV:len()
|
|
-- vettore nullo
|
|
if math.abs( dLen) < GEO.EPS_ZERO then
|
|
return 0, 0, 0
|
|
end
|
|
-- vettore diretto come Z o -Z
|
|
if math.abs( vtV[1]) < GEO.EPS_ZERO and math.abs( vtV[2]) < GEO.EPS_ZERO then
|
|
if vtV[3] > 0 then
|
|
return dLen, 0, 0
|
|
else
|
|
return dLen, 180, 0
|
|
end
|
|
end
|
|
-- vettore nel piano XY
|
|
if math.abs( vtV[3]) < GEO.EPS_ZERO then
|
|
local dAngOri = math.deg( math.atan( vtV[2], vtV[1]))
|
|
if dAngOri < 0 then
|
|
dAngOri = dAngOri + 360
|
|
end
|
|
return dLen, 90, dAngOri
|
|
end
|
|
-- caso generale
|
|
local dAngVert = math.deg( math.acos( vtV[3] / dLen))
|
|
local dAngOri = math.deg( math.atan( vtV[2], vtV[1]))
|
|
if dAngOri < 0 then
|
|
dAngOri = dAngOri + 360
|
|
end
|
|
return dLen, dAngVert, dAngOri
|
|
end
|
|
|
|
-- Vettori notevoli
|
|
function V_NULL()
|
|
return Vector3d(0,0,0)
|
|
end
|
|
function X_AX()
|
|
return Vector3d(1,0,0)
|
|
end
|
|
function Y_AX()
|
|
return Vector3d(0,1,0)
|
|
end
|
|
function Z_AX()
|
|
return Vector3d(0,0,1)
|
|
end
|
|
|
|
|
|
return EgtVector3d
|