//---------------------------------------------------------------------------- // EgalTech 2017-2017 //---------------------------------------------------------------------------- // File : Pocketing.cpp Data : 04.02.17 Versione : 1.8b1 // Contenuto : Implementazione gestione svuotature. // // // // Modifiche : 04.02.17 DS Creazione modulo. // // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "MachMgr.h" #include "DllMain.h" #include "Pocketing.h" #include "OperationConst.h" #include "MachiningConst.h" #include "/EgtDev/Include/EGkCurveLine.h" #include "/EgtDev/Include/EGkCurveArc.h" #include "/EgtDev/Include/EGkArcSpecial.h" #include "/EgtDev/Include/EGkChainCurves.h" #include "/EgtDev/Include/EGkOffsetCurve.h" #include "/EgtDev/Include/EGkCurveAux.h" #include "/EgtDev/Include/EGkSfrCreate.h" #include "/EgtDev/Include/EGkSurfTriMesh.h" #include "/EgtDev/Include/EGkExtText.h" #include "/EgtDev/Include/EGkCurveLocal.h" #include "/EgtDev/Include/EGkDistPointCurve.h" #include "/EgtDev/Include/EGkUserObjFactory.h" #include "/EgtDev/Include/EGkIntervals.h" #include "/EgtDev/Include/EGkStringUtils3d.h" #include "/EgtDev/Include/EGnStringKeyVal.h" #include "/EgtDev/Include/EgtPointerOwner.h" #include "/EgtDev/Include/EgtNumUtils.h" #include "/EgtDev/Include/EgkStmFromCurves.h" #include "/EgtDev/Include/EGkDistPointSurfTm.h" using namespace std ; //------------------------------ Errors -------------------------------------- // 2401 = "Error in Pocketing : UpdateToolData failed" // 2402 = "Error in Pocketing : Open Contour" // 2403 = "Error in Pocketing : Contour Not Flat" // 2404 = "Error in Pocketing : Tool Not Perpendicular to Flat Area" // 2405 = "Error in Pocketing : Empty RawBox" // 2406 = "Error in Pocketing : Depth not computable" // 2408 = "Error in Pocketing : Entity GetElevation" // 2409 = "Error in Pocketing : missing aggregate from bottom" // 2410 = "Error in Pocketing : path too far from part sides" // 2411 = "Error in Pocketing : toolpath allocation failed" // 2412 = "Error in Pocketing : Offset not computable" // 2413 = "Error in Pocketing : Toolpath not computable" // 2414 = "Error in Pocketing : Approach not computable" // 2415 = "Error in Pocketing : LeadIn not computable" // 2416 = "Error in Pocketing : LeadOut not computable" // 2417 = "Error in Pocketing : Retract not computable" // 2418 = "Error in Pocketing : Link not computable" // 2419 = "Error in Pocketing : Linear Approx not computable" // 2420 = "Error in Pocketing : Return toolpath not computable" // 2421 = "Error in Pocketing : Chaining failed" // 2422 = "Error in Pocketing : Tool MaxMaterial too small (xxx)" // 2423 = "Error in Pocketing : axes values not calculable" // 2424 = "Error in Pocketing : outstroke xxx" // 2425 = "Error in Pocketing : link movements not calculable" // 2426 = "Error in Pocketing : link outstroke xxx" // 2427 = "Error in Pocketing : post apply not calculable" // 2428 = "Error in Pocketing : Tool loading failed" // 2429 = "Error in Pocketing : machining depth (xxx) bigger than MaxDepth (yyy)" // 2430 = "Error in Pocketing : adjust open edges failed" // 2431 = "Error in Pocketing : LeadIn with Mill NoTip in material" // 2451 = "Warning in Pocketing : Skipped entity (xx)" // 2452 = "Warning in Pocketing : No machinable pocket" // 2453 = "Warning in Pocketing : Tool name changed (xx)" // 2454 = "Warning in Pocketing : Tool data changed (xx)" // 2455 = "Warning in Pocketing : skipped Path too short" // 2456 = "Warning in Pocketing : machining step too small (xx)" // 2457 = "Warning in Pocketing : machining step (xxx) bigger than MaxMaterial (yyy)" // 2458 = "Warning in Pocketing : machining depth (xxx) bigger than MaxMaterial (yyy)" //---------------------------------------------------------------------------- static string KEY_OPEN = "OPEN" ; //---------------------------------------------------------------------------- USEROBJ_REGISTER( GetOperationClass( OPER_POCKETING), Pocketing) ; //---------------------------------------------------------------------------- const string& Pocketing::GetClassName( void) const { return USEROBJ_GETNAME( Pocketing) ; } //---------------------------------------------------------------------------- Pocketing* Pocketing::Clone( void) const { // alloco oggetto Pocketing* pPock = new(nothrow) Pocketing ; // eseguo copia dei dati if ( pPock != nullptr) { try { pPock->m_vId = m_vId ; pPock->m_pMchMgr = m_pMchMgr ; pPock->m_nPhase = m_nPhase ; pPock->m_Params = m_Params ; pPock->m_TParams = m_TParams ; pPock->m_nStatus = m_nStatus ; pPock->m_nPockets = m_nPockets ; pPock->m_bTiltingTab = m_bTiltingTab ; pPock->m_bAboveHead = m_bAboveHead ; pPock->m_bAggrBottom = m_bAggrBottom ; } catch( ...) { delete pPock ; return nullptr ; } } // ritorno l'oggetto return pPock ; } //---------------------------------------------------------------------------- bool Pocketing::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_nPockets) + szNewLine ; sOut += KEY_STAT + EQUAL + ToString( m_nStatus) + szNewLine ; return true ; } //---------------------------------------------------------------------------- bool Pocketing::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_nPockets, vString[++k])) return false ; if ( ! SetVal( KEY_STAT, m_nStatus, vString[++k])) return false ; } catch( ...) { return false ; } return true ; } //---------------------------------------------------------------------------- bool Pocketing::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_nPockets)) return false ; } else if ( sKey == KEY_STAT) { if ( ! FromString( sVal, m_nStatus)) return false ; } } return true ; } //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- Pocketing::Pocketing( void) { m_Params.m_sName = "*" ; m_Params.m_sToolName = "*" ; m_TParams.m_sName = "*" ; m_TParams.m_sHead = "*" ; m_dTHoldLen = 0 ; m_dTHoldDiam = 0 ; m_dMaxHelixRad = INFINITO ; m_nStatus = MCH_ST_TO_VERIFY ; m_nPockets = 0 ; m_bTiltingTab = false ; m_bAboveHead = true ; m_bAggrBottom = false ; } //---------------------------------------------------------------------------- bool Pocketing::Prepare( const string& sMillName) { // 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 PocketingData* pDdata = GetPocketingData( pMMgr->GetMachining( sMillName)) ; 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 Pocketing::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 ; case MPA_TOOLINVERT : if ( bVal != m_Params.m_bToolInvert) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_bToolInvert = bVal ; return true ; } return false ; } //---------------------------------------------------------------------------- bool Pocketing::SetParam( int nType, int nVal) { switch ( nType) { 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 ; 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 ; } return false ; } //---------------------------------------------------------------------------- bool Pocketing::SetParam( int nType, double dVal) { switch ( nType) { case MPA_SPEED : if ( ! m_TParams.VerifySpeed( dVal)) return false ; if ( abs( m_TParams.m_dSpeed - dVal) < EPS_MACH_ANG_PAR) dVal = 0 ; if ( abs( dVal - m_Params.m_dSpeed) > EPS_MACH_ANG_PAR) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dSpeed = dVal ; return true ; case MPA_FEED : if ( abs( m_TParams.m_dFeed - dVal) < EPS_MACH_LEN_PAR) dVal = 0 ; if ( abs( dVal - m_Params.m_dFeed) > EPS_MACH_LEN_PAR) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dFeed = dVal ; return true ; case MPA_STARTFEED : if ( abs( m_TParams.m_dStartFeed - dVal) < EPS_MACH_LEN_PAR) dVal = 0 ; if ( abs( dVal - m_Params.m_dStartFeed) > EPS_MACH_LEN_PAR) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dStartFeed = dVal ; return true ; case MPA_ENDFEED : if ( abs( m_TParams.m_dEndFeed - dVal) < EPS_MACH_LEN_PAR) dVal = 0 ; if ( abs( dVal - m_Params.m_dEndFeed) > EPS_MACH_LEN_PAR) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dEndFeed = dVal ; return true ; case MPA_TIPFEED : if ( abs( m_TParams.m_dTipFeed - dVal) < EPS_MACH_LEN_PAR) dVal = 0 ; if ( abs( dVal - m_Params.m_dTipFeed) > EPS_MACH_LEN_PAR) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dTipFeed = dVal ; return true ; case MPA_OFFSR : if ( abs( m_TParams.m_dOffsR - dVal) < EPS_MACH_LEN_PAR) dVal = UNKNOWN_PAR ; if ( abs( dVal - m_Params.m_dOffsR) > EPS_MACH_LEN_PAR) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dOffsR = dVal ; return true ; case MPA_OFFSL : if ( abs( m_TParams.m_dOffsL - dVal) < EPS_MACH_LEN_PAR) dVal = UNKNOWN_PAR ; if ( abs( dVal - m_Params.m_dOffsL) > EPS_MACH_LEN_PAR) 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 ( abs( dVal - m_Params.m_dStartPos) > EPS_MACH_LEN_PAR) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dStartPos = dVal ; return true ; case MPA_STEP : if ( abs( dVal - m_Params.m_dStep) > EPS_MACH_LEN_PAR) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dStep = dVal ; return true ; case MPA_SIDESTEP : if ( abs( dVal - m_Params.m_dSideStep) > EPS_MACH_LEN_PAR) 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_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_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_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 ; } return false ; } //---------------------------------------------------------------------------- bool Pocketing::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 Pocketing::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 (tutte curve o tutte facce) int nType = GEO_NONE ; for ( const auto& Id : vIds) { // test sull'entità int nSubs ; if ( ! VerifyGeometry( Id, nSubs, nType)) { string sInfo = "Warning in Pocketing : Skipped entity " + ToString( Id) ; m_pMchMgr->SetWarning( 2451, 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() || vIds.empty()) ; } //---------------------------------------------------------------------------- bool Pocketing::Preview( bool bRecalc) { // reset numero percorsi di svuotatura generati m_nPockets = 0 ; // verifico validità gestore DB geometrico e Id del gruppo if ( m_pGeomDB == nullptr || ! m_pGeomDB->ExistsObj( m_nOwnerId)) return false ; // 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 ; } // aggiorno dati geometrici dell'utensile if ( ! UpdateToolData()) { m_pMchMgr->SetLastError( 2401, "Error in Pocketing : UpdateToolData failed") ; return false ; } // 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( 2428, "Error in Pocketing : Tool loading failed") ; return false ; } // recupero i dati del portautensile int nToolId = m_pMchMgr->GetCalcTool() ; 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( 2421, "Error in Pocketing : Chaining failed") ; return false ; } // recupero gruppo per geometria di Preview int nPvId = m_pGeomDB->GetFirstNameInGroup( m_nOwnerId, MCH_PV) ; // se non c'è, lo aggiungo if ( nPvId == GDB_ID_NULL) { nPvId = m_pGeomDB->AddGroup( GDB_ID_NULL, m_nOwnerId, Frame3d()) ; if ( nPvId == GDB_ID_NULL) return false ; m_pGeomDB->SetName( nPvId, MCH_PV) ; } // altrimenti lo svuoto else m_pGeomDB->EmptyGroup( nPvId) ; // lavoro ogni singola catena int nPathId = m_pGeomDB->GetFirstGroupInGroup( nAuxId) ; while ( nPathId != GDB_ID_NULL) { if ( ! ProcessPath( nPathId, nPvId, GDB_ID_NULL)) return false ; nPathId = m_pGeomDB->GetNextGroup( nPathId) ; } return true ; } //---------------------------------------------------------------------------- bool Pocketing::Apply( bool bRecalc, bool bPostApply) { // reset numero percorsi di svuotatura generati int nCurrPockets = m_nPockets ; m_nPockets = 0 ; // reset raggio massimo attacco ad elica nel caso di cerchi m_dMaxHelixRad = INFINITO ; // 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( 2401, "Error in Pocketing : UpdateToolData failed") ; return false ; } // verifico se necessario continuare nell'aggiornamento if ( ! bRecalc && ! bToolChanged && ( m_nStatus == MCH_ST_OK || ( ! bPostApply && m_nStatus == MCH_ST_NO_POSTAPPL))) { m_nPockets = nCurrPockets ; LOG_DBG_INFO( GetEMkLogger(), "Pocketing apply skipped : status already ok") ; 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( 2428, "Error in Pocketing : Tool loading failed") ; return false ; } // recupero i dati del portautensile int nToolId = m_pMchMgr->GetCalcTool() ; 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( 2421, "Error in Pocketing : 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) ; // lavoro ogni singola catena bool bOk = true ; int nPathId = m_pGeomDB->GetFirstGroupInGroup( nAuxId) ; if ( ! ProcessPath2( nPathId, GDB_ID_NULL, nClId) ) return false ; // while ( nPathId != GDB_ID_NULL) { // if ( ! ProcessPath( nPathId, 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) ; return true ; } //---------------------------------------------------------------------------- bool Pocketing::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_nPockets == 0) { m_pMchMgr->SetWarning( 2452, "Warning in Pocketing : No machinable pocket") ; return true ; } // imposto eventuale asse bloccato da lavorazione if ( ! m_Params.m_sBlockedAxis.empty()) { string sAxis, sVal ; Split( m_Params.m_sBlockedAxis, "=", true, sAxis, sVal) ; double dVal = 0 ; FromString( sVal, dVal) ; m_pMchMgr->ClearRotAxisBlock() ; m_pMchMgr->SetRotAxisBlock( sAxis, dVal) ; } // 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( 2423, "Error in Pocketing : axes values not calculable") ; else m_pMchMgr->SetLastError( 2424, "Error in Pocketing : 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( 2425, "Error in Pocketing : link movements not calculable") ; else m_pMchMgr->SetLastError( 2426, "Error in Pocketing : 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( 2427, sErr) ; else m_pMchMgr->SetLastError( 2427, "Error in Pocketing : post apply not calculable") ; return false ; } return true ; } //---------------------------------------------------------------------------- bool Pocketing::GetParam( int nType, bool& bVal) const { switch ( nType) { case MPA_INVERT : bVal = m_Params.m_bInvert ; return true ; case MPA_TOOLINVERT : bVal = m_Params.m_bToolInvert ; return true ; } bVal = false ; return false ; } //---------------------------------------------------------------------------- bool Pocketing::GetParam( int nType, int& nVal) const { switch ( nType) { case MPA_TYPE : nVal = MT_POCKETING ; 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 ; case MPA_SUBTYPE : nVal = m_Params.m_nSubType ; return true ; } nVal = 0 ; return false ; } //---------------------------------------------------------------------------- bool Pocketing::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_SIDESTEP : dVal = m_Params.m_dSideStep ; return true ; case MPA_SIDEANGLE : dVal = m_Params.m_dSideAngle ; return true ; case MPA_LITANG : dVal = m_Params.m_dLiTang ; return true ; case MPA_LIELEV : dVal = m_Params.m_dLiElev ; return true ; case MPA_LOTANG : dVal = m_Params.m_dLoTang ; return true ; } dVal = 0 ; return false ; } //---------------------------------------------------------------------------- bool Pocketing::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& Pocketing::GetToolData( void) const { return m_TParams ; } //---------------------------------------------------------------------------- bool Pocketing::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 ; // verifico se sono diversi (ad esclusione del nome) m_TParams.m_sName = pTdata->m_sName ; bool bChanged = ! SameTool( m_TParams, *pTdata) ; // aggiorno comunque i parametri m_TParams = *pTdata ; // eventuali segnalazioni if ( ! EqualNoCase( m_Params.m_sToolName, m_TParams.m_sName)) { string sInfo = "Warning in Pocketing : tool name changed (" + m_Params.m_sToolName + "->" + m_TParams.m_sName + ")" ; m_pMchMgr->SetWarning( 2453, sInfo) ; m_Params.m_sToolName = m_TParams.m_sName ; } if ( bChanged) { string sInfo = "Warning in Pocketing : tool data changed (" + m_Params.m_sToolName + ")" ; m_pMchMgr->SetWarning( 2454, sInfo) ; } // se definito parametro di ritorno, lo assegno if ( pbChanged != nullptr) *pbChanged = bChanged ; return true ; } //---------------------------------------------------------------------------- bool Pocketing::GetGeometry( SELVECTOR& vIds) const { // restituisco l'elenco delle entità vIds = m_vId ; return true ; } //---------------------------------------------------------------------------- bool Pocketing::VerifyGeometry( SelData Id, int& nSubs, int& nType) { // ammessi : curve, testi, facce di trimesh o regioni const IGeoObj* pGObj = m_pGeomDB->GetGeoObj( Id.nId) ; if ( pGObj == nullptr) return false ; // se ammesse curve ed è tale if ( ( nType == GEO_NONE || nType == GEO_CURVE) && ( pGObj->GetType() & GEO_CURVE) != 0) { nType = GEO_CURVE ; const ICurve* pCurve = nullptr ; // se direttamente la curva if ( Id.nSub == SEL_SUB_ALL) { pCurve = ::GetCurve( pGObj) ; if ( pCurve == nullptr) return false ; if ( pCurve->GetType() == CRV_COMPO) nSubs = ::GetCurveComposite( pCurve)->GetCurveCount() ; else nSubs = 0 ; } // altrimenti sottocurva di composita else { const ICurveComposite* pCompo = GetCurveComposite( pGObj) ; pCurve = ( pCompo != nullptr ? pCompo->GetCurve( Id.nSub) : nullptr) ; if ( pCurve == nullptr) return false ; nSubs = 0 ; } return true ; } // se altrimenti ammessi testi ed è tale else if ( ( nType == GEO_NONE || nType == EXT_TEXT) && pGObj->GetType() == EXT_TEXT) { nType = EXT_TEXT ; const IExtText* pText = ::GetExtText( pGObj) ; if ( pText == nullptr) return false ; nSubs = 0 ; return true ; } // se altrimenti ammesse superfici trimesh ed è tale else if ( ( nType == GEO_NONE || nType == SRF_TRIMESH) && pGObj->GetType() == SRF_TRIMESH) { nType = SRF_TRIMESH ; const ISurfTriMesh* pSurf = ::GetSurfTriMesh( pGObj) ; if ( pSurf == nullptr) return false ; // se direttamente la superficie if ( Id.nSub == SEL_SUB_ALL) { // deve avere una sola faccia if ( pSurf->GetFacetCount() != 1) return false ; nSubs = 1 ; } // altrimenti faccia di superficie trimesh else { // se faccia non esistente if ( Id.nSub >= pSurf->GetFacetCount()) return false ; nSubs = 0 ; } return true ; } // se altrimenti ammesse regioni ed è tale else if ( ( nType == GEO_NONE || nType == SRF_FLATRGN) && pGObj->GetType() == SRF_FLATRGN) { nType = SRF_FLATRGN ; const ISurfFlatRegion* pReg = ::GetSurfFlatRegion( pGObj) ; if ( pReg == nullptr) return false ; // se direttamente la regione if ( Id.nSub == SEL_SUB_ALL) { nSubs = pReg->GetChunkCount() ; } // altrimenti chunk di regione else { // se chunk non esistente if ( Id.nSub >= pReg->GetChunkCount()) return false ; // tutto bene nSubs = 0 ; } return true ; } // altrimenti errore else return false ; } //---------------------------------------------------------------------------- bool Pocketing::GetCurves( SelData Id, ICURVEPLIST& lstPC) { LOG_ERROR( GetEMkLogger(), (" -- GET CURVES " + to_string( Id.nId) + " " + to_string( Id.nSub)).c_str()) // ammessi : curve, testi, facce di trimesh o regioni 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()) ; // recupero eventuali informazioni per lati aperti SetCurveAllTempProp( Id.nId, pCurve) ; // 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()) ; // reset proprietà temporanee ResetCurveAllTempProp( pCurve) ; // 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 testo else if ( pGObj->GetType() == EXT_TEXT) { // recupero il testo const IExtText* pText = ::GetExtText( pGObj) ; if ( pText == nullptr) return false ; // recupero l'outline del testo if ( ! pText->GetOutline( lstPC)) return false ; // reset proprietà temporanee for ( auto pCrv : lstPC) ResetCurveAllTempProp( pCrv) ; // porto le curve in globale for ( auto pCrv : lstPC) pCrv->ToGlob( frGlob) ; // ritorno return true ; } // se altrimenti superficie else if ( pGObj->GetType() == SRF_TRIMESH) { // recupero la trimesh const ISurfTriMesh* pSurf = ::GetSurfTriMesh( pGObj) ; if ( pSurf == nullptr) return false ; // recupero l'indice della faccia int nFacet = ( ( Id.nSub == SEL_SUB_ALL) ? 0 : Id.nSub) ; // recupero i contorni della faccia POLYLINEVECTOR vPL ; pSurf->GetFacetLoops( nFacet, vPL) ; if ( vPL.empty()) return false ; // creo la curva a partire da quello esterno for ( size_t k = 0 ; k < vPL.size() ; k++) { PtrOwner pCrvCompo( CreateCurveComposite()) ; pCrvCompo->FromPolyLine( vPL[k]) ; if ( ! pCrvCompo->IsValid()) return false ; // reset proprietà temporanee ResetCurveAllTempProp( pCrvCompo) ; // determino eventuali lati aperti e aggiorno proprietà del contorno int nInd = 0 ; double dPar ; bool bFound = vPL[k].GetFirstU( dPar, true) ; while ( bFound) { // recupero il flag int nFlag = int( dPar) ; // se non c'è nulla di adiacente, lato aperto if ( nFlag == SVT_NULL) pCrvCompo->SetCurveTempProp( nInd, 1) ; // altrimenti verifico se la faccia adiacente forma diedro convesso o concavo else { bool bAdjac ; Point3d ptP1, ptP2 ; double dAng ; if ( ! pSurf->GetFacetsContact( nFacet, nFlag, bAdjac, ptP1, ptP2, dAng)) dAng = - ANG_RIGHT ; if ( dAng > - EPS_ANG_SMALL) pCrvCompo->SetCurveTempProp( nInd, 1) ; } // passo al successivo ++ nInd ; bFound = vPL[k].GetNextU( dPar, true) ; } // recupero la normale esterna della faccia Vector3d vtN ; if ( ! pSurf->GetFacetNormal( nFacet, vtN)) return false ; // assegno l'estrusione dalla normale alla faccia pCrvCompo->SetExtrusion( vtN) ; // unisco le eventuali parti allineate pCrvCompo->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL) ; // la porto in globale pCrvCompo->ToGlob( frGlob) ; // sistemazioni varie AdjustCurveFromSurf( pCrvCompo, TOOL_ORTHO, FACE_CONT, 0) ; for( size_t i = 0 ; i < pCrvCompo->GetCurveCount() ; i++){ int val ; pCrvCompo->GetCurveTempProp( i, val) ; } // la restituisco lstPC.emplace_back( Release( pCrvCompo)) ; } return true ; } // se altrimenti regione else if ( pGObj->GetType() == SRF_FLATRGN) { // recupero la regione const ISurfFlatRegion* pReg = ::GetSurfFlatRegion( pGObj) ; if ( pReg == nullptr) return false ; // recupero la normale della regione Vector3d vtN = pReg->GetNormVersor() ; if ( vtN.IsSmall()) return false ; // determino intervallo di chunk int nCstart = 0 ; int nCend = pReg->GetChunkCount() ; // if ( Id.nSub != SEL_SUB_ALL) { // nCstart = Id.nSub ; // nCend = nCstart + 1 ; // } // ciclo sui chunk for ( int nC = nCstart ; nC < nCend ; ++ nC) { // recupero i contorni del chunk for ( int nL = 0 ; nL < pReg->GetLoopCount( nC) ; ++ nL) { PtrOwner pCrvCompo( CreateCurveComposite()) ; if ( IsNull( pCrvCompo) || ! pCrvCompo->AddCurve( pReg->GetLoop( nC, nL))) return false ; // reset proprietà temporanee ResetCurveAllTempProp( pCrvCompo) ; // assegno l'estrusione dalla normale alla regione pCrvCompo->SetExtrusion( vtN) ; // unisco le eventuali parti allineate pCrvCompo->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL) ; // la porto in globale pCrvCompo->ToGlob( frGlob) ; // sistemazioni varie AdjustCurveFromSurf( pCrvCompo, TOOL_ORTHO, FACE_CONT, 0) ; // la restituisco lstPC.emplace_back( Release( pCrvCompo)) ; } } return true ; } // altrimenti errore else return false ; } //---------------------------------------------------------------------------- bool Pocketing::SetCurveAllTempProp( int nCrvId, ICurve* pCurve) { if ( pCurve == nullptr) return false ; // reset proprietà temporanee ResetCurveAllTempProp( pCurve) ; // verifico se presenti info per lati aperti if ( ! m_pGeomDB->ExistsInfo( nCrvId, KEY_OPEN)) return true ; // recupero info sui lati aperti INTVECTOR vOpen ; m_pGeomDB->GetInfo( nCrvId, KEY_OPEN, vOpen) ; // se curva composita ICurveComposite* pCC = GetCurveComposite( pCurve) ; if ( pCC != nullptr) { for ( int j : vOpen) pCC->SetCurveTempProp( j, 1) ; } // altrimenti else { if ( ! vOpen.empty() && vOpen[0] == 0) pCurve->SetTempProp( 1) ; } return true ; } //---------------------------------------------------------------------------- bool Pocketing::ResetCurveAllTempProp( ICurve* pCurve) { if ( pCurve == nullptr) return false ; pCurve->SetTempProp( 0) ; ICurveComposite* pCC = GetCurveComposite( pCurve) ; if ( pCC != nullptr) { for ( int i = 0 ; i < pCC->GetCurveCount() ; ++ i) pCC->SetCurveTempProp( i, 0) ; } return true ; } //---------------------------------------------------------------------------- bool Pocketing::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 Pocketing : Skipped entity " + ToString( Id) ; m_pMchMgr->SetWarning( 2451, 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, true)) return false ; // recupero eventuali lati aperti INTVECTOR vOpen ; for ( int i = 0 ; i < int( pCrvCompo->GetCurveCount()) ; ++ i) { int nProp = 0 ; if ( pCrvCompo->GetCurveTempProp( i, nProp) && nProp == 1) vOpen.emplace_back( i) ; } // 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)) ; string s ; m_pGeomDB->GetName(nPathId, s) ; 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 ; // salvo info con eventuali lati aperti if ( ! vOpen.empty()) m_pGeomDB->SetInfo( nNewId, KEY_OPEN, vOpen) ; } return true ; } //---------------------------------------------------------------------------- bool Pocketing::ProcessPath2( int nPathId, int nPvId, int 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) ; // analizzo tutti i path nel gruppo aux int nAuxId = m_pGeomDB->GetFirstNameInGroup( m_nOwnerId, MCH_AUX) ; int nPId = m_pGeomDB->GetFirstInGroup( nAuxId) ; if ( nPId == GDB_ID_NULL) return false ; // Costruisco la flat region definita dalle curve selezionate // cerco la curva che definisce il loop esterno della superficie e verifico che le altre curve siano contenute al suo interno std::vector< std::pair> vIdxArea ; // vettore di coppie indice curva, area while ( nPId != GDB_ID_NULL) { int nCrvId = m_pGeomDB->GetFirstInGroup( nPId) ; if ( m_pGeomDB->GetGeoType( nCrvId) != CRV_COMPO) return false ; ICurve* pCrv = ::GetCurve( m_pGeomDB->GetGeoObj( nCrvId)) ; if ( pCrv == nullptr) return false ; Plane3d plPlane ; double dArea ; if ( ! pCrv->GetArea( plPlane, dArea)) return false ; vIdxArea.emplace_back( nCrvId, dArea) ; // passo al path succesivo nPId = m_pGeomDB->GetNextGroup( nPId) ; } // ordino in senso decrescente sull'area sort( vIdxArea.begin(), vIdxArea.end(), []( const std::pair& a, const std::pair& b) { return ( abs( a.second) > abs( b.second)) ; }) ; // identifico il loop esterno come il loop di area maggiore const ICurveComposite * pCompoExtTmp = GetCurveComposite( m_pGeomDB->GetGeoObj( vIdxArea[0].first)) ; ISurfFlatRegion * pSrfTmp = CreateSurfFlatRegion() ; if ( pSrfTmp == nullptr || ! pSrfTmp->AddExtLoop( pCompoExtTmp->Clone())) return false ; // verifico che contenga tutte le altre curve che rappresentano i loop interni for ( auto it = vIdxArea.begin() + 1 ; it != vIdxArea.end() ; it ++ ) { CRVCVECTOR ccClass ; ICurve * pCrv = ::GetCurve( m_pGeomDB->GetGeoObj( it->first)) ; if ( ! pSrfTmp->GetCurveClassification( *pCrv, ccClass)) return false ; // se una curva non � completamente contenuta la ignoro if ( ccClass.size() != 1 || ccClass[0].nClass != CRVC_IN) { m_pMchMgr->SetWarning( 2413, "Warining in Pocketing : curve " + to_string( it->first) + " is ignored") ; it = vIdxArea.erase( it) ; it -- ; } } Vector3d vtExtr = Z_AX ; double dThick = 0.0 ; double dRbDist ; double dElev ; double dDepth ; Vector3d vtTool ; BBox3d b3Raw ; INTVECTOR vCopyIds ; // analizzo tutti i path for( size_t i = 0 ; i < vIdxArea.size() ; i++ ) { int nCrvId = vIdxArea[i].first ; ICurve* pCrv = ::GetCurve( m_pGeomDB->GetGeoObj( nCrvId)) ; // verifico sia una curva chiusa (deve delimitare l'area da svuotare) if ( pCrv == nullptr || ! pCrv->IsClosed()) { m_pMchMgr->SetLastError( 2402, "Error in Pocketing : 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 ; vCopyIds.push_back( nCopyId) ; ICurveComposite* pCompo = GetCurveComposite( m_pGeomDB->GetGeoObj( nCopyId)) ; // aggiorno flag per lati aperti bool bSomeOpen = m_pGeomDB->ExistsInfo( nCrvId, KEY_OPEN) ; if ( bSomeOpen) { for ( int i = 0 ; i < int( pCompo->GetCurveCount()) ; ++ i) pCompo->SetCurveTempProp( i, 0) ; INTVECTOR vOpen ; m_pGeomDB->GetInfo( nCrvId, KEY_OPEN, vOpen) ; for ( int j : vOpen) pCompo->SetCurveTempProp( j, 1) ; } // recupero estrusione e spessore Vector3d vtExtrCrv = Z_AX ; double dThickCrv ; pCompo->GetExtrusion( vtExtrCrv) ; pCompo->GetThickness( dThickCrv) ; // eventuale inversione direzione utensile if ( m_Params.m_bToolInvert) { vtExtrCrv.Invert() ; pCompo->SetExtrusion( vtExtrCrv) ; dThickCrv = - dThick ; pCompo->SetThickness( dThickCrv) ; } // verifico sia piana e se necessario la appiattisco PtrOwner pFlatCrv( FlattenCurve( *pCompo, 50 * EPS_SMALL, 50 * EPS_ANG_SMALL, FLTCRV_USE_EXTR)) ; if ( IsNull( pFlatCrv)) { Plane3d plPlane ; if ( ! pCompo->IsFlat( plPlane, true, 50 * EPS_SMALL)) m_pMchMgr->SetLastError( 2403, "Error in Pocketing : Contour Not Flat") ; else m_pMchMgr->SetLastError( 2404, "Error in Pocketing : Tool Not Perpendicular to Flat Area") ; return false ; } pFlatCrv->GetExtrusion( vtExtrCrv) ; pCompo->Clear() ; pCompo->AddCurve( Release( pFlatCrv)) ; pCompo->SetExtrusion( vtExtrCrv) ; pCompo->SetThickness( dThickCrv) ; LOG_ERROR( GetEMkLogger(), (" dThick " + to_string( dThickCrv)).c_str()) ; // Prendo come vtExtr e dThick di riferimento quelle della prima curva if ( i == 0) { vtExtr = vtExtrCrv ; dThick = dThickCrv ; // valuto l'espressione dell'affondamento ExeLuaSetGlobNumVar( "TH", abs( dThick)) ; string sMyDepth = m_Params.m_sDepth ; if ( ! ExeLuaEvalNumExpr( ToUpper( sMyDepth), &dDepth)) { m_pMchMgr->SetLastError( 2406, "Error in Pocketing : Depth not computable") ; return false ; } // se spessore positivo, lo sottraggo dal risultato if ( dThick > 0) dDepth -= dThick ; // sottraggo eventuale offset longitudinale dDepth -= GetOffsL() ; // assegno il versore fresa vtTool = vtExtr ; } else { if ( ! AreSameVectorApprox( vtExtr, vtExtrCrv)) return false ; if ( abs( dThick - dThickCrv ) > EPS_SMALL) return false ; } // unisco le parti allineate (tranne inizio-fine se chiusa) if ( ! pCompo->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL, false, true)) return false ; // recupero distanza da fondo dei grezzi interessati dal percorso double dRbDist2 = 0 ; if ( AreSameVectorApprox( vtExtr, Z_AX)) { if ( ! GetDistanceFromRawBottom( m_nPhase, nCopyId, m_TParams.m_dTDiam, dRbDist2)) return false ; } if ( i == 0) { dRbDist = dRbDist2 ; ExeLuaSetGlobNumVar( "RB", dRbDist) ; } else { if ( abs( dRbDist - dRbDist2 ) > EPS_SMALL) return false ; } // recupero il box del grezzo in globale if ( i == 0) { if ( ! GetRawGlobBox( m_nPhase, nPathId, 0.5 * m_TParams.m_dTDiam, b3Raw) || b3Raw.IsEmpty()) { m_pMchMgr->SetLastError( 2405, "Error in Pocketing : Empty RawBox") ; return false ; } } // calcolo l'elevazione massima double dElev2 ; if ( CalcRegionElevation( pCompo, vtTool, dDepth, 0.5 * m_TParams.m_dDiam, dElev2)) { if ( dElev2 < EPS_SMALL && AreSameVectorApprox( vtExtr, Z_AX)) { BBox3d b3Crv ; pCompo->GetLocalBBox( b3Crv) ; dElev2 = max( 0., b3Raw.GetMax().z - b3Crv.GetMin().z + min( 0., dThick) + dDepth) ; } } else return false ; if ( i == 0 ) dElev = dElev2 ; else { if ( abs( dElev - dElev2) > EPS_SMALL) return false ; } } // end while // // sistemo senso antiorario visto dalla direzione di estrusione per curva pi� esterna ICurveComposite * pCompoExt = GetCurveComposite( m_pGeomDB->GetGeoObj( vCopyIds[0])) ; Plane3d plPlane ; double dArea ; pCompoExt->GetArea( plPlane, dArea) ; if ( plPlane.GetVersN() * vtExtr * dArea < 0) { pCompoExt->Invert() ; } // gestione lati aperti per la curva pi� esterna bool bMidOpen = false ; Point3d ptMidOpen ; Vector3d vtMidOut ; bool bSomeOpen = m_pGeomDB->ExistsInfo( vCopyIds[0], KEY_OPEN) ; if ( bSomeOpen) { // ricerca del punto medio del lato aperto pi� lungo bMidOpen = GetMidOfLongestOpenSide( pCompoExt, ptMidOpen, vtMidOut) ; // sistemazioni per eventuali lati aperti if ( ! AdjustContourWithOpenEdges( pCompoExt)) { m_pMchMgr->SetLastError( 2430, "Error in Pocketing : adjust open edges failed") ; return false ; } } // sposto l'inizio a met� del tratto pi� lungo ( o aperto pi� lungo) if ( bMidOpen) { const double LEN_OUT = 5 ; double dPar ; int nFlag ; bMidOpen = ( DistPointCurve( ptMidOpen + LEN_OUT * vtMidOut, *pCompoExt).GetParamAtMinDistPoint( 0, dPar, nFlag) && pCompoExt->ChangeStartPoint( dPar)) ; } if ( ! bMidOpen) AdjustContourStart( pCompoExt) ; Point3d ptStart ; pCompoExt->GetStartPoint( ptStart) ; // if ( m_Params.m_bToolInvert) { // vtExtrCrv.Invert() ; // pCompo->SetExtrusion( vtExtrCrv) ; // dThickCrv = - dThick ; // pCompo->SetThickness( dThickCrv) ; // } // recupero nome del path string sPathName ; m_pGeomDB->GetName( nPathId, sPathName) ; // eventuale imposizione massima elevazione da note utente double dMaxElev ; if ( FromString( ExtractInfo( m_Params.m_sUserNotes, "MaxElev="), dMaxElev) && dElev > dMaxElev) dElev = dMaxElev ; // verifico che lo step dell'utensile sia sensato double dOkStep = ( m_Params.m_dStep > EPS_SMALL ? m_Params.m_dStep + EPS_SMALL : 0) ; const double MIN_ZSTEP = 1.0 ; if ( dOkStep >= EPS_SMALL && dOkStep < MIN_ZSTEP) { dOkStep = MIN_ZSTEP + EPS_SMALL ; string sInfo = "Warning in Pocketing : machining step too small (" + ToString( m_Params.m_dStep, 2) + ")" ; m_pMchMgr->SetWarning( 2456, sInfo) ; } // verifico che il massimo materiale dell'utensile sia sensato const double MIN_MAXMAT = 1.0 ; if ( m_TParams.m_dMaxMat < dElev && m_TParams.m_dMaxMat < MIN_MAXMAT) { string sInfo = "Error in Pocketing : Tool MaxMaterial too small (" + ToString( m_TParams.m_dMaxMat, 2) + ")" ; m_pMchMgr->SetLastError( 2422, sInfo) ; return false ; } // verifico di non superare il massimo materiale // se lo step supera la capacit� dell'utensile if ( m_Params.m_dStep > m_TParams.m_dMaxMat + EPS_SMALL) { dOkStep = m_TParams.m_dMaxMat + EPS_SMALL ; string sInfo = "Warning in Pocketing : machining step (" + ToString( m_Params.m_dStep, 1) + ") bigger than MaxMaterial (" + ToString( m_TParams.m_dMaxMat, 1) + ")" ; m_pMchMgr->SetWarning( 2457, sInfo) ; } // se lavorazione singola if ( dOkStep < EPS_SMALL || dOkStep > dElev) { // se l'elevazione supera la capacit� dell'utensile if ( dElev > m_TParams.m_dMaxMat + EPS_SMALL) { string sInfo = "Warning in Pocketing : machining depth (" + ToString( dElev, 1) + ") bigger than MaxMaterial (" + ToString( m_TParams.m_dMaxMat, 1) + ")" ; m_pMchMgr->SetWarning( 2458, sInfo) ; dDepth -= dElev - m_TParams.m_dMaxMat ; dElev = m_TParams.m_dMaxMat ; } } // altrimenti lavorazione a step else { // se l'elevazione supera il massimo affondamento dell'utensile double dSafe = m_pMchMgr->GetCurrMachiningsMgr()->GetMaxDepthSafe() ; double dMaxDepth = m_TParams.m_dLen - ( m_TParams.m_dDiam > m_dTHoldDiam ? 0 : m_dTHoldLen) - dSafe ; if ( dElev > dMaxDepth + EPS_SMALL) { // segnalo, riduco e continuo string sInfo = "Warning in Pocketing : machining depth (" + ToString( dElev, 1) + ") bigger than MaxDepth (" + ToString( dMaxDepth, 1) + ")" ; m_pMchMgr->SetWarning( 2458, sInfo) ; dDepth -= dElev - dMaxDepth ; dElev = dMaxDepth ; } } // verifico se tavola basculante bool bTiltTab = false ; m_bTiltingTab = ( m_pMchMgr->GetCurrMachine()->GetCurrTableIsTilting( bTiltTab) && bTiltTab) ; // verifico se testa da sopra (Z+) m_bAboveHead = m_pMchMgr->GetHeadAbove( m_TParams.m_sHead) ; // verifiche per svuotature dal basso m_bAggrBottom = false ; if ( ! VerifyPathFromBottom( pCompoExt, vtTool)) { return false ; } // // se richiesta anteprima // if ( nPvId != GDB_ID_NULL) { // // creo gruppo per geometria di lavorazione del percorso // int nPxId = m_pGeomDB->AddGroup( GDB_ID_NULL, nPvId, Frame3d()) ; // if ( nPxId == GDB_ID_NULL) // return false ; // m_pGeomDB->SetName( nPxId, sPathName) ; // m_pGeomDB->SetMaterial( nPxId, GREEN) ; // // creo l'anteprima del percorso // if ( ! GeneratePocketingPv( nPxId, pCompo)) // return false ; // } // 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 int nSplitArcs = m_pMchMgr->GetCurrMachiningsMgr()->GetSplitArcs() ; bool bSplitArcs = ( nSplitArcs == SPLAR_ALWAYS || ( nSplitArcs == SPLAR_NO_XY_PLANE && ! vtExtr.IsZplus()) || ( nSplitArcs == SPLAR_GEN_PLANE && vtExtr.IsGeneric())) ; // assegno il vettore estrazione al gruppo del percorso m_pGeomDB->SetInfo( nPxId, KEY_EXTR, vtTool) ; // assegno i punti di inizio e fine al gruppo del percorso m_pGeomDB->SetInfo( nPxId, KEY_START, ptStart) ; m_pGeomDB->SetInfo( nPxId, KEY_END, ptStart) ; // assegno l'elevazione massima m_pGeomDB->SetInfo( nPxId, KEY_ELEV, dElev) ; // Imposto dati comuni SetPathId( nPxId) ; SetToolDir( vtTool) ; // Creo una SurfFlatRegion a partire dalle curve in Temp int pnCount ; int nSrfId = ExeCreateSurfFlatRegion( nTempId, vCopyIds, &pnCount) ; if ( nSrfId == GDB_ID_NULL) return false ; ISurfFlatRegion * pSrf = GetSurfFlatRegion( m_pGeomDB->GetGeoObj( nSrfId)) ; if ( pSrf == nullptr) return false ; // Eseguo la lavorazione a seconda del tipo switch ( m_Params.m_nSubType) { case POCKET_SUB_ZIGZAG : if ( ! AddZigZag( pSrf, vtTool, vtExtr, dDepth, dElev, dOkStep, bSplitArcs)) return false ; break ; case POCKET_SUB_ONEWAY : if ( ! AddOneWay( pSrf, vtTool, vtExtr, dDepth, dElev, dOkStep, bSplitArcs)) return false ; break ; case POCKET_SUB_SPIRALIN : if ( ! AddSpiralIn( pSrf, vtTool, vtExtr, dDepth, dElev, dOkStep, bSplitArcs, bMidOpen, ptMidOpen, vtMidOut)) return false ; break ; case POCKET_SUB_SPIRALOUT : if ( ! AddSpiralOut( pSrf, vtTool, vtExtr, dDepth, dElev, dOkStep, bSplitArcs)) return false ; break ; } } // incremento numero di svuotature ++ m_nPockets ; return true ; } //---------------------------------------------------------------------------- bool Pocketing::ProcessPath( int nPathId, int nPvId, int 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) ; // 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( 2402, "Error in Pocketing : 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)) ; // aggiorno flag per lati aperti bool bSomeOpen = m_pGeomDB->ExistsInfo( nCrvId, KEY_OPEN) ; if ( bSomeOpen) { for ( int i = 0 ; i < int( pCompo->GetCurveCount()) ; ++ i) pCompo->SetCurveTempProp( i, 0) ; INTVECTOR vOpen ; m_pGeomDB->GetInfo( nCrvId, KEY_OPEN, vOpen) ; for ( int j : vOpen) pCompo->SetCurveTempProp( j, 1) ; } // recupero estrusione e spessore Vector3d vtExtr = Z_AX ; pCompo->GetExtrusion( vtExtr) ; double dThick ; pCompo->GetThickness( dThick) ; // eventuale inversione direzione utensile if ( m_Params.m_bToolInvert) { vtExtr.Invert() ; pCompo->SetExtrusion( vtExtr) ; dThick = - dThick ; pCompo->SetThickness( dThick) ; } // verifico sia piana e se necessario la appiattisco PtrOwner pFlatCrv( FlattenCurve( *pCompo, 50 * EPS_SMALL, 50 * EPS_ANG_SMALL, FLTCRV_USE_EXTR)) ; if ( IsNull( pFlatCrv)) { Plane3d plPlane ; if ( ! pCompo->IsFlat( plPlane, true, 50 * EPS_SMALL)) m_pMchMgr->SetLastError( 2403, "Error in Pocketing : Contour Not Flat") ; else m_pMchMgr->SetLastError( 2404, "Error in Pocketing : Tool Not Perpendicular to Flat Area") ; return false ; } pFlatCrv->GetExtrusion( vtExtr) ; pCompo->Clear() ; pCompo->AddCurve( Release( pFlatCrv)) ; pCompo->SetExtrusion( vtExtr) ; pCompo->SetThickness( dThick) ; // sistemo senso antiorario visto dalla direzione di estrusione Plane3d plPlane ; double dArea ; pCompo->GetArea( plPlane, dArea) ; if ( plPlane.GetVersN() * vtExtr * dArea < 0) pCompo->Invert() ; // unisco le parti allineate (tranne inizio-fine se chiusa) if ( ! pCompo->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL, false, true)) return false ; // se ci sono lati aperti bool bMidOpen = false ; Point3d ptMidOpen ; Vector3d vtMidOut ; if ( bSomeOpen) { // ricerca del punto medio del lato aperto pi� lungo bMidOpen = GetMidOfLongestOpenSide( pCompo, ptMidOpen, vtMidOut) ; // sistemazioni per eventuali lati aperti if ( ! AdjustContourWithOpenEdges( pCompo)) { m_pMchMgr->SetLastError( 2430, "Error in Pocketing : adjust open edges failed") ; return false ; } } // sposto l'inizio a met� del tratto pi� lungo ( o aperto pi� lungo) if ( bMidOpen) { const double LEN_OUT = 5 ; double dPar ; int nFlag ; bMidOpen = ( DistPointCurve( ptMidOpen + LEN_OUT * vtMidOut, *pCompo).GetParamAtMinDistPoint( 0, dPar, nFlag) && pCompo->ChangeStartPoint( dPar)) ; } if ( ! bMidOpen) AdjustContourStart( pCompo) ; // recupero il punto di inizio (per poi salvarlo nelle info di CL path) Point3d ptStart ; pCompo->GetStartPoint( ptStart) ; // 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( 2405, "Error in Pocketing : Empty RawBox") ; return false ; } // recupero distanza da fondo dei grezzi interessati dal percorso double dRbDist = 0 ; if ( AreSameVectorApprox( vtExtr, Z_AX)) { if ( ! GetDistanceFromRawBottom( m_nPhase, nCopyId, m_TParams.m_dTDiam, dRbDist)) return false ; } // valuto l'espressione dell'affondamento ExeLuaSetGlobNumVar( "TH", abs( dThick)) ; ExeLuaSetGlobNumVar( "RB", dRbDist) ; double dDepth ; string sMyDepth = m_Params.m_sDepth ; if ( ! ExeLuaEvalNumExpr( ToUpper( sMyDepth), &dDepth)) { m_pMchMgr->SetLastError( 2406, "Error in Pocketing : Depth not computable") ; return false ; } // se spessore positivo, lo sottraggo dal risultato if ( dThick > 0) dDepth -= dThick ; // sottraggo eventuale offset longitudinale dDepth -= GetOffsL() ; // recupero nome del path string sPathName ; m_pGeomDB->GetName( nPathId, sPathName) ; // assegno il versore fresa Vector3d vtTool = vtExtr ; // calcolo l'elevazione massima double dElev ; if ( CalcRegionElevation( pCompo, vtTool, dDepth, 0.5 * m_TParams.m_dDiam, dElev)) { if ( dElev < EPS_SMALL && AreSameVectorApprox( vtExtr, Z_AX)) { BBox3d b3Crv ; pCompo->GetLocalBBox( b3Crv) ; dElev = max( 0., b3Raw.GetMax().z - b3Crv.GetMin().z + min( 0., dThick) + dDepth) ; } } else return false ; // eventuale imposizione massima elevazione da note utente double dMaxElev ; if ( FromString( ExtractInfo( m_Params.m_sUserNotes, "MaxElev="), dMaxElev) && dElev > dMaxElev) dElev = dMaxElev ; // verifico che lo step dell'utensile sia sensato double dOkStep = ( m_Params.m_dStep > EPS_SMALL ? m_Params.m_dStep + EPS_SMALL : 0) ; const double MIN_ZSTEP = 1.0 ; if ( dOkStep >= EPS_SMALL && dOkStep < MIN_ZSTEP) { dOkStep = MIN_ZSTEP + EPS_SMALL ; string sInfo = "Warning in Pocketing : machining step too small (" + ToString( m_Params.m_dStep, 2) + ")" ; m_pMchMgr->SetWarning( 2456, sInfo) ; } // verifico che il massimo materiale dell'utensile sia sensato const double MIN_MAXMAT = 1.0 ; if ( m_TParams.m_dMaxMat < dElev && m_TParams.m_dMaxMat < MIN_MAXMAT) { string sInfo = "Error in Pocketing : Tool MaxMaterial too small (" + ToString( m_TParams.m_dMaxMat, 2) + ")" ; m_pMchMgr->SetLastError( 2422, sInfo) ; return false ; } // verifico di non superare il massimo materiale // se lo step supera la capacit� dell'utensile if ( m_Params.m_dStep > m_TParams.m_dMaxMat + EPS_SMALL) { dOkStep = m_TParams.m_dMaxMat + EPS_SMALL ; string sInfo = "Warning in Pocketing : machining step (" + ToString( m_Params.m_dStep, 1) + ") bigger than MaxMaterial (" + ToString( m_TParams.m_dMaxMat, 1) + ")" ; m_pMchMgr->SetWarning( 2457, sInfo) ; } // se lavorazione singola if ( dOkStep < EPS_SMALL || dOkStep > dElev) { // se l'elevazione supera la capacit� dell'utensile if ( dElev > m_TParams.m_dMaxMat + EPS_SMALL) { string sInfo = "Warning in Pocketing : machining depth (" + ToString( dElev, 1) + ") bigger than MaxMaterial (" + ToString( m_TParams.m_dMaxMat, 1) + ")" ; m_pMchMgr->SetWarning( 2458, sInfo) ; dDepth -= dElev - m_TParams.m_dMaxMat ; dElev = m_TParams.m_dMaxMat ; } } // altrimenti lavorazione a step else { // se l'elevazione supera il massimo affondamento dell'utensile double dSafe = m_pMchMgr->GetCurrMachiningsMgr()->GetMaxDepthSafe() ; double dMaxDepth = m_TParams.m_dLen - ( m_TParams.m_dDiam > m_dTHoldDiam ? 0 : m_dTHoldLen) - dSafe ; if ( dElev > dMaxDepth + EPS_SMALL) { // segnalo, riduco e continuo string sInfo = "Warning in Pocketing : machining depth (" + ToString( dElev, 1) + ") bigger than MaxDepth (" + ToString( dMaxDepth, 1) + ")" ; m_pMchMgr->SetWarning( 2458, sInfo) ; dDepth -= dElev - dMaxDepth ; dElev = dMaxDepth ; } } // verifico se tavola basculante bool bTiltTab = false ; m_bTiltingTab = ( m_pMchMgr->GetCurrMachine()->GetCurrTableIsTilting( bTiltTab) && bTiltTab) ; // verifico se testa da sopra (Z+) m_bAboveHead = m_pMchMgr->GetHeadAbove( m_TParams.m_sHead) ; // verifiche per svuotature dal basso m_bAggrBottom = false ; if ( ! VerifyPathFromBottom( pCompo, vtTool)) { return false ; } // se richiesta anteprima if ( nPvId != GDB_ID_NULL) { // creo gruppo per geometria di lavorazione del percorso int nPxId = m_pGeomDB->AddGroup( GDB_ID_NULL, nPvId, Frame3d()) ; if ( nPxId == GDB_ID_NULL) return false ; m_pGeomDB->SetName( nPxId, sPathName) ; m_pGeomDB->SetMaterial( nPxId, GREEN) ; // creo l'anteprima del percorso if ( ! GeneratePocketingPv( nPxId, pCompo)) return false ; } // 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 int nSplitArcs = m_pMchMgr->GetCurrMachiningsMgr()->GetSplitArcs() ; bool bSplitArcs = ( nSplitArcs == SPLAR_ALWAYS || ( nSplitArcs == SPLAR_NO_XY_PLANE && ! vtExtr.IsZplus()) || ( nSplitArcs == SPLAR_GEN_PLANE && vtExtr.IsGeneric())) ; // assegno il vettore estrazione al gruppo del percorso m_pGeomDB->SetInfo( nPxId, KEY_EXTR, vtTool) ; // assegno i punti di inizio e fine al gruppo del percorso m_pGeomDB->SetInfo( nPxId, KEY_START, ptStart) ; m_pGeomDB->SetInfo( nPxId, KEY_END, ptStart) ; // assegno l'elevazione massima m_pGeomDB->SetInfo( nPxId, KEY_ELEV, dElev) ; // Imposto dati comuni SetPathId( nPxId) ; SetToolDir( vtTool) ; LOG_ERROR( GetEMkLogger(), (" dRibdist " + to_string( dRbDist) + " dElev " + to_string( dElev)).c_str()) ; // Creo una SurfFlatRegion a partire dalle curve in Temp int nAuxId = m_pGeomDB->GetFirstNameInGroup( m_nOwnerId, MCH_AUX) ; int nPId = m_pGeomDB->GetFirstInGroup( nAuxId) ; INTVECTOR vCopyIds ; while ( nPId != GDB_ID_NULL) { vCopyIds.push_back( m_pGeomDB->CopyGlob( nPId + 1, GDB_ID_NULL, nTempId)) ; nPId = m_pGeomDB->GetNextGroup( nPId) ; } DBLVECTOR vArea ; for ( size_t i = 0 ; i < vCopyIds.size() ; i++) { Plane3d plPlane ; double dArea ; ICurveComposite * pCmp = GetCurveComposite( m_pGeomDB->GetGeoObj( vCopyIds[i])) ; if ( ! pCmp->GetArea( plPlane, dArea)) return false ; vArea.emplace_back( dArea) ; } DBLVECTOR::iterator it = max_element( vArea.begin(), vArea.end()) ; size_t idx = it - vArea.begin() ; ICurveComposite * pCmp = GetCurveComposite( m_pGeomDB->GetGeoObj( vCopyIds[idx])) ; Plane3d plPlane ; double dArea ; pCmp->GetArea( plPlane, dArea) ; if ( plPlane.GetVersN() * vtExtr * dArea < 0) { pCmp->Invert() ; } int pnCount ; int nSrfId = ExeCreateSurfFlatRegion( nTempId, vCopyIds, &pnCount) ; ISurfFlatRegion * pSrf = GetSurfFlatRegion( m_pGeomDB->GetGeoObj( nSrfId)) ; // Eseguo la lavorazione a seconda del tipo switch ( m_Params.m_nSubType) { case POCKET_SUB_ZIGZAG : if ( ! AddZigZag( pSrf, vtTool, vtExtr, dDepth, dElev, dOkStep, bSplitArcs)) return false ; break ; case POCKET_SUB_ONEWAY : if ( ! AddOneWay( pSrf, vtTool, vtExtr, dDepth, dElev, dOkStep, bSplitArcs)) return false ; break ; case POCKET_SUB_SPIRALIN : if ( ! AddSpiralIn( pSrf, vtTool, vtExtr, dDepth, dElev, dOkStep, bSplitArcs, bMidOpen, ptMidOpen, vtMidOut)) return false ; break ; case POCKET_SUB_SPIRALOUT : if ( ! AddSpiralOut( pSrf, vtTool, vtExtr, dDepth, dElev, dOkStep, bSplitArcs)) return false ; break ; } } // incremento numero di svuotature ++ m_nPockets ; return true ; } //---------------------------------------------------------------------------- bool Pocketing::CalcRegionElevation( const ICurveComposite* pCompo, const Vector3d& vtTool, double dDepth, double dRad, double& dElev) const { // inizializzo l'elevazione dElev = 0 ; // affondamento come vettore Vector3d vtDepth = vtTool * dDepth ; // Campiono il contorno int nMaxInd = pCompo->GetCurveCount() - 1 ; for ( int i = 0 ; i <= nMaxInd ; ++ i) { // curva corrente const ICurve* pCrvC = pCompo->GetCurve( i) ; Point3d ptStart ; pCrvC->GetStartPoint( ptStart) ; Point3d ptMid ; pCrvC->GetMidPoint( ptMid) ; Point3d ptEnd ; pCrvC->GetEndPoint( ptEnd) ; // elevazione della curva double dCurrElev ; if ( GetElevation( m_nPhase, ptStart - vtDepth, ptMid - vtDepth, ptEnd - vtDepth, vtTool, dCurrElev)) { if ( dCurrElev > dElev) dElev = dCurrElev ; } else { m_pMchMgr->SetLastError( 2408, "Error in Pocketing : Entity GetElevation") ; return false ; } } // Campiono l'interno con una griglia (uso linee parallele a X) // determino il riferimento di base Frame3d frPocket ; Point3d ptCen ; pCompo->GetCentroid( ptCen) ; frPocket.Set( ptCen, vtTool) ; // copio il contorno e lo porto nel riferimento PtrOwner pCompoL( pCompo->Clone()) ; if ( IsNull( pCompoL) || ! pCompoL->ToLoc( frPocket)) { m_pMchMgr->SetLastError( 2408, "Error in Pocketing : Entity GetElevation") ; return false ; } // ingombro del contorno in locale BBox3d b3Pocket ; pCompoL->GetLocalBBox( b3Pocket) ; Point3d ptMin ; double dDimX, dDimY, dDimZ ; b3Pocket.GetMinDim( ptMin, dDimX, dDimY, dDimZ) ; // passi in Y const double STEP = 50 ; int nYStep = max( int( ceil( ( dDimY - 20 * EPS_SMALL) / STEP)), 2) ; double dYStep = ( nYStep > 0 ? ( dDimY - 20 * EPS_SMALL) / nYStep : 0) ; // calcolo le linee di svuotatura int nCount = 0 ; for ( int i = 1 ; i < nYStep ; ++ i) { // definisco la linea PtrOwner pLine( CreateCurveLine()) ; const double EXP_LEN = 1.0 ; Point3d ptStart( ptMin.x - EXP_LEN, ptMin.y + 10 * EPS_SMALL + i * dYStep, ptMin.z + dDimZ) ; if ( IsNull( pLine) || ! pLine->SetPVL( ptStart, X_AX, dDimX + 2 * EXP_LEN)) { m_pMchMgr->SetLastError( 2408, "Error in Pocketing : Entity GetElevation") ; return false ; } // calcolo la classificazione della curva rispetto al contorno IntersCurveCurve intCC( *pLine, *pCompoL) ; CRVCVECTOR ccClass ; if ( intCC.GetCurveClassification( 0, ccClass)) { // determino gli intervalli di curva interni Intervals inOk ; for ( auto& ccOne : ccClass) { if ( ccOne.nClass == CRVC_IN) { Point3d ptStart ; pLine->GetPointD1D2( ccOne.dParS, ICurve::FROM_PLUS, ptStart) ; ptStart.ToGlob( frPocket) ; Point3d ptEnd ; pLine->GetPointD1D2( ccOne.dParE, ICurve::FROM_MINUS, ptEnd) ; ptEnd.ToGlob( frPocket) ; // elevazione della curva double dCurrElev ; if ( GetElevation( m_nPhase, ptStart - vtDepth, ptEnd - vtDepth, vtTool, dCurrElev)) { if ( dCurrElev > dElev) dElev = dCurrElev ; } else { m_pMchMgr->SetLastError( 2408, "Error in Pocketing : Entity GetElevation") ; return false ; } } } } // altrimenti uso tutta la curva else { Point3d ptStart ; pLine->GetStartPoint( ptStart) ; ptStart.ToGlob( frPocket) ; Point3d ptEnd ; pLine->GetEndPoint( ptEnd) ; ptEnd.ToGlob( frPocket) ; // elevazione della curva double dCurrElev ; if ( GetElevation( m_nPhase, ptStart - vtDepth, ptEnd - vtDepth, vtTool, dCurrElev)) { if ( dCurrElev > dElev) dElev = dCurrElev ; } else { m_pMchMgr->SetLastError( 2408, "Error in Pocketing : Entity GetElevation") ; return false ; } } } return true ; } //---------------------------------------------------------------------------- bool Pocketing::VerifyPathFromBottom( const ICurveComposite* pCompo, const Vector3d& vtTool) { // se non è svuotatura dal basso in alto, esco if ( vtTool.z > MIN_ZDIR_TOP_TOOL) return true ; // se c'è testa non dall'alto o tavola basculante, esco if ( ! m_bAboveHead || m_bTiltingTab) return true ; // recupero dati di eventuale rinvio da sotto if ( ! GetAggrBottomData( m_TParams.m_sHead, m_AggrBottom) || m_AggrBottom.nType == 0) { m_pMchMgr->SetLastError( 2409, "Error in Pocketing : missing aggregate from bottom") ; return false ; } // calcolo la massima distanza minima del percorso dal contorno del grezzo double dDist = 0 ; Vector3d vtDir ; int nMaxInd = pCompo->GetCurveCount() - 1 ; for ( int i = 0 ; i <= nMaxInd ; ++ i) { // curva corrente const ICurve* pCrvC = pCompo->GetCurve( i) ; // considero inizio della prima curva, punto medio e fine di tutte Point3d ptP ; double dCurrDist = 0 ; Vector3d vtCurrDir ; if ( i == 0) { pCrvC->GetStartPoint( ptP) ; GetMinDistanceFromRawSide( m_nPhase, ptP, 0, dCurrDist, vtCurrDir) ; if ( dCurrDist > dDist) { dDist = dCurrDist ; vtDir = vtCurrDir ; } } pCrvC->GetMidPoint( ptP) ; GetMinDistanceFromRawSide( m_nPhase, ptP, 0, dCurrDist, vtCurrDir) ; if ( dCurrDist > dDist) { dDist = dCurrDist ; vtDir = vtCurrDir ; } pCrvC->GetEndPoint( ptP) ; GetMinDistanceFromRawSide( m_nPhase, ptP, 0, dCurrDist, vtCurrDir) ; if ( dCurrDist > dDist) { dDist = dCurrDist ; vtDir = vtCurrDir ; } } // se supera il limite, errore if ( dDist > m_AggrBottom.dDMax) { m_pMchMgr->SetLastError( 2410, "Error in Pocketing : path too far from part sides") ; return false ; } // assegno direzione di accesso e segnalo utilizzo aggregato da sotto m_vtAggrBottom = vtDir ; m_bAggrBottom = true ; return true ; } //---------------------------------------------------------------------------- bool Pocketing::GeneratePocketingPv( int nPathId, const ICurveComposite* pCompo) { // creo copia della curva composita PtrOwner< ICurve> pCrv( pCompo->Clone()) ; if ( IsNull( pCrv)) return false ; // calcolo la regione SurfFlatRegionByContours SfrCntrRr ; SfrCntrRr.AddCurve( Release( pCrv)) ; PtrOwner pSfr( SfrCntrRr.GetSurf()) ; if ( IsNull( pSfr)) return false ; // ne recupero il contorno PtrOwner< ICurve> pCrv2 ; pCrv2.Set( pSfr->GetLoop( 0, 0)) ; if ( IsNull( pCrv2)) return false ; // inserisco la curva nel DB int nC2Id = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nPathId, Release( pCrv2)) ; if ( nC2Id == GDB_ID_NULL) return false ; // assegno nome e colore m_pGeomDB->SetName( nC2Id, MCH_PV_CUT) ; m_pGeomDB->SetMaterial( nC2Id, RED) ; // eventuali altri contorni ( interni di contornatura chiusa) const int MAX_INT_LOOP = 1000 ; for ( int i = 1 ; i <= MAX_INT_LOOP ; ++i) { PtrOwner< ICurve> pCrv3 ; pCrv3.Set( pSfr->GetLoop( 0, i)) ; if ( IsNull( pCrv3)) break ; // inserisco la curva nel DB int nC3Id = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nPathId, Release( pCrv3)) ; if ( nC3Id == GDB_ID_NULL) return false ; // assegno nome e colore m_pGeomDB->SetName( nC3Id, MCH_PV_CUT) ; m_pGeomDB->SetMaterial( nC3Id, RED) ; } // inserisco la regione nel DB int nRId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nPathId, Release( pSfr)) ; if ( nRId == GDB_ID_NULL) return false ; m_pGeomDB->SetName( nRId, MCH_PV_RCUT) ; m_pGeomDB->SetMaterial( nRId, Color( 255, 0, 0, 60)) ; // la copio anche come regione ridotta int nRrId = m_pGeomDB->Copy( nRId, GDB_ID_NULL, nPathId) ; if ( nRrId == GDB_ID_NULL) return false ; m_pGeomDB->SetName( nRrId, MCH_PV_RRCUT) ; m_pGeomDB->SetMaterial( nRrId, INVISIBLE) ; return true ; } //---------------------------------------------------------------------------- static double GetCurveRadius( const ICurve* pCrv) { if ( pCrv == nullptr) return 0.0 ; BBox3d b3Loc ; if ( ! pCrv->GetLocalBBox( b3Loc, BBF_EXACT)) return 0.0 ; double dRad ; if ( ! b3Loc.GetRadius( dRad)) return 0.0 ; return dRad ; } //---------------------------------------------------------------------------- bool Pocketing::AddZigZag( const ISurfFlatRegion* pSrf, const Vector3d& vtTool, const Vector3d& vtExtr, double dDepth, double dElev, double dOkStep, bool bSplitArcs) { // recupero distanze di sicurezza double dSafeZ = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeZ() ; double dSafeAggrBottZ = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeAggrBottZ() ; // lunghezza di approccio/retrazione double dAppr = m_Params.m_dStartPos ; // se utensile che non lavora di testa poichè ingresso non fuori dal pezzo, errore if ( m_TParams.m_nType == TT_MILL_NOTIP) { if ( ! LeadInIsOk()) { m_pMchMgr->SetLastError( 2431, "Error in Pocketing : LeadIn with Mill NoTip in material") ; return false ; } } // determino numero e affondamento degli step int nStep = 1 ; nStep = max( 1, static_cast( ceil( dElev / dOkStep))) ; double dStep = dElev / nStep ; // calcolo superficie offsettata del raggio utensile + sovramateriale + (se non lucidatura) extra double dTRad = 0.5 * m_TParams.m_dDiam ; double dOffs = dTRad + GetOffsR() ; double dExtra = (( m_TParams.m_nType != TT_MILL_POLISHING) ? min( 0.1 * m_TParams.m_dDiam, 2.0) : 0) ; PtrOwner pSrfOff1( pSrf->Clone()) ; if ( IsNull( pSrfOff1)) { m_pMchMgr->SetLastError( 2412, "Error in Pocketing : Offset not computable") ; return false ; } if ( ! pSrfOff1->Offset( - ( dOffs + dExtra), ICurve::OFF_FILLET) || ! pSrfOff1->IsValid()) { m_pMchMgr->SetLastError( 2412, "Error in Pocketing : Offset not computable") ; return false ; } // ciclo sulle superfici risultanti bool bStart = true ; Point3d ptOld ; int nChunks = pSrfOff1->GetChunkCount() ; int nC = 0 ; while ( nC != nChunks) { // recupero la prima regione di offset PtrOwner pSrfChunk( pSrfOff1->CloneChunk( nC)) ; if ( IsNull( pSrfChunk)) return false ; // determino il riferimento di base e il box della svuotatura Frame3d frPocket ; Point3d ptCen ; pSrfChunk->GetChunkCentroid( 0, ptCen) ; frPocket.Set( ptCen, vtExtr) ; frPocket.Rotate( ptCen, vtExtr, m_Params.m_dSideAngle) ; pSrfChunk->ToLoc( frPocket) ; // calcolo i percorsi di svuotatura ICRVCOMPOPOVECTOR vpCrvs ; if ( ! CalcZigZag( pSrfChunk, vpCrvs)) return false ; // se richiesta inversione if ( m_Params.m_bInvert) { // ciclo sui percorsi for ( int k = 0 ; k < int( vpCrvs.size()) ; ++ k) vpCrvs[k]->Invert() ; } // se lucidatura if ( m_TParams.m_nType == TT_MILL_POLISHING) { // ciclo sui percorsi for ( int k = 0 ; k < int( vpCrvs.size()) ; ++ k) { // se attacco a scivolo if ( GetLeadInType() == POCKET_LI_GLIDE) { double dU ; vpCrvs[k]->GetParamAtLength( m_Params.m_dLiTang, dU) ; vpCrvs[k]->AddJoint( dU) ; Point3d ptStart ; vpCrvs[k]->GetStartPoint( ptStart) ; vpCrvs[k]->ModifyStart( ptStart + vtTool * m_Params.m_dLiElev) ; } // se uscita a scivolo if ( GetLeadOutType() == POCKET_LO_GLIDE) { double dLen, dU ; vpCrvs[k]->GetLength( dLen) ; vpCrvs[k]->GetParamAtLength( dLen - m_Params.m_dLoTang, dU) ; vpCrvs[k]->AddJoint( dU) ; Point3d ptEnd ; vpCrvs[k]->GetEndPoint( ptEnd) ; vpCrvs[k]->ModifyEnd( ptEnd + vtTool * m_Params.m_dLiElev) ; } } } // inserisco i movimenti di svuotatura for ( int j = 1 ; j <= nStep ; ++ j) { // ciclo sui percorsi for ( int k = 0 ; k < int( vpCrvs.size()) ; ++ k) { // ciclo sulle curve elementari int nMaxInd = vpCrvs[k]->GetCurveCount() - 1 ; for ( int i = 0 ; i <= nMaxInd ; ++ i) { // curva corrente const ICurve* pCrvC = vpCrvs[k]->GetCurve( i) ; // copio la curva PtrOwner pCurve( pCrvC->Clone()) ; if ( IsNull( pCurve)) return false ; pCurve->ToGlob( frPocket) ; // aggiungo affondamento pCurve->Translate( - vtTool * ( dDepth - dElev + j * dStep)) ; // se prima entità if ( i == 0 ) { // dati inizio entità Point3d ptStart ; pCurve->GetStartPoint( ptStart) ; Vector3d vtStart ; pCurve->GetStartDir( vtStart) ; // determino inizio attacco Point3d ptP1 ; if ( ! CalcLeadInStart( ptStart, vtStart, vtExtr, nullptr, ptP1)) return false ; // determino elevazione su inizio attacco double dStElev ; if ( ! GetElevation( m_nPhase, ptStart - 10 * EPS_SMALL * vtTool, vtTool, GetRadiusForStartEndElevation(), vtTool, dStElev)) dStElev = j * dStep ; bool bUnderRaw = GetPointUnderRaw( ptP1, vtTool, 0, GetRadiusForStartEndElevation(), m_TParams.m_dLen, false, dSafeZ, dStElev) ; if ( bUnderRaw == m_bAboveHead) dStElev = max( dStElev, j * dStep) ; dStElev -= ( ptP1 - ptStart) * vtExtr ; // se inizio, approccio globale al punto iniziale if ( bStart) { if ( ! AddApproach( ptP1, vtTool, dSafeZ, dSafeAggrBottZ, dStElev, dAppr, false)) { m_pMchMgr->SetLastError( 2414, "Error in Pocketing : Approach not computable") ; return false ; } bStart = false ; } // altrimenti, approccio di collegamento else { if ( ! AddLinkApproach( ptP1, vtTool, dSafeZ, dSafeAggrBottZ, dStElev, dAppr)) { m_pMchMgr->SetLastError( 2418, "Error in Pocketing : Link not computable") ; return false ; } } // aggiungo attacco SetFeed( GetStartFeed()) ; if ( ! AddLeadIn( ptP1, ptStart, vtStart, vtExtr, pSrf, nullptr, ! m_Params.m_bInvert, bSplitArcs, true)) { m_pMchMgr->SetLastError( 2415, "Error in Pocketing : LeadIn not computable") ; return false ; } } // elaborazioni sulla curva corrente if ( pCurve->GetType() == CRV_LINE) { ICurveLine* pLine = GetCurveLine( pCurve) ; Point3d ptP3 = pLine->GetEnd() ; SetFeed( GetFeed()) ; if ( AddLinearMove( ptP3) == GDB_ID_NULL) return false ; } else if ( pCurve->GetType() == CRV_ARC) { ICurveArc* pArc = GetCurveArc( pCurve) ; Point3d ptCen = pArc->GetCenter() ; double dAngCen = pArc->GetAngCenter() ; Vector3d vtN = pArc->GetNormVersor() ; Point3d ptP3 ; pArc->GetEndPoint( ptP3) ; SetFeed( GetFeed()) ; if ( AddArcMove( ptP3, ptCen, dAngCen, vtN) == GDB_ID_NULL) return false ; } // se ultima entità if ( i == nMaxInd) { // dati fine entità Point3d ptEnd ; pCurve->GetEndPoint( ptEnd) ; Vector3d vtEnd ; pCurve->GetEndDir( vtEnd) ; // aggiungo uscita double dEndElev = dElev ; Point3d ptP1 ; SetFeed( GetEndFeed()) ; if ( ! AddLeadOut( ptEnd, vtEnd, vtExtr, nullptr, bSplitArcs, ptP1, dEndElev, true)) { m_pMchMgr->SetLastError( 2416, "Error in Pocketing : LeadOut not computable") ; return false ; } // se lucidatura e ultimo step, aggiungo retrazione if ( m_TParams.m_nType == TT_MILL_POLISHING && j == nStep) { if ( ! AddRetract( ptP1, vtTool, dSafeZ, dSafeAggrBottZ, dEndElev, dAppr)) { m_pMchMgr->SetLastError( 2418, "Error in Pocketing : Retract not computable") ; return false ; } } // altrimenti, aggiungo retrazione di collegamento else { if ( ! AddLinkRetract( ptP1, vtTool, dSafeZ, dSafeAggrBottZ, dEndElev, dAppr)) { m_pMchMgr->SetLastError( 2418, "Error in Pocketing : Link not computable") ; return false ; } } } } } } nC ++ ; } // se lucidatura, non aggiungo contorno if ( m_TParams.m_nType == TT_MILL_POLISHING) return true ; // calcolo seconda superifice offsettata del raggio utensile + sovramateriale PtrOwner pSrfOff2 ( pSrf->Clone()) ; if ( IsNull( pSrfOff2)) { m_pMchMgr->SetLastError( 2412, "Error in Pocketing : Offset not computable") ; return false ; } if ( ! pSrfOff2->Offset( - dOffs , ICurve::OFF_FILLET) || ! pSrfOff2->IsValid()) { m_pMchMgr->SetLastError( 2412, "Error in Pocketing : Offset not computable") ; return false ; } // ciclo sulle superfici risultanti bStart = true ; nChunks = pSrfOff2->GetChunkCount() ; for ( int nC = 0 ; nC < nChunks ; nC++) { int nLoops = pSrfOff2->GetLoopCount( nC) ; for ( int nL = 0 ; nL < nLoops ; nL ++) { PtrOwner pOffs2( CreateCurveComposite()) ; if ( IsNull( pOffs2) || ! pOffs2->AddCurve( pSrfOff2->GetLoop( nC, nL))) { m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ; return false ; } VerifyArcs( pOffs2) ; // se richiesto, la inverto if ( m_Params.m_bInvert) pOffs2->Invert() ; // sposto l'inizio a metà del tratto più lungo AdjustContourStart( pOffs2) ; // aggiungo la lavorazione di questa curva Point3d ptP1 ; for ( int j = 1 ; j <= nStep ; ++ j) { // ciclo sulle curve elementari int nMaxInd = pOffs2->GetCurveCount() - 1 ; for ( int i = 0 ; i <= nMaxInd ; ++ i) { // curva corrente const ICurve* pCrvC = pOffs2->GetCurve( i) ; // copio la curva PtrOwner pCurve( pCrvC->Clone()) ; if ( IsNull( pCurve)) return false ; // aggiungo affondamento pCurve->Translate( - vtTool * ( dDepth - dElev + j * dStep)) ; // se prima entità if ( i == 0 ) { // dati inizio entità Point3d ptStart ; pCurve->GetStartPoint( ptStart) ; Vector3d vtStart ; pCurve->GetStartDir( vtStart) ; // se primo step, approccio e affondo if ( j == 1) { // determino inizio attacco if ( ! CalcLeadInStart( ptStart, vtStart, vtExtr, nullptr, ptP1)) return false ; // determino elevazione su inizio attacco double dStElev ; if ( ! GetElevation( m_nPhase, ptStart - 10 * EPS_SMALL * vtTool, vtTool, GetRadiusForStartEndElevation(), vtTool, dStElev)) dStElev = dElev ; bool bUnderStart = m_bAboveHead && GetPointUnderRaw( ptP1, vtTool, 0, GetRadiusForStartEndElevation(), m_TParams.m_dLen, false, dSafeZ, dStElev) ; if ( bUnderStart) dStElev = max( dStElev, dElev) ; dStElev -= ( ptP1 - ptStart) * vtExtr ; // se attacco a zigzag o a spirale o a scivolo, l'elevazione va nell'attacco if ( GetLeadInType() == POCKET_LI_ZIGZAG || GetLeadInType() == POCKET_LI_HELIX || GetLeadInType() == POCKET_LI_GLIDE) { ptP1 += vtExtr * dStElev ; dStElev = 0 ; } // approccio al punto iniziale if ( ! AddLinkApproach( ptP1, vtTool, dSafeZ, dSafeAggrBottZ, dStElev, dAppr)) { m_pMchMgr->SetLastError( 2418, "Error in Pocketing : Link not computable") ; return false ; } // aggiungo attacco SetFeed( GetStartFeed()) ; if ( ! AddLeadIn( ptP1, ptStart, vtStart, vtExtr, pSrf, nullptr, ! m_Params.m_bInvert, bSplitArcs)) { m_pMchMgr->SetLastError( 2415, "Error in Pocketing : LeadIn not computable") ; return false ; } } // altrimenti solo collegamento else { SetFeed( GetStartFeed()) ; GetCurrPos( ptP1) ; if ( ! AddLeadIn( ptP1, ptStart, vtStart, vtExtr, pSrf, nullptr, ! m_Params.m_bInvert, bSplitArcs)) { m_pMchMgr->SetLastError( 2418, "Error in Pocketing : Link not computable") ; return false ; } } } // elaborazioni sulla curva corrente if ( pCurve->GetType() == CRV_LINE) { ICurveLine* pLine = GetCurveLine( pCurve) ; Point3d ptP3 = pLine->GetEnd() ; SetFeed( GetFeed()) ; if ( AddLinearMove( ptP3) == GDB_ID_NULL) return false ; } else if ( pCurve->GetType() == CRV_ARC) { ICurveArc* pArc = GetCurveArc( pCurve) ; Point3d ptCen = pArc->GetCenter() ; double dAngCen = pArc->GetAngCenter() ; Vector3d vtN = pArc->GetNormVersor() ; Point3d ptP3 ; pArc->GetEndPoint( ptP3) ; SetFeed( GetFeed()) ; if ( AddArcMove( ptP3, ptCen, dAngCen, vtN) == GDB_ID_NULL) return false ; } // se ultima entità if ( i == nMaxInd) { // se ultimo step, uscita e retrazione di collegamento if ( j == nStep) { // dati fine entità Point3d ptEnd ; pCurve->GetEndPoint( ptEnd) ; Vector3d vtEnd ; pCurve->GetEndDir( vtEnd) ; // aggiungo uscita double dEndElev = dElev ; SetFeed( GetEndFeed()) ; if ( ! AddLeadOut( ptEnd, vtEnd, vtExtr, nullptr, bSplitArcs, ptP1, dEndElev)) { m_pMchMgr->SetLastError( 2416, "Error in Pocketing : LeadOut not computable") ; return false ; } // se ci sono ancora curve, aggiungo retrazione di collegamento if ( nC != nChunks-1 || nL != nLoops-1) { if ( ! AddLinkRetract( ptP1, vtTool, dSafeZ, dSafeAggrBottZ, dEndElev, dAppr)) { m_pMchMgr->SetLastError( 2418, "Error in Pocketing : Link not computable") ; return false ; } } // altrimenti retrazione finale else { if ( ! AddRetract( ptP1, vtTool, dSafeZ, dSafeAggrBottZ, dEndElev, dAppr)) { m_pMchMgr->SetLastError( 2418, "Error in Pocketing : Retract not computable") ; return false ; } } } } } } } } return true ; } //---------------------------------------------------------------------------- bool Pocketing::CalcZigZag( const ISurfFlatRegion* pSrf, ICRVCOMPOPOVECTOR& vpCrvs) { // vettore di curve che delimitano la superficie ICRVCOMPOPVECTOR vpCrvLoop ; for ( int nL = 0 ; nL < pSrf->GetLoopCount( 0) ; nL ++) { vpCrvLoop.push_back( CreateCurveComposite()) ; if ( ! vpCrvLoop.back()->AddCurve( pSrf->GetLoop( 0, nL))) { m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ; return false ; } } // ingombro del contorno offsettato BBox3d b3Pocket ; pSrf->GetLocalBBox( b3Pocket) ; Point3d ptMin ; double dDimX, dDimY, dDimZ ; b3Pocket.GetMinDim( ptMin, dDimX, dDimY, dDimZ) ; // lunghezza dei contorni offsettati DBLVECTOR vLen( vpCrvLoop.size()) ; for ( size_t i = 0 ; i < vLen.size() ; i++) vpCrvLoop[i]->GetLength( vLen[i]) ; // passi in Y int nYStep = static_cast( ceil( ( dDimY - 20 * EPS_SMALL) / GetSideStep())) ; double dYStep = ( nYStep > 0 ? ( dDimY - 20 * EPS_SMALL) / nYStep : 0) ; // tratto valido struct Section { bool bActive ; Point3d ptS ; Point3d ptE ; double dOs ; double dOe ; size_t nIdxS ; // indice posizione in vpCrvLoop della curva di offset a cui appartiene ptS size_t nIdxE ; // indice posizione in vpCrvLoop della curva di offset a cui appartiene ptE } ; // raccolta di tratti typedef vector> VECVECSECT ; VECVECSECT vvSec ; vvSec.resize( nYStep + 1) ; // calcolo le linee di svuotatura int nCount = 0 ; for ( int i = 0 ; i <= nYStep ; ++ i) { // determino senso bool bPlus = (( i % 2) == 0) ; // definisco la linea PtrOwner pLine( CreateCurveLine()) ; const double EXP_LEN = 1.0 ; Point3d ptStart( ptMin.x - EXP_LEN, ptMin.y + 10 * EPS_SMALL + i * dYStep, ptMin.z + dDimZ) ; if ( IsNull( pLine) || ! pLine->SetPVL( ptStart, X_AX, dDimX + 2 * EXP_LEN)) { m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ; return false ; } // calcolo la classificazione della curva rispetto alla regione offsettata CRVCVECTOR ccClass ; if ( ! pSrf->GetCurveClassification( *pLine, ccClass)) { m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ; return false ; } // determino gli intervalli di curva da conservare Intervals inOk ; for ( auto& ccOne : ccClass) { if ( ccOne.nClass == CRVC_IN || ccOne.nClass == CRVC_ON_P || ccOne.nClass == CRVC_ON_M) inOk.Add( ccOne.dParS, ccOne.dParE) ; } // inserisco i tratti validi (secondo X+ i pari, secondo X- i dispari) double dParS, dParE ; bool bFound = ( bPlus ? inOk.GetFirst( dParS, dParE) : inOk.GetLast( dParE, dParS)) ; while ( bFound) { // determino i dati della sezione Section Sect ; Sect.bActive = true ; pLine->GetPointD1D2( dParS, ICurve::FROM_PLUS, Sect.ptS) ; pLine->GetPointD1D2( dParE, ICurve::FROM_MINUS, Sect.ptE) ; // cerco la curva della regione di offset che passa per ptS bool bCrvFound = false ; for ( size_t k = 0 ; ! bCrvFound && k < vpCrvLoop.size() ; k++) { bCrvFound = vpCrvLoop[k]->GetParamAtPoint( Sect.ptS, Sect.dOs, 10 * EPS_SMALL) ; if ( bCrvFound) Sect.nIdxS = k ; } if ( ! bCrvFound) { m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ; return false ; } // cerco la curva della regione di offset che passa per ptE bCrvFound = false ; for ( size_t k = 0 ; ! bCrvFound && k < vpCrvLoop.size() ; k++) { bCrvFound = vpCrvLoop[k]->GetParamAtPoint( Sect.ptE, Sect.dOe, 10 * EPS_SMALL) ; if ( bCrvFound) Sect.nIdxE = k ; } if ( ! bCrvFound) { m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ; return false ; } // inserisco nel contenitore vvSec[i].emplace_back( Sect) ; ++ nCount ; // recupero successivo intervallo bFound = ( bPlus ? inOk.GetNext( dParS, dParE) : inOk.GetPrev( dParE, dParS)) ; } } // dominio del contorno DBLVECTOR vUmax( vpCrvLoop.size()) ; DBLVECTOR vUmin( vpCrvLoop.size()) ; DBLVECTOR vUspan( vpCrvLoop.size()) ; for ( size_t i = 0 ; i < vpCrvLoop.size() ; i++) { vpCrvLoop[i]->GetDomain( vUmin[i], vUmax[i]) ; vUspan[i] = vUmax[i] - vUmin[i] ; } // creo i percorsi di svuotatura vpCrvs.reserve( nCount) ; int nI = -1, nJ = -1 ; while ( true) { // se sezione non valida if ( nI < 0 || nJ < 0) { // ricerco la prima valida for ( int k = 0 ; k < int( vvSec.size()) && nI < 0 ; ++ k) { for ( int l = 0 ; l < int( vvSec[k].size()) && nJ < 0 ; ++ l) { if ( vvSec[k][l].bActive) { nI = k ; nJ = l ; } } } // se trovata, creo nuova curva composita if ( nI >= 0 && nJ >= 0) { // creo la curva vpCrvs.emplace_back( CreateCurveComposite()) ; // aggiungo punto iniziale vpCrvs.back()->AddPoint( vvSec[nI][nJ].ptS) ; } // altrimenti, esco else break ; } // determino senso bool bPlus = (( nI % 2) == 0) ; // aggiungo la sezione alla curva Section& Sec = vvSec[nI][nJ] ; Sec.bActive = false ; vpCrvs.back()->AddLine( vvSec[nI][nJ].ptE) ; // cerco nella stessa fila o in quella successiva sezione successiva raccordabile tramite il contorno double dUstart = Sec.dOe ; double dUref = ( bPlus ? INFINITO : - INFINITO) ; int nNextI = -1 ; int nNextJ = -1 ; int li = nJ + 1 ; for ( int k = nI ; k <= nI + 1 && k < int( vvSec.size()) ; ++ k) { for ( int l = li ; l < int( vvSec[k].size()) ; ++ l) { if ( ! vvSec[k][l].bActive) continue ; // la nuova sezione deve partire dalla stessa curva su cui ci si � fermati if ( vvSec[k][l].nIdxS != Sec.nIdxE) continue ; double dU = vvSec[k][l].dOs ; if ( bPlus) { if ( dU < dUstart) dU += vUspan[Sec.nIdxE] ; if ( dU < dUref) { dUref = dU ; nNextI = k ; nNextJ = l ; } } else { if ( dU > dUstart) dU -= vUspan[Sec.nIdxE] ; if ( dU > dUref) { dUref = dU ; nNextI = k ; nNextJ = l ; } } } li = 0 ; } // se trovato, aggiungo il tratto di contorno e continuo if ( nNextI != -1) { PtrOwner pCopy ; size_t idx = vvSec[nNextI][nNextJ].nIdxS ; if ( bPlus) { if ( dUref > vUmax[idx]) dUref -= vUspan[idx] ; pCopy.Set( vpCrvLoop[idx]->CopyParamRange( dUstart, dUref)) ; if ( ! IsNull( pCopy)) { double dCLen ; pCopy->GetLength( dCLen) ; if ( dCLen > 0.5 * vLen[idx]) { pCopy.Set( vpCrvLoop[idx]->CopyParamRange( dUref, dUstart)) ; if ( ! IsNull( pCopy)) pCopy->Invert() ; } } } else { if ( dUref < vUmin[idx]) dUref += vUspan[idx] ; pCopy.Set( vpCrvLoop[idx]->CopyParamRange( dUref, dUstart)) ; if ( ! IsNull( pCopy)) { pCopy->Invert() ; double dCLen ; pCopy->GetLength( dCLen) ; if ( dCLen > 0.5 * vLen[idx]) pCopy.Set( vpCrvLoop[idx]->CopyParamRange( dUstart, dUref)) ; } } BBox3d b3Copy ; if ( ! IsNull( pCopy)) pCopy->GetLocalBBox( b3Copy) ; if ( ! b3Copy.IsEmpty() && ( b3Copy.GetMax().y - b3Copy.GetMin().y) < dYStep + 10 * EPS_SMALL) { vpCrvs.back()->AddCurve( Release( pCopy)) ; nI = nNextI ; nJ = nNextJ ; } else { nI = -1 ; nJ = -1 ; } } else { nI = -1 ; nJ = -1 ; } } return true ; } //---------------------------------------------------------------------------- bool Pocketing::AddOneWay( const ISurfFlatRegion* pSrf, const Vector3d& vtTool, const Vector3d& vtExtr, double dDepth, double dElev, double dOkStep, bool bSplitArcs) { // recupero distanze di sicurezza double dSafeZ = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeZ() ; double dSafeAggrBottZ = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeAggrBottZ() ; // lunghezza di approccio/retrazione double dAppr = m_Params.m_dStartPos ; // se utensile che non lavora di testa poichè ingresso non fuori dal pezzo, errore if ( m_TParams.m_nType == TT_MILL_NOTIP) { if ( ! LeadInIsOk()) { m_pMchMgr->SetLastError( 2431, "Error in Pocketing : LeadIn with Mill NoTip in material") ; return false ; } } // determino numero e affondamento degli step int nStep = 1 ; nStep = max( 1, static_cast( ceil( dElev / dOkStep))) ; double dStep = dElev / nStep ; // calcolo regione offsettata del raggio utensile + sovramateriale double dTRad = 0.5 * m_TParams.m_dDiam ; double dOffs = dTRad + GetOffsR() ; PtrOwner pSrfOff1( pSrf->Clone()) ; if( IsNull( pSrfOff1)) return false ; if ( ! pSrfOff1->Offset( - dOffs, ICurve::OFF_FILLET) || ! pSrfOff1->IsValid()) { m_pMchMgr->SetLastError( 2412, "Error in Pocketing : Offset not computable") ; return false ; } // ciclo sulle superifici risultanti for ( int nC = 0 ; nC < pSrfOff1->GetChunkCount() ; nC ++) { // ciclo sulle curve for ( int nL = 0 ; nL < pSrfOff1->GetLoopCount( nC) ; nL ++) { // recupero la curva di offset PtrOwner pOffs( CreateCurveComposite()) ; if ( IsNull( pOffs) || ! pOffs->AddCurve( pSrfOff1->GetLoop( nC, nL))) { m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ; return false ; } VerifyArcs( pOffs) ; // se richiesto, la inverto if ( m_Params.m_bInvert) pOffs->Invert() ; // sposto l'inizio a metà del tratto più lungo AdjustContourStart( pOffs) ; // coefficiente di riduzione feed di lavorazione di questa curva double dFeedRid = min( GetSideStep() / m_TParams.m_dDiam, 1.0) ; // aggiungo la lavorazione di questa curva Point3d ptP1 ; for ( int j = 1 ; j <= nStep ; ++ j) { // ciclo sulle curve elementari int nMaxInd = pOffs->GetCurveCount() - 1 ; for ( int i = 0 ; i <= nMaxInd ; ++ i) { // curva corrente const ICurve* pCrvC = pOffs->GetCurve( i) ; // copio la curva PtrOwner pCurve( pCrvC->Clone()) ; if ( IsNull( pCurve)) return false ; // aggiungo affondamento pCurve->Translate( - vtTool * ( dDepth - dElev + j * dStep)) ; // se prima entità if ( i == 0 ) { // dati inizio entità Point3d ptStart ; pCurve->GetStartPoint( ptStart) ; Vector3d vtStart ; pCurve->GetStartDir( vtStart) ; // se primo step, approccio e affondo if ( j == 1) { // determino inizio attacco if ( ! CalcLeadInStart( ptStart, vtStart, vtExtr, nullptr, ptP1)) return false ; // determino elevazione su inizio attacco double dStElev ; if ( ! GetElevation( m_nPhase, ptStart - 10 * EPS_SMALL * vtTool, vtTool, GetRadiusForStartEndElevation(), vtTool, dStElev)) dStElev = dStep ; bool bUnderRaw = GetPointUnderRaw( ptP1, vtTool, 0, GetRadiusForStartEndElevation(), m_TParams.m_dLen, false, dSafeZ, dStElev) ; if ( bUnderRaw == m_bAboveHead) dStElev = max( dStElev, dStep) ; dStElev -= ( ptP1 - ptStart) * vtExtr ; // se attacco a zigzag o a spirale o a scivolo, l'elevazione va nell'attacco if ( GetLeadInType() == POCKET_LI_ZIGZAG || GetLeadInType() == POCKET_LI_HELIX || GetLeadInType() == POCKET_LI_GLIDE) { ptP1 += vtExtr * dStElev ; dStElev = 0 ; } // approccio al punto iniziale if ( ! AddApproach( ptP1, vtTool, dSafeZ, dSafeAggrBottZ, dStElev, dAppr, false)) { m_pMchMgr->SetLastError( 2414, "Error in Pocketing : Approach not computable") ; return false ; } // aggiungo attacco SetFeed( GetStartFeed()) ; if ( ! AddLeadIn( ptP1, ptStart, vtStart, vtExtr, pSrf, nullptr, ! m_Params.m_bInvert, bSplitArcs)) { m_pMchMgr->SetLastError( 2415, "Error in Pocketing : LeadIn not computable") ; return false ; } } // altrimenti solo collegamento else { SetFeed( GetStartFeed()) ; GetCurrPos( ptP1) ; if ( ! AddLeadIn( ptP1, ptStart, vtStart, vtExtr, pSrf, nullptr, ! m_Params.m_bInvert, bSplitArcs)) { m_pMchMgr->SetLastError( 2418, "Error in Pocketing : Link not computable") ; return false ; } } } // elaborazioni sulla curva corrente if ( pCurve->GetType() == CRV_LINE) { ICurveLine* pLine = GetCurveLine( pCurve) ; Point3d ptP3 = pLine->GetEnd() ; SetFeed( dFeedRid * GetFeed()) ; 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( dFeedRid * GetFeed()) ; if ( AddArcMove( ptP3, ptCen, dAngCen, vtN) == GDB_ID_NULL) return false ; } // se ultima entità if ( i == nMaxInd) { // se ultimo step, uscita e retrazione di collegamento if ( j == nStep) { // dati fine entità Point3d ptEnd ; pCurve->GetEndPoint( ptEnd) ; Vector3d vtEnd ; pCurve->GetEndDir( vtEnd) ; // aggiungo uscita Point3d ptP1 ; double dEndElev = dElev ; SetFeed( GetEndFeed()) ; if ( ! AddLeadOut( ptEnd, vtEnd, vtExtr, nullptr, bSplitArcs, ptP1, dEndElev)) { m_pMchMgr->SetLastError( 2416, "Error in Pocketing : LeadOut not computable") ; return false ; } // aggiungo retrazione if ( ! AddLinkRetract( ptP1, vtTool, dSafeZ, dSafeAggrBottZ, dEndElev, dAppr)) { m_pMchMgr->SetLastError( 2418, "Error in Pocketing : Link not computable") ; return false ; } } } } } } } // calcolo seconda superficie di offset PtrOwner pSrfOff2( pSrf->Clone()) ; if( IsNull( pSrfOff2)) return false ; double dExtra = min( 0.1 * m_TParams.m_dDiam, 1.0) ; if ( ! pSrfOff2->Offset( - ( dOffs + dExtra), ICurve::OFF_FILLET) || ! pSrfOff2->IsValid()) { m_pMchMgr->SetLastError( 2412, "Error in Pocketing : Offset not computable") ; return false ; } // ciclo sulle superfici risultanti int nC = 0 ; int nChunks = pSrfOff2->GetChunkCount() ; while ( nC < nChunks) { PtrOwner pSrfChunk( pSrfOff2->CloneChunk( nC)) ; if ( IsNull( pSrfChunk)) return false ; // determino il riferimento di base e il box della svuotatura Frame3d frPocket ; Point3d ptCen ; pSrfChunk->GetChunkCentroid( 0, ptCen) ; frPocket.Set( ptCen, vtExtr) ; frPocket.Rotate( ptCen, vtExtr, m_Params.m_dSideAngle) ; pSrfChunk->ToLoc( frPocket) ; BBox3d b3Pocket ; pSrfChunk->GetLocalBBox( b3Pocket) ; Point3d ptMin ; double dDimX, dDimY, dDimZ ; b3Pocket.GetMinDim( ptMin, dDimX, dDimY, dDimZ) ; // passi in Y int nYStep = static_cast( ceil( ( dDimY + 2 * dExtra) / GetSideStep())) ; double dYStep = ( nYStep > 0 ? ( dDimY + 2 * dExtra) / nYStep : 0) ; -- nYStep ; // calcolo le linee di svuotatura const double EXP_LEN = 1.0 ; for ( int j = 1 ; j <= nStep ; ++ j) { for ( int i = 1 ; i <= nYStep ; ++ i) { // definisco la linea PtrOwner pLine( CreateCurveLine()) ; Point3d ptStart( ptMin.x - EXP_LEN, ptMin.y + ( - dExtra + i * dYStep), ptMin.z + dDimZ) ; if ( IsNull( pLine) || ! pLine->SetPVL( ptStart, X_AX, dDimX + 2 * EXP_LEN)) { m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ; return false ; } // calcolo la classificazione della curva rispetto alla superficie offsettata CRVCVECTOR ccClass ; if ( ! pSrfChunk->GetCurveClassification( *pLine, ccClass)) { m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ; return false ; } // determino gli intervalli di curva da conservare Intervals inOk ; for ( auto& ccOne : ccClass) { if ( ccOne.nClass == CRVC_IN || ccOne.nClass == CRVC_ON_P || ccOne.nClass == CRVC_ON_M) inOk.Add( ccOne.dParS, ccOne.dParE) ; } // inserisco i tratti validi double dParS, dParE ; bool bFound = inOk.GetFirst( dParS, dParE) ; while ( bFound) { // calcolo inizio con affondamento Point3d ptS ; pLine->GetPointD1D2( dParS, ICurve::FROM_PLUS, ptS) ; ptS.ToGlob( frPocket) ; ptS.Translate( - vtTool * ( dDepth - dElev + j * dStep)) ; // determino inizio attacco Point3d ptP ; if ( ! CalcLeadInStart( ptS, frPocket.VersX(), vtExtr, nullptr, ptP)) return false ; // determino elevazione su inizio attacco double dStElev ; if ( ! GetElevation( m_nPhase, ptS - 10 * EPS_SMALL * vtTool, vtTool, GetRadiusForStartEndElevation(), vtTool, dStElev)) dStElev = j * dStep ; bool bUnderRaw = GetPointUnderRaw( ptP, vtTool, 0, GetRadiusForStartEndElevation(), m_TParams.m_dLen, false, dSafeZ, dStElev) ; if ( bUnderRaw == m_bAboveHead) dStElev = max( dStElev, j * dStep) ; dStElev -= ( ptP - ptS) * vtExtr ; // sempre approccio di collegamento if ( ! AddLinkApproach( ptP, vtTool, dSafeZ, dSafeAggrBottZ, dStElev, dAppr)) { m_pMchMgr->SetLastError( 2418, "Error in Pocketing : Link not computable") ; return false ; } // aggiungo attacco SetFeed( GetStartFeed()) ; if ( ! AddLeadIn( ptP, ptS, frPocket.VersX(), vtExtr, pSrf, nullptr, ! m_Params.m_bInvert, bSplitArcs, true)) { m_pMchMgr->SetLastError( 2415, "Error in Pocketing : LeadIn not computable") ; return false ; } // calcolo fine con affondamento Point3d ptE ; pLine->GetPointD1D2( dParE, ICurve::FROM_MINUS, ptE) ; ptE.ToGlob( frPocket) ; ptE.Translate( - vtTool * ( dDepth - dElev + j * dStep)) ; // movimento al punto finale SetFeed( GetFeed()) ; if ( AddLinearMove( ptE) == GDB_ID_NULL) return false ; // risalita Point3d ptQ ; double dEndElev = dElev ; SetFeed( GetEndFeed()) ; if ( ! AddLeadOut( ptE, frPocket.VersX(), vtExtr, nullptr, bSplitArcs, ptQ, dEndElev, true)) { m_pMchMgr->SetLastError( 2416, "Error in Pocketing : LeadOut not computable") ; return false ; } // recupero successivo intervallo bFound = inOk.GetNext( dParS, dParE) ; // se ultimo movimento di ultima area, aggiungo retrazione globale if ( j == nStep && i == nYStep && ! bFound && nC == nChunks - 1 ) { if ( ! AddRetract( ptQ, vtTool, dSafeZ, dSafeAggrBottZ, dEndElev, dAppr)) { m_pMchMgr->SetLastError( 2417, "Error in Pocketing : Retract not computable") ; return false ; } } // altrimenti aggiungo retrazione di collegamento else { if ( ! AddLinkRetract( ptQ, vtTool, dSafeZ, dSafeAggrBottZ, dEndElev, dAppr)) { m_pMchMgr->SetLastError( 2418, "Error in Pocketing : Link not computable") ; return false ; } } } } } nC ++ ; } return true ; } //---------------------------------------------------------------------------- bool Pocketing::AddSpiralIn( const ISurfFlatRegion* pSrf, const Vector3d& vtTool, const Vector3d& vtExtr, double dDepth, double dElev, double dOkStep, bool bSplitArcs, bool bMidOpen, const Point3d& ptMidOpen, const Vector3d& vtMidOut) { // recupero distanze di sicurezza double dSafeZ = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeZ() ; double dSafeAggrBottZ = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeAggrBottZ() ; // lunghezza di approccio/retrazione double dAppr = m_Params.m_dStartPos ; // ciclo sulle regioni const int MAX_REGS = 50 ; int nReg = 0 ; while ( nReg < MAX_REGS) { // calcolo la spirale dall'esterno all'interno e la curva che unisce inizio e fine PtrOwner pMCrv( CreateCurveComposite()) ; PtrOwner pRCrv( CreateCurveComposite()) ; if ( IsNull( pMCrv) || IsNull( pRCrv)) { m_pMchMgr->SetLastError( 2411, "Error in Pocketing : toolpath allocation failed") ; return false ; } if ( ! CalcSpiral( pSrf, nReg, bSplitArcs, pMCrv, pRCrv)) return false ; // se terminate le regioni, esco if ( pMCrv->GetCurveCount() == 0) break ; ++ nReg ; // se prima regione e gestione lato aperto bool bOutStart = ( nReg == 1 && bMidOpen) ; if ( bOutStart) { // calcolo il punto fuori Point3d ptOut = ptMidOpen + vtMidOut * ( 0.5 * m_TParams.m_dDiam + dSafeZ) ; // aggiungo al ritorno l'uscita if ( pRCrv->GetCurveCount() == 0) { Point3d ptStart ; pMCrv->GetStartPoint( ptStart) ; pRCrv->AddPoint( ptStart) ; } pRCrv->AddLine( ptOut, true) ; // premetto alla spirale la partenza da fuori pMCrv->AddLine( ptOut, false) ; } // se utensile che non lavora di testa e ingresso non fuori dal pezzo, errore if ( m_TParams.m_nType == TT_MILL_NOTIP && ! bOutStart) { if ( ! LeadInIsOk()) { m_pMchMgr->SetLastError( 2431, "Error in Pocketing : LeadIn with Mill NoTip in material") ; return false ; } } // determino numero e affondamento degli step int nStep = 1 ; nStep = max( 1, static_cast( ceil( dElev / dOkStep))) ; double dStep = dElev / nStep ; int nMaxInd = pMCrv->GetCurveCount() - 1 ; int nMaxRInd = pRCrv->GetCurveCount() - 1 ; // ciclo sugli step Point3d ptP1 ; for ( int j = 1 ; j <= nStep ; ++ j) { // ciclo sulle curve elementari for ( int i = 0 ; i <= nMaxInd ; ++ i) { // curva corrente const ICurve* pCrvC = pMCrv->GetCurve( i) ; // copio la curva PtrOwner pCurve( pCrvC->Clone()) ; if ( IsNull( pCurve)) return false ; // aggiungo affondamento pCurve->Translate( - vtTool * ( dDepth - dElev + j * dStep)) ; // se prima entità if ( i == 0 ) { // dati inizio entità Point3d ptStart ; pCurve->GetStartPoint( ptStart) ; Vector3d vtStart ; pCurve->GetStartDir( vtStart) ; // se primo step, approccio e affondo if ( j == 1) { // determino inizio attacco if ( ! CalcLeadInStart( ptStart, vtStart, vtExtr, pRCrv, ptP1)) return false ; // determino elevazione su inizio attacco (se non trovata, elevazione è step) double dStElev ; if ( ! GetElevation( m_nPhase, ptStart - 10 * EPS_SMALL * vtTool, vtTool, GetRadiusForStartEndElevation(), vtTool, dStElev)) dStElev = dStep ; bool bUnderRaw = GetPointUnderRaw( ptP1, vtTool, 0, GetRadiusForStartEndElevation(), m_TParams.m_dLen, false, dSafeZ, dStElev) ; if ( bUnderRaw == m_bAboveHead) dStElev = max( dStElev, dStep) ; dStElev -= ( ptP1 - ptStart) * vtExtr ; // se attacco a zigzag o a spirale o a scivolo, l'elevazione va nell'attacco if ( GetLeadInType() == POCKET_LI_ZIGZAG || GetLeadInType() == POCKET_LI_HELIX || GetLeadInType() == POCKET_LI_GLIDE) { ptP1 += vtExtr * dStElev ; dStElev = 0 ; } // approccio al punto iniziale if ( ! AddApproach( ptP1, vtTool, dSafeZ, dSafeAggrBottZ, dStElev, dAppr, bOutStart)) { m_pMchMgr->SetLastError( 2414, "Error in Pocketing : Approach not computable") ; return false ; } // aggiungo attacco SetFeed( GetStartFeed()) ; if ( ! AddLeadIn( ptP1, ptStart, vtStart, vtExtr, pSrf, pRCrv, ! m_Params.m_bInvert, bSplitArcs, bOutStart)) { m_pMchMgr->SetLastError( 2415, "Error in Pocketing : LeadIn not computable") ; return false ; } } // altrimenti solo collegamento else { SetFeed( GetStartFeed()) ; GetCurrPos( ptP1) ; if ( ! AddLeadIn( ptP1, ptStart, vtStart, vtExtr, pSrf, pRCrv, ! m_Params.m_bInvert, bSplitArcs, bOutStart)) { m_pMchMgr->SetLastError( 2418, "Error in Pocketing : Link not computable") ; return false ; } } } // elaborazioni sulla curva corrente if ( pCurve->GetType() == CRV_LINE) { ICurveLine* pLine = GetCurveLine( pCurve) ; Point3d ptP3 = pLine->GetEnd() ; SetFeed( GetFeed()) ; if ( AddLinearMove( ptP3) == GDB_ID_NULL) return false ; } else if ( pCurve->GetType() == CRV_ARC) { ICurveArc* pArc = GetCurveArc( pCurve) ; Point3d ptCen = pArc->GetCenter() ; double dAngCen = pArc->GetAngCenter() ; Vector3d vtN = pArc->GetNormVersor() ; Point3d ptP3 ; pArc->GetEndPoint( ptP3) ; SetFeed( GetFeed()) ; if ( AddArcMove( ptP3, ptCen, dAngCen, vtN) == GDB_ID_NULL) return false ; } // se ultima entità if ( i == nMaxInd) { // se step intermedio, ritorno all'inizio direttamente if ( j < nStep) { // se necessario ritorno all'inizio if ( nMaxRInd >= 0) { // copio la curva di ritorno PtrOwner pRet( pRCrv->Clone()) ; if ( IsNull( pRet)) return false ; // aggiungo affondamento pRet->Translate( - vtTool * ( dDepth - dElev + j * dStep)) ; // se attacco a scivolo, accorcio della lunghezza dell'attacco if ( GetLeadInType() == POCKET_LI_GLIDE) { double dLen ; pRet->GetLength( dLen) ; if ( dLen > m_Params.m_dLiTang + 10 * EPS_SMALL) pRet->TrimEndAtLen( dLen - m_Params.m_dLiTang) ; else pRet->Clear() ; } // emetto SetFeed( GetFeed()) ; if ( pRet->GetCurveCount() > 0 && AddCurveMove( pRet) == GDB_ID_NULL) return false ; } } // atrimenti ultimo step, uscita e retrazione else { // dati fine entità Point3d ptEnd ; pCurve->GetEndPoint( ptEnd) ; Vector3d vtEnd ; pCurve->GetEndDir( vtEnd) ; // aggiungo uscita Point3d ptP1 ; double dEndElev = dElev ; SetFeed( GetEndFeed()) ; if ( ! AddLeadOut( ptEnd, vtEnd, vtExtr, pRCrv, bSplitArcs, ptP1, dEndElev)) { m_pMchMgr->SetLastError( 2416, "Error in Pocketing : LeadOut not computable") ; return false ; } // aggiungo retrazione if ( ! AddRetract( ptP1, vtTool, dSafeZ, dSafeAggrBottZ, dEndElev, dAppr)) { m_pMchMgr->SetLastError( 2417, "Error in Pocketing : Retract not computable") ; return false ; } } } } } } return true ; } //---------------------------------------------------------------------------- bool Pocketing::AddSpiralOut( const ISurfFlatRegion* pSrf, const Vector3d& vtTool, const Vector3d& vtExtr, double dDepth, double dElev, double dOkStep, bool bSplitArcs) { // recupero distanze di sicurezza double dSafeZ = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeZ() ; double dSafeAggrBottZ = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeAggrBottZ() ; // lunghezza di approccio/retrazione double dAppr = m_Params.m_dStartPos ; // se utensile che non lavora di testa poichè ingresso non fuori dal pezzo, errore if ( m_TParams.m_nType == TT_MILL_NOTIP) { if ( ! LeadInIsOk()) { m_pMchMgr->SetLastError( 2431, "Error in Pocketing : LeadIn with Mill NoTip in material") ; return false ; } } // ciclo sulle regioni const int MAX_REGS = 50 ; int nReg = 0 ; while ( nReg < MAX_REGS) { // calcolo la spirale dall'interno all'esterno PtrOwner pMCrv( CreateCurveComposite()) ; PtrOwner pRCrv( CreateCurveComposite()) ; if ( IsNull( pMCrv) || IsNull( pRCrv)) { m_pMchMgr->SetLastError( 2411, "Error in Pocketing : toolpath allocation failed") ; return false ; } if ( ! CalcSpiral( pSrf, nReg, bSplitArcs, pMCrv, pRCrv)) return false ; // se terminate le regioni, esco if ( pMCrv->GetCurveCount() == 0) break ; ++ nReg ; // inverto i percorsi, perchè sono calcolati dall'esterno all'interno pMCrv->Invert() ; pRCrv->Invert() ; // determino numero e affondamento degli step int nStep = 1 ; nStep = max( 1, static_cast( ceil( dElev / dOkStep))) ; double dStep = dElev / nStep ; int nMaxInd = pMCrv->GetCurveCount() - 1 ; int nMaxRInd = pRCrv->GetCurveCount() - 1 ; // ciclo sugli step Point3d ptP1 ; for ( int j = 1 ; j <= nStep ; ++ j) { // ciclo sulle curve elementari for ( int i = 0 ; i <= nMaxInd ; ++ i) { // curva corrente const ICurve* pCrvC = pMCrv->GetCurve( i) ; // copio la curva PtrOwner pCurve( pCrvC->Clone()) ; if ( IsNull( pCurve)) return false ; // aggiungo affondamento pCurve->Translate( - vtTool * ( dDepth - dElev + j * dStep)) ; // se prima entità if ( i == 0 ) { // dati inizio entità Point3d ptStart ; pCurve->GetStartPoint( ptStart) ; Vector3d vtStart ; pCurve->GetStartDir( vtStart) ; // se primo step, approccio e affondo if ( j == 1) { // determino inizio attacco if ( ! CalcLeadInStart( ptStart, vtStart, vtExtr, pRCrv, ptP1)) { m_pMchMgr->SetLastError( 2415, "Error in Pocketing : LeadIn not computable") ; return false ; } // determino elevazione su inizio attacco double dStElev ; if ( ! GetElevation( m_nPhase, ptStart - 10 * EPS_SMALL * vtTool, vtTool, GetRadiusForStartEndElevation(), vtTool, dStElev)) dStElev = dStep ; bool bUnderRaw = GetPointUnderRaw( ptP1, vtTool, 0, GetRadiusForStartEndElevation(), m_TParams.m_dLen, false, dSafeZ, dStElev) ; if ( bUnderRaw == m_bAboveHead) dStElev = max( dStElev, dStep) ; dStElev -= ( ptP1 - ptStart) * vtExtr ; // se attacco a zigzag o a spirale o a scivolo, l'elevazione va nell'attacco if ( GetLeadInType() == POCKET_LI_ZIGZAG || GetLeadInType() == POCKET_LI_HELIX || GetLeadInType() == POCKET_LI_GLIDE) { ptP1 += vtExtr * dStElev ; dStElev = 0 ; } // approccio al punto iniziale if ( ! AddApproach( ptP1, vtTool, dSafeZ, dSafeAggrBottZ, dStElev, dAppr, false)) { m_pMchMgr->SetLastError( 2414, "Error in Pocketing : Approach not computable") ; return false ; } // aggiungo attacco SetFeed( GetStartFeed()) ; if ( ! AddLeadIn( ptP1, ptStart, vtStart, vtExtr, pSrf, pRCrv, m_Params.m_bInvert, bSplitArcs)) { m_pMchMgr->SetLastError( 2415, "Error in Pocketing : LeadIn not computable") ; return false ; } } // altrimenti solo collegamento else { SetFeed( GetStartFeed()) ; GetCurrPos( ptP1) ; if ( ! AddLeadIn( ptP1, ptStart, vtStart, vtExtr, pSrf, pRCrv, m_Params.m_bInvert, bSplitArcs)) { m_pMchMgr->SetLastError( 2418, "Error in Pocketing : Link not computable") ; return false ; } } } // elaborazioni sulla curva corrente if ( pCurve->GetType() == CRV_LINE) { ICurveLine* pLine = GetCurveLine( pCurve) ; Point3d ptP3 = pLine->GetEnd() ; SetFeed( GetFeed()) ; if ( AddLinearMove( ptP3) == GDB_ID_NULL) return false ; } else if ( pCurve->GetType() == CRV_ARC) { ICurveArc* pArc = GetCurveArc( pCurve) ; Point3d ptCen = pArc->GetCenter() ; double dAngCen = pArc->GetAngCenter() ; Vector3d vtN = pArc->GetNormVersor() ; Point3d ptP3 ; pArc->GetEndPoint( ptP3) ; SetFeed( GetFeed()) ; if ( AddArcMove( ptP3, ptCen, dAngCen, vtN) == GDB_ID_NULL) return false ; } // se ultima entità if ( i == nMaxInd) { // se step intermedio if ( j < nStep) { // se necessario ritorno all'inizio if ( nMaxRInd >= 0) { // copio la curva di ritorno PtrOwner pRet( pRCrv->Clone()) ; if ( IsNull( pRet)) return false ; // aggiungo affondamento pRet->Translate( - vtTool * ( dDepth - dElev + j * dStep)) ; // se attacco a scivolo, accorcio della lunghezza dell'attacco if ( GetLeadInType() == POCKET_LI_GLIDE) { double dLen ; pRet->GetLength( dLen) ; if ( dLen > m_Params.m_dLiTang + 10 * EPS_SMALL) pRet->TrimEndAtLen( dLen - m_Params.m_dLiTang) ; else pRet->Clear() ; } // emetto SetFeed( GetFeed()) ; if ( pRet->GetCurveCount() > 0 && AddCurveMove( pRet) == GDB_ID_NULL) return false ; } } // atrimenti ultimo step, uscita e retrazione else { // dati fine entità Point3d ptEnd ; pCurve->GetEndPoint( ptEnd) ; Vector3d vtEnd ; pCurve->GetEndDir( vtEnd) ; // aggiungo uscita Point3d ptQ ; double dEndElev = dElev ; SetFeed( GetEndFeed()) ; if ( ! AddLeadOut( ptEnd, vtEnd, vtExtr, pRCrv, bSplitArcs, ptQ, dEndElev)) { m_pMchMgr->SetLastError( 2416, "Error in Pocketing : LeadOut not computable") ; return false ; } // aggiungo retrazione if ( ! AddRetract( ptQ, vtTool, dSafeZ, dSafeAggrBottZ, dEndElev, dAppr)) { m_pMchMgr->SetLastError( 2417, "Error in Pocketing : Retract not computable") ; return false ; } } } } } } return true ; } //---------------------------------------------------------------------------- bool Pocketing::CalcSpiral( const ISurfFlatRegion * pSrf , int nReg, bool bSplitArcs, ICurveComposite* pMCrv, ICurveComposite* pRCrv) { // inizializzo i risultati pMCrv->Clear() ; pRCrv->Clear() ; ISurfFlatRegion * pCutRegion = CreateSurfFlatRegion() ; // regione lavorata Vector3d vtExtr = pSrf->GetNormVersor() ; // primo offset pari al raggio utensile + sovramateriale double dTRad = 0.5 * m_TParams.m_dDiam ; double dOffs = dTRad + GetOffsR() ; // ciclo di offset verso l'interno const int MAX_ITER = 1000 ; int nIter = 0 ; PtrOwner pSrfOff( pSrf->Clone()) ; // superficie che viene offsettata PtrOwner pSrfOffOld( pSrf->Clone()) ; // superficie di offset all'iterazione precedente PtrOwner pSrfOff1 ; // superficie di offset alla prima iterazione if ( IsNull( pSrfOff) || IsNull( pSrfOffOld)) { m_pMchMgr->SetLastError( 2412, "Error in Pocketing : Offset not computable") ; return false ; } ISURFFRPOVECTOR vSrfStack ; ICRVCOMPOPVECTOR vOffs ; PtrOwner pOffs ; bool bCircleSpiral ; size_t LastExtLoopPos = 0 ; while ( nIter < MAX_ITER) { // calcolo offset if ( ! pSrfOff->Offset( - dOffs, ICurve::OFF_FILLET)) { pSrfOff->Clear() ; m_pMchMgr->SetLastError( 2412, "Error in Pocketing : Offset not computable") ; return false ; } // salvo la prima surface di offset per CalcBoundedLink if ( nIter == 0 && pSrfOff->IsValid()) pSrfOff1.Set( pSrfOff->Clone()) ; if ( IsNull( pSrfOff1) || ! pSrfOff1->IsValid()) return false ; // se primo offset e richiesta regione oltre il massimo, esco int nChunks = pSrfOff->GetChunkCount() ; if ( nIter == 0 && nReg >= nChunks) return true ; // recupero le superfici di offset e le metto sullo stack (se primo offset solo quella voluta) int nCount = 0 ; while ( nCount < nChunks) { if ( nIter != 0 || nReg == nCount) { vSrfStack.emplace_back( pSrfOff->CloneChunk( nCount)) ; if ( nIter == 0) break ; } nCount ++ ; } // recupero la prossima superficie di offset if ( ! vSrfStack.empty() && ( pSrfOff->IsValid() || dOffs < dTRad + EPS_ZERO)) { pSrfOff.Set( Release( vSrfStack.back())) ; vSrfStack.pop_back() ; } bool bNextOk = pSrfOff->IsValid() ; bool bSmallRad = ( nIter == 0 ? dOffs < dTRad + GetOffsR() + EPS_ZERO : dOffs < dTRad + EPS_ZERO) ; // se offset va bene aggiorno pSrfOffOld if ( pSrfOff->IsValid()) pSrfOffOld.Set( pSrfOff->Clone()) ; // se non valido ma riducibile, provo con offset ridotto al raggio utensile else if ( ! bSmallRad) { pSrfOff.Set( pSrfOffOld->Clone()) ; // nuovo valore pari al raggio dOffs = ( nIter == 0 ? dTRad + GetOffsR() : dTRad) ; continue ; } // altrimenti esco else break ; // verifico se circonferenza o circonferenze concentriche bCircleSpiral = CircleSpiral( pSrfOff, bSplitArcs, vOffs, pRCrv) ; if ( bCircleSpiral) break ; // Inserisco le curve che delimitano la superficie di offset nel vettore vOffs in modo che siano ordinate dalla // più esterna alla più interna for ( int nL = 0 ; nL < pSrfOff->GetLoopCount( 0) ; nL ++) { pOffs.Set( GetCurveComposite( pSrfOff->GetLoop( 0, nL))) ; // oriento tutte le curve nello stesso senso if ( nL > 0) pOffs->Invert() ; if ( IsNull( pOffs)) { m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ; return false ; } // Se sono al primo offset inserisco le curve senza preoccuparmi dell'ordine if ( nIter == 0) { vOffs.emplace_back( Release( pOffs)) ; LastExtLoopPos = vOffs.size() - 1 ; } // altrimenti cerco il punto dove aggiungere la curva else { // creo la sua superficie racchiusa dalla curva da inserire PtrOwner pSrfTmp( CreateSurfFlatRegion()) ; if ( IsNull( pSrfTmp) || ! pSrfTmp->AddExtLoop( pOffs->Clone())) vOffs.push_back( Release( pOffs)) ; else { // scorro vOffs fino a quando trovo una curva inclusa nella regione definita da pOffs auto it = vOffs.begin() ; while ( it != vOffs.end()) { CRVCVECTOR ccClass ; // se non riesco a classificare passo alla curva successiva if ( ! pSrfTmp->GetCurveClassification( **it, ccClass)) continue ; if ( ccClass.size() != 1) { m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ; return false ; } if ( ccClass[0].nClass == CRVC_IN) break ; it ++ ; } // Inserisco pOffs in vOffs if ( it != vOffs.end()) { // se loop esterno per quell'offset aggiorno il valore di LastExtCrvPos if ( nL == 0) LastExtLoopPos = it - vOffs.begin() ; vOffs.insert( it, Release( pOffs)) ; } // se non ho trovato in vOffs una curva inclusa nella regione generata da pOffs, inserisco pOffs subito dopo // il loop esterno dell'offset precedente (che si trova in LastExtCrvPos) else { vOffs.insert( vOffs.begin() + LastExtLoopPos + 1, Release( pOffs)) ; // se loop esterno per quell'offset aggiorno il valore di LastExtCrvPos if ( nL == 0) LastExtLoopPos = LastExtLoopPos + 1 ; } } } } // nuovo valore pari allo step dOffs = GetSideStep() ; // incremento contatore iterazioni ++ nIter ; } // start points per le curve Point3d ptOld ; AdjustContourStart( vOffs[0]) ; vOffs[0]->GetEndPoint( ptOld) ; // per le curve successive scelgo come start point quello più vicino all'end point della curva precedente for ( size_t i = 1 ; i < vOffs.size() ; i++) { double dParam ; int nFlag ; if ( DistPointCurve( ptOld, *vOffs[i]).GetParamAtMinDistPoint( 0, dParam, nFlag)) vOffs[i]->ChangeStartPoint( dParam) ; vOffs[i]->GetEndPoint( ptOld) ; } // calcolo la superficie coperta dal tool quando percorre i percorsi in vOffs for ( size_t i = 0 ; ! bCircleSpiral && i < vOffs.size() ; i++) { OffsetCurve OffsCrvPlus ; OffsCrvPlus.Make( vOffs[i], m_TParams.m_dDiam / 2 + 5 * EPS_SMALL, ICurve::OFF_FILLET) ; ICurve * pCrvOffPlus = OffsCrvPlus.GetLongerCurve() ; if ( pCrvOffPlus == nullptr ) { m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, vOffs[i]->Clone()) ; return false ; } ISurfFlatRegion * pSrfTool = CreateSurfFlatRegion() ; pSrfTool->AddExtLoop( pCrvOffPlus) ; if ( OffsCrvPlus.GetCurveCount() > 0) { pCrvOffPlus = GetCurveComposite( OffsCrvPlus.GetCurve()) ; while ( pCrvOffPlus != nullptr) { if ( GetCurveRadius( pCrvOffPlus) > EPS_ZERO) pSrfTool->AddIntLoop( pCrvOffPlus) ; pCrvOffPlus = GetCurveComposite( OffsCrvPlus.GetCurve()) ; } } OffsetCurve OffsCrvMinus ; OffsCrvMinus.Make( vOffs[i], - m_TParams.m_dDiam / 2 - 5 * EPS_SMALL, ICurve::OFF_FILLET) ; ICurveComposite * pCrvOffMinus = GetCurveComposite( OffsCrvMinus.GetLongerCurve()) ; while ( pCrvOffMinus != nullptr) { if ( GetCurveRadius( pCrvOffMinus) > EPS_ZERO) pSrfTool->AddIntLoop( pCrvOffMinus) ; pCrvOffMinus = GetCurveComposite( OffsCrvMinus.GetCurve()) ; } if ( i == 0) pCutRegion = pSrfTool->Clone() ; else pCutRegion->Add( *(pSrfTool->Clone())) ; } // calcolo i collegamenti ICURVEPOVECTOR vLinks( vOffs.size()) ; for ( int i = 1 ; i < int( vOffs.size()) ; ++ i) { // punti di inizio e fine Point3d ptStart ; vOffs[i-1]->GetEndPoint( ptStart) ; Point3d ptEnd ; vOffs[i]->GetStartPoint( ptEnd) ; if ( AreSamePointApprox( ptStart, ptEnd ) ) { vLinks[i].Set( CreateCurveLine()) ; continue ; } // calcolo il collegamento (garantendo che non esca dalla svuotatura) PtrOwner pCrvLink( CreateCurveComposite()) ; if ( CalcBoundedLink( ptStart, ptEnd, pSrfOff1, pCrvLink)) { // Superficie coperta dal tool quando percorre il collegamento const ICurve * pCrvLinkTmp = pCrvLink->GetFirstCurve() ; while ( pCrvLinkTmp != nullptr) { if ( pCrvLinkTmp->GetType() == CRV_LINE) { Point3d ptS, ptE ; pCrvLinkTmp->GetStartPoint( ptS) ; pCrvLinkTmp->GetEndPoint( ptE) ; ICurveComposite * pCrvTmp = CreateCurveComposite() ; pCrvTmp->AddPoint( ptS) ; pCrvTmp->AddLine( ptE) ; pCrvTmp->AddLine( ptS) ; pCrvTmp->SetExtrusion( vtExtr) ; OffsetCurve OffsCrvPlus ; OffsCrvPlus.Make( pCrvTmp, m_TParams.m_dDiam / 2 + 10 * EPS_SMALL, ICurve::OFF_FILLET) ; ICurve * pCrvOffPlus = OffsCrvPlus.GetLongerCurve() ; ISurfFlatRegion * pSrf = CreateSurfFlatRegion() ; pSrf->AddExtLoop( pCrvOffPlus) ; pCutRegion->Add( *(pSrf->Clone())) ; } pCrvLinkTmp = pCrvLink->GetNextCurve() ; } // aggiungo il collegamento vLinks[i].Set( Release( pCrvLink)) ; } else { m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ; return false ; } } m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCutRegion->Clone()) ; // rimuovo le aree non lavorate if ( pCutRegion->GetLoopCount( 0) > pSrfOff1->GetLoopCount( nReg)) { if ( ! RemoveUncutRegions( pCutRegion, vOffs, pSrfOff1->CloneChunk( nReg))) { m_pMchMgr->SetLastError( 2413, "Error in Pocketing : removal of uncut regions failed") ; return false ; } } // calcolo il percorso di ritorno if ( vOffs.size() >= 2) { pRCrv->Clear() ; // punti di inizio e fine Point3d ptStart ; vOffs.back()->GetEndPoint( ptStart) ; Point3d ptEnd ; vOffs.front()->GetStartPoint( ptEnd) ; // calcolo il ritorno (garantendo che non esca dalla svuotatura) PtrOwner pCrvLink( CreateCurveComposite()) ; if ( CalcBoundedLink( ptStart, ptEnd, pSrfOff1, pCrvLink)) { pRCrv->AddCurve( Release( pCrvLink)) ; pRCrv->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL, false) ; // se necessario, approssimo archi con rette if ( bSplitArcs && ! ApproxWithLines( pRCrv)) { m_pMchMgr->SetLastError( 2421, "Error in Pocketing : Linear Approx not computable") ; return false ; } VerifyArcs( pRCrv) ; } else { m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ; return false ; } } // creo il percorso di lavoro a partire dalla raccolta degli offset e dei collegamenti for ( int i = 0 ; i < int( vOffs.size()) ; ++ i) { // se collegamento da aggiungere if ( ! IsNull( vLinks[i])) { // accodo nel percorso di lavorazione pMCrv->AddCurve( Release( vLinks[i])) ; } // se richiesta percorrenza invertita if ( m_Params.m_bInvert) vOffs[i]->Invert() ; // aggiungo la curva pMCrv->AddCurve( Release( (PtrOwner)vOffs[i])) ; } // verifico il percorso di lavoro if ( pMCrv->GetCurveCount() == 0) { m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ; return false ; } // se necessario, approssimo archi con rette if ( bSplitArcs && ! ApproxWithLines( pMCrv)) { m_pMchMgr->SetLastError( 2421, "Error in Pocketing : Linear Approx not computable") ; return false ; } // eventuale sistemazione archi VerifyArcs( pMCrv) ; return true ; } //---------------------------------------------------------------------------- bool Pocketing::CalcBoundedLink( const Point3d& ptStart, const Point3d& ptEnd, const ISurfFlatRegion* pSrf, ICurveComposite* pCrvLink) { // creo la retta PtrOwner pLine( CreateCurveLine()) ; if ( IsNull( pLine) || ! pLine->Set( ptStart, ptEnd)) { return false ; } // classifico la curva di collegamento rispetto alla superficie di contenimento CRVCVECTOR ccClass ; pSrf->GetCurveClassification( *pLine, ccClass) ; // se nessuno o un solo tratto e interno, la retta è il collegamento if ( ccClass.empty() || ( ccClass.size() == 1 && ccClass[0].nClass == CRVC_IN)) { pCrvLink->AddCurve( Release( pLine)) ; return true ; } // altrimenti combino i tratti interni di retta con tratti opportuni delle curve che delimitano la superficie di contenimento else { PtrOwner pCompo( CreateCurveComposite()) ; if ( IsNull( pCompo)) return false ; // curve che delimitano la superficie ICURVEPOVECTOR vpCrvBound ; for ( int nC = 0 ; nC < pSrf->GetChunkCount() ; nC ++) for ( int nL = 0 ; nL < pSrf->GetLoopCount( nC) ; nL ++) vpCrvBound.emplace_back( pSrf->GetLoop( nC, nL)) ; for ( int j = 0 ; j < int( ccClass.size()) ; j++) { if ( ccClass[j].nClass == CRVC_IN || ccClass[j].nClass == CRVC_ON_P || ccClass[j].nClass == CRVC_ON_M) pCompo->AddCurve( pLine->CopyParamRange( ccClass[j].dParS, ccClass[j].dParE)) ; else if ( ccClass[j].nClass == CRVC_OUT) { Point3d ptS ; pLine->GetPointD1D2( ccClass[j].dParS, ICurve::FROM_PLUS, ptS) ; double dOffS ; // cerco la curva dell'offset che passa per ptS bool bFound = false ; size_t CrvIdx ; auto it = vpCrvBound.begin() ; for ( size_t k = 0 ; ! bFound && k < vpCrvBound.size() ; k++) { bFound = vpCrvBound[k]->GetParamAtPoint( ptS, dOffS) ; if ( bFound) CrvIdx = k ; } if ( ! bFound) { m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ; return false ; } Point3d ptE ; pLine->GetPointD1D2( ccClass[j].dParE, ICurve::FROM_MINUS, ptE) ; double dOffE ; // ptE deve trovarsi sulla stessa curva di ptS bFound = vpCrvBound[CrvIdx]->GetParamAtPoint( ptE, dOffE) ; // se non lo trovo sulla curva di ptS, cerco in ccClass un altro intervallo il cui ptE si trova sulla curva di ptS if ( ! bFound) { while ( ! bFound && j < int( ccClass.size()) - 1) { j ++ ; pLine->GetPointD1D2( ccClass[j].dParE, ICurve::FROM_MINUS, ptE) ; bFound = vpCrvBound[CrvIdx]->GetParamAtPoint( ptE, dOffE) ; } // se intervallo non esiste, è errore if ( ! bFound) { m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ; return false ; } } // recupero i due possibili percorsi e uso il più corto PtrOwner pCrvA( vpCrvBound[CrvIdx]->CopyParamRange( dOffS, dOffE)) ; PtrOwner pCrvB( vpCrvBound[CrvIdx]->CopyParamRange( dOffE, dOffS)) ; if ( IsNull( pCrvA) || IsNull( pCrvB)) return false ; double dLenA ; pCrvA->GetLength( dLenA) ; double dLenB ; pCrvB->GetLength( dLenB) ; if ( dLenA < dLenB) { pCompo->AddCurve( Release( pCrvA)) ; } else { pCrvB->Invert() ; pCompo->AddCurve( Release( pCrvB)) ; } } } pCrvLink->AddCurve( Release( pCompo)) ; return true ; } } // ---------------------------------------------------------------------------- bool Pocketing::CircleSpiral( ISurfFlatRegion* pSrf, bool bSplitArcs, ICRVCOMPOPVECTOR& vOffs, ICurveComposite * pRCrv) { int nLoops = pSrf->GetLoopCount( 0) ; // posso usare CalcCircleSpiral se al massimo ci sono due circonferenze concentriche if ( nLoops > 2) return false ; ICurveComposite * pExt = GetCurveComposite( pSrf->GetLoop( 0, 0)) ; Point3d ptCen ; Vector3d vtN ; double dRad ; bool bCCW ; // verifico sia circonferenza if ( ! pExt->IsACircle( 10 * EPS_SMALL, ptCen, vtN, dRad, bCCW )) return false ; vOffs.emplace_back( CreateCurveComposite()) ; // se ho solo il loop esterno if ( nLoops == 1) { double dIntRad = 0 ; if ( m_Params.m_nSubType == POCKET_SUB_SPIRALOUT && GetLeadInType() == POCKET_LI_HELIX) { dIntRad = min( 0.5 * min( m_Params.m_dLiTang, m_TParams.m_dDiam), dRad ) ; m_dMaxHelixRad = dIntRad ; } return CalcCircleSpiral( ptCen, vtN, dRad, dIntRad, bSplitArcs, vOffs[0], pRCrv) ; } // se ho anche un loop interno, verifico sia una circonfernza concentrica al loop esterno ICurveComposite * pInt = GetCurveComposite( pSrf->GetLoop( 0, 1)) ; Point3d ptCen2 ; Vector3d vtN2 ; double dRad2 ; bool bCCW2 ; if ( ! pInt->IsACircle( 100 * EPS_SMALL, ptCen2, vtN2, dRad2, bCCW2) || ! AreSamePointEpsilon( ptCen, ptCen2, EPS_SMALL)) return false ; if ( m_Params.m_nSubType == POCKET_SUB_SPIRALOUT && GetLeadInType() == POCKET_LI_HELIX) { m_dMaxHelixRad = min( 0.5 * min( m_Params.m_dLiTang, m_TParams.m_dDiam), dRad - dRad2) ; } return CalcCircleSpiral( ptCen, vtN, dRad, dRad2, bSplitArcs, vOffs[0], pRCrv) ; } //---------------------------------------------------------------------------- bool Pocketing::CalcCircleSpiral( const Point3d& ptCen, const Vector3d& vtN, double dOutRad, double dIntRad, bool bSplitArcs, ICurveComposite* pMCrv, ICurveComposite* pRCrv) { // raggio della circonferenza esterna if ( dOutRad < 10 * EPS_SMALL) { m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ; return false ; } // imposto versore estrusione sulle curve composite pMCrv->SetExtrusion( vtN) ; pRCrv->SetExtrusion( vtN) ; // creo e inserisco la circonferenza esterna PtrOwner pArc( CreateCurveArc()) ; if ( IsNull( pArc) || ! pArc->Set( ptCen, vtN, dOutRad)) { m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ; return false ; } Vector3d vtDir = pArc->GetStartVersor() ; pMCrv->AddCurve( Release( pArc)) ; // se richiesta percorrenza invertita if ( m_Params.m_bInvert) pMCrv->Invert() ; // se raggio esterno maggiore dell'interno if ( dOutRad > dIntRad + 10 * EPS_SMALL) { // aggiungo le semicirconferenze della spirale ( devono essere in numero dispari) int nStep = int( ceil( ( dOutRad - dIntRad) / ( 0.5 * GetSideStep()))) ; if ( IsEven( nStep)) nStep += 1 ; double dStep = ( dOutRad - dIntRad) / nStep ; for ( int i = 1 ; i <= nStep ; ++ i) { if ( ! IsEven( i)) pMCrv->AddArcTg( ptCen - vtDir * ( dOutRad - i * dStep)) ; else pMCrv->AddArcTg( ptCen + vtDir * ( dOutRad - i * dStep)) ; } // aggiungo la circonferenza interna pMCrv->AddArcTg( ptCen + vtDir * dIntRad) ; pMCrv->AddArcTg( ptCen - vtDir * dIntRad) ; } // verifico il percorso di lavoro if ( pMCrv->GetCurveCount() == 0) { m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ; return false ; } // se necessario, approssimo con rette if ( bSplitArcs && ! ApproxWithLines( pMCrv)) { m_pMchMgr->SetLastError( 2421, "Error in Pocketing : Linear Approx not computable") ; return false ; } // eventuale sistemazione archi VerifyArcs( pMCrv) ; // calcolo l'eventuale percorso di ritorno Point3d ptStart ; pMCrv->GetStartPoint( ptStart) ; Point3d ptEnd ; pMCrv->GetEndPoint( ptEnd) ; Vector3d vtStart ; pMCrv->GetStartDir( vtStart) ; if ( ! AreSamePointApprox( ptStart, ptEnd)) { PtrOwner pArc2( CreateCurveArc()) ; if ( IsNull( pArc2) || ! pArc2->Set2PVN( ptStart, ptEnd, - vtStart, vtN)) { m_pMchMgr->SetLastError( 2420, "Error in Pocketing : Return toolpath not computable") ; return false ; } pRCrv->AddCurve( Release( pArc2)) ; // inverto e eventualmente sistemo archi pRCrv->Invert() ; VerifyArcs( pRCrv) ; } return true ; } //---------------------------------------------------------------------------- bool Pocketing::AddApproach( const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dSafeAggrBottZ, double dElev, double dAppr, bool bOutStart) { SetFlag( 1) ; // se con aggregato da sotto if ( m_bAggrBottom) { // aggiuntivo in Z double dAggZ = max( dElev + max( dSafeAggrBottZ, dAppr), 0.) ; // distanza dal bordo del pezzo double dDistBottom ; if ( ! GetDistanceFromRawSide( m_nPhase, ptP, m_vtAggrBottom, dDistBottom)) dDistBottom = 0 ; // pre-approccio Point3d ptP0 = ptP - Z_AX * dAggZ + m_vtAggrBottom * ( dDistBottom + m_AggrBottom.dEncH + dSafeZ) ; Point3d ptP00 = ptP0 + Z_AX * ( m_AggrBottom.dEncV + m_TParams.m_dLen + dAggZ - dElev) ; // se rinvio da sotto che richiede speciale rotazione if ( m_AggrBottom.nType == 1) { Vector3d vtAux = m_vtAggrBottom ; vtAux.Rotate( Z_AX, 0, 1) ; SetAuxDir( vtAux) ; if ( AddRapidStart( ptP00, MCH_CL_AGB_DWN) == GDB_ID_NULL) return false ; SetAuxDir( m_vtAggrBottom) ; SetFlag( 0) ; if ( AddRapidMove( ptP0, MCH_CL_AGB_IN) == GDB_ID_NULL) return false ; } // altrimenti rinvio normale else { SetAuxDir( m_vtAggrBottom) ; if ( AddRapidStart( ptP0, MCH_CL_AGB_IN) == GDB_ID_NULL) return false ; SetFlag( 0) ; } } // se sopra attacco c'è spazio per sicurezza o approccio double dSafeDist = ( m_bAggrBottom ? dSafeAggrBottZ : 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 ( ( ! m_bAggrBottom && AddRapidStart( ptP1) == GDB_ID_NULL) || ( m_bAggrBottom && AddRapidMove( ptP1) == GDB_ID_NULL)) return false ; } else { // 1a -> punto sopra inizio Point3d ptP1b = ptP + vtTool * ( dElev + dAppr) ; Point3d ptP1a = ptP1b + vtTool * ( dSafeDist - dAppr) ; if ( ( ! m_bAggrBottom && AddRapidStart( ptP1a) == GDB_ID_NULL) || ( m_bAggrBottom && AddRapidMove( 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( bOutStart ? GetStartFeed() : GetTipFeed()) ; if ( AddLinearMove( ptP) == GDB_ID_NULL) return false ; } else { // affondo diretto al punto iniziale SetFlag( 0) ; if ( ( ! m_bAggrBottom && AddRapidStart( ptP) == GDB_ID_NULL) || ( m_bAggrBottom && AddRapidMove( ptP) == GDB_ID_NULL)) return false ; } return true ; } //---------------------------------------------------------------------------- bool Pocketing::AddLinkApproach( const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dSafeAggrBottZ, double dElev, double dAppr) { // 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( 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 Pocketing::AddLinkRetract( const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dSafeAggrBottZ, 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 Pocketing::AddRetract( const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dSafeAggrBottZ, double dElev, double dAppr) { // se sopra uscita c'è spazio per sicurezza o approccio double dSafeDist = ( m_bAggrBottom ? dSafeAggrBottZ : 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 ; } } // se con aggregato da sotto if ( m_bAggrBottom) { // aggiuntivo in Z double dAggZ = max( dElev + max( dSafeAggrBottZ, dAppr), 0.) ; // distanza dal bordo del pezzo double dDistBottom ; if ( ! GetDistanceFromRawSide( m_nPhase, ptP, m_vtAggrBottom, dDistBottom)) dDistBottom = 0 ; // post-retract Point3d ptP0 = ptP - Z_AX * dAggZ + m_vtAggrBottom * ( dDistBottom + m_AggrBottom.dEncH + dSafeZ) ; Point3d ptP00 = ptP0 + Z_AX * ( m_AggrBottom.dEncV + m_TParams.m_dLen + dAggZ - dElev) ; if ( AddRapidMove( ptP0, MCH_CL_AGB_OUT) == GDB_ID_NULL) return false ; // se rinvio da sotto che richiede speciale rotazione if ( m_AggrBottom.nType == 1) { Vector3d vtAux = m_vtAggrBottom ; vtAux.Rotate( Z_AX, 0, 1) ; SetAuxDir( vtAux) ; if ( AddRapidMove( ptP00, MCH_CL_AGB_UP) == GDB_ID_NULL) return false ; } } return true ; } //---------------------------------------------------------------------------- bool Pocketing::CalcLeadInStart( const Point3d& ptStart, const Vector3d& vtStart, const Vector3d& vtN, const ICurveComposite* pRCrv, Point3d& ptP1) const { // Assegno tipo e parametri int nType = GetLeadInType() ; if ( nType == POCKET_LI_GLIDE && ( pRCrv == nullptr || pRCrv->GetCurveCount() == 0)) nType = POCKET_LI_NONE ; // senso di rotazione da dir tg a dir esterna bool bCcwRot = true ; // Calcolo punto iniziale switch ( nType) { case POCKET_LI_NONE : case POCKET_LI_ZIGZAG : case POCKET_LI_HELIX : ptP1 = ptStart ; return true ; case POCKET_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 += vtN * ( vtN * ( ptStart - ptP1)) ; return true ; } default : return false ; } } //---------------------------------------------------------------------------- bool Pocketing::AddLeadIn( const Point3d& ptP1, const Point3d& ptStart, const Vector3d& vtStart, const Vector3d& vtN, const ISurfFlatRegion* pSrf, const ICurveComposite* pRCrv, bool bAtLeft, bool bSplitArcs, bool bNoneForced) { // Assegno il tipo int nType = GetLeadInType() ; if ( bNoneForced || AreSamePointEpsilon( ptP1, ptStart, 10 * EPS_SMALL) || ( nType == POCKET_LI_GLIDE && ( pRCrv == nullptr || pRCrv->GetCurveCount() == 0))) nType = POCKET_LI_NONE ; // Se elica e fattibile lo creo if ( nType == POCKET_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 + 10 * EPS_SMALL)) * ( bAtLeft ? ANG_FULL : - ANG_FULL) ; // verifico se fattibile if ( VerifyLeadInHelix( pSrf, ptCen, dRad)) { // creo l'elica PtrOwner pArc( CreateCurveArc()) ; if ( IsNull( pArc) || ! pArc->Set( ptCen, vtN, dRad, - vtCen, dAngCen, dDeltaN)) return false ; // eventuale spezzatura if ( bSplitArcs) { PtrOwner pCompo( CreateCurveComposite()) ; if ( IsNull( pCompo) || ! pCompo->AddCurve( Release( pArc)) || ! ApproxWithLines( pCompo)) return false ; return ( AddCurveMove( pCompo, MCH_CL_LEADIN) != GDB_ID_NULL) ; } else { // emetto l'elica return ( AddCurveMove( pArc, MCH_CL_LEADIN) != GDB_ID_NULL) ; } } // altrimenti zigzag else nType = POCKET_LI_ZIGZAG ; } // Se zigzag e fattibile lo creo if ( nType == POCKET_LI_ZIGZAG) { // dati dello zigzag double dDeltaN = ( ptStart - ptP1) * vtN ; int nStep = int( ceil( - dDeltaN / ( m_Params.m_dLiElev + 10 * 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 ( VerifyLeadInZigZag( pSrf, ptPa, ptPb)) { for ( int i = 1 ; i <= nStep ; ++ i) { if ( AddLinearMove( ptPa - vtN * ( i - 0.75) * dStep, MCH_CL_LEADIN) == GDB_ID_NULL) return false ; if ( AddLinearMove( ptPb - vtN * ( i - 0.25) * dStep, MCH_CL_LEADIN) == GDB_ID_NULL) return false ; } return ( AddLinearMove( ptStart, MCH_CL_LEADIN) != GDB_ID_NULL) ; } // altrimenti diretto else nType = POCKET_LI_NONE ; } // Se a scivolo e fattibile if ( nType == POCKET_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( CreateCurveComposite()) || ! pCrv->AddCurve( 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) ; // eventuale spezzatura if ( bSplitArcs && ! ApproxWithLines( pCrv)) return false ; // emetto return ( AddCurveMove( pCrv) != GDB_ID_NULL) ; } // altrimenti diretto else nType = POCKET_LI_NONE ; } // Se diretto if ( nType == POCKET_LI_NONE) { Point3d ptCurr = ptP1 ; GetCurrPos( ptCurr) ; if ( ! AreSamePointApprox( ptCurr, ptStart)) { if ( AddLinearMove( ptStart, MCH_CL_LEADIN) == GDB_ID_NULL) return false ; } return true ; } // Altrimenti errore return false ; } //---------------------------------------------------------------------------- bool Pocketing::AddLeadOut( const Point3d& ptEnd, const Vector3d& vtEnd, const Vector3d& vtN, const ICurveComposite* pRCrv, bool bSplitArcs, Point3d& ptP1, double& dElev, bool bNoneForced) { // assegno i parametri int nType = GetLeadOutType() ; if ( bNoneForced || ( nType == POCKET_LO_GLIDE && ( pRCrv == nullptr || pRCrv->GetCurveCount() == 0))) nType = POCKET_LO_NONE ; // eseguo a seconda del tipo switch ( nType) { case POCKET_LO_NONE : { // nessuna uscita ptP1 = ptEnd ; // determino elevazione su fine uscita double dEndElev ; if ( GetElevation( m_nPhase, ptP1 - 10 * EPS_SMALL * vtN, vtN, GetRadiusForStartEndElevation(), vtN, dEndElev)) dElev = dEndElev ; // correzione per punto sotto il grezzo con testa normale da sopra double dSafeZ = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeZ() ; bool bUnderEnd = m_bAboveHead && ! m_bAggrBottom && GetPointUnderRaw( ptP1, vtN, 0, GetRadiusForStartEndElevation(), m_TParams.m_dLen, false, dSafeZ, dElev) ; return true ; } case POCKET_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( CreateCurveComposite()) || ! pCrv->AddCurve( 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) ; // eventuale spezzatura if ( bSplitArcs && ! ApproxWithLines( pCrv)) return false ; // emetto AddCurveMove( pCrv) ; // determino elevazione su fine uscita ptP1 = ptFin ; double dEndElev ; if ( GetElevation( m_nPhase, ptP1 - 10 * EPS_SMALL * vtN, vtN, GetRadiusForStartEndElevation(), vtN, dEndElev)) dElev = dEndElev ; // correzione per punto sotto il grezzo con testa normale da sopra double dSafeZ = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeZ() ; bool bUnderEnd = m_bAboveHead && ! m_bAggrBottom && GetPointUnderRaw( ptP1, vtN, 0, GetRadiusForStartEndElevation(), m_TParams.m_dLen, false, dSafeZ, dElev) ; return true ; } default : return false ; } } //---------------------------------------------------------------------------- double Pocketing::GetRadiusForStartEndElevation( void) const { const double DELTA_ELEV_RAD = 20.0 ; return ( 0.5 * m_TParams.m_dTDiam + min( 0.25 * m_TParams.m_dTDiam, DELTA_ELEV_RAD)) ; } //---------------------------------------------------------------------------- bool Pocketing::GetMidOfLongestOpenSide( const ICurveComposite* pCompo, Point3d& ptMid, Vector3d& vtMidOrt) { // recupero il vettore estrusione Vector3d vtExtr = Z_AX ; pCompo->GetExtrusion( vtExtr) ; // verifico se tutti i lati sono aperti bool bAllOpen = true ; const ICurve* pMyCrv = pCompo->GetFirstCurve() ; while ( pMyCrv != nullptr) { if ( pMyCrv->GetTempProp() != 1) { bAllOpen = false ; break ; } pMyCrv = pCompo->GetNextCurve() ; } // richiedo lunghezza superiore a diametro utensile più doppio offset radiale double dMaxLen = ( bAllOpen ? 0 : m_TParams.m_dDiam + 2 * GetOffsR() - EPS_SMALL) ; // ciclo sulle singole curve bool bFound = false ; const ICurve* pPrevCrv = pCompo->GetLastCurve() ; double dLenPrev = 0 ; if ( pPrevCrv != nullptr && pPrevCrv->GetTempProp() == 1) pPrevCrv->GetLength( dLenPrev) ; const ICurve* pCrv = pCompo->GetFirstCurve() ; while ( pCrv != nullptr) { // analizzo la curva successiva const ICurve* pNextCrv = pCompo->GetNextCurve() ; bool bNextOk = ( pNextCrv != nullptr) ; if ( ! bNextOk) pNextCrv = pCompo->GetFirstCurve() ; double dLenNext = 0 ; if ( pNextCrv != nullptr && pNextCrv->GetTempProp() == 1) pNextCrv->GetLength( dLenNext) ; // verifico la curva corrente if ( pCrv->GetTempProp() == 1) { // contributo dalle entità adiacenti (se non tutte aperte) double dLenAgg = 0 ; if ( ! bAllOpen) { if ( pPrevCrv != nullptr && pPrevCrv->GetTempProp() == 1) { Vector3d vtPrevEnd ; pPrevCrv->GetEndDir( vtPrevEnd) ; Vector3d vtStart ; pCrv->GetStartDir( vtStart) ; dLenAgg += max( 0., vtPrevEnd * vtStart * dLenPrev) ; } if ( pNextCrv != nullptr && pNextCrv->GetTempProp() == 1) { Vector3d vtEnd ; pCrv->GetEndDir( vtEnd) ; Vector3d vtNextStart ; pNextCrv->GetStartDir( vtNextStart) ; dLenAgg += max( 0., vtEnd * vtNextStart * dLenNext) ; } } // entità corrente double dLen = 0 ; if ( pCrv->GetLength( dLen) && dLen + dLenAgg > dMaxLen) { dMaxLen = dLen + dLenAgg ; pCrv->GetMidPoint( ptMid) ; // vettore ortogonale verso l'esterno (ruotato -90deg rispetto a estrusione) pCrv->GetMidDir( vtMidOrt) ; vtMidOrt.Rotate( vtExtr, 0, -1) ; bFound = true ; } dLenPrev = dLen ; } else dLenPrev = 0 ; // vado alla successiva pPrevCrv = pCrv ; pCrv = ( bNextOk ? pNextCrv : nullptr) ; } return bFound ; } //---------------------------------------------------------------------------- bool Pocketing::AdjustContourWithOpenEdges( ICurveComposite* pCompo) { // vettore estrusione Vector3d vtExtr ; pCompo->GetExtrusion( vtExtr) ; // calcolo riferimento nel piano della svuotatura Frame3d frPocket ; Point3d ptStart ; pCompo->GetStartPoint( ptStart) ; frPocket.Set( ptStart, vtExtr) ; // sposto l'inizio a metà del tratto più lungo AdjustContourStart( pCompo) ; // raggio di riferimento per offset double dRad = 0.5 * m_TParams.m_dDiam + GetOffsR() ; // estraggo tutte le curve in un vettore ICURVEPOVECTOR vpCrvs ; vpCrvs.reserve( pCompo->GetCurveCount()) ; while ( pCompo->GetCurveCount() > 0) vpCrvs.emplace_back( pCompo->RemoveFirstOrLastCurve( false)) ; // elimino le curve troppo corte (10 epsilon) for ( int i = 0 ; i < int( vpCrvs.size()) ;) { double dLen = 0 ; vpCrvs[i]->GetLength( dLen) ; if ( dLen < 10 * EPS_SMALL) vpCrvs.erase( vpCrvs.begin() + i) ; else ++ i ; } // offsetto del raggio le curve aperte for ( int i = 0 ; i < int( vpCrvs.size()) ; ++ i) { if ( vpCrvs[i]->GetTempProp() == 1) vpCrvs[i]->SimpleOffset( dRad) ; } // reinserisco le curve, chiudendo eventuali gap bool bOpenCurr = false ; double dDiam = 1.05 * m_TParams.m_dDiam + 2 * GetOffsR() ; for ( int i = 0 ; i < int( vpCrvs.size()) ; ++ i) { // stato curve bool bOpenPrev = bOpenCurr ; bOpenCurr = ( vpCrvs[i]->GetTempProp() != 0) ; // chiudo eventuale gap if ( i > 0) { Point3d ptEnd ; pCompo->GetEndPoint( ptEnd) ; Point3d ptStart ; vpCrvs[i]->GetStartPoint( ptStart) ; if ( ! AreSamePointEpsilon( ptEnd, ptStart, 10 * EPS_SMALL)) { // se passo da chiuso ad aperto if ( ! bOpenPrev && bOpenCurr) { // determino la curva ad amo Vector3d vtTg ; pCompo->GetEndDir( vtTg) ; Vector3d vtOrt = vtTg ; vtOrt.Rotate( vtExtr, 0, 1) ; Point3d ptArc = ptEnd + dDiam * vtOrt ; Point3d ptLine = ptArc - 5 * dDiam * vtTg ; PtrOwner pJCrv( CreateCurveComposite()) ; if ( IsNull( pJCrv)) return false ; pJCrv->SetExtrusion( vtExtr) ; pJCrv->AddPoint( ptLine) ; pJCrv->AddLine( ptArc, false) ; pJCrv->AddArcTg( ptEnd, false) ; // calcolo l'intersezione nel piano della svuotatura dell'amo con la curva aperta pJCrv->ToLoc( frPocket) ; vpCrvs[i]->ToLoc( frPocket) ; IntersCurveCurve intCC( *pJCrv, *vpCrvs[i]) ; pJCrv->ToGlob( frPocket) ; vpCrvs[i]->ToGlob( frPocket) ; // taglio opportunamente le curve IntCrvCrvInfo aInfo ; if ( intCC.GetIntCrvCrvInfo( intCC.GetIntersCount() - 1, aInfo)) { pJCrv->TrimEndAtParam( aInfo.IciA[0].dU) ; vpCrvs[i]->TrimStartAtParam( aInfo.IciB[0].dU) ; pCompo->AddCurve( ::Release( pJCrv), true, 10 * EPS_SMALL) ; } else pCompo->AddLine( ptStart) ; } // se passo da aperto a chiuso else if ( bOpenPrev && ! bOpenCurr) { // determino la curva ad amo Vector3d vtTg ; vpCrvs[i]->GetStartDir( vtTg) ; Vector3d vtOrt = vtTg ; vtOrt.Rotate( vtExtr, 0, 1) ; Point3d ptArc = ptStart + dDiam * vtOrt ; Point3d ptLine = ptArc + 5 * dDiam * vtTg ; PtrOwner pJCrv( CreateCurveComposite()) ; if ( IsNull( pJCrv)) return false ; pJCrv->SetExtrusion( vtExtr) ; pJCrv->AddPoint( ptLine) ; pJCrv->AddLine( ptArc) ; pJCrv->AddArcTg( ptStart) ; // calcolo l'intersezione nel piano della svuotatura dell'amo con la curva aperta PtrOwner pLCrv( CreateCurveComposite()) ; if ( IsNull( pLCrv)) return false ; pLCrv->AddCurve( pCompo->GetLastCurve()->Clone()) ; if ( pCompo->GetCurveCount() >= 2) pLCrv->AddCurve( pCompo->GetPrevCurve()->Clone(), false) ; double dUL = pLCrv->GetCurveCount() ; pJCrv->ToLoc( frPocket) ; pLCrv->ToLoc( frPocket) ; IntersCurveCurve intCC( *pJCrv, *pLCrv) ; pJCrv->ToGlob( frPocket) ; pLCrv->ToGlob( frPocket) ; // taglio opportunamente le curve IntCrvCrvInfo aInfo ; if ( intCC.GetIntCrvCrvInfo( 0, aInfo)) { double dUs, dUe ; pCompo->GetDomain( dUs, dUe) ; pCompo->TrimEndAtParam( dUe - dUL + aInfo.IciB[0].dU) ; pJCrv->TrimStartAtParam( aInfo.IciA[0].dU) ; pCompo->AddCurve( ::Release( pJCrv), true, 10 * EPS_SMALL) ; } else pCompo->AddLine( ptStart) ; } else pCompo->AddLine( ptStart) ; } } // aggiungo la curva pCompo->AddCurve( ::Release( vpCrvs[i]), true, 10 * EPS_SMALL) ; } // non dovrebbe esserci un gap, ma meglio prevenire problemi pCompo->Close() ; return true ; } //---------------------------------------------------------------------------- bool Pocketing::AdjustContourStart( ICurveComposite* pCompo) { // cerco il tratto lineare più lungo int i = 0 ; double dLenMax = 0 ; int nMax = - 1 ; const ICurve* pCrv = pCompo->GetFirstCurve() ; while ( pCrv != nullptr) { double dLen = 0 ; if ( pCrv->GetType() == CRV_LINE && pCrv->GetLength( dLen) && dLen > dLenMax) { dLenMax = dLen ; nMax = i ; } ++ i ; pCrv = pCompo->GetNextCurve() ; } // se non trovato o troppo corto, cerco il tratto generico pi� lungo if ( nMax < 0 || dLenMax < 2 * m_TParams.m_dDiam) { i = 0 ; pCrv = pCompo->GetFirstCurve() ; while ( pCrv != nullptr) { double dLen ; if ( pCrv->GetType() != CRV_LINE && pCrv->GetLength( dLen) && dLen > dLenMax) { dLenMax = dLen ; nMax = i ; } ++ i ; pCrv = pCompo->GetNextCurve() ; } } // sposto inizio a metà del tratto più lungo bool bOk = true ; if ( nMax >= 0) bOk = pCompo->ChangeStartPoint( nMax + 0.5) ; return bOk ; } //---------------------------------------------------------------------------- bool Pocketing::VerifyLeadInHelix( const ISurfFlatRegion* pSrf, const Point3d& ptCen, double dRad) const { // recupero il piano della curva di contorno ICurve * pCrv = pSrf->GetLoop( 0, 0) ; Point3d ptStart ; Vector3d vtN ; if ( pCrv == nullptr || ! pCrv->GetStartPoint( ptStart) || ! pCrv->GetExtrusion( vtN)) return false ; // porto il centro sullo stesso piano del contorno Point3d ptCenL = ptCen - ( ptCen - ptStart) * vtN * vtN ; // calcolo la distanza del centro da tutti i contorni DBLVECTOR vMinDist ; double val ; for ( int nC = 0 ; nC < pSrf->GetChunkCount() ; nC ++) { for ( int nL = 0 ; nL < pSrf->GetLoopCount( nC) ; nL ++) { if ( ! DistPointCurve( ptCenL, *( pSrf->GetLoop( nC, nL))).GetDist( val)) return false ; vMinDist.push_back( val) ; } } // cerco la distanza minima double dMinDist = *min_element( vMinDist.begin(), vMinDist.end()) ; return ( dMinDist > dRad + 0.5 * m_TParams.m_dDiam - 10 * EPS_SMALL) ; } //---------------------------------------------------------------------------- bool Pocketing::VerifyLeadInZigZag( const ISurfFlatRegion* pSrf, const Point3d& ptPa, const Point3d& ptPb) const { // recupero il piano della curva di contorno ICurve * pCrv = pSrf->GetLoop( 0, 0) ; Point3d ptStart ; Vector3d vtN ; if ( pCrv == nullptr || ! pCrv->GetStartPoint( ptStart) || ! pCrv->GetExtrusion( vtN)) return false ; // porto i punti sullo stesso piano del contorno Point3d ptPaL = ptPa - ( ptPa - ptStart) * vtN * vtN ; Point3d ptPbL = ptPb - ( ptPb - ptStart) * vtN * vtN ; // calcolo la distanza dei due punti da tutti i contorni DBLVECTOR vMinDistPa ; DBLVECTOR vMinDistPb ; double val ; for ( int nC = 0 ; nC < pSrf->GetChunkCount() ; nC ++) { for ( int nL = 0 ; nL < pSrf->GetLoopCount( nC) ; nL++) { if ( ! DistPointCurve( ptPaL, *( pSrf->GetLoop( nC, nL))).GetDist( val)) return false ; vMinDistPa.push_back( val) ; if ( ! DistPointCurve( ptPbL, *( pSrf->GetLoop( nC, nL))).GetDist( val)) return false ; vMinDistPb.push_back( val) ; } } // cerco le distanze minime double dMinDistPa = *min_element( vMinDistPa.begin(), vMinDistPa.end()) ; double dMinDistPb = *min_element( vMinDistPb.begin(), vMinDistPb.end()) ; return ( dMinDistPa > 0.5 * m_TParams.m_dDiam - 10 * EPS_SMALL && dMinDistPb > 0.5 * m_TParams.m_dDiam - 10 * EPS_SMALL) ; } //---------------------------------------------------------------------------- bool Pocketing::RemoveUncutRegions( const ISurfFlatRegion * pCutRegion, ICRVCOMPOPVECTOR& vOffs, const ISurfFlatRegion * pSrfBound) { // Conservo le curve vOffs originali in vettore Tmp da usare per i calcoli sui percorsi aggiuntivi ICRVCOMPOPOVECTOR vOffsTmp( vOffs.size()) ; for ( size_t i = 0 ; i < vOffs.size() ; i++) vOffsTmp[i].Set( vOffs[i]->Clone()) ; ISurfFlatRegion * pNewCutRegion = pCutRegion->Clone() ; bool bAddedPaths = false ; // analizzo tutte le aree non lavorate int nLoops = pCutRegion->GetLoopCount( 0) ; for ( int i = 1 ; i < nLoops ; i++) { ICurve * pResidualCrv = pCutRegion->GetLoop( 0, i) ; // verifico che la curva corrisponda ad una regione non lavorata CRVCVECTOR ccClass ; pSrfBound->GetCurveClassification( *pResidualCrv, ccClass) ; if ( ccClass[0].nClass != CRVC_IN) continue ; if ( pResidualCrv == nullptr || ! pResidualCrv->IsValid()) continue ; // cerco la curva di vOffs su cui andrà il percorso aggiuntivo size_t idx ; // indice della curva in vOffs Point3d ptCrit ; // punto in cui aggiungere il percorso extra double dParCrit ; // parametro corrispondente a ptCrit if ( ! FindCurveForPathAdd( pResidualCrv, vOffsTmp, idx, ptCrit, dParCrit, pSrfBound)) return false ; // calcolo la lunghezza del tratto da aggiungere basandomi sull'angolo e sull'overlap Point3d ptEnd ; bool bUsePtEnd = false ; // se sono sul punto di congiunzione fra due curve if ( vOffsTmp[idx]->IsParamAtJoint( dParCrit)) { const ICurve* pCrv1 = dParCrit < EPS_SMALL ? vOffsTmp[idx]->GetLastCurve() : vOffsTmp[idx]->GetCurve( int( dParCrit + 0.5) - 1) ; const ICurve* pCrv2 = vOffsTmp[idx]->GetCurve( int( dParCrit + 0.5)) ; // se le due curve sono due linee if ( pCrv1->GetType() == CRV_LINE && pCrv2->GetType() == CRV_LINE) { // calcolo angolo formato dalle due linee Vector3d vt1, vt2 ; vOffsTmp[idx]->GetPointTang( dParCrit, ICurve::FROM_MINUS, Point3d(), vt1) ; vOffsTmp[idx]->GetPointTang( dParCrit, ICurve::FROM_PLUS, Point3d(), vt2) ; vt2.Invert() ; double dCosAng = vt1 * vt2 ; // calcolo lunghezza basandomi sull'angolo e sull'overlap double dAngSin = sqrt( (1 - dCosAng) / 2) ; double dOverlap = 1 - GetSideStep() / m_TParams.m_dDiam ; double dLen = dAngSin > EPS_ANG_SMALL ? (( m_TParams.m_dDiam / 2 - m_TParams.m_dDiam * dOverlap) / dAngSin - m_TParams.m_dDiam / 2) : - 1.0 ; Point3d ptCen ; pResidualCrv->GetCentroid( ptCen) ; Vector3d vtDir = ptCen - ptCrit ; vtDir.Normalize() ; ptEnd = ptCrit + dLen * vtDir ; bUsePtEnd = dLen > 0 ; // se devo usare ptEnd verifico sia interno alla svuotatura if ( bUsePtEnd) { const ISurfTriMesh* pSrfTmBound = pSrfBound->GetAuxSurf() ; DistPointSurfTm DistPtSTm( ptEnd, *pSrfTmBound) ; Point3d ptMinDist ; if ( DistPtSTm.GetMinDistPoint( ptMinDist) && ! AreSamePointApprox( ptEnd, ptMinDist)) bUsePtEnd = false ; } } } // calcolo il percorso aggiuntivo ICurveComposite * pAddPath = CreateCurveComposite() ; if ( ! ComputeAdditionalPath( ptCrit, ptEnd, bUsePtEnd, pAddPath, pResidualCrv, pSrfBound, pNewCutRegion)) return false ; // se non ho aggiunto alcun percorso passo alla prossima regione residua if ( pAddPath->GetCurveCount() == 0) continue ; // nuova curva di offset con tratti aggiuntivi bAddedPaths = true ; PtrOwner pNewOffs( CreateCurveComposite()) ; double dPar, dParS, dParE ; vOffs[idx]->GetDomain( dParS, dParE) ; vOffs[idx]->GetParamAtPoint( ptCrit, dPar) ; pNewOffs->AddCurve( vOffs[idx]->CopyParamRange( dParS, dPar)) ; // fino al punto critico è il vecchio offset pNewOffs->AddCurve( pAddPath) ; // al punto critico aggiungo il nuovo percorso if ( abs( dPar - dParS) > EPS_SMALL && abs( dPar - dParE) > EPS_SMALL) pNewOffs->AddCurve( vOffs[idx]->CopyParamRange( dPar, dParE)) ; // aggiungo la parte rimanente del vecchio offset vOffs[idx] = Release( pNewOffs) ; } // Se ho aggiunto nuovi percorsi, verifico se sono rimaste aree non lavorate e le rimuovo if ( bAddedPaths && pNewCutRegion->GetLoopCount( 0) > pSrfBound->GetLoopCount( 0)) { if ( ! RemoveUncutRegions( pNewCutRegion, vOffs, pSrfBound)) return false ; } return true ; } //---------------------------------------------------------------------------- bool Pocketing::FindCurveForPathAdd( const ICurve* pResidualCrv, const ICRVCOMPOPOVECTOR& vOffs, size_t& nIdxMin, Point3d& ptMinDist, double& dMinDistPar, const ISurfFlatRegion * pSrfBound) { nIdxMin = -1 ; double dMinDist = INFINITO ; Vector3d vtExtr ; vOffs[0]->GetExtrusion( vtExtr) ; Frame3d frLoc ; frLoc.Set( ORIG, vtExtr) ; // porto le curve in questo riferimento CurveLocal pCrvLoc( pResidualCrv, GLOB_FRM, frLoc) ; Point3d ptCen ; pResidualCrv->GetCentroid( ptCen) ; double dist ; for ( size_t i = 0 ; i < vOffs.size() ; i ++) { // verifico se la regione da rimuovere ( pCrv) è esterna alla regione racchiusa da vOffs ISurfFlatRegion * pSrf = CreateSurfFlatRegion() ; pSrf->AddExtLoop( vOffs[i]->Clone()) ; CRVCVECTOR ccClass ; pSrf->GetCurveClassification( *pResidualCrv, ccClass) ; if ( ccClass.size() != 1) continue ; // se è esterna calcolo la sua distanza dal centro della regione da rimuovere if ( ccClass[0].nClass == CRVC_OUT) { DistPointCurve distPtCrv( ptCen, *(vOffs[i]->Clone())) ; if ( distPtCrv.GetDist( dist) && dist < dMinDist) { dMinDist = dist ; nIdxMin = i ; int nFlag ; distPtCrv.GetMinDistPoint( 0, ptMinDist, nFlag) ; vOffs[i]->GetParamAtPoint( ptMinDist, dMinDistPar) ; } } } // for ( size_t i = 1 ; i < vOffs.size() ; i ++) { // // // verifico se la parte da rimuovere ( pResidualCrv) è esterna alla regione racchiusa da vOffs[i] // CurveLocal pOffsLoc( vOffs[i]->Clone(), GLOB_FRM, frLoc) ; // IntersCurveCurve intersCC( *pCrvLoc, *pOffsLoc) ; // // if ( intersCC.GetRegionCurveClassification() != CCREGC_NULL && intersCC.GetRegionCurveClassification() != CCREGC_IN1) { // // double dParS, dParE ; // vOffs[i]->GetDomain( dParS, dParE) ; // // considero i punti di congiunzione fra le curve di vOffs[i] // for ( int j = int( dParS + 0.5) ; j < int( dParE + 0.5) ; j ++) { // // // calcolo il punto più vicino su pResidualCrv // Point3d ptCrv ; // vOffs[i]->GetPointD1D2( j, ICurve::FROM_MINUS, ptCrv) ; // DistPointCurve distPtCrv( ptCrv, *pResidualCrv) ; // int nFlag ; // Point3d ptResCrv ; // distPtCrv.GetMinDistPoint( 0, ptResCrv, nFlag) ; // // // calcolo la distanza come lunghezza del percorso interno alla svuotatura che li congiunge // ICurveComposite * pLinkPath = CreateCurveComposite() ; // if ( ! CalcBoundedLink( ptCrv, ptResCrv, pSrfBound, pLinkPath)) // continue ; // double dLen ; // if ( pLinkPath->GetLength( dLen) && dLen < dMinDist) { // dMinDist = dLen ; // nIdxMin = i ; // ptMinDist = ptCrv ; // dMinDistPar = j ; // } // } // } // } if ( nIdxMin == -1 ) return false ; return true ; } //---------------------------------------------------------------------------- bool Pocketing::ComputeAdditionalPath( const Point3d ptStart, Point3d ptEnd, bool bUsePtEnd, ICurveComposite * pAddPath, const ICurve * pResidualCrv, const ISurfFlatRegion * pSrfBound, ISurfFlatRegion * pNewCutRegion) { ICurveComposite * pResidualCrvClosed = GetCurveComposite( pResidualCrv->Clone()) ; if ( ! pResidualCrv->IsClosed()) pResidualCrvClosed->Close() ; // Se chiudendo la curva creo autointersezione, conservo la sottoparte di curva più lunga che non si autointerseca SelfIntersCurve SelfIntersC( *pResidualCrvClosed) ; if ( SelfIntersC.GetIntersCount() == 1) { IntCrvCrvInfo aInfo ; SelfIntersC.GetIntCrvCrvInfo( 0, aInfo) ; double dParS, dParE ; pResidualCrvClosed->GetDomain( dParS, dParE) ; PtrOwner pCrvTmp1( GetCurveComposite( pResidualCrvClosed->CopyParamRange( dParS, aInfo.IciA[0].dU))) ; pCrvTmp1->AddCurve( pResidualCrvClosed->CopyParamRange( aInfo.IciB[0].dU, dParE)) ; PtrOwner pCrvTmp2( GetCurveComposite( pResidualCrvClosed->CopyParamRange( aInfo.IciA[0].dU, aInfo.IciB[0].dU))) ; double dLen1 = 0.0, dLen2 = 0.0 ; pCrvTmp1->GetLength( dLen1) ; pCrvTmp2->GetLength( dLen2) ; pResidualCrvClosed = dLen1 > dLen2 ? Release( pCrvTmp1) : Release( pCrvTmp2) ; } // verifico che area non sia troppo piccola double dArea = 0 ; Plane3d plPlane ; if ( pResidualCrvClosed->GetArea( plPlane, dArea) && dArea < 10 * EPS_SMALL) return true ; // inverto direzione della curve per essere coerente con pAddSrf quando credo la superficie if ( AreOppositeVectorApprox( plPlane.GetVersN(), pNewCutRegion->GetNormVersor())) pResidualCrvClosed->Invert() ; // scelta del punto finale if ( ! bUsePtEnd) { pResidualCrv->GetCentroid( ptEnd) ; ISurfTriMesh* pResidualSrfTm = GetSurfTriMeshByFlatContour( pResidualCrvClosed) ; dArea = 0 ; if ( pResidualSrfTm != nullptr && pResidualSrfTm->GetArea( dArea) && dArea < 10 * EPS_SMALL) return true ; // se regione è abbastanza grande e il centroide non è interno alla regione chiamo la funzione specifica if ( dArea > 5) { DistPointSurfTm DistPtSTm( ptEnd, *pResidualSrfTm) ; Point3d ptMinDist ; if ( DistPtSTm.GetMinDistPoint( ptMinDist) && ! AreSamePointApprox( ptEnd, ptMinDist)) return AdditionalPathExternalCentroid( ptStart, pAddPath, pResidualCrvClosed, pSrfBound, pNewCutRegion) ; } } // se il punto iniziale e finale coincidono, scelgo un nuovo ptEnd if ( AreSamePointEpsilon( ptStart, ptEnd, 1e-2)) { Point3d ptMid ; pResidualCrv->GetMidPoint( ptMid) ; Vector3d vtDir = ptMid - ptStart ; vtDir.Normalize() ; double len = Dist( ptStart, ptMid) + 10 * EPS_SMALL - m_TParams.m_dDiam / 2 ; if ( Dist( ptStart, ptMid) < EPS_SMALL ) return true ; ptEnd = ptStart + len * vtDir ; } // creo il percorso fra ptStart e ptEnd senza uscire dalla svuotatura if ( ! CalcBoundedLink( ptStart, ptEnd, pSrfBound, pAddPath)) return false ; ICurveComposite * pReturnPath = pAddPath->Clone() ; // percorso di ritorno pReturnPath->Invert() ; // regione svuotata da pAddPath PtrOwner pAddPathTmp( CreateCurveComposite()) ; pAddPathTmp->AddCurve( pAddPath->Clone()) ; pAddPathTmp->AddCurve( pReturnPath->Clone()) ; Vector3d vtExtr = pNewCutRegion->GetNormVersor() ; pAddPathTmp->SetExtrusion( vtExtr) ; OffsetCurve OffsCrv ; OffsCrv.Make( pAddPathTmp, m_TParams.m_dDiam / 2 + 10 * EPS_SMALL, ICurve::OFF_FILLET) ; ICurve * pCrvOffs = OffsCrv.GetLongerCurve() ; PtrOwner pToolSrf( CreateSurfFlatRegion()) ; pToolSrf->AddExtLoop( pCrvOffs->Clone()) ; while ( OffsCrv.GetCurveCount() != 0) { ICurve * pCrvOffs2 = OffsCrv.GetCurve() ; pToolSrf->AddIntLoop( pCrvOffs2->Clone()) ; } // aggiorno la superficie lavorata if ( ! pNewCutRegion->Add( *Release( pToolSrf))) { // se fallisce provo con una ToolSurf più piccola pToolSrf.Set( CreateSurfFlatRegion()) ; OffsCrv.Make( pAddPathTmp, m_TParams.m_dDiam / 2 - 10 * EPS_SMALL, ICurve::OFF_FILLET) ; ICurve * pCrvOffs = OffsCrv.GetLongerCurve() ; pToolSrf->AddExtLoop( pCrvOffs->Clone()) ; while ( OffsCrv.GetCurveCount() != 0) { ICurve * pCrvOffs2 = OffsCrv.GetCurve() ; pToolSrf->AddIntLoop( pCrvOffs2->Clone()) ; } if ( ! pNewCutRegion->Add( *Release( pToolSrf))) return false ; } // porto le curva in locale per farne intersezione Frame3d frLoc ; frLoc.Set( ORIG, vtExtr) ; CurveLocal pResidualCrvLoc( pResidualCrv, GLOB_FRM, frLoc) ; CurveLocal pOffsCrvLoc( pCrvOffs, GLOB_FRM, frLoc) ; IntersCurveCurve intersCC( *pResidualCrvLoc, *pOffsCrvLoc) ; CRVCVECTOR ccClass ; intersCC.GetCurveClassification( 0, ccClass) ; // ricorsione su eventuali aree non lavorate rimaste size_t nFirst = 0 ; size_t nLast = ccClass.size() ; // verifico se posso trattare in una volta sola la parte inziale e finale della curva if ( pResidualCrv->IsClosed() && ccClass.front().nClass == CRVC_OUT && ccClass.back().nClass == CRVC_OUT) { ICurveComposite* pNewResidualCrv = CreateCurveComposite() ; pNewResidualCrv->AddCurve( pResidualCrv->CopyParamRange( ccClass.back().dParS, ccClass.back().dParE)) ; pNewResidualCrv->AddCurve( pResidualCrv->CopyParamRange( ccClass.front().dParS, ccClass.front().dParE)) ; ICurveComposite * pNewAddPath = CreateCurveComposite() ; if ( ! ComputeAdditionalPath( ptEnd, Point3d(), false, pNewAddPath, pNewResidualCrv, pSrfBound, pNewCutRegion)) return false ; pAddPath->AddCurve( pNewAddPath->Clone()) ; nFirst = 1 ; nLast = ccClass.size() - 1 ; } for ( size_t i = nFirst ; i < nLast ; i++) { if ( ccClass[i].nClass != CRVC_IN ) { ICurve * pNewResidualCrv = pResidualCrv->CopyParamRange( ccClass[i].dParS, ccClass[i].dParE) ; ICurveComposite * pNewAddPath = CreateCurveComposite() ; if ( ! ComputeAdditionalPath( ptEnd, Point3d(), false, pNewAddPath, pNewResidualCrv, pSrfBound, pNewCutRegion)) return false ; pAddPath->AddCurve( pNewAddPath) ; } } pAddPath->AddCurve( pReturnPath) ; // percorso di ritorno return true ; } //---------------------------------------------------------------------------- bool Pocketing::AdditionalPathExternalCentroid( const Point3d ptStart, ICurveComposite * pAddPath, ICurveComposite * pResidualCrv, const ISurfFlatRegion * pSrfBound, ISurfFlatRegion * pNewCutRegion) { DistPointCurve distPtCrv( ptStart, *pResidualCrv) ; double dParam ; int nFlag ; Point3d ptEnd ; distPtCrv.GetParamAtMinDistPoint( 0, dParam, nFlag) ; distPtCrv.GetMinDistPoint( 0, ptEnd, nFlag) ; pResidualCrv->ChangeStartPoint( dParam) ; if ( ! CalcBoundedLink( ptStart, ptEnd, pSrfBound, pAddPath)) return false ; PtrOwner pReturnPath( pAddPath->Clone()) ; // percorso di ritorno pReturnPath->Invert() ; pAddPath->AddCurve( pResidualCrv->Clone()) ; pAddPath->AddCurve( Release( pReturnPath)) ; // area coperta da pAddPath PtrOwner pToolSrf( CreateSurfFlatRegion()) ; OffsetCurve OffsCrvPlus ; if ( ! OffsCrvPlus.Make( pAddPath, m_TParams.m_dDiam / 2 + 5 * EPS_SMALL, ICurve::OFF_FILLET)) return false ; ICurve * pCrvOffPlus = OffsCrvPlus.GetLongerCurve() ; if ( pCrvOffPlus == nullptr) pToolSrf->AddExtLoop( pResidualCrv->Clone()) ; else pToolSrf->AddExtLoop( pCrvOffPlus) ; OffsetCurve OffsCrvMinus ; OffsCrvMinus.Make( pAddPath, - m_TParams.m_dDiam / 2 - 5 * EPS_SMALL, ICurve::OFF_FILLET) ; ICurve * pCrvOffMinus = OffsCrvMinus.GetLongerCurve() ; while ( pCrvOffMinus != nullptr) { if ( GetCurveRadius( pCrvOffMinus) > EPS_ZERO) pToolSrf->AddIntLoop( pCrvOffMinus) ; pCrvOffMinus = OffsCrvMinus.GetCurve() ; } // aggiorno la superficie lavorata if ( ! pNewCutRegion->Add( *Release( pToolSrf))) { // se fallisce provo con una ToolSurf più piccola pToolSrf.Set( CreateSurfFlatRegion()) ; if ( ! OffsCrvPlus.Make( pAddPath, m_TParams.m_dDiam / 2 - 5 * EPS_SMALL, ICurve::OFF_FILLET)) return false ; pCrvOffPlus = OffsCrvPlus.GetLongerCurve() ; if ( pCrvOffPlus == nullptr) pToolSrf->AddExtLoop( pResidualCrv->Clone()) ; else pToolSrf->AddExtLoop( pCrvOffPlus->Clone()) ; OffsCrvMinus.Make( pAddPath, - m_TParams.m_dDiam / 2 + 5 * EPS_SMALL, ICurve::OFF_FILLET) ; pCrvOffMinus = OffsCrvMinus.GetLongerCurve() ; while ( pCrvOffMinus != nullptr) { if ( GetCurveRadius( pCrvOffMinus) > EPS_ZERO) pToolSrf->AddIntLoop( pCrvOffMinus) ; pCrvOffMinus = OffsCrvMinus.GetCurve() ; } if ( ! pNewCutRegion->Add( *Release( pToolSrf))) return false ; } return true ; }