Files
EgtGeomKernel/IntersLineTria.cpp
T
Dario Sassi 07b1f21ecd EgtGeomKernel :
- aggiunta IntersSurfTmSurfTm
- correzioni a HashGrids.
2018-08-30 07:19:29 +00:00

319 lines
10 KiB
C++

//----------------------------------------------------------------------------
// 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 <array>
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<int, 3> 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 ;
}
}
}
}