Files
EgtGeomKernel/IntersLineTria.cpp
T
Dario Sassi 5bcd4bb67d EgtGeomKernel 1.8j4 :
- aggiunta classe Polygon3d (da EgtExchange)
- razionalizzata classe Plane3d
- corretta funzione IntersLineTria.
2017-10-16 07:56:04 +00:00

201 lines
7.1 KiB
C++

//----------------------------------------------------------------------------
// 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.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) ;
// 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_IN && nPTT2 != PTT_OUT) || ( nPTT != PTT_OUT && nPTT2 == PTT_IN))
return ILTT_SEGM ;
if ( nPTT == PTT_VERT && nPTT2 == PTT_VERT)
return ILTT_SEGM_ON_EDGE ;
if ( ( nPTT == PTT_VERT || nPTT == PTT_EDGE) && ( nPTT2 == PTT_VERT || nPTT2 == PTT_EDGE)) {
Point3d ptMed = Media( ptInt, ptInt2, 0.5) ;
if ( PointInTria( ptMed, trTria) == PTT_IN)
return ILTT_SEGM ;
else
return ILTT_SEGM_ON_EDGE ;
}
// 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) {
ptInt = ptL ;
ptInt2 = ptInt ;
return ILTT_SEGM ;
}
// se altrimenti è la fine nel triangolo
else if ( nPTT2 == PTT_IN) {
ptInt2 = ptL + vtL * dLen ;
return ILTT_SEGM ;
}
// altrimenti entrambi esterni, è un vertice
else
return ILTT_VERT ;
}
}
// 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 ;
}