//---------------------------------------------------------------------------- // EgalTech 2014-2015 //---------------------------------------------------------------------------- // File : EGkTria3d.h Data : 07.02.15 Versione : 1.6b2 // Contenuto : Dichiarazione classe triangolo Triangle3d. // // // // Modifiche : 30.03.14 DS Creazione modulo. // 07.02.15 DS Agg. GetArea e GetAspectRatio. // //---------------------------------------------------------------------------- #pragma once #include "/EgtDev/Include/EGkPoint3d.h" #include #include #include //----------------------------------------------------------------------------- class Triangle3d { public : Triangle3d( void) {} void Set( const Point3d& ptP0, const Point3d& ptP1, const Point3d& ptP2) { ptP[0] = ptP0 ; ptP[1] = ptP1 ; ptP[2] = ptP2 ; vtN.Set( 0, 0, 0) ; } void Set( const Point3d& ptP0, const Point3d& ptP1, const Point3d& ptP2, const Vector3d& vtV) { ptP[0] = ptP0 ; ptP[1] = ptP1 ; ptP[2] = ptP2 ; vtN = vtV ; } bool SetP( int nId, const Point3d& ptV) { if ( nId < 0 || nId >= 3) return false ; ptP[nId] = ptV ; return true ; } bool Validate( void) { if ( AreSamePointApprox( ptP[0], ptP[1]) || AreSamePointApprox( ptP[0], ptP[2])) return false ; Vector3d vtV = ( ptP[1] - ptP[0]) ^ ( ptP[2] - ptP[0]) ; vtV.Normalize() ; if ( ! vtN.IsZero()) return AreSameVectorApprox( vtV, vtN) ; vtN = vtV ; return true ; } bool ToGlob( const Frame3d& frRef) { return ( ptP[0].ToGlob( frRef) && ptP[1].ToGlob( frRef) && ptP[2].ToGlob( frRef)) ; } bool ToLoc( const Frame3d& frRef) { return ( ptP[0].ToLoc( frRef) && ptP[1].ToLoc( frRef) && ptP[2].ToLoc( frRef)) ; } bool LocToLoc( const Frame3d& frOri, const Frame3d& frDest) { return ( ptP[0].LocToLoc( frOri, frDest) && ptP[1].LocToLoc( frOri, frDest) && ptP[2].LocToLoc( frOri, frDest)) ; } const Point3d& GetP( int nId) const { if ( nId >= 0 && nId < 3) return ptP[nId] ; else if ( nId < 0) return ptP[0] ; else return ptP[2] ; } const Vector3d& GetN( void) const { return vtN ; } Point3d GetCentroid( void) const { return ( ptP[0] + ptP[1] + ptP[2]) / 3 ; } double GetArea( void) const { return (( ptP[1] - ptP[0]) ^ ( ptP[2] - ptP[0])).Len() / 2 ; } double GetAspectRatio( void) const { double dSqDistA = SqDist( ptP[0], ptP[1]) ; double dSqDistB = SqDist( ptP[1], ptP[2]) ; double dSqDistC = SqDist( ptP[2], ptP[0]) ; double dTwoArea = (( ptP[1] - ptP[0]) ^ ( ptP[2] - ptP[0])).Len() ; if ( dTwoArea < EPS_SMALL * EPS_SMALL) return INFINITO ; else return ( (std::max)( dSqDistA, (std::max)( dSqDistB, dSqDistC)) / dTwoArea) ; } private : Point3d ptP[3] ; Vector3d vtN ; } ; //---------------------------------------------------------------------------- // Raccolte di Triangle3d typedef std::vector TRIA3DVECTOR ; // vettore di Triangle3d typedef std::list TRIA3DLIST ; // lista di Triangle3d //----------------------------------------------------------------------------- // Flags indicanti se i lati sono parte del contorno di un poligono di pił triangoli class TriFlags3d { public : bool bFlag[3] ; } ; //----------------------------------------------------------------------------- // Normali sui vertici, ottenute mediando opportunamente coi triangoli vicini class TriNormals3d { public : Vector3d vtN[3] ; } ; //----------------------------------------------------------------------------- enum PlaneType { PL_NULL = 0, PL_XY = 1, PL_YZ = 2, PL_ZX = 3} ; //---------------------------------------------------------------------------- // Piano canonico di miglior proiezione (perpendicolare alla componente maggiore della normale) inline bool CalcProjPlane( const Vector3d& vtN, int& nPlane, bool& bCCW) { // verifico che la normale non sia nulla if ( vtN.IsZero()) return false ; // proiezione sul piano XY (Nz con valore maggiore) if ( fabs( vtN.z) > fabs( vtN.x) && fabs( vtN.z) > fabs( vtN.y)) { nPlane = PL_XY ; bCCW = ( vtN.z > 0) ; } // proiezione sul piano YZ (Nx con valore maggiore) else if ( fabs( vtN.x) > fabs( vtN.y)) { nPlane = PL_YZ ; bCCW = ( vtN.x > 0) ; } // proiezione sul piano ZX (Ny con valore maggiore) else { nPlane = PL_ZX ; bCCW = ( vtN.y > 0) ; } return true ; } //---------------------------------------------------------------------------- // Prodotto vettoriale nel piano di proiezione ( positivo se i 3 punti in ordine CCW) inline double TwoAreaInPlane( int nPlane, const Point3d& ptA, const Point3d& ptB, const Point3d& ptC) { switch ( nPlane) { default : // PL_XY return ( ptB.x - ptA.x) * ( ptC.y - ptB.y) - ( ptB.y - ptA.y) * ( ptC.x - ptB.x) ; case PL_YZ : return ( ptB.y - ptA.y) * ( ptC.z - ptB.z) - ( ptB.z - ptA.z) * ( ptC.y - ptB.y) ; case PL_ZX : return ( ptB.z - ptA.z) * ( ptC.x - ptB.x) - ( ptB.x - ptA.x) * ( ptC.z - ptB.z) ; } } //---------------------------------------------------------------------------- // Prodotto scalare nel piano di proiezione inline double ProScaInPlane( int nPlane, const Point3d& ptP, const Point3d& ptA, const Point3d& ptB) { switch ( nPlane) { default : // PL_XY return ( ptP.x - ptA.x) * ( ptB.x - ptA.x) + ( ptP.y - ptA.y) * ( ptB.y - ptA.y) ; case PL_YZ : return ( ptP.y - ptA.y) * ( ptB.y - ptA.y) + ( ptP.z - ptA.z) * ( ptB.z - ptA.z) ; case PL_ZX : return ( ptP.z - ptA.z) * ( ptB.z - ptA.z) + ( ptP.x - ptA.x) * ( ptB.x - ptA.x) ; } } //---------------------------------------------------------------------------- // Coordinate baricentriche di un punto giacente nel piano del triangolo inline bool BarycentricCoord( const Point3d& ptP, const Triangle3d& Tria, double& dU, double& dV, double& dW) { // calcolo del piano ottimale di proiezione int nPlane ; bool bCCW ; if ( ! CalcProjPlane( Tria.GetN(), nPlane, bCCW)) return false ; // verifico che l'area (doppia) non sia nulla double d2Area = TwoAreaInPlane( nPlane, Tria.GetP( 0), Tria.GetP( 1), Tria.GetP( 2)) ; if ( fabs( d2Area) < EPS_SMALL * EPS_SMALL) return false ; // calcolo delle coordinate baricentriche double dDenom = 1 / d2Area ; dU = TwoAreaInPlane( nPlane, ptP, Tria.GetP( 1), Tria.GetP( 2)) * dDenom ; dV = TwoAreaInPlane( nPlane, Tria.GetP( 0), ptP, Tria.GetP( 2)) * dDenom ; dW = TwoAreaInPlane( nPlane, Tria.GetP( 0), Tria.GetP( 1), ptP) * dDenom ; // devono dare somma unitaria double dSumm = dU + dV + dW ; if ( fabs( dSumm) < EPS_ZERO) return false ; if ( fabs( dSumm - 1) > EPS_ZERO) { double dDenom = 1 / dSumm ; dU *= dDenom ; dV *= dDenom ; dW *= dDenom ; } return true ; } //---------------------------------------------------------------------------- // Normale in un punto del triangolo, come media baricentrica delle normali nei vertici inline bool CalcNormal( const Point3d& ptP, const Triangle3d& Tria, const TriNormals3d& Tnorms, Vector3d& vtNorm) { // calcolo le coordinate baricentriche del punto double dU, dV, dW ; if ( ! BarycentricCoord( ptP, Tria, dU, dV, dW)) return false ; // calcolo la media vtNorm = dU * Tnorms.vtN[0] + dV * Tnorms.vtN[1] + dW * Tnorms.vtN[2] ; // la normalizzo return vtNorm.Normalize() ; }