//---------------------------------------------------------------------------- // EgalTech 2015-2015 //---------------------------------------------------------------------------- // File : IntersLinePlane.cpp Data : 18.02.15 Versione : 1.6b7 // 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 "/EgtDev/Include/EGkFrame3d.h" #include "/EgtDev/Include/EGkIntersLineTria.h" #include "/EgtDev/Include/EGkIntersLinePlane.h" //---------------------------------------------------------------------------- static int IntersCoplanarLineTria( const Point3d& ptL, const Vector3d& vtL, double dLen, const Triangle3d& trTria, Point3d& ptInt, Point3d& ptInt2) ; //---------------------------------------------------------------------------- int IntersLineTria( const Point3d& ptL1, const Point3d& ptL2, const Triangle3d& trTria, Point3d& ptInt, Point3d& ptInt2) { 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) ; } //---------------------------------------------------------------------------- int IntersLineTria( const Point3d& ptL, const Vector3d& vtL, double dLen, const Triangle3d& trTria, Point3d& ptInt, Point3d& ptInt2) { // determino il piano del triangolo Plane3d plPlane ; plPlane.vtN = trTria.GetN() ; plPlane.dDist = ( trTria.GetP(0) - ORIG) * plPlane.vtN ; // calcolo l'intersezione tra il segmento di linea e il piano del triangolo int nRes = IntersLinePlane( ptL, vtL, dLen, plPlane, ptInt) ; // 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) ; } } //---------------------------------------------------------------------------- int IntersCoplanarLineTria( const Point3d& ptL, const Vector3d& vtL, double dLen, const Triangle3d& trTria, Point3d& ptInt, Point3d& ptInt2) { // verifico se il segmento è completamente contenuto nel triangolo ptInt = ptL ; ptInt2 = ptL + vtL * dLen ; int nPTT = PointInTria( ptInt, trTria) ; int nPTT2 = PointInTria( ptInt2, trTria) ; if ( nPTT != PTT_OUT && nPTT2 != PTT_OUT) return ILTT_SEGM ; // se segmento nullo, basta verificare la posizione del punto iniziale if ( dLen < EPS_SMALL || vtL.IsSmall()) { switch ( nPTT) { case PTT_OUT : return ILTT_NO ; case PTT_VERT : return ILTT_VERT ; case PTT_EDGE : return ILTT_EDGE ; default : return ILTT_IN ; } } // definisco un riferimento coincidente con il piano del triangolo Frame3d frRef ; if ( ! frRef.Set( trTria.GetP( 0), trTria.GetN(), ( trTria.GetP( 1) - trTria.GetP( 0)))) return ILTT_NO ; // esprimo il triangolo e il segmento in questo riferimento Triangle3d trTriaL = trTria ; trTriaL.ToLoc( frRef) ; Point3d ptLL = ptL ; ptLL.ToLoc( frRef) ; Vector3d vtLL = vtL ; vtLL.ToLoc( frRef) ; // calcolo le intersezioni tra i lati del triangolo e il segmento CurveLine LineLL ; LineLL.Set( ptLL, ptLL + vtLL * dLen) ; int nNumInt = 0 ; IntCrvCrvInfo IntCCI[3] ; for ( int i = 0 ; i < 3 ; ++ i) { CurveLine LineTL ; LineTL.Set( trTriaL.GetP( i), trTriaL.GetP( ( i + 1) % 3)) ; IntersLineLine IntLL( LineLL, LineTL) ; if ( IntLL.GetIntCrvCrvInfo( IntCCI[nNumInt])) ++ nNumInt ; } // se nessuna intersezione if ( nNumInt == 0) return ILTT_NO ; // se una sola intersezione else if ( nNumInt == 1) { // punto di intersezione Point3d ptIntL = IntCCI[0].IciA[0].ptI ; ptInt = ptIntL ; ptInt.ToGlob( frRef) ; // se è l'inizio del segmento ( e il resto del segmento deve essere per forza esterno) if ( AreSamePointApprox( ptIntL, LineLL.GetStart())) return ( ( nPTT == PTT_VERT) ? ILTT_VERT : ILTT_EDGE) ; // se è la fine del segmento ( e il resto del segmento deve essere per forza esterno) else if ( AreSamePointApprox( ptIntL, LineLL.GetEnd())) return ( ( nPTT2 == PTT_VERT) ? ILTT_VERT : ILTT_EDGE) ; // altrimenti è un punto intermedio else { // se l'inizio è nel triangolo if ( nPTT == PTT_IN) { ptInt2 = ptInt ; ptInt = ptL ; } // altrimenti è la fine nel triangolo else ptInt2 = ptL + vtL * dLen ; return ILTT_SEGM ; } } // se 2 intersezioni else if ( nNumInt == 2) { // punti di intersezione Point3d ptIntL = IntCCI[0].IciA[0].ptI ; ptInt = ptIntL ; ptInt.ToGlob( frRef) ; Point3d ptInt2L = IntCCI[1].IciA[0].ptI ; ptInt2 = ptInt2L ; ptInt2.ToGlob( frRef) ; // se coincidono, deve essere un vertice if ( AreSamePointApprox( ptIntL, ptInt2L)) return ILTT_VERT ; // altrimenti è un tratto else { // le ordino secondo il verso positivo della linea if ( ( ptInt - ptL) * vtL > ( ptInt2 - ptL) * vtL) std::swap( ptInt, ptInt2) ; return ILTT_SEGM ; } } // altrimenti 3 intersezioni, una deve coincidere con un lato le altre due sono i suoi vertici else { for ( int i = 0 ; i < 3 ; ++ i) { if ( IntCCI[i].bOverlap) { // punti di intersezione Point3d ptIntL = IntCCI[i].IciA[0].ptI ; ptInt = ptIntL ; ptInt.ToGlob( frRef) ; Point3d ptInt2L = IntCCI[i].IciA[1].ptI ; ptInt2 = ptInt2L ; ptInt2.ToGlob( frRef) ; return ILTT_SEGM_ON_EDGE ; } } } return ILTT_NO ; }