//---------------------------------------------------------------------------- // EgalTech 2024-2024 //---------------------------------------------------------------------------- // File : IntersCurveSurfTm.cpp Data : 23.02.24 Versione : 2.6b4 // Contenuto : Implementazione della intersezione curva/superficie trimesh. // // // // Modifiche : 23.02.24 DS Creazione modulo. // // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "GeoConst.h" #include "/EgtDev/Include/EGkIntersLineTria.h" #include "/EgtDev/Include/EGkIntersCurveSurfTm.h" using namespace std ; //---------------------------------------------------------------------------- static void UpdateInfoIntersCurveSurfTm( const Point3d& ptL, const Vector3d& vtDir, double dLen, double dUs, double dUe, int nT, const Triangle3d& Tria, ICSIVECTOR& vInfo) { Point3d ptInt, ptInt2 ; int nRes = IntersLineTria( ptL, vtDir, dLen, Tria, ptInt, ptInt2, true) ; if ( nRes == ILTT_IN || nRes == ILTT_EDGE || nRes == ILTT_VERT) { double dU = dUs + ( ptInt - ptL) * vtDir / dLen * ( dUe - dUs) ; double dCosDN = vtDir * Tria.GetN() ; vInfo.emplace_back( nRes, dU, nT, dCosDN, ptInt) ; } else if ( nRes == ILTT_SEGM || nRes == ILTT_SEGM_ON_EDGE) { double dU = dUs + ( ptInt - ptL) * vtDir / dLen * ( dUe - dUs) ; double dU2 = dUs + ( ptInt2 - ptL) * vtDir / dLen * ( dUe - dUs) ; double dCosDN = vtDir * Tria.GetN() ; vInfo.emplace_back( nRes, dU, dU2, nT, dCosDN, ptInt, ptInt2) ; } } //---------------------------------------------------------------------------- static void OrderInfoIntersCurveSurfTm( ICSIVECTOR& vInfo) { // se non trovati, esco if ( vInfo.size() == 0) return ; // ordino il vettore delle intersezioni secondo il senso crescente del parametro di linea sort( vInfo.begin(), vInfo.end(), []( const IntCrvStmInfo& a, const IntCrvStmInfo& b) { double dUa = ( ( a.nILTT == ILTT_SEGM || a.nILTT == ILTT_SEGM_ON_EDGE) ? ( a.dU + a.dU2) / 2 : a.dU) ; double dUb = ( ( b.nILTT == ILTT_SEGM || b.nILTT == ILTT_SEGM_ON_EDGE) ? ( b.dU + b.dU2) / 2 : b.dU) ; return ( dUa < dUb) ; }) ; } //---------------------------------------------------------------------------- // Intersezione di una curva con una superficie TriMesh //---------------------------------------------------------------------------- bool IntersCurveSurfTm( const ICurve& Curve, const ISurfTriMesh& Stm, double dLinTol, ICSIVECTOR& vInfo) { // verifico i parametri ricevuti if ( & Curve == nullptr || &Stm == nullptr || &vInfo == nullptr) return false ; dLinTol = max( dLinTol, EPS_SMALL) ; vInfo.clear() ; // approssimo la curva con una spezzata PolyLine PL ; if ( ! Curve.ApproxWithLines( dLinTol, ANG_TOL_APPROX_DEG, ICurve::APL_SPECIAL, PL)) return false ; // per ogni segmento dell'approssimante cerco l'intersezione con la superficie double dParS, dParE ; Point3d ptStart, ptEnd ; bool bFound = PL.GetFirstULine( &dParS, &ptStart, &dParE, &ptEnd) ; while ( bFound) { Vector3d vtDir = ptEnd - ptStart ; double dLen = vtDir.Len() ; if ( dLen > EPS_SMALL) { vtDir /= dLen ; // cerco i triangoli intersecati dal segmento const double BOX_STEP = 10 ; int nStep = int( ceil( dLen / BOX_STEP)) ; Vector3d vtStep = dLen / nStep * vtDir ; INTVECTOR vPrevT ; for ( int i = 0 ; i < nStep ; ++ i) { BBox3d b3Box( ptStart + i * vtStep, ptStart + ( i + 1) * vtStep) ; INTVECTOR vT ; if ( Stm.GetAllTriaOverlapBox( b3Box, vT)) { for ( auto nT : vT) { // se triangolo non ancora intersecato if ( find( vPrevT.begin(), vPrevT.end(), nT) == vPrevT.end()) { vPrevT.emplace_back( nT) ; Triangle3d Tria ; Stm.GetTriangle( nT, Tria) ; // aggiorno info con intersezione UpdateInfoIntersCurveSurfTm( ptStart, vtDir, dLen, dParS, dParE, nT, Tria, vInfo) ; } } } } } // passo al segmento successivo bFound = PL.GetNextULine( &dParS, &ptStart, &dParE, &ptEnd) ; } // ordino il vettore delle eventuali intersezioni secondo il senso crescente del parametro di linea OrderInfoIntersCurveSurfTm( vInfo) ; return true ; } //---------------------------------------------------------------------------- bool IntersCurveSurfTmExt( const ICurve& Curve, const ISurfTriMesh& Stm, double dLinTol, INTDBLVECTOR& vInters) { ICSIVECTOR vInfo ; vInters.clear() ; return ( IntersCurveSurfTm( Curve, Stm, dLinTol, vInfo) && FilterCurveSurfTmInters( Curve, vInfo, vInters)) ; } //---------------------------------------------------------------------------- bool FilterCurveSurfTmInters( const ICurve& Curve, const ICSIVECTOR& vInfo, INTDBLVECTOR& vInters) { // verifico i parametri ricevuti if ( & Curve == nullptr || &vInfo == nullptr || &vInters == nullptr) return false ; vInters.clear() ; // info sulla curva bool bClosedCrv = Curve.IsClosed() ; double dParSCrv, dParECrv ; Curve.GetDomain( dParSCrv, dParECrv) ; // ciclo sulle intersezioni for ( const auto& Info : vInfo) { // se intersezione puntuale if ( Info.nILTT == ILTT_VERT || Info.nILTT == ILTT_EDGE || Info.nILTT == ILTT_IN) { int nFlag = CSIT_NONE ; if ( Info.dCosDN > EPS_ZERO) nFlag = CSIT_IN_OUT ; else if ( Info.dCosDN < -EPS_ZERO) nFlag = CSIT_OUT_IN ; vInters.emplace_back( nFlag, Info.dU) ; } // se altrimenti intersezione con coincidenza else if ( Info.nILTT == ILTT_SEGM || Info.nILTT == ILTT_SEGM_ON_EDGE) { vInters.emplace_back( CSIT_IN_ON, Info.dU) ; vInters.emplace_back( CSIT_ON_IN, Info.dU2) ; } } // elimino intersezioni ripetute int nStart = ( bClosedCrv ? 0 : 1) ; for ( int j = nStart ; j < int( vInters.size()) ; ) { // intersezione precedente int i = ( j > 0 ? j - 1 : int( vInters.size()) - 1) ; // se hanno lo stesso parametro if ( abs( vInters[i].second - vInters[j].second) < EPS_PARAM || ( bClosedCrv && abs( vInters[i].second - dParECrv) < EPS_PARAM && abs( vInters[j].second - dParSCrv) < EPS_PARAM)) { // flag per eseguita cancellazione bool bSomeErased = false ; // se sono entrambe entranti o uscenti, elimino la seconda if ( ( vInters[i].first == CSIT_OUT_IN && vInters[j].first == CSIT_OUT_IN) || ( vInters[i].first == CSIT_IN_OUT && vInters[j].first == CSIT_IN_OUT)) { vInters.erase( vInters.begin() + j) ; bSomeErased = true ; } // se una entrante e l'altra uscente, cambio in touch da fuori ed elimino la seconda else if ( vInters[i].first == CSIT_OUT_IN && vInters[j].first == CSIT_IN_OUT) { vInters[i].first = CSIT_OUT_OUT ; vInters.erase( vInters.begin() + j) ; bSomeErased = true ; } // se una uscente e l'altra entrante, cambio in touch da dentro ed elimino la seconda else if ( vInters[i].first == CSIT_IN_OUT && vInters[j].first == CSIT_OUT_IN) { vInters[i].first = CSIT_IN_IN ; vInters.erase( vInters.begin() + j) ; bSomeErased = true ; } // se una touch da fuori o da dentro e l'altra entrante o uscente, elimino la prima else if ( ( vInters[i].first == CSIT_OUT_OUT || vInters[i].first == CSIT_IN_IN) && ( vInters[j].first == CSIT_OUT_IN || vInters[j].first == CSIT_IN_OUT)) { vInters.erase( vInters.begin() + i) ; bSomeErased = true ; } // se una entrante o uscente e l'altra touch da fuori o da dentro, elimino la seconda else if ( ( vInters[i].first == CSIT_OUT_IN || vInters[i].first == CSIT_IN_OUT) && ( vInters[j].first == CSIT_OUT_OUT || vInters[j].first == CSIT_IN_IN)) { vInters.erase( vInters.begin() + j) ; bSomeErased = true ; } // se una puntuale e l'altra inizio di coincidenza, elimino la prima else if ( ( vInters[i].first == CSIT_OUT_IN || vInters[i].first == CSIT_IN_OUT || vInters[i].first == CSIT_NONE) && ( vInters[j].first == CSIT_IN_ON || vInters[j].first == CSIT_OUT_ON)) { vInters[j].first = ( vInters[i].first == CSIT_IN_OUT ? CSIT_IN_ON : CSIT_OUT_ON) ; vInters.erase( vInters.begin() + i) ; bSomeErased = true ; } // se una fine di coincidenza e l'altra puntuale, elimino la seconda else if ( ( vInters[i].first == CSIT_ON_IN || vInters[i].first == CSIT_ON_OUT) && ( vInters[j].first == CSIT_OUT_IN || vInters[j].first == CSIT_IN_OUT || vInters[j].first == CSIT_NONE)) { vInters[i].first = ( vInters[j].first == CSIT_IN_OUT ? CSIT_ON_OUT : CSIT_ON_IN) ; vInters.erase( vInters.begin() + j) ; bSomeErased = true ; } // se una fine di coincidenza e l'altra inizio di coincidenza, elimino entrambe else if ( ( vInters[i].first == CSIT_ON_IN || vInters[i].first == CSIT_ON_OUT) && ( vInters[j].first == CSIT_IN_ON || vInters[j].first == CSIT_OUT_ON)) { vInters.erase( vInters.begin() + j) ; vInters.erase( vInters.begin() + ( j > 0 ? i : i - 1)) ; bSomeErased = true ; } if ( bSomeErased) { if ( j > 0) -- j ; continue ; } } // passo alla successiva ++ j ; } return true ; }