Files
EgtGeomKernel/CDeConeTria.cpp
T
Dario Sassi ddade325c4 EgtGeomKernel 2.6b3 :
- standardizzate le funzione Collision Detection sia per trimesh sia per Zmap (ex Avoid...)
- nelle funzioni Cde ora se arrivano geometrie errate si ritorna collisione (maggior sicurezza).
2024-02-16 08:43:15 +01:00

151 lines
6.1 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 "CDeConeTria.h"
#include "CDeSpheTria.h"
#include "CDeConvexTorusTria.h"
#include "CDeConeFrustumTria.h"
#include "CDeUtility.h"
#include "IntersLineSurfStd.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 ha asse Z coincidente con l'asse del cono e origine nel vertice del cono (punto più basso).
//----------------------------------------------------------------------------
bool
CDeSimpleConeTria( const Frame3d& frCone, double dRad, double dHeight, const Triangle3d& trTria)
{
// Porto il triangolo nel sistema di riferimento del tronco di cono
Triangle3d trMyTria = trTria ;
trMyTria.ToLoc( frCone) ;
// 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( dRad * dLenZ / dHeight, 0., dRad) ;
if ( dLenZ > - EPS_SMALL && dLenZ < dHeight + EPS_SMALL && dLenXY < dRadAtHeight + EPS_SMALL)
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 = SegmentCone( ptSegSt, vtDir, dSegLen, ORIG, Z_AX, dRad, dHeight, dU1, dU2) ;
if ( nIndex != CC_ERROR_INT && nIndex != CC_NO_INTERS)
return true ;
// Collisione con la base
nIndex = SegmentDisc( ptSegSt, vtDir, dSegLen, Point3d( 0., 0., dHeight), Z_AX, dRad, 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 ;
// Piano triangolo
Plane3d plPlaneTria ;
plPlaneTria.Set( ptP, vtN) ;
// Base
Plane3d plBase ;
plBase.Set( Point3d( 0., 0., dHeight), Z_AX) ;
int nBaseTriaIndex = IntersPlanePlane( plPlaneTria, plBase, ptLine, vtLine) ;
if ( nBaseTriaIndex == IPPT_OVERLAPS) {
if ( CoplanarDiscTriangleInterference( plBase.GetPoint(), dRad, trMyTria, TriangleType::CLOSED))
return true ;
return false ;
}
else if ( nBaseTriaIndex == IPPT_YES) {
double dU1, dU2;
if ( LineDisc( ptLine, vtLine, Point3d( 0., 0., dHeight), Z_AX, dRad, dU1, dU2) == D_INFINITE_INT_LINE_ON_PLANE) {
Point3d ptInt, ptInt2 ;
int nLineTriaIndex = IntersLineTria( ptLine + dU1 * vtLine, ptLine + dU2 * vtLine, trMyTria, ptInt, ptInt2) ;
if ( nLineTriaIndex != ILTT_NO && nLineTriaIndex != ILTT_IN)
return true ;
}
}
// Triangolo tangente al cono
Vector3d vtTriaNormXY( vtN.x, vtN.y, 0.) ;
if ( ! vtTriaNormXY.Normalize())
return false ;
Point3d ptContactSt( 0., 0., 0.) ;
Point3d ptContactEn( dRad * vtTriaNormXY.x, dRad * vtTriaNormXY.y, dHeight) ;
Point3d ptInt, ptInt2 ;
int nContactIndex = IntersLineTria( ptContactSt, ptContactEn, trMyTria, ptInt, ptInt2) ;
return ! ( nContactIndex == ILTT_NO || nContactIndex == ILTT_IN) ;
}
//----------------------------------------------------------------------------
bool
CDeConeTria( const Frame3d& frCone, double dRad, double dHeight, const Triangle3d& trTria, double dSafeDist)
{
// Verifico validità del cono
if ( dRad < EPS_SMALL || dHeight < EPS_SMALL)
return false ;
// Se distanza di sicurezza nulla
if ( dSafeDist < EPS_SMALL)
return CDeSimpleConeTria( frCone, dRad, dHeight, trTria) ;
// Verifica preliminare con cono esteso
double dDeltaVert = dSafeDist * sqrt( 1 + ( dHeight * dHeight / ( dRad * dRad))) ;
double dHeightExt = dHeight + dSafeDist + dDeltaVert ;
double dRadExt = dRad * dHeightExt / dHeight ;
Frame3d frTmp = frCone ; frTmp.Translate( -dDeltaVert * frCone.VersZ()) ;
if ( ! CDeSimpleConeTria( frTmp, dRadExt, dHeightExt, trTria))
return false ;
// Sfera nel vertice in basso
if ( CDeSimpleSpheTria( frCone.Orig() + dHeight * frCone.VersZ(), dSafeDist, trTria))
return true ;
// Tronco di cono intermedio
double dHypo = sqrt( dRad * dRad + dHeight * dHeight ) ;
double dDeltaH = dSafeDist * dRad / dHypo ;
double dDeltaR = dSafeDist * dHeight / dHypo ;
frTmp = frCone ; frTmp.Translate( -dDeltaH * frCone.VersZ()) ;
if ( CDeSimpleConeFrustumTria( frTmp, dDeltaR, dRad + dDeltaR, dHeight, trTria))
return true ;
// Toro in alto
frTmp = frCone ; frTmp.Translate( dHeight * frCone.VersZ()) ;
if ( CDeSimpleConvexTorusTria( frTmp, dRad, dSafeDist, CT_TOT, trTria))
return true ;
return false ;
}