diff --git a/EgtMachKernel.rc b/EgtMachKernel.rc index f23336b..0c0ec43 100644 Binary files a/EgtMachKernel.rc and b/EgtMachKernel.rc differ diff --git a/SurfFinishing.cpp b/SurfFinishing.cpp index cc26225..b7ec312 100644 --- a/SurfFinishing.cpp +++ b/SurfFinishing.cpp @@ -27,6 +27,7 @@ #include "/EgtDev/Include/EGkChainCurves.h" #include "/EgtDev/Include/EGkOffsetCurve.h" #include "/EgtDev/Include/EGkSurfBezier.h" +#include "/EgtDev/Include/EGkIntersLinePlane.h" #include "/EgtDev/Include/EGkIntersCurves.h" #include "/EgtDev/Include/EGkCurveAux.h" #include "/EgtDev/Include/EGkSfrCreate.h" @@ -116,17 +117,23 @@ enum { #define DEBUG 0 #define DEBUG_SFR 0 #define ENABLE_ZCONST_PATH_DEBUG 0 +#define ENABLE_ZCONST_LINK_DEBUG 0 #define ENABLE_OPTIMAL_DEBUG 0 #define ENABLE_OPTIMAL_SOFT_DEBUG 0 #define ENABLE_OPTIMAL_FINAL_CURVES_DEBUG 0 #define ENABLE_PENCIL_DEBUG 0 #define ENABLE_LINK_DEBUG 0 #define ENABLE_MAXDOWN_STARTEND_DEBUG 0 -#if DEBUG || DEBUG_SFR || ENABLE_ZCONST_PATH_DEBUG || ENABLE_OPTIMAL_DEBUG || ENABLE_OPTIMAL_SOFT_DEBUG || \ - ENABLE_PENCIL_DEBUG || ENABLE_OPTIMAL_FINAL_CURVES_DEBUG || ENABLE_LINK_DEBUG || ENABLE_MAXDOWN_STARTEND_DEBUG +#define ENABLE_ZCONST_TOOL_MOVE_DEBUG 0 +#if DEBUG || DEBUG_SFR || ENABLE_ZCONST_PATH_DEBUG || ENABLE_ZCONST_LINK_DEBUG || ENABLE_OPTIMAL_DEBUG || ENABLE_OPTIMAL_SOFT_DEBUG || \ + ENABLE_PENCIL_DEBUG || ENABLE_OPTIMAL_FINAL_CURVES_DEBUG || ENABLE_LINK_DEBUG || ENABLE_MAXDOWN_STARTEND_DEBUG || \ + ENABLE_ZCONST_TOOL_MOVE_DEBUG #include "/EgtDev/Include/EGkGeoPoint3d.h" #include "/EgtDev/Include/EGkGeoVector3d.h" #include "/EgtDev/Include/EgtPerfCounter.h" + inline Color GetRandomColor() { + return Color( double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, 1.) ; + } #endif @@ -686,9 +693,6 @@ SurfFinishing::MyApply( bool bRecalc, bool bPostApply) return false ; m_pGeomDB->SetStatus( nToolVtId, GDB_ST_ON) ; m_pGeomDB->SetMaterial( nToolVtId, FUCHSIA) ; - // nel caso di lavorazioni Optimal o Zlevel nascondo tale frame - if ( m_Params.m_nSubType == SURFFIN_SUB_Z_CONST || m_Params.m_nSubType == SURFFIN_SUB_OPTIMAL) - m_pGeomDB->SetStatus( nToolVtId, GDB_ST_OFF) ; } // rendo corrente l'utensile usato nella lavorazione @@ -2352,9 +2356,8 @@ SurfFinishing::ProcessSfr( int nPathId, int nPvId, int nClId) if ( IsNull( pCAvTlStm) || IsNull( pSfrCntLoc) || ! pSfrCntLoc->IsValid() || ! pSfrCntLoc->ToLoc( frSurf) || - ! SetCAvTlStmForSurfaces( pCAvTlStm, pSfrCntLoc, dDepth, m_TParams.m_dLen, m_TParams.m_dDiam, - m_TParams.m_dCornRad, m_TParams.m_dSideAng, m_TParams.m_dMaxMat, - GetOffsR(), vSrfLoc, vSrfLocSupp)) { + ! SetCAvTlStmForSurfaces( pCAvTlStm, pSfrCntLoc, dDepth, m_TParams.m_dLen, m_TParams.m_dDiam, m_TParams.m_dCornRad, + m_TParams.m_dSideAng, m_TParams.m_dMaxMat, GetOffsR(), vSrfLoc, vSrfLocSupp)) { m_pMchMgr->SetLastError( 3124, "Error in SurfFinishing : region not computable") ; return false ; } @@ -2411,7 +2414,8 @@ SurfFinishing::ProcessSfr( int nPathId, int nPvId, int nClId) SetAuxDir( vtAux) ; // assegno il vettore estrusione al gruppo del percorso - m_pGeomDB->SetInfo( nPxId, KEY_EXTR, vtTool) ; + m_pGeomDB->SetInfo( nPxId, KEY_TOOL_DIR, vtTool) ; + m_pGeomDB->SetInfo( nPxId, KEY_TOOL_MOVE, vtMove) ; // inserisco le superfici di supporto tra le superfici locali for ( SurfLocal& SurfLocSupp : vSrfLocSupp) @@ -2422,23 +2426,23 @@ SurfFinishing::ProcessSfr( int nPathId, int nPvId, int nClId) switch ( m_Params.m_nSubType) { case SURFFIN_SUB_ZIGZAG : - if ( ! AddZigZag( pCAvTlStm, frSurf, pSfrCnt, vtTool, vtMove, dDepth, dElev, bSplitArcs)) + if ( ! AddZigZag( pCAvTlStm, vSrfLoc, frSurf, pSfrCnt, vtTool, vtMove, dDepth, dElev, bSplitArcs)) return false ; break ; case SURFFIN_SUB_ONEWAY : - if ( ! AddOneWay( pCAvTlStm, frSurf, pSfrCnt, vtTool, vtMove, dDepth, dElev, bSplitArcs)) + if ( ! AddOneWay( pCAvTlStm, vSrfLoc, frSurf, pSfrCnt, vtTool, vtMove, dDepth, dElev, bSplitArcs)) return false ; break ; case SURFFIN_SUB_SPIRALIN : - if ( ! AddSpiral( pCAvTlStm, frSurf, pSfrCnt, vtTool, vtMove, dDepth, dElev, bSplitArcs, true)) + if ( ! AddSpiral( pCAvTlStm, vSrfLoc, frSurf, pSfrCnt, vtTool, vtMove, dDepth, dElev, bSplitArcs, true)) return false ; break ; case SURFFIN_SUB_SPIRALOUT : - if ( ! AddSpiral( pCAvTlStm, frSurf, pSfrCnt, vtTool, vtMove, dDepth, dElev, bSplitArcs, false)) + if ( ! AddSpiral( pCAvTlStm, vSrfLoc, frSurf, pSfrCnt, vtTool, vtMove, dDepth, dElev, bSplitArcs, false)) return false ; break ; case SURFFIN_SUB_Z_CONST : - if ( ! AddZConst( pCAvTlStm, vSrfLoc, frSurf, pSfrCnt, vtTool, dDepth, dElev, bSplitArcs)) + if ( ! AddZConst( pCAvTlStm, vSrfLoc, frSurf, pSfrCnt, vtTool, vtMove, dDepth, dElev, bSplitArcs)) return false ; break ; case SURFFIN_SUB_OPTIMAL : @@ -2636,7 +2640,7 @@ SurfFinishing::CorrectPathByCollision( ICAvToolSurfTm* pCAvTlStm, const Frame3d& //---------------------------------------------------------------------------- bool -SurfFinishing::AddZigZag( ICAvToolSurfTm* pCAvTlStm, const Frame3d& frSurf, const ISurfFlatRegion* pSfrCnt, +SurfFinishing::AddZigZag( ICAvToolSurfTm* pCAvTlStm, const SURFLOCALVECTOR& vSrfLoc, const Frame3d& frSurf, const ISurfFlatRegion* pSfrCnt, const Vector3d& vtTool, const Vector3d& vtMove, double dDepth, double dElev, bool bSplitArcs) { // calcolo lo ZigZag @@ -2655,7 +2659,7 @@ SurfFinishing::AddZigZag( ICAvToolSurfTm* pCAvTlStm, const Frame3d& frSurf, cons } // aggiungo i percorsi di finitura calcolati - if ( ! AddFinishing( pSfrCnt, pCAvTlStm, frSurf, vpCrvs, vtTool, vtMove, dElev, dDepth, bSplitArcs)) + if ( ! AddFinishing( pSfrCnt, pCAvTlStm, vSrfLoc, frSurf, vpCrvs, vtTool, vtMove, dElev, dDepth, bSplitArcs)) return false ; return true ; @@ -2663,7 +2667,7 @@ SurfFinishing::AddZigZag( ICAvToolSurfTm* pCAvTlStm, const Frame3d& frSurf, cons //---------------------------------------------------------------------------- bool -SurfFinishing::AddOneWay( ICAvToolSurfTm* pCAvTlStm, const Frame3d& frSurf, const ISurfFlatRegion* pSfrCnt, +SurfFinishing::AddOneWay( ICAvToolSurfTm* pCAvTlStm, const SURFLOCALVECTOR& vSrfLoc, const Frame3d& frSurf, const ISurfFlatRegion* pSfrCnt, const Vector3d& vtTool, const Vector3d& vtMove, double dDepth, double dElev, bool bSplitArcs) { // calcolo OneWay @@ -2682,7 +2686,7 @@ SurfFinishing::AddOneWay( ICAvToolSurfTm* pCAvTlStm, const Frame3d& frSurf, cons } // aggiungo i percorsi di finitura calcolati - if ( ! AddFinishing( pSfrCnt, pCAvTlStm, frSurf, vpCrvs, vtTool, vtMove, dElev, dDepth, bSplitArcs)) + if ( ! AddFinishing( pSfrCnt, pCAvTlStm, vSrfLoc, frSurf, vpCrvs, vtTool, vtMove, dElev, dDepth, bSplitArcs)) return false ; return true ; @@ -2690,7 +2694,7 @@ SurfFinishing::AddOneWay( ICAvToolSurfTm* pCAvTlStm, const Frame3d& frSurf, cons //---------------------------------------------------------------------------- bool -SurfFinishing::AddSpiral( ICAvToolSurfTm* pCAvTlStm, const Frame3d& frSurf, const ISurfFlatRegion* pSfrCnt, +SurfFinishing::AddSpiral( ICAvToolSurfTm* pCAvTlStm, const SURFLOCALVECTOR& vSrfLoc, const Frame3d& frSurf, const ISurfFlatRegion* pSfrCnt, const Vector3d& vtTool, const Vector3d& vtMove, double dDepth, double dElev, bool bSplitArcs, bool bInVsOut) { // calcolo la spirale @@ -2710,7 +2714,7 @@ SurfFinishing::AddSpiral( ICAvToolSurfTm* pCAvTlStm, const Frame3d& frSurf, cons } // aggiungo i percorsi di finitura calcolati - if ( ! AddFinishing( pSfrCnt, pCAvTlStm, frSurf, vpCrvs, vtTool, vtMove, dElev, dDepth, bSplitArcs)) + if ( ! AddFinishing( pSfrCnt, pCAvTlStm, vSrfLoc, frSurf, vpCrvs, vtTool, vtMove, dElev, dDepth, bSplitArcs)) return false ; return true ; @@ -2867,25 +2871,31 @@ SurfFinishing::GetSfrSilhouette( const SURFLOCALVECTOR& vSrfLoc, const Frame3d& //---------------------------------------------------------------------------- bool SurfFinishing::CalcZConstSilCrv( ICAvParSilhouettesSurfTm* pCavParSilh, const SURFLOCALVECTOR& vSrfLoc, const Frame3d& frSurf, - const ISurfFlatRegion* pSfrClass, const Vector3d& vtTool, double dDepth, vector& vCrvCompo) const + const ISurfFlatRegion* pSfrCnt, const Vector3d& vtTool, double dDepth, ICRVCOMPOPOMAT& matCompo) const { // funzione per calcolare le curve singole di finitura mediante Silhouette e le regioni da non rovinare - // NB. Come primo TempParam delle curve viene memorizzata la distanza tra essa e il piano della pSfrClass + // NB. Come primo TempParam delle curve viene memorizzata la distanza tra essa e il piano della pSfrCnt // controllo che la regione piana sia definita correttamente - vCrvCompo.clear() ; - if ( pSfrClass == nullptr || ! pSfrClass->IsValid()) + matCompo.clear() ; + if ( pSfrCnt == nullptr || ! pSfrCnt->IsValid()) + return false ; + + // porto la regione di contorno nel frame locale alle superfici + PtrOwner pSfrCntLoc( CloneSurfFlatRegion( pSfrCnt)) ; + if ( IsNull( pSfrCntLoc) || ! pSfrCntLoc->IsValid() || ! pSfrCntLoc->ToLoc( frSurf)) return false ; // definisco un frame implicito rispetto alla superficie di classificazione Frame3d frLocXY ; - Point3d ptC ; pSfrClass->GetCentroid( ptC) ; - frLocXY.Set( ptC, pSfrClass->GetNormVersor()) ; + Point3d ptC ; pSfrCntLoc->GetCentroid( ptC) ; + if ( ! frLocXY.Set( ptC, pSfrCntLoc->GetNormVersor())) + return false ; // NB. Essendo una finitura a Z costante, devo controllare che i piani di finitura non facciano // overlap con facce delle TriMesh selezionate con normale simile a vtTool set setZAmbiguos ; - PtrOwner pSfrZCheck( CloneSurfFlatRegion( pSfrClass)) ; + PtrOwner pSfrZCheck( CloneSurfFlatRegion( pSfrCntLoc)) ; if ( IsNull( pSfrZCheck) || ! pSfrZCheck->IsValid() || ! GetZConstQuotesInsideSfrParallelToTool( vSrfLoc, frSurf, pSfrZCheck, vtTool, setZAmbiguos)) return false ; @@ -2896,7 +2906,7 @@ SurfFinishing::CalcZConstSilCrv( ICAvParSilhouettesSurfTm* pCavParSilh, const SU // calcolo la silhouette sui diversi piani for ( int nPlane = 1 ; nPlane * m_Params.m_dSideStep < dDepth + EPS_SMALL ; ++ nPlane) { // riservo lo spazio nel vettore delle curve - vCrvCompo.resize( vCrvCompo.size() + 1) ; + matCompo.resize( matCompo.size() + 1) ; // definisco la Zlocale per il calcolo della silhouette double dZLoc = - nPlane * m_Params.m_dSideStep ; for ( set::iterator it = setZAmbiguos.begin() ; it != setZAmbiguos.end() ; ++ it) { @@ -2911,14 +2921,14 @@ SurfFinishing::CalcZConstSilCrv( ICAvParSilhouettesSurfTm* pCavParSilh, const SU POLYLINEVECTOR vPLInsideSfr ; for ( PolyLine& PL : vPL) { // porto la PolyLine a contatto con la regione - PL.Translate( - dZLoc * pSfrClass->GetNormVersor()) ; + PL.Translate( - dZLoc * pSfrCntLoc->GetNormVersor()) ; // converto in curva composita PtrOwner pCrvPL( CreateCurveComposite()) ; if ( IsNull( pCrvPL) || ! pCrvPL->FromPolyLine( PL)) return false ; // classifico la curva con la superficie CRVCVECTOR ccClass ; - if ( ! pSfrClass->GetCurveClassification( *pCrvPL, EPS_SMALL, ccClass)) + if ( ! pSfrCntLoc->GetCurveClassification( *pCrvPL, EPS_SMALL, ccClass)) return false ; // tengo tutti i tratti non esterni alla superficie for ( int i = 0 ; i < ssize( ccClass) ; ++ i) { @@ -2927,14 +2937,14 @@ SurfFinishing::CalcZConstSilCrv( ICAvParSilhouettesSurfTm* pCavParSilh, const SU if ( ! IsNull( pCrvCompoPartIn) && pCrvCompoPartIn->IsValid()) { vPLInsideSfr.emplace_back( PolyLine()) ; // riporto la curva alla quota giusta - pCrvCompoPartIn->Translate( dZLoc * pSfrClass->GetNormVersor()) ; + pCrvCompoPartIn->Translate( dZLoc * pSfrCntLoc->GetNormVersor()) ; pCrvCompoPartIn->ApproxWithLines( 0, 0, ICurve::APL_SPECIAL, vPLInsideSfr.back()) ; } } } } swap( vPL, vPLInsideSfr) ; - for ( PolyLine& PL : vPL) { + for ( const PolyLine& PL : vPL) { // recupero la curva dalla silhouette PtrOwner pSilCrv( CreateCurveComposite()) ; if ( IsNull( pSilCrv)) @@ -2953,24 +2963,25 @@ SurfFinishing::CalcZConstSilCrv( ICAvParSilhouettesSurfTm* pCavParSilh, const SU pSilCrv.Set( pTempCrv) ; } SimplifyCurve( pSilCrv, frLocXY) ; - vCrvCompo.back().emplace_back( Release( pSilCrv)) ; + matCompo.back().emplace_back( Release( pSilCrv)) ; } // controllo validità delle curve - for ( int i = 0 ; i < ssize( vCrvCompo.back()) ; ++ i) - if ( vCrvCompo.back()[i] == nullptr || ! vCrvCompo.back()[i]->IsValid()) + for ( int i = 0 ; i < ssize( matCompo.back()) ; ++ i) { + if ( matCompo.back()[i] == nullptr || ! matCompo.back()[i]->IsValid()) return false ; + } // preparo i dati per il concatenamento bool bFirst = true ; Point3d ptNear = ORIG ; double dToler = 500. * EPS_SMALL ; ChainCurves chainC ; - chainC.Init( false, dToler, int( vCrvCompo.back().size())) ; - for ( int i = 0 ; i < ssize( vCrvCompo.back()) ; ++ i) { + chainC.Init( false, dToler, int( matCompo.back().size())) ; + for ( int i = 0 ; i < ssize( matCompo.back()) ; ++ i) { // recupero i dati della curva necessari al concatenamento e li assegno Point3d ptStart, ptEnd ; Vector3d vtStart, vtEnd ; - if ( ! vCrvCompo.back()[i]->GetStartPoint( ptStart) || ! vCrvCompo.back()[i]->GetStartDir( vtStart) || - ! vCrvCompo.back()[i]->GetEndPoint( ptEnd) || ! vCrvCompo.back()[i]->GetEndDir( vtEnd)) + if ( ! matCompo.back()[i]->GetStartPoint( ptStart) || ! matCompo.back()[i]->GetStartDir( vtStart) || + ! matCompo.back()[i]->GetEndPoint( ptEnd) || ! matCompo.back()[i]->GetEndDir( vtEnd)) return false ; if ( ! chainC.AddCurve( i + 1, ptStart, vtStart, ptEnd, vtEnd)) return false ; @@ -2993,7 +3004,7 @@ SurfFinishing::CalcZConstSilCrv( ICAvParSilhouettesSurfTm* pCavParSilh, const SU for ( int i = 0 ; i < ssize( vnInd) ; ++ i) { int nId = abs( vnInd[i]) - 1 ; // la aggiungo alla curva composta - if ( ! pCrvCompo->AddCurve( CloneCurveComposite( vCrvCompo.back()[nId]), true, dToler)) + if ( ! pCrvCompo->AddCurve( CloneCurveComposite( matCompo.back()[nId]), true, dToler)) return false ; } // aggiorno il nuovo punto vicino @@ -3002,23 +3013,27 @@ SurfFinishing::CalcZConstSilCrv( ICAvParSilhouettesSurfTm* pCavParSilh, const SU vCrvCompoChained.emplace_back( Release( pCrvCompo)) ; } } - swap( vCrvCompoChained, vCrvCompo.back()) ; + swap( vCrvCompoChained, matCompo.back()) ; // salvo lo Step come primo temp param della curva e inverto se necessario - for ( int i = 0 ; i < ssize( vCrvCompo.back()) ; ++ i) { - vCrvCompo.back()[i]->SetTempParam( - nPlane * m_Params.m_dSideStep, 0) ; + for ( int i = 0 ; i < ssize( matCompo.back()) ; ++ i) { + matCompo.back()[i]->SetTempParam( - nPlane * m_Params.m_dSideStep, 0) ; if ( m_Params.m_bInvert) - vCrvCompo.back()[i]->Invert() ; + matCompo.back()[i]->Invert() ; } // aggiorno la ProgressBar ExeProcessEvents( 40 + int( 40 / ( dDepth / max( 0.1, m_Params.m_dSideStep)) * ( nPlane - 1)), 0) ; } - // controllo la validità di tutte le curve trovate - for ( int i = 0 ; i < ssize( vCrvCompo) ; ++ i) { - for ( int j = 0 ; j < ssize( vCrvCompo[i]) ; ++ j) { - if ( vCrvCompo[i][j] == nullptr || ! vCrvCompo[i][j]->IsValid()) + // controllo la validità di tutte le curve trovate e le riporto in globale + for ( int i = 0 ; i < ssize( matCompo) ; ++ i) { + for ( int j = 0 ; j < ssize( matCompo[i]) ; ++ j) { + if ( matCompo[i][j] == nullptr || ! matCompo[i][j]->IsValid()) return false ; + matCompo[i][j]->ToGlob( frSurf) ; + #if 0 + m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, matCompo[i][j]->Clone()) ; + #endif } } @@ -3028,44 +3043,43 @@ SurfFinishing::CalcZConstSilCrv( ICAvParSilhouettesSurfTm* pCavParSilh, const SU //---------------------------------------------------------------------------- bool SurfFinishing::CreateZConstPaths( ICAvToolSurfTm* pCAvTlStm, const CISURFTMPVECTOR& vpStm, const Frame3d& frSurf, - vector& vCrvCompo, const Vector3d& vtTool, const ISurfFlatRegion* pSfr, - double dDepth, ICRVCOMPOPOVECTOR& vCrvPath) const + ICRVCOMPOPOMAT& MatCompo, const Vector3d& vtTool, const Vector3d& vtMove, + const ISurfFlatRegion* pSfrCnt, double dDepth, ICRVCOMPOPOVECTOR& vCrvPath) const { // funzione per collegare le curve trovate creando quindi i percorsi di lavoro - // NB. Nel primo TempParam deve essere memorizzata la distanza del piano della curva con il piano della Sfr + // NB. Nel primo TempParam deve essere memorizzata la distanza del piano della curva con il piano della pSfrCnt // controllo dei parametri - if ( pSfr == nullptr || ! pSfr->IsValid()) + if ( pSfrCnt == nullptr || ! pSfrCnt->IsValid()) return false ; - // porto il tool nel frame della superficie - Vector3d vtToolLoc = GetToLoc( vtTool, frSurf) ; - - // porto tutte le curve nel piano XY locale alla pSfr e, per ognuna di esse, definisco la regione - // piana di proiezione del materiale rimosso orientato a sinistra della curva - Frame3d frXY ; - Point3d ptCenter ; pSfr->GetCentroid( ptCenter) ; - if ( ! frXY.Set( ptCenter, vtToolLoc)) - return false ; - vector vSfrRemMatCol ; vSfrRemMatCol.resize( vCrvCompo.size()) ; // RemovedMaterialColumn - double dRadSignOffs = m_Params.m_bInvert ? m_TParams.m_dDiam / 2. : - m_TParams.m_dDiam / 2. ; #if ENABLE_ZCONST_PATH_DEBUG int nGrp = m_pGeomDB->AddGroup( GDB_ID_NULL, GDB_ID_ROOT, GLOB_FRM) ; m_pGeomDB->SetName( nGrp, "Crv & Sfr") ; m_pGeomDB->SetStatus( nGrp, GDB_ST_OFF) ; #endif - for ( int i = 0 ; i < ssize( vCrvCompo) ; ++ i) { - vSfrRemMatCol[i].resize( vCrvCompo[i].size()) ; - for ( int j = 0 ; j < ssize( vCrvCompo[i]) ; ++ j) { - // Frame locale XY - vCrvCompo[i][j]->ToLoc( frXY) ; - vCrvCompo[i][j]->SetExtrusion( m_Params.m_bInvert ? - Z_AX : Z_AX) ; + + // definisco la regione piana di interferenza per ordinare le curve di Silhouette + vector vSfrRMC ; vSfrRMC.resize( MatCompo.size()) ; // "Removed Material Column" + // definisco l'offset per l'ipotetica regione piana di interferenza + double dRadSignOffs = m_Params.m_bInvert ? m_TParams.m_dDiam / 2. : - m_TParams.m_dDiam / 2. ; + // scorro la matrice delle curve + for ( int i = 0 ; i < ssize( MatCompo) ; ++ i) { + vSfrRMC[i].resize( MatCompo[i].size()) ; + for ( int j = 0 ; j < ssize( MatCompo[i]) ; ++ j) { + // controllo che la curva sia valida, altrimenti passo alla successiva + if ( IsNull( MatCompo[i][j]) || ! MatCompo[i][j]->IsValid()) + continue ; + // imposto l'estrusione per il calcolo dell'offset + MatCompo[i][j]->SetExtrusion( m_Params.m_bInvert ? - vtTool : vtTool) ; + + // inizializzo la classe di calcolo della regione piana SurfFlatRegionByContours SfrBC ; // --- Se curva chiusa - if ( vCrvCompo[i][j]->IsClosed()) { - SfrBC.AddCurve( CloneCurveComposite( vCrvCompo[i][j])) ; + if ( MatCompo[i][j]->IsClosed()) { + SfrBC.AddCurve( CloneCurveComposite( MatCompo[i][j])) ; OffsetCurve OffsCrv ; - OffsCrv.Make( vCrvCompo[i][j], dRadSignOffs, ICurve::OFF_FILLET) ; + OffsCrv.Make( MatCompo[i][j], dRadSignOffs, ICurve::OFF_FILLET) ; PtrOwner pCrvIsl( OffsCrv.GetLongerCurve()) ; while ( ! IsNull( pCrvIsl)) { SfrBC.AddCurve( Release( pCrvIsl)) ; @@ -3075,58 +3089,60 @@ SurfFinishing::CreateZConstPaths( ICAvToolSurfTm* pCAvTlStm, const CISURFTMPVECT // --- Se curva aperta else { OffsetCurve OffsCrv ; - OffsCrv.Make( vCrvCompo[i][j], dRadSignOffs, ICurve::OFF_FILLET) ; - // [euristico, migliorabile/da_correggere] + OffsCrv.Make( MatCompo[i][j], dRadSignOffs, ICurve::OFF_FILLET) ; PtrOwner pCrvInt( OffsCrv.GetLongerCurve()) ; if ( ! IsNull( pCrvInt)) { pCrvInt->Invert() ; Point3d ptS ; pCrvInt->GetStartPoint( ptS) ; - Point3d ptE ; vCrvCompo[i][j]->GetStartPoint( ptE) ; + Point3d ptE ; MatCompo[i][j]->GetStartPoint( ptE) ; PtrOwner pSfrLoop( CreateCurveComposite()) ; if ( IsNull( pSfrLoop)) return false ; - pSfrLoop->AddCurve( CloneCurveComposite( vCrvCompo[i][j])) ; + pSfrLoop->AddCurve( CloneCurveComposite( MatCompo[i][j])) ; pSfrLoop->AddLine( ptS) ; pSfrLoop->AddCurve( Release( pCrvInt)) ; pSfrLoop->AddLine( ptE) ; SfrBC.AddCurve( Release( pSfrLoop)) ; } } - vSfrRemMatCol[i][j].Set( SfrBC.GetSurf()) ; - if ( IsNull( vSfrRemMatCol[i][j]) || ! vSfrRemMatCol[i][j]->IsValid()) - vSfrRemMatCol[i][j].Set( GetSurfFlatRegionFromFatCurve( vCrvCompo[i][j]->Clone(), m_TParams.m_dDiam / 2., false, false)) ; - // tutte rivolte come Z_AX ( vtTool locale) - if ( AreOppositeVectorApprox( vSfrRemMatCol[i][j]->GetNormVersor(), Z_AX)) - vSfrRemMatCol[i][j]->Invert() ; + + // definisco la regione rimossa + vSfrRMC[i][j].Set( SfrBC.GetSurf()) ; + if ( IsNull( vSfrRMC[i][j]) || ! vSfrRMC[i][j]->IsValid()) + vSfrRMC[i][j].Set( GetSurfFlatRegionFromFatCurve( MatCompo[i][j]->Clone(), m_TParams.m_dDiam / 2., false, false)) ; // caso limite + if ( AreOppositeVectorApprox( vSfrRMC[i][j]->GetNormVersor(), Z_AX)) + vSfrRMC[i][j]->Invert() ; + #if ENABLE_ZCONST_PATH_DEBUG Color myCol = Color( double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, 1.) ; int nLay = m_pGeomDB->AddGroup( GDB_ID_NULL, nGrp, GLOB_FRM) ; - m_pGeomDB->SetName( nLay, ToString( vCrvCompo[i][j]->GetTempParam( 0))) ; - int nId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLay, vCrvCompo[i][j]->Clone()) ; + m_pGeomDB->SetName( nLay, ToString( MatCompo[i][j]->GetTempParam( 0))) ; + int nId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLay, MatCompo[i][j]->Clone()) ; m_pGeomDB->SetMaterial( nId, myCol) ; - nId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLay, vSfrRemMatCol[i][j]->Clone()) ; + nId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLay, vSfrRMC[i][j]->Clone()) ; myCol.SetAlpha( .25) ; m_pGeomDB->SetMaterial( nId, myCol) ; #endif } } - // definisco le relazioni delle curve mediante le superfici create - int nRowSize = int( vCrvCompo.size()) ; + // definisco le relazioni delle curve mediante le superfici create. Due curve sono tra loro in relazione se le regioni ipotetiche + // di interferenza di intersecano tra di loro. In caso di intersezione bisogna definire quale delle due curve deve necessariamente + // essere inserita prima nel percorso di lavorazione + int nRowSize = ssize( MatCompo) ; int nColSize = 0 ; for ( int i = 0 ; i < nRowSize ; ++ i) - nColSize = max( nColSize, int( vCrvCompo[i].size())) ; - unordered_map MapLock ; - unordered_map MapUnlock ; - for ( int nR = ssize( vCrvCompo) - 1 ; nR >= 1 ; -- nR) { - for ( int nC = 0 ; nC < ssize( vCrvCompo[nR]) ; ++ nC) { - for ( int nCol = 0 ; nCol < ssize( vCrvCompo[nR - 1]) ; ++ nCol) { - PtrOwner pSfrCheck( CloneSurfFlatRegion( vSfrRemMatCol[nR][nC])) ; + nColSize = max( nColSize, int( ssize( MatCompo[i]))) ; + unordered_map MapLock, MapUnlock ; + for ( int nR = ssize( MatCompo) - 1 ; nR >= 1 ; -- nR) { + for ( int nC = 0 ; nC < ssize( MatCompo[nR]) ; ++ nC) { + for ( int nCol = 0 ; nCol < ssize( MatCompo[nR - 1]) ; ++ nCol) { + PtrOwner pSfrCheck( CloneSurfFlatRegion( vSfrRMC[nR][nC])) ; if ( ! IsNull( pSfrCheck)) { - pSfrCheck->Intersect( *vSfrRemMatCol[nR - 1][nCol]) ; + pSfrCheck->Intersect( *vSfrRMC[nR - 1][nCol]) ; if ( pSfrCheck->IsValid() && pSfrCheck->GetChunkCount() > 0) { - int nKeyLock = nR * nColSize + nC ; - int nKeyUnLock = ( nR - 1) * nColSize + nCol ; + int nKeyLock = nR * nColSize + nC, + nKeyUnLock = ( nR - 1) * nColSize + nCol ; MapLock[nKeyLock].emplace_back( make_pair( nR - 1, nCol)) ; MapUnlock[nKeyUnLock].emplace_back( make_pair( nR, nC)) ; } @@ -3135,9 +3151,8 @@ SurfFinishing::CreateZConstPaths( ICAvToolSurfTm* pCAvTlStm, const CISURFTMPVECT } } - // definisco i gruppi di curve indpendenti; Un insieme di curve risulta indipendente da un altro - // insieme se l'ordine di esecuzione di essi è indifferente ; - // [non esiste alcuna curva nel gruppo A che interferisce con una curva del gruppo B) + // definisco i gruppi di curve indpendenti; Un insieme di curve risulta indipendente da un altro insieme se l'ordine di esecuzione + // di essi è indifferente. [non esiste alcuna curva nel gruppo A che interferisce con una curva del gruppo B) vector vIndependentCurveGroup ; bool bGroup = true ; int nCont = 0 ; @@ -3145,11 +3160,11 @@ SurfFinishing::CreateZConstPaths( ICAvToolSurfTm* pCAvTlStm, const CISURFTMPVECT ++ nCont ; bGroup = false ; // cerco la prima curva non ancora inserita in un gruppo - for ( int nR = ssize( vCrvCompo) - 1 ; nR >= 0 && ! bGroup ; -- nR) { + for ( int nR = ssize( MatCompo) - 1 ; nR >= 0 && ! bGroup ; -- nR) { // scorro sulle colonne ( dalla prima all'ultima) [ordine casuale] - for ( int nC = 0 ; nC < ssize( vCrvCompo[nR]) && ! bGroup ; ++ nC) { + for ( int nC = 0 ; nC < ssize( MatCompo[nR]) && ! bGroup ; ++ nC) { // se la curva attuale già in un gruppo ( quindi nullptr), passo alla successiva - if ( vCrvCompo[nR][nC] == nullptr) + if ( MatCompo[nR][nC] == nullptr) continue ; // se trovo una curva, allora ho un nuovo gruppo da analizzare bGroup = true ; @@ -3164,7 +3179,7 @@ SurfFinishing::CreateZConstPaths( ICAvToolSurfTm* pCAvTlStm, const CISURFTMPVECT // tolgo l'elemento ( non devo ricontrollarlo all'iterazione successiva) vMapIndCheck.pop_back() ; // aggiungo la curva al percorso corrente - vIndependentCurveGroup.back().emplace_back( Release( vCrvCompo[nCurrRow][nCurrCol])) ; + vIndependentCurveGroup.back().emplace_back( Release( MatCompo[nCurrRow][nCurrCol])) ; // --- se la curva non è bloccata da nessun'altra auto itLock = MapLock.find( nCurrRow * nColSize + nCurrCol) ; if ( itLock == MapLock.end()) { @@ -3181,7 +3196,7 @@ SurfFinishing::CreateZConstPaths( ICAvToolSurfTm* pCAvTlStm, const CISURFTMPVECT // verifico che non ci siano altre curve bloccate bool bLock = false ; for ( int j = 0 ; j < ssize( itUnLock->second) && ! bLock ; ++ j) - bLock = ( vCrvCompo[itUnLock->second[j].first][itUnLock->second[j].second] != nullptr) ; + bLock = ( MatCompo[itUnLock->second[j].first][itUnLock->second[j].second] != nullptr) ; if ( ! bLock) vMapIndCheck.emplace_back( Key) ; } @@ -3192,7 +3207,7 @@ SurfFinishing::CreateZConstPaths( ICAvToolSurfTm* pCAvTlStm, const CISURFTMPVECT } #if ENABLE_ZCONST_PATH_DEBUG - nGrp = m_pGeomDB->AddGroup( GDB_ID_NULL, GDB_ID_ROOT, GLOB_FRM) ; + int nGrp = m_pGeomDB->AddGroup( GDB_ID_NULL, GDB_ID_ROOT, GLOB_FRM) ; m_pGeomDB->SetName( nGrp, "Independent Groups") ; m_pGeomDB->SetStatus( nGrp, GDB_ST_OFF) ; vector vCol ; @@ -3209,17 +3224,12 @@ SurfFinishing::CreateZConstPaths( ICAvToolSurfTm* pCAvTlStm, const CISURFTMPVECT } #endif - // definisco il piano locale della regione piana ( frXY è centrato su di essa) - Plane3d plProjection ; - if ( ! plProjection.Set( ORIG, Z_AX)) - return false ; - // ordino i gruppi di curve indipendenti typedef pair> INTDBLDBL ; // > vector vMapGrpZLoc ; vMapGrpZLoc.reserve( vIndependentCurveGroup.size()) ; for ( int i = 0 ; i < ssize( vIndependentCurveGroup) ; ++ i) { - // scorro le curve del gruppo cercando quella più in alto ( rispetto alla Zlocale di frXY) + // scorro le curve del gruppo cercando quella più in alto (rispetto alla Zlocale di frXY) double dZMax = - INFINITO ; double dZMin = INFINITO ; for ( auto& pCrv : vIndependentCurveGroup[i]) { @@ -3253,64 +3263,127 @@ SurfFinishing::CreateZConstPaths( ICAvToolSurfTm* pCAvTlStm, const CISURFTMPVECT } #endif - // tengo una copia dei bordi della regione ( servono per limitare i collegamenti tra le curve dei Path) - PtrOwner pSfrClass( CloneSurfFlatRegion( pSfr)) ; - if ( IsNull( pSfrClass) || ! pSfrClass->IsValid() || ! pSfrClass->ToLoc( frXY)) + // tengo una copia dei bordi della regione (servono per limitare i collegamenti tra le curve dei Path) + // NB. per la classificazione si usa sempre la regione, tengo però in memoria le curve di bordo in modo che, se alcuni percorsi + // si estendono al di fuori, questi possono essere trimmati e raccordati con i bordi della regione. Invece di chidere alla SurfFlatRegion + // i bordi ogni volta, tengo una loro copia e uso sempre quella per il trim e il raccordo. + ICRVCOMPOPOVECTOR vCrvCnt ; + PtrOwner pMySfrCnt( pSfrCnt->CreateOffsetSurf( 10. * EPS_SMALL, ICurve::OFF_FILLET)) ; + if ( IsNull( pMySfrCnt) || ! pMySfrCnt->IsValid()) return false ; - ICRVCOMPOPOVECTOR vCrvSfrLoops ; - for ( int nC = 0 ; nC < pSfrClass->GetChunkCount() ; ++ nC) { - for ( int nL = 0 ; nL < pSfrClass->GetLoopCount( nC) ; ++ nL) { - PtrOwner pCrvLoop( ConvertCurveToComposite( pSfrClass->GetLoop( nC, nL))) ; + for ( int nC = 0 ; nC < pMySfrCnt->GetChunkCount() ; ++ nC) { + for ( int nL = 0 ; nL < pMySfrCnt->GetLoopCount( nC) ; ++ nL) { + PtrOwner pCrvLoop( ConvertCurveToComposite( pMySfrCnt->GetLoop( nC, nL))) ; if ( IsNull( pCrvLoop) || ! pCrvLoop->IsValid()) return false ; - // tutti i loop sono orientati come il loop esterno - // NB. Per classificare i collegamenti si usa la regione, non queste curve ! - // [ Vengono utilizzate per non inizializzare ogni volta una curva corrispondente al bordo - // della superficie di classificazione] if ( nL > 0) pCrvLoop->Invert() ; - vCrvSfrLoops.emplace_back( Release( pCrvLoop)) ; + vCrvCnt.emplace_back( ::Release( pCrvLoop)) ; } } - // porto tutte le regioni nel frame locale XY per la verifica di collegamenti verticali - CISURFTMPVECTOR vpStmLoc ; vpStmLoc.reserve( vpStm.size()) ; - for ( int i = 0 ; i < ssize( vpStm) ; ++ i) { - PtrOwner pStmLoc( CloneSurfTriMesh( vpStm[i])) ; - if ( ! IsNull( pStmLoc) && pStmLoc->IsValid() && pStmLoc->GetTriangleCount() > 0) { - pStmLoc->ToLoc( frXY) ; - vpStmLoc.emplace_back( ::Release( pStmLoc)) ; - #if 0 - m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, vpStmLoc[i]->Clone()) ; - #endif - } - } - - // definisco i collegamenti tra i percorsi - #if ENABLE_ZCONST_PATH_DEBUG - nGrp = m_pGeomDB->AddGroup( GDB_ID_NULL, GDB_ID_ROOT, GLOB_FRM) ; + #if ENABLE_ZCONST_PATH_DEBUG or ENABLE_ZCONST_LINK_DEBUG + int nGrp = m_pGeomDB->AddGroup( GDB_ID_NULL, GDB_ID_ROOT, GLOB_FRM) ; m_pGeomDB->SetName( nGrp, "Paths") ; m_pGeomDB->SetStatus( nGrp, GDB_ST_OFF) ; #endif - const double LINK_TOL = 25. * EPS_SMALL ; - Point3d ptRef = P_INVALID ; - for ( int i = 0 ; i < ssize( vMapGrpZLoc) ; ++ i) { + + // definisco ora il piano di proiezione definito dal versore di movimento (normale della regione pMySfrCnt) + Plane3d plProjection ; + if ( ! plProjection.Set( ORIG, vtMove)) + return false ; + + #if 0 + int a = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pMySfrCnt->Clone()) ; + m_pGeomDB->SetMaterial( a, FUCHSIA) ; + #endif + + // ----------------------------------------------------------- + struct CurveInfo { + int nInd ; + double dLen ; + CurveInfo( int nI, double dL) + : nInd( nI), dLen( dL) {} ; + } ; + auto ChangeZConstStartPoint = [&]( int nPath, int nCrv) { + // Controllo di validità su indici e puntatore + if ( nPath < 0 || nPath >= ssize( vIndependentCurveGroup) || nCrv < 0 || nCrv >= ssize( vIndependentCurveGroup[nPath])) + return false ; + // recupero la curva + ICurveComposite* pCompo = vIndependentCurveGroup[nPath][nCrv] ; + if ( pCompo == nullptr || ! pCompo->IsValid()) + return false ; + // se la curva è aperta, non faccio nulla + if ( ! pCompo->IsClosed()) + return true ; + // se la curva è chiusa + vector vArcInfo, vLineInfo ; + for ( int i = 0 ; i < pCompo->GetCurveCount() ; ++ i) { + // recupero la curva corrente + const ICurve* pCrv = pCompo->GetCurve( i) ; + if ( pCrv == nullptr || ! pCrv->IsValid()) + continue ; + // determino le informazioni + int nType = pCrv->GetType() ; + double dLen ; pCrv->GetLength( dLen) ; + if ( nType == CRV_ARC) + vArcInfo.emplace_back( i, dLen) ; + else + vLineInfo.emplace_back( i, dLen) ; + } + // controllo di avere qualcosa + if ( vLineInfo.empty() && vArcInfo.empty()) + return false ; + // ordino i tratti lineari per lunghezza + sort( vLineInfo.begin(), vLineInfo.end(), []( const CurveInfo& A, const CurveInfo& B) { return ( A.dLen > B.dLen) ; }) ; + // cerco il tratto lineare più lungo ed entro da quello + for ( int i = 0 ; i < ssize( vLineInfo) ; ++ i) { + if ( vLineInfo[i].dLen > m_TParams.m_dDiam + 50. * EPS_SMALL) { + pCompo->ChangeStartPoint( double( vLineInfo[i].nInd) + 0.5) ; + return true ; + } + else + break ; + } + // stesso ragionamento ma con gli archi + sort( vArcInfo.begin(), vArcInfo.end(), []( const CurveInfo& A, const CurveInfo& B) { return ( A.dLen > B.dLen) ; }) ; + // cerco il tratto lineare più lungo ed entro da quello + for ( int i = 0 ; i < ssize( vArcInfo) ; ++ i) { + if ( vArcInfo[i].dLen > m_TParams.m_dDiam + 50. * EPS_SMALL) { + pCompo->ChangeStartPoint( double( vArcInfo[i].nInd) + 0.5) ; + return true ; + } + else + break ; + } + // prendo il tratto più lungo + if ( vArcInfo.empty() || ( ! vLineInfo.empty() && vArcInfo[0].dLen < vLineInfo[0].dLen)) { + pCompo->ChangeStartPoint( double( vLineInfo[0].nInd) + 0.5) ; + return true ; + } + pCompo->ChangeStartPoint( double( vArcInfo[0].nInd) + 0.5) ; + return true ; + } ; + // ----------------------------------------------------------- + + // definisco i collegamenti tra i percorsi + const double LINK_TOL = 25. * EPS_SMALL ; + Point3d ptRef = P_INVALID ; + for ( int i = 0 ; i < ssize( vMapGrpZLoc) ; ++ i) { // recupero l'indice ordinato del percorso int nPath = vMapGrpZLoc[i].first ; // inverto il vettore delle curve di bordo del percorso corrente reverse( vIndependentCurveGroup[nPath].begin(), vIndependentCurveGroup[nPath].end()) ; // definisco il vettore dei collegamenti creati tra le curve - // NB. Un collegamento potrebbe non essere valido e non realizzabile + // NB. Un collegamento potrebbe non essere valido e non realizzabile (inizializzato come nullptr) // NB. Il collegamento i-esimo collega la curva di bordo (i-1)-esima con la curva di bordo i-esima - ICRVCOMPOPOVECTOR vCompoLink ; - vCompoLink.resize( vIndependentCurveGroup[nPath].size()) ; // nullptr per ogni Link + ICRVCOMPOPOVECTOR vCompoLink ; vCompoLink.resize( vIndependentCurveGroup[nPath].size()) ; // --- se non ho curve, passo al gruppo successivo if ( vIndependentCurveGroup[nPath].empty()) continue ; - // --- se ho una sola curva, allora controllo se posso cambiare il suo punto d'inizio - // nel caso non sia la prima in assoluto [ -> controllo ptRef] + // --- se ho una sola curva, allora controllo se posso cambiare il suo punto d'inizio nel caso non sia la prima in assoluto if ( ssize( vIndependentCurveGroup[nPath]) == 1) { if ( ptRef.IsValid()) { // --- se la curva di bordo singola è aperta @@ -3324,17 +3397,22 @@ SurfFinishing::CreateZConstPaths( ICAvToolSurfTm* pCAvTlStm, const CISURFTMPVECT } // --- se la curva di bordo singola è chiusa else { - // cerco il punto a minima distanza da ptRef ( non inverto, tengo il senso di lavorazione) + // cerco il punto a minima distanza da ptRef (non inverto, tengo il senso di lavorazione) double dMinPar = 0. ; int nFlag = 0 ; DistPointCurve( ptRef, *vIndependentCurveGroup[nPath][0]).GetParamAtMinDistPoint( 0., dMinPar, nFlag) ; vIndependentCurveGroup[nPath][0]->ChangeStartPoint( dMinPar) ; } } + else { + if ( ! ChangeZConstStartPoint( nPath, 0)) + return false ; + } // inserisco la curva nel percorso vCrvPath.emplace_back( Release( vIndependentCurveGroup[nPath][0])) ; // aggiorno il punto di riferimento vCrvPath.back()->GetEndPoint( ptRef) ; + #if ENABLE_ZCONST_PATH_DEBUG int nLay = m_pGeomDB->AddGroup( GDB_ID_NULL, nGrp, GLOB_FRM) ; m_pGeomDB->SetName( nLay, "Single") ; @@ -3342,16 +3420,18 @@ SurfFinishing::CreateZConstPaths( ICAvToolSurfTm* pCAvTlStm, const CISURFTMPVECT int nId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLay, CloneCurveComposite( vCrvPath.back())) ; m_pGeomDB->SetMaterial( nId, myCol) ; #endif - continue ; + + continue ; // !<-- } // --- se ho più curve di bordo, scorro le curve a due a due per creare i collegamenti for ( int nCompo = 0 ; nCompo < ssize( vIndependentCurveGroup[nPath]) - 1 ; ++ nCompo) { + // se prima curva di bordo e ho un punto di riferimento valido if ( nCompo == 0 && ptRef.IsValid()) { - // --- se la prima curva di bordo è aperta + // --- se la prima curva di bordo è aperta con un riferimento valido if ( ! vIndependentCurveGroup[nPath][0]->IsClosed()) { - // ... se necessario la inverto per recuperare l'estremo più vicino a ptRef + // se necessario la inverto per recuperare l'estremo più vicino a ptRef // [ per ora le curve aperte possono essere invertite nelle finiture a ZLevel] Point3d ptS ; vIndependentCurveGroup[nPath][0]->GetStartPoint( ptS) ; Point3d ptE ; vIndependentCurveGroup[nPath][0]->GetEndPoint( ptE) ; @@ -3367,11 +3447,17 @@ SurfFinishing::CreateZConstPaths( ICAvToolSurfTm* pCAvTlStm, const CISURFTMPVECT vIndependentCurveGroup[nPath][0]->ChangeStartPoint( dMinPar) ; } } + else if ( nCompo == 0) { + if ( ! ChangeZConstStartPoint( nPath, 0)) + return false ; + } + // come riferimento imposto inizialmente il punto finale della curva corrente vIndependentCurveGroup[nPath][nCompo]->GetEndPoint( ptRef) ; - // --- se la curva di bordo successiva è aperta... + + // --- se la curva di bordo successiva è aperta if ( ! vIndependentCurveGroup[nPath][nCompo + 1]->IsClosed()) { - // ... se necessario la inverto per recuperare l'estremo più vicino a quello corrente + // se necessario la inverto per recuperare l'estremo più vicino a quello corrente // [ per ora le curve aperte possono essere invertite nelle finiture a ZLevel] Point3d ptS ; vIndependentCurveGroup[nPath][nCompo + 1]->GetStartPoint( ptS) ; Point3d ptE ; vIndependentCurveGroup[nPath][nCompo + 1]->GetEndPoint( ptE) ; @@ -3380,7 +3466,7 @@ SurfFinishing::CreateZConstPaths( ICAvToolSurfTm* pCAvTlStm, const CISURFTMPVECT } // --- se la curva successiva è chiusa else { - // cerco il punto a minima distanza ( non inverto, tengo il senso di lavorazione) + // cerco il punto a minima distanza (non inverto, tengo il senso di lavorazione) double dMinPar = 0. ; int nFlag = 0 ; DistPointCurve( ptRef, *vIndependentCurveGroup[nPath][nCompo + 1]).GetParamAtMinDistPoint( 0., dMinPar, nFlag) ; @@ -3392,61 +3478,68 @@ SurfFinishing::CreateZConstPaths( ICAvToolSurfTm* pCAvTlStm, const CISURFTMPVECT Point3d ptEndLink ; vIndependentCurveGroup[nPath][nCompo + 1]->GetStartPoint( ptEndLink) ; PtrOwner pLineLink( CreateCurveLine()) ; if ( IsNull( pLineLink) || ! pLineLink->Set( ptStartLink, ptEndLink) || ! pLineLink->IsValid()) - continue ; // il Link rimane nullptr + continue ; // il Link rimane nullptr (-> retroazione) - // !<--- se il Link è parallelo a vtTool ( Z_AX in locale), allora scendo verticalmente + // se il Link è parallelo a vtMove, allora la sua proiezione è automaticamente all'interno della regione di classificazione + // e non vi è la necessità di controllare che il tratto lineare rovini le superfici di collisione Vector3d vtDirLink ; pLineLink->GetStartDir( vtDirLink) ; - if ( AreSameOrOppositeVectorEpsilon( vtDirLink, Z_AX, 100. * EPS_SMALL)) { - // la proiezione del Link è automaticamente all'interno della superficie di classificazione - vCompoLink[nCompo + 1].Set( ConvertCurveToComposite( Release( pLineLink))) ; - } + if ( AreSameOrOppositeVectorEpsilon( vtDirLink, vtMove, 100. * EPS_SMALL)) + vCompoLink[nCompo + 1].Set( ConvertCurveToComposite( ::Release( pLineLink))) ; + // se il Link non è parallelo a vtMove else { - // !<--- se il tratto lineare è troppo lungo, non considero il collegamento come valido - if ( SqDist( ptStartLink, ptEndLink) > 4. * m_TParams.m_dDiam * m_TParams.m_dDiam) - continue ; // il Link rimane nullptr - // proietto la curva nel piano locale della superficie di classificazione ( Z=0 ; Z_AX) + // se il tratto lineare è troppo lungo, non considero il collegamento come valido + if ( SqDist( ptStartLink, ptEndLink) > 4. * m_TParams.m_dDiam * m_TParams.m_dDiam) + continue ; // il Link rimane nullptr (-> retroazione) + // proietto la curva nel piano locale della superficie di classificazione PtrOwner pLineLinkProj( ProjectCurveOnPlane( *pLineLink, plProjection)) ; if ( IsNull( pLineLinkProj) || ! pLineLinkProj->IsValid()) - return false ; + continue ; // il Link rimane nullptr (-> retroazione) + + #if 0 + int a = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pLineLinkProj->Clone()) ; + m_pGeomDB->SetMaterial( a, YELLOW) ; + #endif // effettuo la classificazione CRVCVECTOR ccClass ; - if ( ! pSfrClass->GetCurveClassification( *pLineLinkProj, EPS_SMALL, ccClass)) - continue ; // il Link rimane nullptr + if ( ! pMySfrCnt->GetCurveClassification( *pLineLinkProj, EPS_SMALL, ccClass)) + continue ; // il Link rimane nullptr (-> retroiazione) // inizializzo il link come curva vuota e scorro le classificazioni ottenute - vCompoLink[nCompo + 1].Set( CreateCurveComposite()) ; + if ( ! vCompoLink[nCompo + 1].Set( CreateCurveComposite())) + return false ; for ( int i = 0 ; i < ssize( ccClass) ; ++ i) { // recupero il tratto di curva corrente PtrOwner pSubCrv( pLineLinkProj->CopyParamRange( ccClass[i].dParS, ccClass[i].dParE)) ; - if ( IsNull( pSubCrv) || ! pSubCrv->IsValid()) // troppo piccolo... - continue ; // passo al tratto di classificazione successivo + if ( IsNull( pSubCrv) || ! pSubCrv->IsValid()) + continue ; // passo al tratto di classificazione successivo (potrebbe essere troppo piccolo) + // --- se la curva non è esterna alla regione, la conservo if ( ccClass[i].nClass != CRVC_OUT) { - if ( ! vCompoLink[nCompo + 1]->AddCurve( Release( pSubCrv), true, LINK_TOL)) + if ( ! vCompoLink[nCompo + 1]->AddCurve( ::Release( pSubCrv), true, LINK_TOL)) return false ; } // --- se la curva è esterna, devo seguire il bordo della regione di classificazione else { + // recupero gli estremi del segmento di classificazione esterno alla pSfrClass Point3d ptStartOnSfr ; pLineLinkProj->GetPointD1D2( ccClass[i].dParS, ICurve::FROM_MINUS, ptStartOnSfr) ; Point3d ptEndOnSfr ; pLineLinkProj->GetPointD1D2( ccClass[i].dParE, ICurve::FROM_MINUS, ptEndOnSfr) ; - // scorro tutti i loop della regione di classificazione - for ( int j = 0 ; j < ssize( vCrvSfrLoops) ; ++ j) { + + // scorro tutti i loop di pSfrCnt (memorizzati in precedenza) + for ( int j = 0 ; j < ssize( vCrvCnt) ; ++ j) { // se i punti trovati sono sul loop corrente - if ( vCrvSfrLoops[j]->IsPointOn( ptStartOnSfr, LINK_TOL) && - vCrvSfrLoops[j]->IsPointOn( ptEndOnSfr, LINK_TOL)) { + if ( vCrvCnt[j]->IsPointOn( ptStartOnSfr, LINK_TOL) && vCrvCnt[j]->IsPointOn( ptEndOnSfr, LINK_TOL)) { // devo orientare la SubCrv secondo il giusto verso di percorrenza - double dUS ; vCrvSfrLoops[j]->GetParamAtPoint( ptStartOnSfr, dUS, LINK_TOL) ; - double dUE ; vCrvSfrLoops[j]->GetParamAtPoint( ptEndOnSfr, dUE, LINK_TOL) ; - PtrOwner pCrvA( ( vCrvSfrLoops[j]->CopyParamRange( dUS, dUE))) ; - PtrOwner pCrvB( ( vCrvSfrLoops[j]->CopyParamRange( dUE, dUS))) ; - double dLenA = INFINITO ; double dLenB = INFINITO ; + double dUS ; vCrvCnt[j]->GetParamAtPoint( ptStartOnSfr, dUS, LINK_TOL) ; + double dUE ; vCrvCnt[j]->GetParamAtPoint( ptEndOnSfr, dUE, LINK_TOL) ; + PtrOwner pCrvA( ( vCrvCnt[j]->CopyParamRange( dUS, dUE))), + pCrvB( ( vCrvCnt[j]->CopyParamRange( dUE, dUS))) ; + double dLenA = INFINITO, dLenB = INFINITO ; if ( ! IsNull( pCrvA) && pCrvA->IsValid()) pCrvA->GetLength( dLenA) ; if ( ! IsNull( pCrvB) && pCrvB->IsValid()) { - // sempre percorsa in senso opposto pCrvB->Invert() ; pCrvB->GetLength( dLenB) ; } @@ -3459,58 +3552,87 @@ SurfFinishing::CreateZConstPaths( ICAvToolSurfTm* pCAvTlStm, const CISURFTMPVECT } // se il link trovato non è valido, passo al successivo if ( ! vCompoLink[nCompo + 1]->IsValid()) - continue ; // il link rimane inizializzato e non valido ( 0 curve) + continue ; // il link rimane inizializzato e non valido - // !<-- ripristino la forma del loop tra inizio e fine + // ripristino il nuovo loop Point3d ptS ; vCompoLink[nCompo + 1]->GetStartPoint( ptS) ; vCompoLink[nCompo + 1]->Translate( ptStartLink - ptS) ; - vCompoLink[nCompo + 1]->SetExtrusion( Z_AX) ; - double dNini = ( ptStartLink - ORIG) * Z_AX ; - double dNfin = ( ptEndLink - ORIG) * Z_AX ; + vCompoLink[nCompo + 1]->SetExtrusion( vtMove) ; + double dNini = ( ptStartLink - ORIG) * vtMove ; + double dNfin = ( ptEndLink - ORIG) * vtMove ; AdjustCurveSlope( vCompoLink[nCompo + 1], dNini, dNfin) ; + PtrOwner pCompoLinkInitial( CloneCurveComposite( vCompoLink[nCompo + 1])) ; + + // verifico se il Link è aderente ad una parete verticale, in caso positivo, modifico il Link corrente + if ( ! CalcZConstLink( vCompoLink[nCompo + 1], ptStartLink, ptEndLink, pCAvTlStm, frSurf, vtTool, vtMove, dDepth, vpStm, true)) + return false ; + // se sono all'interno della regione, allora lo conservo + if ( ! IsNull( vCompoLink[nCompo + 1]) && vCompoLink[nCompo + 1]->IsValid()) { + PtrOwner pLinkProj( ProjectCurveOnPlane( *vCompoLink[nCompo + 1], plProjection)) ; + if ( IsNull( pLinkProj) || ! pLinkProj->IsValid()) + vCompoLink[nCompo + 1].Reset() ; + else { + CRVCVECTOR ccClass ; + if ( ! pMySfrCnt->GetCurveClassification( *pLinkProj, EPS_SMALL, ccClass)) + continue ; + bool bRecalcLink = false ; + for ( int j = 0 ; ! bRecalcLink && j < ssize( ccClass) ; ++ j) + bRecalcLink = ( ccClass[j].nClass == CRVC_OUT) ; + if ( bRecalcLink) { + if ( ! CalcZConstLink( pCompoLinkInitial, ptStartLink, ptEndLink, pCAvTlStm, frSurf, vtTool, vtMove, dDepth, vpStm, false)) + return false ; + vCompoLink[nCompo + 1].Set( ::Release( pCompoLinkInitial)) ; + } + } + } + #if 0 int nId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, vCompoLink[nCompo + 1]->Clone()) ; - m_pGeomDB->SetMaterial( nId, RED) ; + m_pGeomDB->SetMaterial( nId, FUCHSIA) ; #endif - // verifico se il Link è aderente ad una parete verticale, in caso positivo, modifico il Link corrente - if ( ! CalcZConstLink( vCompoLink[nCompo + 1], ptStartLink, ptEndLink, pCAvTlStm, frXY, frSurf, Z_AX, dDepth, vpStmLoc)) - return false ; + } + + if ( nCompo == ssize( vIndependentCurveGroup[nPath]) - 2) + ptRef = P_INVALID ; } // calcolo il percorso unendo le curve di bordo con i Link ricavati const double PATH_TOL = 1500. * EPS_SMALL ; + #if ENABLE_ZCONST_PATH_DEBUG - int nLay = GDB_ID_NULL ; - Color myCol = INVISIBLE ; + int nLay = GDB_ID_NULL ; Color myCol = INVISIBLE ; #endif + for ( int nCompo = 0 ; nCompo < ssize( vIndependentCurveGroup[nPath]) ; ++ nCompo) { if ( IsNull( vCompoLink[nCompo]) || ! vCompoLink[nCompo]->IsValid()) { + #if ENABLE_ZCONST_PATH_DEBUG nLay = m_pGeomDB->AddGroup( GDB_ID_NULL, nGrp, GLOB_FRM) ; myCol = Color( double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, 1.) ; #endif + if ( ! vCrvPath.emplace_back( CreateCurveComposite())) return false ; } else { + #if ENABLE_ZCONST_PATH_DEBUG int nId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLay, CloneCurveComposite( vCompoLink[nCompo])) ; m_pGeomDB->SetMaterial( nId, myCol) ; #endif - vCrvPath.back()->AddCurve( Release( vCompoLink[nCompo]), true, PATH_TOL) ; + + vCrvPath.back()->AddCurve( ::Release( vCompoLink[nCompo]), true, PATH_TOL) ; } + #if ENABLE_ZCONST_PATH_DEBUG int nId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLay, CloneCurveComposite( vIndependentCurveGroup[nPath][nCompo])) ; m_pGeomDB->SetMaterial( nId, myCol) ; #endif - vCrvPath.back()->AddCurve( Release( vIndependentCurveGroup[nPath][nCompo]), true, PATH_TOL) ; - } - } - // riporto i percorsi nel frame originale - for ( int i = 0 ; i < ssize( vCrvPath) ; ++ i) - vCrvPath[i]->ToGlob( frXY) ; + vCrvPath.back()->AddCurve( ::Release( vIndependentCurveGroup[nPath][nCompo]), true, PATH_TOL) ; + } + } return true ; } @@ -3518,86 +3640,110 @@ SurfFinishing::CreateZConstPaths( ICAvToolSurfTm* pCAvTlStm, const CISURFTMPVECT //---------------------------------------------------------------------------- bool SurfFinishing::CalcZConstLink( ICurveComposite* pCompoLink, const Point3d& ptStartLink, const Point3d& ptEndLink, ICAvToolSurfTm* pCAvTlStm, - const Frame3d& frPocket, const Frame3d& frSurf, const Vector3d& vtTool, double dDepth, - const CISURFTMPVECTOR& vpStm) const + const Frame3d& frSurf, const Vector3d& vtTool, const Vector3d& vtMove, double dDepth, + const CISURFTMPVECTOR& vpStm, bool bAllowMove) const { // verifica dei parametri in ingresso if ( pCompoLink == nullptr || ! pCompoLink->IsValid() || - ! ptStartLink.IsValid() || ! ptEndLink.IsValid() || ! vtTool.IsValid() || - pCAvTlStm == nullptr || ! frPocket.IsValid() || ! frSurf.IsValid() || ! vtTool.IsValid()) + ! ptStartLink.IsValid() || ! ptEndLink.IsValid() || ! vtTool.IsValid() || ! vtMove.IsValid() || + pCAvTlStm == nullptr || ! frSurf.IsValid()) return false ; for ( const ISurfTriMesh* pStm : vpStm) { if ( pStm == nullptr || ! pStm->IsValid() || pStm->GetTriangleCount() == 0) return false ; + #if 0 + m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pStm->Clone()) ; + #endif } - // verifico se il link è lungo una parete verticiale (escludo gli estremi in quanto forzati) - Vector3d vtMove = vtTool ; // !<-- - double dLen = pCompoLink->GetLength( dLen) ; - const int MAX_POINTS = 5 ; - bool bFound = false ; - for ( int i = 1 ; !bFound && i < MAX_POINTS + 1 ; ++ i) { - double dLenCurr = i * ( dLen / MAX_POINTS + 1) ; - double dUCurr ; pCompoLink->GetParamAtLength( dLenCurr, dUCurr) ; - Point3d ptCurr ; pCompoLink->GetPointD1D2( dUCurr, ICurve::FROM_MINUS, ptCurr) ; - for ( const ISurfTriMesh* pStm : vpStm) { - DistPointSurfTm distPtStm( ptCurr, *pStm) ; - INTVECTOR vIndMinDistTria ; - if ( distPtStm.GetMinDistTriaIndices( vIndMinDistTria)) { - for ( int nTria : vIndMinDistTria) { - Triangle3d Tria ; pStm->GetTriangle( nTria, Tria) ; - if ( abs( Tria.GetN() * vtTool) < cos( 88. * DEGTORAD)) { - vtMove = Tria.GetN() ; - bFound = true ; - break ; + Vector3d myVtMove = vtMove ; + // verifico se il link è lungo una parete orientata come la direzione utensile, in caso positivo sposto leggermente il versore + // utensile per evitare di trovare collisioni errate (tratti a ZigZag per tolleranza collisione) + if ( bAllowMove) { + const int MAX_POINTS = 5 ; + const double COS_ANG_LIMIT = cos( 88. * DEGTORAD) ; + double dLen ; pCompoLink->GetLength( dLen) ; + bool bFound = false ; + for ( int i = 1 ; ! bFound && i < MAX_POINTS ; ++ i) { + double dLenCurr = i * ( dLen / MAX_POINTS) ; + double dUCurr ; pCompoLink->GetParamAtLength( dLenCurr, dUCurr) ; + Point3d ptCurr ; pCompoLink->GetPointD1D2( dUCurr, ICurve::FROM_MINUS, ptCurr) ; + // porto il punto corrente nel frame locale della superfici + ptCurr.ToLoc( frSurf) ; + + #if 0 + PtrOwner _ptM( CreateGeoPoint3d()) ; _ptM->Set( ptCurr) ; + int _nId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, _ptM->Clone()) ; + m_pGeomDB->SetMaterial( _nId, YELLOW) ; + #endif + + for ( const ISurfTriMesh* pStm : vpStm) { + DistPointSurfTm distPtStm( ptCurr, *pStm) ; + INTVECTOR vIndMinDistTria ; + if ( distPtStm.GetMinDistTriaIndices( vIndMinDistTria)) { + for ( int nTria : vIndMinDistTria) { + Triangle3d Tria ; pStm->GetTriangle( nTria, Tria) ; + if ( abs( Tria.GetN() * vtMove) < COS_ANG_LIMIT) { // vtMove perpendicolare al vtN (2 gradi di tolleranza) + if ( vtTool * Tria.GetN() > - 10. * EPS_SMALL) { // il triangolo è coerente con la direzione utensile + myVtMove = Media( Tria.GetN(), vtTool, 0.8) ; + bFound = true ; + break ; + } + } } } } } } - if ( bFound) { - vtMove = Media( vtMove, vtTool, 0.2) ; - vtMove.Normalize() ; - } - // approssimo la curva con una polilinea - PolyLine PL ; - if ( ! pCompoLink->ApproxWithLines( m_Params.m_dApprox, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL)) - return false ; - #if ENABLE_ZCONST_PATH_DEBUG - int nGrp = m_pGeomDB->AddGroup( GDB_ID_NULL, GDB_ID_ROOT, Frame3d()) ; - int nLay = m_pGeomDB->AddGroup( GDB_ID_NULL, nGrp, Frame3d()) ; - int nId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLay, pCompoLink->Clone()) ; - m_pGeomDB->SetMaterial( nId, RED) ; + #if ENABLE_ZCONST_LINK_DEBUG + int _nGrp = m_pGeomDB->AddGroup( GDB_ID_NULL, GDB_ID_ROOT, Frame3d()) ; + int _nLay = m_pGeomDB->AddGroup( GDB_ID_NULL, _nGrp, Frame3d()) ; + int _nId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, _nLay, pCompoLink->Clone()) ; + m_pGeomDB->SetMaterial( _nId, RED) ; + PtrOwner _vtT( CreateGeoVector3d()) ; _vtT->Set( 5. * vtTool, ptStartLink) ; + PtrOwner _vtM( CreateGeoVector3d()) ; _vtM->Set( 5.* myVtMove, ptStartLink) ; + _nId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, _nLay, _vtT->Clone()) ; + m_pGeomDB->SetMaterial( _nId, YELLOW) ; + _nId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, _nLay, _vtM->Clone()) ; + m_pGeomDB->SetMaterial( _nId, FUCHSIA) ; #endif + + // porto i dati geometrici in locale alle superfici + Vector3d vtToolL = GetToLoc( vtTool, frSurf), + vtMoveL = GetToLoc( myVtMove, frSurf) ; + // 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) ; + + // approssimo la curva con una polilinea + PolyLine PL ; + if ( ! pCompoLink->ApproxWithLines( min( LIN_TOL_FINE, m_Params.m_dApprox), ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL)) + return false ; if ( ! PL.AdjustForMaxSegmentLen( dDist)) return false ; + + #if ENABLE_ZCONST_LINK_DEBUG + for ( const POINTU& ptU : PL.GetUPointList()) { + PtrOwner _myPt( CreateGeoPoint3d()) ; _myPt->Set( ptU.first) ; + int _nId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, _nLay, _myPt->Clone()) ; + m_pGeomDB->SetMaterial( _nId, WHITE) ; + } + #endif + // porto nel riferimento delle superfici - PL.ToGlob( frPocket) ; - // porto i dati geometrici in locale alle superfici - Vector3d vtToolL = GetToLoc( vtTool, frSurf) ; - Vector3d vtMoveL = GetToLoc( vtMove, frSurf) ; + PL.ToLoc( frSurf) ; // traslo della lunghezza utensile - PL.Translate( vtToolL * ( m_TParams.m_dLen)) ; + PL.Translate( vtToolL * m_TParams.m_dLen) ; // eseguo il test del percorso if ( ! pCAvTlStm->TestPath( PL.GetUPointList(), vtToolL, vtMoveL, m_Params.m_dApprox)) return false ; // contro-traslo della lunghezza utensile PL.Translate( - vtToolL * m_TParams.m_dLen) ; // riporto la polilinea nel riferimento della curva - PL.ToLoc( frPocket) ; - #if ENABLE_ZCONST_PATH_DEBUG - for ( const POINTU& ptU : PL.GetUPointList()) { - PtrOwner myPt( CreateGeoPoint3d()) ; - myPt->Set( ptU.first) ; - int nId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLay, myPt->Clone()) ; - m_pGeomDB->SetMaterial( nId, WHITE) ; - } - #endif + PL.ToGlob( frSurf) ; // elimino i punti allineati PL.RemoveAlignedPoints( 0.8 * m_Params.m_dApprox) ; // sostituisco primo ed ultimo punto con quelli forzati @@ -3605,46 +3751,343 @@ SurfFinishing::CalcZConstLink( ICurveComposite* pCompoLink, const Point3d& ptSta PL.EraseLastUPoint() ; PL.AddUPoint( 0, ptStartLink, false) ; PL.AddUPoint( PL.GetPointNbr(), ptEndLink, true) ; - // creo una curva composita a partire dalla polilinea - PtrOwner pCompo( CreateCurveComposite()) ; - if ( IsNull( pCompo) || ! pCompo->FromPolyLine( PL)) - return false ; - #if ENABLE_ZCONST_PATH_DEBUG - nId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCompo->Clone()) ; - m_pGeomDB->SetMaterial( nId, LIME) ; + + // assegno al nuovo Link trovato + pCompoLink->Clear() ; + pCompoLink->FromPolyLine( PL) ; + + #if ENABLE_ZCONST_LINK_DEBUG + _nId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, _nLay, pCompoLink->Clone()) ; + m_pGeomDB->SetMaterial( _nId, LIME) ; #endif + + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfFinishing::AdjustZConstFrame( const Vector3d& vtTool, Frame3d& frSfr, ISurfFlatRegion* pSfrClass, double& dRawDepth) const +{ + // verifico la regione passata + if ( pSfrClass == nullptr) + return false ; + pSfrClass->Clear() ; + + // recupero il Box del grezzo + BBox3d b3Raw ; + int nRawId = m_pMchMgr->GetFirstRawPart() ; + while ( nRawId != GDB_ID_NULL) { + if ( m_pMchMgr->VerifyRawPartPhase( nRawId, m_nPhase)) { + // recupero la trimesh del grezzo + int nStmId = m_pGeomDB->GetFirstNameInGroup( nRawId, MACH_RAW_SOLID) ; + const ISurfTriMesh* pStm = GetSurfTriMesh( m_pGeomDB->GetGeoObj( nStmId)) ; + if ( pStm != nullptr) { + // recupero il riferimento della trimesh + Frame3d frStm ; m_pGeomDB->GetGlobFrame( nStmId, frStm) ; + // calcolo il suo Box e aggiungo tale contributo al Box globale + BBox3d BBoxCurr ; pStm->GetBBox( frStm, BBoxCurr) ; + b3Raw.Add( BBoxCurr) ; + } + // passo al grezzo successivo + nRawId = m_pMchMgr->GetNextRawPart( nRawId) ; + } + } + + // recupero il diamentro di estensione del box + double dMaxDim ; b3Raw.GetDiameter( dMaxDim) ; + + // definisco un frame implicito orientato come il versore utensile + Frame3d frTool ; + if ( ! frTool.Set( ORIG, vtTool)) + return false ; + + // verifico quale punto del box del grezzo ha coordinata Z locale maggiore rispetto a tale frame + // calcolo anche il punto a coordinata z minore (serve per la RawDepth) + const Point3d& ptMin = b3Raw.GetMin() ; + const Point3d& ptMax = b3Raw.GetMax() ; + Point3d vLocalPoints[8] = { + GetToLoc( ptMin, frTool), + GetToLoc( Point3d( ptMax.x, ptMin.y, ptMin.z), frTool), + GetToLoc( Point3d( ptMin.x, ptMax.y, ptMin.z), frTool), + GetToLoc( Point3d( ptMax.x, ptMax.y, ptMin.z), frTool), + GetToLoc( Point3d( ptMax.x, ptMin.y, ptMax.z), frTool), + GetToLoc( Point3d( ptMin.x, ptMax.y, ptMax.z), frTool), + GetToLoc( Point3d( ptMax.x, ptMax.y, ptMax.z), frTool), + GetToLoc( ptMax, frTool) + } ; + Point3d ptSfrCentroid = vLocalPoints[0] ; + Point3d ptMaxDepth = vLocalPoints[0] ; + for ( int i = 1 ; i < 8 ; ++ i) { + if ( vLocalPoints[i].z > ptSfrCentroid.z) + ptSfrCentroid = vLocalPoints[i] ; + if ( vLocalPoints[i].z < ptMaxDepth.z) + ptMaxDepth = vLocalPoints[i] ; + } + + // definisco il frame di orientamento + if ( ! frSfr.Set( GetToGlob( ptSfrCentroid, frTool) + vtTool, vtTool)) + return false ; + + // calcolo la RawDepth + Point3d ptFarther = GetToGlob( ptMaxDepth, frTool) ; + dRawDepth = abs( ( ptFarther - frSfr.Orig()) * vtTool) ; + + // definisco la regione di classificazione + PtrOwner pCompoLoop( CreateCurveComposite()) ; + if ( IsNull( pCompoLoop) || + ! pCompoLoop->AddPoint( GetToGlob( Point3d( dMaxDim, dMaxDim, 0.), frSfr)) || + ! pCompoLoop->AddLine( GetToGlob( Point3d( -dMaxDim, dMaxDim, 0.), frSfr)) || + ! pCompoLoop->AddLine( GetToGlob( Point3d( -dMaxDim, -dMaxDim, 0.), frSfr)) || + ! pCompoLoop->AddLine( GetToGlob( Point3d( dMaxDim, -dMaxDim, 0.), frSfr)) || + ! pCompoLoop->Close()) + return false ; + if ( ! pSfrClass->AddExtLoop( ::Release( pCompoLoop))) + return false ; + // --- estrema sicurezza --- + if ( AreOppositeVectorApprox( pSfrClass->GetNormVersor(), vtTool)) + pSfrClass->Invert() ; + + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfFinishing::AdjustZConstCurvesBySfr( const ISurfFlatRegion* pSfrCnt, const ISurfFlatRegion* pSfrClass, const Vector3d& vtTool, + const Vector3d& vtMove, double dDepth, ICRVCOMPOPOMAT& matCompo) const +{ + // verifico che le regioni piane siano valide + if ( pSfrCnt == nullptr || ! pSfrCnt->IsValid() || pSfrClass == nullptr || ! pSfrClass->IsValid()) + return false ; + + // definisco un piano al livello della Depth e taglio tutte le curve al di sotto di tale piano + Point3d ptCentroid ; pSfrCnt->GetCentroid( ptCentroid) ; + Plane3d PlaneDepth ; + if ( ! PlaneDepth.Set( ptCentroid - vtMove * dDepth, - vtMove)) + return false ; + + // definisco il piano intriseco della superficie di contorno + Plane3d PlaneProj ; + if ( ! PlaneProj.Set( ptCentroid, vtMove)) + return false ; + + // definisco il piano intrinseco alla superficie di classificazione + Point3d ptCentroid1 ; pSfrClass->GetCentroid( ptCentroid1) ; + Plane3d PlaneSfrClass ; + if ( ! PlaneSfrClass.Set( ptCentroid1, vtTool)) + return false ; + + // --- Funzione che, dato un punto sulla curva di Silhouette proiettata su PlaneProj restituisce il rispettivo punto sulla curva di Silhouette + // non proiettata, assieme al suo parametro --- + auto CalcUnprojectedPoint = [&]( const Point3d& ptProj, const Plane3d& PlaneSil, const ICurve* pCrvSil, Point3d& ptUnprojected, double& dU) { + // Calcolo il punto di intersezione tra una linea infinita diretta come -vtTool e uscente dal punto ptProj con il piano di Silhouette + Point3d ptInters ; + if ( ! IntersLinePlane( ptProj, - vtMove, 1e8, PlaneSil, ptInters, false)) + return false ; + // Dal punto di intersezione corrente cerco il punto più vicino sulla curva + int nFlag ; + DistPointCurve DPC( ptInters, *pCrvSil) ; + if ( ! DPC.GetMinDistPoint( 0., ptUnprojected, nFlag) || ! DPC.GetParamAtMinDistPoint( 0., dU, nFlag)) + return false ; + return true ; + } ; + + // --- Funzione per concatenare le curve --- + auto ChainCompoCurves = []( ICRVCOMPOPOVECTOR& vpCompo) { + if ( ssize( vpCompo) < 2) + return true ; + // Controllo validità delle curve + for ( int i = 0 ; i < ssize( vpCompo) ; ++ i) { + if ( IsNull( vpCompo[i]) || ! vpCompo[i]->IsValid()) + return false ; + } + // Preparo i dati per il concatenamento + bool bFirst = true ; + Point3d ptNear = ORIG ; + double dToler = 20. * EPS_SMALL ; + ChainCurves chainC ; chainC.Init( false, dToler, ssize( vpCompo)) ; // evito inversioni, le curve devono essere coerenti + for ( int i = 0 ; i < ssize( vpCompo) ; ++ i) { + // Recupero i dati della curva necessari al concatenamento e li assegno + Point3d ptStart, ptEnd ; Vector3d vtStart, vtEnd ; + if ( ! vpCompo[i]->GetStartPoint( ptStart) || ! vpCompo[i]->GetStartDir( vtStart) || + ! vpCompo[i]->GetEndPoint( ptEnd) || ! vpCompo[i]->GetEndDir( vtEnd)) + return false ; + if ( ! chainC.AddCurve( i + 1, ptStart, vtStart, ptEnd, vtEnd)) + return false ; + // Se prima curva, assegno inizio della ricerca + if ( bFirst) { + ptNear = ptStart + 10. * EPS_SMALL * vtStart ; + bFirst = false ; + } + } + // Vettore delle curve composite risultante + ICRVCOMPOPOVECTOR vCrvCompoChained ; vCrvCompoChained.reserve( vpCompo.size()) ; + // recupero i percorsi concatenati + INTVECTOR vnInd ; + while ( chainC.GetChainFromNear( ptNear, true, vnInd)) { + // Creo una curva composita + PtrOwner pCrvCompo( CreateCurveComposite()) ; + if ( IsNull( pCrvCompo)) + return false ; + // Recupero le curve semplici e le inserisco nella curva composita + for ( int i = 0 ; i < ssize( vnInd) ; ++ i) { + int nId = abs( vnInd[i]) - 1 ; + bool bInvert = ( vnInd[i] < 0) ; + // Se necessario, la inverto + if ( bInvert) + vpCompo[nId]->Invert() ; + // La aggiungo alla curva composta + if ( ! pCrvCompo->AddCurve( Release( vpCompo[nId]), true, dToler)) + return false ; + } + // Aggiorno il nuovo punto vicino + if ( pCrvCompo->GetCurveCount() > 0) { + pCrvCompo->GetEndPoint( ptNear) ; + vCrvCompoChained.emplace_back( Release( pCrvCompo)) ; + } + } + swap( vCrvCompoChained, vpCompo) ; + return true ; + } ; + + #if ENABLE_ZCONST_TOOL_MOVE_DEBUG + int _nGrpDebug = m_pGeomDB->AddGroup( GDB_ID_NULL, GDB_ID_ROOT, GLOB_FRM) ; + int _nSilCrvLayer = m_pGeomDB->AddGroup( GDB_ID_NULL, _nGrpDebug, GLOB_FRM) ; + m_pGeomDB->SetMaterial( _nSilCrvLayer, LIME) ; + m_pGeomDB->SetName( _nSilCrvLayer, "Silhouette") ; + int _nProjCrvLayer = m_pGeomDB->AddGroup( GDB_ID_NULL, _nGrpDebug, GLOB_FRM) ; + m_pGeomDB->SetMaterial( _nProjCrvLayer, YELLOW) ; + m_pGeomDB->SetName( _nProjCrvLayer, "Projection") ; + int _nResultLayer = m_pGeomDB->AddGroup( GDB_ID_NULL, _nGrpDebug, GLOB_FRM) ; + m_pGeomDB->SetMaterial( _nResultLayer, RED) ; + m_pGeomDB->SetName( _nResultLayer, "Path") ; + #endif + + // per ogni curva + vector vCrvCompoCut ; vCrvCompoCut.resize( matCompo.size()) ; + for ( int i = 0 ; i < ssize( matCompo) ; ++ i) { + for ( int j = 0 ; j < ssize( matCompo[i]) ; ++ j) { + if ( ! IsNull( matCompo[i][j]) && matCompo[i][j]->IsValid()) { + + // memorizzo le TempProps e i TempParams + int nTempProp0 = matCompo[i][j]->GetTempProp( 0), + nTempProp1 = matCompo[i][j]->GetTempProp( 1) ; + double dTempParam0 = matCompo[i][j]->GetTempParam( 0), + dTempParam1 = matCompo[i][j]->GetTempParam( 1) ; + + // determino il piano su cui è contenuta tale curva + Plane3d PlaneCrvSil = PlaneSfrClass ; + PlaneCrvSil.Translate( vtTool * dTempParam0) ; // nel primo TempParam è slavata la distanza della Silhouette + + // taglio con il piano che definisce la Depth + ICURVEPOVECTOR vCrvRes ; + if ( ! CutCurveWithPlane( matCompo[i][j], PlaneDepth, true, vCrvRes)) + return false ; + ICRVCOMPOPOVECTOR vCompoRes ; vCompoRes.reserve( vCrvRes.size()) ; + for ( int k = 0 ; k < ssize( vCrvRes) ; ++ k) { + if ( ! vCompoRes.emplace_back( ConvertCurveToComposite( ::Release( vCrvRes[k])))) + return false ; + } + ChainCompoCurves( vCompoRes) ; + + // Per ogni curva ottenuta + for ( int k = 0 ; k < ssize( vCompoRes) ; ++ k) { + if ( ! IsNull( vCompoRes[k]) && vCompoRes[k]->IsValid()) { + + // Memorizzo tale curva + PtrOwner pCompo( ConvertCurveToComposite( ::Release( vCompoRes[k]))) ; + if ( IsNull( pCompo) || ! pCompo->IsValid()) + continue ; + + #if ENABLE_ZCONST_TOOL_MOVE_DEBUG + m_pGeomDB->AddGeoObj( GDB_ID_NULL, _nSilCrvLayer, pCompo->Clone()) ; + #endif + + // proietto la curva rispetto al contorno originario + PtrOwner pCompoProj( ProjectCurveOnPlane( *pCompo, PlaneProj)) ; + if ( IsNull( pCompoProj) || ! pCompoProj->IsValid()) + continue ; + + // classifico i tratti di curva tenendo solo quelli interni alla regione di contorno originale + CRVCVECTOR ccClass ; + if ( ! pSfrCnt->GetCurveClassification( *pCompoProj, EPS_SMALL, ccClass)) + return false ; + ICRVCOMPOPOVECTOR vCompoProjInSfrCnt ; vCompoProjInSfrCnt.reserve( ccClass.size()) ; + for ( const CrvClass& Class : ccClass) { + if ( Class.nClass != CRVC_OUT) { + PtrOwner pCompoProjInSfrCnt( ConvertCurveToComposite( pCompoProj->CopyParamRange( Class.dParS, Class.dParE))) ; + if ( ! IsNull( pCompoProjInSfrCnt) && pCompoProjInSfrCnt->IsValid()) { + if ( ! vCompoProjInSfrCnt.emplace_back( ::Release( pCompoProjInSfrCnt))) + return false ; + } + } + } + // concateno i risultati ottenuti + ChainCompoCurves( vCompoProjInSfrCnt) ; + + #if ENABLE_ZCONST_TOOL_MOVE_DEBUG + for ( int _n = 0 ; _n < ssize( vCompoProjInSfrCnt) ; ++ _n) + m_pGeomDB->AddGeoObj( GDB_ID_NULL, _nProjCrvLayer, vCompoProjInSfrCnt[_n]->Clone()) ; + #endif + + // per ogni curva, recupero il suo tratto associato alla curva di Silhouette + for ( PtrOwner& pCompoProjInSfrCnt : vCompoProjInSfrCnt) { + if ( pCompoProjInSfrCnt != nullptr && pCompoProjInSfrCnt->IsValid()) { + + // se la curva è chiusa, allora non devo modificare nulla + if ( pCompoProjInSfrCnt->IsClosed()) { + if ( ! vCrvCompoCut[i].emplace_back( ::Release( matCompo[i][j]))) + return false ; + } + // se la curva è aperta + else { + // recupero gli estremi + Point3d ptStart ; pCompoProjInSfrCnt->GetStartPoint( ptStart) ; + Point3d ptEnd ; pCompoProjInSfrCnt->GetEndPoint( ptEnd) ; + // recupero i punti associati + Point3d ptStartOnSil, ptEndOnSil ; double dUSOnSil, dUEOnSil ; + if ( ! CalcUnprojectedPoint( ptStart, PlaneCrvSil, matCompo[i][j], ptStartOnSil, dUSOnSil) || + ! CalcUnprojectedPoint( ptEnd, PlaneCrvSil, matCompo[i][j], ptEndOnSil, dUEOnSil)) + return false ; + // copio il tratto di curva corrispondente + PtrOwner pCompoPath( ConvertCurveToComposite( matCompo[i][j]->CopyParamRange( dUSOnSil, dUEOnSil))) ; + if ( ! IsNull( pCompoPath) && pCompoPath->IsValid()) { + if ( ! vCrvCompoCut[i].emplace_back( ::Release( pCompoPath))) + return false ; + } + } + + #if ENABLE_ZCONST_TOOL_MOVE_DEBUG + m_pGeomDB->AddGeoObj( GDB_ID_NULL, _nResultLayer, vCrvCompoCut[i].back()->Clone()) ; + #endif + + // ripristino le proprietà temporanee + vCrvCompoCut[i].back()->SetTempProp( nTempProp0, 0) ; + vCrvCompoCut[i].back()->SetTempProp( nTempProp1, 1) ; + vCrvCompoCut[i].back()->SetTempParam( dTempParam0, 0) ; + vCrvCompoCut[i].back()->SetTempParam( dTempParam1, 1) ; + } + } + } + } + } + } + } + + swap ( vCrvCompoCut, matCompo) ; return true ; } //---------------------------------------------------------------------------- bool SurfFinishing::AddZConst( ICAvToolSurfTm* pCAvTlStm, const SURFLOCALVECTOR& vSrfLoc, const Frame3d& frSurf, const ISurfFlatRegion* pSfrCnt, - const Vector3d& vtTool, double dDepth, double dElev, bool bSplitArcs) + const Vector3d& vtTool, const Vector3d& vtMove, double dDepth, double dElev, bool bSplitArcs) { // controllo che la regione sia definita correttamente if ( pSfrCnt == nullptr || ! pSfrCnt->IsValid()) return false ; - // aggiorno la ProgressBar del 5% per simulare l'inizio della funzione ExeProcessEvents( 5, 0) ; - // definisco un frame implicito dalla superficie - Frame3d frSfr ; - Point3d ptC ; pSfrCnt->GetCentroid( ptC) ; - if ( ! frSfr.Set( ptC, pSfrCnt->GetNormVersor())) - return false ; - frSfr.ToLoc( frSurf) ; // in locale alle SrfLoc - - // aggiusto la regione a seconda dei parametri e la porto nel frame locale delle superfici - // NB. Per rendere questa superficie coerente con le superfici degli altri tipi di lavorazione, devo effettuare un ControOffset - // del raggio utensile. Se la lavorazione fosse a ZigZag le curve si trovano all'interno di questa regione del raggio utensile - // ( questo passaggio è calcolato implicitamente dalla lavorazione di Pocketing ZigZag). Nel caso di Lavorazione a ZLevel bisogna - // aggiungere questo passaggio in modo tale che dalla curva originaria Offsettata del parametro di Overlap, tutto l'utensile stia - // al suo interno. - PtrOwner pSfrClass( pSfrCnt->CreateOffsetSurf( - m_TParams.m_dDiam / 2. + EPS_SMALL, ICurve::OFF_FILLET)) ; - if ( IsNull( pSfrClass) || ! pSfrClass->IsValid() || ! pSfrClass->ToLoc( frSurf)) - return false ; - // inizializzo la classe di calcolo delle silhouette CISURFTMPVECTOR vpStm ; vpStm.reserve( vSrfLoc.size()) ; // scorro le superfici @@ -3675,46 +4118,89 @@ SurfFinishing::AddZConst( ICAvToolSurfTm* pCAvTlStm, const SURFLOCALVECTOR& vSrf } } } - const double TOL_SAMPLING = 1. ; - PtrOwner pCavParSilh( CreateCAvParSilhouettesSurfTm()) ; - if ( IsNull( pCavParSilh) || - ! pCavParSilh->SetData( vpStm, frSfr, TOL_SAMPLING, m_TParams.m_dSideAng, m_TParams.m_dDiam, - m_TParams.m_dCornRad, m_TParams.m_dMaxMat, GetOffsR(), dDepth)) + + // definisco il frame per il calcolo delle curve di Silhouette (definito a partire dalla superficie di contorno) + Frame3d myfrSfr ; + // definisco la Depth per la finitura (in base all'orientamento dell'utensile) + double dMyDepth = dDepth ; + // definisco la superficie di campionamento per la silhouette orientata come la direzine utensile + // (valida solo se direzione utensile e versore movimento non paralleli) + PtrOwner pSfrTool( CreateSurfFlatRegion()) ; + if ( IsNull( pSfrTool)) + return false ; + + bool bToolDirToolMoveParallel = AreSameVectorEpsilon( vtTool, vtMove, 10. * EPS_SMALL) ; + + // se l'utensile e il versore movimento non sono tra loro paralleli + if ( ! bToolDirToolMoveParallel) { + // aggiusto il frame per il calcolo della regione su cui calcolare le Silhouette e definisco la regione di classificazione. Quest'ultima + // deve essere sufficientemente estesa per coprire l'intero grezzo localmente alla direzione utensile + if ( ! AdjustZConstFrame( vtTool, myfrSfr, pSfrTool, dMyDepth) || ! myfrSfr.ToLoc( frSurf)) + return false ; + } + // se l'utensile e il versore movimento sono tra loro paralleli + else { + Point3d ptC ; pSfrCnt->GetCentroid( ptC) ; + if ( ! myfrSfr.Set( ptC, pSfrCnt->GetNormVersor()) || ! myfrSfr.ToLoc( frSurf)) + return false ; + } + + // inizializzo la classe di calcolo della silhouette con CAv + PtrOwner pCavParSilh( CreateCAvParSilhouettesSurfTm()) ; + if ( IsNull( pCavParSilh) || + ! pCavParSilh->SetData( vpStm, myfrSfr, SILH_SAMPLING, m_TParams.m_dSideAng, m_TParams.m_dDiam, m_TParams.m_dCornRad, + m_TParams.m_dMaxMat, GetOffsR(), dMyDepth)) return false ; - // aggiorno la ProgressBar al 30% ExeProcessEvents( 30, 0) ; + // aggiusto la regione di contorno in modo che la punta dell'utensile sia sempre al suo interno + PtrOwner pMySfrCnt( pSfrCnt->CreateOffsetSurf( - m_TParams.m_dDiam / 2. + EPS_SMALL, ICurve::OFF_FILLET)) ; + if ( IsNull( pMySfrCnt) || ! pMySfrCnt->IsValid()) + return false ; + // recupero le curve singole definite dal bordo della Silhouette - vector vCrvCompo ; - if ( ! CalcZConstSilCrv( pCavParSilh, vSrfLoc, frSurf, pSfrClass, vtTool, dDepth, vCrvCompo)) { + const ISurfFlatRegion* pSfrToolDir = ( ! bToolDirToolMoveParallel ? pSfrTool : pMySfrCnt) ; + ICRVCOMPOPOMAT matCompo ; + if ( ! CalcZConstSilCrv( pCavParSilh, vSrfLoc, frSurf, pSfrToolDir, vtTool, dMyDepth, matCompo)) { m_pMchMgr->SetLastError( 3126, "Error in SurfFinishing : Computing ZConst Curves failed") ; return false ; } // se non ho curve, esco bool bNoCrv = true ; - for ( int i = 0 ; i < ssize( vCrvCompo) && bNoCrv ; ++ i) - bNoCrv = ( vCrvCompo[i].empty()) ; + for ( int i = 0 ; i < ssize( matCompo) && bNoCrv ; ++ i) + bNoCrv = ( matCompo[i].empty()) ; if ( bNoCrv) return true ; + // aggiusto le curve in base alla superficie originale di vista (se Tool Dir e Tool Move non paralleli) + if ( ! bToolDirToolMoveParallel) { + if ( ! AdjustZConstCurvesBySfr( pMySfrCnt, pSfrTool, vtTool, vtMove, dDepth, matCompo)) + return false ; + #if 0 + for ( int _i = 0 ; _i < ssize( matCompo) ; ++ _i) { + for ( int _j = 0 ; _j < ssize( matCompo[_i]) ; ++ _j) { + int _nInd = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, matCompo[_i][_j]->Clone()) ; + m_pGeomDB->SetMaterial( _nInd, YELLOW) ; + } + } + #endif + } + // collego tra loro le curve trovate - ICRVCOMPOPOVECTOR vCrvPath ; - if ( ! CreateZConstPaths( pCAvTlStm, vpStm, frSurf, vCrvCompo, vtTool, pSfrClass, dDepth, vCrvPath)) { + ICRVCOMPOPOVECTOR vCompoPath ; + if ( ! CreateZConstPaths( pCAvTlStm, vpStm, frSurf, matCompo, vtTool, vtMove, pMySfrCnt, dMyDepth, vCompoPath)) { m_pMchMgr->SetLastError( 3127, "Error in SurfFinishing : Computing ZConst Paths failed") ; return false ; } // se non ho percorsi, errore - if ( vCrvPath.empty()) + if ( vCompoPath.empty()) return false ; + ExeProcessEvents( 90, 0) ; - // porto tutti i percorsi in Globale - for ( int i = 0 ; i < ssize( vCrvPath) ; ++ i) - vCrvPath[i]->ToGlob( frSurf) ; - // aggiungo i percorsi di finitura calcolati - if ( ! AddFinishing( pSfrCnt, pCAvTlStm, frSurf, vCrvPath, vtTool, vtTool, dElev, dDepth, bSplitArcs)) + if ( ! AddFinishing( pSfrCnt, pCAvTlStm, vSrfLoc, frSurf, vCompoPath, vtTool, vtMove, dElev, dDepth, bSplitArcs)) return false ; return true ; @@ -3734,7 +4220,7 @@ SurfFinishing::OrderOptimalPathsByZLoc( const ISurfFlatRegion* pSfrCntZConst, co if ( ssize( vCrvPaths) <= 1) return true ; - // determino il piano contenente la superficie di lavoro ( identico per pSfrCntZigZag e pSfrCntZConst) + // determino il piano contenente la superficie di lavoro (identico per pSfrCntZigZag e pSfrCntZConst) Point3d ptCenter ; Vector3d vtN ; if ( pSfrCntZigZag != nullptr && pSfrCntZigZag->IsValid()) { @@ -3842,7 +4328,7 @@ SurfFinishing::OrderOptimalPathsByZLoc( const ISurfFlatRegion* pSfrCntZConst, co vTmp[i].pCrvPath.Set( Release( vCrvPaths[nInd].pCrvPath)) ; vTmp[i].nType = vCrvPaths[nInd].nType ; } - swap(vCrvPaths, vTmp) ; + swap( vCrvPaths, vTmp) ; return true ; } @@ -4714,7 +5200,7 @@ SurfFinishing::GetOptimalSubType() const //---------------------------------------------------------------------------- bool -SurfFinishing::CalcOptimalZigZagCurves( ISURFFRPOVECTOR& vSfrZigZagProj, const Frame3d& frSurf, const Vector3d& vtTool, +SurfFinishing::CalcOptimalZigZagCurves( ISURFFRPOVECTOR& vSfrZigZagProj, const Frame3d& frSurf, const Vector3d& vtTool, const Vector3d& vtMove, double dDepth, ICAvToolSurfTm* pCAvTlStm, VECTORPATHS& vPaths) const { #if ENABLE_OPTIMAL_DEBUG @@ -4738,7 +5224,7 @@ SurfFinishing::CalcOptimalZigZagCurves( ISURFFRPOVECTOR& vSfrZigZagProj, const F int nSubType = GetOptimalSubType() ; // Scorro le superfici presenti - for ( ISurfFlatRegion* pSfrZigZag : vSfrZigZagProj) { + for ( const ISurfFlatRegion* pSfrZigZag : vSfrZigZagProj) { if ( pSfrZigZag == nullptr || ! pSfrZigZag->IsValid()) continue ; @@ -4761,8 +5247,6 @@ SurfFinishing::CalcOptimalZigZagCurves( ISURFFRPOVECTOR& vSfrZigZagProj, const F pSfrChunk->SetCurveTempProp( nC, nL, nU, TEMP_PROP_CLOSE_AS_OPEN, 0) ; } } - // porto il Chunk in Globale - pSfrChunk->ToGlob( frSurf) ; // eseguo il calcolo della lavorazione ZigZag ICRVCOMPOPOVECTOR vpCrvs ; if ( ! CalcPocketing( pSfrChunk, m_TParams.m_dDiam / 2., 0., m_Params.m_dSideStep, GetLocalSideAngle(), 5., @@ -4775,16 +5259,17 @@ SurfFinishing::CalcOptimalZigZagCurves( ISURFFRPOVECTOR& vSfrZigZagProj, const F for ( int i = 0 ; i < ssize( vpCrvs) ; ++ i) { #if ENABLE_OPTIMAL_DEBUG PtrOwner pCompoCL( CloneCurveComposite( vpCrvs[i])) ; - pCompoCL->ToLoc( frSurf) ; int nCrvId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLayPock, ::Release( pCompoCL)) ; m_pGeomDB->SetMaterial( nCrvId, YELLOW) ; #endif + vCrvCompoZigZag.emplace_back( Release( vpCrvs[i])) ; } } - // porto i dati geometrici in locale alle superfici ( proeittando) - Vector3d vtToolL = GetToLoc( vtTool, frSurf) ; + // porto i dati geometrici in locale alle superfici + Vector3d vtToolL = GetToLoc( vtTool, frSurf), + vtMoveL = GetToLoc( vtMove, frSurf) ; const double MIN_DIST = 1. ; const double MAX_DIST = 50. ; double dDist = Clamp( m_Params.m_dApprox, MIN_DIST, MAX_DIST) ; @@ -4804,29 +5289,35 @@ SurfFinishing::CalcOptimalZigZagCurves( ISURFFRPOVECTOR& vSfrZigZagProj, const F return false ; // porto nel riferimento delle superfici PL.ToLoc( frSurf) ; + #if ENABLE_OPTIMAL_DEBUG PtrOwner pCompoPL( CreateCurveComposite()) ; pCompoPL->FromPolyLine( PL) ; int nPLId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLayPockApprox, ::Release( pCompoPL)) ; m_pGeomDB->SetMaterial( nPLId, ORANGE) ; #endif + // traslo della lunghezza utensile diminuita dell'affondamento - PL.Translate( vtToolL * ( m_TParams.m_dLen - dDepth)) ; + PL.Translate( vtToolL * m_TParams.m_dLen - vtMoveL * dDepth) ; // eseguo CAv - if ( ! pCAvTlStm->TestPath( PL.GetUPointList(), vtToolL, vtToolL, m_Params.m_dApprox, ( i + 1) * dProgCoeff)) + if ( ! pCAvTlStm->TestPath( PL.GetUPointList(), vtToolL, vtMoveL, m_Params.m_dApprox, ( i + 1) * dProgCoeff)) return false ; // contro-traslo della lunghezza utensile PL.Translate( - vtToolL * m_TParams.m_dLen) ; + // riporto la polilinea in globale + PL.ToGlob( frSurf) ; // elimino i punti allineati PL.RemoveAlignedPoints( 0.8 * m_Params.m_dApprox) ; // creo una curva composita a partire dalla polilinea PtrOwner pCrvCompo( CreateCurveComposite()) ; if ( IsNull( pCrvCompo) || ! pCrvCompo->FromPolyLine( PL)) return false ; + #if ENABLE_OPTIMAL_DEBUG int nCrvId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLayCrv, CloneCurveComposite( pCrvCompo)) ; m_pGeomDB->SetMaterial( nCrvId, RED) ; #endif + // definisco un nuovo percorso vPaths.resize( vPaths.size() + 1) ; vPaths.back().nType = SURFFIN_SUB_ZIGZAG ; @@ -4840,60 +5331,66 @@ SurfFinishing::CalcOptimalZigZagCurves( ISURFFRPOVECTOR& vSfrZigZagProj, const F //---------------------------------------------------------------------------- bool -SurfFinishing::CalcOptimalZigZagSfrByZConstCrv( const ISurfFlatRegion* pSfrLoc, const CISURFTMPVECTOR& vpStm, const Vector3d& vtToolLoc, +SurfFinishing::CalcOptimalZigZagSfrByZConstCrv( const ISurfFlatRegion* pSfrCnt, const Vector3d& vtTool, const Vector3d& vtMove, double dExtraCollOffs, ICurveComposite* pCompoSil, ISurfFlatRegion* pSfrCollCompoSil) const { // verifica dei parametri - if ( pSfrLoc == nullptr || ! pSfrLoc->IsValid() || - vpStm.empty() || - pCompoSil == nullptr || ! pCompoSil->IsValid() || + if ( pSfrCnt == nullptr || ! pSfrCnt->IsValid() || pCompoSil == nullptr || ! pCompoSil->IsValid() || pSfrCollCompoSil == nullptr) return false ; pSfrCollCompoSil->Clear() ; - // abballisco e semplifico la curva calcolata - Point3d ptC ; pSfrLoc->GetCentroid( ptC) ; + // definisco un frame locale a partire dalla curva di contorno + Point3d ptC ; pSfrCnt->GetCentroid( ptC) ; Frame3d frLoc ; - if ( ! frLoc.Set( ptC, pSfrLoc->GetNormVersor())) + if ( ! frLoc.Set( ptC, pSfrCnt->GetNormVersor())) return false ; - SimplifyCurve( pCompoSil, frLoc) ; + + ICurveComposite* pMyCompoSil = pCompoSil ; + if ( pMyCompoSil == nullptr) + return false ; + PtrOwner pCompoSilProj( nullptr) ; + + // se il versore utensile e il versore movimento non sono paralleli + if ( ! AreSameVectorEpsilon( vtTool, vtMove, 10. * EPS_SMALL)) { + // proietto la curva nel piano definito dalla regione di contorno + Plane3d PlaneCnt ; + if ( ! PlaneCnt.Set( ptC, pSfrCnt->GetNormVersor())) + return false ; + pCompoSilProj.Set( ConvertCurveToComposite( ProjectCurveOnPlane( *pCompoSil, PlaneCnt))) ; + if ( IsNull( pCompoSilProj) || ! pCompoSilProj->IsValid()) + return false ; + pMyCompoSil = pCompoSilProj ; + } + + // abballisco e semplifico la curva calcolata + SimplifyCurve( pMyCompoSil, frLoc) ; // definisco una regione di FatCurve pari al valore dell'Offset richiesto - PtrOwner pSfrFat( GetSurfFlatRegionFromFatCurve( CloneCurveComposite( pCompoSil), dExtraCollOffs, false, false)) ; + PtrOwner pSfrFat( GetSurfFlatRegionFromFatCurve( CloneCurveComposite( pMyCompoSil), dExtraCollOffs, false, false)) ; if ( IsNull( pSfrFat) || ! pSfrFat->IsValid()) return false ; pSfrCollCompoSil->CopyFrom( pSfrFat) ; // verifico che sia orientata correttamente - if ( AreOppositeVectorApprox( pSfrLoc->GetNormVersor(), pSfrCollCompoSil->GetNormVersor())) + if ( AreOppositeVectorApprox( pSfrCnt->GetNormVersor(), pSfrCollCompoSil->GetNormVersor())) pSfrCollCompoSil->Invert() ; - + return true ; } //---------------------------------------------------------------------------- bool -SurfFinishing::CalcOptimalZConstCurves( const ISurfFlatRegion* pSfrLoc, const SURFLOCALVECTOR& vSrfLoc, const Frame3d& frSurf, - const Vector3d& vtTool, double dAngDegSplit, double dAngDegTol, double dDepth, - ICAvToolSurfTm* pCAvTlStm, VECTORPATHS& vPaths, ISurfFlatRegion* pSfrToolColl) const +SurfFinishing::CalcOptimalZConstCurves( const ISurfFlatRegion* pSfrCnt, const SURFLOCALVECTOR& vSrfLoc, const Frame3d& frSurf, + const Vector3d& vtTool, const Vector3d& vtMove, double dAngDegSplit, double dAngDegTol, + double dDepth, ICAvToolSurfTm* pCAvTlStm, VECTORPATHS& vPaths, ISurfFlatRegion* pSfrToolColl) const { // se la superficie non è valida, non restituisco nulla if ( pSfrToolColl == nullptr) return false ; - if ( pSfrLoc == nullptr || ! pSfrLoc->IsValid()) + if ( pSfrCnt == nullptr || ! pSfrCnt->IsValid()) return true ; - // mi assicuro di non uscire dalla superficie originale - PtrOwner pMySfrZConst( CloneSurfFlatRegion( pSfrLoc)) ; - if ( IsNull( pMySfrZConst) || ! pMySfrZConst->IsValid()) - return false ; - for ( int nC = 0 ; nC < pMySfrZConst->GetChunkCount() ; ++ nC) { - for ( int nL = 0 ; nL < pMySfrZConst->GetLoopCount( nC) ; ++ nL) { - for ( int nU = 0 ; nU < pMySfrZConst->GetLoopCurveCount( nC, nL) ; ++ nU) - pMySfrZConst->SetCurveTempProp( nC, nL, nU, 0, TEMP_PROP_CLOSE_EDGE) ; - } - } - // inizializzo la classe di calcolo delle silhouette CISURFTMPVECTOR vpStm ; vpStm.reserve( vSrfLoc.size()) ; // scorro le superfici @@ -4923,33 +5420,75 @@ SurfFinishing::CalcOptimalZConstCurves( const ISurfFlatRegion* pSfrLoc, const SU } } - // definisco il frame della regione piana - Frame3d frSfr ; - Point3d ptC ; pSfrLoc->GetCentroid( ptC) ; - if ( ! frSfr.Set( ptC, pSfrLoc->GetNormVersor())) + // definisco il frame per il calcolo delle curve di Silhouette (definito a partire dalla superficie di contorno) + Frame3d myfrSfr ; + // definisco la depth di finitura (in base all'orientamento dell'utensile) + double dMyDepth = dDepth ; + // definisco la superficie di campionamento per la silhouette orientata come la direzine utensile + // (valida solo se direzione utensile e versore movimento non paralleli) + PtrOwner pSfrTool( CreateSurfFlatRegion()) ; + if ( IsNull( pSfrTool)) return false ; - // inizializzo classe di calcolo per le curve a ZConst con utensile corrente + bool bToolDirToolMoveParallel = AreSameVectorEpsilon( vtTool, vtMove, 10. * EPS_SMALL) ; + + // se l'utensile e il versore movimento non sono tra loro paralleli + if ( ! bToolDirToolMoveParallel) { + // aggiusto il frame per il calcolo della regione su cui calcolare le Silhouette e definisco la regione di classificazione. Quest'ultima + // deve essere sufficientemente estesa per coprire l'intero grezzo localmente alla direzione utensile + if ( ! AdjustZConstFrame( vtTool, myfrSfr, pSfrTool, dMyDepth) || ! myfrSfr.ToLoc( frSurf)) + return false ; + } + // se l'utensile e il versore movimento sono tra loro paralleli + else { + Point3d ptC ; pSfrCnt->GetCentroid( ptC) ; + if ( ! myfrSfr.Set( ptC, pSfrCnt->GetNormVersor()) || ! myfrSfr.ToLoc( frSurf)) + return false ; + } + + // inizializzo la classe di calcolo della silhouette con CAv PtrOwner pCavParSilh( CreateCAvParSilhouettesSurfTm()) ; if ( IsNull( pCavParSilh) || - ! pCavParSilh->SetData( vpStm, frSfr, SILH_SAMPLING, m_TParams.m_dSideAng, m_TParams.m_dDiam, m_TParams.m_dCornRad, - m_TParams.m_dMaxMat, GetOffsR(), dDepth)) + ! pCavParSilh->SetData( vpStm, myfrSfr, SILH_SAMPLING, m_TParams.m_dSideAng, m_TParams.m_dDiam, m_TParams.m_dCornRad, + m_TParams.m_dMaxMat, GetOffsR(), dMyDepth)) return false ; + ExeProcessEvents( 30, 0) ; + + // aggiusto la regione di contorno in modo che la punta dell'utensile sia sempre al suo interno + PtrOwner pMySfrCnt( pSfrCnt->CreateOffsetSurf( - m_TParams.m_dDiam / 2. + EPS_SMALL, ICurve::OFF_FILLET)) ; + if ( IsNull( pMySfrCnt) || ! pMySfrCnt->IsValid()) + return false ; + // recupero le curve singole definite dal bordo della Silhouette - vector vvCrvCompo ; - if ( ! CalcZConstSilCrv( pCavParSilh, vSrfLoc, frSurf, pMySfrZConst, vtTool, dDepth, vvCrvCompo)) { + const ISurfFlatRegion* pSfrToolDir = ( ! bToolDirToolMoveParallel ? pSfrTool : pMySfrCnt) ; + ICRVCOMPOPOMAT matCompo ; + if ( ! CalcZConstSilCrv( pCavParSilh, vSrfLoc, frSurf, pSfrToolDir, vtTool, dMyDepth, matCompo)) { m_pMchMgr->SetLastError( 3126, "Error in SurfFinishing : Computing ZConst Curves failed") ; return false ; } - // se non ho ricato curve, non faccio nulla - if ( vvCrvCompo.empty()) + // se non ho curve, esco + bool bNoCrv = true ; + for ( int i = 0 ; i < ssize( matCompo) && bNoCrv ; ++ i) + bNoCrv = ( matCompo[i].empty()) ; + if ( bNoCrv) return true ; + // aggiusto le curve in base alla superficie originale di vista (se Tool Dir e Tool Move non paralleli) + if ( ! bToolDirToolMoveParallel) { + if ( ! AdjustZConstCurvesBySfr( pMySfrCnt, pSfrTool, vtTool, vtMove, dDepth, matCompo)) + return false ; + #if 0 + for ( int _i = 0 ; _i < ssize( matCompo) ; ++ _i) { + for ( int _j = 0 ; _j < ssize( matCompo[_i]) ; ++ _j) { + int _nInd = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, matCompo[_i][_j]->Clone()) ; + m_pGeomDB->SetMaterial( _nInd, YELLOW) ; + } + } + #endif + } + // definisco i parametri e le geometrie locali - // --- versore direzione utensile e versore direzione movimento - Vector3d vtAxL = vtTool ; - vtAxL.ToLoc( frSurf) ; // --- tolleranza di campionamento per punti della PolyLine const double MIN_DIST = 1. ; const double MAX_DIST = 50. ; @@ -4988,10 +5527,13 @@ SurfFinishing::CalcOptimalZConstCurves( const ISurfFlatRegion* pSfrLoc, const SU int nLaySfrColl = m_pGeomDB->AddGroup( GDB_ID_NULL, nGrp, GLOB_FRM) ; m_pGeomDB->SetName( nLaySfrColl, "SfrColl") ; m_pGeomDB->SetStatus( nLaySfrColl, GDB_ST_OFF) ; + int nLayZConstPath = m_pGeomDB->AddGroup( GDB_ID_NULL, nGrp, GLOB_FRM) ; + m_pGeomDB->SetName( nLayZConstPath, "ZConstPaths") ; + m_pGeomDB->SetStatus( nLayZConstPath, GDB_ST_OFF) ; #endif // scorro i piani di ZConst ricavati... - for ( int i = 0 ; i < ssize( vvCrvCompo) ; ++ i) { + for ( int i = 0 ; i < ssize( matCompo) ; ++ i) { // Dalle curve si ricavano le PolyLine corrispondeti e vengono suddivise in 3 categorie : // - PolyLine valide : definite da punti di campionamento consecutivi dove esiste una normale di // di collisione con angolo rispetto a vtTool > dSplitAngDeg @@ -5006,20 +5548,20 @@ SurfFinishing::CalcOptimalZConstCurves( const ISurfFlatRegion* pSfrLoc, const SU double dSfrDist = 0. ; // per il piano corrente scorro le curve di Silhouette ricavate - for ( int j = 0 ; j < ssize( vvCrvCompo[i]) ; ++ j) { + for ( int j = 0 ; j < ssize( matCompo[i]) ; ++ j) { // se curva non valida, passo alla successiva - if ( IsNull( vvCrvCompo[i][j]) || ! vvCrvCompo[i][j]->IsValid()) + if ( IsNull( matCompo[i][j]) || ! matCompo[i][j]->IsValid()) continue ; - dSfrDist = vvCrvCompo[i][j]->GetTempParam( 0) ; // [*] + dSfrDist = matCompo[i][j]->GetTempParam( 0) ; // [*] #if ENABLE_OPTIMAL_DEBUG - int nCrvOrigId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLayOrigCrv, vvCrvCompo[i][j]->Clone()) ; + int nCrvOrigId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLayOrigCrv, matCompo[i][j]->Clone()) ; m_pGeomDB->SetMaterial( nCrvOrigId, ORANGE) ; #endif // recupero la PolyLine della curva corrente e la campiono PolyLine PL ; - vvCrvCompo[i][j]->ApproxWithLines( EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_STD, PL) ; + matCompo[i][j]->ApproxWithLines( EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_STD, PL) ; if ( ! PL.AdjustForMaxSegmentLen( dDist)) return false ; @@ -5034,7 +5576,7 @@ SurfFinishing::CalcOptimalZConstCurves( const ISurfFlatRegion* pSfrLoc, const SU VCT3DVECTOR vecvN ; double dMinDist = INFINITO - 1 ; for ( int nSurf = 0 ; nSurf < ssize( vpStm) ; ++ nSurf) { - DistPointSurfTm distPtSurfTm( ptU.first, *vpStm[nSurf]) ; + DistPointSurfTm distPtSurfTm( GetToLoc( ptU.first, frSurf), *vpStm[nSurf]) ; double dMyDist = INFINITO - 2 ; if ( distPtSurfTm.GetDist( dMyDist) && dMyDist < dMinDist) { dMinDist = dMyDist ; @@ -5050,11 +5592,11 @@ SurfFinishing::CalcOptimalZConstCurves( const ISurfFlatRegion* pSfrLoc, const SU // classificazione del punto if ( ! vecvN.empty()) { for ( const Vector3d& vtN : vecvN) { - if ( abs( vtN * vtAxL) < dCosLimit) { + if ( abs( vtN * vtTool) < dCosLimit) { nPointType = VALID ; break ; } - else if ( abs( vtN * vtAxL) < dCosUpperBound) + else if ( abs( vtN * vtTool) < dCosUpperBound) nPointType = AMBIGUOUS ; } } @@ -5172,7 +5714,7 @@ SurfFinishing::CalcOptimalZConstCurves( const ISurfFlatRegion* pSfrLoc, const SU } // dalle PolyLine recupero le curve - vvCrvCompo[i].clear() ; + matCompo[i].clear() ; for ( const PolyLine& PL : vPL) { // se vuota, non faccio nulla if ( PL.GetPointNbr() < 2) @@ -5182,23 +5724,24 @@ SurfFinishing::CalcOptimalZConstCurves( const ISurfFlatRegion* pSfrLoc, const SU if ( dLen < m_TParams.m_dDiam) continue ; // definisco la curva - PtrOwner pNewCompo( CreateCurveComposite()) ; - if ( IsNull( pNewCompo) || ! pNewCompo->FromPolyLine( PL)) + PtrOwner pCompo( CreateCurveComposite()) ; + if ( IsNull( pCompo) || ! pCompo->FromPolyLine( PL)) continue ; - // aggiorno la regione per il calcolo dello ZigZag ( la funzione abbellisce le curve) + // aggiorno la regione per il calcolo dello ZigZag (la funzione abbellisce le curve) PtrOwner pSfrColl( CreateSurfFlatRegion()) ; - CalcOptimalZigZagSfrByZConstCrv( pSfrLoc, vpStm, vtAxL, - dExtraOffs, pNewCompo, pSfrColl) ; + CalcOptimalZigZagSfrByZConstCrv( pSfrCnt, vtTool, vtMove, - dExtraOffs, pCompo, pSfrColl) ; if ( ! IsNull( pSfrColl) && pSfrColl->IsValid()) { if ( ! pSfrToolColl->IsValid()) pSfrToolColl->CopyFrom( pSfrColl) ; else pSfrToolColl->Add( *pSfrColl) ; } - vvCrvCompo[i].emplace_back( Release( pNewCompo)) ; + matCompo[i].emplace_back( Release( pCompo)) ; // memorizzo come primo TempParam la distanza della superficie ( per coerenza) - vvCrvCompo[i].back()->SetTempParam( dSfrDist, 0) ; + matCompo[i].back()->SetTempParam( dSfrDist, 0) ; + #if ENABLE_OPTIMAL_DEBUG - int a = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLayCrv, vvCrvCompo[i].back()->Clone()) ; + int a = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLayCrv, matCompo[i].back()->Clone()) ; m_pGeomDB->SetMaterial( a, FUCHSIA) ; #endif } @@ -5206,29 +5749,38 @@ SurfFinishing::CalcOptimalZConstCurves( const ISurfFlatRegion* pSfrLoc, const SU // la superficie complessiva di collisione viene limitata al bordo if ( pSfrToolColl->IsValid()) { - #if 0 - pSfrToolColl->Offset( - dExtraOffs, ICurve::OFF_FILLET) ; - #endif - if ( pSfrToolColl->IsValid()) - pSfrToolColl->Intersect( *pSfrLoc) ; + pSfrToolColl->Intersect( *pSfrCnt) ; + #if ENABLE_OPTIMAL_DEBUG int a = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLaySfrColl, pSfrToolColl->Clone()) ; m_pGeomDB->SetMaterial( a, Color( 255, 0, 255, 50)) ; #endif } - // collego tra loro le curve trovate definendo quindi un percorso - ICRVCOMPOPOVECTOR vCrv ; - if ( ! CreateZConstPaths( pCAvTlStm, vpStm, frSurf, vvCrvCompo, vtTool, pMySfrZConst, dDepth, vCrv)) { + // collego tra loro le curve trovate + ICRVCOMPOPOVECTOR vCompoPath ; + if ( ! CreateZConstPaths( pCAvTlStm, vpStm, frSurf, matCompo, vtTool, vtMove, pMySfrCnt, dMyDepth, vCompoPath)) { m_pMchMgr->SetLastError( 3127, "Error in SurfFinishing : Computing ZConst Paths failed") ; return false ; } + // se non ho percorsi, errore + if ( vCompoPath.empty()) + return true ; // restituisco i percorsi trovati - for ( int i = 0 ; i < ssize( vCrv) ; ++ i) { + for ( int i = 0 ; i < ssize( vCompoPath) ; ++ i) { + // verifico la vaidità del percorso + if ( IsNull( vCompoPath[i]) || ! vCompoPath[i]->IsValid()) + continue ; + // memorizzo le informazioni vPaths.resize( vPaths.size() + 1) ; - vPaths.back().pCrvPath.Set( Release( vCrv[i])) ; + vPaths.back().pCrvPath.Set( ::Release( vCompoPath[i])) ; vPaths.back().nType = SURFFIN_SUB_Z_CONST ; + + #if ENABLE_OPTIMAL_DEBUG + int nCrvId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLayZConstPath, vPaths.back().pCrvPath->Clone()) ; + m_pGeomDB->SetMaterial( nCrvId, RED) ; + #endif } return true ; @@ -5316,31 +5868,45 @@ SurfFinishing::AreSameSfrChunkEpsilon( const ISurfFlatRegion* pSfrChunkA, const //---------------------------------------------------------------------------- bool -SurfFinishing::CalcOptimalZigZagRegion( const ISurfFlatRegion* pSfrCntLoc, const ISurfFlatRegion* pSfrZLevelColl, ISURFFRPOVECTOR& vpSfrZigZagProj) const +SurfFinishing::CalcOptimalZigZagRegion( const ISurfFlatRegion* pSfrCnt, const ISurfFlatRegion* pSfrZLevelColl, ISURFFRPOVECTOR& vpSfrZigZagProj) const { // verifico validità dei parametri - if ( pSfrCntLoc == nullptr || ! pSfrCntLoc->IsValid()) + if ( pSfrCnt == nullptr || ! pSfrCnt->IsValid()) return false ; vpSfrZigZagProj.clear() ; + // alla regione di contorno effettuo un offset del raggio untensile (in questo modo la regione definisce le posizioni ammissibili + // per il centro utensile) + PtrOwner pMySfrCnt( pSfrCnt->CreateOffsetSurf( - m_TParams.m_dDiam / 2., ICurve::OFF_FILLET)) ; + if ( IsNull( pMySfrCnt) || ! pMySfrCnt->IsValid()) + return false ; + // se non esiste una regione di ZLevelColl, quindi non esistono curve di Zlevel, tutta la superficie deve // essere lavorata in ZigZag if ( pSfrZLevelColl == nullptr || ! pSfrZLevelColl->IsValid()) - return ( vpSfrZigZagProj.emplace_back( CloneSurfFlatRegion( pSfrCntLoc))) ; + return ( vpSfrZigZagProj.emplace_back( ::Release( pMySfrCnt))) ; + // effettuo un piccolo Offset di separazione tra la regione ZigZag e ZConst (evito Spikes in caso di pareti verticali) + const double EXTRA_OFFS_TOL = 25. * EPS_SMALL ; // (alzare se necessario) + PtrOwner pMySfrZLevelColl( pSfrZLevelColl->CreateOffsetSurf( - m_TParams.m_dDiam / 2. + EXTRA_OFFS_TOL, ICurve::OFF_FILLET)) ; + if ( IsNull( pMySfrZLevelColl)) + return false ; + if ( ! pMySfrZLevelColl->IsValid()) + return ( vpSfrZigZagProj.emplace_back( ::Release( pMySfrCnt))) ; + + // recupero la superficie per la lavorazione a ZigZag + PtrOwner pSfrZigZag( CreateSurfFlatRegion()) ; + if ( IsNull( pSfrZigZag) || ! pSfrZigZag->CopyFrom( pSfrCnt)) + return false ; + if ( ! pSfrZigZag->Subtract( *pMySfrZLevelColl)) + return false ; // separo ogni Chunk della regione a ZigZag (ognuno di essi verrà lavorato singolarmanete) - PtrOwner pSfrZigZag( CloneSurfFlatRegion( pSfrCntLoc)) ; - if ( IsNull( pSfrZigZag) || ! pSfrZigZag->IsValid()) - return false ; - if ( ! pSfrZigZag->Subtract( *pSfrZLevelColl)) - return false ; if ( pSfrZigZag->IsValid()) { #if 0 m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSfrZigZag->Clone()) ; #endif // Offset di confine tra passata Zlevel e ZigZag (per sicurezza è meglio lasciare questo valore non nullo, dato che la CAv è fatta // su una PolyLine che potrebbe approssimare archi, trovando quindi collisioni nei punti intermedi di esso creando Spike verticali) - const double EXTRA_OFFS_TOL = 25. * EPS_SMALL ; // (alzare se necessario) for ( int nC = 0 ; nC < pSfrZigZag->GetChunkCount() ; ++ nC) { PtrOwner pSfrZigZagChunk( pSfrZigZag->CloneChunk( nC)) ; if ( ! IsNull( pSfrZigZagChunk) && pSfrZigZagChunk->IsValid()) { @@ -5349,20 +5915,11 @@ SurfFinishing::CalcOptimalZigZagRegion( const ISurfFlatRegion* pSfrCntLoc, const pSfrZigZagChunk->GetMaxOffset( dMaxOffs) ; if ( dMaxOffs < m_TParams.m_dDiam / 2. - 20. * EPS_SMALL) continue ; + // non esco dal bordo originale + pSfrZigZagChunk->Intersect( *pMySfrCnt) ; #if 0 m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSfrZigZagChunk->Clone()) ; #endif - // Effettuo un Offset per portare la regione di ZigZag a confine con la regione di Finitura ZConst (in tolleranza) - if ( ! pSfrZigZagChunk->Offset( m_TParams.m_dDiam / 2. - EXTRA_OFFS_TOL, ICurve::OFF_FILLET)) - return false ; - // Regolarizzo la regione mediante Offset-ControOffset - pSfrZigZagChunk->Offset( - m_TParams.m_dDiam / 2., ICurve::OFF_FILLET) ; - pSfrZigZagChunk->Offset( m_TParams.m_dDiam / 2., ICurve::OFF_FILLET) ; - // evito in ogni modo di uscire dalla regione originaria - pSfrZigZagChunk->Intersect( *pSfrCntLoc) ; - #if 0 - m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSfrZigZagChunk->Clone()) ; - #endif vpSfrZigZagProj.emplace_back( Release( pSfrZigZagChunk)) ; } } @@ -5374,8 +5931,8 @@ SurfFinishing::CalcOptimalZigZagRegion( const ISurfFlatRegion* pSfrCntLoc, const //---------------------------------------------------------------------------- bool SurfFinishing::AddOptimal( ICAvToolSurfTm* pCAvTlStm, const SURFLOCALVECTOR& vSrfLoc, const Frame3d& frSurf, - const ISurfFlatRegion* pSfrCnt, const ISurfFlatRegion* pSfrCntExt, - const Vector3d& vtTool, const Vector3d& vtMove, double dDepth, double dElev, bool bSplitArcs) + const ISurfFlatRegion* pSfrCnt, const ISurfFlatRegion* pSfrCntExt, const Vector3d& vtTool, + const Vector3d& vtMove, double dDepth, double dElev, bool bSplitArcs) { // se entrambe le regioni non sono valide, non faccio nulla if ( ( pSfrCnt == nullptr || ! pSfrCnt->IsValid()) && ( pSfrCntExt == nullptr || ! pSfrCntExt->IsValid())) @@ -5385,27 +5942,19 @@ SurfFinishing::AddOptimal( ICAvToolSurfTm* pCAvTlStm, const SURFLOCALVECTOR& vSr double dAngDegSplit = 45. ; GetValInNotes( m_Params.m_sUserNotes, UN_SPLITANGLE, dAngDegSplit) ; double dAngDegTol = 5. ; GetValInNotes( m_Params.m_sUserNotes, UN_ANGLETOL, dAngDegTol) ; - // tengo una copia della regione di contorno in locale alle superfici - PtrOwner pSfrCntLoc( CloneSurfFlatRegion( pSfrCnt)) ; - if ( IsNull( pSfrCntLoc) || ! pSfrCntLoc->IsValid() || ! pSfrCntLoc->ToLoc( frSurf)) - return false ; - // --- [1°] calcolo delle curve ZLevel e [2°] definizione della regione di proiezione per Zlevel --- - PtrOwner pSfrCntLimit( pSfrCntLoc->CreateOffsetSurf( - m_TParams.m_dDiam / 2. + EPS_SMALL, ICurve::OFF_FILLET)) ; - if ( IsNull( pSfrCntLimit)) - return false ; - // calcolo tutte le curve a ZLevel e determino la regione rimossa da queste curve VECTORPATHS vPathsZConst ; PtrOwner pSfrZLevelColl( CreateSurfFlatRegion()) ; if ( IsNull( pSfrZLevelColl) || - ! CalcOptimalZConstCurves( pSfrCntLimit, vSrfLoc, frSurf, vtTool, dAngDegSplit, dAngDegTol, dDepth, pCAvTlStm, vPathsZConst, pSfrZLevelColl)) { + ! CalcOptimalZConstCurves( pSfrCnt, vSrfLoc, frSurf, vtTool, vtMove, dAngDegSplit, dAngDegTol, dDepth, pCAvTlStm, + vPathsZConst, pSfrZLevelColl)) { m_pMchMgr->SetLastError( 3124, "Error in SurfFinishing : region not computable") ; return false ; } // [3°] calcolo della regione di proiezione ZigZag --- ISURFFRPOVECTOR vSfrZigZagProj ; - if ( ! CalcOptimalZigZagRegion( pSfrCntLimit, pSfrZLevelColl, vSfrZigZagProj)) { + if ( ! CalcOptimalZigZagRegion( pSfrCnt, pSfrZLevelColl, vSfrZigZagProj)) { m_pMchMgr->SetLastError( 3124, "Error in SurfFinishing : region not computable") ; return false ; } @@ -5413,7 +5962,7 @@ SurfFinishing::AddOptimal( ICAvToolSurfTm* pCAvTlStm, const SURFLOCALVECTOR& vSr // [4°] calcolo delle curve ZigZag --- VECTORPATHS vPathsZigZag ; if ( ! vSfrZigZagProj.empty()) { - if ( ! CalcOptimalZigZagCurves( vSfrZigZagProj, frSurf, vtTool, dDepth, pCAvTlStm, vPathsZigZag)) { + if ( ! CalcOptimalZigZagCurves( vSfrZigZagProj, frSurf, vtTool, vtMove, dDepth, pCAvTlStm, vPathsZigZag)) { m_pMchMgr->SetLastError( 3124, "Error in SurfFinishing : region not computable") ; return false ; } @@ -5421,18 +5970,6 @@ SurfFinishing::AddOptimal( ICAvToolSurfTm* pCAvTlStm, const SURFLOCALVECTOR& vSr if ( vPathsZConst.empty() && vPathsZigZag.empty()) return true ; - // porto tutti i percorsi in globale - for ( PATH& path : vPathsZConst) { - if ( IsNull( path.pCrvPath) || ! path.pCrvPath->IsValid()) - continue ; - path.pCrvPath->ToGlob( frSurf) ; - } - for ( PATH& path : vPathsZigZag) { - if ( IsNull( path.pCrvPath) || ! path.pCrvPath->IsValid()) - continue ; - path.pCrvPath->ToGlob( frSurf) ; - } - // ordino i percorsi ricavati, priorità alle curve di ZConst per pareti verticali VECTORPATHS vPaths ; if ( ! OrderOptimalPathsByZLoc( pSfrCntExt, pSfrCnt, vPathsZConst)) @@ -5479,7 +6016,7 @@ SurfFinishing::AddOptimal( ICAvToolSurfTm* pCAvTlStm, const SURFLOCALVECTOR& vSr for ( int i = 0 ; i < ssize( vPaths) ; ++ i) vCrvCompo[i].Set( Release( vPaths[i].pCrvPath)) ; if ( ! AddFinishing( ( pSfrCntExt == nullptr || ! pSfrCntExt->IsValid()) ? pSfrCnt : pSfrCntExt, - pCAvTlStm, frSurf, vCrvCompo, vtTool, vtMove, dElev, dDepth, bSplitArcs)) + pCAvTlStm, vSrfLoc, frSurf, vCrvCompo, vtTool, vtMove, dElev, dDepth, bSplitArcs)) return false ; return true ; @@ -5639,7 +6176,7 @@ SurfFinishing::AddProjection( ICAvToolSurfTm* pCAvTlStm, const SURFLOCALVECTOR& for ( int i = 0 ; i < ssize( vCrvToProj) ; ++ i) { ICRVCOMPOPOVECTOR vCrvSingle ; vCrvSingle.emplace_back( Release( vCrvToProj[i])) ; - if ( ! AddFinishing( nullptr, pCAvTlStm, frSurf, vCrvSingle, vtTool, vtMove, dElev, dDepth, bSplitArcs)) + if ( ! AddFinishing( nullptr, pCAvTlStm, vSrfLoc, frSurf, vCrvSingle, vtTool, vtMove, dElev, dDepth, bSplitArcs)) return false ; } @@ -5945,25 +6482,25 @@ SurfFinishing::GetLastGoodPoint( ICAvToolSurfTm* pCAvTlStm, const Frame3d& frSur if ( bLeadInVsOut) { // recupero il tipo di LeadIn switch( GetLeadInType()) { - case SURFFIN_LI_NONE : - return true ; - case SURFFIN_LI_LINEAR : { - // inserisco gli estremi del tratto lineare - lstPntU = { { ptStartL, 0}, { ptEndL, 1}} ; - } - break ; - case SURFFIN_LI_TANGENT : { - // definisco la curva ad arco - PtrOwner pCrv( GetArc2PVN( ptEndL, ptStartL, - vtInitL, vtToolL)) ; - if ( IsNull( pCrv)) - return false ; - pCrv->Invert() ; - // inserisco i punti nella lista, campionandola - PolyLine PL ; - pCrv->ApproxWithLines( m_Params.m_dApprox, EPS_ANG_SMALL, ICurve::APL_SPECIAL, PL) ; - lstPntU = PL.GetUPointList() ; - } - break ; + case SURFFIN_LI_NONE : + return true ; + case SURFFIN_LI_LINEAR : { + // inserisco gli estremi del tratto lineare + lstPntU = { { ptStartL, 0}, { ptEndL, 1}} ; + } + break ; + case SURFFIN_LI_TANGENT : { + // definisco la curva ad arco + PtrOwner pCrv( GetArc2PVN( ptEndL, ptStartL, - vtInitL, vtToolL)) ; + if ( IsNull( pCrv)) + return false ; + pCrv->Invert() ; + // inserisco i punti nella lista, campionandola + PolyLine PL ; + pCrv->ApproxWithLines( m_Params.m_dApprox, EPS_ANG_SMALL, ICurve::APL_SPECIAL, PL) ; + lstPntU = PL.GetUPointList() ; + } + break ; } lstPntU.reverse() ; } @@ -5983,30 +6520,30 @@ SurfFinishing::GetLastGoodPoint( ICAvToolSurfTm* pCAvTlStm, const Frame3d& frSur } // eseguo a seconda del tipo switch( nType) { - case SURFFIN_LO_NONE : - return true ; - case SURFFIN_LO_LINEAR : { - // inserisco gli estremi del tratto lineare - lstPntU = { { ptStartL, 0}, { ptEndL, 1}} ; - } - break ; - case SURFFIN_LO_TANGENT : { - // definisco la curva ad arco - PtrOwner pCrv( GetArc2PVN( ptStartL, ptEndL, vtInitL, vtToolL)) ; - if ( IsNull( pCrv)) - return false ; - // inserisco i punti nella lista, campionandola - PolyLine PL ; - pCrv->ApproxWithLines( m_Params.m_dApprox, EPS_ANG_SMALL, ICurve::APL_SPECIAL, PL) ; - lstPntU = PL.GetUPointList() ; - } - break ; + case SURFFIN_LO_NONE : + return true ; + case SURFFIN_LO_LINEAR : { + // inserisco gli estremi del tratto lineare + lstPntU = { { ptStartL, 0}, { ptEndL, 1}} ; + } + break ; + case SURFFIN_LO_TANGENT : { + // definisco la curva ad arco + PtrOwner pCrv( GetArc2PVN( ptStartL, ptEndL, vtInitL, vtToolL)) ; + if ( IsNull( pCrv)) + return false ; + // inserisco i punti nella lista, campionandola + PolyLine PL ; + pCrv->ApproxWithLines( m_Params.m_dApprox, EPS_ANG_SMALL, ICurve::APL_SPECIAL, PL) ; + lstPntU = PL.GetUPointList() ; + } + break ; } } // se non ho inserito almeno 2 punti nella lista, non faccio nulla if ( ssize( lstPntU) < 2) - return true ; // per sicurezza... + return true ; // eseguo controllo collisione if ( ! pCAvTlStm->TestPath( lstPntU, vtToolL, vtMoveL, m_Params.m_dApprox, 0.)) @@ -6047,16 +6584,20 @@ SurfFinishing::GetLinkFromPaths( const Point3d& ptStart, const Point3d& ptEnd, c Vector3d vtToolL = GetToLoc( vtTool, frSurf) ; Vector3d vtMoveL = GetToLoc( vtMove, frSurf) ; // porto i punti sul top dell'utensile - ptEndL += vtToolL * m_TParams.m_dLen ; - ptStartL += vtToolL * m_TParams.m_dLen ; + ptEndL += vtToolL * m_TParams.m_dLen - vtMoveL * dDepth ; + ptStartL += vtToolL * m_TParams.m_dLen - vtMoveL * dDepth ; - // mi assicuro che il collegamento non interferica con la superficie + // mi assicuro che il collegamento non interferisca con la superficie PNTULIST lstPntU{ { ptEndL, 0.}, { ptStartL, 1.}} ; if ( ! pCAvTlStm->TestPath( lstPntU, vtToolL, vtMoveL, m_Params.m_dApprox, 0.)) return false ; // determino un piano al di sotto della lavorazione, orientato come pSfrCnt // --- serve per individuare la quota ZLocMax per i Link tra le curve di finitura + Frame3d frMove ; + if ( ! frMove.Set( ORIG, vtMove)) + return false ; + Point3d ptC ; pSfrCnt->GetCentroid( ptC) ; Plane3d plZLocMin ; if ( ! plZLocMin.Set( ptC, vtMove)) @@ -6138,21 +6679,130 @@ SurfFinishing::GetRadiusForStartEndElevation( void) const //---------------------------------------------------------------------------- bool -SurfFinishing::AddFinishing( const ISurfFlatRegion* pSfrCnt, ICAvToolSurfTm* pCAvTlStm, const Frame3d& frSurf, const ICRVCOMPOPOVECTOR& vCrvCompo, - const Vector3d& vtTool, const Vector3d& vtMove, double dElev, double dDepth, bool bSplitArcs) +SurfFinishing::AdjustStartEndPoints( ICAvToolSurfTm* pCAvTlStm, const CISURFTMPVECTOR& vpStmLoc, const Frame3d& frSurf, ICurveComposite* pCompo, + const Vector3d& vtTool, const Vector3d& vtMove) const +{ + // verifica dei parametri in ingresso + if ( pCAvTlStm == nullptr || pCompo == nullptr) + return false ; + if ( ! pCompo->IsValid()) + return true ; + + // se la direzione utensile e la direzione di movimento sono tra loro parallele, non modifico la curva + if ( AreSameVectorEpsilon( vtTool, vtMove, 100. * EPS_SMALL)) + return true ; + + const double EXTENSION = 5. ; + const double COS_ANG_TOL = cos( ( ANG_RIGHT - 2.) * DEGTORAD) ; + + for ( int i = 0 ; i < 1 ; ++ i) { + bool bStart = ( i == 0) ; + if ( bStart && GetLeadInType() != SURFFIN_LI_NONE && m_Params.m_dLiTang < EPS_SMALL && m_Params.m_dLiPerp < EPS_SMALL) + continue ; + if ( ! bStart && GetLeadOutType() == SURFFIN_LO_NONE && m_Params.m_dLoTang < EPS_SMALL && m_Params.m_dLoPerp < EPS_SMALL) + continue ; + + // recupero il punto corrente e la direzione corrente + Point3d ptCurr ; Vector3d vtTan ; + if ( bStart) { + pCompo->GetStartPoint( ptCurr) ; + pCompo->GetStartDir( vtTan) ; + } + else { + pCompo->GetEndPoint( ptCurr) ; + pCompo->GetEndDir( vtTan) ; + } + + // se la direzione tangente e la direzione di movimento hanno tra loro un angolo inferiore a 90deg aggiungo un tratto di estensione + if ( vtTan * vtTool < COS_ANG_TOL) + continue ; + + // il tratto di estensione è perpendicolare alla superficie + VCT3DVECTOR vVtN ; + double dMinDist = INFINITO - 1 ; + for ( int nSurf = 0 ; nSurf < ssize( vpStmLoc) ; ++ nSurf) { + DistPointSurfTm distPtSurfTm( GetToLoc( ptCurr, frSurf), *vpStmLoc[nSurf]) ; + double dMyDist = INFINITO - 2 ; + if ( distPtSurfTm.GetDist( dMyDist) && dMyDist < dMinDist) { + dMinDist = dMyDist ; + INTVECTOR vTriaMinDist ; distPtSurfTm.GetMinDistTriaIndices( vTriaMinDist) ; + vVtN.clear() ; + Triangle3d Tria ; + for ( int nTria : vTriaMinDist) { + vpStmLoc[nSurf]->GetTriangle( nTria, Tria) ; + vVtN.push_back( Tria.GetN()) ; + } + } + } + Vector3d vtNorm ; + for ( const Vector3d& vtN : vVtN) { + if ( vtN * vtTool < COS_ANG_TOL) + continue ; + vtNorm += vtN ; + } + vtNorm.Normalize() ; + + // determino il nuovo punto candidato + Point3d ptNew = ptCurr + vtNorm * EXTENSION ; + if ( ! GetLastGoodPoint( pCAvTlStm, frSurf, ptCurr, ptNew, vtNorm, vtTool, vtNorm, bStart, ptNew)) + return false ; + + // aggiungo il tratto fino al punto corrente + if ( ! AreSamePointEpsilon( ptCurr, ptNew, 10. * EPS_SMALL)) + pCompo->AddLine( ptNew, ! bStart) ; + } + + return true ; +} + +//---------------------------------------------------------------------------- +bool +SurfFinishing::AddFinishing( const ISurfFlatRegion* pSfrCnt, ICAvToolSurfTm* pCAvTlStm, const SURFLOCALVECTOR& vSrfLoc, const Frame3d& frSurf, + const ICRVCOMPOPOVECTOR& vCompo, const Vector3d& vtTool, const Vector3d& vtMove, double dElev, + double dDepth, bool bSplitArcs) { // se non ho curve, non faccio nulla - if ( vCrvCompo.empty()) + if ( vCompo.empty()) return true ; // se classe di calcolo per le collisioni non inizializzata, errore if ( pCAvTlStm == nullptr) return false ; // tutte le curve devono essere valide e ben definite - for ( const PtrOwner& pMCrv : vCrvCompo) { + for ( const PtrOwner& pMCrv : vCompo) { if ( pMCrv == nullptr || ! pMCrv->IsValid()) return false ; } + // recupero le superfici di selezione + CISURFTMPVECTOR vpStmLoc ; vpStmLoc.reserve( vSrfLoc.size()) ; + for ( int i = 0 ; i < ssize( vSrfLoc) ; ++ i) { + // recupero la superficie + const ISurf* pSurf = GetSurf( vSrfLoc[i].Get()) ; + if ( pSurf == nullptr || ! pSurf->IsValid()) + continue ; + int nType = pSurf->GetType() ; + // se TriMesh + if ( nType == SRF_TRIMESH) { + const ISurfTriMesh* pStm = GetSurfTriMesh( pSurf) ; + // se valida, memorizzo + if ( pStm != nullptr && pStm->IsValid() && pStm->GetTriangleCount() > 0) + vpStmLoc.emplace_back( pStm) ; + } + // se Bezier + if ( nType == SRF_BEZIER) { + const ISurfBezier* pSBz = GetSurfBezier( pSurf) ; + if ( pSBz != nullptr && pSBz->IsValid()) { + double dOldTol = GetSurfBezierAuxSurfRefinedTol() ; + SetSurfBezierAuxSurfRefinedTol( 5. * EPS_SMALL) ; + const ISurfTriMesh* pStm = pSBz->GetAuxSurfRefined() ; + SetSurfBezierAuxSurfRefinedTol( dOldTol) ; + // se valida, memorizzo + if ( pStm != nullptr && pStm->IsValid() && pStm->GetTriangleCount() > 0) + vpStmLoc.emplace_back( pStm) ; + } + } + } + // recupero distanze di sicurezza double dSafeZ = GetSafeZ() ; // lunghezza di approccio/retrazione @@ -6168,35 +6818,60 @@ SurfFinishing::AddFinishing( const ISurfFlatRegion* pSfrCnt, ICAvToolSurfTm* pCA m_pGeomDB->SetName( nLayLink, "links") ; int nLayLeadInOut = m_pGeomDB->AddGroup( GDB_ID_NULL, nGrp, GLOB_FRM) ; m_pGeomDB->SetName( nLayLeadInOut, "leadInOut") ; - Vector3d vtToolL = GetToLoc( vtTool, frSurf) ; #endif // ciclo sulle curve - bool bStart = true ; double dStElev = dElev ; - Point3d ptStart, ptP1 ; + Point3d ptCurr, ptStart, ptP1 ; Vector3d vtStart ; - for ( int nCrv = 0 ; nCrv < ssize( vCrvCompo) ; ++ nCrv) { + bool bFirst = true ; + double dLastElev = 0. ; + for ( int nCompo = 0 ; nCompo < ssize( vCompo) ; ++ nCompo) { + + // recupero la curva corrente + ICurveComposite* pCompo = vCompo[nCompo] ; + if ( pCompo == nullptr || ! pCompo->IsValid()) + continue ; + + // se direzione utensile e direzione movimento non parallele tra di loro aggiungo un piccolo raccordo all'inizio e alla + // fine della curva corrente per evitare LeadIn/LeadOut con angoli piccoli + if ( ! AreSameVectorEpsilon( vtTool, vtMove, 10. * EPS_SMALL)) { + if ( ! AdjustStartEndPoints( pCAvTlStm, vpStmLoc, frSurf, pCompo, vtTool, vtMove)) + return false ; + } #if ENABLE_LINK_DEBUG - int nIdCrv = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLayCurve, CloneCurveComposite( vCrvCompo[nCrv])) ; - m_pGeomDB->SetMaterial( nIdCrv, PURPLE) ; + int nIdCrv = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLayCurve, pCompo->Clone()) ; + m_pGeomDB->SetMaterial( nIdCrv, FUCHSIA) ; #endif // ciclo sulle curve elementari - int nMaxInd = vCrvCompo[nCrv]->GetCurveCount() - 1 ; + int nMaxInd = pCompo->GetCurveCount() - 1 ; for ( int i = 0 ; i <= nMaxInd ; ++ i) { // curva corrente - const ICurve* pCrvC = vCrvCompo[nCrv]->GetCurve( i) ; + const ICurve* pCrvC = pCompo->GetCurve( i) ; // copio la curva PtrOwner pCurve( pCrvC->Clone()) ; if ( IsNull( pCurve)) return false ; - // --- se prima entità in assoluto - if ( bStart) { - // dati inizio entità + // prima entità + if ( i == 0) { + + // se esiste un percorso precedente + if ( ! bFirst) { + + // aggiungo la retroazione del nuovo percorso + GetCurrPos( ptCurr) ; + if ( ! AddRetract( ptCurr, vtTool, dSafeZ, dLastElev, dAppr)) { + m_pMchMgr->SetLastError( 3115, "Error in SurfFinishing : Retract not computable") ; + return false ; + } + GetCurrPos( ptCurr) ; + } + + // dati di inizio entità pCurve->GetStartPoint( ptStart) ; pCurve->GetStartDir( vtStart) ; // determino normale della superficie sul punto iniziale @@ -6209,6 +6884,42 @@ SurfFinishing::AddFinishing( const ISurfFlatRegion* pSfrCnt, ICAvToolSurfTm* pCA // determino inizio attacco if ( ! CalcLeadInStart( ptStart, vtStart, vtTool, vtNorm, ptP1)) return false ; + + // determino elevazione su inizio attacco + if ( ! GetElevation( m_nPhase, ptStart - ( m_TParams.m_dDiam / 2.) * vtTool, vtTool, GetRadiusForStartEndElevation(), vtTool, dStElev)) + dStElev = dElev ; + dStElev -= ( ptP1 - ptStart) * vtTool ; + + // se esiste un percorso precedente + if ( ! bFirst) { + // calcolo il punto di approccio + Point3d ptAppr ; + if ( dSafeZ < dAppr + 10 * EPS_SMALL) + ptAppr = ptP1 + vtTool * dStElev ; + else + ptAppr = ptP1 + vtTool * ( dStElev + dSafeZ) ; + + // se il punto corrente e di futuro approccio non coicidono + if ( ! AreSamePointEpsilon( ptCurr, ptAppr, 10. * EPS_SMALL)) { + // calcolo l'elevazione al di sopra del possibile link lineare + double dLinkElev = 0. ; + if ( ! GetElevation( m_nPhase, ptCurr - ( m_TParams.m_dDiam / 2.) * vtTool, ptAppr - ( m_TParams.m_dDiam / 2.) * vtTool, vtTool, + m_TParams.m_dDiam / 2., m_TParams.m_dLen, vtMove, dLinkElev)) + return false ; + // aggiungo il link + if ( dLinkElev > 10. * EPS_SMALL) { + if ( AddRapidMove( ptCurr + vtMove * dLinkElev) == GDB_ID_NULL || + AddRapidMove( ptAppr + vtMove * dLinkElev) == GDB_ID_NULL || + AddRapidMove( ptAppr) == GDB_ID_NULL) + return false ; + } + else { + if ( AddRapidMove( ptAppr) == GDB_ID_NULL) + return false ; + } + } + } + #if ENABLE_LINK_DEBUG PtrOwner pt( CreateGeoPoint3d()) ; pt->Set( ptStart) ; @@ -6218,24 +6929,19 @@ SurfFinishing::AddFinishing( const ISurfFlatRegion* pSfrCnt, ICAvToolSurfTm* pCA nPtId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLayLeadInOut, pt->Clone()) ; m_pGeomDB->SetMaterial( nPtId, AQUA) ; #endif - // eventuale correzione inizio attacco per evitare interferenze - if ( ! GetLastGoodPoint( pCAvTlStm, frSurf, ptP1, ptStart, vtStart, vtTool, vtMove, true, ptP1)) - return false ; + #if ENABLE_LINK_DEBUG pt->Set( ptP1) ; nPtId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLayLeadInOut, pt->Clone()) ; m_pGeomDB->SetMaterial( nPtId, TEAL) ; #endif - // determino elevazione su inizio attacco - if ( ! GetElevation( m_nPhase, ptStart - 10. * EPS_SMALL * vtTool, vtTool, GetRadiusForStartEndElevation(), vtMove, dStElev)) - dStElev = dElev ; - dStElev -= ( ptP1 - ptStart) * vtTool ; - // --- approccio globale al punto iniziale + + // approccio globale al punto iniziale if ( ! AddApproach( ptP1, vtTool, dSafeZ, dStElev, dAppr)) { m_pMchMgr->SetLastError( 3111, "Error in SurfFinishing : Approach not computable") ; return false ; } - bStart = false ; + // --- aggiungo attacco SetFeed( GetStartFeed()) ; if ( ! AddLeadIn( ptP1, ptStart, vtStart, vtTool, bSplitArcs)) { @@ -6266,76 +6972,60 @@ SurfFinishing::AddFinishing( const ISurfFlatRegion* pSfrCnt, ICAvToolSurfTm* pCA // dati fine entità Point3d ptEnd ; pCurve->GetEndPoint( ptEnd) ; Vector3d vtEnd ; pCurve->GetEndDir( vtEnd) ; - // --- se ultima entità in assoluto - if ( nCrv == ssize( vCrvCompo) - 1) { - // determino normale della superficie sul punto finale - Vector3d vtNorm ; - if ( ! GetSurfaceNormalAtPoint( pCAvTlStm, frSurf, ptEnd, vtTool, vtMove, vtNorm)) { - Point3d ptStart ; pCurve->GetStartPoint( ptStart) ; - if ( ! GetSurfaceNormalAtPoint( pCAvTlStm, frSurf, ptStart, vtTool, vtMove, vtNorm)) - vtNorm = V_NULL ; - } - // determino fine uscita - if ( ! CalcLeadOutEnd( ptEnd, vtEnd, vtTool, vtNorm, ptP1)) - return false ; - #if ENABLE_LINK_DEBUG - PtrOwner pt( CreateGeoPoint3d()) ; - pt->Set( ptEnd) ; - int nPtId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLayLeadInOut, pt->Clone()) ; - m_pGeomDB->SetMaterial( nPtId, BLUE) ; - pt->Set( ptP1) ; - nPtId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLayLeadInOut, pt->Clone()) ; - m_pGeomDB->SetMaterial( nPtId, AQUA) ; - #endif - // eventuale correzione fine uscita per evitare interferenze - if ( ! GetLastGoodPoint( pCAvTlStm, frSurf, ptEnd, ptP1, vtEnd, vtTool, vtMove, false, ptP1)) - return false ; - #if ENABLE_LINK_DEBUG - pt->Set( ptP1) ; - nPtId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLayLeadInOut, pt->Clone()) ; - m_pGeomDB->SetMaterial( nPtId, TEAL) ; - #endif - // aggiungo uscita - SetFeed( GetEndFeed()) ; - if ( ! AddLeadOut( ptEnd, vtEnd, ptP1, vtTool, bSplitArcs)) { - m_pMchMgr->SetLastError( 3114, "Error in SurfFinishing : LeadOut not computable") ; - return false ; - } - // 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 ; - // aggiungo retroazione finale - if ( ! AddRetract( ptP1, vtTool, dSafeZ, dEndElev, dAppr)) { - m_pMchMgr->SetLastError( 3115, "Error in SurfFinishing : Retract not computable") ; - return false ; - } + // determino normale della superficie sul punto finale + Vector3d vtNorm ; + if ( ! GetSurfaceNormalAtPoint( pCAvTlStm, frSurf, ptEnd, vtTool, vtMove, vtNorm)) { + Point3d ptStart ; pCurve->GetStartPoint( ptStart) ; + if ( ! GetSurfaceNormalAtPoint( pCAvTlStm, frSurf, ptStart, vtTool, vtMove, vtNorm)) + vtNorm = V_NULL ; } - // --- se ultima entità di percorso intermedio - else { - // punto iniziale entità per la curva successiva - vCrvCompo[nCrv+1]->GetStartPoint( ptStart) ; - // se inizio e fine sono coincidenti, non faccio nulla - if ( AreSamePointApprox( ptEnd, ptStart)) - continue ; - // definisco il collegamento tra i due percorsi - PtrOwner pCrvLink( CreateCurveComposite()) ; - if ( IsNull( pCrvLink) || - ! GetLinkFromPaths( ptStart, ptEnd, vtTool, vtMove, pSfrCnt, dDepth, dSafeZ, pCAvTlStm, frSurf, pCrvLink)) - return false ; - #if ENABLE_LINK_DEBUG - int nIdLink = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLayLink, CloneCurveComposite( pCrvLink)) ; - m_pGeomDB->SetMaterial( nIdLink, RED) ; - #endif - SetFeed( GetEndFeed()) ; - if ( ! AddCurveMove( pCrvLink, bSplitArcs)) - return false ; - ptP1 = ptStart ; + + // determino fine uscita + if ( ! CalcLeadOutEnd( ptEnd, vtEnd, vtTool, vtNorm, ptP1)) + return false ; + + #if ENABLE_LINK_DEBUG + PtrOwner pt( CreateGeoPoint3d()) ; + pt->Set( ptEnd) ; + int nPtId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLayLeadInOut, pt->Clone()) ; + m_pGeomDB->SetMaterial( nPtId, BLUE) ; + pt->Set( ptP1) ; + nPtId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLayLeadInOut, pt->Clone()) ; + m_pGeomDB->SetMaterial( nPtId, AQUA) ; + #endif + + // eventuale correzione fine uscita per evitare interferenze + if ( ! GetLastGoodPoint( pCAvTlStm, frSurf, ptEnd, ptP1, vtEnd, vtTool, vtMove, false, ptP1)) + return false ; + + #if ENABLE_LINK_DEBUG + pt->Set( ptP1) ; + nPtId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLayLeadInOut, pt->Clone()) ; + m_pGeomDB->SetMaterial( nPtId, TEAL) ; + #endif + + // aggiungo uscita + SetFeed( GetEndFeed()) ; + if ( ! AddLeadOut( ptEnd, vtEnd, ptP1, vtTool, bSplitArcs)) { + m_pMchMgr->SetLastError( 3114, "Error in SurfFinishing : LeadOut not computable") ; + return false ; } + + // determino elevazione su fine uscita + if ( ! GetElevation( m_nPhase, ptEnd - ( m_TParams.m_dDiam / 2.) * vtTool, vtTool, GetRadiusForStartEndElevation(), vtTool, dLastElev)) + dLastElev = dElev ; + dLastElev -= ( ptP1 - ptEnd) * vtTool ; + + bFirst = false ; } } } + // aggiungo la retroiazione finale + GetCurrPos( ptCurr) ; + if ( ! AddRetract( ptCurr, vtTool, dSafeZ, dLastElev, dAppr)) { + m_pMchMgr->SetLastError( 3115, "Error in SurfFinishing : Retract not computable") ; + return false ; + } ExeProcessEvents( 100, 0) ; return true ; @@ -6363,13 +7053,6 @@ SurfFinishing::GetLocalSideAngle() const bool SurfFinishing::GetLocalToolDir( Vector3d& vtToolLoc) const { - // l'orientamento dell'utensile mediante il versore ausiliario definito dagli angoli theta e phi viene applicato solo - // se lavorazione in Spiral, ZigZag, OneWay o Projection - if ( m_Params.m_nSubType != SURFFIN_SUB_ZIGZAG && m_Params.m_nSubType != SURFFIN_SUB_ONEWAY && - m_Params.m_nSubType != SURFFIN_SUB_SPIRALIN && m_Params.m_nSubType != SURFFIN_SUB_SPIRALOUT && - m_Params.m_nSubType != SURFFIN_SUB_PROJECT) - return false ; - // ricerca del vettore direzione utensile locale all'interno del gruppo Owner della lavorazione di finitura corrente int nFrameId = m_pGeomDB->GetFirstNameInGroup( m_nOwnerId, MCH_AUXVIEW) ; if ( nFrameId == GDB_ID_NULL) diff --git a/SurfFinishing.h b/SurfFinishing.h index 067761a..d141668 100644 --- a/SurfFinishing.h +++ b/SurfFinishing.h @@ -50,6 +50,9 @@ struct CollisionSfr { // vettore associato typedef std::vector VECTORCOLLISIONSFR ; +// matrice di PtrOnwer di CurveComposite +typedef std::vector ICRVCOMPOPOMAT ; + //---------------------------------------------------------------------------- class SurfFinishing : public Machining { @@ -127,17 +130,17 @@ class SurfFinishing : public Machining double dSmallDefLinTol = 150. * EPS_SMALL, double dSmallDefAngTolDeg = 2. * ANG_TOL_STD_DEG, double dArcApproxLinTol = 50. * EPS_SMALL, double dArcApproxAngTolDeg = ANG_TOL_STD_DEG) const ; bool CalcZConstLink( ICurveComposite* pCompoLink, const Point3d& ptStartLink, const Point3d& ptEndLink, ICAvToolSurfTm* pCAvTlStm, - const Frame3d& frPocket, const Frame3d& frSurf, const Vector3d& vtTool, double dDepth, - const CISURFTMPVECTOR& vpStm) const ; + const Frame3d& frSurf, const Vector3d& vtTool, const Vector3d& vtMove, double dDepth, + const CISURFTMPVECTOR& vpStm, bool bAllowMove) const ; // lavorazioni per superfici - bool AddZigZag( ICAvToolSurfTm* pCAvTlStm, const Frame3d& frSurf, const ISurfFlatRegion* pSfrCnt, + bool AddZigZag( ICAvToolSurfTm* pCAvTlStm, const SURFLOCALVECTOR& vSrfLoc, const Frame3d& frSurf, const ISurfFlatRegion* pSfrCnt, const Vector3d& vtTool, const Vector3d& vtMove, double dDepth, double dElev, bool bSplitArcs) ; - bool AddOneWay( ICAvToolSurfTm* pCAvTlStm, const Frame3d& frSurf, const ISurfFlatRegion* pSfrCnt, + bool AddOneWay( ICAvToolSurfTm* pCAvTlStm, const SURFLOCALVECTOR& vSrfLoc, const Frame3d& frSurf, const ISurfFlatRegion* pSfrCnt, const Vector3d& vtTool, const Vector3d& vtMove, double dDepth, double dElev, bool bSplitArcs) ; - bool AddSpiral( ICAvToolSurfTm* pCAvTlStm, const Frame3d& frSurf, const ISurfFlatRegion* pSfrCnt, + bool AddSpiral( ICAvToolSurfTm* pCAvTlStm, const SURFLOCALVECTOR& vSrfLoc, const Frame3d& frSurf, const ISurfFlatRegion* pSfrCnt, const Vector3d& vtTool, const Vector3d& vtMove, double dDepth, double dElev, bool bSplitArcs, bool bInVsOut) ; bool AddZConst( ICAvToolSurfTm* pCAvTlStm, const SURFLOCALVECTOR& vSrfLoc, const Frame3d& frSurf, - const ISurfFlatRegion* pSfrCnt, const Vector3d& vtTool, double dDepth, double dElev, bool bSplitArcs) ; + const ISurfFlatRegion* pSfrCnt, const Vector3d& vtTool, const Vector3d& vtMove, double dDepth, double dElev, bool bSplitArcs) ; bool AddOptimal( ICAvToolSurfTm* pCAvTlStm, const SURFLOCALVECTOR& vSrfLoc, const Frame3d& frSurf, const ISurfFlatRegion* pSfrCntZigZag, const ISurfFlatRegion* pSfrCntZConst, const Vector3d& vtTool, const Vector3d& vtMove, double dDepth, double dElev, bool bSplitArcs) ; @@ -147,7 +150,9 @@ class SurfFinishing : public Machining bool AddProjection( ICAvToolSurfTm* pCAvTlStm, const SURFLOCALVECTOR& vSrfLoc, const Frame3d& frSurf, const ICurveComposite* pCompo, const Vector3d& vtTool, const Vector3d& vtMove, double dDepth, double dElev, bool bSplitArcs) ; // creazione del percorso finale di lavorazione - bool AddFinishing( const ISurfFlatRegion* pSfrCnt, ICAvToolSurfTm* pCAvTlStm, const Frame3d& frSurf, const ICRVCOMPOPOVECTOR& vCrvCompo, + bool AdjustStartEndPoints( ICAvToolSurfTm* pCAvTlStm, const CISURFTMPVECTOR& vpStmLoc, const Frame3d& frSurf, ICurveComposite* pCompo, + const Vector3d& vtTool, const Vector3d& vtMove) const ; + bool AddFinishing( const ISurfFlatRegion* pSfrCnt, ICAvToolSurfTm* pCAvTlStm, const SURFLOCALVECTOR& vSurfLoc, const Frame3d& frSurf, const ICRVCOMPOPOVECTOR& vCrvCompo, const Vector3d& vtTool, const Vector3d& vtMove, double dElev, double dDepth, bool bSplitArcs) ; // collisione con i percorsi di lavorazione bool CorrectPathByCollision( ICAvToolSurfTm* pCAvTlStm, const Frame3d& frSurf, const Vector3d& vtTool, const Vector3d& vtMove, @@ -171,18 +176,21 @@ class SurfFinishing : public Machining bool GetZConstQuotesInsideSfrParallelToTool( const SURFLOCALVECTOR&, const Frame3d& frSurf, const ISurfFlatRegion* pSfr, const Vector3d& vtTool, std::set& setZAmbiguos) const ; ISurfFlatRegion* GetSfrSilhouette( const SURFLOCALVECTOR& vSrfLoc, const Frame3d& frLvl0, double dDepth) const ; - bool CalcOptimalZConstCurves( const ISurfFlatRegion* pSfrLoc, const SURFLOCALVECTOR& vSrfLoc, - const Frame3d& frSurf, const Vector3d& vtTool, double dAngDegSplit, + bool CalcOptimalZConstCurves( const ISurfFlatRegion* pSfrLoc, const SURFLOCALVECTOR& vSrfLoc, const Frame3d& frSurf, + const Vector3d& vtTool, const Vector3d& vtMove, double dAngDegSplit, double dAngDegTol, double dDepth, ICAvToolSurfTm* pCAvTlStm, VECTORPATHS& vPaths, ISurfFlatRegion* pSfrToolColl) const ; - bool CalcOptimalZigZagSfrByZConstCrv( const ISurfFlatRegion* pSfrLoc, const CISURFTMPVECTOR& vpStm, const Vector3d& vtToolLoc, - double dExtraCollOffs, ICurveComposite* pCompoSil, ISurfFlatRegion* pSfrZigZag) const ; - bool CalcOptimalZigZagCurves( ISURFFRPOVECTOR& vSfrZigZagProj, const Frame3d& frSurf, - const Vector3d& vtTool, double dDepth, ICAvToolSurfTm* pCAvTlStm, VECTORPATHS& vPaths) const ; + bool CalcOptimalZigZagSfrByZConstCrv( const ISurfFlatRegion* pSfrLoc, const Vector3d& vtTool, + const Vector3d& vtMove, double dExtraCollOffs, ICurveComposite* pCompoSil, ISurfFlatRegion* pSfrZigZag) const ; + bool CalcOptimalZigZagCurves( ISURFFRPOVECTOR& vSfrZigZagProj, const Frame3d& frSurf, const Vector3d& vtTool, const Vector3d& vtMove, + double dDepth, ICAvToolSurfTm* pCAvTlStm, VECTORPATHS& vPaths) const ; + bool AdjustZConstFrame( const Vector3d& vtTool, Frame3d& frSfr, ISurfFlatRegion* pSfrClass, double& dRawDepth) const ; + bool AdjustZConstCurvesBySfr( const ISurfFlatRegion* pSfrCnt, const ISurfFlatRegion* pSfrClass, const Vector3d& vtTool, + const Vector3d& vtMove, double dDepth, std::vector& vCrvCompo) const ; bool CalcZConstSilCrv( ICAvParSilhouettesSurfTm* pCavParSilh, const SURFLOCALVECTOR& vSrfLoc, const Frame3d& frSurf, const ISurfFlatRegion* pSfrClass, const Vector3d& vtTool, double dDepth, std::vector& vCrvCompo) const ; bool CreateZConstPaths( ICAvToolSurfTm* pCAvTlStm, const CISURFTMPVECTOR& vpStm, const Frame3d& frSurf, - std::vector& vCrvCompo, const Vector3d& vtTool, const ISurfFlatRegion* pSfr, + std::vector& vCrvCompo, const Vector3d& vtTool, const Vector3d& vtMove, const ISurfFlatRegion* pSfr, double dDepth, ICRVCOMPOPOVECTOR& vCrvPath) const ; bool AddApproach( const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dElev, double dAppr) ; bool AddLinkApproach( const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dElev, double dAppr) ;