diff --git a/SurfFinishing.cpp b/SurfFinishing.cpp index 2e59023..4ecd6e0 100644 --- a/SurfFinishing.cpp +++ b/SurfFinishing.cpp @@ -41,6 +41,9 @@ #include "/EgtDev/Include/EGkCurveAux.h" #include "/EgtDev/Include/EGkDistPointCurve.h" #include "/EgtDev/Include/EGkDistPointSurfFr.h" +#include "/EgtDev/Include/EGkStmFromTriangleSoup.h" +#include +#include // per far dimenticare macro di WinUser.h #undef GetClassName @@ -74,6 +77,7 @@ using namespace std ; // 3125 = "Error in SurfFinishing : CalcPocketing failed" // 3126 = "Error in SurfFinishing : Computing ZConst Curves failed" // 3127 = "Error in SurfFinishing : Computing ZConst Paths failed" +// 3128 = "Error in SurfFinishing : Curves with different extrusion" // 3151 = "Warning in SurfFinishing : Skipped entity (xx)" // 3152 = "Warning in SurfFinishing : No machinable path" // 3153 = "Warning in SurfFinishing : Tool name changed (xx)" @@ -1012,6 +1016,7 @@ SurfFinishing::Chain( int nGrpDestId) } } // preparo i dati per il concatenamento + Vector3d vtExtr = Z_AX ; bool bFirst = true ; Point3d ptNear = ORIG ; double dToler = 10 * EPS_SMALL ; @@ -1032,9 +1037,18 @@ SurfFinishing::Chain( int nGrpDestId) return false ; // se prima curva, assegno inizio della ricerca if ( bFirst) { + pCrv->GetExtrusion( vtExtr) ; ptNear = ptStart + 10 * EPS_SMALL * vtStart ; bFirst = false ; } + // altrimenti + else { + Vector3d vtTmpExtr ; pCrv->GetExtrusion( vtTmpExtr) ; + if ( ! AreSameVectorApprox( vtTmpExtr, vtExtr)) { + m_pMchMgr->SetLastError( 3128, "Error in SurfFinishing : Curves with different extrusion") ; + return false ; + } + } } // recupero i percorsi concatenati e definisco la regione piana di svuotatura SurfFlatRegionByContours SfrByC ; @@ -1108,6 +1122,9 @@ SurfFinishing::Chain( int nGrpDestId) int nGroupName = -1 ; PtrOwner pSfrCurr( SfrByC.GetSurf()) ; while ( ! IsNull( pSfrCurr) && pSfrCurr->IsValid()) { + // la normale del Chunk deve essere coerente con l'estrusione ricavata + if ( AreOppositeVectorApprox( pSfrCurr->GetNormVersor(), vtExtr)) + pSfrCurr->Invert() ; // per ogni Chunk for ( int nC = 0 ; nC < pSfrCurr->GetChunkCount() ; ++ nC) { // creo nuovo gruppo @@ -1129,7 +1146,7 @@ SurfFinishing::Chain( int nGrpDestId) PtrOwner pCrvLoop( ConvertCurveToComposite( pSfrChunk->GetLoop( 0, nL))) ; if ( IsNull( pCrvLoop) || ! pCrvLoop->IsValid()) return false ; - // memorizzo le propriet� di lato aperto nelle Info del gruppo + // memorizzo le proprietà di lato aperto nelle Info del gruppo INTVECTOR vIndOpen ; for ( int nU = 0 ; nU < pCrvLoop->GetCurveCount() ; ++ nU) { int nTmpProp0 = TEMP_PROP_INVALID ; @@ -1140,8 +1157,6 @@ SurfFinishing::Chain( int nGrpDestId) if ( nL == 0) { double dThick = pCrvLoop->GetTempParam( 1) ; m_pGeomDB->SetInfo( nNewId, KEY_THICK, dThick) ; - Vector3d vtExtr ; - pCrvLoop->GetExtrusion( vtExtr) ; m_pGeomDB->SetInfo( nNewId, KEY_EXTR, vtExtr) ; } } @@ -1323,9 +1338,11 @@ SurfFinishing::ProcessPath( int nPathId, int nPvId, int nClId) } // se richiesto, elimino le parti al massimo affondamento - if ( bSkipMaxDown && ( m_Params.m_nSubType != SURFFIN_SUB_Z_CONST)) { + if ( bSkipMaxDown && + ( m_Params.m_nSubType != SURFFIN_SUB_Z_CONST && + m_Params.m_nSubType != SURFFIN_SUB_OPTIMAL)) { // calcolo silhouette dell'insieme di superfici - CISURFTMPVECTOR vpStm ; vpStm.reserve( vSurfId.size()) ; + CISURFTMPVECTOR vpStm ; vpStm.reserve( vSurfId.size()) ; for ( int i = 0 ; i < int( vSrfLoc.size()) ; ++ i) vpStm.emplace_back( GetSurfTriMesh( vSrfLoc[i].Get())) ; Frame3d frPocket ; @@ -1378,7 +1395,7 @@ SurfFinishing::ProcessPath( int nPathId, int nPvId, int nClId) pSfrCnt->Clear() ; pSfrCnt->AddExtLoop( *pCompo) ; } - // azzero le propriet� delle curve semplici dei contorni delle regioni ( se 1 lato aperto) + // azzero le proprietà delle curve semplici dei contorni delle regioni ( se 1 lato aperto) for ( int nC = 0 ; nC < pSfrCnt->GetChunkCount() ; ++ nC) { for ( int nL = 0 ; nL < pSfrCnt->GetLoopCount( nC) ; ++ nL) { for ( int nCrv = 0 ; ; ++ nCrv) { @@ -1423,10 +1440,13 @@ SurfFinishing::ProcessPath( int nPathId, int nPvId, int nClId) return false ; break ; case SURFFIN_SUB_Z_CONST : - case SURFFIN_SUB_OPTIMAL : if ( ! AddZConst( pCAvTlStm, vSrfLoc, frSurf, pSfrCnt, vtTool, dDepth, dElev, bSplitArcs)) return false ; break ; + case SURFFIN_SUB_OPTIMAL : + if ( ! AddOptimal( pCAvTlStm, vSrfLoc, frSurf, pSfrCnt, vtTool, dDepth, dElev, bSplitArcs)) + return false ; + break ; } } @@ -2421,7 +2441,7 @@ SurfFinishing::CreateZConstPaths( ICAvToolSurfTm* pCAvTlStm, const SURFLOCALVECT for ( ; nCurrRow < int( vCrvCompo.size()) - 1 ; ++ nCurrRow) { // scorro sulle colonne for ( int nCurrCol = 0 ; nCurrCol < int( vCrvCompo[nCurrRow].size()) ; ++ nCurrCol) { - // se la curva attuale � nulla, passo alla successiva + // se la curva attuale è nulla, passo alla successiva if ( vCrvCompo[nCurrRow][nCurrCol] == nullptr) continue ; // recupero il punto finale della curva corrente @@ -2477,8 +2497,8 @@ SurfFinishing::CreateZConstPaths( ICAvToolSurfTm* pCAvTlStm, const SURFLOCALVECT } } } - // se la curva risulta troppo distante o non ho trovato nessuna colonna valida - if ( /*dMinSqDist > m_Params.m_dSideStep * m_Params.m_dSideStep * 1000 ||*/ nNextCol_path == -1) { + // se non ho trovato nessuna colonna valida (potrei controllare anche la distanza...) + if ( nNextCol_path == -1) { nCurrRow = 0 ; // azzero il contatore delle righe break ; // interrompo ciclo sulle righe successive di ricerca } @@ -2570,8 +2590,9 @@ SurfFinishing::CreateZConstPaths( ICAvToolSurfTm* pCAvTlStm, const SURFLOCALVECT if ( ! pCompoLink->IsValid()) return false ; - // porto il link sulla curva attuale di silhouette e lo proietto sulla pStm - pCompoLink->Translate( vtTool * dSfrDistCurr) ; + // porto il link sulla curva attuale di silhouette e lo proietto sulla pStm (sono in locale) + double dSfrDistNext = vCrvCompo[nNextRow][nNextCol_path]->GetTempParam( 0) ; + pCompoLink->Translate( Z_AX * min( dSfrDistCurr, dSfrDistNext)) ; #if ENABLE_ZCONST_DEBUG int _d = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCompoLink->Clone()) ; @@ -2885,12 +2906,830 @@ SurfFinishing::AddZConst( ICAvToolSurfTm* pCAvTlStm, const SURFLOCALVECTOR& vSrf return true ; } +//---------------------------------------------------------------------------- +bool +SurfFinishing::ApproxSilhouetteClosedPLForOptimal( PolyLine& PL, double dSampleTol, double dMaxLinTol, double dAngTol, double dLinFeaTol, + ICurveComposite* pCompoPL) +{ + /* approssimazione di una polyline di Silhouette per rimuovere Spikes di proiezione */ + // controllo dei parametri + if ( pCompoPL == nullptr) + return false ; + pCompoPL->Clear() ; + // se aperta errore + Plane3d plPL ; + double dArea ; + if ( ! PL.IsClosedAndFlat( plPL, dArea)) + return false ; + // semplifico rimuovendo i punti allineati + PL.RemoveAlignedPoints( dSampleTol + 10 * EPS_SMALL) ; + // essendo chiusa, se presenti meno di 4 punti, non faccio nulla + int nPts = PL.GetPointNbr() ; + if ( nPts < 4) + return true ; + // porto la PolyLine nel frame LocaleXY + Frame3d frLoc ; + if ( ! frLoc.Set( plPL.GetPoint(), plPL.GetVersN())) + return false ; + PL.ToLoc( frLoc) ; + + // --------------------------- scelta del punto iniziale ------------------------------ + + // creo un vettore contenente tutti i punti ( cerco nel mentre il segmento più lungo) + PNTVECTOR vPt ; vPt.reserve( nPts) ; + int nLongEdge = -1 ; + double dMaxSqLen = 0. ; + Point3d myPt ; + if ( ! PL.GetFirstPoint( myPt)) + return false ; + vPt.emplace_back( myPt) ; + while ( PL.GetNextPoint( myPt)) { + double dCurrSqDist = SqDist( vPt.back(), myPt) ; + if ( dCurrSqDist > dMaxSqLen) { + dMaxSqLen = dCurrSqDist ; + nLongEdge = int( vPt.size()) - 1 ; + } + vPt.emplace_back( myPt) ; + } + if ( nLongEdge < 0 || nLongEdge > nPts - 2) + return false ; + // calcolo il punto iniziale come punto medio del segmento più lungo + Point3d ptStart = Media( vPt[nLongEdge], vPt[nLongEdge + 1]) ; + ChangePolyLineStart( PL, ptStart, 10 * EPS_SMALL) ; + nPts = PL.GetPointNbr() ; + + // ---------------------- modifica dei punti Spike --------------------------------- + + // creo un vettore di punti a partire dai punti della PolyLine + PNTVECTOR vPts ; vPts.reserve( nPts) ; + PL.GetFirstPoint( myPt) ; + vPts.emplace_back( myPt) ; + while ( PL.GetNextPoint( myPt)) + vPts.emplace_back( myPt) ; + + /*ICurveComposite* pCrvOrig = CreateCurveComposite() ; + for ( int i = 0 ; i < int( vPts.size()) ; ++ i) { + if ( i == 0) + pCrvOrig->AddPoint( vPts[i]) ; + else + pCrvOrig->AddLine( vPts[i]) ; + IGeoPoint3d* pt = CreateGeoPoint3d() ; + pt->Set( vPts[i]) ; + int a = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pt->Clone()) ; + m_pGeomDB->SetMaterial( a, WHITE) ; + } + pCrvOrig->Close() ; + int a = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCrvOrig->Clone()) ; + m_pGeomDB->SetMaterial( a, GREEN) ; + LOG_ERROR( GetEMkLogger(), ("Samp tol -> " + to_string( dSampleTol)).c_str()) ; + LOG_ERROR( GetEMkLogger(), ("Lin tol ( 2*dMaxRad) -> " + to_string( dMaxLinTol)).c_str()) ; + LOG_ERROR( GetEMkLogger(), ("Ang tol -> " + to_string( dAngTol)).c_str()) ;*/ + + // dichiaro i versori tangenti consecutivi per il percorso della PolyLinea + Vector3d vtTanPrev, vtTan, vtTanAfter ; + // recupero il cosendo della tolleranza angolare + double dCosAngTol = abs( cos( dAngTol * DEGTORAD)) ; + // calcolo il quadrato della tolleranza lineare + double dSqMaxLinTol = dMaxLinTol * dMaxLinTol ; + // ciclo tutti i punti della PolyLine + for ( int i = 2 ; i < int( vPts.size()) - 1 ; ++ i) { + // se distanza tra punto attuale e precedente sopra al tolleranza, passo ai successivi + if ( SqDist( vPts[i], vPts[i-1]) > dSqMaxLinTol) + continue ; + // calcolo il versore tangente del segmento pecedente + vtTanPrev = vPts[i-1] - vPts[i-2] ; + vtTanPrev.Normalize() ; + // calcolo versore tangente attuale + vtTan = vPts[i] - vPts[i-1] ; + vtTan.Normalize() ; + // recupero la direzione successia + vtTanAfter = vPts[i+1] - vPts[i] ; + vtTanAfter.Normalize() ; + // controllo se l'angolo tra la direzione attuale e precedente supera la tolleranza + if ( abs( vtTanPrev * vtTan) > dCosAngTol && abs( vtTan * vtTanAfter) > dCosAngTol) + continue ; // se uno dei due sotto la tolleranza, analizzo segmento successivo + // se Spike individuato, modifico il punto corrente con il punto medio del segmento attuale + vPts[i] = Media( vPts[i], vPts[i-1]) ; + /*IGeoPoint3d* pt = CreateGeoPoint3d() ; + pt->Set( vPts[i]) ; + int a = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pt->Clone()) ; + m_pGeomDB->SetMaterial( a, YELLOW) ;*/ + // il punto precedente diventa uguale all' i-2-esimo + vPts[i-1] = vPts[i-2] ; + } + + // a partire da questi punti, creo la PolyLine + double dPar = -1 ; + PolyLine myPL ; + myPL.AddUPoint( ++ dPar, vPts[0]) ; // il primo punto è automaticamente inserito + Point3d myLastPtInPL = vPts[0] ; + for ( int i = 1 ; i < int( vPts.size()) ; ++ i) { + // se il punto corrente è già inserito nella PolyLine, passo al successivo + if ( AreSamePointApprox( vPts[i], myLastPtInPL)) + continue ; + // altrimenti inserisco il punto nella Polyline e aggiorno il punto finale + myPL.AddUPoint( ++ dPar, vPts[i]) ; + myLastPtInPL = vPts[i] ; + } + // chiudo la PolyLine per sicurezza + myPL.Close() ; + + // swap + swap( PL, myPL) ; + + // recupero la curva composita dalla polyLine + if ( ! pCompoPL->FromPolyLine( PL) || ! pCompoPL->IsValid()) + return false ; + /*int _b = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCompoPL->Clone()) ; + m_pGeomDB->SetMaterial( _b, ORANGE) ;*/ + + // approssimo con archi + PolyArc PA ; + double dMyLinFea = dLinFeaTol ; + double dMyAngTol = dAngTol ; + if ( dMaxLinTol > LIN_TOL_STD) { + double dCoeff = ( dMaxLinTol - LIN_TOL_STD) / LIN_TOL_STD ; + dMyLinFea = min( LIN_FEA_STD + 1.0 * dCoeff * LIN_FEA_STD, 400.) ; + dMyAngTol = min( ANG_TOL_STD_DEG + 0.2 * dCoeff * ANG_TOL_STD_DEG, 60.) ; + } + if ( pCompoPL->ApproxWithArcsEx( dMaxLinTol, dMyAngTol, dMyLinFea, PA)) { + PtrOwner pTempCrv( CreateCurveComposite()) ; + if ( ! IsNull( pTempCrv) && + pTempCrv->FromPolyArc( PA) && + pTempCrv->RemoveSmallDefects( dMaxLinTol, ANG_TOL_STD_DEG) && + pTempCrv->MergeCurves( dMaxLinTol, ANG_TOL_STD_DEG)) { + /*int _a = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pTempCrv->Clone()) ; + m_pGeomDB->SetMaterial( _a, GREEN) ;*/ + pCompoPL->CopyFrom( pTempCrv) ; + } + } + // riporto la curva nel frame di partenza + pCompoPL->ToGlob( frLoc) ; + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfFinishing::GetSfrBySilhouette( ICAvParSilhouettesSurfTm* pCavParSilh, double dDepth, + double dSilTolSamp, double dSilTolLin, + double dSilTolAng, ISurfFlatRegion* pSfrSil) +{ + /* funzione per resitutire una regione piana data la classe di calcolo per silhouette */ + // controllo dei parametri + if ( pSfrSil == nullptr) + return false ; + pSfrSil->Clear() ; + // recupero il vettore di PolyLine della silhouette + POLYLINEVECTOR vPL ; + if ( ! pCavParSilh->GetSilhouette( - dDepth, vPL)) + return false ; + // creo la regione piana dalle PolyLine ricavate dalla Silhouette + SurfFlatRegionByContours SfrMaker ; + for ( auto& PL : vPL) { + // recupero la curva in base alla polyLine + PtrOwner pSilCrv( CreateCurveComposite()) ; + if ( IsNull( pSilCrv)) + return false ; + if ( ! ApproxSilhouetteClosedPLForOptimal( PL, dSilTolSamp, dSilTolLin, ANG_TOL_STD_DEG, LIN_FEA_STD, pSilCrv)) + return false ; + // aggiungo per regione + if ( ! SfrMaker.AddCurve( Release( pSilCrv))) + return false ; + } + // definisco la reigone piana + PtrOwner pSfrTmp( SfrMaker.GetSurf()) ; + if ( ! IsNull( pSfrTmp) && pSfrTmp->IsValid()) + pSfrSil->CopyFrom( pSfrTmp) ; + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfFinishing::SplitStmTrianglesForSpiralAndZConst( const ISurfTriMesh* pStm, const Frame3d& frSurf, + const Vector3d& vtTool, double dClippingAngle, double dTolerAngle, + StmFromTriangleSoup& TriaSoup, double& dMaxFrontTriaRad) +{ + /* + funzione per ciclare i triangoli di una TriMesh (*pStm) partendo da nT_start e terminando a nT_end + I triangoli che formano un angolo in valore assoluto con vtTool, maggiore di dClippingAngle + vengono inseriti nella zuppa + dMaxFrontTriaRad è il raggio massimo dei triangoli con normale che si discosta da vtTool per + meno di dTolerAngle (triangoli frontalieri) + */ + + // controllo della superficie + if ( pStm == nullptr || ! pStm->IsValid()) + return false ; + // porto il versore utensile nel riferimento locale + Vector3d vtToolLoc = vtTool ; vtToolLoc.ToLoc( frSurf) ; + // aggiusto i parametri + dClippingAngle = Clamp( dClippingAngle, 30., 60.) ; // [30°,60°] + dTolerAngle = Clamp( dTolerAngle, 1., 5.) ; // [1°,5°] + + // definizione delle costanti + double dCosLimit = cos( dClippingAngle * DEGTORAD) ; + double dCosLimSup = cos( ( dClippingAngle - dTolerAngle) * DEGTORAD) ; + double dCosLimInf = cos( max( 0., ( dClippingAngle + dTolerAngle)) * DEGTORAD) ; + double dAbsCosPerpTol = dTolerAngle * DEGTORAD ; // x->PI/2, cos(x) ~ -x + PI/2 + + // scorro i triangoli della superficie + for ( int nT = 0 ; nT < pStm->GetTriangleCount() ; ++ nT) { + // recupero il triangolo corrente (controllo la sua validità) + Triangle3d Tria ; pStm->GetTriangle( nT, Tria) ; + if ( ! Tria.IsValid()) + continue ; + // recupero la normale del triangolo + Vector3d vtN_tria = Tria.GetN() ; + // se i due versori sono quasi paralleli, passo al triangolo successivo + // ( se faccia piana equiversa a vtToolLoc allora è in Spiral, se opposta non la considero) + if ( AreSameOrOppositeVectorEpsilon( vtN_tria, vtToolLoc, 50 * EPS_SMALL)) + continue ; + // recupero il valore coseno dell'angolo + double dCos = vtN_tria * vtToolLoc ; + // se triangolo è forntaliero, lo inserisco nel vettore + if ( dCos < dCosLimSup && dCos > dCosLimInf) { + // recupero il raggio della sfera che contine il triangolo + BBox3d BBoxTria ; + double dRad ; + if ( ! Tria.GetLocalBBox( BBoxTria) || ! BBoxTria.GetRadius( dRad)) + continue ; + // se raggio più grande del limite superiore, aggiorno + if ( dRad > dMaxFrontTriaRad) + dMaxFrontTriaRad = dRad ; + } + // se la normale è circa perpendicolare a vtToolLoc, salto il triangolo (crea loop non validi) + if ( abs( dCos) < dAbsCosPerpTol) + continue ; + // se la normale del triangolo è sotto la tolleranza, lo inserisco nella zuppa + // più il prodottoscalare tende a 0, più i versori sono distanti + if ( abs( dCos) < dCosLimit + EPS_ANG_ZERO) + TriaSoup.AddTriangle( Tria.GetP( 0), Tria.GetP( 1), Tria.GetP( 2)) ; + } + + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfFinishing::SplitStmInTwoSilSfrByClippingAngle( const SURFLOCALVECTOR& vSrfLoc, const Frame3d& frSurf, const ISurfFlatRegion* pSfrCnt, + double dDepth, const Vector3d& vtTool, double dClippingAngle, ISurfFlatRegion* pSfrSpiral, + ISurfFlatRegion* pSfrZConst) +{ + // controllo delle regioni piane + if ( pSfrSpiral == nullptr || pSfrZConst == nullptr || + pSfrCnt == nullptr || ! pSfrCnt->IsValid()) + return false ; + pSfrSpiral->Clear() ; + pSfrZConst->Clear() ; + + // definisco il piano di taglio alla profondità massima + Point3d ptCenter ; pSfrCnt->GetCentroid( ptCenter) ; + Plane3d plClipping ; + Point3d ptPlCl = GetToLoc( ptCenter, frSurf) ; + Vector3d vtNCl = GetToLoc( vtTool, frSurf) ; + if ( ! plClipping.Set( ptPlCl - vtNCl * dDepth, - vtNCl)) + return false ; + + // parametri e costanti per il calcolo della regione + double dMaxRad = 100 * EPS_SMALL ; // raggio massimo della sfera che contiene i triangoli frontalieri + const double OFFS_TRIA_ANG_TOL = 2. ; // tolleranza di ricerca dei triangoli frontalieri + const double OFFS_CORR = 0. ; // offset correttivo regione piana ZConst + + // creazione della zuppa di triangoli per la Zconst + StmFromTriangleSoup StmSoup ; + StmSoup.Start() ; + // scorro il vettore delle regioni piane + for ( int i = 0 ; i < int( vSrfLoc.size()) ; ++ i) { + // recupero la regione come superficie trimesh (controllo la sua validità) + PtrOwner pStm( CloneSurfTriMesh( GetSurfTriMesh( vSrfLoc[i].Get()))) ; + if ( IsNull( pStm) || ! pStm->IsValid()) + continue ; + // NB. devo tagliare la supericie con un piano diretto come vtTool a profondità dDepth + // ( altrimenti rischio di calcolare regioni piane inutili ) + if ( ! pStm->Cut( plClipping, true)) + return false ; + // recupero la zuppa per ZConst + if ( ! SplitStmTrianglesForSpiralAndZConst( pStm, frSurf, vtTool, dClippingAngle, OFFS_TRIA_ANG_TOL, StmSoup, dMaxRad)) + return false ; + dMaxRad = Clamp( dMaxRad, 100 * EPS_SMALL, 5.) ; // per sicurezza + } + StmSoup.End() ; + + // definisco vettori superfici locali ZConst + CISURFTMPVECTOR vStmLocZConst ; + // recupero le superfici trimesh + PtrOwner pStmCurr( StmSoup.GetSurf()) ; + while ( ! IsNull( pStmCurr) && pStmCurr->IsValid() && pStmCurr->GetTriangleCount() > 0) { + // porto la superficie nel sistema di riferimento globale + pStmCurr->ToGlob( frSurf) ; + int _o = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pStmCurr->Clone()) ; + m_pGeomDB->SetMaterial( _o, PURPLE) ; + vStmLocZConst.emplace_back( Release( pStmCurr)) ; + pStmCurr.Set( StmSoup.GetSurf()) ; + } ; + + // definisco il frame di calcolo per la superficie in base alla pSfrCnt + Frame3d frLoc ; + if ( ! frLoc.Set( ptCenter, vtTool)) + return false ; + + // definisco la costante di campionamento per la silhouette + const double SILH_TOL = 1. ; + + // construisco la regione piana per ZConst + pSfrSpiral->CopyFrom( pSfrCnt) ; // superficie per spiral uguale all'originale + if ( ! vStmLocZConst.empty()) { + // inizializzo classe di calcolo della Silhoeutte + PtrOwner pCavParSilh( CreateCAvParSilhouettesSurfTm()) ; + if ( IsNull( pCavParSilh) || ! pCavParSilh->SetData( vStmLocZConst, frLoc, SILH_TOL)) + return false ; + // recupero la regione piana + if ( ! GetSfrBySilhouette( pCavParSilh, dDepth, SILH_TOL, 2. * dMaxRad, ANG_TOL_STD_DEG, pSfrZConst)) + return false ; + // se regione valida, la porto nel sistema di riferimento globale + if ( pSfrZConst->IsValid()) { + // traslo la superficie sopra al grezzo + bool bOK = pSfrZConst->Translate( dDepth * vtTool) ; + // offset di correzione... + bOK = bOK && pSfrZConst->Offset( OFFS_CORR, ICurve::OFF_FILLET) ; + // limito la superficie a ZConst alla regione di contorno + bOK = bOK && pSfrZConst->Intersect( *pSfrCnt) ; + // definizione superficie Spiral per sottrazione + bOK = bOK && pSfrSpiral->Subtract( *pSfrZConst) ; + if ( ! bOK) + return false ; + } + } + + int _a = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSfrSpiral->Clone()) ; + m_pGeomDB->SetMaterial( _a, Color( 255., 0., 255., .25)) ; + _a = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSfrZConst->Clone()) ; + m_pGeomDB->SetMaterial( _a, Color( 0., 255., 0., .25)) ; + LOG_ERROR( GetEMkLogger(), ToString( dMaxRad).c_str()) ; + + // elimino i piccoli chunk imprecisi + for ( int nC = 0 ; nC < pSfrSpiral->GetChunkCount() ; ++ nC) { + // verifico se l'Offset massimo del chunk è sopra alla tolleranza + double dMaxOffs = EPS_SMALL ; + pSfrSpiral->GetChunkMaxOffset( nC, dMaxOffs) ; + // rimuovo il Chunk c-esimo se l'Offset massimo è minore della tolleranza + if ( dMaxOffs < dMaxRad) { + pSfrSpiral->EraseChunk( nC) ; + -- nC ; + } + } + for ( int nC = 0 ; nC < pSfrZConst->GetChunkCount() ; ++ nC) { + // verifico se l'Offset massimo del chunk è sopra alla tolleranza + double dMaxOffs = EPS_SMALL ; + pSfrZConst->GetChunkMaxOffset( nC, dMaxOffs) ; + // rimuovo il Chunk c-esimo se l'Offset massimo è minore della tolleranza + if ( dMaxOffs < dMaxRad) { + pSfrZConst->EraseChunk( nC) ; + -- nC ; + } + } + + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfFinishing::OrderOptimalPathsByZLoc( const ISurfFlatRegion* pSfr, VECTORPATHS& vCrvPaths) +{ + // controllo dei parametri + if ( pSfr == nullptr || ! pSfr->IsValid()) + return false ; + // se ho un solo percorso, non faccio nulla + if ( int( vCrvPaths.size()) == 1) + return true ; + // creo un frame sulla superficie + Frame3d frOrder ; + Point3d ptOrder ; pSfr->GetCentroid( ptOrder) ; + Vector3d vtOrder = pSfr->GetNormVersor() ; + if ( ! frOrder.Set( ptOrder, vtOrder)) + return false ; + DBLVECTOR vZorder( vCrvPaths.size()) ; + for ( int i = 0 ; i < int( vCrvPaths.size()) ; ++ i) { + Point3d ptStart ; vCrvPaths[i].pCrvPath->GetStartPoint( ptStart) ; + ptStart.ToLoc( frOrder) ; + vZorder[i] = ptStart.z ; + } + // swap degli indici per ordine delle Z locali + for ( int i = 0 ; i < int( vZorder.size()) - 1 ; ++ i) { + for ( int j = i + 1 ; j < int( vZorder.size()) ; ++ j) { + if ( vZorder[j] > vZorder[i]) { + swap( vZorder[j], vZorder[i]) ; + swap( vCrvPaths[j], vCrvPaths[i]) ; + } + } + } + + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfFinishing::ChooseFinishingForOptimal( const ISurfFlatRegion* pSfr, int nChunk, bool& bSpiral, + double& dSideAng) +{ + // controllo dei parametri + if ( pSfr == nullptr || ! pSfr->IsValid()) + return false ; + // controllo valore di nChunk + if ( nChunk < 0 || nChunk >= pSfr->GetChunkCount()) + return false ; + // informazioni sul Chunk + int nLines = 0 ; double dMaxLineLen = 0. ; Vector3d vtTanMaxLine ; + int nArcs = 0 ; double dMaxArcLen = 0. ; + BBox3d BBox ; Vector3d vtX ; + for ( int nL = 0 ; nL < pSfr->GetLoopCount( nChunk) ; ++ nL) { + // recupero il loop come curva composita + PtrOwner pCompoLoop( ConvertCurveToComposite( pSfr->GetLoop( nChunk, nL))) ; + if ( IsNull( pCompoLoop) || ! pCompoLoop->IsValid()) + return false ; + // se loop esterno calcolo il Box + if ( nL == 0) { + PolyLine PL ; + if ( ! pCompoLoop->ApproxWithLines( 100 * EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_STD, PL)) + return false ; + Point3d ptCenter ; + double dLen ; double dHeight ; + if ( ! PL.GetMinAreaRectangleXY( ptCenter, vtX, dLen, dHeight)) + return false ; + } + // scorro le curve del Loop + for ( int nU = 0 ; nU < pCompoLoop->GetCurveCount() ; ++ nU) { + const ICurve* pCurve = pCompoLoop->GetCurve( nU) ; + if ( pCurve == nullptr || ! pCurve->IsValid()) + return false ; + // se arco + if ( pCurve->GetType() == CRV_ARC) { + ++ nArcs ; + double dLen ; pCurve->GetLength( dLen) ; + if ( dLen > dMaxArcLen) + dMaxArcLen = dLen ; + } + // se linea + else if ( pCurve->GetType() == CRV_LINE) { + ++ nLines ; + double dLen ; pCurve->GetLength( dLen) ; + if ( dLen > dMaxLineLen) { + dMaxLineLen = dLen ; + pCurve->GetStartDir( vtTanMaxLine) ; + } + } + } + } + // di base lavorazione Spiral + bSpiral = true ; + // se l'entità più lunga è la linea + if ( dMaxLineLen > dMaxArcLen) { + // se ci sono in genere più linee che archi (60% linee) + if ( nLines / ( nLines + nArcs + 1) > .6) { + // se la direzione principale della linea concide con la direzione massima del box minimo + if ( AreSameOrOppositeVectorApprox( vtTanMaxLine, vtX)) { + bSpiral = false ; // ZigZag + X_AX.GetAngle( vtX, dSideAng) ; + abs( dSideAng) ; + } + } + } + + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfFinishing::AddOptimal( ICAvToolSurfTm* pCAvTlStm, const SURFLOCALVECTOR& vSrfLoc, const Frame3d& frSurf, const ISurfFlatRegion* pSfr, + const Vector3d& vtTool, double dDepth, double dElev, bool bSplitArcs) +{ + return true ; // per ora (Test) + + // controllo che la regione sia definita correttamente + if ( pSfr == nullptr || ! pSfr->IsValid()) + return false ; + + // recupero distanze di sicurezza + double dSafeZ = GetSafeZ() ; + // lunghezza di approccio/retrazione + double dAppr = m_Params.m_dStartPos ; + // raggio di lavorazione e offset di correzione + double dPockRad = m_Params.m_dSideStep ; + double dPockRadOffs = m_TParams.m_dDiam / 2 - m_Params.m_dSideStep - m_Params.m_dOverlap ; + // vettore dei percorsi da calcolare + VECTORPATHS vPaths ; + + // definizione angolo di tolleranza per lavorazioni Spiral e ZConst + double dClippingAngle = ANG_TOL_STD_DEG * 3. ; + PtrOwner pSfrSpiral( CreateSurfFlatRegion()) ; + PtrOwner pSfrZConst( CreateSurfFlatRegion()) ; + if ( ! SplitStmInTwoSilSfrByClippingAngle( vSrfLoc, frSurf, pSfr, dDepth, vtTool, dClippingAngle, pSfrSpiral, pSfrZConst)) + return false ; + + // ----------------------- Lavorazione Spiral/ZigZag ------------------------------- + if ( ! IsNull( pSfrSpiral) && pSfrSpiral->IsValid()) { + // aggiusto la regione a seconda dei parametri (il centro utensile deve stare sul bordo) + PtrOwner pSfrToWork( pSfrSpiral->CreateOffsetSurf( m_TParams.m_dDiam / 2. - m_Params.m_dOverlap, ICurve::OFF_FILLET)) ; + if ( IsNull( pSfrToWork) || ! pSfrToWork->IsValid()) + return false ; + // mi assicuro di non uscire dalla superficie originale + pSfrToWork->Intersect( *pSfr) ; + // assegno tutte proprietà di lato chiuso + for ( int nC = 0 ; nC < pSfrToWork->GetChunkCount() ; ++ nC) + for ( int nL = 0 ; nL < pSfrToWork->GetLoopCount( nC) ; ++ nL) + for ( int nU = 0 ; nU < pSfrToWork->GetLoopCurveCount( nC, nL) ; ++ nU) + pSfrToWork->SetCurveTempProp( nC, nL, nU, 0, TEMP_PROP_CLOSE_EDGE) ; + // lavorazione Spiral/ZigZag + ICRVCOMPOPOVECTOR vpCrvs ; + if ( ! CalcPocketing( pSfrToWork, dPockRad, dPockRadOffs, m_Params.m_dSideStep, m_Params.m_dSideAngle, + POCKET_SPIRALIN, false, false, true, false, P_INVALID, nullptr, vpCrvs)) { + m_pMchMgr->SetLastError( 3125, "Error in SurfFinishing : CalcPocketing failed") ; + return false ; + } + // determino il riferimento di base della svuotatura + Frame3d frPocket ; + Point3d ptCen ; pSfr->GetCentroid( ptCen) ; + frPocket.Set( ptCen, vtTool) ; + // ciclo sui percorsi ricavati risultanti + double dProgCoeff = 1. / max( int( vpCrvs.size()), 1) ; + for ( int k = 0 ; k < int( vpCrvs.size()) ; ++ k) { + // definisco un nuovo percorso (in locale) + vPaths.resize( vPaths.size() + 1) ; + vPaths.back().pCrvPath.Set( Release( vpCrvs[k])) ; + vPaths.back().pCrvPath->ToLoc( frPocket) ; + vPaths.back().nType = SURFFIN_SUB_SPIRALIN ; + // li correggo per non interferire con le superfici + if ( pCAvTlStm != nullptr) { + // approssimo la curva con una polilinea + PolyLine PL ; + if ( ! vPaths.back().pCrvPath->ApproxWithLines( LIN_TOL_STD, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL)) + return false ; + // eventuale aggiunta di punti per garantire max distanza + const double MIN_DIST = 1. ; + const double MAX_DIST = 50. ; + double dDist = Clamp( m_TParams.m_dDiam / 2, MIN_DIST, MAX_DIST) ; + if ( ! PL.AdjustForMaxSegmentLen( dDist)) + return false ; + // porto nel riferimento delle superfici + PL.LocToLoc( frPocket, frSurf) ; + // porto i dati geometrici in locale alle superfici + Vector3d vtAxL = vtTool ; + vtAxL.ToLoc( frSurf) ; + Vector3d vtMoveL = vtAxL ; + // traslo della lunghezza utensile diminuita dell'affondamento + PL.Translate( vtAxL * ( m_TParams.m_dLen - dDepth)) ; + // eseguo CAv + if ( ! pCAvTlStm->TestPath( PL.GetUPointList(), vtAxL, vtMoveL, m_Params.m_dApprox, ( k + 1) * dProgCoeff)) + return false ; + // contro-traslo della lunghezza utensile + PL.Translate( - vtAxL * m_TParams.m_dLen) ; + // riporto la polilinea nel riferimento della curva + PL.LocToLoc( frSurf, frPocket) ; + // elimino i punti allineati + PL.RemoveAlignedPoints( 0.8 * m_Params.m_dApprox) ; + // creo una curva composita a partire dalla polilinea + PtrOwner< ICurveComposite> pCompo( CreateCurveComposite()) ; + if ( IsNull( pCompo) || ! pCompo->FromPolyLine( PL)) + return false ; + // sostituisco la vecchia curva con la nuova + vPaths.back().pCrvPath.Set( pCompo) ; + } + } + // porto tutti i percorsi nel frame globale + for ( int i = 0 ; i < int( vPaths.size()) ; ++ i) + vPaths[i].pCrvPath->ToGlob( frPocket) ; + } + // disegno i percorsi per controllo + int ___a = int( vPaths.size()) ; + for ( int i = 0 ; i < int( vPaths.size()) ; ++ i) { + int _n = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, vPaths[i].pCrvPath->Clone()) ; + m_pGeomDB->SetMaterial( _n, RED) ; + } + + // ----------------------- Lavorazione Zconst ------------------------------- + if ( ! IsNull( pSfrZConst) && pSfrZConst->IsValid()) { + // aggiusto la regione a seconda dei parametri (il centro utensile deve stare sul bordo) + PtrOwner pSfrToWork( pSfrZConst->CreateOffsetSurf( 0., ICurve::OFF_FILLET)) ; + if ( IsNull( pSfrToWork) || ! pSfrToWork->IsValid()) + return false ; + // mi assicuro di non uscire dalla superficie originale + pSfrToWork->Intersect( *pSfr) ; + // assegno tutte proprietà di lato chiuso + for ( int nC = 0 ; nC < pSfrToWork->GetChunkCount() ; ++ nC) + for ( int nL = 0 ; nL < pSfrToWork->GetLoopCount( nC) ; ++ nL) + for ( int nU = 0 ; nU < pSfrToWork->GetLoopCurveCount( nC, nL) ; ++ nU) + pSfrToWork->SetCurveTempProp( nC, nL, nU, 0, TEMP_PROP_CLOSE_EDGE) ; + // inizializzo la classe di calcolo delle silhouette nei piani come sopra + PtrOwner pCavParSilh( GetParSilhouettesForZConst( vSrfLoc, frSurf, pSfrToWork)) ; + if ( IsNull( pCavParSilh)) + return false ; + // recupero le curve singole definite dal bordo della Silhouette + vector vCrvCompo ; + if ( ! CalcZConstSilCrv( pCavParSilh, vSrfLoc, frSurf, pSfrToWork, vtTool, dDepth, vCrvCompo)) { + m_pMchMgr->SetLastError( 3126, "Error in SurfFinishing : Computing ZConst Curves failed") ; + return false ; + } + // se ho delle curve, allora unisco i percorsi trovati + if ( ! vCrvCompo.empty()) { + // collego tra loro le curve trovate + ICRVCOMPOPOVECTOR vCrv ; + if ( ! CreateZConstPaths( pCAvTlStm, vSrfLoc, frSurf, vCrvCompo, vtTool, pSfrToWork, dDepth, vCrv)) { + m_pMchMgr->SetLastError( 3127, "Error in SurfFinishing : Computing ZConst Paths failed") ; + return false ; + } + // aggiungo i percorsi trovati + for ( int i = 0 ; i < int( vCrv.size()) ; ++ i) { + vPaths.resize( vPaths.size() + 1) ; + vPaths.back().pCrvPath.Set( Release( vCrv[i])) ; + vPaths.back().nType = SURFFIN_SUB_ZIGZAG ; + } + } + } + + // disegno i percorsi per controllo + for ( int i = ___a ; i < int( vPaths.size()) ; ++ i) { + int _n = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, vPaths[i].pCrvPath->Clone()) ; + m_pGeomDB->SetMaterial( _n, GREEN) ; + } + + // ordino i percorsi in base alla Zlocale + if ( ! OrderOptimalPathsByZLoc( pSfr, vPaths)) + return false ; + // aggiusto la regione a seconda dei parametri + PtrOwner pSfrClass( pSfr->CreateOffsetSurf( - m_TParams.m_dDiam / 2. + m_Params.m_dOverlap, ICurve::OFF_FILLET)) ; + if ( IsNull( pSfrClass) || ! pSfrClass->IsValid()) + return false ; + + // inserisco i percorsi + bool bStart = true ; + // ciclo sulle curve risultanti + for ( int k = 0 ; k < int( vPaths.size()) ; ++ k) { + // se la curva non è valida, passo alla successiva + if ( IsNull( vPaths[k].pCrvPath) || ! vPaths[k].pCrvPath->IsValid()) + continue ; + // determino in che piano di partenza e il piano di arrivo se ZConst + int nStartPlane = 0 ; + int nEndPlane = 0 ; + if ( vPaths[k].nType == SURFFIN_SUB_Z_CONST) { + nStartPlane = vPaths[k].pCrvPath->GetTempProp( 0) ; + nEndPlane = vPaths[k].pCrvPath->GetTempProp( 1) ; + } + // ciclo sulle curve elementari + int nMaxInd = vPaths[k].pCrvPath->GetCurveCount() - 1 ; + for ( int i = 0 ; i <= nMaxInd ; ++ i) { + // curva corrente + const ICurve* pCrvC = vPaths[k].pCrvPath->GetCurve( i) ; + // copio la curva + PtrOwner pCurve( pCrvC->Clone()) ; + if ( IsNull( pCurve)) + return false ; + // se prima entità + if ( i == 0) { + // dati inizio entità + Point3d ptStart ; pCurve->GetStartPoint( ptStart) ; + Vector3d vtStart ; pCurve->GetStartDir( vtStart) ; + // vettore tangente iniziale non deve salire rispetto a estrusione (poi si prende opposto) + double dStartOnExtr = vtStart * vtTool ; + if ( dStartOnExtr > 0) { + vtStart -= dStartOnExtr * vtTool ; + vtStart.Normalize() ; + } + // determino normale della superficie sul punto iniziale + Vector3d vtNorm ; + if ( ! GetSurfaceNormalAtPoint( pCAvTlStm, frSurf, ptStart, vtTool, vtNorm)) { + Point3d ptEnd ; + pCurve->GetEndPoint( ptEnd) ; + if ( ! GetSurfaceNormalAtPoint( pCAvTlStm, frSurf, ptEnd, vtTool, vtNorm)) + vtNorm = V_NULL ; + } + // determino inizio attacco + Point3d ptP1 ; + if ( ! CalcLeadInStart( ptStart, vtStart, vtTool, vtNorm, ptP1)) + return false ; + // eventuale correzione inizio attacco per evitare interferenze + if ( ! GetLastGoodPoint( pCAvTlStm, frSurf, ptStart, ptP1, vtTool, ptP1)) + return false ; + // se ZConst, controllo che tale punto sia al di fuori della regione piana + if ( vPaths[k].nType == SURFFIN_SUB_Z_CONST) { + bool bIsInside = false ; + if ( IsPointInsideSurfFr( ptP1 + vtTool * ( m_Params.m_dSideStep * nStartPlane), pSfrClass, EPS_SMALL, bIsInside)) + ptP1 = ptStart ; + } + // determino elevazione su inizio attacco + double dStElev ; + if ( ! GetElevation( m_nPhase, ptStart - 10 * EPS_SMALL * vtTool, vtTool, GetRadiusForStartEndElevation(), vtTool, dStElev)) + dStElev = dElev ; + dStElev -= ( ptP1 - ptStart) * vtTool ; + // se inizio, approccio globale al punto iniziale + if ( bStart) { + if ( ! AddApproach( ptP1, vtTool, dSafeZ, dStElev, dAppr)) { + m_pMchMgr->SetLastError( 3111, "Error in SurfFinishing : Approach not computable") ; + return false ; + } + bStart = false ; + } + // altrimenti, approccio di collegamento + else { + if ( ! AddLinkApproach( ptP1, vtTool, dSafeZ, dStElev, dAppr)) { + m_pMchMgr->SetLastError( 3112, "Error in SurfFinishing : Link not computable") ; + return false ; + } + } + // aggiungo attacco + SetFeed( GetStartFeed()) ; + if ( ! AddLeadIn( ptP1, ptStart, vtStart, vtTool, bSplitArcs)) { + m_pMchMgr->SetLastError( 3113, "Error in SurfFinishing : LeadIn not computable") ; + return false ; + } + } + // elaborazioni sulla curva corrente (sempre un segmento di retta) + if ( pCurve->GetType() == CRV_LINE) { + ICurveLine* pLine = GetCurveLine( pCurve) ; + Point3d ptP3 = pLine->GetEnd() ; + Vector3d vtMove ; pLine->GetStartDir( vtMove) ; + SetFeed( GetRightFeed( vtMove, vtTool)) ; + if ( AddLinearMove( ptP3) == GDB_ID_NULL) + return false ; + } + else if ( pCurve->GetType() == CRV_ARC) { + ICurveArc* pArc = GetCurveArc( pCurve) ; + Point3d ptCen = pArc->GetCenter() ; + double dAngCen = pArc->GetAngCenter() ; + Vector3d vtN = pArc->GetNormVersor() ; + Point3d ptP3 ; pArc->GetEndPoint( ptP3) ; + SetFeed( GetFeed()) ; + if ( AddArcMove( ptP3, ptCen, dAngCen, vtN) == GDB_ID_NULL) + return false ; + } + // se ultima entità + if ( i == nMaxInd) { + // dati fine entità + Point3d ptEnd ; pCurve->GetEndPoint( ptEnd) ; + Vector3d vtEnd ; pCurve->GetEndDir( vtEnd) ; + // vettore tangente finale non deve scendere rispetto a estrusione + double dEndOnExtr = vtEnd * vtTool ; + if ( dEndOnExtr < 0) { + vtEnd -= dEndOnExtr * vtTool ; + vtEnd.Normalize() ; + } + // determino normale della superficie sul punto finale + Vector3d vtNorm ; + if ( ! GetSurfaceNormalAtPoint( pCAvTlStm, frSurf, ptEnd, vtTool, vtNorm)) { + Point3d ptStart ; + pCurve->GetStartPoint( ptStart) ; + if ( ! GetSurfaceNormalAtPoint( pCAvTlStm, frSurf, ptStart, vtTool, vtNorm)) + vtNorm = V_NULL ; + } + // determino fine uscita + Point3d ptP1 ; + if ( ! CalcLeadOutEnd( ptEnd, vtEnd, vtTool, vtNorm, ptP1)) + return false ; + // eventuale correzione fine uscita per evitare interferenze + if ( ! GetLastGoodPoint( pCAvTlStm, frSurf, ptEnd, ptP1, vtTool, ptP1)) + return false ; + // controllo che tale punto sia al di fuori della regione piana + bool bIsInside = false ; + if ( IsPointInsideSurfFr( ptP1 + vtTool * ( m_Params.m_dSideStep * nStartPlane), pSfrClass, EPS_SMALL, bIsInside)) + ptP1 = ptEnd ; + // se ultima uscita globale del percorso + if ( k == int( vPaths.size()) - 1) { + // aggiungo LeadOut + SetFeed( GetEndFeed()) ; + if ( ! AddLeadOut( ptEnd, vtEnd, ptP1, vtTool, bSplitArcs)) { + m_pMchMgr->SetLastError( 3114, "Error in SurfFinishing : LeadOut not computable") ; + return false ; + } + // aggiungo retroazione finale + if ( ! AddRetract( ptP1, vtTool, dSafeZ, nEndPlane * m_Params.m_dSideStep, dAppr)) { + m_pMchMgr->SetLastError( 3115, "Error in SurfFinishing : Retract not computable") ; + return false ; + } + } + // altrimenti + else { + // determino elevazione su fine uscita + double dEndElev ; + if ( ! GetElevation( m_nPhase, ptEnd - 10 * EPS_SMALL * vtTool, vtTool, GetRadiusForStartEndElevation(), vtTool, dEndElev)) + dEndElev = dElev ; + dEndElev -= ( ptP1 - ptEnd) * vtTool ; + if ( ! AddRetract( ptP1, vtTool, dSafeZ, dEndElev, dAppr)) { + m_pMchMgr->SetLastError( 3115, "Error in SurfFinishing : Retract not computable") ; + return false ; + } + } + } + } + } + + return true ; +} + //---------------------------------------------------------------------------- bool SurfFinishing::AddApproach( const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dElev, double dAppr) { SetFlag( 1) ; - // se sopra attacco c'� spazio per sicurezza o approccio + // se sopra attacco c'è spazio per sicurezza o approccio double dSafeDist = dSafeZ ; if ( dElev + max( dSafeDist, dAppr) > 10 * EPS_SMALL) { // se distanza di sicurezza minore di distanza di inizio @@ -3223,7 +4062,7 @@ SurfFinishing::GetRightFeed( const Vector3d& vtMove, const Vector3d& vtTool) con // Se l'utensile non ha movimento significativo di punta, si restituisce la feed standard if ( dCosMove > - COS_ORTO_ANG_SMALL) return GetFeed() ; - // Altrimenti non si deve superare la massima velocit� di punta prevista + // Altrimenti non si deve superare la massima velocità di punta prevista return min( GetFeed(), GetTipFeed() / abs( dCosMove)) ; } diff --git a/SurfFinishing.h b/SurfFinishing.h index 7679d10..5c4c326 100644 --- a/SurfFinishing.h +++ b/SurfFinishing.h @@ -24,7 +24,17 @@ class ICAvToolSurfTm ; class ISurfFlatRegion ; +class ISurfTriMesh ; class ICAvParSilhouettesSurfTm ; +class StmFromTriangleSoup ; + +// vettore dei percorsi da calcolare per finiture ottimizzate +struct PATH { + PtrOwner pCrvPath ; + int nType ; + double dSideAng ; +} ; +typedef std::vector VECTORPATHS ; //---------------------------------------------------------------------------- class SurfFinishing : public Machining @@ -90,7 +100,21 @@ class SurfFinishing : public Machining const Vector3d& vtTool, double dDepth, double dElev, bool bSplitArcs, bool bInVsOut) ; bool AddZConst( ICAvToolSurfTm* pCAvTlStm, const SURFLOCALVECTOR& vSrfLoc, const Frame3d& frSurf, const ISurfFlatRegion* pSfr, const Vector3d& vtTool, double dDepth, double dElev, bool bSliptArcs) ; - bool GetZConstFacesInsideSfr( const SURFLOCALVECTOR& vSrfLoc, const Frame3d& frSurf, const ISurfFlatRegion* pSfr, + bool AddOptimal( ICAvToolSurfTm* pCAvTlStm, const SURFLOCALVECTOR& vSrfLoc, const Frame3d& frSurf, const ISurfFlatRegion* pSfr, + const Vector3d& vtTool, double dDepth, double dElev, bool bSliptArcs) ; + bool ChooseFinishingForOptimal( const ISurfFlatRegion* pSfr, int nChunk, bool& bSpiral, double& dSideAng) ; + bool OrderOptimalPathsByZLoc( const ISurfFlatRegion* pSfr, VECTORPATHS& vCrvPaths) ; + bool SplitStmTrianglesForSpiralAndZConst( const ISurfTriMesh* pStm, const Frame3d& frSurf, + const Vector3d& vtTool, double dClippingAngle, double dTolerAngle, + StmFromTriangleSoup& TriaSoup, double& dMaxFrontTriaRad) ; + bool GetSfrBySilhouette( ICAvParSilhouettesSurfTm* pCavParSilh, double dDepth, double dSilTolSamp, + double dSilTolLin, double dSilTolAng, ISurfFlatRegion* pSfrSil) ; + bool ApproxSilhouetteClosedPLForOptimal( PolyLine& PL, double dSampleTol, double dMaxLinTol, double dAngTol, double dLinFeaTol, ICurveComposite* pCompoPL) ; + bool SplitStmInTwoSilSfrByClippingAngle( const SURFLOCALVECTOR&, const Frame3d& frSurf, const ISurfFlatRegion* pSfrCnt, + double dDepth, const Vector3d& vtTool, double dClippingAngle, ISurfFlatRegion* pSfrSpiral, ISurfFlatRegion* pSfrZConst) ; + bool GetZConstFacesInsideSfr( const SURFLOCALVECTOR& + + , const Frame3d& frSurf, const ISurfFlatRegion* pSfr, const Vector3d& vtTool, std::set& setZAmbiguos) ; ICAvParSilhouettesSurfTm* GetParSilhouettesForZConst( const SURFLOCALVECTOR& vSrfLoc, const Frame3d& frSurf, const ISurfFlatRegion* pSfr) const ;