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