-- 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