//---------------------------------------------------------------------------- // EgalTech 2023-2026 //---------------------------------------------------------------------------- // File : ProjectCurveSurfTm.cpp Data : 03.01.26 Versione : 3.1a1 // Contenuto : Implementazione funzioni proiezione curve su superficie Trimesh. // // // // Modifiche : 31.08.23 DS Creazione modulo. // // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "SurfTriMesh.h" #include "SurfBezier.h" #include "GeoConst.h" #include "/EgtDev/Include/EGkDistPointLine.h" #include "/EgtDev/Include/EGkDistPointCurve.h" #include "/EgtDev/Include/EGkDistPointSurfTm.h" #include "/EgtDev/Include/EGkDistPointSurfBz.h" #include "/EgtDev/Include/EGkIntersPlanePlane.h" #include "/EgtDev/Include/EGkIntersLinePlane.h" #include "/EgtDev/Include/EGkIntersLineSurfTm.h" #include "/EgtDev/Include/EGkProjectCurveSurf.h" using namespace std ; //---------------------------------------------------------------------------- // Angolo limite tra normale al triangolo e direzione di proiezione 89° const double COS_ANG_LIM = 0.0175 ; // Angolo massimo tra normali per effettuare bisezione su spigolo const double COS_ANG_MAX_CORNER = 0.8660 ; // Tipologia di punto const int P5AX_TO_DELETE = -1 ; // da cancellare const int P5AX_OUT = 0 ; // aggiunto prima di inizio o dopo fine const int P5AX_STD = 1 ; // standard const int P5AX_CVEX = 2 ; // su angolo convesso const int P5AX_CONC = 3 ; // in angolo concavo const int P5AX_BEFORE_CONC = 4 ; // adiacente ad angolo concavo const int P5AX_AFTER_CONC = 5 ; // adiacente ad angolo concavo //---------------------------------------------------------------------------- static double GetSurfBezierTol( double dLinTol) { return max( dLinTol / 10, EPS_SMALL) ; } //---------------------------------------------------------------------------- static bool PointsInTolerance( const PNT5AXVECTOR& vPt5ax, int nPrec, int nCurr, int nNext, double dSqTol) { for ( int i = nPrec + 1 ; i < nCurr ; ++ i) { double dSqDist ; if ( ! DistPointLine( vPt5ax[i].ptP, vPt5ax[nPrec].ptP, vPt5ax[nNext].ptP).GetSqDist( dSqDist) || dSqDist > dSqTol) return false ; } return true ; } //---------------------------------------------------------------------------- static bool AddPointsOnCorners( PNT5AXVECTOR& vPt5ax) { for ( int i = 1 ; i < ssize( vPt5ax) ; ++ i) { // precedente int j = i - 1 ; // se normali tra corrente e precedente oltre limite e punti abbastanza lontani if ( vPt5ax[i].vtDir1 * vPt5ax[j].vtDir1 < COS_ANG_MAX_CORNER && SqDist( vPt5ax[i].ptP, vPt5ax[j].ptP) > 25 * SQ_EPS_SMALL) { // intersezione tra le due facce Plane3d plPlane1 ; plPlane1.Set( vPt5ax[j].ptP, vPt5ax[j].vtDir1) ; Plane3d plPlane2 ; plPlane2.Set( vPt5ax[i].ptP, vPt5ax[i].vtDir1) ; Point3d ptEdge ; Vector3d vtEdge ; if ( IntersPlanePlane( plPlane1, plPlane2, ptEdge, vtEdge) == IPPT_YES) { Plane3d plPlane3 ; plPlane3.Set(vPt5ax[i].ptP, (vPt5ax[i].ptP - vPt5ax[j].ptP) ^ ( vPt5ax[i].vtDir1 + vPt5ax[j].vtDir1)) ; Point3d ptInt ; if ( IntersLinePlane( ptEdge, vtEdge, 1, plPlane3, ptInt, false) == ILPT_YES) { // verifico se spigolo convesso o concavo bool bConvex ; if ( ! AreSamePointApprox( ptInt, vPt5ax[j].ptP)) bConvex = ( ( vPt5ax[j].vtDir1 ^ ( ptInt - vPt5ax[j].ptP)) * vtEdge > 0) ; else bConvex = (( vPt5ax[i].vtDir1 ^ ( ptInt - vPt5ax[i].ptP)) * vtEdge < 0) ; // se convesso, metto due punti con direzione appena prima e appena dopo if ( bConvex) { Vector3d vtLine1 = ptInt - vPt5ax[j].ptP ; double dLen1 = vtLine1.Len() ; Vector3d vtLine2 = vPt5ax[i].ptP - ptInt ; double dLen2 = vtLine2.Len() ; if ( dLen1 > 2 * EPS_SMALL) { Point5ax Pt5ax ; Pt5ax.ptP = ptInt - vtLine1 / dLen1 * 2 * EPS_SMALL ; Pt5ax.vtDir1 = vPt5ax[j].vtDir1 ; Pt5ax.vtDir2 = vPt5ax[j].vtDir2 ; Pt5ax.vtDirU = vPt5ax[j].vtDirU ; Pt5ax.vtDirV = vPt5ax[j].vtDirV ; Pt5ax.dPar = ( vPt5ax[i].dPar + vPt5ax[j].dPar) / 2 ; Pt5ax.nFlag = P5AX_CVEX ; vPt5ax.insert( vPt5ax.begin() + i, Pt5ax) ; ++ i ; } else vPt5ax[j].nFlag = P5AX_CVEX ; if ( dLen2 > 2 * EPS_SMALL) { Point5ax Pt5ax ; Pt5ax.ptP = ptInt + vtLine2 / dLen2 * 2 * EPS_SMALL ; Pt5ax.vtDir1 = vPt5ax[i].vtDir1 ; Pt5ax.vtDir2 = vPt5ax[i].vtDir2 ; Pt5ax.vtDirU = vPt5ax[i].vtDirU ; Pt5ax.vtDirV = vPt5ax[i].vtDirV ; Pt5ax.dPar = ( vPt5ax[i].dPar + vPt5ax[j].dPar) / 2 ; Pt5ax.nFlag = P5AX_CVEX ; vPt5ax.insert( vPt5ax.begin() + i, Pt5ax) ; ++ i ; } else vPt5ax[i].nFlag = P5AX_CVEX ; } // altrimenti concavo, aggiungo un solo punto con la direzione media else { Point5ax Pt5ax ; Pt5ax.ptP = ptInt ; Pt5ax.vtDir1 = Media( vPt5ax[i].vtDir1, vPt5ax[j].vtDir1) ; Pt5ax.vtDir1.Normalize() ; Pt5ax.vtDir2 = Media( vPt5ax[i].vtDir2, vPt5ax[j].vtDir2) ; Pt5ax.vtDir2.Normalize() ; Pt5ax.vtDirU = Media( vPt5ax[i].vtDirU, vPt5ax[j].vtDirU) ; Pt5ax.vtDirU.Normalize() ; Pt5ax.vtDirV = Media( vPt5ax[i].vtDirV, vPt5ax[j].vtDirV) ; Pt5ax.vtDirV.Normalize() ; Pt5ax.dPar = ( vPt5ax[i].dPar + vPt5ax[j].dPar) / 2 ; Pt5ax.nFlag = P5AX_CONC ; vPt5ax.insert( vPt5ax.begin() + i, Pt5ax) ; ++ i ; } } } } } return true ; } //---------------------------------------------------------------------------- static bool RemovePointsInExcess( PNT5AXVECTOR& vPt5ax, double dLinTol, double dMaxSegmLen, bool bTestDir) { // Parametri di riferimento double dSqMaxLen = dMaxSegmLen * dMaxSegmLen ; double dSqTol = dLinTol * dLinTol ; const double LENREF = 200 ; double dCosAngLim = 1 - dSqTol / ( 2 * LENREF * LENREF) ; // Cerco gli angoli interni e marco opportunamente i punti nelle vicinanze fino ai limiti prima e dopo int nInd = 0 ; while ( nInd < ssize( vPt5ax)) { if ( vPt5ax[nInd].nFlag == P5AX_CONC) { // analizzo i punti appena precedenti int nIpv = nInd - 1 ; while ( nIpv >= 0) { double dSqLen = SqDist( vPt5ax[nInd].ptP, vPt5ax[nIpv].ptP) ; if ( dSqLen < dSqMaxLen) vPt5ax[nIpv].nFlag = P5AX_TO_DELETE ; else { vPt5ax[nIpv].nFlag = P5AX_BEFORE_CONC ; break ; } -- nIpv ; } // analizzo i punti appena successivi int nInx = nInd + 1 ; while ( nInx < ssize( vPt5ax)) { double dSqLen = SqDist( vPt5ax[nInd].ptP, vPt5ax[nInx].ptP) ; if ( dSqLen < dSqMaxLen) vPt5ax[nInx].nFlag = P5AX_TO_DELETE ; else { vPt5ax[nInx].nFlag = P5AX_AFTER_CONC ; break ; } ++ nInx ; } } ++ nInd ; } // Rimuovo i punti allineati entro la tolleranza e non più lontani tra loro del massimo int nCnt = 0 ; int nPrec = 0 ; int nCurr = 1 ; int nNext = 2 ; while ( nNext < ssize( vPt5ax)) { bool bRemove = false ; // lunghezza del segmento che unisce gli adiacenti double dSqLen = SqDist( vPt5ax[nPrec].ptP, vPt5ax[nNext].ptP) ; // se rimovibile (Flag standard) e lunghezza inferiore al massimo, passo agli altri controlli if ( vPt5ax[nCurr].nFlag == P5AX_STD && dSqLen <= dSqMaxLen) { // distanza del punto corrente dal segmento che unisce gli adiacenti DistPointLine dPL( vPt5ax[nCurr].ptP, vPt5ax[nPrec].ptP, vPt5ax[nNext].ptP) ; double dSqDist ; // se distanza inferiore a tolleranza lineare if ( dPL.GetSqDist( dSqDist) && dSqDist < dSqTol && PointsInTolerance( vPt5ax, nPrec, nCurr, nNext, dSqTol)) { // verifico se errore angolare inferiore a limite double dPar ; dPL.GetParamAtMinDistPoint( dPar) ; if ( bTestDir) { Vector3d vtNew = Media( vPt5ax[nPrec].vtDir1, vPt5ax[nNext].vtDir1, dPar) ; if ( vtNew.Normalize() && vtNew * vPt5ax[nCurr].vtDir1 > dCosAngLim) bRemove = true ; } else { Vector3d vtNew = Media( vPt5ax[nPrec].vtDir2, vPt5ax[nNext].vtDir2, dPar) ; if ( vtNew.Normalize() && vtNew * vPt5ax[nCurr].vtDir2 > dCosAngLim) bRemove = true ; } } } // se da eliminare if ( bRemove) { // dichiaro da eliminare il punto vPt5ax[nCurr].nFlag = P5AX_TO_DELETE ; // avanzo con corrente e successivo nCurr = nNext ; ++ nNext ; } // altrimenti da tenere else { // avanzo il terzetto di uno step nPrec = nCurr ; nCurr = nNext ; ++ nNext ; // incremento contatore dei punti conservati ++ nCnt ; } } // Copio i punti da conservare in un vettore temporaneo PNT5AXVECTOR vMyPt5ax ; vMyPt5ax.reserve( nCnt) ; for ( const auto& Pt5ax : vPt5ax) { if ( Pt5ax.nFlag != P5AX_TO_DELETE) vMyPt5ax.emplace_back( Pt5ax) ; } // scambio i due vettori vPt5ax.swap( vMyPt5ax) ; return true ; } //---------------------------------------------------------------------------- static const SurfTriMesh* MyGetAuxSurf( const ISurf* pSrf) { if ( pSrf == nullptr) return nullptr ; switch ( pSrf->GetType()) { case SRF_TRIMESH : return GetBasicSurfTriMesh( pSrf) ; case SRF_FLATRGN : return GetBasicSurfFlatRegion( pSrf)->GetAuxSurf() ; case SRF_BEZIER : return GetBasicSurfBezier( pSrf)->GetAuxSurf() ; default : return nullptr ; } } //---------------------------------------------------------------------------- static bool ProjectPointOnSurf( const Point3d& ptP, const CISURFPVECTOR& vpSurf, double dPar, Point5ax& Pt5ax) { // punto sulle superfici a minima distanza int nSurfMin = -1 ; int nTriaMin = -1 ; double dUMin = -1, dVMin = -1 ; Point3d ptMin ; double dMinDist = NAN ; for ( int i = 0 ; i < ssize( vpSurf) ; ++ i) { // punto sulla superficie a minima distanza int nSrfType = ( vpSurf[i] != nullptr ? vpSurf[i]->GetType() : GEO_NONE) ; if ( nSrfType == SRF_TRIMESH || nSrfType == SRF_FLATRGN) { DistPointSurfTm dPS( ptP, *MyGetAuxSurf( vpSurf[i])) ; double dDist ; if ( dPS.GetDist( dDist) && ( nSurfMin == -1 || dDist < dMinDist)) { nSurfMin = i ; dPS.GetMinDistPoint( ptMin) ; dPS.GetMinDistTriaIndex ( nTriaMin) ; dMinDist = dDist ; } } else if ( nSrfType == SRF_BEZIER) { DistPointSurfBz dPS( ptP, *GetBasicSurfBezier( vpSurf[i])) ; double dDist ; if ( dPS.GetDist( dDist) && ( nSurfMin == -1 || dDist < dMinDist)) { nSurfMin = i ; dPS.GetMinDistPoint( ptMin) ; dPS.GetParamsAtMinDistPoint( dUMin, dVMin) ; dMinDist = dDist ; } } } // se trovato if ( nSurfMin >= 0) { // assegno il punto Point3d ptInt = ptMin ; // calcolo gli altri dati int nSrfType = ( vpSurf[nSurfMin] != nullptr ? vpSurf[nSurfMin]->GetType() : GEO_NONE) ; if ( nSrfType == SRF_TRIMESH || nSrfType == SRF_FLATRGN) { // recupero superficie trimesh const SurfTriMesh* pSurfTm = MyGetAuxSurf( vpSurf[nSurfMin]) ; // calcolo la normale (si calcola smooth, in caso di errore si prende quella del triangolo) Triangle3dEx trTria ; if ( ! pSurfTm->GetTriangle( nTriaMin, trTria)) return false ; Vector3d vtN ; if ( ! CalcNormal( ptMin, trTria, vtN)) vtN = trTria.GetN() ; // assegno valori al punto 5assi Pt5ax.ptP = ptInt ; Pt5ax.vtDir1 = vtN ; Pt5ax.vtDir2 = vtN ; Pt5ax.vtDirU = V_NULL ; Pt5ax.vtDirV = V_NULL ; Pt5ax.dPar = dPar ; Pt5ax.nFlag = P5AX_STD ; } else if ( nSrfType == SRF_BEZIER) { Point3d ptSB ; Vector3d vtN, vtDerU, vtDerV ; if ( ! GetBasicSurfBezier( vpSurf[nSurfMin])->GetPointNrmD1D2( dUMin, dVMin, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptSB, vtN, &vtDerU, &vtDerV)) return false ; vtDerU.Normalize() ; vtDerV.Normalize() ; // assegno valori al punto 5assi Pt5ax.ptP = ptInt ; Pt5ax.vtDir1 = vtN ; Pt5ax.vtDir2 = vtN ; Pt5ax.vtDirU = vtDerU ; Pt5ax.vtDirV = vtDerV ; Pt5ax.dPar = dPar ; Pt5ax.nFlag = P5AX_STD ; } // ritorno con successo return true ; } return false ; } //---------------------------------------------------------------------------- bool ProjectCurveOnSurf( const ICurve& crCrv, const CISURFPVECTOR& vpSurf, double dLinTol, double dMaxSegmLen, bool bSharpEdges, PNT5AXVECTOR& vPt5ax) { // controllo le tolleranze dLinTol = max( dLinTol, LIN_TOL_MIN) ; dMaxSegmLen = max( dMaxSegmLen, 10 * EPS_SMALL) ; // approssimo la curva con una polilinea entro la tolleranza PolyLine PL ; if ( ! crCrv.ApproxWithLines( 10 * EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL) || ! PL.RemoveAlignedPoints( dLinTol, false) ) return false ; const double MAX_SEG_LEN = min( dMaxSegmLen, 0.977) ; if ( ! PL.AdjustForMaxSegmentLen( MAX_SEG_LEN)) return false ; // Pulisco e riservo spazio nel vettore dei punti risultanti vPt5ax.clear() ; vPt5ax.reserve( PL.GetPointNbr()) ; // proietto i punti della polilinea sulla superficie secondo la direzione di minima distanza double dPar ; Point3d ptP ; bool bFound = PL.GetFirstUPoint( &dPar, &ptP) ; while ( bFound) { // se trovo proiezione, la salvo Point5ax Pt5ax ; if ( ProjectPointOnSurf( ptP, vpSurf, dPar, Pt5ax)) vPt5ax.emplace_back( Pt5ax) ; // passo al successivo bFound = PL.GetNextUPoint( &dPar, &ptP) ; } // se richiesto, inserimento punti intermedi in presenza di spigoli if ( bSharpEdges) AddPointsOnCorners( vPt5ax) ; // rimozione punti in eccesso rispetto alle tolleranze RemovePointsInExcess( vPt5ax, dLinTol, dMaxSegmLen, bSharpEdges) ; return true ; } //---------------------------------------------------------------------------- // --- vettore di oggetti intersezione massiva rette parallele SurfTM -------- typedef std::vector INTPARLINESTMPVECTOR ; //---------------------------------------------------------------------------- static bool ProjectPointOnSurf( const Point3d& ptP, const CISRFTMPVECTOR& vpStm, const Frame3d& frRefLine, const INTPARLINESTMPVECTOR& vpIntPLSTM, double dPar, bool bFromVsTo, Point5ax& Pt5ax) { // intersezione retta di proiezione con superfici (conservo l'intersezione più alta) Point3d ptL = GetToLoc( ptP, frRefLine) ; int nInd = -1 ; IntLinStmInfo IntRes ; for ( int i = 0 ; i < ssize( vpIntPLSTM) ; ++ i) { ILSIVECTOR vIntRes ; if ( vpIntPLSTM[i]->GetInters( ptL, 1, vIntRes, false)) { // se dalla direzione if ( bFromVsTo) { // cerco la prima intersezione valida a partire dall'ultima (è la più alta) int nI = ssize( vIntRes) - 1 ; while ( nI >= 0 && abs( vIntRes[nI].dCosDN) < COS_ANG_LIM) --nI ; // se trovata if ( nI >= 0) { if ( nInd < 0) { IntRes = vIntRes[nI] ; nInd = i ; } else { double dUref = (( IntRes.nILTT == ILTT_SEGM || IntRes.nILTT == ILTT_SEGM_ON_EDGE) ? IntRes.dU2 : IntRes.dU) ; double dU = (( vIntRes[nI].nILTT == ILTT_SEGM || vIntRes[nI].nILTT == ILTT_SEGM_ON_EDGE) ? vIntRes[nI].dU2 : vIntRes[nI].dU) ; if ( dU > dUref) { IntRes = vIntRes[nI] ; nInd = i ; } } } } // altrimenti verso la direzione else { // cerco la prima intersezione valida a partire dalla prima (è la più alta) int nI = 0 ; while ( nI < ssize( vIntRes) && abs( vIntRes[nI].dCosDN) < COS_ANG_LIM) ++nI ; // se trovata if ( nI < ssize( vIntRes)) { if ( nInd < 0) { IntRes = vIntRes[nI] ; nInd = i ; } else { double dUref = (( IntRes.nILTT == ILTT_SEGM || IntRes.nILTT == ILTT_SEGM_ON_EDGE) ? IntRes.dU : IntRes.dU2) ; double dU = (( vIntRes[nI].nILTT == ILTT_SEGM || vIntRes[nI].nILTT == ILTT_SEGM_ON_EDGE) ? vIntRes[nI].dU : vIntRes[nI].dU2) ; if ( dU < dUref) { IntRes = vIntRes[nI] ; nInd = i ; } } } } } } // se trovata if ( nInd >= 0) { // calcolo il punto Point3d ptInt ; if ( IntRes.nILTT == ILTT_SEGM || IntRes.nILTT == ILTT_SEGM_ON_EDGE) ptInt = IntRes.ptI2 ; else ptInt = IntRes.ptI ; // calcolo la normale (si calcola smooth, in caso di errore si prende quella del triangolo) Triangle3dEx trTria ; if ( ! vpStm[nInd]->GetTriangle( IntRes.nT, trTria)) return false ; Vector3d vtN ; if ( ! CalcNormal( ptInt, trTria, vtN)) vtN = trTria.GetN() ; // assegno valori al punto 5assi Pt5ax.ptP = ptInt ; Pt5ax.vtDir1 = vtN ; Pt5ax.vtDir2 = frRefLine.VersZ() ; Pt5ax.vtDirU = V_NULL ; Pt5ax.vtDirV = V_NULL ; Pt5ax.dPar = dPar ; Pt5ax.nFlag = P5AX_STD ; // ritorno con successo return true ; } return false ; } //---------------------------------------------------------------------------- bool ProjectCurveOnSurf( const ICurve& crCrv, const CISURFPVECTOR& vpSurf, const Vector3d& vtDir, double dLinTol, double dMaxSegmLen, bool bSharpEdges, bool bFromVsTo, PNT5AXVECTOR& vPt5ax) { // sistemazioni per tipo di superficie CISRFTMPVECTOR vpSurfTm ; for ( int i = 0 ; i < ssize( vpSurf) ; ++ i) { const SurfTriMesh* pSurfTm = nullptr ; switch ( vpSurf[i]->GetType()) { case SRF_TRIMESH : pSurfTm = GetBasicSurfTriMesh( vpSurf[i]) ; break ; case SRF_BEZIER : { double dOldLinTol = GetSurfBezierAuxSurfRefinedTol() ; SetSurfBezierAuxSurfRefinedTol( GetSurfBezierTol( dLinTol)) ; pSurfTm = GetBasicSurfBezier( vpSurf[i])->GetAuxSurfRefined() ; SetSurfBezierAuxSurfRefinedTol( dOldLinTol) ; } break ; case SRF_FLATRGN : pSurfTm = GetBasicSurfFlatRegion( vpSurf[i])->GetAuxSurf() ; break ; default : break ; } if ( pSurfTm == nullptr) return false ; vpSurfTm.emplace_back( pSurfTm) ; } // controllo le tolleranze dLinTol = max( dLinTol, LIN_TOL_MIN) ; dMaxSegmLen = max( dMaxSegmLen, 10 * EPS_SMALL) ; // approssimo la curva con una polilinea entro la tolleranza PolyLine PL ; if ( ! crCrv.ApproxWithLines( 10 * EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL) || ! PL.RemoveAlignedPoints( dLinTol, false) ) return false ; const double MAX_SEG_LEN = min( dMaxSegmLen, 0.977) ; if ( ! PL.AdjustForMaxSegmentLen( MAX_SEG_LEN)) return false ; // Oggetti per calcolo massivo intersezioni tra linee di proiezione e superfici Frame3d frRefLine ; if ( ! frRefLine.Set( ORIG, vtDir)) return false ; INTPARLINESTMPVECTOR vpIntPLSTM ; vpIntPLSTM.reserve( vpSurfTm.size()) ; for ( int i = 0 ; i < ssize( vpSurfTm) ; ++ i) { IntersParLinesSurfTm* pIntPLSTM = new IntersParLinesSurfTm( frRefLine, *vpSurfTm[i]) ; if ( pIntPLSTM == nullptr) { for ( int j = 0 ; j < ssize( vpIntPLSTM) ; ++ j) delete vpIntPLSTM[j] ; return false ; } vpIntPLSTM.emplace_back( pIntPLSTM) ; } // Pulisco e riservo spazio nel vettore dei punti risultanti vPt5ax.clear() ; vPt5ax.reserve( PL.GetPointNbr()) ; // proietto i punti della polilinea sulla superficie double dPar ; Point3d ptP ; bool bFound = PL.GetFirstUPoint( &dPar, &ptP) ; while ( bFound) { // se trovo proiezione, la salvo Point5ax Pt5ax ; if ( ProjectPointOnSurf( ptP, vpSurfTm, frRefLine, vpIntPLSTM, dPar, bFromVsTo, Pt5ax)) vPt5ax.emplace_back( Pt5ax) ; // passo al successivo bFound = PL.GetNextUPoint( &dPar, &ptP) ; } // Libero oggetti per calcolo massivo for ( int i = 0 ; i < ssize( vpIntPLSTM) ; ++ i) delete vpIntPLSTM[i] ; // se richiesto, inserimento punti intermedi in presenza di spigoli if ( bSharpEdges) AddPointsOnCorners( vPt5ax) ; // rimozione punti in eccesso rispetto alle tolleranze RemovePointsInExcess( vPt5ax, dLinTol, dMaxSegmLen, bSharpEdges) ; return true ; } //---------------------------------------------------------------------------- static bool ProjectPointOnSurf( const Point3d& ptP, const CISRFTMPVECTOR& vpStm, const IGeoPoint3d& gpRef, double dPar, bool bFromVsTo, Point5ax& Pt5ax) { // punto di riferimento Point3d ptMin = gpRef.GetPoint() ; // intersezione della retta di minima distanza con le superfici Vector3d vtLine = ptP - ptMin ; double dLineLen = vtLine.Len() ; if ( dLineLen > EPS_SMALL) { vtLine /= dLineLen ; // conservo l'intersezione più alta int nInd = -1 ; IntLinStmInfo IntRes ; for ( int i = 0 ; i < ssize( vpStm) ; ++ i) { ILSIVECTOR vIntRes ; if ( IntersLineSurfTm( ptP, vtLine, dLineLen, *vpStm[i], vIntRes, false)) { // se dal punto if ( bFromVsTo) { // cerco la prima intersezione valida a partire dall'ultima (è la più alta) int nI = ssize( vIntRes) - 1 ; while ( nI >= 0 && abs( vIntRes[nI].dCosDN) < COS_ANG_LIM) --nI ; // se trovata if ( nI >= 0) { if ( nInd < 0) { IntRes = vIntRes[nI] ; nInd = i ; } else { double dUref = (( IntRes.nILTT == ILTT_SEGM || IntRes.nILTT == ILTT_SEGM_ON_EDGE) ? IntRes.dU2 : IntRes.dU) ; double dU = (( vIntRes[nI].nILTT == ILTT_SEGM || vIntRes[nI].nILTT == ILTT_SEGM_ON_EDGE) ? vIntRes[nI].dU2 : vIntRes[nI].dU) ; if ( dU > dUref) { IntRes = vIntRes[nI] ; nInd = i ; } } } } // altrimenti verso il punto else { // cerco la prima intersezione valida a partire dalla prima (è la più alta) int nI = 0 ; while ( nI < ssize( vIntRes) && abs( vIntRes[nI].dCosDN) < COS_ANG_LIM) ++nI ; // se trovata if ( nI < ssize( vIntRes)) { if ( nInd < 0) { IntRes = vIntRes[nI] ; nInd = i ; } else { double dUref = (( IntRes.nILTT == ILTT_SEGM || IntRes.nILTT == ILTT_SEGM_ON_EDGE) ? IntRes.dU : IntRes.dU2) ; double dU = (( vIntRes[nI].nILTT == ILTT_SEGM || vIntRes[nI].nILTT == ILTT_SEGM_ON_EDGE) ? vIntRes[nI].dU : vIntRes[nI].dU2) ; if ( dU < dUref) { IntRes = vIntRes[nI] ; nInd = i ; } } } } } } // se trovata if ( nInd >= 0) { // calcolo il punto Point3d ptInt ; if ( IntRes.nILTT == ILTT_SEGM || IntRes.nILTT == ILTT_SEGM_ON_EDGE) ptInt = IntRes.ptI2 ; else ptInt = IntRes.ptI ; // calcolo la normale (si calcola smooth, in caso di errore si prende quella del triangolo) Triangle3dEx trTria ; if ( ! vpStm[nInd]->GetTriangle( IntRes.nT, trTria)) return false ; Vector3d vtN ; if ( ! CalcNormal( ptInt, trTria, vtN)) vtN = trTria.GetN() ; // assegno valori al punto 5assi Pt5ax.ptP = ptInt ; Pt5ax.vtDir1 = vtN ; Pt5ax.vtDir2 = vtLine ; Pt5ax.vtDirU = V_NULL ; Pt5ax.vtDirV = V_NULL ; Pt5ax.dPar = dPar ; Pt5ax.nFlag = P5AX_STD ; // ritorno con successo return true ; } } return false ; } //---------------------------------------------------------------------------- bool ProjectCurveOnSurf( const ICurve& crCrv, const CISURFPVECTOR& vpSurf, const IGeoPoint3d& gpRef, double dLinTol, double dMaxSegmLen, bool bSharpEdges, bool bFromVsTo, PNT5AXVECTOR& vPt5ax) { // sistemazioni per tipo di superficie CISRFTMPVECTOR vpSurfTm ; for ( int i = 0 ; i < ssize( vpSurf) ; ++ i) { const SurfTriMesh* pSurfTm = nullptr ; switch ( vpSurf[i]->GetType()) { case SRF_TRIMESH : pSurfTm = GetBasicSurfTriMesh( vpSurf[i]) ; break ; case SRF_BEZIER : { double dOldLinTol = GetSurfBezierAuxSurfRefinedTol() ; SetSurfBezierAuxSurfRefinedTol( GetSurfBezierTol( dLinTol)) ; pSurfTm = GetBasicSurfBezier( vpSurf[i])->GetAuxSurfRefined() ; SetSurfBezierAuxSurfRefinedTol( dOldLinTol) ; } break ; case SRF_FLATRGN : pSurfTm = GetBasicSurfFlatRegion( vpSurf[i])->GetAuxSurf() ; break ; default : break ; } if ( pSurfTm == nullptr) return false ; vpSurfTm.emplace_back( pSurfTm) ; } // controllo le tolleranze dLinTol = max( dLinTol, LIN_TOL_MIN) ; dMaxSegmLen = max( dMaxSegmLen, 10 * EPS_SMALL) ; // approssimo la curva con una polilinea entro la tolleranza PolyLine PL ; if ( ! crCrv.ApproxWithLines( 10 * EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL) || ! PL.RemoveAlignedPoints( dLinTol, false) ) return false ; const double MAX_SEG_LEN = min( dMaxSegmLen, 0.977) ; if ( ! PL.AdjustForMaxSegmentLen( MAX_SEG_LEN)) return false ; // Pulisco e riservo spazio nel vettore dei punti risultanti vPt5ax.clear() ; vPt5ax.reserve( PL.GetPointNbr()) ; // proietto i punti della polilinea sulla superficie con direzione data dal punto di riferimento double dPar ; Point3d ptP ; bool bFound = PL.GetFirstUPoint( &dPar, &ptP) ; while ( bFound) { // se trovo proiezione, la salvo Point5ax Pt5ax ; if ( ProjectPointOnSurf( ptP, vpSurfTm, gpRef, dPar, bFromVsTo, Pt5ax)) vPt5ax.emplace_back( Pt5ax) ; // passo al successivo bFound = PL.GetNextUPoint( &dPar, &ptP) ; } // se richiesto, inserimento punti intermedi in presenza di spigoli if ( bSharpEdges) AddPointsOnCorners( vPt5ax) ; // rimozione punti in eccesso rispetto alle tolleranze RemovePointsInExcess( vPt5ax, dLinTol, dMaxSegmLen, bSharpEdges) ; return true ; } //---------------------------------------------------------------------------- static bool ProjectPointOnSurf( const Point3d& ptP, const CISRFTMPVECTOR& vpStm, const ICurve& crRef, double dPar, bool bFromVsTo, Point5ax& Pt5ax) { // punto a minima distanza DistPointCurve dPC( ptP, crRef) ; Point3d ptMin ; int nFlag ; if ( dPC.GetMinDistPoint( 0, ptMin, nFlag)) { // intersezione della retta di minima distanza con le superfici Vector3d vtLine = ptP - ptMin ; double dLineLen = vtLine.Len() ; if ( dLineLen > EPS_SMALL) { vtLine /= dLineLen ; // conservo l'intersezione più alta int nInd = -1 ; IntLinStmInfo IntRes ; for ( int i = 0 ; i < ssize( vpStm) ; ++ i) { ILSIVECTOR vIntRes ; if ( IntersLineSurfTm( ptP, vtLine, dLineLen, *vpStm[i], vIntRes, false)) { // se dalla curva if ( bFromVsTo) { // cerco la prima intersezione valida a partire dall'ultima (è la più alta) int nI = ssize( vIntRes) - 1 ; while ( nI >= 0 && abs( vIntRes[nI].dCosDN) < COS_ANG_LIM) --nI ; // se trovata if ( nI >= 0) { if ( nInd < 0) { IntRes = vIntRes[nI] ; nInd = i ; } else { double dUref = (( IntRes.nILTT == ILTT_SEGM || IntRes.nILTT == ILTT_SEGM_ON_EDGE) ? IntRes.dU2 : IntRes.dU) ; double dU = (( vIntRes[nI].nILTT == ILTT_SEGM || vIntRes[nI].nILTT == ILTT_SEGM_ON_EDGE) ? vIntRes[nI].dU2 : vIntRes[nI].dU) ; if ( dU > dUref) { IntRes = vIntRes[nI] ; nInd = i ; } } } } // altrimenti verso la curva else { // cerco la prima intersezione valida a partire dalla prima (è la più alta) int nI = 0 ; while ( nI < ssize( vIntRes) && abs( vIntRes[nI].dCosDN) < COS_ANG_LIM) ++nI ; // se trovata if ( nI < ssize( vIntRes)) { if ( nInd < 0) { IntRes = vIntRes[nI] ; nInd = i ; } else { double dUref = (( IntRes.nILTT == ILTT_SEGM || IntRes.nILTT == ILTT_SEGM_ON_EDGE) ? IntRes.dU : IntRes.dU2) ; double dU = (( vIntRes[nI].nILTT == ILTT_SEGM || vIntRes[nI].nILTT == ILTT_SEGM_ON_EDGE) ? vIntRes[nI].dU : vIntRes[nI].dU2) ; if ( dU < dUref) { IntRes = vIntRes[nI] ; nInd = i ; } } } } } } // se trovata if ( nInd >= 0) { // assegno il punto Point3d ptInt ; if ( IntRes.nILTT == ILTT_SEGM || IntRes.nILTT == ILTT_SEGM_ON_EDGE) ptInt = IntRes.ptI2 ; else ptInt = IntRes.ptI ; // calcolo la normale (si calcola smooth, in caso di errore si prende quella del triangolo) Triangle3dEx trTria ; if ( ! vpStm[nInd]->GetTriangle( IntRes.nT, trTria)) return false ; Vector3d vtN ; if ( ! CalcNormal( ptInt, trTria, vtN)) vtN = trTria.GetN() ; // assegno valori al punto 5assi Pt5ax.ptP = ptInt ; Pt5ax.vtDir1 = vtN ; Pt5ax.vtDir2 = ( bFromVsTo ? vtLine : -vtLine) ; Pt5ax.vtDirU = V_NULL ; Pt5ax.vtDirV = V_NULL ; Pt5ax.dPar = dPar ; Pt5ax.nFlag = P5AX_STD ; // ritorno con successo return true ; } } } return false ; } //---------------------------------------------------------------------------- bool ProjectCurveOnSurf( const ICurve& crCrv, const CISURFPVECTOR& vpSurf, const ICurve& crRef, double dLinTol, double dMaxSegmLen, bool bSharpEdges, bool bFromVsTo, PNT5AXVECTOR& vPt5ax) { // Sistemazioni per tipo di superficie CISRFTMPVECTOR vpSurfTm ; for ( int i = 0 ; i < ssize( vpSurf) ; ++ i) { const SurfTriMesh* pSurfTm = nullptr ; switch ( vpSurf[i]->GetType()) { case SRF_TRIMESH : pSurfTm = GetBasicSurfTriMesh( vpSurf[i]) ; break ; case SRF_BEZIER : { double dOldLinTol = GetSurfBezierAuxSurfRefinedTol() ; SetSurfBezierAuxSurfRefinedTol( GetSurfBezierTol( dLinTol)) ; pSurfTm = GetBasicSurfBezier( vpSurf[i])->GetAuxSurfRefined() ; SetSurfBezierAuxSurfRefinedTol( dOldLinTol) ; } break ; case SRF_FLATRGN : pSurfTm = GetBasicSurfFlatRegion( vpSurf[i])->GetAuxSurf() ; break ; default : break ; } if ( pSurfTm == nullptr) return false ; vpSurfTm.emplace_back( pSurfTm) ; } // Controllo le tolleranze dLinTol = max( dLinTol, LIN_TOL_MIN) ; dMaxSegmLen = max( dMaxSegmLen, 10 * EPS_SMALL) ; // Approssimo la curva con una polilinea entro la tolleranza PolyLine PL ; if ( ! crCrv.ApproxWithLines( 10 * EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL) || ! PL.RemoveAlignedPoints( dLinTol, false) ) return false ; const double MAX_SEG_LEN = min( dMaxSegmLen, 0.977) ; if ( ! PL.AdjustForMaxSegmentLen( MAX_SEG_LEN)) return false ; // Pulisco e riservo spazio nel vettore dei punti risultanti vPt5ax.clear() ; vPt5ax.reserve( PL.GetPointNbr()) ; // proietto i punti della polilinea sulla superficie con direzione normale alla curva di riferimento double dPar ; Point3d ptP ; bool bFound = PL.GetFirstUPoint( &dPar, &ptP) ; while ( bFound) { // se trovo proiezione, la salvo Point5ax Pt5ax ; if ( ProjectPointOnSurf( ptP, vpSurfTm, crRef, dPar, bFromVsTo, Pt5ax)) vPt5ax.emplace_back( Pt5ax) ; // passo al successivo bFound = PL.GetNextUPoint( &dPar, &ptP) ; } // se richiesto, inserimento punti intermedi in presenza di spigoli if ( bSharpEdges) AddPointsOnCorners( vPt5ax) ; // rimozione punti in eccesso rispetto alle tolleranze RemovePointsInExcess( vPt5ax, dLinTol, dMaxSegmLen, bSharpEdges) ; return true ; } //---------------------------------------------------------------------------- static bool ProjectPointOnSurf( const Point3d& ptP, const CISRFTMPVECTOR& vpStm, const SurfTriMesh& stmRef, double dPar, bool bFromVsTo, Point5ax& Pt5ax) { // punto sulla superficie guida a minima distanza DistPointSurfTm dPS( ptP, stmRef) ; Point3d ptMin ; int nTriaMin ; if ( dPS.GetMinDistPoint( ptMin) && dPS.GetMinDistTriaIndex ( nTriaMin)) { // recupero direzione della retta di minima distanza, altrimenti normale alla superficie Vector3d vtLine = ptP - ptMin ; double dLineLen = vtLine.Len() ; if ( dLineLen > EPS_SMALL) vtLine /= dLineLen ; else { // calcolo la normale della superficie guida Triangle3dEx trGuide ; if ( ! stmRef.GetTriangle( nTriaMin, trGuide)) return false ; if ( ! CalcNormal( ptMin, trGuide, vtLine)) vtLine = trGuide.GetN() ; dLineLen = 100 ; } // intersezione della retta con le superfici (conservo l'intersezione più alta) int nInd = -1 ; IntLinStmInfo IntRes ; for ( int i = 0 ; i < ssize( vpStm) ; ++ i) { ILSIVECTOR vIntRes ; if ( IntersLineSurfTm( ptP, vtLine, dLineLen, *vpStm[i], vIntRes, false)) { // se dalla superficie if ( bFromVsTo) { // cerco la prima intersezione valida a partire dall'ultima (è la più alta) int nI = ssize( vIntRes) - 1 ; while ( nI >= 0 && abs( vIntRes[nI].dCosDN) < COS_ANG_LIM) --nI ; // se trovata if ( nI >= 0) { if ( nInd < 0) { IntRes = vIntRes[nI] ; nInd = i ; } else { double dUref = (( IntRes.nILTT == ILTT_SEGM || IntRes.nILTT == ILTT_SEGM_ON_EDGE) ? IntRes.dU2 : IntRes.dU) ; double dU = (( vIntRes[nI].nILTT == ILTT_SEGM || vIntRes[nI].nILTT == ILTT_SEGM_ON_EDGE) ? vIntRes[nI].dU2 : vIntRes[nI].dU) ; if ( dU > dUref) { IntRes = vIntRes[nI] ; nInd = i ; } } } } // altrimenti verso la superficie else { // cerco la prima intersezione valida a partire dalla prima (è la più alta) int nI = 0 ; while ( nI < ssize( vIntRes) && abs( vIntRes[nI].dCosDN) < COS_ANG_LIM) ++nI ; // se trovata if ( nI < ssize( vIntRes)) { if ( nInd < 0) { IntRes = vIntRes[nI] ; nInd = i ; } else { double dUref = (( IntRes.nILTT == ILTT_SEGM || IntRes.nILTT == ILTT_SEGM_ON_EDGE) ? IntRes.dU : IntRes.dU2) ; double dU = (( vIntRes[nI].nILTT == ILTT_SEGM || vIntRes[nI].nILTT == ILTT_SEGM_ON_EDGE) ? vIntRes[nI].dU : vIntRes[nI].dU2) ; if ( dU < dUref) { IntRes = vIntRes[nI] ; nInd = i ; } } } } } } // se trovata if ( nInd >= 0) { // calcolo il punto Point3d ptInt ; if ( IntRes.nILTT == ILTT_SEGM || IntRes.nILTT == ILTT_SEGM_ON_EDGE) ptInt = IntRes.ptI2 ; else ptInt = IntRes.ptI ; // calcolo la normale (si calcola smooth, in caso di errore si prende quella del triangolo) Triangle3dEx trTria ; if ( ! vpStm[nInd]->GetTriangle( IntRes.nT, trTria)) return false ; Vector3d vtN ; if ( ! CalcNormal( ptMin, trTria, vtN)) vtN = trTria.GetN() ; // calcolo la normale della superficie guida Triangle3dEx trGuide ; if ( ! stmRef.GetTriangle( nTriaMin, trGuide)) return false ; Vector3d vtN2 ; if ( ! CalcNormal( ptMin, trGuide, vtN2)) vtN2 = trGuide.GetN() ; // assegno valori al punto 5assi Pt5ax.ptP = ptInt ; Pt5ax.vtDir1 = vtN ; Pt5ax.vtDir2 = vtN2 ; Pt5ax.vtDirU = V_NULL ; Pt5ax.vtDirV = V_NULL ; Pt5ax.dPar = dPar ; Pt5ax.nFlag = P5AX_STD ; // ritorno con successo return true ; } } return false ; } //---------------------------------------------------------------------------- bool ProjectCurveOnSurf( const ICurve& crCrv, const CISURFPVECTOR& vpSurf, const ISurf& sfRef, double dLinTol, double dMaxSegmLen, bool bSharpEdges, bool bFromVsTo, PNT5AXVECTOR& vPt5ax) { // sistemazioni per tipo di superficie CISRFTMPVECTOR vpSurfTm ; for ( int i = 0 ; i < ssize( vpSurf) ; ++ i) { const SurfTriMesh* pSurfTm = nullptr ; switch ( vpSurf[i]->GetType()) { case SRF_TRIMESH : pSurfTm = GetBasicSurfTriMesh( vpSurf[i]) ; break ; case SRF_BEZIER : { double dOldLinTol = GetSurfBezierAuxSurfRefinedTol() ; SetSurfBezierAuxSurfRefinedTol( GetSurfBezierTol( dLinTol)) ; pSurfTm = GetBasicSurfBezier( vpSurf[i])->GetAuxSurfRefined() ; SetSurfBezierAuxSurfRefinedTol( dOldLinTol) ; } break ; case SRF_FLATRGN : pSurfTm = GetBasicSurfFlatRegion( vpSurf[i])->GetAuxSurf() ; break ; default : break ; } if ( pSurfTm == nullptr) return false ; vpSurfTm.emplace_back( pSurfTm) ; } // sistemazioni per tipo di superficie di riferimento const SurfTriMesh* pRefTm = nullptr ; switch ( sfRef.GetType()) { case SRF_TRIMESH : pRefTm = GetBasicSurfTriMesh( &sfRef) ; break ; case SRF_BEZIER : { double dOldLinTol = GetSurfBezierAuxSurfRefinedTol() ; SetSurfBezierAuxSurfRefinedTol( GetSurfBezierTol( dLinTol)) ; pRefTm = GetBasicSurfBezier( &sfRef)->GetAuxSurfRefined() ; SetSurfBezierAuxSurfRefinedTol( dOldLinTol) ; } break ; case SRF_FLATRGN : pRefTm = GetBasicSurfFlatRegion( &sfRef)->GetAuxSurf() ; break ; default : break ; } if ( pRefTm == nullptr) return false ; // controllo le tolleranze dLinTol = max( dLinTol, LIN_TOL_MIN) ; dMaxSegmLen = max( dMaxSegmLen, 10 * EPS_SMALL) ; // approssimo la curva con una polilinea entro la tolleranza PolyLine PL ; if ( ! crCrv.ApproxWithLines( 10 * EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL) || ! PL.RemoveAlignedPoints( dLinTol, false) ) return false ; const double MAX_SEG_LEN = min( dMaxSegmLen, 0.977) ; if ( ! PL.AdjustForMaxSegmentLen( MAX_SEG_LEN)) return false ; // Pulisco e riservo spazio nel vettore dei punti risultanti vPt5ax.clear() ; vPt5ax.reserve( PL.GetPointNbr()) ; // proietto i punti della polilinea sulla superficie con direzione normale alla curva di riferimento double dPar ; Point3d ptP ; bool bFound = PL.GetFirstUPoint( &dPar, &ptP) ; while ( bFound) { // se trovo proiezione, la salvo Point5ax Pt5ax ; if ( ProjectPointOnSurf( ptP, vpSurfTm, *pRefTm, dPar, bFromVsTo, Pt5ax)) vPt5ax.emplace_back( Pt5ax) ; // passo al successivo bFound = PL.GetNextUPoint( &dPar, &ptP) ; } // se richiesto, inserimento punti intermedi in presenza di spigoli if ( bSharpEdges) AddPointsOnCorners( vPt5ax) ; // rimozione punti in eccesso rispetto alle tolleranze RemovePointsInExcess( vPt5ax, dLinTol, dMaxSegmLen, bSharpEdges) ; return true ; }