//---------------------------------------------------------------------------- // EgalTech 2020-2022 //---------------------------------------------------------------------------- // File : IntersLineBox.cpp Data : 08.01.22 Versione : 2.4a3 // Contenuto : Implementazione della intersezione linea/box. // // // // Modifiche : 07.05.20 DS Creazione modulo. // // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "IntersLineBox.h" #include "/EgtDev/Include/EGkIntersLineBox.h" #include "/EgtDev/Include/EgtNumUtils.h" #include using namespace std ; //---------------------------------------------------------------------------- // Linea e box allineato assi devono essere nel medesimo sistema di riferimento. // In caso di intersezione viene restituito true e i parametri lunghezza in dU1 e dU2. //---------------------------------------------------------------------------- bool IntersLineBox( const Point3d& ptL, const Vector3d& vtL, const Point3d& ptMin, const Point3d& ptMax, double& dU1, double& dU2) { // Verifico il versore if ( vtL.IsSmall()) return false ; // Verifico gli estremi del box if ( ptMin.x > ptMax.x + EPS_SMALL || ptMin.y > ptMax.y + EPS_SMALL || ptMin.z > ptMax.z + EPS_SMALL) return false ; // Casi di intersezione impossibile if ( abs( vtL.x) < EPS_ZERO && ( ptL.x < ptMin.x - EPS_SMALL || ptL.x > ptMax.x + EPS_SMALL)) return false ; if ( abs( vtL.y) < EPS_ZERO && ( ptL.y < ptMin.y - EPS_SMALL || ptL.y > ptMax.y + EPS_SMALL)) return false ; if ( abs( vtL.z) < EPS_ZERO && ( ptL.z < ptMin.z - EPS_SMALL || ptL.z > ptMax.z + EPS_SMALL)) return false ; // Parametri degli estremi della retta dU1 = -INFINITO ; dU2 = INFINITO ; // Confronto con piani YZ (perpendicolari ad asse X) if ( vtL.x > EPS_ZERO) { dU1 = max( dU1, ( ptMin.x - ptL.x) / vtL.x) ; dU2 = min( dU2, ( ptMax.x - ptL.x) / vtL.x) ; } else if ( vtL.x < -EPS_ZERO) { dU1 = max( dU1, ( ptMax.x - ptL.x) / vtL.x) ; dU2 = min( dU2, ( ptMin.x - ptL.x) / vtL.x) ; } // Confronto con piani ZX (perpendicolari ad asse Y) if ( vtL.y > EPS_ZERO) { dU1 = max( dU1, ( ptMin.y - ptL.y) / vtL.y) ; dU2 = min( dU2, ( ptMax.y - ptL.y) / vtL.y) ; } else if ( vtL.y < -EPS_ZERO) { dU1 = max( dU1, ( ptMax.y - ptL.y) / vtL.y) ; dU2 = min( dU2, ( ptMin.y - ptL.y) / vtL.y) ; } // Confronto con piani XY (perpendicolari ad asse Z) if ( vtL.z > EPS_ZERO) { dU1 = max( dU1, ( ptMin.z - ptL.z) / vtL.z) ; dU2 = min( dU2, ( ptMax.z - ptL.z) / vtL.z) ; } else if ( vtL.z < -EPS_ZERO){ dU1 = max( dU1, ( ptMax.z - ptL.z) / vtL.z) ; dU2 = min( dU2, ( ptMin.z - ptL.z) / vtL.z) ; } return ( dU2 >= dU1) ; } //---------------------------------------------------------------------------- bool IntersLineBox( const Point3d& ptL1, const Point3d& ptL2, const BBox3d& b3Box, INTDBLVECTOR& vInters, bool bFinite) { Vector3d vtL = ptL2 - ptL1 ; double dLen = vtL.Len() ; if ( dLen > EPS_SMALL) vtL /= dLen ; else vtL = V_NULL ; return IntersLineBox( ptL1, vtL, dLen, b3Box, vInters, bFinite) ; } //---------------------------------------------------------------------------- bool IntersLineBox( const Point3d& ptL, const Vector3d& vtL, double dLen, const BBox3d& b3Box, INTDBLVECTOR& vInters, bool bFinite) { // Recupero i dati del Box Point3d ptMin, ptMax ; if ( ! b3Box.GetMinMax( ptMin, ptMax)) return false ; // Pulisco vettore intersezioni vInters.clear() ; // Eseguo intersezione della linea completa double dU1, dU2 ; bool bInters = IntersLineBox( ptL, vtL, b3Box.GetMin(), b3Box.GetMax(), dU1, dU2) ; // Se non c'รจ intersezione if ( ! bInters || ( bFinite && ( dU1 > dLen + EPS_SMALL || dU2 < -EPS_SMALL))) return true ; // Se le due intersezioni coincidono if ( ( dU2 - dU1) < EPS_SMALL) { double dU = ( dU1 + dU2) / 2 ; if ( ! bFinite) { vInters.emplace_back( ILBT_TOUCH, dU) ; } else { if ( dU > - EPS_SMALL && dU < dLen + EPS_SMALL) vInters.emplace_back( ILBT_TOUCH, Clamp( dU, 0., dLen)) ; } return true ; } // Se sono due intersezioni con la linea giacente su una faccia del box if ( ( abs( vtL.x) < EPS_ZERO && ( abs( ptL.x - ptMin.x) < EPS_SMALL || abs( ptL.x - ptMax.x) < EPS_SMALL)) || ( abs( vtL.y) < EPS_ZERO && ( abs( ptL.y - ptMin.y) < EPS_SMALL || abs( ptL.y - ptMax.y) < EPS_SMALL)) || ( abs( vtL.z) < EPS_ZERO && ( abs( ptL.z - ptMin.z) < EPS_SMALL || abs( ptL.z - ptMax.z) < EPS_SMALL))) { if ( ! bFinite) { vInters.emplace_back( ILBT_TG_INI, dU1) ; vInters.emplace_back( ILBT_TG_FIN, dU2) ; } else { if ( dU1 > dLen - EPS_SMALL) vInters.emplace_back( ILBT_IN, dLen) ; else if ( dU2 < EPS_SMALL) vInters.emplace_back( ILBT_OUT, 0) ; else { if ( dU1 < - EPS_SMALL) vInters.emplace_back( ILBT_TG_INSIDE, 0.) ; else vInters.emplace_back( ILBT_TG_INI, Clamp( dU1, 0., dLen)) ; if ( dU2 > dLen + EPS_SMALL) vInters.emplace_back( ILBT_TG_INSIDE, dLen) ; else vInters.emplace_back( ILBT_TG_FIN, Clamp( dU2, 0., dLen)) ; } } return true ; } // Altrimenti sono due intersezioni con attraversamento if ( ! bFinite) { vInters.emplace_back( ILBT_IN, dU1) ; vInters.emplace_back( ILBT_OUT, dU2) ; } else { if ( dU1 > dLen - EPS_SMALL) vInters.emplace_back( ILBT_IN, dLen) ; else if ( dU2 < EPS_SMALL) vInters.emplace_back( ILBT_OUT, 0) ; else { if ( dU1 < - EPS_SMALL) vInters.emplace_back( ILBT_INSIDE, 0.) ; else vInters.emplace_back( ILBT_IN, Clamp( dU1, 0., dLen)) ; if ( dU2 > dLen + EPS_SMALL) vInters.emplace_back( ILBT_INSIDE, dLen) ; else vInters.emplace_back( ILBT_OUT, Clamp( dU2, 0., dLen)) ; } } return true ; }