Files
EgtGeomKernel/CDeConeTria.cpp
T
Dario Sassi 50f653750b EgtGeomKernel 2.2k1 :
- aggiunte funzioni per verifica di collisione tra Tronco di Cono e Triangolo e tra Tronco di Piramide Generalizzato e Triangolo
- migliorate funzioni per verifica di collisione tra Tronco di Cono e Zmap e tra Tronco di Piramide Generalizzato e Zmap.
2020-11-06 19:39:00 +00:00

148 lines
6.6 KiB
C++

//----------------------------------------------------------------------------
// EgalTech 2020-2020
//----------------------------------------------------------------------------
// File : CDeConTria.cpp Data : 27.10.20 Versione : 2.2k1
// Contenuto : Implementazione della verifica di collisione tra
// Cono e Triangle3d.
//
//
// Modifiche : 27.10.20 LM Creazione modulo.
//
//
//----------------------------------------------------------------------------
//--------------------------- Include ----------------------------------------
#include "stdafx.h"
#include "IntersLineSurfStd.h"
#include "CDeUtility.h"
#include "EgtDev/Include/EGkCDeConeTria.h"
#include "EgtDev/Include/EGkCDeCylTria.h"
#include "EgtDev/Include/EGkPlane3d.h"
#include "EgtDev/Include/EGkIntersLineTria.h"
#include "EgtDev/Include/EGkIntersPlanePlane.h"
#include "EgtDev/Include/EgtNumUtils.h"
using namespace std ;
//----------------------------------------------------------------------------
// Il sistema di riferimento deve avere l'asse di simmetria del cono come asse Z e origine nel centro della base.
// La distanza di sicurezza ha effetto solo se maggiore di epsilon, altrimenti è ignorata ed è ininfluente.
bool
CDeConeTria( const Frame3d& frCone, double dBaseRad, double dTopRad, double dHeight, double dSafeDist, const Triangle3d& trTria)
{
// Se è un cilindro chiamo la routine apposita.
if ( abs( dBaseRad - dTopRad) < EPS_SMALL)
return CDeCylTria( frCone, dHeight, max( dBaseRad, dTopRad), dSafeDist, trTria) ;
// Se il tronco di cono o il trinagolo non è ben definito non procedo
if ( dBaseRad < EPS_SMALL || dTopRad < EPS_SMALL || dHeight < EPS_SMALL || ! trTria.IsValid())
return false ;
// Se il raggio di base è maggiore del raggio top cambio il sistema di riferimento.
double dMinRad = dBaseRad ;
double dMaxRad = dTopRad ;
Frame3d frMyFrame = frCone ;
if ( dBaseRad > dTopRad) {
swap( dMinRad, dMaxRad) ;
frMyFrame.Translate( dHeight * frMyFrame.VersZ()) ;
frMyFrame.Rotate( frMyFrame.Orig(), frMyFrame.VersX(), 180.) ;
}
// Se la distanza di sicurezza è maggiore di epsilon aumento le dimensioni del tronco di cono.
if ( dSafeDist > EPS_SMALL) {
dBaseRad += dSafeDist ;
dTopRad += dSafeDist ;
dHeight += ( 2 * dSafeDist) ;
frMyFrame.Translate( - dSafeDist * frMyFrame.VersZ()) ;
}
// Porto il triangolo nel sistema di riferimento del tronco di cono
Triangle3d trMyTria = trTria ;
trMyTria.ToLoc( frMyFrame) ;
// Se almeno un vertice collide ho finito
for ( int nV = 0 ; nV < 3 ; ++ nV) {
Point3d ptVert = trMyTria.GetP( nV) ;
double dLenZ = ptVert.z ;
double dLenXY = sqrt( ptVert.x * ptVert.x + ptVert.y * ptVert.y) ;
double dRadAtHeight = Clamp( dMinRad + ( dMaxRad - dMinRad) * dLenZ / dHeight, dMinRad, dMaxRad) ;
if ( dLenZ > - EPS_SMALL && dLenZ < dHeight + EPS_SMALL && dLenXY < dRadAtHeight)
return true ;
}
// Se almeno un segmento collide ho finito
for ( int nS = 0 ; nS < 3 ; ++ nS) {
Point3d ptSegSt = trMyTria.GetP( nS) ;
Point3d ptSegEn = trMyTria.GetP( ( nS + 1) % 3) ;
Vector3d vtDir = ptSegEn - ptSegSt ;
double dSegLen = vtDir.Len() ;
vtDir /= dSegLen ;
double dU1, dU2 ;
// Collisione con la superficie laterale
int nIndex = SegmentTruncatedCone( ptSegSt, vtDir, dSegLen, ORIG, Z_AX, dMinRad, dMaxRad, dHeight, dU1, dU2) ;
if ( nIndex != CC_ERROR_INT && nIndex != CC_NO_INTERS)
return true ;
// Collisione con le basi
nIndex = SegmentDisc( ptSegSt, vtDir, dSegLen, ORIG, -Z_AX, dMinRad, dU1, dU2) ;
if ( nIndex != D_ERROR_INT && nIndex != D_NO_INTERS)
return true ;
nIndex = SegmentDisc( ptSegSt, vtDir, dSegLen, Point3d( 0., 0., dHeight), Z_AX, dMaxRad, dU1, dU2) ;
if ( nIndex != D_ERROR_INT && nIndex != D_NO_INTERS)
return true ;
}
// Contatti con l'interno del triangolo
Point3d ptP = trMyTria.GetP( 0) ;
Vector3d vtN = trMyTria.GetN() ;
// Se il segmento congiungente i centri delle basi interseca il triangolo ho finito
if ( abs( vtN.z) > EPS_ZERO) {
Point3d ptInt( 0., 0., ( ( ptP - ORIG) * vtN) / vtN.z) ;
if ( ptInt.z > - EPS_SMALL && ptInt.z < dHeight + EPS_SMALL && IsPointInsideTriangle( ptInt, trMyTria, TriangleType::CLOSED))
return true ;
}
// Intersezione basi / interno triangolo
Point3d ptLine ;
Vector3d vtLine ;
Plane3d plPlaneTria ;
plPlaneTria.Set( ptP, vtN) ;
// Base minore
Plane3d plMinBase ;
plMinBase.Set( ORIG, - Z_AX) ;
int nMinBaseTriaIndex = IntersPlanePlane( plPlaneTria, plMinBase, ptLine, vtLine) ;
if ( nMinBaseTriaIndex == IPPT_OVERLAPS) {
if ( CoplanarDiscTriangleInterference( plMinBase.GetPoint(), dMinRad, trMyTria, TriangleType::CLOSED))
return true ;
}
else if ( nMinBaseTriaIndex == IPPT_YES) {
double dU1, dU2 ;
if ( LineDisc( ptLine, vtLine, ORIG, -Z_AX, dMinRad, dU1, dU2) == D_INFINITE_INT_LINE_ON_PLANE) {
int nLineTriaIndex = IntersLineTria( ptLine + dU1 * vtLine, ptLine + dU2 * vtLine, trMyTria, Point3d(), Point3d()) ;
if ( nLineTriaIndex != ILTT_NO && nLineTriaIndex != ILTT_IN)
return true ;
}
}
// Base maggiore
Plane3d plMaxBase ;
plMaxBase.Set( Point3d( 0., 0., dHeight), Z_AX) ;
int nMaxBaseTriaIndex = IntersPlanePlane( plPlaneTria, plMaxBase, ptLine, vtLine) ;
if ( nMaxBaseTriaIndex == IPPT_OVERLAPS) {
if ( CoplanarDiscTriangleInterference( plMaxBase.GetPoint(), dMaxRad, trMyTria, TriangleType::CLOSED))
return true ;
}
else if ( nMinBaseTriaIndex == IPPT_YES) {
double dU1, dU2 ;
if ( LineDisc( ptLine, vtLine, ORIG, -Z_AX, dMaxRad, dU1, dU2) == D_INFINITE_INT_LINE_ON_PLANE) {
int nLineTriaIndex = IntersLineTria( ptLine + dU1 * vtLine, ptLine + dU2 * vtLine, trMyTria, Point3d(), Point3d()) ;
if ( nLineTriaIndex != ILTT_NO && nLineTriaIndex != ILTT_IN)
return true ;
}
}
// Tronco di cono tangente al triangolo
Vector3d vtTriaNormXY( vtN.x, vtN.y, 0.) ;
vtTriaNormXY.Normalize() ;
Point3d ptContactSt( dMinRad * vtTriaNormXY.x, dMinRad * vtTriaNormXY.y, 0.) ;
Point3d ptContactEn( dMaxRad * vtTriaNormXY.x, dMaxRad * vtTriaNormXY.y, 0.) ;
int nContactIndex = IntersLineTria( ptContactSt, ptContactEn, trMyTria, Point3d(), Point3d()) ;
return ! ( nContactIndex == ILTT_NO || nContactIndex == ILTT_IN) ;
}