//---------------------------------------------------------------------------- // EgalTech 2013-2013 //---------------------------------------------------------------------------- // File : Vector3d.cpp Data : 20.11.13 Versione : 1.3a1 // Contenuto : Funzioni della classe Vettore 3d. // // // // Modifiche : 04.01.13 DS Creazione modulo. // // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "\EgtDev\Include\EGkGeoConst.h" #include "\EgtDev\Include\EGkVector3d.h" #include "\EgtDev\Include\EGKFrame3d.h" //---------------------------------------------------------------------------- // Definizione a partire da coordinate sferiche //---------------------------------------------------------------------------- void Vector3d::FromSpherical( double dLen, double dAngVertDeg, double dAngOrizzDeg) { double dAngVertRad = dAngVertDeg * DEGTORAD ; double dAngOrizzRad = dAngOrizzDeg * DEGTORAD ; double dSinAngVert = sin( dAngVertRad) ; x = dLen * dSinAngVert * cos( dAngOrizzRad) ; y = dLen * dSinAngVert * sin( dAngOrizzRad) ; z = dLen * cos( dAngVertRad) ; } //---------------------------------------------------------------------------- // Definizione a partire da coordinate polari //---------------------------------------------------------------------------- void Vector3d::FromPolar( double dLen, double dAngDeg) { double dAngRad = dAngDeg * DEGTORAD ; x = dLen * cos( dAngRad) ; y = dLen * sin( dAngRad) ; z = 0 ; } //---------------------------------------------------------------------------- // Quadrato della lunghezza di un vettore //---------------------------------------------------------------------------- double Vector3d::SqLen( void) const { return ( x * x + y * y + z * z) ; } //---------------------------------------------------------------------------- // Lunghezza di un vettore //---------------------------------------------------------------------------- double Vector3d::Len( void) const { if ( fabs( y) < EPS_ZERO && fabs( z) < EPS_ZERO) return fabs( x) ; if ( fabs( z) < EPS_ZERO && fabs( x) < EPS_ZERO) return fabs( y) ; if ( fabs( x) < EPS_ZERO && fabs( y) < EPS_ZERO) return fabs( z) ; return sqrt( x * x + y * y + z * z) ; } //---------------------------------------------------------------------------- // Ritorna la rappresentazione in coordinate sferiche //---------------------------------------------------------------------------- void Vector3d::ToSpherical( double* pdLen, double* pdAngVertDeg, double* pdAngOrizzDeg) const { double dLen ; double dAngVertDeg ; double dAngOrizzDeg ; // lunghezza dLen = Len() ; // se vettore nullo if ( dLen < EPS_ZERO) { dAngVertDeg = 0 ; dAngOrizzDeg = 0 ; } // altrimenti else { // se diretto come Z if ( fabs( x) < EPS_ZERO && fabs( y) < EPS_ZERO) { dAngVertDeg = (( z > 0) ? 0 : 180) ; dAngOrizzDeg = 0 ; } // se altrimenti nel piano XY else if ( fabs( z) < EPS_ZERO) { dAngVertDeg = 90.0 ; dAngOrizzDeg = atan2( y, x) * RADTODEG ; if ( dAngOrizzDeg < 0) dAngOrizzDeg += 360 ; } // caso generico else { dAngVertDeg = acos( z / dLen) * RADTODEG ; dAngOrizzDeg = atan2( y, x) * RADTODEG ; if ( dAngOrizzDeg < 0) dAngOrizzDeg += 360 ; } } // ritorno i valori if ( pdLen != nullptr) *pdLen = dLen ; if ( pdAngVertDeg != nullptr) *pdAngVertDeg = dAngVertDeg ; if ( pdAngOrizzDeg != nullptr) *pdAngOrizzDeg = dAngOrizzDeg ; } //---------------------------------------------------------------------------- // Normalizzazione di un vettore (trasformazione in versore) //---------------------------------------------------------------------------- bool Vector3d::Normalize( double dEps) { double dSqLen ; double dLen ; // se già normalizzato, ok dSqLen = x * x + y * y + z * z ; if ( fabs( 1.0 - dSqLen) < ( 2 * EPS_ZERO)) return true ; // se troppo piccolo, errore if ( fabs( dSqLen) < ( dEps * dEps)) return false ; // eseguo la normalizzazione dLen = sqrt( dSqLen) ; *this = *this / dLen ; return true ; } //---------------------------------------------------------------------------- // Rotazione //---------------------------------------------------------------------------- bool Vector3d::Rotate( const Vector3d& vtAx, double dAngDeg) { double dAngRad = dAngDeg * DEGTORAD ; return Rotate( vtAx, cos( dAngRad), sin( dAngRad)) ; } //---------------------------------------------------------------------------- // Rotazione //---------------------------------------------------------------------------- bool Vector3d::Rotate( const Vector3d& vtAx, double dCosAng, double dSinAng) { // ricavo versore asse di rotazione Vector3d vtDirAx = vtAx ; if ( ! vtDirAx.Normalize()) return false ; // separazione del vettore nelle componenti parallela e perp. asse double dCompPar = *this * vtDirAx ; Vector3d vtCompPar = vtDirAx * dCompPar ; Vector3d vtCompPerp = *this - vtCompPar ; // calcolo vettore perp. componente perp. e asse Vector3d vtPerp2 = vtDirAx ^ vtCompPerp ; // calcolo componenti perp. del vettore ruotato Vector3d vtNewCompPerpX = dCosAng * vtCompPerp ; Vector3d vtNewCompPerpY = dSinAng * vtPerp2 ; Vector3d vtNewCompPerp = vtNewCompPerpX + vtNewCompPerpY ; // calcolo del vettore ruotato *this = vtCompPar + vtNewCompPerp ; return true ; } //---------------------------------------------------------------------------- // Scalatura non uniforme //---------------------------------------------------------------------------- bool Vector3d::Scale( const Frame3d& frRef, double dCoeffX, double dCoeffY, double dCoeffZ) { // verifico validità del frame if ( frRef.GetType() == Frame3d::ERR) return false ; // ricavo le componenti sugli assi di scalatura, le scalo e riassemblo il vettore completo *this = ( (*this) * frRef.VersX() * dCoeffX) * frRef.VersX() + ( (*this) * frRef.VersY() * dCoeffY) * frRef.VersY() + ( (*this) * frRef.VersZ() * dCoeffZ) * frRef.VersZ() ; return true ; } //---------------------------------------------------------------------------- // Specchiatura //---------------------------------------------------------------------------- bool Vector3d::Mirror( const Vector3d& vtNorm) { // ricavo versore normale al piano di simmetria Vector3d vtDirNorm = vtNorm ; if ( ! vtDirNorm.Normalize()) return false ; // calcolo la componente parallela alla normale double dCompNorm = *this * vtDirNorm ; // il simmetrico è il vettore originale meno il doppio della componente parallela *this = *this - 2 * dCompNorm * vtDirNorm ; return true ; } //---------------------------------------------------------------------------- // Scorrimento //---------------------------------------------------------------------------- bool Vector3d::Shear( const Vector3d& vtNorm, const Vector3d& vtDir, double dCoeff) { // costruisco il vettore *this += dCoeff * ( *this * vtNorm) * vtDir ; return true ; } //---------------------------------------------------------------------------- // Cambio di riferimento : dal riferimento al globale //---------------------------------------------------------------------------- bool Vector3d::ToGlob( const Frame3d& frRef) { // verifico validità del frame if ( frRef.GetType() == Frame3d::ERR) return false ; // eseguo trasformazione if ( frRef.GetType() != Frame3d::TOP) { Vector3d vtT( x, y, z) ; x = vtT.x * frRef.VersX().x + vtT.y * frRef.VersY().x + vtT.z * frRef.VersZ().x ; y = vtT.x * frRef.VersX().y + vtT.y * frRef.VersY().y + vtT.z * frRef.VersZ().y ; z = vtT.x * frRef.VersX().z + vtT.y * frRef.VersY().z + vtT.z * frRef.VersZ().z ; } return true ; } //---------------------------------------------------------------------------- // Cambio di riferimento : dal globale al riferimento //---------------------------------------------------------------------------- bool Vector3d::ToLoc( const Frame3d& frRef) { // verifico validità del frame if ( frRef.GetType() == Frame3d::ERR) return false ; // eseguo trasformazione if ( frRef.GetType() != Frame3d::TOP) { Vector3d vtT( x, y, z) ; x = vtT.x * frRef.VersX().x + vtT.y * frRef.VersX().y + vtT.z * frRef.VersX().z ; y = vtT.x * frRef.VersY().x + vtT.y * frRef.VersY().y + vtT.z * frRef.VersY().z ; z = vtT.x * frRef.VersZ().x + vtT.y * frRef.VersZ().y + vtT.z * frRef.VersZ().z ; } return true ; } //---------------------------------------------------------------------------- // Cambio di riferimento : dal primo riferimento al secondo //---------------------------------------------------------------------------- bool Vector3d::LocToLoc( const Frame3d& frOri, const Frame3d& frDest) { // se i due riferimenti coincidono, non devo fare alcunché if ( AreSameFrame( frOri, frDest)) return true ; return ( ToGlob( frOri) && ToLoc( frDest)) ; } //---------------------------------------------------------------------------- // Calcolo dell'angolo tra il vettore e un altro //---------------------------------------------------------------------------- bool Vector3d::GetAngle( const Vector3d& vtEnd, double& dAngDeg) const { double dProSca ; double dProVett ; // quantità ugualmente proporzionali a coseno e seno dProSca = *this * vtEnd ; dProVett = ( *this ^ vtEnd).Len() ; // se entrambe nulle if ( fabs( dProSca) < EPS_ZERO && fabs( dProVett) < EPS_ZERO) { dAngDeg = 0 ; return false ; } dAngDeg = atan2( dProVett, dProSca) * RADTODEG ; return true ; } //---------------------------------------------------------------------------- // Calcolo angolo di rotazione per portare la componente del vettore perpendicolare // all'asse di rotazione sulla stessa direzione della componente perpendicolare di vtEnd //---------------------------------------------------------------------------- bool Vector3d::GetRotation( const Vector3d& vtEnd, const Vector3d& vtAx, double& dAngDeg, bool& bDet) const { double dKcosA ; double dKsinA ; Vector3d vtDirAx ; Vector3d vtPerp ; Vector3d vtPerpE ; Vector3d vtPerp2 ; // ricavo versore asse di rotazione vtDirAx = vtAx ; if ( ! vtDirAx.Normalize()) return false ; // ricavo le componenti perpendicolari all'asse di rotazione vtPerp = *this - vtDirAx * ( *this * vtDirAx) ; vtPerpE = vtEnd - vtDirAx * ( vtEnd * vtDirAx) ; // se sono entrambe non nulle : angolo determinato if ( ! vtPerp.IsZero() && ! vtPerpE.IsZero()) { // secondo vettore perpendicolare ad asse e a componente perpendicolare vtPerp2 = vtDirAx ^ vtPerp ; // proporzionali a seno e coseno del perpendicolare E dKcosA = vtPerpE * vtPerp ; dKsinA = vtPerpE * vtPerp2 ; // angolo di rotazione dAngDeg = atan2( dKsinA, dKcosA) * RADTODEG ; bDet = true ; return true ; } // se comunque sono entrambe molto piccole : angolo indeterminato else if ( vtPerp.IsSmall() && vtPerpE.IsSmall()) { dAngDeg = 0 ; bDet = false ; return true ; } // altrimenti angolo impossibile else return false ; }