//---------------------------------------------------------------------------- // EgalTech 2015-2015 //---------------------------------------------------------------------------- // File : ProjPlane.h Data : 20.02.15 Versione : 1.6b7 // Contenuto : Gestione calcoli su proiezione in piano canonico. // // // // Modifiche : 20.02.15 DS Creazione modulo. // // //---------------------------------------------------------------------------- #pragma once #include "/EgtDev/Include/EGkTriangle3d.h" //----------------------------------------------------------------------------- enum PntTriaPos { PTT_OUT = 0, // punto esterno al triangolo PTT_VERT = 1, // punto su un vertice PTT_EDGE = 2, // punto interno ad un lato PTT_IN = 3} ; // punto interno //---------------------------------------------------------------------------- #define UpdateMin( dMin, dVal) if ( dVal < dMin) dMin = dVal ; #define UpdateMax( dMax, dVal) if ( dVal > dMax) dMax = dVal ; //---------------------------------------------------------------------------- // Verifica se un punto è compreso nel box del triangolo. inline bool PointInTriaBox( const Point3d& ptP, const Point3d& ptA, const Point3d& ptB, const Point3d& ptC) { double Xmin = ptA.x ; UpdateMin( Xmin, ptB.x) UpdateMin( Xmin, ptC.x) if ( ptP.x < Xmin - EPS_SMALL) return false ; double Ymin = ptA.y ; UpdateMin( Ymin, ptB.y) UpdateMin( Ymin, ptC.y) if ( ptP.y < Ymin - EPS_SMALL) return false ; double Zmin = ptA.z ; UpdateMin( Zmin, ptB.z) UpdateMin( Zmin, ptC.z) if ( ptP.z < Zmin - EPS_SMALL) return false ; double Xmax = ptA.x ; UpdateMax( Xmax, ptB.x) UpdateMax( Xmax, ptC.x) if ( ptP.x > Xmax + EPS_SMALL) return false ; double Ymax = ptA.y ; UpdateMax( Ymax, ptB.y) UpdateMax( Ymax, ptC.y) if ( ptP.y > Ymax + EPS_SMALL) return false ; double Zmax = ptA.z ; UpdateMax( Zmax, ptB.z) UpdateMax( Zmax, ptC.z) if ( ptP.z > Zmax + EPS_SMALL) return false ; return true ; } //---------------------------------------------------------------------------- // Coincidenza approssimata di punti nel piano di proiezione inline bool AreSamePointApproxInPlane( int nPlane, const Point3d& ptP1, const Point3d& ptP2) { double dX, dY, dZ ; switch ( nPlane) { default : // PL_XY dX = ptP1.x - ptP2.x ; dY = ptP1.y - ptP2.y ; return ( ( dX * dX + dY * dY) < SQ_EPS_SMALL) ; case PL_YZ : dY = ptP1.y - ptP2.y ; dZ = ptP1.z - ptP2.z ; return ( ( dY * dY + dZ * dZ) < SQ_EPS_SMALL) ; case PL_ZX : dZ = ptP1.z - ptP2.z ; dX = ptP1.x - ptP2.x ; return ( ( dZ * dZ + dX * dX) < SQ_EPS_SMALL) ; } } //---------------------------------------------------------------------------- // Lunghezza del segmento nel piano di proiezione inline double LenSegmentInPlane( int nPlane, const Point3d& ptA, const Point3d& ptB) { switch ( nPlane) { default : // PL_XY return sqrt( ( ptB.x - ptA.x) * ( ptB.x - ptA.x) + ( ptB.y - ptA.y) * ( ptB.y - ptA.y)) ; case PL_YZ : return sqrt( ( ptB.y - ptA.y) * ( ptB.y - ptA.y) + ( ptB.z - ptA.z) * ( ptB.z - ptA.z)) ; case PL_ZX : return sqrt( ( ptB.z - ptA.z) * ( ptB.z - ptA.z) + ( ptB.x - ptA.x) * ( ptB.x - ptA.x)) ; } } //---------------------------------------------------------------------------- // Verifica se un punto giacente nel piano del triangolo è compreso nello stesso. inline int PointInTria( const Point3d& ptP, const Triangle3d& Tria) { // verifico che il punto stia nel box del triangolo if ( ! PointInTriaBox( ptP, Tria.GetP( 0), Tria.GetP( 1), Tria.GetP( 2))) return PTT_OUT ; // calcolo il piano ottimale di proiezione int nPlane ; bool bCCW ; if ( ! CalcProjPlane( Tria.GetN(), nPlane, bCCW)) return PTT_OUT ; // verifico se il punto sta su un vertice if ( AreSamePointApproxInPlane( nPlane, ptP, Tria.GetP( 0)) || AreSamePointApproxInPlane( nPlane, ptP, Tria.GetP( 1)) || AreSamePointApproxInPlane( nPlane, ptP, Tria.GetP( 2))) return PTT_VERT ; // calcolo la lunghezza dei lati double dLenAB = LenSegmentInPlane( nPlane, Tria.GetP( 0), Tria.GetP( 1)) ; double dLenBC = LenSegmentInPlane( nPlane, Tria.GetP( 1), Tria.GetP( 2)) ; double dLenCA = LenSegmentInPlane( nPlane, Tria.GetP( 2), Tria.GetP( 0)) ; if ( dLenAB < EPS_SMALL || dLenBC < EPS_SMALL || dLenCA < EPS_SMALL) return PTT_OUT ; // determino la posizione del punto rispetto ai lati del triangolo double dPosAB = TwoAreaInPlane( nPlane, ptP, Tria.GetP( 0), Tria.GetP( 1)) / dLenAB ; double dPosBC = TwoAreaInPlane( nPlane, ptP, Tria.GetP( 1), Tria.GetP( 2)) / dLenBC ; double dPosCA = TwoAreaInPlane( nPlane, ptP, Tria.GetP( 2), Tria.GetP( 0)) / dLenCA ; // se tre valori nulli, triangolo non definito correttamente if ( fabs( dPosAB) < EPS_SMALL && fabs( dPosBC) < EPS_SMALL && fabs( dPosCA) < EPS_SMALL) return PTT_OUT ; // se un valore nullo e gli altri due con lo stesso segno if ( fabs( dPosAB) < EPS_SMALL && ( dPosBC * dPosCA) > 0) { // se la proiezione del punto sta sul lato AB double dPro = ProScaInPlane( nPlane, ptP, Tria.GetP( 0), Tria.GetP( 1)) / dLenAB ; if ( dPro > 0 && dPro < dLenAB) return PTT_EDGE ; } if ( fabs( dPosBC) < EPS_SMALL && ( dPosCA * dPosAB) > 0) { // se la proiezione del punto sta sul lato BC double dPro = ProScaInPlane( nPlane, ptP, Tria.GetP( 1), Tria.GetP( 2)) / dLenBC ; if ( dPro > 0 && dPro < dLenBC) return PTT_EDGE ; } if ( fabs( dPosCA) < EPS_SMALL && ( dPosAB * dPosBC) > 0) { // se la proiezione del punto sta sul lato CA double dPro = ProScaInPlane( nPlane, ptP, Tria.GetP( 2), Tria.GetP( 0)) / dLenCA ; if ( dPro > 0 && dPro < dLenCA) return PTT_EDGE ; } // se tre valori con lo stesso segno, sta dentro if ( ( dPosAB > EPS_SMALL && dPosBC > EPS_SMALL && dPosCA > EPS_SMALL) || ( dPosAB < - EPS_SMALL && dPosBC < - EPS_SMALL && dPosCA < - EPS_SMALL)) return PTT_IN ; // deve essere esterno return PTT_OUT ; }