//---------------------------------------------------------------------------- // EgalTech 2024-2024 //---------------------------------------------------------------------------- // File : SurfRoughing.cpp Data : 24.05.24 Versione : 2.6e5 // Contenuto : Implementazione gestione sgrossatura superfici. // // Note : Questa lavorazione è sempre espressa nel riferimento globale. // // Modifiche : 24.05.24 DS Creazione modulo. // // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "MachMgr.h" #include "DllMain.h" #include "SurfRoughing.h" #include "OperationConst.h" #include "GeoConst.h" #include "/EgtDev/Include/EXeCmdLogOff.h" #include "/EgtDev/Include/EXeConst.h" #include "/EgtDev/Include/EGkCurveLine.h" #include "/EgtDev/Include/EGkCurveArc.h" #include "/EgtDev/Include/EGkCurveComposite.h" #include "/EgtDev/Include/EGkArcSpecial.h" #include "/EgtDev/Include/EGkChainCurves.h" #include "/EgtDev/Include/EGkOffsetCurve.h" #include "/EgtDev/Include/EGkSurfTriMesh.h" #include "/EgtDev/Include/EGkSfrCreate.h" #include "/EgtDev/Include/EGkCalcPocketing.h" #include "/EgtDev/Include/EGkSurfLocal.h" #include "/EgtDev/Include/EGkCAvSilhouetteSurfTm.h" #include "/EgtDev/Include/EGkIntervals.h" #include "/EgtDev/Include/EGkStringUtils3d.h" #include "/EgtDev/Include/EGkUserObjFactory.h" #include "/EgtDev/Include/EGnStringKeyVal.h" #include "/EgtDev/Include/EgtPointerOwner.h" #include "/EgtDev/Include/EGkDistPointCurve.h" #include "/EgtDev/Include/EGkDistPointSurfFr.h" #include "/EgtDev/Include/EGkCurveAux.h" #include "/EgtDev/Include/EGkDistPointSurfTm.h" #include "/EgtDev/Include/EGkIntersPlaneSurfTm.h" #include "/EgtDev/Include/EGkStmFromCurves.h" #include "/EgtDev/Include/EXeExecutor.h" // per far dimenticare macro di WinUser.h #undef GetClassName using namespace std ; //------------------------------ Errors -------------------------------------- // 3001 = "Error in SurfRoughing : UpdateToolData failed" // 3002 = "Error in SurfRoughing : Tool loading failed" // 3003 = "Error in SurfRoughing : Chaining failed" // 3004 = "Error in SurfRoughing : Open Contour" // 3005 = "Error in SurfRoughing : Contour Not Flat" // 3006 = "Error in SurfRoughing : Tool Dir not perpendicular to Flat Area" // 3007 = "Error in SurfRoughing : Empty RawBox" // 3008 = "Error in SurfRoughing : Depth not computable" // 3009 = "Error in SurfRoughing : Offset not computable" // 3010 = "Error in SurfRoughing : Toolpath not computable" // 3011 = "Error in SurfRoughing : Approach not computable" // 3012 = "Error in SurfRoughing : Link not computable" // 3013 = "Error in SurfRoughing : LeadIn not computable" // 3014 = "Error in SurfRoughing : LeadOut not computable" // 3015 = "Error in SurfRoughing : Retract not computable" // 3016 = "Error in SurfRoughing : axes values not calculable" // 3017 = "Error in SurfRoughing : outstroke xx" // 3018 = "Error in SurfRoughing : link movements not calculable" // 3019 = "Error in SurfRoughing : link outstroke" // 3020 = "Error in SurfRoughing : post apply not calculable" // 3021 = "Error in SurfRoughing : Linear Approx not computable" // 3022 = "Error in SurfRoughing : aggregate from bottom not allowed" // 3023 = "Error in SurfRoughing : missing surfaces" // 3024 = "Error in SurfRoughing : region not computable" // 3025 = "Error in SurfRoughing : RawPart not computable" // 3026 = "Error in SurfRoughing : Detecting open edges failed" // 3027 = "Error in SurfRoughing : Slicing Raw failed" // 3028 = "Error in SurfRoughing : Error in CalcPocketing" // 3029 = "Error in SurfRoughing : Error in Classifying border" // 3029 = "Error in SurfRoughing : Simplify Chunks for SubSteps failed" // 3030 = "Error in SurfRoughing : Conformal ZigZag not valid at step (xx)" // 3051 = "Warning in SurfRoughing : Skipped entity (xx)" // 3052 = "Warning in SurfRoughing : No machinable path" // 3053 = "Warning in SurfRoughing : Tool name changed (xx)" // 3054 = "Warning in SurfRoughing : Tool data changed (xx)" // 3055 = "Warning in SurfRoughing : CalcPocketing failed with substep (xx)" // 3056 = "Warning in SurfRoughing : invalid Conformal ZigZag at substep (xx)" //---------------------------------------------------------------------------- static string KEY_SURF_POCK = "SurfPock_" ; static string KEY_SURF_LIMIT = "SurfLimit_" ; #define ENABLE_DEBUG 0 static string _DEBUG_GROUP_TERRACE = "Terraces" ; static string _DEBUG_GROUP_FEED = "Feeds" ; bool _DEBUG_CLEAR_GROUP_TERRACE = TRUE ; bool _DEBUG_CLEAR_GROUP_FEED = TRUE ; //---------------------------------------------------------------------------- USEROBJ_REGISTER( GetOperationClass( OPER_SURFROUGHING), SurfRoughing) ; //---------------------------------------------------------------------------- const string& SurfRoughing::GetClassName( void) const { return USEROBJ_GETNAME( SurfRoughing) ; } //---------------------------------------------------------------------------- SurfRoughing* SurfRoughing::Clone( void) const { // alloco oggetto SurfRoughing* pSrR = new(nothrow) SurfRoughing ; // eseguo copia dei dati if ( pSrR != nullptr) { try { pSrR->m_vId = m_vId ; pSrR->m_pMchMgr = m_pMchMgr ; pSrR->m_nPhase = m_nPhase ; pSrR->m_Params = m_Params ; pSrR->m_TParams = m_TParams ; pSrR->m_dTHoldBase = m_dTHoldBase ; pSrR->m_dTHoldLen = m_dTHoldLen ; pSrR->m_dTHoldDiam = m_dTHoldDiam ; pSrR->m_nStatus = m_nStatus ; pSrR->m_nPaths = m_nPaths ; pSrR->m_dMaxHelixRad = m_dMaxHelixRad ; } catch( ...) { delete pSrR ; return nullptr ; } } // ritorno l'oggetto return pSrR ; } //---------------------------------------------------------------------------- bool SurfRoughing::Dump( string& sOut, bool bMM, const char* szNewLine) const { sOut += GetClassName() + "[mm]" + szNewLine ; sOut += KEY_PHASE + EQUAL + ToString( m_nPhase) + szNewLine ; sOut += KEY_IDS + EQUAL + ToString( m_vId) + szNewLine ; for ( int i = 0 ; i < m_Params.GetSize() ; ++ i) sOut += m_Params.ToString( i) + szNewLine ; for ( int i = 0 ; i < m_TParams.GetSize() ; ++ i) sOut += m_TParams.ToString( i) + szNewLine ; sOut += KEY_NUM + EQUAL + ToString( m_nPaths) + szNewLine ; sOut += KEY_STAT + EQUAL + ToString( m_nStatus) + szNewLine ; return true ; } //---------------------------------------------------------------------------- bool SurfRoughing::Save( int nBaseId, STRVECTOR& vString) const { try { int nSize = 1 + m_Params.GetSize() + m_TParams.GetSize() + 3 ; vString.insert( vString.begin(), nSize, "") ; int k = - 1 ; if ( ! SetVal( KEY_IDS, m_vId, vString[++k])) return false ; for ( int i = 0 ; i < m_Params.GetSize() ; ++ i) vString[++k] = m_Params.ToString( i) ; for ( int i = 0 ; i < m_TParams.GetSize() ; ++ i) vString[++k] = m_TParams.ToString( i) ; if ( ! SetVal( KEY_PHASE, m_nPhase, vString[++k])) return false ; if ( ! SetVal( KEY_NUM, m_nPaths, vString[++k])) return false ; if ( ! SetVal( KEY_STAT, m_nStatus, vString[++k])) return false ; } catch( ...) { return false ; } return true ; } //---------------------------------------------------------------------------- bool SurfRoughing::Load( const STRVECTOR& vString, int nBaseGdbId) { int nSize = int( vString.size()) ; // lista identificativi geometrie da lavorare int k = - 1 ; if ( k >= nSize - 1 || ! GetVal( vString[++k], KEY_IDS, m_vId)) return false ; for ( auto& Sel : m_vId) Sel.nId += nBaseGdbId ; // parametri lavorazione for ( int i = 0 ; i < m_Params.GetSize() ; ++ i) { int nKey ; if ( k >= nSize - 1 || ! m_Params.FromString( vString[++k], nKey) || nKey != i) { if ( m_Params.IsOptional( i)) -- k ; else return false ; } } // parametri utensile for ( int i = 0 ; i < m_TParams.GetSize() ; ++ i) { int nKey ; if ( k >= nSize - 1 || ! m_TParams.FromString( vString[++k], nKey) || nKey != i) return false ; } // parametri di stato while ( k < nSize - 1) { // separo chiave da valore string sKey, sVal ; SplitFirst( vString[++k], "=", sKey, sVal) ; // leggo if ( sKey == KEY_PHASE) { if ( ! FromString( sVal, m_nPhase)) return false ; } else if ( sKey == KEY_NUM) { if ( ! FromString( sVal, m_nPaths)) return false ; } else if ( sKey == KEY_STAT) { if ( ! FromString( sVal, m_nStatus)) return false ; } } return true ; } //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- SurfRoughing::SurfRoughing( void) { m_Params.m_sName = "*" ; m_Params.m_sToolName = "*" ; m_TParams.m_sName = "*" ; m_TParams.m_sHead = "*" ; m_dTHoldBase = 0 ; m_dTHoldLen = 0 ; m_dTHoldDiam = 0 ; m_nStatus = MCH_ST_TO_VERIFY ; m_nPaths = 0 ; m_dMaxHelixRad = INFINITO ; m_dSubStepToler = 2.0 / 2 ; } //---------------------------------------------------------------------------- bool SurfRoughing::Prepare( const string& sSawName) { // verifico il gestore lavorazioni if ( m_pMchMgr == nullptr) return false ; // recupero il gestore DB utensili della macchina corrente ToolsMgr* pTMgr = m_pMchMgr->GetCurrToolsMgr() ; if ( pTMgr == nullptr) return false ; // recupero il gestore DB lavorazioni della macchina corrente MachiningsMgr* pMMgr = m_pMchMgr->GetCurrMachiningsMgr() ; if ( pMMgr == nullptr) return false ; // ricerca della lavorazione di libreria con il nome indicato const SurfRoughingData* pDdata = GetSurfRoughingData( pMMgr->GetMachining( sSawName)) ; if ( pDdata == nullptr) return false ; m_Params = *pDdata ; // ricerca dell'utensile usato dalla lavorazione const ToolData* pTdata = pTMgr->GetTool( m_Params.m_ToolUuid) ; if ( pTdata == nullptr) return false ; m_TParams = *pTdata ; m_Params.m_sToolName = m_TParams.m_sName ; return true ; } //---------------------------------------------------------------------------- bool SurfRoughing::SetParam( int nType, bool bVal) { switch ( nType) { case MPA_INVERT : if ( bVal != m_Params.m_bInvert) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_bInvert = bVal ; return true ; } return false ; } //---------------------------------------------------------------------------- bool SurfRoughing::SetParam( int nType, int nVal) { switch ( nType) { case MPA_SUBTYPE : if ( ! m_Params.VerifySubType( nVal)) return false ; if ( nVal != m_Params.m_nSubType) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_nSubType = nVal ; return true ; case MPA_LEADINTYPE : if ( ! m_Params.VerifyLeadInType( nVal)) return false ; if ( nVal != m_Params.m_nLeadInType) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_nLeadInType = nVal ; return true ; case MPA_LEADOUTTYPE : if ( ! m_Params.VerifyLeadOutType( nVal)) return false ; if ( nVal != m_Params.m_nLeadOutType) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_nLeadOutType = nVal ; return true ; case MPA_SCC : if ( ! m_Params.VerifySolCh( nVal)) return false ; if ( nVal != m_Params.m_nSolCh) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_nSolCh = nVal ; return true ; } return false ; } //---------------------------------------------------------------------------- bool SurfRoughing::SetParam( int nType, double dVal) { switch ( nType) { case MPA_SPEED : if ( ! m_TParams.VerifySpeed( dVal)) return false ; if ( AreSameAngValue( dVal, m_TParams.m_dSpeed)) dVal = 0 ; m_Params.m_dSpeed = dVal ; return true ; case MPA_FEED : if ( AreSameLenValue( dVal, m_TParams.m_dFeed)) dVal = 0 ; if ( ! AreSameLenValue( dVal, m_Params.m_dFeed)) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dFeed = dVal ; return true ; case MPA_STARTFEED : if ( AreSameLenValue( dVal, m_TParams.m_dStartFeed)) dVal = 0 ; if ( ! AreSameLenValue( dVal, m_Params.m_dStartFeed)) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dStartFeed = dVal ; return true ; case MPA_ENDFEED : if ( AreSameLenValue( dVal, m_TParams.m_dEndFeed)) dVal = 0 ; if ( ! AreSameLenValue( dVal, m_Params.m_dEndFeed)) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dEndFeed = dVal ; return true ; case MPA_TIPFEED : if ( AreSameLenValue( dVal, m_TParams.m_dTipFeed)) dVal = 0 ; if ( ! AreSameLenValue( dVal, m_Params.m_dTipFeed)) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dTipFeed = dVal ; return true ; case MPA_OFFSR : if ( AreSameLenValue( dVal, m_TParams.m_dOffsR)) dVal = UNKNOWN_PAR ; if ( ! AreSameLenValue( dVal, m_Params.m_dOffsR)) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dOffsR = dVal ; return true ; case MPA_OFFSL : if ( AreSameLenValue( dVal, m_TParams.m_dOffsL)) dVal = UNKNOWN_PAR ; if ( ! AreSameLenValue( dVal, m_Params.m_dOffsL)) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dOffsL = dVal ; return true ; case MPA_DEPTH: { string sVal = ToString( dVal) ; if ( sVal != m_Params.m_sDepth) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_sDepth = sVal ; } return true ; case MPA_STARTPOS : if ( ! AreSameLenValue( dVal, m_Params.m_dStartPos)) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dStartPos = dVal ; return true ; case MPA_STEP : if ( ! AreSameLenValue( dVal, m_Params.m_dStep)) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dStep = dVal ; return true ; case MPA_SUBSTEP : if ( ! AreSameLenValue( dVal, m_Params.m_dSubStep)) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dSubStep = dVal ; return true ; case MPA_SIDESTEP : if ( ! AreSameLenValue( dVal, m_Params.m_dSideStep)) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dSideStep = dVal ; return true ; case MPA_SIDEANGLE : if ( abs( dVal - m_Params.m_dSideAngle) > EPS_MACH_LEN_PAR) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dSideAngle = dVal ; return true ; case MPA_LIELEV : if ( abs( dVal - m_Params.m_dLiElev) > EPS_MACH_LEN_PAR) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dLiElev = dVal ; return true ; case MPA_LITANG : if ( abs( dVal - m_Params.m_dLiTang) > EPS_MACH_LEN_PAR) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dLiTang = dVal ; return true ; case MPA_LOTANG : if ( abs( dVal - m_Params.m_dLoTang) > EPS_MACH_LEN_PAR) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dLoTang = dVal ; return true ; case MPA_APPROX : if ( abs( dVal - m_Params.m_dApprox) > EPS_SMALL) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dApprox = dVal ; return true ; } return false ; } //---------------------------------------------------------------------------- bool SurfRoughing::SetParam( int nType, const string& sVal) { switch ( nType) { case MPA_TOOL : { const ToolData* pTdata ; if ( ! m_Params.VerifyTool( m_pMchMgr->GetCurrToolsMgr(), sVal, pTdata)) return false ; if ( ! SameTool( m_TParams, *pTdata)) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_sToolName = sVal ; m_Params.m_ToolUuid = pTdata->m_Uuid ; m_TParams = *pTdata ; } return true ; case MPA_DEPTH_STR : if ( sVal != m_Params.m_sDepth) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_sDepth = sVal ; return true ; case MPA_SYSNOTES : if ( sVal != m_Params.m_sSysNotes) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_sSysNotes = sVal ; return true ; case MPA_USERNOTES : if ( sVal != m_Params.m_sUserNotes) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_sUserNotes = sVal ; return true ; case MPA_INITANGS : if ( sVal != m_Params.m_sInitAngs) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_sInitAngs = sVal ; return true ; case MPA_BLOCKEDAXIS : if ( sVal != m_Params.m_sBlockedAxis) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_sBlockedAxis = sVal ; return true ; } return false ; } //---------------------------------------------------------------------------- bool SurfRoughing::SetGeometry( const SELVECTOR& vIds) { // verifico validità gestore DB geometrico if ( m_pGeomDB == nullptr) return false ; // reset della geometria corrente m_vId.clear() ; // verifico che gli identificativi rappresentino delle entità ammissibili for ( const auto& Id : vIds) { // test sull'entità int nSubs ; if ( ! VerifyGeometry( Id, nSubs)) { string sInfo = "Warning in SurfRoughing : Skipped entity " + ToString( Id) ; m_pMchMgr->SetWarning( 3051, sInfo) ; continue ; } // posso aggiungere alla lista m_vId.emplace_back( Id) ; } // aggiorno lo stato m_nStatus |= MCH_ST_GEO_MODIF ; // restituisco presenza geometria da lavorare return ( ! m_vId.empty()) ; } //---------------------------------------------------------------------------- bool SurfRoughing::Preview( bool bRecalc) { // non esiste preview, si fa apply return Apply( bRecalc, false) ; } //---------------------------------------------------------------------------- bool SurfRoughing::Apply( bool bRecalc, bool bPostApply) { // reset numero tagli nella lavorazione int nCurrPaths = m_nPaths ; m_nPaths = 0 ; // verifico validità gestore DB geometrico e Id del gruppo if ( m_pGeomDB == nullptr || ! m_pGeomDB->ExistsObj( m_nOwnerId)) return false ; // aggiorno dati geometrici dell'utensile bool bToolChanged = true ; if ( ! UpdateToolData( &bToolChanged)) { m_pMchMgr->SetLastError( 3001, "Error in SurfRoughing : UpdateToolData failed") ; return false ; } // non è prevista sgrossatura superficie con aggregato da sotto if ( IsAggrBottom( m_TParams.m_sHead)) { m_pMchMgr->SetLastError( 3022, "Error in SurfRoughing : aggregate from bottom not allowed") ; return false ; } // verifico se necessario continuare nell'aggiornamento if ( ! bRecalc && ! bToolChanged && ( m_nStatus == MCH_ST_OK || ( ! bPostApply && m_nStatus == MCH_ST_NO_POSTAPPL))) { // confermo i percorsi di lavorazione m_nPaths = nCurrPaths ; LOG_DBG_INFO( GetEMkLogger(), "SurfRoughing apply skipped : status already ok") ; // eseguo aggiornamento assi macchina e collegamento con operazione precedente if ( ! Update( bPostApply)) return false ; LOG_DBG_INFO( GetEMkLogger(), "Update done") ; // esco con successo return true ; } m_nStatus = MCH_ST_TO_VERIFY ; // recupero gruppo per geometria ausiliaria int nAuxId = m_pGeomDB->GetFirstNameInGroup( m_nOwnerId, MCH_AUX) ; bool bChain = false ; // se non c'è, lo aggiungo if ( nAuxId == GDB_ID_NULL) { nAuxId = m_pGeomDB->AddGroup( GDB_ID_NULL, m_nOwnerId, Frame3d()) ; if ( nAuxId == GDB_ID_NULL) return false ; m_pGeomDB->SetName( nAuxId, MCH_AUX) ; m_pGeomDB->SetStatus( nAuxId, GDB_ST_OFF) ; bChain = true ; } // altrimenti, se chiesto ricalcolo, lo svuoto else if ( bRecalc) { m_pGeomDB->EmptyGroup( nAuxId) ; bChain = true ; } // rendo corrente l'utensile usato nella lavorazione if ( ! m_pMchMgr->SetCalcTool( m_TParams.m_sName, m_TParams.m_sHead, m_TParams.m_nExit)) { m_pMchMgr->SetLastError( 3002, "Error in SurfRoughing : Tool loading failed") ; return false ; } // recupero i dati del portautensile int nToolId = m_pMchMgr->GetCalcTool() ; m_dTHoldBase = 0 ; m_pGeomDB->GetInfo( nToolId, TTH_BASE, m_dTHoldBase) ; m_dTHoldLen = 0 ; m_pGeomDB->GetInfo( nToolId, TTH_LEN, m_dTHoldLen) ; m_dTHoldDiam = 0 ; m_pGeomDB->GetInfo( nToolId, TTH_DIAM, m_dTHoldDiam) ; // se necessario, eseguo concatenamento ed inserisco i percorsi sotto la geometria ausiliaria if ( bChain && ! Chain( nAuxId)) { m_pMchMgr->SetLastError( 3003, "Error in SurfRoughing : Chaining failed") ; return false ; } // recupero gruppo per geometria di lavorazione (Cutter Location) int nClId = m_pGeomDB->GetFirstNameInGroup( m_nOwnerId, MCH_CL) ; // se non c'è, lo aggiungo if ( nClId == GDB_ID_NULL) { nClId = m_pGeomDB->AddGroup( GDB_ID_NULL, m_nOwnerId, Frame3d()) ; if ( nClId == GDB_ID_NULL) return false ; m_pGeomDB->SetName( nClId, MCH_CL) ; } // altrimenti lo svuoto else m_pGeomDB->EmptyGroup( nClId) ; // recupero gruppo per geometria temporanea const string GRP_TEMP = "Temp" ; int nTempId = m_pGeomDB->GetFirstNameInGroup( m_nOwnerId, GRP_TEMP) ; // se non c'è, lo aggiungo if ( nTempId == GDB_ID_NULL) { nTempId = m_pGeomDB->AddGroup( GDB_ID_NULL, m_nOwnerId, Frame3d()) ; if ( nTempId == GDB_ID_NULL) return false ; m_pGeomDB->SetName( nTempId, GRP_TEMP) ; } // altrimenti lo svuoto else m_pGeomDB->EmptyGroup( nTempId) ; // in ogni caso lo dichiaro temporaneo e non visibile m_pGeomDB->SetLevel( nTempId, GDB_LV_TEMP) ; m_pGeomDB->SetStatus( nTempId, GDB_ST_OFF) ; // lavoro ogni singola catena bool bOk = true ; int nPathId = m_pGeomDB->GetFirstGroupInGroup( nAuxId) ; while ( nPathId != GDB_ID_NULL) { if ( ! ProcessPath( nPathId, nTempId, GDB_ID_NULL, nClId)) bOk = false ; nPathId = m_pGeomDB->GetNextGroup( nPathId) ; } if ( ! bOk) return false ; // assegno ingombri dei vari percorsi di lavorazione e della lavorazione nel suo complesso CalcAndSetBBox( nClId) ; // eseguo aggiornamento assi macchina e collegamento con operazione precedente if ( ! Update( bPostApply)) return false ; // aggiorno stato della lavorazione m_nStatus = ( bPostApply ? MCH_ST_OK : MCH_ST_NO_POSTAPPL) ; // dichiaro successiva da aggiornare UpdateFollowingOperationsStatus( MCH_ST_OTH_MODIF) ; LOG_DBG_INFO( GetEMkLogger(), "SurfRoughing apply done") ; return true ; } //---------------------------------------------------------------------------- bool SurfRoughing::Update( bool bPostApply) { // verifico validità gestore DB geometrico e Id del gruppo if ( m_pGeomDB == nullptr || ! m_pGeomDB->ExistsObj( m_nOwnerId)) return false ; // se lavorazione vuota, esco if ( m_nPaths == 0) { m_pMchMgr->SetWarning( 3052, "Warning in SurfRoughing : No machinable path") ; return true ; } // elimino le entità CLIMB, RISE e HOME della lavorazione, potrebbero falsare i calcoli degli assi (in ogni casi vengono riaggiunte dopo) RemoveClimbRiseHome() ; // imposto eventuale asse bloccato da lavorazione SetBlockedRotAxis( m_Params.m_sBlockedAxis) ; // calcolo gli assi macchina string sHint = ExtractHint( m_Params.m_sUserNotes) ; if ( ! m_Params.m_sInitAngs.empty()) sHint = m_Params.m_sInitAngs ; if ( ! CalculateAxesValues( sHint)) { string sInfo = m_pMchMgr->GetOutstrokeInfo() ; if ( sInfo.empty()) m_pMchMgr->SetLastError( 3016, "Error in SurfRoughing : axes values not calculable") ; else m_pMchMgr->SetLastError( 3017, "Error in SurfRoughing : outstroke ") ; return false ; } // gestione movimenti all'inizio di ogni singolo percorso di lavorazione e alla fine della lavorazione if ( ! AdjustStartEndMovements()) { string sInfo = m_pMchMgr->GetOutstrokeInfo() ; if ( sInfo.empty()) m_pMchMgr->SetLastError( 3018, "Error in SurfRoughing : link movements not calculable") ; else m_pMchMgr->SetLastError( 3019, "Error in SurfRoughing : link outstroke ") ; return false ; } // assegno estremi degli assi dei vari percorsi di lavorazione e della lavorazione nel suo complesso CalcAndSetAxesBBox() ; // esecuzione eventuali personalizzazioni string sErr ; if ( bPostApply && ! PostApply( sErr)) { if ( ! IsEmptyOrSpaces( sErr)) m_pMchMgr->SetLastError( 3020, sErr) ; else m_pMchMgr->SetLastError( 3020, "Error in SurfRoughing : post apply not calculable") ; return false ; } return true ; } //---------------------------------------------------------------------------- bool SurfRoughing::GetParam( int nType, bool& bVal) const { switch ( nType) { case MPA_INVERT : bVal = m_Params.m_bInvert ; return true ; } bVal = false ; return false ; } //---------------------------------------------------------------------------- bool SurfRoughing::GetParam( int nType, int& nVal) const { switch ( nType) { case MPA_TYPE : nVal = MT_SURFROUGHING ; return true ; case MPA_SUBTYPE : nVal = m_Params.m_nSubType ; return true ; case MPA_LEADINTYPE : nVal = m_Params.m_nLeadInType ; return true ; case MPA_LEADOUTTYPE : nVal = m_Params.m_nLeadOutType ; return true ; case MPA_SCC : nVal = m_Params.m_nSolCh ; return true ; } nVal = 0 ; return false ; } //---------------------------------------------------------------------------- bool SurfRoughing::GetParam( int nType, double& dVal) const { switch ( nType) { case MPA_SPEED : dVal = GetSpeed() ; return true ; case MPA_FEED : dVal = GetFeed() ; return true ; case MPA_STARTFEED : dVal = GetStartFeed() ; return true ; case MPA_ENDFEED : dVal = GetEndFeed() ; return true ; case MPA_TIPFEED : dVal = GetTipFeed() ; return true ; case MPA_OFFSR : dVal = GetOffsR() ; return true ; case MPA_OFFSL : dVal = GetOffsL() ; return true ; case MPA_STARTPOS : dVal = m_Params.m_dStartPos ; return true ; case MPA_STEP : dVal = m_Params.m_dStep ; return true ; case MPA_SUBSTEP : dVal = m_Params.m_dSubStep ; return true ; case MPA_SIDESTEP : dVal = m_Params.m_dSideStep ; return true ; case MPA_SIDEANGLE : dVal = m_Params.m_dSideAngle ; return true ; case MPA_LIELEV : dVal = m_Params.m_dLiElev ; return true ; case MPA_LITANG : dVal = m_Params.m_dLiTang ; return true ; case MPA_LOTANG : dVal = m_Params.m_dLoTang ; return true ; case MPA_APPROX : dVal = m_Params.m_dApprox ; return true ; } dVal = 0 ; return false ; } //---------------------------------------------------------------------------- bool SurfRoughing::GetParam( int nType, string& sVal) const { switch ( nType) { case MPA_NAME : sVal = m_Params.m_sName ; return true ; case MPA_TOOL : sVal = m_Params.m_sToolName ; return true ; case MPA_DEPTH_STR : sVal = m_Params.m_sDepth ; return true ; case MPA_TUUID : sVal = ToString( m_Params.m_ToolUuid) ; return true ; case MPA_UUID : sVal = ToString( m_Params.m_Uuid) ; return true ; case MPA_SYSNOTES : sVal = m_Params.m_sSysNotes ; return true ; case MPA_USERNOTES : sVal = m_Params.m_sUserNotes ; return true ; case MPA_INITANGS : sVal = m_Params.m_sInitAngs ; return true ; case MPA_BLOCKEDAXIS : sVal = m_Params.m_sBlockedAxis ; return true ; } sVal = "" ; return false ; } //---------------------------------------------------------------------------- const ToolData& SurfRoughing::GetToolData( void) const { return m_TParams ; } //---------------------------------------------------------------------------- bool SurfRoughing::UpdateToolData( bool* pbChanged) { // recupero il gestore DB utensili della macchina corrente ToolsMgr* pTMgr = m_pMchMgr->GetCurrToolsMgr() ; if ( pTMgr == nullptr) return false ; // recupero l'utensile nel DB utensili const ToolData* pTdata = pTMgr->GetTool( m_Params.m_ToolUuid) ; if ( pTdata == nullptr) return false ; // salvo posizione TC, testa e uscita originali string sOrigTcPos = m_TParams.m_sTcPos ; string sOrigHead = m_TParams.m_sHead ; int nOrigExit = m_TParams.m_nExit ; // verifico se sono diversi (ad esclusione di nome, posizione TC, testa e uscita) bool bChanged = ( ! SameTool( m_TParams, *pTdata, false)) ; // aggiorno comunque i parametri m_TParams = *pTdata ; // se definito attrezzaggio, aggiorno i parametri che ne possono derivare string sTcPos ; string sHead ; int nExit ; if ( m_pMchMgr->GetCurrSetupMgr().GetToolData( m_TParams.m_sName, sTcPos, sHead, nExit)) { if ( sOrigTcPos != sTcPos || sOrigHead != sHead || nOrigExit != nExit) bChanged = true ; m_TParams.m_sTcPos = sTcPos ; m_TParams.m_sHead = sHead ; m_TParams.m_nExit = nExit ; } else { if ( sOrigTcPos != pTdata->m_sTcPos || sOrigHead != pTdata->m_sHead || nOrigExit != pTdata->m_nExit) bChanged = true ; } // eventuali segnalazioni if ( ! EqualNoCase( m_Params.m_sToolName, m_TParams.m_sName)) { string sInfo = "Warning in SurfRoughing : tool name changed (" + m_Params.m_sToolName + "->" + m_TParams.m_sName + ")" ; m_pMchMgr->SetWarning( 3053, sInfo) ; m_Params.m_sToolName = m_TParams.m_sName ; } if ( bChanged) { string sInfo = "Warning in SurfRoughing : tool data changed (" + m_Params.m_sToolName + ")" ; m_pMchMgr->SetWarning( 3054, sInfo) ; } // se definito parametro di ritorno, lo assegno if ( pbChanged != nullptr) *pbChanged = bChanged ; return true ; } //---------------------------------------------------------------------------- bool SurfRoughing::GetGeometry( SELVECTOR& vIds) const { // restituisco l'elenco delle entità vIds = m_vId ; return true ; } //---------------------------------------------------------------------------- bool SurfRoughing::AdjustEndPointForAxesCalc( const CamData* pCamData, Point3d& ptP) const { // compenso il raggio dell'utensile ptP += pCamData->GetCorrDir() * ( m_TParams.m_dDiam / 2) ; return true ; } //---------------------------------------------------------------------------- bool SurfRoughing::VerifyGeometry( SelData Id, int& nSubs) { // ammessi : curve o superfici const IGeoObj* pGObj = m_pGeomDB->GetGeoObj( Id.nId) ; if ( pGObj == nullptr) return false ; // se curva if ( ( pGObj->GetType() & GEO_CURVE) != 0) { const ICurve* pCurve = nullptr ; // se direttamente la curva if ( Id.nSub == SEL_SUB_ALL) { pCurve = ::GetCurve( pGObj) ; if ( pCurve != nullptr) { if ( pCurve->GetType() == CRV_COMPO) nSubs = ::GetCurveComposite( pCurve)->GetCurveCount() ; else nSubs = 0 ; } } // altrimenti sottocurva di composita else { const ICurveComposite* pCompo = GetCurveComposite( pGObj) ; if ( pCompo != nullptr) pCurve = pCompo->GetCurve( Id.nSub) ; nSubs = 0 ; } return ( pCurve != nullptr) ; } // se altrimenti è superficie trimesh else if ( pGObj->GetType() == SRF_TRIMESH) { const ISurfTriMesh* pSurf = ::GetSurfTriMesh( pGObj) ; return ( pSurf != nullptr && pSurf->GetFacetCount() >= 1) ; } // altrimenti errore else return false ; } //---------------------------------------------------------------------------- bool SurfRoughing::GetCurves( SelData Id, ICURVEPLIST& lstPC) { // ammessi : curve const IGeoObj* pGObj = m_pGeomDB->GetGeoObj( Id.nId) ; if ( pGObj == nullptr) return false ; // ne recupero il riferimento globale Frame3d frGlob ; if ( ! m_pGeomDB->GetGlobFrame( Id.nId, frGlob)) return false ; // se curva if ( ( pGObj->GetType() & GEO_CURVE) != 0) { PtrOwner pCurve ; // se direttamente curva if ( Id.nSub == SEL_SUB_ALL) { // recupero la curva const ICurve* pOriCurve = ::GetCurve( pGObj) ; if ( pOriCurve == nullptr) return false ; // la duplico pCurve.Set( pOriCurve->Clone()) ; // se estrusione mancante, imposto default Vector3d vtExtr ; if ( ! pCurve->GetExtrusion( vtExtr) || vtExtr.IsSmall()) pCurve->SetExtrusion( Z_AX) ; } // altrimenti sottocurva di composita else { // recupero la composita const ICurveComposite* pCompo = GetCurveComposite( pGObj) ; if ( pCompo == nullptr) return false ; // recupero la curva semplice const ICurve* pOriCurve = ::GetCurve( pCompo->GetCurve( Id.nSub)) ; if ( pOriCurve == nullptr) return false ; // la duplico pCurve.Set( pOriCurve->Clone()) ; // recupero estrusione e spessore Vector3d vtExtr ; if ( ! pCompo->GetExtrusion( vtExtr) || vtExtr.IsSmall()) vtExtr = Z_AX ; pCurve->SetExtrusion( vtExtr) ; double dThick ; if ( pCompo->GetThickness( dThick)) pCurve->SetThickness( dThick) ; } if ( IsNull( pCurve)) return false ; // la porto in globale pCurve->ToGlob( frGlob) ; // la restituisco lstPC.emplace_back( Release( pCurve)) ; return true ; } // se altrimenti superficie else if ( pGObj->GetType() == SRF_TRIMESH) return true ; // altrimenti errore else return false ; } //---------------------------------------------------------------------------- bool SurfRoughing::Chain( int nGrpDestId) { // vettore puntatori alle curve ICURVEPOVECTOR vpCrvs ; vpCrvs.reserve( m_vId.size()) ; // vettore selettori delle curve originali SELVECTOR vInds ; // recupero tutte le curve e le porto in globale for ( const auto& Id : m_vId) { // prendo le curve ICURVEPLIST lstPC ; if ( ! GetCurves( Id, lstPC)) { string sInfo = "Warning in SurfRoughing : Skipped entity " + ToString( Id) ; m_pMchMgr->SetWarning( 3051, sInfo) ; } for ( auto pCrv : lstPC) { vpCrvs.emplace_back( pCrv) ; vInds.emplace_back( Id) ; } } // preparo i dati per il concatenamento bool bFirst = true ; Point3d ptNear = ORIG ; double dToler = 10 * EPS_SMALL ; ChainCurves chainC ; chainC.Init( true, dToler, int( vpCrvs.size())) ; for ( size_t i = 0 ; i < vpCrvs.size() ; ++ i) { // recupero la curva e il suo riferimento ICurve* pCrv = vpCrvs[i] ; if ( pCrv == nullptr) continue ; // recupero i dati della curva necessari al concatenamento e li assegno Point3d ptStart, ptEnd ; Vector3d vtStart, vtEnd ; if ( ! pCrv->GetStartPoint( ptStart) || ! pCrv->GetStartDir( vtStart) || ! pCrv->GetEndPoint( ptEnd) || ! pCrv->GetEndDir( vtEnd)) return false ; if ( ! chainC.AddCurve( int( 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 ; } } // recupero i percorsi concatenati int nCount = 0 ; INTVECTOR vnId2 ; while ( chainC.GetChainFromNear( ptNear, false, vnId2)) { // creo una curva composita PtrOwner pCrvCompo( CreateCurveComposite()) ; if ( IsNull( pCrvCompo)) return false ; // estrusione e spessore Vector3d vtExtr = Z_AX ; double dThick = 0 ; // vettore Id originali SELVECTOR vId2 ; vId2.reserve( vnId2.size()) ; // recupero le curve semplici e le inserisco nella curva composita for ( size_t i = 0 ; i < vnId2.size() ; ++ i) { int nId = abs( vnId2[i]) - 1 ; bool bInvert = ( vnId2[i] < 0) ; vId2.emplace_back( vInds[nId]) ; // recupero la curva ICurve* pCrv = vpCrvs[nId] ; // se necessario, la inverto if ( bInvert) pCrv->Invert() ; // recupero eventuali estrusione e spessore Vector3d vtTemp ; if ( pCrv->GetExtrusion( vtTemp)) { vtExtr = vtTemp ; double dTemp ; if ( pCrv->GetThickness( dTemp) && abs( dTemp) > abs( dThick)) dThick = dTemp ; } // la aggiungo alla curva composta if ( ! pCrvCompo->AddCurve( ::Release( vpCrvs[nId]), true, dToler)) return false ; } // se non sono state inserite curve, vado oltre if ( pCrvCompo->GetCurveCount() == 0) continue ; // imposto estrusione e spessore pCrvCompo->SetExtrusion( vtExtr) ; pCrvCompo->SetThickness( dThick) ; // aggiorno il nuovo punto vicino pCrvCompo->GetEndPoint( ptNear) ; // se utile, approssimo con archi if ( ! ApproxWithArcsIfUseful( pCrvCompo)) return false ; // creo nuovo gruppo int nPathId = m_pGeomDB->AddGroup( GDB_ID_NULL, nGrpDestId, Frame3d()) ; if ( nPathId == GDB_ID_NULL) return false ; m_pGeomDB->SetName( nPathId, MCH_PATH + ToString( ++ nCount)) ; m_pGeomDB->SetInfo( nPathId, KEY_IDS, ToString( vId2)) ; // inserisco la curva composita nel gruppo destinazione int nNewId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nPathId, ::Release( pCrvCompo)) ; if ( nNewId == GDB_ID_NULL) return false ; } return true ; } //---------------------------------------------------------------------------- bool SurfRoughing::ProcessPath( int nPathId, int nTempId, int nPvId, int nClId) { // aggiorno la ProgressBar del 5% per simulare l'inizio della funzione ExeProcessEvents( 5, 0) ; // verifico sia una curva chiusa (deve delimitare l'area da svuotare) int nCrvId = m_pGeomDB->GetFirstInGroup( nPathId) ; if ( m_pGeomDB->GetGeoType( nCrvId) != CRV_COMPO) return false ; ICurve* pCrv = ::GetCurve( m_pGeomDB->GetGeoObj( nCrvId)) ; if ( pCrv == nullptr || ! pCrv->IsClosed()) { m_pMchMgr->SetLastError( 3004, "Error in SurfRoughing : Open Contour") ; return false ; } // copio la curva composita da elaborare int nCopyId = m_pGeomDB->CopyGlob( nCrvId, GDB_ID_NULL, nTempId) ; if ( nCopyId == GDB_ID_NULL) return false ; ICurveComposite* pCompo = GetCurveComposite( m_pGeomDB->GetGeoObj( nCopyId)) ; // recupero estrusione e spessore Vector3d vtExtr = Z_AX ; pCompo->GetExtrusion( vtExtr) ; double dThick ; pCompo->GetThickness( dThick) ; // verifico sia piana e sistemo senso antiorario visto dalla direzione di estrusione Plane3d plPlane ; double dArea ; if ( ! pCompo->GetArea( plPlane, dArea)) { m_pMchMgr->SetLastError( 3005, "Error in SurfRoughing : Contour Not Flat") ; return false ; } if ( abs( plPlane.GetVersN() * vtExtr) < cos( 10 * EPS_ANG_SMALL)) { m_pMchMgr->SetLastError( 3006, "Error in SurfRoughing : Tool Dir not perpendicular to Flat Area") ; return false ; } if ( plPlane.GetVersN() * vtExtr * dArea < 0) pCompo->Invert() ; if ( plPlane.GetVersN() * vtExtr < 0) plPlane.Invert() ; // creo un frame centrato sulla curva Frame3d fr_pCompo ; if ( ! fr_pCompo.Set( plPlane.GetPoint(), plPlane.GetVersN())) return false ; // unisco le parti allineate if ( ! pCompo->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL, true)) return false ; // recupero il box del grezzo in globale BBox3d b3Raw ; if ( ! GetRawGlobBox( m_nPhase, nPathId, 0.5 * m_TParams.m_dTDiam, b3Raw) || b3Raw.IsEmpty()) { m_pMchMgr->SetLastError( 3007, "Error in SurfRoughing : Empty RawBox") ; return false ; } // valuto l'espressione dell'affondamento ExeLuaSetGlobNumVar( "TH", abs( dThick)) ; double dDepth ; string sMyDepth = m_Params.m_sDepth ; if ( ! ExeLuaEvalNumExpr( ToUpper( sMyDepth), &dDepth)) { m_pMchMgr->SetLastError( 3008, "Error in SurfRoughing : Depth not computable") ; return false ; } // recupero nome del path string sPathName ; m_pGeomDB->GetName( nPathId, sPathName) ; // assegno il versore fresa Vector3d vtTool = vtExtr ; // non prevista gestione anteprima di lavorazione // se richiesta lavorazione if ( nClId != GDB_ID_NULL) { // creo gruppo per geometria di lavorazione del percorso int nPxId = m_pGeomDB->AddGroup( GDB_ID_NULL, nClId, Frame3d()) ; if ( nPxId == GDB_ID_NULL) return false ; m_pGeomDB->SetName( nPxId, sPathName) ; m_pGeomDB->SetMaterial( nPxId, BLUE) ; // verifico se archi vanno approssimati con segmenti di retta bool bSplitArcs = GetSplitArcs( vtTool) ; // recupero le superfici attive INTVECTOR vSurfId ; GetActiveSurfaces( vSurfId) ; if ( vSurfId.empty()) { m_pMchMgr->SetLastError( 3023, "Error in SurfRoughing : missing surfaces") ; return false ; } // recupero il grezzo PtrOwner pStmRaw( GetRaw()) ; if ( IsNull( pStmRaw)) { m_pMchMgr->SetLastError( 3025, "Error in SurfRoughing : RawPart not computable") ; return false ; } // inizializzo la classe di intersezione tra grezzo e piani paralleli ( quelli di lavoro) IntersParPlanesSurfTm IPPStm( fr_pCompo, *pStmRaw) ; // inizializzo la classe di calcolo delle silhouette nei piani come sopra SURFLOCALVECTOR vSurfL ; vSurfL.reserve( vSurfId.size()) ; CISURFTMPVECTOR vpStm ; vpStm.reserve( vSurfId.size()) ; for ( int i = 0 ; i < int( vSurfId.size()) ; ++ i) { vSurfL.emplace_back( m_pGeomDB, vSurfId[i], GLOB_FRM) ; if ( vSurfL[i].Get() == nullptr) return false ; vpStm.emplace_back( GetSurfTriMesh( vSurfL[i].Get())) ; } Frame3d frPlanes ; frPlanes.Set( plPlane.GetPoint(), vtTool) ; const double SILH_TOL = 1.0 ; PtrOwner pCavParSilh( CreateCAvParSilhouettesSurfTm()) ; if ( IsNull( pCavParSilh) || ! pCavParSilh->SetData( vpStm, frPlanes, SILH_TOL)) return false ; // vettore Id salvati nel gruppo Temp INTINTVECTOR vPocket ; // vettore delle curve composite con proprietà Aperto/Chiuso riferite ai vari step della curva originale ICRVCOMPOPOVECTOR vCrvPocketCompo ; // definisco la dimensione dello step ( base ) e il numero di passate double dOkStep = min( m_Params.m_dStep, m_TParams.m_dMaxMat + EPS_SMALL) ; int nStep = max( 1, static_cast( ceil( dDepth / dOkStep))) ; double dStep = dDepth / nStep ; // definisco la dimensione degli step intermedi ( subSteps ) e il numero di passate [ se definiti ] double dOkSubStep = -1. ; int nSubStep = -1 ; double dSubStep = -1. ; if ( m_Params.m_dSubStep > EPS_SMALL && m_Params.m_dSubStep < m_Params.m_dStep) { dOkSubStep = min( m_Params.m_dSubStep, m_TParams.m_dMaxMat + EPS_SMALL) ; nSubStep = nStep * max( 1, static_cast( ceil( dOkStep / dOkSubStep))) ; dSubStep = dDepth / nSubStep ; } // definisco una struttura per i parametri utili sugli step struct myStepInfo { myStepInfo( void) : nInd( -1), nIndRef( -1), dDepth( 0), bSubStep( false), nNumStep( 0), pSfrRemoved( nullptr) {} myStepInfo( int nI, int nIR, double dD, bool bSS, int nNS, ISurfFlatRegion* pSR) : nInd( nI), nIndRef( nIR), dDepth( dD), bSubStep( bSS), nNumStep( nNS), pSfrRemoved( pSR) {} ~myStepInfo() { delete( pSfrRemoved) ; } int nInd ; // indice step (0-based) int nIndRef ; // ( usato solo per step intermedi ) indice step precedente double dDepth ; // profondità posizione piano di svuotatura ( in negativo) bool bSubStep ; // flag per indicare se lo Step è base o intermedio int nNumStep ; // numero relativo progressivo di Step ( per Feed) ISurfFlatRegion* pSfrRemoved ; // regione PROGRESSIVA rimossa attuale } ; /* - nNumStep - Nel caso di Step base indica il numero di tale step ( da 0 a nStep - 1) Nel caso di SubStep indica il numero di tale SubStep relativo ai due Step Base che lo racchiudono ( da 0 a nSubStep - 1 per ogni coppia di Step base successivi) */ vector< myStepInfo> vStepInfo ; // inserisco prima gli step... for ( int i = 0 ; i < nStep ; ++ i) vStepInfo.emplace_back( i, -1, - ( i + 1) * dStep, false, i, nullptr) ; // ... e poi gli step intermedi ( se presenti e non coincidenti con gli Step base) int nIndRef = 0 ; // ( step base sottostante allo step intermedio corrente ) // creo un vettore di step intermedi presenti tra lo step base ( nIndRef-1)-esimo e nIndRef-esimo // ( NB. Il primo intervallo sta tra -1 e 0, in quanto lo Step base a filo del grezzo non è presente) vector vStepInfo_tmp ; // temporaneo ( vanno ordinati ) for ( int i = 0 ; i <= nSubStep ; ++ i) { // se SubStep coincidente con lo step, passo al successivo if ( abs( ( - ( i + 1) * dSubStep) - vStepInfo[nIndRef].dDepth) < 10 * EPS_SMALL) continue ; // se SubStep più profondo dello Step base di riferimento... if ( ( - ( i + 1) * dSubStep) - vStepInfo[nIndRef].dDepth < EPS_SMALL) { ++ nIndRef ; // il riferimento è lo step base successivo // scorro gli step intermedi temporanei trovati al contrario int nNumStep = -1 ; // numero relativo di SubStep for ( auto it = vStepInfo_tmp.rbegin() ; it != vStepInfo_tmp.rend() ; ++ it) { // se lo step intermedio non è il precedente allo step base di riferimento if ( it != vStepInfo_tmp.rbegin()) { auto it_prec = it ; it->nIndRef = ( -- it_prec)->nInd ; // il riferimento è lo step intermedio precedente // ( NB. tutti gli step intermedi hanno in origine associato lo step base sottostante come step di // riferimento... ad eccezione del primo, i successivi in salita avranno lo step intermedio // precedente come riferimento } it->nNumStep = ++ nNumStep ; // aggiornamento numero relativo di SubStep vStepInfo.emplace_back( *it) ; // aggiungo lo step intermedio al vettore degli step } vStepInfo_tmp.clear() ; // pulisco } // aggiunta dello step intermedio al vettore temporaneo vStepInfo_tmp.emplace_back( nStep + i, nIndRef, - ( i + 1) * dSubStep, true, 0, nullptr) ; } // su tutti gli step ricavati, calcolo le PolyLine delle Silhouette int nPocket = 0 ; // numero effettivo di Pocketing calcolate int nProgressBarStep = 0 ; // step per progressBar for ( auto it = vStepInfo.begin() ; it != vStepInfo.end() ; ++ it) { // per i contatori non controllo se effettivamente svuoto una superficie o meno ++ nProgressBarStep ; // aggiorno step per progressBar /* ******************** Regione estesa di lavoro ******************** */ // regione di lavoro allo step corrente ( definita dalla curva di lavoro ) PtrOwner pSfr( CreateSurfFlatRegion()) ; if ( IsNull( pSfr) || ! pSfr->AddExtLoop( *pCompo)) { m_pMchMgr->SetLastError( 3024, "Error in SurfRoughing : region not computable") ; return false ; } pSfr->Translate( ( it->dDepth + GetOffsL()) * vtTool) ; /* ******************** Regione adattata al grezzo ******************** */ // questa regione bisogna ridurla basandosi sulla geometria del grezzo, in modo da non lavorare // parti in eccesso ; taglio il grezzo sul piano corrente e interseco con questa regione PtrOwner pSfrRaw( GetSfrByStmIntersection( IPPStm, it->dDepth + GetOffsL(), 0)) ; if ( IsNull( pSfrRaw)) { m_pMchMgr->SetLastError( 3027, "Error in SurfRoughing : Slicing Raw failed") ; return false ; } PtrOwner pCompoPocket( CloneCurveComposite( pCompo)) ; if ( IsNull( pCompoPocket) || ! pCompoPocket->IsValid() || ! pCompoPocket->Translate( ( it->dDepth + GetOffsL()) * vtTool)) return false ; if ( pSfrRaw->IsValid() && pSfrRaw->GetChunkCount() > 0) { // per la curva composita selezionata, assegno i lati aperti e chiusi controllando // la geometria del grezzo ( servirà per controllare i LeadIn) if ( ! AssignOpenEdgesForPocketCrvCompo( pCompoPocket, pSfrRaw)) { m_pMchMgr->SetLastError( 3029, "Error in SurfRoughing : Error in Classifying border") ; return false ; } pSfr->Intersect( *pSfrRaw) ; } else continue ; // step fuori dal grezzo, passo al successivo /* *************************** Silhouette **************************** */ // determino la regione da non lavorare e la sottraggo POLYLINEVECTOR vPL ; if ( ! pCavParSilh->GetSilhouette( it->dDepth, vPL)) { m_pMchMgr->SetLastError( 3024, "Error in SurfRoughing : region not computable") ; return false ; } // creo la regione piana dalle PolyLine ricavate dalla Silhouette SurfFlatRegionByContours SfrMaker ; for ( auto& PL : vPL) { // recupero la curva dalla silhouette PtrOwner pSilCrv( CreateCurveComposite()) ; if ( IsNull( pSilCrv)) return false ; pSilCrv->FromPolyLine( PL) ; // approssimo con archi const double SILH_ARC_TOL = 0.1 * SILH_TOL ; const double SILH_ARC_FEA_MAX = 100. ; PolyArc PA ; if ( pSilCrv->ApproxWithArcsEx( SILH_ARC_TOL, ANG_TOL_STD_DEG, SILH_ARC_FEA_MAX, PA)) { PtrOwner pTempCrv( CreateCurveComposite()) ; if ( ! IsNull( pTempCrv) && pTempCrv->FromPolyArc( PA) && pTempCrv->RemoveSmallDefects( SILH_ARC_TOL / 2, ANG_TOL_STD_DEG) && pTempCrv->MergeCurves( SILH_ARC_TOL / 2, ANG_TOL_STD_DEG)) pSilCrv.Set( pTempCrv) ; } // aggiungo per regione if ( ! SfrMaker.AddCurve( Release( pSilCrv))) { m_pMchMgr->SetLastError( 3024, "Error in SurfRoughing : region not computable") ; return false ; } } PtrOwner pSfrSil( SfrMaker.GetSurf()) ; if ( ! IsNull( pSfrSil)) { pSfrSil->Offset( GetOffsR(), ICurve::OFF_CHAMFER) ; // offset radiale sulla Silhouette pSfr->Subtract( *pSfrSil) ; // sottraggo le parti da non lavorare } if ( ! pSfr->IsValid() || pSfr->GetChunkCount() == 0) // se superficie non valida continue ; // passo allo step successivo ( la silhouette coincide con il grezzo ) // salvo la superficie rimossa delete( it->pSfrRemoved) ; it->pSfrRemoved = pSfr->Clone() ; // inizializzo Regione piana per gestione lati aperti PtrOwner pSfrOpenClose( CloneSurfFlatRegion( pSfrRaw)) ; if ( IsNull( pSfrOpenClose)) return false ; /* *************************** Gestione SubSteps **************************** */ if ( it->bSubStep) { // recupero l'indice nel vettore dello step di riferimento int nIndRef = 0 ; for ( auto j = vStepInfo.begin() ; j != vStepInfo.end() ; ) { if ( j->nInd == it->nIndRef) { // cerco ora tra tutti gli step ( sia base che intermedi) che stanno tra nIndRef // e lo step base precedente, il primo che ha una superficie rimossa valida if ( ( ! j->bSubStep) || ( j->pSfrRemoved != nullptr && j->pSfrRemoved->IsValid())) break ; // superficie valida trovata else { it->nIndRef = j->nIndRef ; // aggiorno l'indice di riferimento nIndRef = -1 ; // annullo l'indice corrente ( diventa 0 alla prossima iterazione) j = vStepInfo.begin() ; // riparto alla ricerca dell'indice ( si aggiorna alla prossima iterazione) } } else ++ j ; ++ nIndRef ; } // piccolo Offset di correzione per booleane SurfFlatRegion double dOffsCor = 25. * EPS_SMALL ; // recupero la superficie progressiva dello step di riferimento const auto& pSfrRef = vStepInfo[nIndRef].pSfrRemoved ; if ( pSfrRef != nullptr && pSfrRef->IsValid()) { // se valida pSfrRef->Offset( dOffsCor, ICurve::OFF_FILLET) ; // correzione pSfr->Subtract( *pSfrRef) ; // sottraggo la regione svuotata in precedenza // aggiorno Regione piana per gestione lati aperti pSfrOpenClose->Subtract( *pSfrRef) ; } } // se regione risultante non vuota if ( pSfr->IsValid() && pSfr->GetChunkCount() > 0) { // se si tratta di un SottoStep, rimuovo tutti i chunk troppo snelli if ( it->bSubStep) { if ( ! RemoveChunksUnderTolerance( pSfr)) { m_pMchMgr->SetLastError( 3029, "Error in SurfRoughing : Simplify Chunks for SubSteps failed") ; return false ; } // se dopo la semplificazione non rimane nulla, allora passo allo step successivo if ( ! pSfr->IsValid() || pSfr->GetChunkCount() == 0) { delete( it->pSfrRemoved) ; // non ho rimosso nulla allo step corrente it->pSfrRemoved = nullptr ; continue ; } // estendo la superficie di riferimento considerando le sottocurve chiuse della // curva di sgrossatura if ( ! ModifySurfRefForOpenCloseEdges( pSfrOpenClose, pCompoPocket)) { m_pMchMgr->SetLastError( 3026, "Error in SurfRoughing : Detecting open edges failed") ; return false ; } } // determino i lati aperti ( mediante vicinanza dei tratti di curva al volume progressivo non svuotato) if ( ! ChooseCloseOrOpenEdge( pSfr, pSfrOpenClose)) { m_pMchMgr->SetLastError( 3026, "Error in SurfRoughing : Detecting open edges failed") ; return false ; } // se si tratta di un SottoStep, chiudo tutti i lati aperti troppo corti if ( it->bSubStep) { if ( ! CloseOpenEdgesUnderTolerance( pSfr, m_TParams.m_dDiam - 200 * EPS_SMALL)) { m_pMchMgr->SetLastError( 3029, "Error in SurfRoughing : Simplify Chunks for SubSteps failed") ; return false ; } } // salvo nella temp Prop della FlatRegion se si tratta di uno step base o intermedio // Step Base -> 0 | Step intermedio -> 1 pSfr->SetTempProp( it->bSubStep ? 1 : 0, 0) ; // salvo nel temp Param della FlatRegion la sua Depth di traslazione pSfr->SetTempParam( it->dDepth + GetOffsL(), 0) ; // salvo come temp Param 1 della FlatRegion il Coefficiente correttivo // per Zloc della Feed ( valore compreso tra 0 e 1) pSfr->SetTempParam( GetAdaptedCoeffFeed( it->bSubStep, it->nNumStep, dStep, dSubStep), 1) ; // aggiungo la Curva composita con tempProp di Open/Close settate al vettore vCrvPocketCompo.emplace_back( Release( pCompoPocket)) ; // la salvo nel gruppo temporaneo int nNew_SfrPock_Id = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nTempId, Release( pSfr)) ; if ( nNew_SfrPock_Id == GDB_ID_NULL) { m_pMchMgr->SetLastError( 3024, "Error in SurfRoughing : region not computable") ; return false ; } m_pGeomDB->SetMaterial( nNew_SfrPock_Id, GREEN) ; m_pGeomDB->SetName( nNew_SfrPock_Id, KEY_SURF_POCK + ToString( nPocket)) ; // nel gruppo temporaneo salvo anche la Shilouette ( per superficie Limite) int nNew_SfrLimit_Id = GDB_ID_NULL ; if ( ! IsNull( pSfrSil) && pSfrSil->IsValid()) { nNew_SfrLimit_Id = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nTempId, Release( pSfrSil)) ; if ( nNew_SfrLimit_Id == GDB_ID_NULL) { m_pMchMgr->SetLastError( 3024, "Error in SurfRoughing : region not computable") ; return false ; } m_pGeomDB->SetMaterial( nNew_SfrLimit_Id, ORANGE) ; m_pGeomDB->SetName( nNew_SfrLimit_Id, KEY_SURF_LIMIT + ToString( nPocket)) ; } ++ nPocket ; vPocket.emplace_back( make_pair( nNew_SfrPock_Id, nNew_SfrLimit_Id)) ; // aggiorno la progressBar ExeProcessEvents( 5 + nProgressBarStep * 45 / int( vStepInfo.size()), 100) ; } else { delete( it->pSfrRemoved) ; // non ho rimosso nulla it->pSfrRemoved = nullptr ; // aggiorno la progressBar ExeProcessEvents( 5 + nProgressBarStep * 45 / int( vStepInfo.size()), 100) ; } } // assegno il vettore estrazione al gruppo del percorso m_pGeomDB->SetInfo( nPxId, KEY_EXTR, vtTool) ; // Imposto dati comuni SetPathId( nPxId) ; SetToolDir( vtTool) ; // Eseguo le svuotature double dElev = dDepth ; if ( ! AddPocket( vPocket, vtTool, vCrvPocketCompo, dElev, dStep, dSubStep, bSplitArcs)) return false ; } // incremento numero di percorsi ++ m_nPaths ; return true ; } //---------------------------------------------------------------------------- ISurfTriMesh* SurfRoughing::GetRaw( void) const { // controllo MachManager e database geometrico if ( m_pMchMgr == nullptr || m_pGeomDB == nullptr) return nullptr ; // creo Stm del grezzo PtrOwner pStmRaw( CreateSurfTriMesh()) ; if ( IsNull( pStmRaw)) return nullptr ; pStmRaw->AdjustTopology() ; // Id prima RawPart int nRawId = m_pMchMgr->GetFirstRawPart() ; while ( nRawId != GDB_ID_NULL) { // verifico che il grezzo compaia nella fase if ( m_pMchMgr->VerifyRawPartPhase( nRawId, m_nPhase)) { // recupero l'oggetto dal database con tale Id int nRawSolidId = m_pGeomDB->GetFirstNameInGroup( nRawId, MACH_RAW_SOLID) ; const IGeoObj* pGObj = m_pGeomDB->GetGeoObj( nRawSolidId) ; if ( pGObj == nullptr) return nullptr ; // recupero il frame in cui si trova Frame3d frRaw ; m_pGeomDB->GetGlobFrame( nRawSolidId, frRaw) ; // controllo che sia una Trimesh if ( pGObj->GetType() == SRF_TRIMESH) { SurfLocal StmRawPart( GetSurfTriMesh( pGObj), frRaw, GLOB_FRM) ; // lo aggiungo alla Trimesh complessiva pStmRaw->Add( *GetSurfTriMesh( StmRawPart)) ; } } // passo al grezzo successivo nRawId = m_pMchMgr->GetNextRawPart( nRawId) ; } return ( ( pStmRaw->IsValid() && pStmRaw->GetTriangleCount() > 0) ? Release( pStmRaw) : nullptr) ; } //---------------------------------------------------------------------------- ISurfFlatRegion* SurfRoughing::GetSfrByStmIntersection( const IntersParPlanesSurfTm& IPPStm, double dDist, double dSmallOffs) const { // interseco la superficie alla quota corrente PNTVECTOR vPnt ; BIPNTVECTOR vBpt ; TRIA3DVECTOR vTria ; if ( ! IPPStm.GetInters( dDist, vPnt, vBpt, vTria)) return nullptr ; // se non c'è intersezione if ( vBpt.empty()) return CreateSurfFlatRegion() ; // definisco la tolleranza per i concatenamenti double dToler = EPS_SMALL ; // costruisco la FlatRegion da ritornare SurfFlatRegionByContours SfrByC ; // Considero l'intersezione solo con Curve ( escludo punti e superfici) ChainCurves chainC ; chainC.Init( false, dToler, int( vBpt.size())) ; for ( int i = 0 ; i < int( vBpt.size()) ; ++ i) { Vector3d vtDir = vBpt[i].second - vBpt[i].first ; vtDir.Normalize() ; if ( ! chainC.AddCurve( i + 1, vBpt[i].first, vtDir, vBpt[i].second, vtDir)) return nullptr ; } // recupero i percorsi concatenati Point3d ptNear = ( vBpt.empty() ? ORIG : vBpt[0].first) ; INTVECTOR vId ; while ( chainC.GetChainFromNear( ptNear, false, vId)) { // creo una curva composita PtrOwner pCrvCompo( CreateCurveComposite()) ; if ( IsNull( pCrvCompo)) return nullptr ; // recupero gli estremi dei segmenti, creo le linee e le inserisco nella composita bool bAdded = true ; for ( int i = 0 ; i < int( vId.size()) ; ++ i) { // creo un segmento di retta PtrOwner pLine( CreateCurveLine()) ; if ( IsNull( pLine)) return nullptr ; // recupero gli estremi ( non vanno mai invertiti per opzione di concatenamento) int nInd = abs( vId[i]) - 1 ; Point3d ptStart = ( bAdded ? vBpt[nInd].first : ptNear) ; Point3d ptEnd = vBpt[nInd].second ; // provo ad accodarlo alla composita bAdded = ( Dist( ptStart, ptEnd) > dToler / 2 && pLine->Set( ptStart, ptEnd) && pCrvCompo->AddCurve( Release( pLine), true, dToler)) ; ptNear = ( bAdded ? ptEnd : ptStart) ; } // se lunghezza curva inferiore a 5 volte la tolleranza, la ignoro double dCrvLen ; if ( ! pCrvCompo->GetLength( dCrvLen) || dCrvLen < 5. * dToler) continue ; // se curva chiusa entro 5 volte la tolleranza ma considerata aperta, la chiudo bene Point3d ptStart, ptEnd ; if ( pCrvCompo->GetStartPoint( ptStart) && pCrvCompo->GetEndPoint( ptEnd) && AreSamePointEpsilon( ptStart, ptEnd, 5. * dToler) && ! AreSamePointApprox( ptStart, ptEnd)) { // porto il punto finale a coincidere esattamente con l'inizio pCrvCompo->ModifyEnd( ptStart) ; } // unisco segmenti allineati pCrvCompo->MergeCurves( 0.5 * dToler, ANG_TOL_STD_DEG) ; pCrvCompo->Close() ; // per sicurezza... // inserisco la curva nella FlatRegion SfrByC.AddCurve( Release( pCrvCompo)) ; } // recupero la regione da restituire PtrOwner pSfrFromCrvs( SfrByC.GetSurf()) ; return ( ( ! IsNull( pSfrFromCrvs) && pSfrFromCrvs->IsValid()) ? Release( pSfrFromCrvs) : nullptr) ; } //---------------------------------------------------------------------------- bool SurfRoughing::GetActiveSurfaces( INTVECTOR& vSurfId) const { // pulisco vettore superfici vSurfId.clear() ; // verifiche if ( m_pMchMgr == nullptr || m_pGeomDB == nullptr) return false ; // cerco tra gli oggetti selezionati for ( const auto& Id : m_vId) { int nEntId = Id.nId ; if ( m_pGeomDB->GetGeoType( nEntId) == SRF_TRIMESH) vSurfId.emplace_back( nEntId) ; } // se trovate superfici, considero solo queste ed esco if ( ! vSurfId.empty()) return true ; // altrimenti considero tutte le superfici dei pezzi nei grezzi attivi della fase int nRawId = m_pMchMgr->GetFirstRawPart() ; while ( nRawId != GDB_ID_NULL) { if ( m_pMchMgr->VerifyRawPartPhase(nRawId, m_nPhase)) { // ciclo sui pezzi del grezzo int nPartId = m_pMchMgr->GetFirstPartInRawPart( nRawId) ; while ( nPartId != GDB_ID_NULL) { // ciclo sui layer dei pezzi int nLayId = m_pGeomDB->GetFirstGroupInGroup( nPartId) ; while ( nLayId != GDB_ID_NULL) { // ciclo sulle entità del layer int nEntId = m_pGeomDB->GetFirstInGroup( nLayId) ; while ( nEntId != GDB_ID_NULL) { // se entità superficie e visibile, la aggiungo int nStat ; if ( m_pGeomDB->GetGeoType( nEntId) == SRF_TRIMESH && m_pGeomDB->GetCalcStatus( nEntId, nStat) && nStat != GDB_ST_OFF) vSurfId.emplace_back( nEntId) ; // passo alla entità successiva nEntId = m_pGeomDB->GetNext( nEntId) ; } nLayId = m_pGeomDB->GetNextGroup( nLayId) ; } nPartId = m_pMchMgr->GetNextPartInRawPart( nPartId) ; } } nRawId = m_pMchMgr->GetNextRawPart( nRawId) ; } return true ; } //---------------------------------------------------------------------------- bool SurfRoughing::CalcPaths( const INTINTVECTOR& vPocket, const ICRVCOMPOPOVECTOR& vCrvPocketCompo, STEPINFOVECTOR& vStepInfo) const { /* funzione per calcolo dei percorsi di Pockets e delle loro proprietà */ // inizializzo vettore dei percorsi vStepInfo.clear() ; vStepInfo.resize( int( vPocket.size())) ; // punto finale di riferimento per il percorso attuale ( serve per trovare il punto iniziale // del percorso successivo) Point3d ptEndLastPath = P_INVALID ; // scorro gli indici delle superfici int nInd = 0 ; for ( auto& vId : vPocket) { // recupero la superficie da lavorare vStepInfo[nInd].pSfrPock.Set( CloneSurfFlatRegion( m_pGeomDB->GetGeoObj( vId.first))) ; // controllo se la regione è relativa ad uno step base o ad uno step intermedio vStepInfo[nInd].bIsSubStep = ( vStepInfo[nInd].pSfrPock->GetTempProp( 0) == 1) ; // ricavo la Depth attuale vStepInfo[nInd].dDepth = vStepInfo[nInd].pSfrPock->GetTempParam( 0) ; // calcolo la Depth relativa if ( ! vStepInfo[nInd].bIsSubStep) { if ( nInd == 0) vStepInfo[nInd].dRelativeDepth = vStepInfo[nInd].dDepth ; // -Step else vStepInfo[nInd].dRelativeDepth = vStepInfo[nInd].dDepth - vStepInfo[nInd-1].dDepth ; // -Step } else { for ( int nI = 0 ; nI < nInd ; ++ nI) { if ( ! vStepInfo[nI].bIsSubStep && vStepInfo[nI].dDepth < vStepInfo[nInd].dDepth) { if ( nI == 0) vStepInfo[nInd].dRelativeDepth = vStepInfo[nInd].dDepth ; // Depth else vStepInfo[nInd].dRelativeDepth = vStepInfo[nInd].dDepth - vStepInfo[nI-1].dDepth ; // Depth relativa break ; } else if ( vStepInfo[nI].bIsSubStep) { vStepInfo[nInd].dRelativeDepth = vStepInfo[nInd].dDepth - vStepInfo[nI-1].dDepth ; // Depth relativa break ; } } } // ricavo il coefficiente di riduzione Feed locale vStepInfo[nInd].dZlocCoeffFeed = vStepInfo[nInd].pSfrPock->GetTempParam( 1) ; // recupero la superficie limite se presente vStepInfo[nInd].pSfrLimit.Set( CreateSurfFlatRegion()) ; if ( vId.second != GDB_ID_NULL) { const ISurfFlatRegion* pSfrL = GetSurfFlatRegion( m_pGeomDB->GetGeoObj( vId.second)) ; if ( pSfrL == nullptr) return false ; vStepInfo[nInd].pSfrLimit.Set( CloneSurfFlatRegion( pSfrL)) ; } // recupero la curva con proprietà OPEN/CLOSE selezionata per la sgrossatura /* Queste curve hanno tutte la stessa geometria ma possono presentare proprietà temporanee di lato OPEN/CLOSE differente sulle loro sottocurve, infatti queste proprietà dipendono dalla Geometria del finito */ vStepInfo[nInd].pCompo.Set( CloneCurveComposite( vCrvPocketCompo[nInd])) ; // se il tipo è SPIRAL_OUT e sto gestendo uno step intermedio, lo lavoro come SPIRAL_IN invertito int nSubType = m_Params.m_nSubType ; bool bInvert = m_Params.m_bInvert ; if ( nSubType == SURFROU_SUB_SPIRALOUT && vStepInfo[nInd].bIsSubStep) { nSubType = SURFROU_SUB_SPIRALIN ; bInvert = ! bInvert ; // per lasciare invariato il senso di percorrenza } vStepInfo[nInd].nSubType = nSubType ; vStepInfo[nInd].bInverted = bInvert ; // calcolo i percorsi di Pocketing ICRVCOMPOPOVECTOR vCrvPaths ; if ( ! CalcPocketing( vStepInfo[nInd].pSfrPock, m_TParams.m_dDiam / 2, 0., m_Params.m_dSideStep, m_Params.m_dSideAngle, vStepInfo[nInd].nSubType, true, vStepInfo[nInd].bInverted, false, true, ptEndLastPath, vStepInfo[nInd].pSfrLimit, vCrvPaths)) { if ( vStepInfo[nInd].bIsSubStep) { string sWarn = "Warning in SurfRoughing : CalcPocketing failed with substep (" + ToString( vStepInfo[nInd].dDepth, 1) + ")" ; m_pMchMgr->SetWarning( 3055, sWarn) ; } else { m_pMchMgr->SetLastError( 3028, "Error in SurfRoughing : Error in CalcPocketing") ; return false ; } } // se la svuotatura è di tipo conformal ZigZag ma la geometria non è valida if ( nSubType == SURFROU_SUB_CONFORMAL_ZIGZAG && vStepInfo[nInd].vPaths.empty()) { if ( vStepInfo[nInd].bIsSubStep) { string sWarn = "Warning in SurfRoughing : invalid Conformal ZigZag at substep (" + ToString( vStepInfo[nInd].dDepth, 1) + ")" ; m_pMchMgr->SetWarning( 3056, sWarn) ; } else { m_pMchMgr->SetLastError( 3030, "Error in SurfRoughing : Conformal ZigZag not valid at step (" + ToString( vStepInfo[nInd].dDepth, 1) + ")") ; return false ; } } // se non ho ottenuto percorsi, allora passo allo step successivo ( nInd non viene aggiornato!) if ( vCrvPaths.empty()) continue ; // sistemo gli archi per massimo angolo al centro for ( int i = 0 ; i < int( vCrvPaths.size()) ; ++ i) VerifyArcs( vCrvPaths[i]) ; // recupero il punto finale del percorso per lo step successivo vCrvPaths.back()->GetEndPoint( ptEndLastPath) ; // aggiorno il vettore degli step e modifico eventuali percorsi per LeadIn/LeadOut /* Controllo se il tratto lineare di estensione per l'entrata da un lato aperto non rovina un tratto chiuso della curva di bordo selezionata per la sgrossatura; idem per il tratto in uscita. */ vStepInfo[nInd].vPaths.resize( int( vCrvPaths.size())) ; for ( int i = 0 ; i < int( vCrvPaths.size()) ; ++ i) { // controllo se il percorso ha un ingresso presso un lato aperto vStepInfo[nInd].vPaths[i].bOutStart = ( vCrvPaths[i]->GetCurveCount() > 0 && vCrvPaths[i]->GetFirstCurve()->GetTempProp( 0) == TEMP_PROP_OUT_START) ; // controllo se il punto di ingresso è valido bool bValidOutLeadIn = true ; if ( vStepInfo[nInd].vPaths[i].bOutStart) { if ( ! VerifyLeadInLeadOut( vCrvPaths[i]->GetFirstCurve(), vStepInfo[nInd].pCompo, bValidOutLeadIn)) return false ; if ( ! bValidOutLeadIn) { // se non valido, rimuovo il primo tratto vStepInfo[nInd].vPaths[i].bOutStart = false ; vCrvPaths[i]->RemoveFirstOrLastCurve( false) ; } } // controllo se il percorso ha un'uscita presso un lato aperto bool bOutEnd = ( vCrvPaths[i]->GetCurveCount() > 0 && vCrvPaths[i]->GetLastCurve()->GetTempProp( 0) == TEMP_PROP_OUT_START) ; // controllo se il punto d'uscita va limitata bool bValidOutLeadOut = true ; if ( bOutEnd) { if ( ! VerifyLeadInLeadOut( vCrvPaths[i]->GetLastCurve(), vStepInfo[nInd].pCompo, bValidOutLeadOut)) return false ; // se non valido, rimuovo l'ultimo tratto if ( ! bValidOutLeadOut) vCrvPaths[i]->RemoveFirstOrLastCurve( true) ; } // controllo se il percorso è formato da una singola curva seguente il lato chiuso vStepInfo[nInd].vPaths[i].bSingleCrv = ( vCrvPaths[i]->GetCurveCount() > 0 && vCrvPaths[i]->GetTempProp( 0) == TEMP_PROP_SINGLE_CURVE) ; // controllo se caso ottimizzato a trapezio vStepInfo[nInd].vPaths[i].bOptTrap = ( vCrvPaths[i]->GetCurveCount() > 0 && vCrvPaths[i]->GetTempProp( 0) == TEMP_PROP_OPT_TRAPEZOID) ; // controllo se è un percorso a ZigZag/OneWay ( non curva di bordo) vStepInfo[nInd].vPaths[i].bIsZigZagOneWayBorder = ( vCrvPaths[i]->GetCurveCount() > 0 && ( vStepInfo[nInd].nSubType == SURFROU_SUB_ONEWAY || vStepInfo[nInd].nSubType == SURFROU_SUB_ZIGZAG) && vCrvPaths[i]->GetTempProp( 0) == TEMP_PROP_BORDER_CURVE) ; // se LeadIn o LeadOut a guida recupero la curva di ritorno se necessaria if ( ( GetLeadInType() == SURFROU_LI_GLIDE || GetLeadOutType() == SURFROU_LO_GLIDE) && ( vStepInfo[nInd].nSubType == SURFROU_SUB_SPIRALIN && ! vStepInfo[nInd].vPaths[i].bSingleCrv && ! vStepInfo[nInd].vPaths[i].bOutStart)) { if ( vStepInfo[nInd].vPaths[i].bOptTrap) vStepInfo[nInd].vPaths[i].pCvrRet.Set( ConvertCurveToComposite( vCrvPaths[i]->GetFirstCurve()->Clone())) ; else { Point3d ptStart ; vCrvPaths[i]->GetFirstCurve()->GetStartPoint( ptStart) ; vStepInfo[nInd].vPaths[i].pCvrRet.Set( CreateCurveComposite()) ; for ( int j = 0 ; j < vCrvPaths[i]->GetCurveCount() ; ++ j) { const ICurve* pCrv = vCrvPaths[i]->GetCurve( j) ; Point3d ptEnd ; if ( pCrv == nullptr || ! vStepInfo[nInd].vPaths[i].pCvrRet->AddCurve( *pCrv) || ! pCrv->GetEndPoint( ptEnd)) return false ; if ( AreSamePointApprox( ptStart, ptEnd)) break ; } } } // assegno il percorso vStepInfo[nInd].vPaths[i].pCrvPath.Set( vCrvPaths[i]) ; } ++ nInd ; // aggiorno la progressBar ExeProcessEvents( 50 + nInd * 50 / int( vPocket.size()), 100) ; } vStepInfo.resize( nInd) ; return true ; } //---------------------------------------------------------------------------- bool SurfRoughing::AddPocket( const INTINTVECTOR& vPocket, const Vector3d& vtTool, const ICRVCOMPOPOVECTOR& vCrvPocketCompo, double dElev, double dStep, double dSubStep, bool bSplitArcs) { // controllo dei parametri if ( vPocket.empty()) return true ; // calcolo i percorsi di svuotatura per ogni Step/SubStep STEPINFOVECTOR vStepInfo ; if ( ! CalcPaths( vPocket, vCrvPocketCompo, vStepInfo)) return false ; // recupero distanze di sicurezza double dSafeZ = GetSafeZ() ; // lunghezza di approccio/retrazione double dAppr = m_Params.m_dStartPos ; // elevazione sopra al punto attuale double dCurrElev ; // punto finale del percorso precedente al corrente Point3d ptEnd = P_INVALID ; // scorro il vettore dei piani di pocketing for ( int i = 0 ; i < int( vStepInfo.size()) ; ++ i) { // riferimento alle informazioni relative allo step i-esimo StepInfo& currStep = vStepInfo[i] ; // scorro i percorsi calcolati per il piano di pocketing i-esimo for ( int j = 0 ; j < int( currStep.vPaths.size()) ; ++ j) { // riferimento alle informazioni relative al percorso j-esimo del piano di pocketing i-esimo PathInfo& currPath = currStep.vPaths[j] ; // ciclo sulle curve elementari del percorso attuale int nMaxInd = currPath.pCrvPath->GetCurveCount() - 1 ; for ( int k = 0 ; k <= nMaxInd ; ++ k) { // curva corrente const ICurve* pCrvC = currPath.pCrvPath->GetCurve( k) ; // copio la curva PtrOwner pCurve( pCrvC->Clone()) ; if ( IsNull( pCurve)) return false ; // coefficiente feed ( riduzione di feed per sezione di taglio superiore al previsto ) double dTempParam ; currPath.pCrvPath->GetCurveTempParam( k, dTempParam) ; double dCoeffFeed = min( 1., ( dTempParam > EPS_SMALL ? dTempParam /= 1000 : 1) * currStep.dZlocCoeffFeed) ; // se prima entità if ( k == 0) { // dati inizio entità Point3d ptStart ; pCurve->GetStartPoint( ptStart) ; Vector3d vtStart ; pCurve->GetStartDir( vtStart) ; // flag approccio libero in aria if ( currPath.bOutStart) dCoeffFeed = ( dTempParam > EPS_SMALL ? dTempParam : 1) ; // calcolo ptP1 per LeadIn iniziale Point3d ptP1 ; if ( ! CalcLeadInStart( ptStart, vtTool, currPath.pCvrRet, ptP1)) { m_pMchMgr->SetLastError( 3013, "Error in SurfRoughing : LeadIn not computable") ; return false ; } // determino l'elevazione sull'inizio dell'attacco della prima curva globale bool bAbsFirst = ( i == 0 && j == 0) ; if ( bAbsFirst) dCurrElev = - currStep.dDepth ; dCurrElev -= ( ptP1 - ptStart) * vtTool ; // se attacco a zigzag o a spirale o a scivolo, l'elevazione va nell'attacco if ( GetLeadInType() != POCKET_LI_NONE) { double dMyLIO_ELEV_TOL = min( LIO_ELEV_TOL, dSafeZ) ; // se prima entità in assoluto if ( bAbsFirst) { ptP1 += vtTool * ( dCurrElev + dMyLIO_ELEV_TOL) ; dCurrElev = - min( LIO_ELEV_TOL, dSafeZ) ; } // altrimenti... else if ( ! currPath.bOutStart) ptP1 += vtTool * ( - currStep.dRelativeDepth + dMyLIO_ELEV_TOL) ; } // approccio al punto iniziale double dMySafeZ = ( bAbsFirst ? dSafeZ : 0.) ; Point3d ptMyPos ; GetCurrPos( ptMyPos) ; double dMyElev = ( bAbsFirst ? dCurrElev : ( ptMyPos - ptP1) * vtTool) ; double dMyAppr = ( bAbsFirst ? dAppr : 0.) ; if ( ! AddApproach( ptP1, vtTool, dMySafeZ, dMyElev, dMyAppr)) { m_pMchMgr->SetLastError( 3011, "Error in SurfRoughing : Approach not computable") ; return false ; } // aggiungo attacco SetFeed( GetStartFeed()) ; bool bNoneForced = ( currPath.bOutStart || currPath.bSingleCrv || ( currStep.nSubType == SURFROU_SUB_ZIGZAG && ! currPath.bIsZigZagOneWayBorder) || ( currStep.nSubType == SURFROU_SUB_ONEWAY && ! currPath.bIsZigZagOneWayBorder)) ; if ( ! AddLeadIn( ptP1, ptStart, vtStart, vtTool, currStep.pSfrPock, ( ( currStep.nSubType == SURFROU_SUB_SPIRALIN || currStep.nSubType == SURFROU_SUB_SPIRALOUT)) ? Get( currPath.pCvrRet) : nullptr, ( currStep.nSubType == SURFROU_SUB_SPIRALOUT) ? currStep.bInverted : ! currStep.bInverted, bSplitArcs, bNoneForced, false)) { m_pMchMgr->SetLastError( 3013, "Error in SurfRoughing : LeadIn not computable") ; return false ; } } // elaborazioni sulla curva corrente (sempre un segmento di retta) if ( pCurve->GetType() == CRV_LINE) { ICurveLine* pLine = GetCurveLine( pCurve) ; Point3d ptP3 = pLine->GetEnd() ; Vector3d vtMove ; pLine->GetStartDir( vtMove) ; SetFeed( dCoeffFeed * GetRightFeed( vtMove, vtTool)) ; if ( AddLinearMove( ptP3) == GDB_ID_NULL) return false ; } else if ( pCurve->GetType() == CRV_ARC) { ICurveArc* pArc = GetCurveArc( pCurve) ; Point3d ptCen = pArc->GetCenter() ; double dAngCen = pArc->GetAngCenter() ; Vector3d vtN = pArc->GetNormVersor() ; Point3d ptP3 ; pArc->GetEndPoint( ptP3) ; SetFeed( dCoeffFeed * GetFeed()) ; if ( AddArcMove( ptP3, ptCen, dAngCen, vtN) == GDB_ID_NULL) return false ; } // se ultima entità if ( k == nMaxInd) { // dati fine entità pCurve->GetEndPoint( ptEnd) ; Vector3d vtEnd ; pCurve->GetEndDir( vtEnd) ; // se sono l'ultima entità globale del percorso if ( i == int( vStepInfo.size()) - 1 && j == int( currStep.vPaths.size()) - 1) { // aggiungo LeadOut Point3d ptP1 ; SetFeed( GetEndFeed()) ; if ( ! AddLeadOut( ptEnd, vtEnd, vtTool, ( ( currStep.nSubType == SURFROU_SUB_SPIRALIN || currStep.nSubType == SURFROU_SUB_SPIRALOUT)) ? Get( currPath.pCvrRet) : nullptr, bSplitArcs, false, ptP1)) { m_pMchMgr->SetLastError( 3014, "Error in SurfRoughing : LeadOut not computable") ; return false ; } // aggiungo retroazione finale if ( ! AddRetract( ptP1, vtTool, dSafeZ, - currStep.dDepth, dAppr)) { m_pMchMgr->SetLastError( 3015, "Error in SurfRoughing : Retract not computable") ; return false ; } } // se ho un percorso successivo else { // ricavo il punto che devo raggiungere e controllo la posizione del percorso successivo bool bSamePlane = ( j < int( currStep.vPaths.size()) - 1) ; bool bNextIsBelow = true ; Point3d ptDest ; if ( bSamePlane) currStep.vPaths[j+1].pCrvPath->GetStartPoint( ptDest) ; else { vStepInfo[i+1].vPaths.front().pCrvPath->GetStartPoint( ptDest) ; bNextIsBelow = ( ( ptDest - ptEnd) * vtTool < - 50 * EPS_SMALL) ; } // determino se un collegamento lineare tra i punti proiettati nel piano attuale è ammissibile bool bSafe = false ; if ( currStep.nSubType != SURFROU_SUB_ZIGZAG && currStep.nSubType != SURFROU_SUB_ONEWAY) { if ( ! CheckSafetyLinearLink( ptEnd, ( bSamePlane ? currStep.pSfrLimit : ( bNextIsBelow ? currStep.pSfrLimit : vStepInfo[i+1].pSfrLimit)), vtTool, ptDest, bSafe)) return false ; } // determino l'elevazione sul punto corrente e sul punto di destinazione dCurrElev = dSafeZ ; double dNextElev = dSafeZ ; if ( bSafe) { if ( bSamePlane && ! vStepInfo[i].vPaths[j+1].bOutStart) dCurrElev -= currStep.dRelativeDepth ; else if ( bNextIsBelow) dNextElev += ( ptEnd - ptDest) * vtTool ; else { if ( vStepInfo[i+1].vPaths.front().bOutStart) dCurrElev += ( ptDest - ptEnd) * vtTool ; else dCurrElev -= currStep.dRelativeDepth ; } } else { dCurrElev -= currStep.dDepth ; if ( bSamePlane) dNextElev -= currStep.dDepth ; else dNextElev -= vStepInfo[i+1].dDepth ; } // tratto lineare sopra al punto corrente SetFeed( GetEndFeed()) ; AddLinearMove( ptEnd + vtTool * dCurrElev) ; // tratto lineare sopra a ptDest AddRapidMove( ptDest + vtTool * dNextElev) ; // aggiorno le elevazioni dCurrElev = dNextElev ; } } } } } return true ; } //---------------------------------------------------------------------------- bool SurfRoughing::AddApproach( const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dElev, double dAppr) { SetFlag( 1) ; // se sopra attacco c'è spazio per sicurezza o approccio double dSafeDist = dSafeZ ; if ( dElev + max( dSafeDist, dAppr) > 10 * EPS_SMALL) { // se distanza di sicurezza minore di distanza di inizio if ( dSafeDist < dAppr + 10 * EPS_SMALL) { // 1 -> punto sopra inizio Point3d ptP1 = ptP + vtTool * ( dElev + dAppr) ; if ( AddRapidStart( ptP1) == GDB_ID_NULL) return false ; } else { // 1a -> punto sopra inizio Point3d ptP1b = ptP + vtTool * ( dElev + dAppr) ; Point3d ptP1a = ptP1b + vtTool * ( dSafeDist - dAppr) ; if ( ( AddRapidStart( ptP1a) == GDB_ID_NULL)) return false ; // 1b -> punto appena sopra inizio if ( ( dElev + dAppr) > EPS_SMALL) { SetFlag( 0) ; if ( AddRapidMove( ptP1b) == GDB_ID_NULL) return false ; } } // affondo al punto iniziale SetFlag( 0) ; SetFeed( GetTipFeed()) ; if ( AddLinearMove( ptP) == GDB_ID_NULL) return false ; } else { // affondo diretto al punto iniziale SetFlag( 0) ; if ( AddRapidStart( ptP) == GDB_ID_NULL) return false ; } return true ; } //---------------------------------------------------------------------------- bool SurfRoughing::AddLinkApproach(const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dElev, double dAppr, bool bOutMove) { // se sopra attacco c'è spazio per approccio if ( ( dElev + dAppr) > 10 * EPS_SMALL) { // 1b -> punto appena sopra inizio Point3d ptP1b = ptP + vtTool * ( dElev + dAppr) ; if ( ( dElev + dAppr) > EPS_SMALL) { SetFlag( 0) ; if ( AddRapidMove( ptP1b) == GDB_ID_NULL) return false ; } // affondo al punto iniziale SetFlag( 0) ; SetFeed( bOutMove ? GetStartFeed() : GetTipFeed()) ; if ( AddLinearMove( ptP) == GDB_ID_NULL) return false ; } else { // affondo diretto al punto iniziale SetFlag( 0) ; if ( AddRapidMove( ptP) == GDB_ID_NULL) return false ; } return true ; } //---------------------------------------------------------------------------- bool SurfRoughing::AddLinkRetract( const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dElev, double dAppr) { // se sopra uscita c'è spazio per approccio if ( ( dElev + dAppr) > 10 * EPS_SMALL) { // 4 -> movimento di risalita sopra il punto finale SetFeed( GetEndFeed()) ; Point3d ptP4 = ptP + vtTool * ( dElev + dAppr) ; if ( AddLinearMove( ptP4) == GDB_ID_NULL) return false ; } return true ; } //---------------------------------------------------------------------------- bool SurfRoughing::AddRetract( const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dElev, double dAppr) { // se sopra uscita c'è spazio per sicurezza o approccio double dSafeDist = dSafeZ ; if ( dElev + max( dSafeDist, dAppr) > 10 * EPS_SMALL) { if ( dSafeDist < dAppr + 10 * EPS_SMALL) { // 4 -> movimento di risalita sopra il punto finale SetFeed( GetEndFeed()) ; Point3d ptP4 = ptP + vtTool * ( dElev + dAppr) ; if ( AddLinearMove( ptP4) == GDB_ID_NULL) return false ; } else { // 4a -> movimento di risalita appena sopra il punto finale Point3d ptP4a = ptP + vtTool * ( dElev + dAppr) ; if ( dElev + dAppr > EPS_SMALL) { SetFeed( GetEndFeed()) ; if ( AddLinearMove( ptP4a) == GDB_ID_NULL) return false ; } // 4b -> movimento di risalita sopra il punto finale Point3d ptP4b = ptP4a + vtTool * ( dSafeDist - dAppr) ; if ( AddRapidMove( ptP4b) == GDB_ID_NULL) return false ; } } return true ; } //---------------------------------------------------------------------------- bool SurfRoughing::CalcLeadInStart( const Point3d& ptStart, const Vector3d& vtTool, const ICurveComposite* pRCrv, Point3d& ptP1) const { // Assegno tipo e parametri int nType = GetLeadInType() ; if ( nType == SURFROU_LI_GLIDE && ( pRCrv == nullptr || pRCrv->GetCurveCount() == 0)) nType = SURFROU_LI_NONE ; // Calcolo punto iniziale switch ( nType) { case SURFROU_LI_NONE : case SURFROU_LI_ZIGZAG : case SURFROU_LI_HELIX : ptP1 = ptStart ; return true ; case SURFROU_LI_GLIDE : { double dLen, dU ; if ( ! pRCrv->GetLength( dLen) || ! pRCrv->GetParamAtLength( dLen - m_Params.m_dLiTang, dU) || ! pRCrv->GetPointD1D2( dU, ICurve::FROM_MINUS, ptP1)) { if ( ! pRCrv->GetStartPoint( ptP1)) return false ; } ptP1 += vtTool * ( vtTool * ( ptStart - ptP1)) ; return true ; } default : return false ; } } //---------------------------------------------------------------------------- bool SurfRoughing::AddLeadIn( const Point3d& ptP1, const Point3d& ptStart, const Vector3d& vtStart, const Vector3d& vtN, const ISurfFlatRegion* pSfr, const ICurveComposite* pRCrv, bool bAtLeft, bool bSplitArcs, bool bNoneForced, bool bSkipControl) { // Assegno il tipo int nType = GetLeadInType() ; if ( bNoneForced || AreSamePointEpsilon( ptP1, ptStart, 10 * EPS_SMALL) || ( nType == SURFROU_LI_GLIDE && ( pRCrv == nullptr || pRCrv->GetCurveCount() == 0))) nType = SURFROU_LI_NONE ; // Se elica e fattibile lo creo if ( nType == SURFROU_LI_HELIX) { // vettore dal punto al centro elica Vector3d vtCen = vtStart ; vtCen.Rotate( vtN, 0, ( bAtLeft ? 1 : - 1)) ; // dati dell'elica double dRad = min( 0.5 * min( m_Params.m_dLiTang, m_TParams.m_dDiam), m_dMaxHelixRad) ; Point3d ptCen = ptP1 + vtCen * dRad ; double dDeltaN = ( ptStart - ptP1) * vtN ; double dAngCen = ceil( - dDeltaN / ( m_Params.m_dLiElev + 20 * EPS_SMALL)) * ( bAtLeft ? ANG_FULL : - ANG_FULL) ; // verifico se fattibile if ( bSkipControl || VerifyLeadInHelix( pSfr, ptStart, ptCen, dRad)) { // creo l'elica PtrOwner pArc( CreateCurveArc()) ; if ( IsNull( pArc) || ! pArc->Set( ptCen, vtN, dRad, - vtCen, dAngCen, dDeltaN)) return false ; // emetto l'elica (con eventuale spezzatura) return ( AddCurveMove( pArc, bSplitArcs, MCH_CL_LEADIN) != GDB_ID_NULL) ; } // altrimenti zigzag else nType = SURFROU_LI_ZIGZAG ; } // Se zigzag e fattibile lo creo if ( nType == SURFROU_LI_ZIGZAG) { // dati dello zigzag double dDeltaN = ( ptStart - ptP1) * vtN ; int nStep = int( ceil( - dDeltaN / ( m_Params.m_dLiElev + 20 * EPS_SMALL))) ; double dStep = - dDeltaN / nStep ; Point3d ptPa = ptP1 + vtStart * 0.5 * min( m_Params.m_dLiTang, m_TParams.m_dDiam) ; Point3d ptPb = ptP1 - vtStart * 0.5 * min( m_Params.m_dLiTang, m_TParams.m_dDiam) ; // verifico se fattibile if ( bSkipControl || VerifyLeadInZigZag( pSfr, ptStart, ptPa, ptPb)) { for ( int i = 1 ; i <= nStep ; ++ i) { if ( AddLinearMove( ptPa - vtN * ( i - 0.75) * dStep, bSplitArcs, MCH_CL_LEADIN) == GDB_ID_NULL) return false ; if ( AddLinearMove( ptPb - vtN * ( i - 0.25) * dStep, bSplitArcs, MCH_CL_LEADIN) == GDB_ID_NULL) return false ; } return ( AddLinearMove( ptStart, bSplitArcs, MCH_CL_LEADIN) != GDB_ID_NULL) ; } // altrimenti diretto else { nType = SURFROU_LI_NONE ; if ( m_TParams.m_nType == TT_MILL_NOTIP) return false ; } } // Se a scivolo e fattibile if ( nType == SURFROU_LI_GLIDE) { if ( pRCrv != nullptr) { // recupero la parte richiesta della curva di ritorno PtrOwner pCrv ; double dLen, dU ; if ( pRCrv->GetLength( dLen) && pRCrv->GetParamAtLength( dLen - m_Params.m_dLiTang, dU)) { double dParS, dParE ; pRCrv->GetDomain( dParS, dParE) ; if ( ! pCrv.Set( ConvertCurveToComposite( pRCrv->CopyParamRange( dU, dParE)))) return false ; } else { if ( ! pCrv.Set( pRCrv->Clone())) return false ; } pCrv->SetExtrusion( vtN) ; // la porto alla giusta quota Point3d ptFin ; pCrv->GetEndPoint( ptFin) ; Vector3d vtMove = ptStart - ptFin ; pCrv->Translate( vtMove) ; // assegno la corretta pendenza double dNini = ( ptP1 - ORIG) * vtN ; double dNfin = ( ptStart - ORIG) * vtN ; AdjustCurveSlope( pCrv, dNini, dNfin) ; // emetto (con eventuale spezzatura) return ( AddCurveMove( pCrv, bSplitArcs, MCH_CL_LEADIN) != GDB_ID_NULL) ; } // altrimenti diretto else nType = SURFROU_LI_NONE ; } // Se diretto if ( nType == SURFROU_LI_NONE) { Point3d ptCurr = ptP1 ; GetCurrPos( ptCurr) ; if ( ! AreSamePointApprox( ptCurr, ptStart)) { if ( AddLinearMove( ptStart, bSplitArcs, MCH_CL_LEADIN) == GDB_ID_NULL) return false ; } return true ; } // Altrimenti errore return false ; } //---------------------------------------------------------------------------- bool SurfRoughing::AddLeadOut( const Point3d& ptEnd, const Vector3d& vtEnd, const Vector3d& vtN, const ICurveComposite* pRCrv, bool bSplitArcs, bool bNoneForced, Point3d& ptP1) { // assegno i parametri int nType = GetLeadOutType() ; if ( bNoneForced || ( nType == SURFROU_LO_GLIDE && ( pRCrv == nullptr || pRCrv->GetCurveCount() == 0))) nType = SURFROU_LO_NONE ; // eseguo a seconda del tipo switch ( nType) { case SURFROU_LO_NONE : { // nessuna uscita ptP1 = ptEnd ; return true ; } case SURFROU_LO_GLIDE : { // recupero la parte richiesta della curva di ritorno PtrOwner pCrv ; double dU ; if ( pRCrv->GetParamAtLength( m_Params.m_dLoTang, dU)) { if ( ! pCrv.Set( ConvertCurveToComposite( pRCrv->CopyParamRange( 0, dU)))) return false ; } else { if ( ! pCrv.Set( pRCrv->Clone())) return false ; } // la porto alla giusta quota Point3d ptIni ; pCrv->GetStartPoint( ptIni) ; Vector3d vtMove = ptEnd - ptIni ; pCrv->Translate( vtMove) ; Point3d ptFin ; pCrv->GetEndPoint( ptFin) ; ptFin += vtN * 1.0 ; pCrv->ModifyEnd( ptFin) ; // emetto (con eventuale spezzatura) AddCurveMove( pCrv, bSplitArcs, MCH_CL_LEADOUT) ; // determino elevazione su fine uscita ptP1 = ptFin ; return true ; } default : return false ; } } //---------------------------------------------------------------------------- double SurfRoughing::GetRightFeed( const Vector3d& vtMove, const Vector3d& vtTool) const { // Determino i versori Vector3d vtM = vtMove ; vtM.Normalize() ; Vector3d vtT = vtTool ; vtT.Normalize() ; // Angolo tra movimento e versore utensile double dCosMove = vtM * vtT ; // Se l'utensile non ha movimento significativo di punta, si restituisce la feed standard if ( dCosMove > - COS_ORTO_ANG_SMALL) return GetFeed() ; // Altrimenti non si deve superare la massima velocità di punta prevista return min( GetFeed(), GetTipFeed() / abs( dCosMove)) ; } //---------------------------------------------------------------------------- bool SurfRoughing::ResetCurveAllTempProp( ICurve* pCurve) const { // controllo validità della curva if ( pCurve == nullptr) return false ; // metto a 0 le tmpProps della curva pCurve->SetTempProp( 0, 0) ; pCurve->SetTempProp( 0, 1) ; // ricavo la composita associata ICurveComposite* pCC = GetCurveComposite( pCurve) ; if ( pCC != nullptr) for ( int i = 0 ; i < pCC->GetCurveCount() ; ++ i) { // per ogni sottcurva metto a 0 le temProps pCC->SetCurveTempProp( i, 0, 0) ; pCC->SetCurveTempProp( i, 0, 1) ; } return true ; } //---------------------------------------------------------------------------- bool SurfRoughing::SimplifyCurve( ICurveComposite* pCompo) const { // controllo dei parametri if ( pCompo == nullptr || ! pCompo->IsValid()) return false ; // ricavo il punto iniziale e finale Point3d ptStart ; pCompo->GetStartPoint( ptStart) ; Point3d ptEnd ; pCompo->GetEndPoint( ptEnd) ; // eseguo le modifiche su una copia della curva originale PtrOwner pCompoCL( CloneCurveComposite( pCompo)) ; if ( IsNull( pCompoCL)) return false ; // merge per uniformità bool bOk = pCompoCL->MergeCurves( 200 * EPS_SMALL, 200 * EPS_ANG_SMALL, false) ; // rimozione Spikes o Curve Z bOk = bOk && pCompoCL->RemoveSmallDefects( 150 * EPS_SMALL, 2 * ANG_TOL_STD_DEG, true) ; // interpolazione mediante linee ed archi PolyArc PA ; bOk = bOk && pCompoCL->ApproxWithArcsEx( 50 * EPS_SMALL, ANG_TOL_STD_DEG, LIN_FEA_STD, PA) && pCompoCL->Clear() && pCompoCL->FromPolyArc( PA) ; // controllo aggiuntivo sui punti iniziali e finali che siano gli stessi Point3d ptNewStart, ptNewEnd ; bOk = bOk && pCompoCL->GetStartPoint( ptNewStart) && pCompoCL->GetEndPoint( ptNewEnd) && AreSamePointApprox( ptNewStart, ptStart) && AreSamePointApprox( ptNewEnd, ptEnd) ; // se tutto bene, sostiuisco la curva originale con la modificata if ( bOk) pCompo->CopyFrom( pCompoCL) ; return true ; } //---------------------------------------------------------------------------- bool SurfRoughing::SimplyfySfr( ISurfFlatRegion* pSfr) const { // controllo dei parametri if ( pSfr == nullptr || ! pSfr->IsValid()) return false ; // creo una superficie vuota; inserirò i Loop di pSfr semplificati PtrOwner pSfrSimple( CreateSurfFlatRegion()) ; if ( IsNull( pSfrSimple)) return false ; // scorro tutti i loops di tutte le parti for ( int nC = 0 ; nC < pSfr->GetChunkCount() ; ++ nC) { for ( int nL = 0 ; nL < pSfr->GetLoopCount( nC) ; ++ nL) { // recupero la curva di Loop e la semplifico PtrOwner pCompoLoop( ConvertCurveToComposite( pSfr->GetLoop( nC, nL))) ; if ( IsNull( pCompoLoop) || ! SimplifyCurve( pCompoLoop)) return false ; // inserisco le curve nella nuova regione (il primo loop di ogni parte è esterno) if ( nL == 0) { if ( ! pSfrSimple->AddExtLoop( Release( pCompoLoop))) return false ; } else { if ( ! pSfrSimple->AddIntLoop( Release( pCompoLoop))) return false ; } } } // se superficie semplificata valida, la sostituisco if ( pSfrSimple->IsValid()) return ( pSfr->CopyFrom( pSfrSimple)) ; return true ; } //---------------------------------------------------------------------------- bool SurfRoughing::RemoveChunksUnderTolerance( ISurfFlatRegion* pSfr) const { /* quando si lavorano dei SubSteps, può capitare che la superfice da rimuovere sia molto snella; questo succede quando lo step eseguito in precedenza rimuove gran parte del materiale utile per il piano di lavoro attuale. Si creano dunque delle regioni formate da più Chunk molto sottili che creano sia problemi di distinzione dei lati aperti che problemi poi ad essere svuotate ( si pensi all'estensione dei lati aperti e al loro raccordo con i chiusi, oltre al fatto che i chunk in questa operazione potrebbero mergiarsi tra loro creando ambiguità. Data la superficie *pSfr, vengono rimossi tutti i Chunks che si annullano mediante il contro-Offset definito dalla tolleranza NB. Il Contro-Offset è possibile farlo solo sul Loop esterno, non c'è bisogno di fare conti aggiuntivi per le isole interne */ // controllo dei parametri if ( pSfr == nullptr || ! pSfr->IsValid()) return false ; if ( m_dSubStepToler < EPS_SMALL) // se tolleranza non presente, non faccio nulla return true ; // scorro tutti i chunk della superficie for ( int nC = 0 ; nC < pSfr->GetChunkCount() ; ++ nC) { // verifico se l'Offset massimo del chunk è sopra alla tolleranza double dMaxOffs = EPS_SMALL ; pSfr->GetChunkMaxOffset( nC, dMaxOffs) ; // rimuovo il Chunk c-esimo se l'Offset massimo è minore della tolleranza if ( dMaxOffs < m_dSubStepToler) { pSfr->EraseChunk( nC) ; -- nC ; } } return true ; } //---------------------------------------------------------------------------- bool SurfRoughing::CloseOpenEdgesUnderTolerance( ISurfFlatRegion* pSfr, double dToler) { /* Nei SubSteps capita spesso che ci siano dei lati aperti molto piccoli o delle sequenze di lati Aperti-Chiusi alternati tutti molto corti ( es. Laurana50K). Chiudo tutti i tratti aperti piccoli */ // controllo dei parametri if ( pSfr == nullptr || ! pSfr->IsValid()) return false ; if ( dToler < 10 * EPS_SMALL) // se tolleranza non presente, non faccio nulla return true ; // inizializzo la superficie da restituire PtrOwner pSfrRegular( CreateSurfFlatRegion()) ; if ( IsNull( pSfrRegular)) return false ; // scorro tutti i chunk della superficie for ( int nC = 0 ; nC < pSfr->GetChunkCount() ; ++ nC) { // scorro tutti i loop for ( int nL = 0 ; nL < pSfr->GetLoopCount( nC) ; ++ nL) { // recupero il loop come curva composita PtrOwner pCrvLoop( ConvertCurveToComposite( pSfr->GetLoop( nC, nL))) ; if ( IsNull( pCrvLoop) || ! pCrvLoop->IsValid()) return false ; // ------------- ricavo tratti di proprietà uniformi ------------- ICRVCOMPOPOVECTOR vpCrvs ; // vettore tratti aperti e chiusi alternati tra gli indici int nCurrTempProp ; int nParStart = 0 ; for ( int i = 0 ; i < pCrvLoop->GetCurveCount() ; ++ i) { // per ogni curva del loop int nTempProp ; pCrvLoop->GetCurveTempProp( i, nTempProp) ; if ( i == 0) { nCurrTempProp = nTempProp ; nParStart = i ; } else if ( nCurrTempProp != nTempProp) { // se TempProp0 differente dalla curva precedente // ricavo il tratto di curva PtrOwner pCrv( ConvertCurveToComposite( pCrvLoop->CopyParamRange( nParStart, i))) ; if ( IsNull( pCrv)) return false ; pCrv->SetTempProp( nCurrTempProp) ; vpCrvs.emplace_back( Release( pCrv)) ; nCurrTempProp = nTempProp ; nParStart = i ; } } // ultima curva ( se esiste) if ( nParStart < pCrvLoop->GetCurveCount()) { PtrOwner pCrvLast( ConvertCurveToComposite( pCrvLoop->CopyParamRange( nParStart, pCrvLoop->GetCurveCount()))) ; if ( IsNull( pCrvLast) || ! pCrvLast->IsValid()) return false ; pCrvLast->SetTempProp( nCurrTempProp) ; if ( vpCrvs.empty()) vpCrvs.emplace_back( Release( pCrvLast)) ; // la curva originale aveva tutte propietà uniformi else { if ( vpCrvs[0]->GetTempProp( 0) == nCurrTempProp) vpCrvs[0]->AddCurve( Release( pCrvLast), false) ; else vpCrvs.emplace_back( Release( pCrvLast)) ; } } // -------------------------------------------------------------------- // scorro tutti i tratti aperti e riconcateno il loop PtrOwner pCrvNewLoop( CreateCurveComposite()) ; if ( IsNull( pCrvNewLoop)) return false ; for ( int i = 0 ; i < int( vpCrvs.size()) ; ++ i) { // se tratto aperto e non coincidente con tutta la curva if ( vpCrvs[i]->GetTempProp( 0) == 1 && int( vpCrvs.size()) != 1) { // semplifico il loop per avere curve più uniformi SimplifyCurve( vpCrvs[i]) ; // riporto le proprietà vpCrvs[i]->SetTempProp( 1) ; for ( int j = 0 ; j < vpCrvs[i]->GetCurveCount() ; ++ j) vpCrvs[i]->SetCurveTempProp( j, 1, 0) ; // controllo la lunghezza delle curve double dLen = EPS_SMALL ; vpCrvs[i]->GetLength( dLen) ; // se più corto della tolleranza if ( dLen < dToler) { vpCrvs[i]->SetTempProp( 0, 0) ; for ( int j = 0 ; j < vpCrvs[i]->GetCurveCount() ; ++ j) vpCrvs[i]->SetCurveTempProp( j, 0, 0) ; } } pCrvNewLoop->AddCurve( Release( vpCrvs[i])) ; } // inserisco i nuovi loop nella superficie regolare if ( nL == 0) { if ( ! pSfrRegular->AddExtLoop( Release( pCrvNewLoop))) return false ; } else { if ( ! pSfrRegular->AddIntLoop( Release( pCrvNewLoop))) return false ; } } } // resituisco la superficie pSfr->CopyFrom( pSfrRegular) ; return true ; } //---------------------------------------------------------------------------- bool SurfRoughing::ModifySurfRefForOpenCloseEdges( ISurfFlatRegion* pSfrRef, const ICurveComposite* pCrvCompo) const { // controllo dei parametri if ( pSfrRef == nullptr || pCrvCompo == nullptr || ! pCrvCompo->IsValid()) return false ; /* NB. Questa funzione è richiamata per i sub steps. Alcuni subStep potrebbero avere dei lati aperti molto vicini ai lati chiusi della curva scelta per la sgrossatura; modifico la superficie di riferimento per la scelta dei lati Aperti/Chiusi estendendola con le regione generate dalle FatCurve dei tratti chiusi */ // ricavo i tratti chiusi della curva di sgrossatura ICRVCOMPOPOVECTOR vpCrvs ; if ( ! GetHomogeneousParts( pCrvCompo, vpCrvs)) return false ; // scorro tutti i tratti chiusi e li aggiungo alla pSfrDanger for ( int i = 0 ; i < int( vpCrvs.size()) ; ++ i) { if ( vpCrvs[i]->GetTempProp( 0) == TEMP_PROP_CLOSE_EDGE) { PtrOwner pSfrFat( GetSurfFlatRegionFromFatCurve( vpCrvs[i]->Clone(), m_TParams.m_dDiam / 2, false, false)) ; if ( ! IsNull( pSfrFat) && pSfrFat->IsValid()) { if ( ! pSfrRef->IsValid()) pSfrRef->CopyFrom( pSfrFat) ; else pSfrRef->Add( *pSfrFat) ; } } } return true ; } //---------------------------------------------------------------------------- bool SurfRoughing::ChooseCloseOrOpenEdge( ISurfFlatRegion* pSfr, const ISurfFlatRegion* pSfrRef) const { // controllo parametri : if ( pSfr == nullptr || ! pSfr->IsValid()) return true ; // <- se superficie non valida, allora non ho niente da impostare sui suoi lati if ( pSfrRef == nullptr || ! pSfrRef->IsValid()) return false ; // recupero la regione di riferimento ( effettuerò un piccolo Offset per tolleranza) PtrOwner pSfrRef_Offs( CloneSurfFlatRegion( pSfrRef)) ; if ( IsNull( pSfrRef_Offs)) return false ; pSfrRef_Offs->Offset( - 50 * EPS_SMALL, ICurve::OFF_FILLET) ; // salvo le informazioni del loop relativi alla flatRegion di classificazione struct SurfRef_Info { bool bIsExternal = true ; int nInternalLoops = 0 ; BBox3d bBox ; PolyLine PL_Loop ; } ; vector vSfrRef_info ; // assegno le info dei Loop della superficie di riferimento for ( int c = 0 ; c < pSfrRef_Offs->GetChunkCount() ; ++ c) { for ( int l = 0 ; l < pSfrRef_Offs->GetLoopCount( c) ; ++ l) { SurfRef_Info mySurfRef_Info ; mySurfRef_Info.bIsExternal = ( l == 0) ; if ( mySurfRef_Info.bIsExternal) mySurfRef_Info.nInternalLoops = pSfrRef_Offs->GetLoopCount( c) - 1 ; PtrOwner pCrv( pSfrRef_Offs->GetLoop( c, l)) ; pCrv->ApproxWithLines( 10 * EPS_SMALL, 15, ICurve::APL_STD, mySurfRef_Info.PL_Loop) ; if ( ! mySurfRef_Info.bIsExternal) mySurfRef_Info.PL_Loop.Invert() ; mySurfRef_Info.PL_Loop.GetLocalBBox( mySurfRef_Info.bBox) ; vSfrRef_info.emplace_back( mySurfRef_Info) ; } } // per ogni curva dei Loop della FlatRegion vengono presi 4 punti di controllo equidistanti. // " IL LATO E' APERTO <=> TUTTI I PUNTI DI CONTROLLO NON SONO DENTRO A pSfrRef " /* Invece di classificare i punti con la FlatRegion stessa è stata creata una struttura che contiene le PolyLine dei singoli loop. Quando io classifico un punto rispetto ad una regione piana, vengono presi tutti i loops e, una volta trasformati in PolyLine, viene classificato il punto rispetto ad esse. Invece di approssimare tutti i Loop da curve composite e Polyline per ogni punto ( per classificarlo), vengono direttamente salvate le PolyLine, in modo che questo passaggio sia fatto solo una volta all'inizio */ const int NUM_POINTS = 4 ; // scorro tutti i loop for ( int c = 0 ; c < pSfr->GetChunkCount() ; ++ c) { for ( int l = 0 ; l < pSfr->GetLoopCount( c) ; ++ l) { // recupero la curva composita del Loop PtrOwner pCrvCompoLoop( ConvertCurveToComposite( pSfr->GetLoop( c, l))) ; if ( IsNull( pCrvCompoLoop) || ! pCrvCompoLoop->IsValid()) return false ; // scorro ogni sua sottocurva for ( int u = 0 ; u < pCrvCompoLoop->GetCurveCount() ; ++ u) { // metto a 1 la TmpProp della sottocurva corrente della superficie pSfr->SetCurveTempProp( c, l, u, TEMP_PROP_OPEN_EDGE, 0) ; // recupero la sottocurva const ICurve* pCrv = pCrvCompoLoop->GetCurve( u) ; if ( pCrv == nullptr) return false ; // recupero i NUM_POINTS punti bool bIsOut = true ; for ( int p = 0 ; p < NUM_POINTS + 1 ; ++ p) { double dPar = ( 1. / ( 1. * NUM_POINTS)) * p ; Point3d ptPar ; if ( ! pCrv->GetPointD1D2( dPar, ICurve::FROM_PLUS, ptPar)) return false ; // scorro il vettore relativo alla regione di riferimento bIsOut = true ; for ( int nI = 0 ; nI < int( vSfrRef_info.size()) ; ++ nI) { if ( vSfrRef_info[nI].bIsExternal) { // se loop esterno if ( vSfrRef_info[nI].bBox.Encloses( ptPar)) { // interno al box del loop if ( IsPointInsidePolyLine( ptPar, vSfrRef_info[nI].PL_Loop, EPS_SMALL)) { // interno al loop vero e proprio bool bInsideHole = false ; // verifico se contenuto in un loop interno al loop esterno corrente int nIntLoops = vSfrRef_info[nI].nInternalLoops ; for ( int nJ = 0 ; nJ < nIntLoops ; ++ nJ) { ++ nI ; if ( vSfrRef_info[nI].bBox.Encloses( ptPar)) { if ( IsPointInsidePolyLine( ptPar, vSfrRef_info[nI].PL_Loop, EPS_SMALL)) bInsideHole = true ; } } // se è contenuto nel loop esterno ma non è contenuto in nessuno dei loop interni allora il punto è interno if ( ! bInsideHole) bIsOut = false ; } } } } if ( ! bIsOut) { pSfr->SetCurveTempProp( c, l, u, TEMP_PROP_CLOSE_EDGE, 0) ; break ; } } } } } return true ; } //---------------------------------------------------------------------------- bool SurfRoughing::AssignOpenEdgesForPocketCrvCompo( ICurveComposite* pCrvCompo, const ISurfFlatRegion* pSfr) const { /* Assegno i lati aperti/Chiusi alla curva di Pocketing modificando però i punti iniziali/finali delle sue sottocurve adattandoli alla geomtria di pSfr */ // controllo validità dei parametri if ( pCrvCompo == nullptr || ! pCrvCompo->IsValid() || pSfr == nullptr || ! pSfr->IsValid()) return false ; // creo la nuova curva di riferimento PtrOwner pMyNewCompo( CreateCurveComposite()) ; if ( IsNull( pMyNewCompo)) return false ; // classifico la curva in base alla superficie CRVCVECTOR ccClass ; if ( pSfr->GetCurveClassification( *pCrvCompo, EPS_SMALL, ccClass)) { for ( int i = 0 ; i < int( ccClass.size()) ; ++ i) { // il sottotratto di curva interno è chiuso, tutto il resto è aperto PtrOwner pCrv( pCrvCompo->CopyParamRange( ccClass[i].dParS, ccClass[i].dParE)) ; if ( ! IsNull( pCrv) && pCrv->IsValid()) { // se sottotratto valido, lo converto in curva composita PtrOwner pCompo( ConvertCurveToComposite( Release( pCrv))) ; if ( IsNull( pCompo) || ! pCompo->IsValid()) return false ; // assegno le proprietà di lato aperto/chiuso alla sottocurve ricavate for ( int j = 0 ; j < pCompo->GetCurveCount() ; ++ j) pCompo->SetCurveTempProp( j, ( ccClass[i].nClass == CRVC_IN ? TEMP_PROP_CLOSE_EDGE : TEMP_PROP_OPEN_EDGE), 0) ; // aggiungo la curva al risultato if ( ! pMyNewCompo->AddCurve( Release( pCompo))) break ; } } } // se tutto è andato a buon fine allora restituisco la curva if ( pMyNewCompo->IsValid() && pMyNewCompo->IsClosed()) pCrvCompo->CopyFrom( pMyNewCompo) ; else { // tutta chiusa per sicurezza for ( int i = 0 ; i < pCrvCompo->GetCurveCount() ; ++ i) pCrvCompo->SetCurveTempProp( i, TEMP_PROP_CLOSE_EDGE, 0) ; } return true ; } //---------------------------------------------------------------------------- double SurfRoughing::GetRadiusForStartEndElevation( void) const { const double DELTA_ELEV_RAD = 4.0 ; double dDeltaRad = min( DELTA_ELEV_RAD, 0.5 * m_TParams.m_dTDiam) ; return ( 0.5 * m_TParams.m_dTDiam + dDeltaRad) ; } //---------------------------------------------------------------------------- bool SurfRoughing::AdjustPathForLeadInLeadOut( ICurveComposite* pCrvCompo, int nSubType, const ICurveComposite* pCrvPocket, bool& bOutStart, bool& bSingleCrv, bool& bOptTrap, bool& bIsZigZagOneWayBorder) const { // controllo dei parametri if ( pCrvCompo == nullptr || ! pCrvCompo->IsValid()) return false ; // controllo se il percorso ha un ingresso presso un lato aperto bOutStart = ( pCrvCompo->GetCurveCount() > 0 && pCrvCompo->GetFirstCurve()->GetTempProp( 0) == TEMP_PROP_OUT_START) ; // controllo se il punto di ingresso è valido bool bValidOutLeadIn = true ; if ( bOutStart) { if ( ! VerifyLeadInLeadOut( pCrvCompo->GetFirstCurve(), pCrvPocket, bValidOutLeadIn)) return false ; if ( ! bValidOutLeadIn) { // se non valido, rimuovo il primo tratto bOutStart = false ; pCrvCompo->RemoveFirstOrLastCurve( false) ; } } // controllo se il percorso ha un'uscita presso un lato aperto bool bOutEnd = ( pCrvCompo->GetCurveCount() > 0 && pCrvCompo->GetLastCurve()->GetTempProp( 0) == TEMP_PROP_OUT_START) ; // controllo se il punto d'uscita va limitata bool bValidOutLeadOut = true ; if ( bOutEnd) { if ( ! VerifyLeadInLeadOut( pCrvCompo->GetLastCurve(), pCrvPocket, bValidOutLeadOut)) return false ; // se non valido, rimuovo l'ultimo tratto if ( ! bValidOutLeadOut) pCrvCompo->RemoveFirstOrLastCurve( true) ; } // controllo se il percorso è formato da una singola curva seguente il lato chiuso bSingleCrv = ( pCrvCompo->GetCurveCount() > 0 && pCrvCompo->GetTempProp( 0) == TEMP_PROP_SINGLE_CURVE) ; // controllo se caso ottimizzato a trapezio bOptTrap = ( pCrvCompo->GetCurveCount() > 0 && pCrvCompo->GetTempProp( 0) == TEMP_PROP_OPT_TRAPEZOID) ; // controllo se è un percorso a ZigZag/OneWay ( non curva di bordo) bIsZigZagOneWayBorder = ( pCrvCompo->GetCurveCount() > 0 && ( nSubType == SURFROU_SUB_ONEWAY || nSubType == SURFROU_SUB_ZIGZAG) && pCrvCompo->GetTempProp( 0) == TEMP_PROP_BORDER_CURVE) ; return true ; } //---------------------------------------------------------------------------- bool SurfRoughing::CheckSafetyLinearLink( const Point3d& ptCurr, const ISurfFlatRegion* pSfrLimit, const Vector3d& vtTool, const Point3d& ptDest, bool& bSafe) const { // controllo dei parametri if ( ! ptCurr.IsValid() || ! ptDest.IsValid() || ! vtTool.IsValid()) return false ; bSafe = true ; // porto ptDest alla stessa quota di ptCurr secondo vtTool Plane3d plProj ; if ( ! plProj.Set( ptCurr, vtTool)) return false ; Point3d ptDestProj = ProjectPointOnPlane( ptDest, plProj) ; // controllo se la retta che collega ptCurr a ptDesProj è interna o esterna alla regione limite // devo prima creare un frame Locale XY if ( pSfrLimit != nullptr && pSfrLimit->IsValid()) { PtrOwner pSfrLimitLoc( CloneSurfFlatRegion( pSfrLimit)) ; PtrOwner pLineLoc( CreateCurveLine()) ; Frame3d frLoc ; if ( IsNull( pSfrLimitLoc) || ! frLoc.Set( ptCurr, vtTool) || ! ptDestProj.ToLoc( frLoc) || ! pSfrLimitLoc->ToLoc( frLoc) || ! pSfrLimitLoc->Offset( m_TParams.m_dDiam / 2 - 10 * EPS_SMALL, ICurve::OFF_FILLET) || ! pLineLoc->Set( ORIG, ptDestProj)) return false ; for ( int nC = 0 ; nC < pSfrLimitLoc->GetChunkCount() && bSafe ; ++ nC) { CRVCVECTOR ccClass ; bSafe = ( pSfrLimitLoc->GetCurveClassification( *pLineLoc, EPS_SMALL, ccClass) && int( ccClass.size()) == 1 && ccClass[0].nClass == CRVC_OUT) ; } } return true ; } //---------------------------------------------------------------------------- bool SurfRoughing::VerifyLeadInHelix( const ISurfFlatRegion* pSfr, const Point3d& ptStart, const Point3d& ptCen, double dHelixRad) const { // controllo validità dei parametri if ( pSfr == nullptr || ! pSfr->IsValid()) return false ; Vector3d vtN = pSfr->GetNormVersor() ; // porto il centro sullo stesso piano del contorno Point3d ptCenL = ptCen - ( ptCen - ptStart) * vtN * vtN ; // Offset della regione PtrOwner pSfrOffs( pSfr->CreateOffsetSurf( - m_TParams.m_dDiam / 2 - dHelixRad + 10 * EPS_SMALL, ICurve::OFF_FILLET)) ; if ( IsNull( pSfrOffs) || ! pSfrOffs->IsValid()) return false ; // controllo se l'elica è valida bool bIsInside ; return ( IsPointInsideSurfFr( ptCenL, pSfrOffs, 0., bIsInside) && bIsInside) ; } //---------------------------------------------------------------------------- bool SurfRoughing::VerifyLeadInZigZag( const ISurfFlatRegion* pSfr, const Point3d& ptStart, const Point3d& ptPa, const Point3d& ptPb) const { // controllo validità dei parametri if ( pSfr == nullptr || ! pSfr->IsValid()) return false ; Vector3d vtN = pSfr->GetNormVersor() ; // porto i punti sullo stesso piano del contorno Point3d ptPaL = ptPa - ( ptPa - ptStart) * vtN * vtN ; Point3d ptPbL = ptPb - ( ptPb - ptStart) * vtN * vtN ; // Offset della regione PtrOwner pSfrOffs( pSfr->CreateOffsetSurf( - m_TParams.m_dDiam / 2 + 10 * EPS_SMALL, ICurve::OFF_FILLET)) ; if ( IsNull( pSfrOffs) || ! pSfrOffs->IsValid()) return false ; // controllo se i due punti sono validi bool bIsInside ; return ( IsPointInsideSurfFr( ptPaL, pSfrOffs, 0., bIsInside) && bIsInside && IsPointInsideSurfFr( ptPbL, pSfrOffs, 0., bIsInside) && bIsInside) ; } //---------------------------------------------------------------------------- bool SurfRoughing::GetHomogeneousParts( const ICurveComposite* pCrvCompo, ICRVCOMPOPOVECTOR& vpCrvs) const { // controllo dei parametri if ( pCrvCompo == nullptr || ! pCrvCompo->IsValid()) return false ; vpCrvs.clear() ; // scorro tutte le curve semplici nella composita int nCurrTempProp ; int nParStart = 0 ; for ( int i = 0 ; i < pCrvCompo->GetCurveCount() ; ++ i) { // ricavo la TmpProp int nTempProp ; pCrvCompo->GetCurveTempProp( i, nTempProp) ; if ( i == 0) { nCurrTempProp = nTempProp ; nParStart = i ; } // se TmpProp differiscono, ricavo il tratto di curva omogeneo else if ( nCurrTempProp != nTempProp) { PtrOwner pCrv( ConvertCurveToComposite( pCrvCompo->CopyParamRange( nParStart, i))) ; if ( IsNull( pCrv)) return false ; pCrv->SetTempProp( nCurrTempProp) ; // globale, al tratto di curva nel vettore vpCrvs.emplace_back( Release( pCrv)) ; nCurrTempProp = nTempProp ; nParStart = i ; } } // ultima curva... PtrOwner pCrvLast( ConvertCurveToComposite( pCrvCompo->CopyParamRange( nParStart, pCrvCompo->GetCurveCount()))) ; if ( ! IsNull( pCrvLast)) { pCrvLast->SetTempProp( nCurrTempProp) ; vpCrvs.emplace_back( Release( pCrvLast)) ; } if ( vpCrvs.size() > 1) { // unisco il primo e l'ultimo se estremi compatibili Point3d ptE ; vpCrvs.back()->GetEndPoint( ptE) ; Point3d ptS ; vpCrvs[0]->GetStartPoint( ptS) ; if ( AreSamePointApprox( ptS, ptE) && vpCrvs[0]->GetTempProp() == vpCrvs.back()->GetTempProp()) { vpCrvs[0]->AddCurve( Release( vpCrvs.back()), false) ; vpCrvs.erase( vpCrvs.end() - 1) ; } } return true ; } //---------------------------------------------------------------------------- bool SurfRoughing::VerifyLeadInLeadOut( const ICurve* pCrv, const ICurveComposite* pCrvPock, bool& bValidLeadIn) const { /* Verifica se il segmento di LeadIn per entrate da fuori sia valido */ // controllo dei parametri if ( pCrv == nullptr || ! pCrv->IsValid() || pCrvPock == nullptr || ! pCrvPock->IsValid()) return false ; // recupero i tratti chiusi della curva di pocketing ICRVCOMPOPOVECTOR vpCrvs ; if ( ! GetHomogeneousParts( pCrvPock, vpCrvs)) return false ; // porto tutto nel piano XY ( la Fat curve di una Linea è ambigua) Frame3d frLoc ; Point3d ptFrLoc ; pCrvPock->GetStartPoint( ptFrLoc) ; double dArea ; Plane3d plPlane ; pCrvPock->GetArea( plPlane, dArea) ; Vector3d vtFrLoc = plPlane.GetVersN() ; if ( ! frLoc.Set( ptFrLoc, vtFrLoc)) return false ; // porto la curva in locale PtrOwner pCrvLoc( pCrv->Clone()) ; if ( IsNull( pCrvLoc) || ! pCrvLoc->IsValid() || ! pCrvLoc->ToLoc( frLoc)) return false ; // calcolo la Fat Curve del tratto lineare e la porto in globale PtrOwner pSfrFat( GetSurfFlatRegionFromFatCurve( pCrvLoc->Clone(), m_TParams.m_dDiam / 2, false, false)) ; if ( IsNull( pSfrFat) || ! pSfrFat->IsValid()) return false ; bValidLeadIn = true ; for ( int i = 0 ; i < int( vpCrvs.size()) && bValidLeadIn ; ++ i) { // se tratto chiuso... if ( vpCrvs[i]->GetTempProp( 0) == 0) { // porto nel frame locale vpCrvs[i]->ToLoc( frLoc) ; // controllo se interseca la fat curve CRVCVECTOR ccClass ; if ( pSfrFat->GetCurveClassification( *vpCrvs[i], EPS_SMALL, ccClass)) bValidLeadIn = ( int( ccClass.size()) == 1 && ccClass[0].nClass == CRVC_OUT) ; else bValidLeadIn = false ; } } return true ; } //---------------------------------------------------------------------------- // Debug Functions //---------------------------------------------------------------------------- void SurfRoughing::DrawLoopsSurf( const ISurfFlatRegion* pSfr, bool bWithSurf, Color Col, bool bAlphaCoverage, int nStep) { int myId = m_pGeomDB->GetFirstNameInGroup( GDB_ID_ROOT, _DEBUG_GROUP_TERRACE) ; if ( myId == GDB_ID_NULL) { myId = m_pGeomDB->AddGroup( GDB_ID_NULL, GDB_ID_ROOT, GLOB_FRM) ; m_pGeomDB->SetName( myId, _DEBUG_GROUP_TERRACE) ; } else { if ( nStep == 0) m_pGeomDB->EmptyGroup( myId) ; } int myStepId = m_pGeomDB->AddGroup( GDB_ID_NULL, myId, GLOB_FRM) ; m_pGeomDB->SetName( myStepId, "Step " + ToString( nStep)) ; int nInd = m_pGeomDB->AddGeoObj( GDB_ID_NULL, myStepId, pSfr->Clone()) ; m_pGeomDB->SetMaterial( nInd, Col) ; for ( int c = 0 ; c < pSfr->GetChunkCount() ; ++ c) { for ( int l = 0 ; l < pSfr->GetLoopCount( c) ; ++ l) { PtrOwner pCrvCompo( GetCurveComposite( pSfr->GetLoop( c, l))) ; for ( int u = 0 ; u < pCrvCompo->GetCurveCount() ; ++ u) { int nProp0 ; pCrvCompo->GetCurveTempProp( u, nProp0, 0) ; int nProp1 ; pCrvCompo->GetCurveTempProp( u, nProp1, 1) ; nInd = m_pGeomDB->AddGeoObj( GDB_ID_NULL, myStepId, pCrvCompo->GetCurve( u)->Clone()) ; m_pGeomDB->SetMaterial( nInd, nProp0 == 0 ? ! bAlphaCoverage ? BLUE : AQUA : ! bAlphaCoverage ? RED : ORANGE) ; } } } return ; } //---------------------------------------------------------------------------- void SurfRoughing::DrawFeed( const ICurveComposite* pCrv, int nStep) { int myId = m_pGeomDB->GetFirstNameInGroup( GDB_ID_ROOT, _DEBUG_GROUP_FEED) ; if ( myId == GDB_ID_NULL) { myId = m_pGeomDB->AddGroup( GDB_ID_NULL, GDB_ID_ROOT, GLOB_FRM) ; m_pGeomDB->SetName( myId, _DEBUG_GROUP_FEED) ; } else { if ( nStep == 0) m_pGeomDB->EmptyGroup( myId) ; } int myStepId = m_pGeomDB->AddGroup( GDB_ID_NULL, myId, GLOB_FRM) ; m_pGeomDB->SetName( myStepId, "Step " + ToString( nStep)) ; double dMinFeed = GetFeed() * GetSideStep() / m_TParams.m_dDiam ; for ( int u = 0 ; u < pCrv->GetCurveCount() ; ++ u) { double myAngle = 120 * ( ( ( pCrv->GetCurve( u)->GetTempParam( 0) - dMinFeed) / ( GetFeed() - dMinFeed))) ; int nInd = m_pGeomDB->AddGeoObj( GDB_ID_NULL, myStepId, pCrv->GetCurve( u)->Clone()) ; m_pGeomDB->SetMaterial( nInd, GetColorFromHSV( HSV( myAngle, 1., 1.))) ; } return ; }