//---------------------------------------------------------------------------- // EgalTech 2015-2017 //---------------------------------------------------------------------------- // File : IntersLineTria.cpp Data : 16.10.17 Versione : 1.8j4 // Contenuto : Implementazione della intersezione linea/triangolo. // // // // Modifiche : 18.02.15 DS Creazione modulo. // // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "ProjPlane.h" #include "CurveLine.h" #include "IntersLineLine.h" #include "IntersLineTria.h" #include "/EgtDev/Include/EGkIntersLinePlane.h" #include "/EgtDev/Include/EGkFrame3d.h" #include using namespace std ; //---------------------------------------------------------------------------- int IntersLineTria( const Point3d& ptL1, const Point3d& ptL2, const Triangle3d& trTria, Point3d& ptInt, Point3d& ptInt2, bool bFinite) { Vector3d vtL = ptL2 - ptL1 ; double dLen = vtL.Len() ; if ( dLen > EPS_SMALL) vtL /= dLen ; else vtL = V_NULL ; return IntersLineTria( ptL1, vtL, dLen, trTria, ptInt, ptInt2, bFinite) ; } //---------------------------------------------------------------------------- int IntersLineTria( const Point3d& ptL, const Vector3d& vtL, double dLen, const Triangle3d& trTria, Point3d& ptInt, Point3d& ptInt2, bool bFinite) { // determino il piano del triangolo Plane3d plPlane ; plPlane.Set( trTria.GetP( 0), trTria.GetN()) ; // calcolo l'intersezione tra il segmento di linea e il piano del triangolo int nRes = IntersLinePlane( ptL, vtL, dLen, plPlane, ptInt, bFinite) ; // se non c'è intersezione if ( nRes == ILPT_NO) return ILTT_NO ; // se c'è una intersezione else if ( nRes == ILPT_START || nRes == ILPT_END || nRes == ILPT_YES) { int nPTT = PointInTria( ptInt, trTria) ; switch ( nPTT) { case PTT_OUT : return ILTT_NO ; case PTT_VERT : return ILTT_VERT ; case PTT_EDGE : return ILTT_EDGE ; default : return ILTT_IN ; } } // se la linea giace nel piano del triangolo else { return IntersCoplanarLineTria( ptL, vtL, dLen, trTria, ptInt, ptInt2, bFinite) ; } } //---------------------------------------------------------------------------- int IntersCoplanarLineTria( const Point3d& ptL, const Vector3d& vtL, double dLen, const Triangle3d& trTria, Point3d& ptInt, Point3d& ptInt2, bool bFinite) { // Normale alla linea giacente nel piano Vector3d vtN = vtL ^ trTria.GetN() ; vtN.Normalize() ; // calcolo le distanze dei vertici del triangolo dalla retta array< double, 3> vDist ; for ( int i = 0 ; i < 3 ; ++i) vDist[i] = ( trTria.GetP( i) - ptL) * vtN ; // verifico posizione del triangolo rispetto alla retta array vPos = { 0, 0, 0} ; int nVertPos = 0 ; int nVertNeg = 0 ; for ( int i = 0 ; i < 3 ; ++i) { if ( vDist[i] > EPS_SMALL) { vPos[i] = 1 ; ++ nVertPos ; } else if ( vDist[i] < -EPS_SMALL) { vPos[i] = -1 ; ++ nVertNeg ; } } // Se il triangolo giace tutto da una parte della retta, nessuna intersezione if ( nVertPos == 3 || nVertNeg == 3) { return ILTT_NO ; } // Se altrimenti il triangolo giace sulla retta (triangolo schiacciato), sovrapposizione else if ( nVertPos == 0 && nVertNeg == 0) { // Determino i vertici estremi sulla retta double dUmin = ( trTria.GetP( 0) - ptL) * vtL ; double dUmax = ( trTria.GetP( 1) - ptL) * vtL ; ptInt = trTria.GetP( 0) ; ptInt2 = trTria.GetP( 1) ; if ( dUmin > dUmax) { swap( dUmin, dUmax) ; swap( ptInt, ptInt2) ; } double dU2 = ( trTria.GetP( 2) - ptL) * vtL ; if ( dU2 < dUmin) ptInt = trTria.GetP( 2) ; else if ( dU2 > dUmax) ptInt2 = trTria.GetP( 2) ; // Se linea infinita if ( ! bFinite) { return ILTT_SEGM_ON_EDGE ; } // Altrimenti linea finita else { // se massimo coincide con inizio segmento di retta if ( abs( dUmax) < EPS_SMALL) { ptInt = ptInt2 ; return ILTT_VERT ; } // se minimo coincide con fine segmento di retta else if ( abs ( dUmin - dLen) < EPS_SMALL) { return ILTT_VERT ; } // se segmento non si sovrappone else if ( dUmax < 0 || dUmin > dLen) { return ILTT_NO ; } // altrimenti sovrapposizione parziale else { if ( dUmin < 0) ptInt = ptL ; if ( dUmax > dLen) ptInt2 = ptL + vtL * dLen ; return ILTT_SEGM_ON_EDGE ; } } } // se altrimenti due vertici del triangolo giacciono sulla linea else if ( nVertPos + nVertNeg == 1) { // Determino i vertici sulla linea int nCount = 0 ; for ( int i = 0 ; i < 3 ; ++i) { if ( vPos[i] == 0) { if ( nCount == 0) ptInt = trTria.GetP( i) ; else ptInt2 = trTria.GetP( i) ; nCount ++ ; } } // Ordino i vertici sulla linea double dUmin = ( ptInt - ptL) * vtL ; double dUmax = ( ptInt2 - ptL) * vtL ; if ( dUmin > dUmax) { swap( dUmin, dUmax) ; swap( ptInt, ptInt2) ; } // Se linea infinita if ( ! bFinite) { return ILTT_SEGM_ON_EDGE ; } // Altrimenti linea finita else { // se massimo coincide con inizio segmento di retta if ( abs( dUmax) < EPS_SMALL) { ptInt = ptInt2 ; return ILTT_VERT ; } // se minimo coincide con fine segmento di retta else if ( abs ( dUmin - dLen) < EPS_SMALL) { return ILTT_VERT ; } // se segmento non si sovrappone else if ( dUmax < 0 || dUmin > dLen) { return ILTT_NO ; } // altrimenti sovrapposizione parziale else { if ( dUmin < 0) ptInt = ptL ; if ( dUmax > dLen) ptInt2 = ptL + vtL * dLen ; return ILTT_SEGM_ON_EDGE ; } } } // se altrimenti un vertice del triangolo giace sulla retta e gli altri due sono dalla stessa parte else if ( ( nVertPos == 2 && nVertNeg == 0) || ( nVertPos == 0 && nVertNeg == 2)) { // Determino quale è il vertice sulla linea for ( int i = 0 ; i < 3 ; ++i) { if ( vPos[i] == 0) { ptInt = trTria.GetP( i) ; break ; } } // Se linea infinita if ( ! bFinite) { return ILTT_VERT ; } // Altrimenti linea finita else { // devo verificare che il vertice stia sul segmento double dU = ( ptInt - ptL) * vtL ; if ( dU < -EPS_SMALL || dU > dLen + EPS_SMALL) return ILTT_NO ; else return ILTT_VERT ; } } // se altrimenti un vertice del triangolo giace sulla retta e gli altri due sono da parti opposte else if ( nVertPos == 1 && nVertNeg == 1) { // Determino il vertice sulla linea e gli altri due da interpolare int nP, nM ; for ( int i = 0 ; i < 3 ; ++i) { if ( vPos[i] == 0) ptInt = trTria.GetP( i) ; else if ( vPos[i] > 0) nP = i ; else nM = i ; } // Calcolo l'intersezione con la linea double dCoeff = abs( vDist[nP]) / ( abs( vDist[nP]) + abs( vDist[nM])) ; ptInt2 = Media( trTria.GetP( nP), trTria.GetP( nM), dCoeff) ; // Ordino i vertici sulla linea double dUmin = ( ptInt - ptL) * vtL ; double dUmax = ( ptInt2 - ptL) * vtL ; if ( dUmin > dUmax) { swap( dUmin, dUmax) ; swap( ptInt, ptInt2) ; } // Se linea infinita if ( ! bFinite) { return ILTT_SEGM ; } // Altrimenti linea finita else { // se massimo coincide con inizio segmento di retta if ( abs( dUmax) < EPS_SMALL) { ptInt = ptInt2 ; return ILTT_EDGE ; } // se minimo coincide con fine segmento di retta else if ( abs ( dUmin - dLen) < EPS_SMALL) { return ILTT_EDGE ; } // se segmento non si sovrappone else if ( dUmax < 0 || dUmin > dLen) { return ILTT_NO ; } // altrimenti sovrapposizione parziale else { if ( dUmin < 0) ptInt = ptL ; if ( dUmax > dLen) ptInt2 = ptL + vtL * dLen ; return ILTT_SEGM ; } } } // altrimenti due vertici giacciono da una parte e uno da quella opposta else { // Determino le intersezioni int nCount = 0 ; for ( int i = 0 ; i < 3 ; ++ i) { int j = ( i + 1) % 3 ; if ( vPos[i] != vPos[j]) { double dCoeff = abs( vDist[i]) / ( abs( vDist[i]) + abs( vDist[j])) ; ( nCount == 0 ? ptInt : ptInt2) = Media( trTria.GetP( i), trTria.GetP( j), dCoeff) ; ++ nCount ; } } // Ordino i vertici sulla linea double dUmin = ( ptInt - ptL) * vtL ; double dUmax = ( ptInt2 - ptL) * vtL ; if ( dUmin > dUmax) { swap( dUmin, dUmax) ; swap( ptInt, ptInt2) ; } // Se linea infinita if ( ! bFinite) { return ILTT_SEGM ; } // Altrimenti linea finita else { // se massimo coincide con inizio segmento di retta if ( abs( dUmax) < EPS_SMALL) { ptInt = ptInt2 ; return ILTT_EDGE ; } // se minimo coincide con fine segmento di retta else if ( abs ( dUmin - dLen) < EPS_SMALL) { return ILTT_EDGE ; } // se segmento non si sovrappone else if ( dUmax < 0 || dUmin > dLen) { return ILTT_NO ; } // altrimenti sovrapposizione parziale else { if ( dUmin < 0) ptInt = ptL ; if ( dUmax > dLen) ptInt2 = ptL + vtL * dLen ; return ILTT_SEGM ; } } } }