//---------------------------------------------------------------------------- // 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 "OperUserNotesConst.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/EGkSurfBezier.h" #include "/EgtDev/Include/EGkSfrCreate.h" #include "/EgtDev/Include/EGkStmStandard.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/EGkDistPointCurve.h" #include "/EgtDev/Include/EGkDistPointSurfFr.h" #include "/EgtDev/Include/EGkCurveAux.h" #include "/EgtDev/Include/EGkDistPointSurfTm.h" #include "/EgtDev/Include/EGkIntersPlaneSurfTm.h" #include "/EgtDev/Include/EGkStmFromCurves.h" #include "/EgtDev/Include/EGkPolygon3d.h" #include "/EgtDev/Include/EGkPolygonElevation.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" // 3030 = "Error in SurfRoughing : Conformal ZigZag not valid at step (xx)" // 3031 = "Error in SurfRoughing : LeadIn with Mill NoTip in material" // 3032 = "Error in SurfRoughing : Curves with different extrusion" // 3033 = "Error in SurfRoughing : CalcRegion elevation failed" // 3034 = "Error in SurfRoughing : Linking paths failed" // 3035 = "Error in SurfRoughing : Entity without Info" // 3036 = "Error in SurfRoughing : special apply not calculable" // 3051 = "Warning in SurfRoughing : Skipped entity (xx)" // 3052 = "Warning in SurfRoughing : No machinable path" // 3053 = "Warning in SurfRoughing : Tool name changed (xx)" // 3054 = "Warning in SurfRoughing : Tool data changed (xx)" // 3055 = "Warning in SurfRoughing : CalcPocketing failed with substep (xx)" // 3056 = "Warning in SurfRoughing : invalid Conformal ZigZag at substep (xx)" // 3057 = "Warning in SurfRoughing : Depth reduced at (xx)" //---------------------------------------------------------------------------- static string KEY_SURF_POCK = "SurfPock_" ; static string KEY_SURF_LIMIT = "SurfLimit_" ; static string KEY_OPEN = "OPEN" ; static string KEY_THICK = "THICK" ; static string SRF_SUPP_LAYER_NAME = "SUPP" ; static string KEY_DEPTH = "DEPTH" ; static string KEY_RELATIVE_DEPTH = "RELATIVEDEPTH" ; static string KEY_ZLOCFEEDCOEF = "ZLOCFEEDCOEFF" ; static string KEY_SUBSTEP = "SUBSTEP" ; #define ENABLE_DEBUG_SFR 0 #define ENABLE_DEBUG_STM_NORMAL_SHADER 0 #define ENABLE_DEBUG_REMOVED_REGION 0 #define ENABLE_DEBUG_FEEDS 0 #define ENABLE_DEBUG_SFR_BOOLEANS 0 #define ENABLE_DEBUG_SFR_COLLISION 0 #define ENABLE_DEBUG_ZPLANE 0 #define ENBALE_DEBUG_LINK 0 #define ENABLE_DEBUG_ORDER_ZCHUNK 0 #if ENABLE_DEBUG_SFR || ENABLE_DEBUG_STM_NORMAL_SHADER || ENABLE_DEBUG_REMOVED_REGION || \ ENABLE_DEBUG_FEEDS || ENABLE_DEBUG_SFR_BOOLEANS || ENABLE_DEBUG_SFR_COLLISION || ENABLE_DEBUG_ZPLANE || \ ENBALE_DEBUG_LINK || ENABLE_DEBUG_ORDER_ZCHUNK #include "/EgtDev/Include/EGkGeoPoint3d.h" #include "/EgtDev/Include/EGkGeoVector3d.h" #include "/EgtDev/Include/EgtPerfCounter.h" #include "/EgtDev/Include/EGkExtText.h" string sPathSrfBool = "C:\\Temp\\" ; int nGrpDebugFeed = GDB_ID_NULL, nLayDebugFeed = GDB_ID_NULL ; #endif const double STEP_TOL = 10. * EPS_SMALL ; const double SIL_DEPTH_TOL = 100. * EPS_SMALL ; const double OFFS_CORR_OPEN_EDGES = 25. * EPS_SMALL ; const double TOL_OFFS_CORNER_COLL = 50. * EPS_SMALL ; const double DIST_TABLE = 5. * EPS_SMALL ; //---------------------------------------------------------------------------- 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 ; m_dStepToler = 1.0 / 2 ; m_bDetectPlaneZ = false ; m_bOrderZ = false ; m_bRunning = false ; } //---------------------------------------------------------------------------- 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_OVERL : if ( ! AreSameLenValue( dVal, m_Params.m_dOverlap)) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dOverlap = 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 ; // copia temporanea e reset della geometria corrente SELVECTOR vOldId = m_vId ; 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 if ( m_vId != vOldId) 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) { // se calcoli già in corso, esco if ( m_bRunning) { LOG_DBG_INFO( GetEMkLogger(), "SurfRoughing::Apply already running") ; return true ; } m_bRunning = true ; bool bOk = MyApply( bRecalc, bPostApply) ; m_bRunning = false ; return bOk ; } //---------------------------------------------------------------------------- bool SurfRoughing::MyApply( 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 if ( ! UpdateToolData()) { 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 ; } // se modificata geometria, necessario ricalcolo if ( ( m_nStatus & MCH_ST_GEO_MODIF) != 0) bRecalc = true ; // verifico se necessario continuare nell'aggiornamento if ( ! bRecalc && ( m_nStatus == MCH_ST_OK || m_nStatus == MCH_ST_NO_POSTAPPL)) { // confermo i percorsi di lavorazione m_nPaths = nCurrPaths ; string sLog = string( "SurfRoughing apply skipped : status ") + ( m_nStatus == MCH_ST_OK ? "already ok" : "no postapply") ; LOG_DBG_INFO( GetEMkLogger(), sLog.c_str()) ; // eseguo aggiornamento assi macchina e collegamento con operazione precedente if ( ! Update( bPostApply)) return false ; m_nStatus = ( bPostApply ? MCH_ST_OK : MCH_ST_NO_POSTAPPL) ; 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) ; // 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) ; // elimino eventuale gruppo geometria simmetrica per lavorazione in doppio int nDblId = m_pGeomDB->GetFirstNameInGroup( m_nOwnerId, MCH_DBL) ; if ( nDblId != GDB_ID_NULL) { m_pGeomDB->Erase( nDblId) ; nDblId = GDB_ID_NULL ; } // 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 ; } // lavoro ogni singola regione piana bool bOk = true ; int nPathId = m_pGeomDB->GetFirstGroupInGroup( nAuxId) ; 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) ; 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 ; } // assegno estremi degli assi dei vari percorsi di lavorazione e della lavorazione nel suo complesso CalcAndSetAxesBBox() ; // esecuzione eventuali personalizzazioni speciali string sSpecErr ; if ( bPostApply && ! SpecialApply( sSpecErr)) { if ( ! IsEmptyOrSpaces( sSpecErr)) m_pMchMgr->SetLastError( 3036, sSpecErr) ; else m_pMchMgr->SetLastError( 3036, "Error in SurfRoughing : special apply not calculable") ; 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 ; } // esecuzione eventuali personalizzazioni finali string sPostErr ; if ( bPostApply && ! PostApply( sPostErr)) { if ( ! IsEmptyOrSpaces( sPostErr)) m_pMchMgr->SetLastError( 3020, sPostErr) ; 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_OVERL : dVal = m_Params.m_dOverlap ; 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() { // recupero il gestore DB utensili della macchina corrente ToolsMgr* pTMgr = m_pMchMgr->GetCurrToolsMgr() ; if ( pTMgr == nullptr) return false ; // recupero l'utensile nel DB utensili (se fallisce con UUID provo con il nome) const ToolData* pTdata = pTMgr->GetTool( m_Params.m_ToolUuid) ; if ( pTdata == nullptr) { pTdata = pTMgr->GetTool( m_Params.m_sToolName) ; if ( pTdata == nullptr) return false ; m_Params.m_ToolUuid = m_TParams.m_Uuid ; } // 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 modificato, aggiusto lo stato if ( bChanged) m_nStatus = MCH_ST_TO_VERIFY ; 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) ; } // se altrimenti è superficie Bezier else if ( pGObj->GetType() == SRF_BEZIER) { const ISurfBezier* pSurf = ::GetSurfBezier( pGObj) ; return ( pSurf != nullptr && pSurf->IsValid()) ; } // altrimenti errore else return false ; } //---------------------------------------------------------------------------- bool SurfRoughing::GetCurves( SelData Id, ICURVEPLIST& lstPC) { // ammessi : curve, superfici TriMesh e superfici Bezier 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 ; // recupero il tipo int nType = pGObj->GetType() ; // se curva if ( ( nType & 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 superficie TriMesh else if ( nType == SRF_TRIMESH) return true ; // se superficie Bezier else if ( nType == SRF_BEZIER) 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 Vector3d vtExtr = Z_AX ; 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) { pCrv->GetExtrusion( vtExtr) ; ptNear = ptStart + 10 * EPS_SMALL * vtStart ; bFirst = false ; } // altrimenti else { Vector3d vtTmpExtr ; pCrv->GetExtrusion( vtTmpExtr) ; if ( ! AreSameVectorApprox( vtTmpExtr, vtExtr)) { m_pMchMgr->SetLastError( 3032, "Error in SurfRoughing : Curves with different extrusion") ; return false ; } } } // recupero i percorsi concatenati e definisco la regione piana di sgrossatura SurfFlatRegionByContours SfrByC ; INTVECTOR vnId2 ; while ( chainC.GetChainFromNear( ptNear, false, vnId2)) { // creo una curva composita PtrOwner pCrvCompo( CreateCurveComposite()) ; if ( IsNull( pCrvCompo)) return false ; // estrusione e spessore 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 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 ; // se la curva non è chiusa, errore if ( ! pCrvCompo->IsClosed()) { m_pMchMgr->SetLastError( 3004, "Error in SurfRoughing : Open Contour") ; return false ; } // imposto estrusione e spessore pCrvCompo->SetExtrusion( vtExtr) ; pCrvCompo->SetThickness( dThick) ; // verifico sia piana e se necessario la appiattisco PtrOwner pFlatCrv( FlattenCurve( *pCrvCompo, 50 * EPS_SMALL, 50 * EPS_ANG_SMALL, FLTCRV_USE_EXTR)) ; if ( IsNull( pFlatCrv)) { Plane3d plPlane ; if ( ! pCrvCompo->IsFlat( plPlane, true, 50 * EPS_SMALL)) m_pMchMgr->SetLastError( 3005, "Error in SurfRoughing : Contour Not Flat") ; else m_pMchMgr->SetLastError( 3006, "Error in SurfRoughing : Tool Dir not perpendicular to Flat Area") ; return false ; } pCrvCompo->Clear() ; pCrvCompo->AddCurve( Release( pFlatCrv)) ; // salvo vettore estrusione pCrvCompo->SetExtrusion( vtExtr) ; // salvo la thickness come seconda temp prop ( la Sfr rimuove la thick delle curve) pCrvCompo->SetTempParam( dThick, 1) ; // aggiorno il nuovo punto vicino pCrvCompo->GetEndPoint( ptNear) ; // se utile, approssimo con archi if ( ! ApproxWithArcsIfUseful( pCrvCompo)) return false ; // inserisco la curva nella regione piana SfrByC.AddCurve( Release( pCrvCompo)) ; } // scorro le regioni piane ricavate dalle curve int nGroupName = 0 ; PtrOwner pSfrCurr( SfrByC.GetSurf()) ; while ( ! IsNull( pSfrCurr) && pSfrCurr->IsValid()) { // la normale del Chunk deve essere coerente con l'estrusione ricavata if ( AreOppositeVectorApprox( pSfrCurr->GetNormVersor(), vtExtr)) pSfrCurr->Invert() ; // per ogni Chunk for ( int nC = 0 ; nC < pSfrCurr->GetChunkCount() ; ++ nC) { // creo nuovo gruppo int nPathId = m_pGeomDB->AddGroup( GDB_ID_NULL, nGrpDestId, Frame3d()) ; if ( nPathId == GDB_ID_NULL) return false ; m_pGeomDB->SetName( nPathId, MCH_PATH + ToString( ++ nGroupName)) ; m_pGeomDB->SetInfo( nPathId, KEY_IDS, ToString( nGroupName)) ; // recupero il Chunk corrente PtrOwner pSfrChunk( pSfrCurr->CloneChunk( nC)) ; if ( IsNull( pSfrChunk) || ! pSfrChunk->IsValid()) return false ; int nNewId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nPathId, ::CloneSurfFlatRegion( pSfrChunk)) ; if ( nNewId == GDB_ID_NULL) return false ; // scorro i loop della regione for ( int nL = 0 ; nL < pSfrChunk->GetLoopCount( 0) ; ++ nL) { // recupero il Loop PtrOwner pCrvLoop( ConvertCurveToComposite( pSfrChunk->GetLoop( 0, nL))) ; if ( IsNull( pCrvLoop) || ! pCrvLoop->IsValid()) return false ; // memorizzo la Thickness e l'Estrusione nelle Info del gruppo if ( nL == 0) { double dThick = pCrvLoop->GetTempParam( 1) ; m_pGeomDB->SetInfo( nNewId, KEY_THICK, dThick) ; m_pGeomDB->SetInfo( nNewId, KEY_EXTR, vtExtr) ; } } } // aggiorno la regione piana con la successiva calcolata pSfrCurr.Set( SfrByC.GetSurf()) ; } return true ; } //---------------------------------------------------------------------------- bool SurfRoughing::CalcRegionElevation( const ICurveComposite* pCompo, const Vector3d& vtTool, double dDepth, double dRad, double dLen, double& dElev) const { // inizializzo l'elevazione dElev = 0 ; // approssimo la curva con una polilinea che uso per creare il poligono equivalente PolyLine PL ; if ( ! pCompo->ApproxWithLines( LIN_TOL_RAW, ANG_TOL_MAX_DEG, ICurve::APL_SPECIAL, PL)) return false ; Polygon3d pgFacet ; if ( ! pgFacet.FromPolyLine( PL)) return false ; // aggiungo l'affondamento pgFacet.Translate( -dDepth * vtTool) ; // inizializzo elevazioni per ogni grezzo INTDBLVECTOR vRawElev ; // ciclo sui grezzi della fase 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 la trimesh del grezzo int nStmId = m_pGeomDB->GetFirstNameInGroup( nRawId, MACH_RAW_SOLID) ; const ISurfTriMesh* pStm = GetSurfTriMesh( m_pGeomDB->GetGeoObj( nStmId)) ; if ( pStm != nullptr) { // recupero il riferimento della trimesh Frame3d frStm ; m_pGeomDB->GetGlobFrame( nStmId, frStm) ; // porto il poligono in questo riferimento Polygon3d pgFacetL = pgFacet ; pgFacetL.ToLoc( frStm) ; // calcolo l'elevazione double dCurrElev ; if ( ! PolygonElevationInClosedSurfTm( pgFacetL, *pStm, true, dCurrElev)) return false ; if ( dCurrElev > EPS_SMALL) vRawElev.emplace_back( nStmId, dCurrElev) ; } } // passo al grezzo successivo nRawId = m_pMchMgr->GetNextRawPart( nRawId) ; } // se trovate elevazioni if ( ! vRawElev.empty()) { // ordino il vettore secondo l'elevazione crescente sort( vRawElev.begin(), vRawElev.end(), []( const INTDBL& a, const INTDBL& b) { return a.second < b.second ; }) ; // box dell'insieme delle posizioni utensile all'inizioe const double MAX_DIST_RAW = 200.0 ; BBox3d b3Tool ; pgFacet.GetLocalBBox( b3Tool) ; b3Tool.Add( b3Tool.GetMin() + dLen * vtTool) ; b3Tool.Add( b3Tool.GetMax() + dLen * vtTool) ; if ( vtTool.IsX()) b3Tool.Expand( 0, dRad, dRad) ; else if ( vtTool.IsY()) b3Tool.Expand( dRad, 0, dRad) ; else if ( vtTool.IsZ()) b3Tool.Expand( dRad, dRad, 0) ; else { double dExpandX = dRad * sqrt( 1 - vtTool.x * vtTool.x) ; double dExpandY = dRad * sqrt( 1 - vtTool.y * vtTool.y) ; double dExpandZ = dRad * sqrt( 1 - vtTool.z * vtTool.z) ; b3Tool.Expand( dExpandX, dExpandY, dExpandZ) ; } b3Tool.Expand( MAX_DIST_RAW) ; // verifico la reale interferenza dell'utensile con i diversi grezzi for ( int i = 0 ; i < int( vRawElev.size()) ; ++ i) { // box del grezzo BBox3d b3Raw ; m_pGeomDB->GetGlobalBBox( vRawElev[i].first, b3Raw) ; // confronto con il box dell'utensile nella posizione precedente BBox3d b3CurrTool = b3Tool ; b3CurrTool.Translate( dElev * vtTool) ; if ( b3Raw.Overlaps( b3CurrTool)) dElev = vRawElev[i].second ; } } return true ; } //---------------------------------------------------------------------------- bool SurfRoughing::ProcessPath( int nPathId, int nPvId, int nClId) { // aggiorno la ProgressBar del 5% per simulare l'inizio della funzione ExeProcessEvents( 5, 0) ; // 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) ; // recupero la regione piana dal database geometrico int nSfrId = m_pGeomDB->GetFirstInGroup( nPathId) ; if ( m_pGeomDB->GetGeoType( nSfrId) != SRF_FLATRGN) return false ; // copio la regione piana da elaborare int nCopyId = m_pGeomDB->CopyGlob( nSfrId, GDB_ID_NULL, nTempId) ; if ( nCopyId == GDB_ID_NULL) return false ; PtrOwner pSfrSgro( CloneSurfFlatRegion( m_pGeomDB->GetGeoObj( nCopyId))) ; if ( IsNull( pSfrSgro) || ! pSfrSgro->IsValid()) return false ; // recupero estrusione Vector3d vtExtr = Z_AX ; if ( m_pGeomDB->ExistsInfo( nSfrId, KEY_EXTR)) m_pGeomDB->GetInfo( nSfrId, KEY_EXTR, vtExtr) ; // controllo che l'estrusione sia coerente con la normale della superficie if ( AreSameOrOppositeVectorApprox( pSfrSgro->GetNormVersor(), vtExtr)) { if ( AreOppositeVectorApprox( pSfrSgro->GetNormVersor(), vtExtr)) pSfrSgro->Invert() ; } else { m_pMchMgr->SetLastError( 3006, "Error in SurfRoughing : Tool Dir not perpendicular to Flat Area") ; return false ; } // recupero lo spessore e valuto l'espressione dell'affondamento double dThick = 0. ; if ( m_pGeomDB->ExistsInfo( nSfrId, KEY_THICK)) m_pGeomDB->GetInfo( nSfrId, KEY_THICK, dThick) ; 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 ; } // se spessore positivo, lo sottraggo dal risultato if ( dThick > 0) dDepth -= dThick ; // 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 ; } // recupero nome del path string sPathName ; m_pGeomDB->GetName( nPathId, sPathName) ; // assegno il versore fresa Vector3d vtTool = vtExtr ; // calcolo l'elevazione al di sopra di tale regione e l'affondamento al di sotto double dSfrMaxElev = 0. ; double dSfrMaxDepth = 0. ; for ( int nC = 0 ; nC < pSfrSgro->GetChunkCount() ; ++ nC) { for ( int nL = 0 ; nL < pSfrSgro->GetLoopCount( nC) ; ++ nL) { // recupero la curva PtrOwner pCrvLoop( ConvertCurveToComposite( pSfrSgro->GetLoop( nC, nL))) ; if ( IsNull( pCrvLoop) || ! pCrvLoop->IsValid()) return false ; // se isola inverto if ( nL > 0) pCrvLoop->Invert() ; // determino l'elevazione double dSfrElev = 0. ; if ( ! CalcRegionElevation( pCrvLoop, vtTool, 0., 0.5 * m_TParams.m_dDiam, m_TParams.m_dLen, dSfrElev)) { m_pMchMgr->SetLastError( 3033, "Error in SurfRoughing : Calc Region elevation failed") ; return false ; } // aggiorno l'elevazione massima dSfrMaxElev = max( dSfrElev, dSfrMaxElev) ; // determino l'affondamento pCrvLoop->Invert() ; double dSfrDepth = 0. ; if ( ! CalcRegionElevation( pCrvLoop, vtTool, 0., 0.5 * m_TParams.m_dDiam, m_TParams.m_dLen, dSfrDepth)) { m_pMchMgr->SetLastError( 3033, "Error in SurfRoughing : Calc Region elevation failed") ; return false ; } // aggiorno l'affondamento massimo dSfrMaxDepth = max( dSfrDepth, dSfrMaxDepth) ; } } // se la regione interseca il grezzo if ( dSfrMaxElev > EPS_SMALL) { // eventuale imposizione massima elevazione da note utente double dMaxElev ; if ( GetValInNotes( m_Params.m_sUserNotes, UN_MAXELEV, dMaxElev) && dSfrMaxElev > dMaxElev - dDepth) dSfrMaxElev = dMaxElev - dDepth ; // la regione viene traslata dell'elevazione trovata lungo vtTool pSfrSgro->Translate( dSfrMaxElev * vtTool) ; // la Depth viene incrementata del valore di traslazione dDepth += dSfrMaxElev ; dSfrMaxDepth += dSfrMaxElev ; } // aggiustiamo l'affondamento se eccesivo const double MAX_DEPTH_EXTRA = 3 ; dDepth = min( dDepth, dSfrMaxDepth + MAX_DEPTH_EXTRA) ; // controllo se richiesto PlaneZDetection bool bPlaneZDetection = false ; m_bDetectPlaneZ = ( GetValInNotes( m_Params.m_sUserNotes, UN_PLANEZ, bPlaneZDetection) && bPlaneZDetection) ; // controllo se richiesto ordinamento dei Chunk lungo vtTool bool bOrderZ = false ; m_bOrderZ = ( GetValInNotes( m_Params.m_sUserNotes, UN_ORDER, bOrderZ) && bOrderZ) ; // NB. [ le superfici vengono riordinate e divise per Chunks prima di essere inserite nel gruppo // temporaneo. L'analisi per la superficie di Sgrossatura, Limite e Removed non dipende // dall'ordine, ma semplicemente dalla quota Z del piano di sgrossatura ] // controllo se presente parametro di Offset radiale per superfici di supporto double dSuppRadOffs = 5. ; double dSuppRadOffsByNotes = 0. ; if ( GetValInNotes( m_Params.m_sUserNotes, UN_SUPP_RAD_OFFS, dSuppRadOffsByNotes) && dSuppRadOffsByNotes > - EPS_ZERO) dSuppRadOffs = dSuppRadOffsByNotes ; // creo un frame centrato sulla superficie Frame3d frSfr ; Point3d ptCenter ; pSfrSgro->GetCentroid( ptCenter) ; if ( ! frSfr.Set( ptCenter, vtTool)) return false ; // 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 e le superfici di supporto INTVECTOR vSurfId ; INTVECTOR vSurfSuppId ; GetActiveSurfaces( vSurfId, vSurfSuppId) ; 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 ; } // verifico se presente parametro di Overlap if ( m_Params.m_dOverlap > 10. * EPS_SMALL) { if ( ! pSfrSgro->Offset( m_Params.m_dOverlap, ICurve::OFF_EXTEND) || ! pSfrSgro->IsValid()) return false ; } // inizializzo la classe di intersezione tra grezzo e piani paralleli ( quelli di lavoro) // traslo leggermente il grezzo per gestire il primo e l'ultimo Step pStmRaw->Translate( - vtTool * 5 * EPS_SMALL) ; IntersParPlanesSurfTm IPPStm( frSfr, *pStmRaw) ; // costruisco una superficie di estrusione della curva (devo determinare parte della regione limite) Vector3d vtLimitExtr = - vtTool * 1.5 * max( b3Raw.GetDimX(), max( b3Raw.GetDimY(), b3Raw.GetDimZ())) ; PtrOwner pStmLimit( GetStmOutSideSfr( pSfrSgro, dDepth, pStmRaw, vtLimitExtr)) ; if ( IsNull( pStmLimit)) return false ; // determino la regione piana di tavola e ventose per evitare collisioni // NB. creo una regione piana perchè questa è statica per ogni step, non si adatta PtrOwner pSfrColl( CreateSurfFlatRegion()) ; PtrOwner pSfrSearchCorners( CreateSurfFlatRegion()) ; if ( IsNull( pSfrColl) || IsNull( pSfrSearchCorners) || ! GetToolCollisionRegion( pSfrSgro, dDepth, pSfrColl, pSfrSearchCorners)) return false ; // inizializzo la classe di intersezione tra la superficie trimesh limite e piani paralleli ( quelli di lavoro) IntersParPlanesSurfTm IPPStm1( frSfr, *pStmLimit) ; // inizializzo la classe di calcolo delle silhouette per le superfici attive 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) { // superfici ammesse : TriMesh, Bezier vSurfL.emplace_back( m_pGeomDB, vSurfId[i], GLOB_FRM) ; if ( vSurfL[i].Get() == nullptr) return false ; const ISurf* pSurf = GetSurf( vSurfL[i].Get()) ; if ( pSurf != nullptr && pSurf->IsValid()) { int nType = pSurf->GetType() ; // se TriMesh if ( nType == SRF_TRIMESH) { const ISurfTriMesh* pStm = GetSurfTriMesh( pSurf) ; if ( pStm != nullptr && pStm->IsValid() && pStm->GetTriangleCount() > 0) vpStm.emplace_back( pStm) ; } // se Bezier else if ( nType == SRF_BEZIER) { const ISurfBezier* pSBz = GetSurfBezier( pSurf) ; if ( pSBz != nullptr && pSBz->IsValid()) { double dOldTol = GetSurfBezierAuxSurfRefinedTol() ; SetSurfBezierAuxSurfRefinedTol( 5. * EPS_SMALL) ; const ISurfTriMesh* pStm = pSBz->GetAuxSurfRefined() ; SetSurfBezierAuxSurfRefinedTol( dOldTol) ; if ( pStm != nullptr && pStm->IsValid() && pStm->GetTriangleCount() > 0) vpStm.emplace_back( pStm) ; } } #if ENABLE_DEBUG_STM_NORMAL_SHADER DrawNormalShaderSurfTm( vpStm.back(), ToString( i)) ; #endif } } const double SILH_TOL = 1.0 ; PtrOwner pCavParSilh( CreateCAvParSilhouettesSurfTm()) ; if ( IsNull( pCavParSilh) || ! pCavParSilh->SetData( vpStm, frSfr, SILH_TOL)) return false ; // inizializzo la classe di calcolo delle silhouette per le superfici di supporto nei piani come sopra SURFLOCALVECTOR vSurfL_supp ; CISURFTMPVECTOR vpStm_supp ; PtrOwner pCavParSilh_supp( CreateCAvParSilhouettesSurfTm()) ; if ( IsNull( pCavParSilh_supp)) return false ; if ( ! vSurfSuppId.empty()) { vSurfL_supp.reserve( vSurfSuppId.size()) ; vpStm.reserve( vSurfSuppId.size()) ; for ( int i = 0 ; i < int( vSurfSuppId.size()) ; ++ i) { // superfici ammesse : TriMesh, Bezier vSurfL_supp.emplace_back( m_pGeomDB, vSurfSuppId[i], GLOB_FRM) ; if ( vSurfL_supp[i].Get() == nullptr) return false ; const ISurf* pSurf = GetSurf( vSurfL_supp[i].Get()) ; if ( pSurf != nullptr && pSurf->IsValid()) { int nType = pSurf->GetType() ; // se TriMesh if ( nType == SRF_TRIMESH) { const ISurfTriMesh* pStm = GetSurfTriMesh( pSurf) ; if ( pStm != nullptr && pStm->IsValid() && pStm->GetTriangleCount() > 0) vpStm_supp.emplace_back( pStm) ; } // se Bezier else if ( nType == SRF_BEZIER) { const ISurfBezier* pSBz = GetSurfBezier( pSurf) ; if ( pSBz != nullptr && pSBz->IsValid()) { double dOldTol = GetSurfBezierAuxSurfRefinedTol() ; SetSurfBezierAuxSurfRefinedTol( 5. * EPS_SMALL) ; const ISurfTriMesh* pStm = pSBz->GetAuxSurfRefined() ; SetSurfBezierAuxSurfRefinedTol( dOldTol) ; if ( pStm != nullptr && pStm->IsValid() && pStm->GetTriangleCount() > 0) vpStm_supp.emplace_back( pStm) ; } } } } if ( ! pCavParSilh_supp->SetData( vpStm_supp, frSfr, SILH_TOL)) return false ; } // vettore Id salvati nel gruppo Temp INTINTVECTOR vPocket ; // vettore delle curve composite con proprietà Aperto/Chiuso riferite ai vari step della curva originale ICRVCOMPOPOVECTOR vCrvPocketCompo ; // definisco la dimensione dello step ( base ) e il numero di passate double dOkStep = min( m_Params.m_dStep, m_TParams.m_dMaxMat + EPS_SMALL) ; int nStep = max( 1, static_cast( ceil( dDepth / dOkStep))) ; double dStep = dDepth / nStep ; // definisco la dimensione degli step intermedi ( subSteps ) e il numero di passate [ se definiti ] double dOkSubStep = -1. ; int nSubStep = -1 ; double dSubStep = -1. ; if ( m_Params.m_dSubStep > EPS_SMALL && m_Params.m_dSubStep < m_Params.m_dStep && dDepth > m_Params.m_dSubStep) { dOkSubStep = min( m_Params.m_dSubStep, m_TParams.m_dMaxMat + EPS_SMALL) ; nSubStep = nStep * max( 1, static_cast( ceil( dOkStep / dOkSubStep))) ; dSubStep = dDepth / nSubStep ; } // se richiesto PlaneZ detection, aggiungo altri step intermedi ( planeZSteps ) PLANEZFACEVECTOR vPlaneZ ; if ( m_bDetectPlaneZ) { if ( ! DetectPlaneZ( vpStm, frSfr, vtTool, vPlaneZ, - GetOffsL(), dDepth - GetOffsL())) return false ; #if ENABLE_DEBUG_ZPLANE for ( int nP = 0 ; nP < int( vPlaneZ.size()) ; ++ nP) { int _a = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, vPlaneZ[nP].first->Clone()) ; m_pGeomDB->SetMaterial( _a, Color( 1., 0., 0., .25)) ; } #endif } // definisco un vettore per Step/SubSteps durante la loro creazione STEPINFOTMPSRVECTOR vStepInfo ; vStepInfo.reserve( nStep + max( 0, nSubStep) + int( vPlaneZ.size())) ; // inserimento degli step ( ed eventuali PlaneZ se SubSteps non presenti) for ( int i = 0 ; i < nStep ; ++ i) { vStepInfo.emplace_back( -1, - ( i + 1) * dStep, false, false, 1., nullptr, nullptr) ; // se non ho SubStep ma PlaneZ, inserisco i PlaneZ if ( nSubStep == -1) { for ( int j = 0 ; j < int( vPlaneZ.size()) ; ++ j) { if ( vPlaneZ[j].second > - ( i + 1) * dStep + STEP_TOL && vPlaneZ[j].second < - i * dStep - STEP_TOL) { vStepInfo.emplace_back( i, vPlaneZ[j].second, false, true, -1., nullptr, nullptr) ; vStepInfo.back().pSfrPlaneZ = Release( vPlaneZ[j].first) ; } } } } INTDBLVECTOR vExtraStep ; // Depth per PlaneZ e SubSteps for ( int i = 0 ; i < nSubStep ; ++ i) vExtraStep.emplace_back( make_pair( -1, - ( i + 1) * dSubStep)) ; if ( nSubStep != -1) { for ( int i = 0 ; i < int( vPlaneZ.size()) ; ++ i) vExtraStep.emplace_back( make_pair( i, vPlaneZ[i].second)) ; sort( vExtraStep.begin(), vExtraStep.end(), []( const INTDBL& a, const INTDBL& b) { return a.second > b.second ; }) ; } // ... e poi gli step extra int nIndRef = 0 ; // ( step base sottostante allo step extra corrente ) int nIndPrev = 0 ; // ( indice finale di copia degli step extra ) // creo un vettore di step extra 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) for ( int i = 0 ; i < int( vExtraStep.size()) ; ++ i) { // se step extra coincidente con lo step, copio gli step extra utili if ( abs( vExtraStep[i].second - vStepInfo[nIndRef].dDepth) < STEP_TOL) { for ( int j = i - 1 ; j >= nIndPrev ; -- j) { int nMyInd = ( j == i - 1 ? nIndRef : int( vStepInfo.size()) - 1) ; bool bSS = ( vExtraStep[j].first == -1) ; vStepInfo.emplace_back( nMyInd, vExtraStep[j].second, bSS, ! bSS, -1. , nullptr, nullptr) ; if ( ! bSS) vStepInfo.back().pSfrPlaneZ = Release( vPlaneZ[vExtraStep[j].first].first) ; } ++ nIndRef ; nIndPrev = i + 1 ; } } // definisco il vettore per salvataggio delle regione e dei loro parametri nel GeomDB SFRGEODBINFOVECTOR vInfoSfrGeomDB ; vInfoSfrGeomDB.reserve( vStepInfo.size()) ; // 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) { // aggiorno step per progressBar ++ nProgressBarStep ; // affondamento per calcolo regioni (limito poco sotto il grezzo) double dSfrDepth = it->dDepth ; double dSfrDeltaDepth = 0 ; if ( dSfrDepth < -dSfrMaxDepth) { dSfrDeltaDepth = dSfrDepth + dSfrMaxDepth ; dSfrDepth = -dSfrMaxDepth ; } /* ******************** Regione definita dai contorni ******************** */ // regione di lavoro allo step corrente ( definita dalla curva di lavoro ) PtrOwner pSfr( CloneSurfFlatRegion( pSfrSgro)) ; if ( IsNull( pSfr) || ! pSfr->IsValid()) { m_pMchMgr->SetLastError( 3024, "Error in SurfRoughing : region not computable") ; return false ; } pSfr->Translate( ( dSfrDepth + GetOffsL()) * vtTool) ; /* ******************** Regione adattata al grezzo ******************** */ // questa regione bisogna ridurla basandosi sulla geometria del grezzo, in modo da non lavorare // parti in eccesso ; taglio il grezzo sul piano corrente e interseco con questa regione PtrOwner pSfrRaw( GetSfrByStmIntersection( IPPStm, dSfrDepth + GetOffsL(), 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 // definisco la regione rimossa temporanea PtrOwner pSfrRemoved_tmp( CloneSurfFlatRegion( pSfr)) ; if ( IsNull( pSfrRemoved_tmp)) return false ; /* ***************** Regione piana esterna ai contorni ****************** */ // regione definita dalla parte di grezzo al di fuori della curva di sgrossatura // unita ad eventuale regione di collisione PtrOwner pSfrOutCompo( CreateSurfFlatRegion()) ; if ( IsNull( pSfrOutCompo)) return false ; if ( pStmLimit->IsValid() && pStmLimit->GetTriangleCount() > 0) { pSfrOutCompo.Set( GetSfrByStmIntersection( IPPStm1, dSfrDepth + GetOffsL(), 0)) ; if ( IsNull( pSfrOutCompo)) { m_pMchMgr->SetLastError( 3027, "Error in SurfRoughing : Slicing Raw failed") ; return false ; } } if ( ! IsNull( pSfrColl) && pSfrColl->IsValid()) { PtrOwner pSfrCollTransl( CloneSurfFlatRegion( pSfrColl)) ; if ( IsNull( pSfrCollTransl) || ! pSfrCollTransl->IsValid()) return false ; pSfrCollTransl->Translate( ( dSfrDepth + GetOffsL()) * vtTool) ; if ( IsNull( pSfrOutCompo) || ! pSfrOutCompo->IsValid()) pSfrOutCompo.Set( CloneSurfFlatRegion( pSfrCollTransl)) ; else pSfrOutCompo->Add( *pSfrCollTransl) ; } /* *************************** Silhouette **************************** */ // determino la regione da non lavorare ( dalle geometrie selezionate) e la sottraggo double dSilDepth = dSfrDepth - ( it->bPlaneZStep ? SIL_DEPTH_TOL : 0.) ; bool bOkSil = false ; PtrOwner pSfrSil_Hypothetical( CreateSurfFlatRegion()) ; if ( IsNull( pSfrSil_Hypothetical)) return false ; PtrOwner pSfrSil( GetSfrSilhouette( pCavParSilh, dSilDepth, SILH_TOL, bOkSil)) ; if ( ! bOkSil) { m_pMchMgr->SetLastError( 3024, "Error in SurfRoughing : region not computable") ; return false ; } if ( ! IsNull( pSfrSil) && ! it->bPlaneZStep) { // provo prima con un Offset Chamfer, se non funziona provo con il Fillet ( pezza da sistemare ! ) PtrOwner pSfrSilCheck( pSfrSil->CreateOffsetSurf( GetOffsR(), ICurve::OFF_CHAMFER)) ; if ( IsNull( pSfrSilCheck) || ! pSfrSilCheck->IsValid()) { m_pMchMgr->SetLastError( 3024, "Error in SurfRoughing : region not computable") ; return false ; } pSfrSil_Hypothetical.Set( CloneSurfFlatRegion( pSfrSilCheck)) ; // regione di silhouette ipotetica // sottraggo le parti da non lavorare if ( ! pSfr->Subtract( *pSfrSilCheck)) { // se non riesco, provo con un Offset di tipo Fillet pSfrSil->Offset( GetOffsR(), ICurve::OFF_FILLET) ; pSfrSil_Hypothetical.Set( CloneSurfFlatRegion( pSfrSil)) ; // regione di silhouette ipotetica if ( ! pSfr->Subtract( *pSfrSil)) return false ; } else pSfrSil.Set( Release( pSfrSilCheck)) ; } if ( ! pSfr->IsValid() || pSfr->GetChunkCount() == 0) // se superficie non valida continue ; // passo allo step successivo ( la silhouette coincide con il grezzo ) /* ************************** Superfici di supporto ************************ */ // sottraggo i contributi dovuti a regioni di supporto ( mediante Offset in 2d) if ( ! vSurfL_supp.empty()) { bool bOkSil_supp = false ; PtrOwner pSfrSil_supp( GetSfrSilhouette( pCavParSilh_supp, dSilDepth, SILH_TOL, bOkSil_supp)) ; if ( ! bOkSil_supp) { m_pMchMgr->SetLastError( 3024, "Error in SurfRoughing : region not computable") ; return false ; } if ( ! IsNull( pSfrSil_supp)) { // Offset radiale sulla Silhouette pSfrSil_supp->Offset( dSuppRadOffs + GetOffsR(), ICurve::OFF_CHAMFER) ; // Sottraggo le parti da non lavorare pSfr->Subtract( *pSfrSil_supp) ; // Aggiungo la regione alla Silhouette if ( ! IsNull( pSfrSil) && pSfrSil->IsValid() && pSfrSil->GetChunkCount() > 0) pSfrSil->Add( *pSfrSil_supp) ; else pSfrSil.Set( Release( pSfrSil_supp)) ; // Aggiorno la regione Ipotetica if ( ! IsNull( pSfrSil_Hypothetical) && pSfrSil_Hypothetical->IsValid() && pSfrSil_Hypothetical->GetChunkCount() > 0) pSfrSil_Hypothetical->Add( *pSfrSil_supp) ; else pSfrSil_Hypothetical.Set( Release( pSfrSil_supp)) ; } // Se superficie non valida, passo allo step successivo if ( ! pSfr->IsValid() || pSfr->GetChunkCount() == 0) continue ; } // salvo la superficie rimossa delete( it->pSfrRemoved) ; it->pSfrRemoved = CloneSurfFlatRegion( pSfrRemoved_tmp) ; if ( ! IsNull( pSfrSil_Hypothetical) && pSfrSil_Hypothetical->IsValid() && pSfrSil_Hypothetical->GetChunkCount() > 0) { pSfrSil_Hypothetical->Offset( m_TParams.m_dDiam / 2, ICurve::OFF_FILLET) ; // si può ingrandire leggermente (più conservativo) pSfrSil_Hypothetical->Offset( - m_TParams.m_dDiam / 2, ICurve::OFF_FILLET) ; // la silhouette ipotetica ora ha i lati chiusi definiti dal rotalamento del tool lungo il chiuso reale it->pSfrRemoved->Subtract( *pSfrSil_Hypothetical) ; // la rimossa dipende dalla silhouette ipotetica (non quella reale) } // se PlaneZ if ( it->bPlaneZStep && ! IsNull( pSfrSil) && pSfrSil->IsValid()) { pSfrSil->Offset( GetOffsR(), ICurve::OFF_CHAMFER) ; // offset radiale sulla Silhouette it->pSfrRemoved->Subtract( *pSfrSil) ; // sottraggo le parti da non lavorare } // inizializzo Regione piana per gestione lati aperti PtrOwner pSfrOpenClose( CloneSurfFlatRegion( pSfrRaw)) ; if ( IsNull( pSfrOpenClose)) return false ; /* *************************** Gestione StepExtra **************************** */ if ( it->bSubStep) { // recupero l'indice nel vettore dello step di riferimento int nIndRef = it->nIndRef ; while ( ( vStepInfo[nIndRef].bSubStep) && ( vStepInfo[nIndRef].pSfrRemoved == nullptr || ! vStepInfo[nIndRef].pSfrRemoved->IsValid())) { nIndRef = vStepInfo[nIndRef].nIndRef ; } // recupero la superficie progressiva dello step di riferimento PtrOwner pSfrRemovedRef( CloneSurfFlatRegion( vStepInfo[nIndRef].pSfrRemoved)) ; if ( ! IsNull( pSfrRemovedRef) && pSfrRemovedRef->IsValid()) { // se valida pSfrRemovedRef->Offset( OFFS_CORR_OPEN_EDGES, ICurve::OFF_FILLET) ; // correzione per booleane if ( ! pSfr->Subtract( *pSfrRemovedRef)) { // sottraggo la regione svuotata in precedenza #if ENABLE_DEBUG_SFR_BOOLEANS SaveSfrBooleans( pSfr, pSfrRef, sPathSrfBool + "Sub_" + to_string( it->dDepth) + ".nge") ; #endif // NB. In attesa di una versione più robusta per le booleane tra regioni piane, il substep viene scartato continue ; } // aggiorno Regione piana per gestione lati aperti pSfrOpenClose->Subtract( *pSfrRemovedRef) ; } } else if ( it->bPlaneZStep && ! IsNull( pSfrSil) && pSfrSil->IsValid()) { PtrOwner pSfrRef( CloneSurfFlatRegion( it->pSfrRemoved)) ; if ( ! IsNull( pSfrRef) && pSfrRef->IsValid()) pSfrRef->Offset( OFFS_CORR_OPEN_EDGES + GetOffsR(), ICurve::OFF_FILLET) ; // correzione // cerco il Chunk nC-esimo della silhouette da rimuovere PtrOwner pSfrPlaneZ( CreateSurfFlatRegion()) ; if ( IsNull( pSfrPlaneZ)) return false ; for ( int nC = 0 ; nC < pSfrSil->GetChunkCount() ; ++ nC) { PtrOwner pSfrSilChunk( pSfrSil->CloneChunk( nC)) ; PtrOwner pSfrMyFace( CloneSurfFlatRegion( it->pSfrPlaneZ)) ; if ( IsNull( pSfrSilChunk) || IsNull( pSfrMyFace) || ! pSfrSilChunk->IsValid() || ! pSfrMyFace->IsValid()) return false ; pSfrMyFace->Intersect( *pSfrSilChunk) ; if ( ! IsNull( pSfrMyFace) && pSfrMyFace->IsValid()) { if ( pSfrPlaneZ->IsValid() && pSfrPlaneZ->GetChunkCount() > 0) pSfrPlaneZ->Add( *pSfrSilChunk) ; else pSfrPlaneZ.Set( pSfrSilChunk) ; } } // se regione PlaneZ valida if ( ! IsNull( pSfrPlaneZ) && pSfrPlaneZ->IsValid()) { // cerco le isole chiuse calcolando la silhouette leggermente sopra al piano delete( it->pSfrPlaneZ) ; it->pSfrPlaneZ = nullptr ; double dSilIslDepth = it->dDepth + SIL_DEPTH_TOL ; bool bOkSil_isl = false ; PtrOwner pSfrSilIslands( GetSfrSilhouette( pCavParSilh, dSilIslDepth, SILH_TOL, bOkSil_isl)) ; if ( ! bOkSil_isl) { m_pMchMgr->SetLastError( 3024, "Error in SurfRoughing : region not computable") ; return false ; } // pulisco la regione di Silhouette pSfrSil->Clear() ; if ( ! IsNull( pSfrSilIslands) && pSfrSilIslands->IsValid()) { // se ho delle isole valide, le sottraggo alla regione di PlaneZ pSfrSilIslands->Offset( GetOffsR(), ICurve::OFF_CHAMFER) ; pSfrPlaneZ->Subtract( *pSfrSilIslands) ; // aggiorno la regione limite if ( pSfrSil->IsValid()) pSfrSil->Add( *pSfrSilIslands) ; else pSfrSil.Set( pSfrSilIslands) ; } // la regione rimossa è la regione calcolata, con isole comprese delete( it->pSfrRemoved) ; it->pSfrRemoved = CloneSurfFlatRegion( pSfr) ; if ( ! IsNull( pSfrSilIslands) && pSfrSilIslands->IsValid()) { if ( it->pSfrRemoved != nullptr && it->pSfrRemoved->IsValid()) it->pSfrRemoved->Subtract( *pSfrSilIslands) ; } // setto la superficie PlaneZ it->pSfrPlaneZ = Release( pSfrPlaneZ) ; } if ( it->pSfrPlaneZ != nullptr && it->pSfrPlaneZ->IsValid()) pSfr->Intersect( *it->pSfrPlaneZ) ; // intersezione con silhouette // aggiorno Regione piana per gestione lati aperti if ( ! IsNull( pSfrRef) && pSfrRef->IsValid()) pSfrOpenClose->Subtract( *pSfrRef) ; } // se regione risultante non vuota if ( pSfr->IsValid() && pSfr->GetChunkCount() > 0) { // *************************** Regione Limite *************************** // la regione limite definisce le aree dove l'utensile non deve passare PtrOwner pSfrLimit( CreateSurfFlatRegion()) ; if ( IsNull( pSfrLimit)) return false ; if ( ! IsNull( pSfrOutCompo) && pSfrOutCompo->IsValid()) pSfrLimit.Set( pSfrOutCompo) ; if ( ! IsNull( pSfrSil) && pSfrSil->IsValid()) { if ( ! IsNull( pSfrLimit) && pSfrLimit->IsValid()) pSfrLimit->Add( *pSfrSil) ; else pSfrLimit.Set( pSfrSil) ; } // rimuovo tutti i chunk troppo snelli if ( it->bSubStep) { if ( ! RemoveChunksUnderTolerance( pSfr, m_dSubStepToler, pSfrLimit, it->pSfrRemoved)) { 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 step base, rimuovo i Chunk sotto una certa tolleranza if ( ! it->bSubStep && ! it->bPlaneZStep) { RemoveChunksUnderTolerance( pSfr, m_dStepToler, pSfrLimit) ; // 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 ; } } // chiudo tutti i lati aperti troppo corti if ( ! CloseOpenEdgesUnderTolerance( pSfr, m_TParams.m_dDiam - 200 * EPS_SMALL)) { m_pMchMgr->SetLastError( 3029, "Error in SurfRoughing : Simplify Chunks for SubSteps failed") ; return false ; } // rimuovo i Chunk troppo snelli ( la regione è cambiata rispetto a prima) if ( it->bSubStep) { // rimuovo tutti i Chunk snelli RemoveChunksUnderTolerance( pSfr, m_dSubStepToler, pSfrLimit) ; // 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 ; } } // se rischiesto, calcolo la regione di Corner allo/al Step/SubStep corrente bool bSfrCorner = ( ! IsNull( pSfrColl) && pSfrColl->IsValid() && ! IsNull( pSfrSearchCorners) && pSfrSearchCorners->IsValid()) ; if ( bSfrCorner) { PtrOwner pSfrCorner( GetSfrCornerColl( pSfr, pSfrLimit, pSfrColl, pSfrSearchCorners)) ; if ( ! IsNull( pSfrCorner) && pSfrCorner->IsValid()) { pSfr->Add( *pSfrCorner) ; if ( ! ChooseCloseOrOpenEdge( pSfr, pSfrOpenClose)) { m_pMchMgr->SetLastError( 3026, "Error in SurfRoughing : Detecting open edges failed") ; return false ; } } } #if ENABLE_DEBUG_SFR DrawLoopsSurf( pSfr, false, Color( .0, 1., 0., .5), it->bSubStep, ToString( it->dDepth)) ; #endif // eventuale traslazione per ultima passata appena sotto il grezzo if ( dSfrDeltaDepth < -EPS_SMALL) pSfr->Translate( dSfrDeltaDepth * vtTool) ; // memorizzo le superfici ricavate con le loro relative informazioni nel vettore vInfoSfrGeomDB.resize( vInfoSfrGeomDB.size() + 1) ; vInfoSfrGeomDB.back().pSfr.Set( Release( pSfr)) ; vInfoSfrGeomDB.back().pSfrLimit.Set( nullptr) ; if ( ! IsNull( pSfrLimit) && pSfrLimit->IsValid()) vInfoSfrGeomDB.back().pSfrLimit.Set( Release( pSfrLimit)) ; vInfoSfrGeomDB.back().pSfrRemoved.Set( nullptr) ; if ( it->pSfrRemoved != nullptr && it->pSfrRemoved->IsValid()) vInfoSfrGeomDB.back().pSfrRemoved.Set( CloneSurfFlatRegion( it->pSfrRemoved)) ; vInfoSfrGeomDB.back().bSubStep = ( it->bSubStep || it->bPlaneZStep) ; vInfoSfrGeomDB.back().dDepth = it->dDepth + GetOffsL() ; if ( ! vInfoSfrGeomDB.back().bSubStep) vInfoSfrGeomDB.back().dRelativeDepth = - dStep ; else vInfoSfrGeomDB.back().dRelativeDepth = dStep * floor( - vInfoSfrGeomDB.back().dDepth / dStep) + vInfoSfrGeomDB.back().dDepth ; double dZLocFeedCoef = GetAdaptedCoeffFeed( ( it->bSubStep || it->bPlaneZStep), it->dDepth, dStep) ; vInfoSfrGeomDB.back().dZLocCoefFeed = dZLocFeedCoef ; // aggiorno la progressBar ExeProcessEvents( 5 + nProgressBarStep * 45 / int( vStepInfo.size()), 0) ; } else { delete( it->pSfrRemoved) ; // non ho rimosso nulla it->pSfrRemoved = nullptr ; // aggiorno la progressBar ExeProcessEvents( 5 + nProgressBarStep * 45 / int( vStepInfo.size()), 0) ; } } // assegno il vettore estrazione al gruppo del percorso m_pGeomDB->SetInfo( nPxId, KEY_EXTR, vtTool) ; // Imposto dati comuni SetPathId( nPxId) ; SetToolDir( vtTool) ; Vector3d vtAux ; if ( GetValInNotes( m_Params.m_sUserNotes, UN_VTAUXDIR, vtAux)) vtAux.Normalize() ; SetAuxDir( vtAux) ; // se richiesto ordine per ZChunk, aggiusto le geometrie inserite nel gruppo if ( m_bOrderZ) OrderByZChunk( vInfoSfrGeomDB, nTempId, pSfrSgro) ; // inserisco le superfici ricavate nel gruppo temporaneo for ( int i = 0 ; i < int( vInfoSfrGeomDB.size()) ; ++ i) { // --- superficie da lavorare int nNew_SfrPock_Id = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nTempId, Release( vInfoSfrGeomDB[i].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)) ; m_pGeomDB->SetInfo( nNew_SfrPock_Id, KEY_DEPTH, ToString( vInfoSfrGeomDB[i].dDepth)) ; m_pGeomDB->SetInfo( nNew_SfrPock_Id, KEY_RELATIVE_DEPTH, ToString( vInfoSfrGeomDB[i].dRelativeDepth)) ; m_pGeomDB->SetInfo( nNew_SfrPock_Id, KEY_ZLOCFEEDCOEF, ToString( vInfoSfrGeomDB[i].dZLocCoefFeed)) ; m_pGeomDB->SetInfo( nNew_SfrPock_Id, KEY_SUBSTEP, ToString( vInfoSfrGeomDB[i].bSubStep)) ; // --- superficie limite int nNew_SfrLimit_Id = GDB_ID_NULL ; if ( ! IsNull( vInfoSfrGeomDB[i].pSfrLimit) && vInfoSfrGeomDB[i].pSfrLimit->IsValid()) { #if ENABLE_DEBUG_SFR DrawLoopsSurf( vInfoSfrGeomDB[i].pSfrLimit, true, Color( .5, .5, .5, .5), vInfoSfrGeomDB[i].bSubStep, ToString( vInfoSfrGeomDB[i].dDepth)) ; #endif nNew_SfrLimit_Id = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nTempId, Release( vInfoSfrGeomDB[i].pSfrLimit)) ; 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)) ; } // Eseguo le svuotature if ( ! AddRoughing( vPocket, vtTool, dDepth, dStep, dSubStep, bSplitArcs)) return false ; } // incremento numero di percorsi ++ m_nPaths ; return true ; } //---------------------------------------------------------------------------- bool SurfRoughing::DetectPlaneZ( const CISURFTMPVECTOR& vpStm, const Frame3d& frCompo, const Vector3d& vtTool, PLANEZFACEVECTOR& vPlaneZ, double dMinDepth, double dMaxDepth) const { // se non richiesta analisi planeZ, esco vPlaneZ.clear() ; if ( ! m_bDetectPlaneZ) return true ; // scorro il vettore di superfici su cui individuare le facce con normale vtTool for ( int i = 0 ; i < int( vpStm.size()) ; ++ i) { // per ogni superficie valida, scorro le facce if ( vpStm[i] == nullptr || ! vpStm[i]->IsValid() || ! vpStm[i]->GetTriangleCount()) continue ; for ( int nF = 0 ; nF < vpStm[i]->GetFacetCount() ; ++ nF) { // recupero centro e versore normale della faccia, verificando il parallelismo con vtTool Point3d ptCen ; Vector3d vtFaceN ; if ( ! vpStm[i]->GetFacetCenter( nF, ptCen, vtFaceN) || ! AreSameVectorEpsilon( vtTool, vtFaceN, 25 * EPS_SMALL)) continue ; // se faccia parallela a vtTool, ricavo la sua depth ( ptCen.z) ptCen.ToLoc( frCompo) ; // se fuori dal range, non la considero if ( abs( ptCen.z) < dMinDepth + 2 * EPS_SMALL || abs( ptCen.z) > dMaxDepth - 2 * EPS_SMALL) continue ; // se area troppo piccola, non la considero ( almeno area come faccia utensile) double dArea = 0. ; if ( ! vpStm[i]->GetFacetArea( nF, dArea) || dArea < PIGRECO * m_TParams.m_dDiam * m_TParams.m_dDiam / 4.) continue ; // recupero la superficie piana della faccia POLYLINEVECTOR vPL ; if ( ! vpStm[i]->GetFacetLoops( nF, vPL)) continue ; PtrOwner pSfrFace( CreateSurfFlatRegion()) ; if ( IsNull( pSfrFace)) return false ; for ( int j = 0 ; j < int( vPL.size()) ; ++ j) { PtrOwner pCompoLoop( CreateCurveComposite()) ; if ( IsNull( pCompoLoop) || ! pCompoLoop->FromPolyLine( vPL[j])) return false ; if ( j == 0) { if ( ! pSfrFace->AddExtLoop( Release( pCompoLoop))) return false ; } else { if ( ! pSfrFace->AddIntLoop( Release( pCompoLoop))) return false ; } } if ( ! pSfrFace->IsValid()) continue ; // controllo se ho già trovato una faccia su un piano simile bool bSamePlaneZ = false ; for ( int j = 0 ; j < int( vPlaneZ.size()) && ! bSamePlaneZ ; ++ j) { if ( abs( ptCen.z - vPlaneZ[j].second) < 2 * EPS_SMALL) { bSamePlaneZ = true ; vPlaneZ[j].first->Add( *pSfrFace) ; } } if ( ! bSamePlaneZ) { // definisco un nuovo Step di tipo PlaneZ vPlaneZ.resize( vPlaneZ.size() + 1) ; vPlaneZ.back().first.Set( pSfrFace) ; vPlaneZ.back().second = ptCen.z ; } } } // ordino i piani per Z in ordine decrescente sort( vPlaneZ.begin(), vPlaneZ.end(), []( const PLANEZFACE& a, const PLANEZFACE& b) { return a.second < b.second ; }) ; 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) ; } //---------------------------------------------------------------------------- ISurfTriMesh* SurfRoughing::GetStmOutSideSfr( const ISurfFlatRegion* pSfr, double dDepth, const ISurfTriMesh* pStmRaw, const Vector3d& vtExtr) const { // controllo dei parametri if ( pSfr == nullptr || ! pSfr->IsValid() || pStmRaw == nullptr || ! pStmRaw->IsValid()) return nullptr ; double dTol = 100 * EPS_SMALL ; // creo una copia della pSfr mediante un piccolo offset correttivo (per problemi con archi) PtrOwner pSfrOffs( pSfr->CreateOffsetSurf( dTol, ICurve::OFF_FILLET)) ; if ( IsNull( pSfrOffs) || ! pSfrOffs->IsValid()) return nullptr ; pSfrOffs->Translate( dTol * pSfr->GetNormVersor()) ; // definisco il vettore delle curve dei bordi della regione CICURVEPVECTOR vpCrv ; bool bOk = true ; // per ogni Chunk for ( int nC = 0 ; nC < pSfrOffs->GetChunkCount() && bOk ; ++ nC) { // per ogni Loop for ( int nL = 0 ; nL < pSfrOffs->GetLoopCount( nC) && bOk ; ++ nL) { // recupero il Loop come curva composita PtrOwner pLoop( pSfrOffs->GetLoop( nC, nL)) ; bOk = ( ! IsNull( pLoop) && pLoop->IsValid()) ; if ( bOk) vpCrv.emplace_back( Release( pLoop)) ; } } // definisco la TrimMesh limite ( inizialmente come copia del grezzo) PtrOwner pStmLimit( CloneSurfTriMesh( pStmRaw)) ; bOk = bOk && ( ! IsNull( pStmLimit) && pStmLimit->IsValid()) ; // tengo solo le parti di superficie che sono effettivamente vicine alla regione di sgrossatura // box della superficie piana BBox3d BBoxSfr ; bOk = bOk && pSfrOffs->GetLocalBBox( BBoxSfr) ; double dExtraX = abs( dDepth * ( pSfrOffs->GetNormVersor() * X_AX)) ; double dExtraY = abs( dDepth * ( pSfrOffs->GetNormVersor() * Y_AX)) ; double dExtraZ = abs( dDepth * ( pSfrOffs->GetNormVersor() * Z_AX)) ; BBoxSfr.Expand( dExtraX, dExtraY, dExtraZ) ; // scorro le parts for ( int nPart = 0 ; nPart < pStmLimit->GetPartCount() && bOk ; ++ nPart) { // calcolo il box della part corrente BBox3d BBoxPart ; bOk = bOk && pStmLimit->GetPartLocalBBox( nPart, BBoxPart) ; // se non c'è intersezione con i Box, elimino la parte corrente BBox3d BBoxInt ; if ( ! BBoxSfr.FindIntersection( BBoxPart, BBoxInt)) { bOk = pStmLimit->RemovePart( nPart) ; -- nPart ; } } // definisco la superficie di estrusione if ( bOk) { PtrOwner pStmExtr( GetSurfTriMeshByRegionExtrusion( vpCrv, ( 1 + 2. * dTol) * vtExtr)) ; bOk = ( ! IsNull( pStmExtr) && pStmExtr->IsValid()) ; // la superficie deve definire un volume double dVol = 0. ; bOk = bOk && pStmExtr->GetVolume( dVol) ; if ( dVol < EPS_ZERO) bOk = bOk && pStmExtr->Invert() ; // sottraggo al grezzo la regione di estrusione bOk = bOk && pStmLimit->Subtract( *pStmExtr) ; } // rimozione del vettore di curve costanti for ( int i = 0 ; i < int( vpCrv.size()) ; ++ i) { delete( vpCrv[i]) ; vpCrv[i] = nullptr ; } return ( bOk ? Release( pStmLimit) : nullptr) ; } //---------------------------------------------------------------------------- bool SurfRoughing::GetToolCollisionRegion( const ISurfFlatRegion* pSfrSgro, double& dDepth, ISurfFlatRegion* pSfrColl, ISurfFlatRegion* pSfrSearchCorners) const { // la collisione viene calcolata mediante tavola e ventose // se la superficie di sgrossatura non è valida, non faccio nulla if ( pSfrSgro == nullptr || ! pSfrSgro->IsValid()) return false ; // le supercici risultante deve essere vuota if ( pSfrColl == nullptr || pSfrSearchCorners == nullptr) return false ; pSfrColl->Clear() ; pSfrSearchCorners->Clear() ; // dalla superficie definisco il riferimento locale ( vista come ZTool) Frame3d frLoc ; Point3d ptCen ; pSfrSgro->GetCentroid( ptCen) ; if ( ! frLoc.Set( ptCen, pSfrSgro->GetNormVersor())) return false ; // definisco la distanza di sicurezza double const SAFE_TOL = 5. * EPS_SMALL ; // Recupero la macchina corrente e gli oggetti di Collisione Machine* pMch = m_pMchMgr->GetCurrMachine() ; if ( pMch != nullptr) { INTVECTOR vTabCollId ; if ( pMch->GetCurrTableCollGroups( vTabCollId)) { for ( const int& nCollId : vTabCollId) { // recupero il Box dell'Oggetto BBox3d BBoxTab ; if ( ! m_pGeomDB->GetGlobalBBox( nCollId, BBoxTab) || BBoxTab.IsEmpty()) continue ; // se sgrossatura orientata come la Tavola, quindi Z_AX if ( AreSameVectorApprox( pSfrSgro->GetNormVersor(), Z_AX)) { // controllo se limitare la Depth della tavola double dTabDist = abs( ( ptCen - BBoxTab.GetMax()) * pSfrSgro->GetNormVersor()) ; if ( dDepth > dTabDist - DIST_TABLE) { dDepth = dTabDist - DIST_TABLE ; string sWarn = "Warning in SurfRoughing : Depth reduced at " + ToString( dDepth, 3) ; m_pMchMgr->SetWarning( 3057, sWarn) ; } } // altrimenti else { // espando leggermente il Box per tolleranze BBoxTab.Expand( SAFE_TOL) ; // creo una TriMesh rappresentativa del Box double dDimX = BBoxTab.GetDimX() ; double dDimY = BBoxTab.GetDimY() ; double dDimZ = BBoxTab.GetDimZ() ; PtrOwner pStmBox( GetSurfTriMeshBox( dDimX, dDimY, dDimZ, true)) ; if ( IsNull( pStmBox) || ! pStmBox->IsValid()) continue ; Point3d ptBoxC ; BBoxTab.GetCenter( ptBoxC) ; Point3d ptStmC = Point3d( dDimX / 2., dDimY / 2., dDimZ / 2.) ; pStmBox->Translate( ptStmC - ptBoxC) ; // recupero la sua proiezione nel piano di sgrossatura come regione piana // NB. Usando il piano, non considero la parte di superifie nel semipiano negativo Plane3d plProj ; if ( ! plProj.Set( frLoc.Orig() - dDepth * frLoc.VersZ(), frLoc.VersZ())) return false ; POLYLINEVECTOR vPL ; if ( ! pStmBox->GetSilhouette( plProj, EPS_SMALL, vPL)) return false ; // se esiste una proiezione nel semipiano positivo, ne recupero la regione piana if ( ! vPL.empty()) { SurfFlatRegionByContours SfrByC ; for ( const PolyLine& PL : vPL) { PtrOwner pCompoLoop( CreateCurveComposite()) ; if ( IsNull( pCompoLoop) || ! pCompoLoop->FromPolyLine( PL) || ! SfrByC.AddCurve( Release( pCompoLoop))) return false ; } PtrOwner pSfrTabColl( SfrByC.GetSurf()) ; if ( IsNull( pSfrTabColl) || ! pSfrTabColl->IsValid()) return false ; // aggiorno la regione di collissione per l'utensile if ( ! pSfrColl->CopyFrom( pSfrTabColl)) return false ; if ( AreOppositeVectorApprox( pSfrColl->GetNormVersor(), frLoc.VersZ())) pSfrColl->Invert() ; #if ENABLE_DEBUG_SFR_COLLISION ISurfFlatRegion* _pSfrTab = CreateSurfFlatRegion() ; _pSfrTab->CopyFrom( pSfrColl) ; int _nSrfTbId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, _pSfrTab) ; m_pGeomDB->SetMaterial( _nSrfTbId, Color( 255, 0, 0, 50)) ; #endif } } } } } // --- ventose INTVECTOR vFxtId ; int nFxtId = m_pMchMgr->GetFirstFixture() ; while ( nFxtId != GDB_ID_NULL) { vFxtId.emplace_back( nFxtId) ; nFxtId = m_pMchMgr->GetNextFixture( nFxtId) ; } for ( const int& nFxtId : vFxtId) { // recupero il Box della ventosa BBox3d bFxtBox ; if ( m_pGeomDB->GetGlobalBBox( nFxtId, bFxtBox) && ! bFxtBox.IsEmpty()) { // se sgrossatura orientata come come Z_AX if ( AreSameVectorApprox( pSfrSgro->GetNormVersor(), Z_AX)) { // controllo se limitare la Depth della tavola double dTabDist = abs( ( ptCen - bFxtBox.GetMax()) * pSfrSgro->GetNormVersor()) ; if ( dDepth > dTabDist - DIST_TABLE) { dDepth = dTabDist - DIST_TABLE ; string sWarn = "Warning in SurfRoughing : Depth reduced at " + ToString( dDepth, 3) ; m_pMchMgr->SetWarning( 3057, sWarn) ; } } else { // espando il Box per evitare la collisione con l'utensile bFxtBox.Expand( SAFE_TOL) ; #if ENABLE_DEBUG_SFR_COLLISION ICurveComposite* _pCompoFxt = CreateCurveComposite() ; _pCompoFxt->AddPoint( bFxtBox.GetMin()) ; _pCompoFxt->AddLine( bFxtBox.GetMin() + X_AX * bFxtBox.GetDimX()) ; _pCompoFxt->AddLine( bFxtBox.GetMax() - Z_AX * bFxtBox.GetDimZ()) ; _pCompoFxt->AddLine( bFxtBox.GetMin() + Y_AX * bFxtBox.GetDimY()) ; _pCompoFxt->Close() ; _pCompoFxt->SetExtrusion( Z_AX) ; _pCompoFxt->SetThickness( bFxtBox.GetDimZ()) ; int nFxtId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, _pCompoFxt) ; m_pGeomDB->SetMaterial( nFxtId, YELLOW) ; #endif // recupero la TriMesh del Box PtrOwner pCompoFxt( CreateCurveComposite()) ; if ( IsNull( pCompoFxt)) return false ; pCompoFxt->AddPoint( bFxtBox.GetMin()) ; pCompoFxt->AddLine( bFxtBox.GetMin() + X_AX * bFxtBox.GetDimX()) ; pCompoFxt->AddLine( bFxtBox.GetMax() - Z_AX * bFxtBox.GetDimZ()) ; pCompoFxt->AddLine( bFxtBox.GetMin() + Y_AX * bFxtBox.GetDimY()) ; pCompoFxt->Close() ; CICURVEPVECTOR vpCrvs ; vpCrvs.emplace_back( pCompoFxt) ; PtrOwner pStmCollFxt( GetSurfTriMeshByRegionExtrusion( vpCrvs, Z_AX * bFxtBox.GetDimZ())) ; if ( IsNull( pStmCollFxt) || ! pStmCollFxt->IsValid() || pStmCollFxt->GetTriangleCount() == 0) return false ; // recupero la sua proiezione nel piano di sgrossatura come regione piana Plane3d plProj ; if ( ! plProj.Set( frLoc.Orig() - dDepth * frLoc.VersZ(), frLoc.VersZ())) return false ; POLYLINEVECTOR vPL ; if ( ! pStmCollFxt->GetSilhouette( plProj, EPS_SMALL, vPL)) // proiezione di 6 triangoli, veloce return false ; // se completamente dietro al piano, non influenza la sgrossatura attuale if ( vPL.empty()) continue ; SurfFlatRegionByContours SfrByC ; for ( const PolyLine& PL : vPL) { PtrOwner pCompoLoop( CreateCurveComposite()) ; if ( IsNull( pCompoLoop) || ! pCompoLoop->FromPolyLine( PL) || ! SfrByC.AddCurve( Release( pCompoLoop))) return false ; } PtrOwner pSfrFxtColl( SfrByC.GetSurf()) ; if ( IsNull( pSfrFxtColl) || ! pSfrFxtColl->IsValid()) return false ; if ( AreOppositeVectorApprox( pSfrFxtColl->GetNormVersor(), frLoc.VersZ())) pSfrFxtColl->Invert() ; // aggiorno la regione di collissione per l'utensile if ( ! pSfrColl->IsValid()) { if ( ! pSfrColl->CopyFrom( pSfrFxtColl)) return false ; } else { if ( ! pSfrColl->Add( *pSfrFxtColl)) return false ; } #if ENABLE_DEBUG_SFR_COLLISION ISurfFlatRegion* _pSfrFxt = CreateSurfFlatRegion() ; _pSfrFxt->CopyFrom( pSfrFxtColl) ; int _nSfrFxtId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, _pSfrFxt) ; m_pGeomDB->SetMaterial( _nSfrFxtId, Color( 255, 255, 0, 50)) ; #endif } } } // se ho una regione di collisione valida if ( pSfrColl->IsValid()) { PtrOwner pSfrBlock( CreateSurfFlatRegion()) ; if ( IsNull( pSfrBlock)) return false ; // scorro le curve della regione di sgrossatura e definisco delle superfici di blocco for ( int nC = 0 ; nC < pSfrSgro->GetChunkCount() ; ++ nC) { for ( int nL = 0 ; nL < pSfrSgro->GetLoopCount( nC) ; ++ nL) { PtrOwner pCompoLoop( ConvertCurveToComposite( pSfrSgro->GetLoop( nC, nL))) ; if ( ! IsNull( pCompoLoop) && pCompoLoop->IsValid()) { pCompoLoop->Translate( - pSfrSgro->GetNormVersor() * dDepth) ; for ( int nU = 0 ; nU < pCompoLoop->GetCurveCount() ; ++ nU) { const ICurve* pSubCrvLoop = pCompoLoop->GetCurve( nU) ; if ( pSubCrvLoop == nullptr || ! pSubCrvLoop->IsValid()) return false ; CRVCVECTOR ccClass ; if ( ! pSfrColl->GetCurveClassification( *pSubCrvLoop, EPS_SMALL, ccClass)) return false ; bool bBlock = false ; for ( int i = 0 ; ! bBlock && i < ssize( ccClass) ; ++ i) { if ( ccClass[i].nClass == CRVC_OUT) continue ; PtrOwner pCrvColl( pSubCrvLoop->CopyParamRange( ccClass[i].dParS, ccClass[i].dParE)) ; if ( IsNull( pCrvColl) || ! pCrvColl->IsValid()) continue ; double dLen = 0. ; pCrvColl->GetLength( dLen) ; bBlock = ( dLen > 2. * SAFE_TOL) ; } if ( bBlock) { PtrOwner pCompoBlock( CreateCurveComposite()) ; if ( IsNull( pCompoBlock)) return false ; pCompoBlock->AddCurve( pSubCrvLoop->Clone()) ; pCompoBlock->SetExtrusion( pSfrSgro->GetNormVersor()) ; OffsetCurve OffsCrv ; // ... rappresentativo OffsCrv.Make( pCompoBlock, m_TParams.m_dDiam, ICurve::OFF_FILLET) ; PtrOwner pCrvOffs( OffsCrv.GetLongerCurve()) ; if ( IsNull( pCrvOffs) || ! pCrvOffs->IsValid()) return false ; pCompoBlock->Invert() ; Point3d ptA ; pCrvOffs->GetStartPoint( ptA) ; Point3d ptC ; pCompoBlock->GetStartPoint( ptC) ; pCompoBlock->AddLine( ptA) ; pCompoBlock->AddCurve( Release( pCrvOffs)) ; pCompoBlock->AddLine( ptC) ; #if ENABLE_DEBUG_SFR_COLLISION int _nCrvId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCompoBlock->Clone()) ; m_pGeomDB->SetMaterial( _nCrvId, PURPLE) ; #endif PtrOwner pSfrCurrBlock( CreateSurfFlatRegion()) ; if ( IsNull( pSfrCurrBlock)) return false ; if ( ! pSfrCurrBlock->AddExtLoop( Release( pCompoBlock))) return false ; if ( ! pSfrBlock->IsValid()) { if ( ! pSfrBlock.Set( Release( pSfrCurrBlock))) return false ; } else { if ( ! pSfrBlock->Add( *pSfrCurrBlock)) return false ; } } } } } } // se non ho una superficie di Blocco, allora non devo fare nulla if ( IsNull( pSfrBlock) || ! pSfrBlock->IsValid()) return true ; // determino la superficie di collisione pSfrColl->Clear() ; pSfrColl->CopyFrom( pSfrBlock) ; // per essere sufficientemente distanti pSfrColl->Offset( 50. * EPS_SMALL, ICurve::OFF_FILLET) ; // riporto la superficie alla stessa quota della regione di sgrossatura pSfrColl->Translate( pSfrSgro->GetNormVersor() * dDepth) ; // determino la superficie di ricerca per la pulizia dei corners pSfrSearchCorners->Clear() ; pSfrSearchCorners->CopyFrom( pSfrColl) ; pSfrSearchCorners->Offset( 1.5 * m_TParams.m_dDiam + TOL_OFFS_CORNER_COLL, ICurve::OFF_FILLET) ; if ( ! pSfrSearchCorners->Intersect( *pSfrSgro)) return false ; } #if ENABLE_DEBUG_SFR_COLLISION int _nSfrId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSfrColl->Clone()) ; m_pGeomDB->SetMaterial( _nSfrId, Color( 128, 0, 128, 50)) ; _nSfrId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSfrSearchCorners->Clone()) ; m_pGeomDB->SetMaterial( _nSfrId, Color( 128, 128, 0, 50)) ; #endif return true ; } //---------------------------------------------------------------------------- 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 = 10 * 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) ; } //---------------------------------------------------------------------------- ISurfFlatRegion* SurfRoughing::GetSfrSilhouette( ICAvParSilhouettesSurfTm* pCavParSilh, double dDepth, double Sil_tol, bool& bOk) const { // controllo dei parametri bOk = false ; if ( pCavParSilh == nullptr) return nullptr ; // vettore di PolyLine POLYLINEVECTOR vPL ; if ( ! pCavParSilh->GetSilhouette( dDepth, vPL)) return nullptr ; // 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 nullptr ; pSilCrv->FromPolyLine( PL) ; // approssimo con archi const double SILH_ARC_TOL = 0.1 * Sil_tol ; const double SILH_ARC_FEA_MAX = 100. ; PolyArc PA ; if ( pSilCrv->ApproxWithArcsEx( SILH_ARC_TOL, ANG_TOL_STD_DEG, SILH_ARC_FEA_MAX, PA)) { PtrOwner pTempCrv( CreateCurveComposite()) ; if ( ! IsNull( pTempCrv) && pTempCrv->FromPolyArc( PA) && pTempCrv->RemoveSmallDefects( SILH_ARC_TOL / 2, ANG_TOL_STD_DEG) && pTempCrv->MergeCurves( SILH_ARC_TOL / 2, ANG_TOL_STD_DEG) && pTempCrv->IsValid()) pSilCrv.Set( pTempCrv) ; } // aggiungo per regione if ( ! SfrMaker.AddCurve( Release( pSilCrv))) return nullptr ; } bOk = true ; return ( SfrMaker.GetSurf()) ; } //---------------------------------------------------------------------------- ISurfFlatRegion* SurfRoughing::GetSfrCornerColl( ISurfFlatRegion* pSfr, const ISurfFlatRegion* pSfrLimit, const ISurfFlatRegion* pSfrColl, const ISurfFlatRegion* pSfrSearchCorners) const { /* se ho la presenza di tavole o ventose, la superficie di collissione ricavata genera dei nuovi lati chiusi nella geometria attuale ( pSfr deve già avere impostati i lati OPEN/CLOSE) i nuovi lati chiusi possono generare regioni i cui spigoli non si possono svuotare ( nei punti di unione dei lati aperti originali con i nuovi chiusi). questa funzione aggiunge delle piccole parti di regione in questi punti, evitando quindi la presenza di colonne di materiale non rimosso NB. questa parti non riguardano nè le regioni non vuotate, nè le regioni di silhouette ipotetica */ // se la superficie di collissione non è valida non faccio nulla if ( pSfrColl == nullptr || ! pSfrColl->IsValid() || pSfrSearchCorners == nullptr || ! pSfrSearchCorners->IsValid()) return nullptr ; if ( pSfr == nullptr) return nullptr ; #if ENABLE_DEBUG_REMOVED_REGION int _nIdSfrSearch = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSfrSearchCorners->Clone()) ; m_pGeomDB->SetMaterial( _nIdSfrSearch, YELLOW) ; int _nIdSfrLimit = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSfrLimit->Clone()) ; m_pGeomDB->SetMaterial( _nIdSfrLimit, GRAY) ; DrawLoopsSurf( pSfr, false, Color( 0., 1., 0.), false, "") ; #endif // recupero tutti i lati aperti della superficie attuale ICURVEPOVECTOR vCrvOpenInSearch ; for ( int nC = 0 ; nC < pSfr->GetChunkCount() ; ++ nC) { for ( int nL = 0 ; nL < pSfr->GetLoopCount( nC) ; ++ nL) { PtrOwner pCompoLoop( ConvertCurveToComposite( pSfr->GetLoop( nC, nL))) ; if ( IsNull( pCompoLoop) || ! pCompoLoop->IsValid()) return nullptr ; ICRVCOMPOPOVECTOR vpCrvs ; GetHomogeneousParts( pCompoLoop, vpCrvs) ; for ( int i = 0 ; i < ssize( vpCrvs) ; ++ i) { if ( vpCrvs[i]->GetTempProp( 0) == TEMP_PROP_OPEN_EDGE) { CRVCVECTOR ccClass ; if ( ! pSfrSearchCorners->GetCurveClassification( *vpCrvs[i], EPS_SMALL, ccClass)) return nullptr ; for ( int j = 0 ; j < ssize( ccClass) ; ++ j) { if ( ccClass[j].nClass != CRVC_OUT) { PtrOwner pCrvIn( vpCrvs[i]->CopyParamRange( ccClass[j].dParS, ccClass[j].dParE)) ; if ( ! IsNull( pCrvIn) && pCrvIn->IsValid()) { if ( ! vCrvOpenInSearch.emplace_back( Release( pCrvIn))) return nullptr ; } } } } } } } #if ENABLE_DEBUG_REMOVED_REGION for ( int _i = 0 ; _i < ssize( vCrvOpenInSearch) ; ++ _i) { int _nIdCrvOpen = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, vCrvOpenInSearch[_i]->Clone()) ; m_pGeomDB->SetMaterial( _nIdCrvOpen, ORANGE) ; } #endif // determino la regione complessiva di ricerca PtrOwner pSfrExtra( CreateSurfFlatRegion()) ; if ( IsNull( pSfrExtra)) return nullptr ; double dOffs = m_TParams.m_dDiam + 50. * EPS_SMALL ; // deve passare l'utensile per tale regione for ( int i = 0 ; i < ssize( vCrvOpenInSearch) ; ++ i) { // recupero la curva come composita PtrOwner pCrvCompo( ConvertCurveToComposite( vCrvOpenInSearch[i]->Clone())) ; if ( IsNull( pCrvCompo) || ! pCrvCompo->IsValid()) return nullptr ; // calcolo il semi-offset pCrvCompo->SetExtrusion( pSfr->GetNormVersor()) ; OffsetCurve OffsCrv ; if ( ! OffsCrv.Make( pCrvCompo, dOffs / 2., ICurve::OFF_FILLET)) return nullptr ; PtrOwner pCrvOffs( OffsCrv.GetLongerCurve()) ; if ( IsNull( pCrvOffs) || ! pCrvOffs->IsValid()) return nullptr ; // determino la regione da aggiungere if ( IsNull( pSfrExtra) || ! pSfrExtra->IsValid()) pSfrExtra.Set( GetSurfFlatRegionFromFatCurve( pCrvOffs->Clone(), dOffs / 2. + 50. * EPS_SMALL, false, false)) ; else { PtrOwner pSfrToAdd( GetSurfFlatRegionFromFatCurve( pCrvOffs->Clone(), dOffs / 2 + 50. * EPS_SMALL, false, false)) ; if ( IsNull( pSfrToAdd) || ! pSfrToAdd->IsValid()) return nullptr ; pSfrExtra->Add( *pSfrToAdd) ; } if ( IsNull( pSfrExtra) || ! pSfrExtra->IsValid()) return nullptr ; } if ( IsNull( pSfrExtra) || ! pSfrExtra->IsValid()) return nullptr ; if ( ! pSfrExtra->Intersect( *pSfrSearchCorners)) return nullptr ; // rimuovo i Chunk che non sono attaccati alle curve aperte ricavate for ( int nC = 0 ; nC < pSfrExtra->GetChunkCount() ; ++ nC) { PtrOwner pSfrExtraChunk( pSfrExtra->CloneChunk( nC)) ; if ( IsNull( pSfrExtraChunk) || ! pSfrExtraChunk->IsValid()) return nullptr ; bool bSave = false ; for ( int i = 0 ; ! bSave && i < ssize( vCrvOpenInSearch) ; ++ i) { CRVCVECTOR ccClass ; if ( pSfrExtraChunk->GetCurveClassification( *vCrvOpenInSearch[i], 10. * EPS_SMALL, ccClass)) { for ( int j = 0 ; ! bSave && j < ssize( ccClass) ; ++ j) bSave = ( ccClass[j].nClass != CRVC_OUT) ; } } if ( ! bSave) { pSfrExtra->EraseChunk( nC) ; -- nC ; } } // se superficie non valida, ho finito if ( IsNull( pSfrExtra) || ! pSfrExtra->IsValid()) return nullptr ; // rimuovo la regione da non rovinare, ho esteso i lati aperti mediante Offset semplice, // devo controllare di non rovinare altre regioni // regolarizzo la superficie pSfrExtra->Offset( m_TParams.m_dDiam / 8., ICurve::OFF_FILLET) ; pSfrExtra->Offset( - m_TParams.m_dDiam / 8., ICurve::OFF_FILLET) ; if ( ! pSfrExtra->Subtract( *pSfrLimit)) return nullptr ; #if ENABLE_DEBUG_REMOVED_REGION int _nIdExtraSfr = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSfrExtra->Clone()) ; m_pGeomDB->SetMaterial( _nIdExtraSfr, FUCHSIA) ; #endif return ( Release( pSfrExtra)) ; } //---------------------------------------------------------------------------- bool SurfRoughing::GetActiveSurfaces( INTVECTOR& vSurfId, INTVECTOR& vSurfSuppId) const { // NB. // - vSrufInd contiene gli Id delle superfici selezionate ( nel caso non ci siano superfici // selezionate, allora vengono considerate tutte le superfici presenti nei grezzi attivi della fase) // - vSurfSupp contiene gli Id delle superfici di supporto, quindi quelle superici da cui si vuole // mantenere una certa distanza con l'utensile ( senza che siano selezionate) // pulisco vettore superfici vSurfId.clear() ; vSurfSuppId.clear() ; // verifiche if ( m_pMchMgr == nullptr || m_pGeomDB == nullptr) return false ; // cerco tra gli oggetti selezionati ( superfici TriMesh o Bezier) for ( const auto& Id : m_vId) { int nEntId = Id.nId ; int nType = m_pGeomDB->GetGeoType( nEntId) ; if ( nType == SRF_TRIMESH || nType == SRF_BEZIER) vSurfId.emplace_back( nEntId) ; } // controllo se sono state trovate delle superfici bool bNoSurfId = ( vSurfId.empty()) ; // scorro 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->GetGeoType( nEntId) == SRF_BEZIER) && m_pGeomDB->GetCalcStatus( nEntId, nStat) && nStat != GDB_ST_OFF) { // se non sono state selezionate superfici precedentemente, memorizzo tale id if ( bNoSurfId) vSurfId.emplace_back( nEntId) ; // verifico se è presente una superficie di controllo string sLayIdName ; if ( m_pGeomDB->GetName( nLayId, sLayIdName) && EqualNoCase( sLayIdName, SRF_SUPP_LAYER_NAME)) vSurfSuppId.emplace_back( nEntId) ; } // passo alla entità successiva nEntId = m_pGeomDB->GetNext( nEntId) ; } nLayId = m_pGeomDB->GetNextGroup( nLayId) ; } nPartId = m_pMchMgr->GetNextPartInRawPart( nPartId) ; } } nRawId = m_pMchMgr->GetNextRawPart( nRawId) ; } return true ; } //---------------------------------------------------------------------------- bool SurfRoughing::CalcPaths( const INTINTVECTOR& vPocket, STEPINFOSRVECTOR& vStepInfo) const { // Funzione per calcolo dei percorsi di Pockets e delle loro proprietà // inizializzo vettore dei percorsi vStepInfo.resize( vPocket.size()) ; // punto finale di riferimento per il percorso attuale ( serve per trovare il punto iniziale // del percorso successivo) Point3d ptEndLastPath = P_INVALID ; // determino se Conventional Milling o Climb Milling per curve singole bool bConventionalMilling = ( m_Params.m_nSubType == POCKET_ONEWAY || m_Params.m_nSubType == POCKET_CONFORMAL_ONEWAY) ; // scorro gli indici delle superfici int nInd = 0 ; for ( auto& vId : vPocket) { // --- recupero la superficie da lavorare const ISurfFlatRegion* pSfrPock = GetSurfFlatRegion( m_pGeomDB->GetGeoObj( vId.first)) ; if ( pSfrPock == nullptr || ! pSfrPock->IsValid()) continue ; vStepInfo[nInd].pSfrPock.Set( CloneSurfFlatRegion( pSfrPock)) ; // --- recupero Flag per step normale o extra ( SubStep/PlaneZ) string sIsExtraStep = "" ; bool bIsExtraStep = false ; if ( ! m_pGeomDB->GetInfo( vId.first, KEY_SUBSTEP, sIsExtraStep) || ! FromString( sIsExtraStep, bIsExtraStep)) { m_pMchMgr->SetLastError( 3035, "Error in SurfRoughing : Entity without Info") ; return false ; } vStepInfo[nInd].bIsExtraStep = bIsExtraStep ; // --- recupero la Depth attuale string sDepth = "" ; double dDepth = 0. ; if ( ! m_pGeomDB->GetInfo( vId.first, KEY_DEPTH, sDepth) || ! FromString( sDepth, dDepth)) { m_pMchMgr->SetLastError( 3035, "Error in SurfRoughing : Entity without Info") ; return false ; } vStepInfo[nInd].dDepth = dDepth ; // --- recupero la Depth relativa string sRelativeDepth = "" ; double dRelativeDepth = 0. ; if ( ! m_pGeomDB->GetInfo( vId.first, KEY_RELATIVE_DEPTH, sRelativeDepth) || ! FromString( sRelativeDepth, dRelativeDepth)) { m_pMchMgr->SetLastError( 3035, "Error in SurfRoughing : Entity without Info") ; return false ; } vStepInfo[nInd].dRelativeDepth = dRelativeDepth ; // --- recupero il coefficiente di riduzione Feed locale string sZlocCoeffFeed = "" ; double dZlocCoeffFeed = 0. ; if ( ! m_pGeomDB->GetInfo( vId.first, KEY_ZLOCFEEDCOEF, sZlocCoeffFeed) || ! FromString( sZlocCoeffFeed, dZlocCoeffFeed)) { m_pMchMgr->SetLastError( 3035, "Error in SurfRoughing : Entity without Info") ; return false ; } vStepInfo[nInd].dZlocCoeffFeed = dZlocCoeffFeed ; // --- recupero la superficie limite se presente vStepInfo[nInd].pSfrLimit.Set( CreateSurfFlatRegion()) ; if ( vId.second != GDB_ID_NULL) { const ISurfFlatRegion* pSfrL = GetSurfFlatRegion( m_pGeomDB->GetGeoObj( vId.second)) ; if ( pSfrL == nullptr) return false ; vStepInfo[nInd].pSfrLimit.Set( CloneSurfFlatRegion( pSfrL)) ; } // se il tipo è SPIRAL_OUT e sto gestendo uno step intermedio, lo lavoro come SPIRAL_IN invertito int nSubType = m_Params.m_nSubType ; bool bInvert = m_Params.m_bInvert ; if ( nSubType == SURFROU_SUB_SPIRALOUT && vStepInfo[nInd].bIsExtraStep) { nSubType = SURFROU_SUB_SPIRALIN ; bInvert = ! bInvert ; // per lasciare invariato il senso di percorrenza } vStepInfo[nInd].nSubType = nSubType ; vStepInfo[nInd].bInverted = bInvert ; // calcolo i percorsi di Pocketing ICRVCOMPOPOVECTOR vCrvPaths ; if ( ! CalcPocketing( vStepInfo[nInd].pSfrPock, m_TParams.m_dDiam / 2, 0., m_Params.m_dSideStep, m_Params.m_dSideAngle, 5., vStepInfo[nInd].nSubType, true, true, vStepInfo[nInd].bInverted, false, bConventionalMilling, true, true, ptEndLastPath, vStepInfo[nInd].pSfrLimit, false, m_Params.m_dSideStep, GetLeadInType(), m_Params.m_dLiTang, m_Params.m_dLiElev, GetLeadOutType(), m_Params.m_dLoTang, false, 0., 0., vCrvPaths)) { if ( vStepInfo[nInd].bIsExtraStep) { string sWarn = "Warning in SurfRoughing : CalcPocketing failed with substep (" + ToString( vStepInfo[nInd].dDepth, 1) + ")" ; m_pMchMgr->SetWarning( 3055, sWarn) ; vCrvPaths.clear() ; } else { m_pMchMgr->SetLastError( 3028, "Error in SurfRoughing : Error in CalcPocketing") ; return false ; } } // se non ho ottenuto percorsi, allora passo allo step successivo ( nInd non viene aggiornato!) if ( vCrvPaths.empty()) continue ; // sistemo gli archi per massimo angolo al centro for ( int i = 0 ; i < int( vCrvPaths.size()) ; ++ i) VerifyArcs( vCrvPaths[i]) ; // recupero il punto finale del percorso per lo step successivo vCrvPaths.back()->GetEndPoint( ptEndLastPath) ; // aggiorno il vettore degli step e modifico eventuali percorsi per LeadIn/LeadOut // --- Controllo se il tratto lineare di estensione per l'entrata da un lato aperto non rovina // --- un tratto chiuso della curva di bordo selezionata per la sgrossatura; // --- idem per il tratto in uscita. vStepInfo[nInd].vPaths.resize( int( vCrvPaths.size())) ; for ( int i = 0 ; i < int( vCrvPaths.size()) ; ++ i) { // controllo se il percorso ha un ingresso presso un lato aperto vStepInfo[nInd].vPaths[i].bOutStart = ( vCrvPaths[i]->GetCurveCount() > 0 && vCrvPaths[i]->GetFirstCurve()->GetTempProp( 0) == TEMP_PROP_OUT_START) ; // se utensile che non lavora di testa e ingresso non fuori dal pezzo, errore if ( m_TParams.m_nType == TT_MILL_NOTIP && ! vStepInfo[nInd].vPaths[i].bOutStart) { if ( ! LeadInRawIsOk()) { m_pMchMgr->SetLastError( 3031, "Error in SurfRoughing : LeadIn with Mill NoTip in material") ; return false ; } } // controllo se il percorso è formato da una singola curva seguente il lato chiuso vStepInfo[nInd].vPaths[i].bSingleCrv = ( vCrvPaths[i]->GetCurveCount() > 0 && vCrvPaths[i]->GetTempProp( 0) == TEMP_PROP_SINGLE_CURVE) ; // controllo se caso ottimizzato a trapezio vStepInfo[nInd].vPaths[i].bOptTrap = ( vCrvPaths[i]->GetCurveCount() > 0 && vCrvPaths[i]->GetTempProp( 0) == TEMP_PROP_OPT_TRAPEZOID) ; // controllo se è un percorso a ZigZag/OneWay ( non curva di bordo) vStepInfo[nInd].vPaths[i].bIsZigZagOneWayBorder = ( vCrvPaths[i]->GetCurveCount() > 0 && ( vStepInfo[nInd].nSubType == SURFROU_SUB_ONEWAY || vStepInfo[nInd].nSubType == SURFROU_SUB_ZIGZAG) && vCrvPaths[i]->GetTempProp( 0) == TEMP_PROP_BORDER_CURVE) ; // se LeadIn o LeadOut a guida recupero la curva di ritorno se necessaria if ( ( GetLeadInType() == SURFROU_LI_GLIDE || GetLeadOutType() == SURFROU_LO_GLIDE) && ( vStepInfo[nInd].nSubType == SURFROU_SUB_SPIRALIN && ! vStepInfo[nInd].vPaths[i].bSingleCrv && ! vStepInfo[nInd].vPaths[i].bOutStart)) { if ( vStepInfo[nInd].vPaths[i].bOptTrap) vStepInfo[nInd].vPaths[i].pCvrRet.Set( ConvertCurveToComposite( vCrvPaths[i]->GetFirstCurve()->Clone())) ; else { Point3d ptStart ; vCrvPaths[i]->GetFirstCurve()->GetStartPoint( ptStart) ; vStepInfo[nInd].vPaths[i].pCvrRet.Set( CreateCurveComposite()) ; for ( int j = 0 ; j < vCrvPaths[i]->GetCurveCount() ; ++ j) { const ICurve* pCrv = vCrvPaths[i]->GetCurve( j) ; Point3d ptEnd ; if ( pCrv == nullptr || ! vStepInfo[nInd].vPaths[i].pCvrRet->AddCurve( *pCrv) || ! pCrv->GetEndPoint( ptEnd)) return false ; if ( AreSamePointApprox( ptStart, ptEnd)) break ; } } } // assegno il percorso vStepInfo[nInd].vPaths[i].pCrvPath.Set( vCrvPaths[i]) ; } ++ nInd ; // aggiorno la progressBar ExeProcessEvents( 50 + nInd * 50 / int( vPocket.size()), 0) ; } vStepInfo.resize( nInd) ; return true ; } //---------------------------------------------------------------------------- bool SurfRoughing::GetLinkFromPaths( STEPINFOSRVECTOR& vStepInfo, int i, int j, const Point3d& ptStart, const Vector3d& vtTool, double dSafeZ, double dExtraElev, double& dEndElev, ICurveComposite* pCrvLink) const { // NB. Tutte le ipotesi descritte valgono globalmente per l'ordine di sgrossatura per piani; // Nel caso di ordine ZChunk queste ipotesi valgono localmente. // controllo dei parametri if ( vStepInfo.empty()) return true ; if ( pCrvLink == nullptr) return false ; // reset parametri restituiti pCrvLink->Clear() ; dEndElev = 0. ; // verifico se lo step successivo si trova sopra, sotto o sullo stesso piano di quello corrente // recupero anche il suo punto iniziale, ovvero il punto finale del Link int nLinkType = -1 ; Point3d ptEnd ; if ( j < ssize( vStepInfo[i].vPaths) - 1) { nLinkType = PLANAR ; vStepInfo[i].vPaths[j+1].pCrvPath->GetStartPoint( ptEnd) ; } else { // --- se non esiste lo Step i+1 errore if ( i + 1 >= ssize( vStepInfo)) return false ; vStepInfo[i+1].vPaths.front().pCrvPath->GetStartPoint( ptEnd) ; nLinkType = ( ( ptEnd - ptStart) * vtTool < - 50 * EPS_SMALL ? DOWN : ABOVE) ; } // se estremi coincidenti, non faccio nulla if ( AreSamePointApprox( ptStart, ptEnd)) return true ; #if ENBALE_DEBUG_LINK int nGrp = m_pGeomDB->AddGroup( GDB_ID_NULL, GDB_ID_ROOT, GLOB_FRM) ; m_pGeomDB->SetName( nGrp, "Path Links") ; int nLay = m_pGeomDB->AddGroup( GDB_ID_NULL, nGrp, GLOB_FRM) ; PtrOwner pt( CreateGeoPoint3d()) ; pt->Set( ptStart) ; int nPt = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLay, pt->Clone()) ; m_pGeomDB->SetMaterial( nPt, RED) ; pt->Set( ptEnd) ; nPt = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLay, pt->Clone()) ; m_pGeomDB->SetMaterial( nPt, AQUA) ; #endif // calcolo l'elevazione sopra al collegamento lineare double dElev = 0. ; if ( ! GetElevation( m_nPhase, ptStart, ptEnd, vtTool, m_TParams.m_dDiam / 2., m_TParams.m_dLen, vtTool, dElev)) return false ; // --- se l'elevazione è nulla, allora il collegamento è completamente fuori dal grezzo, quindi ho finito if ( dElev < EPS_SMALL) { pCrvLink->AddPoint( ptStart) ; pCrvLink->AddLine( ptEnd) ; #if ENBALE_DEBUG_LINK int nCrv = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLay, pCrvLink->Clone()) ; m_pGeomDB->SetMaterial( nCrv, LIME) ; #endif return true ; } // classifico a seconda del tipo di collegamento switch ( nLinkType) { case DOWN : { // ---------- il percorso successivo si trova ad uno step più in basso ---------- // Controllo se sono fuori dalla regione limite allo step i-esimo bool bSafe = false ; if ( ! CheckSafetyLinearLink( ptStart, ptEnd, vStepInfo[i].pSfrLimit, vtTool, bSafe)) return false ; // nel caso stessi ordinando per ZChunk, devo controllare di essere fuori dalla limite // anche per lo Step i+1 // NB. Nel caso stessi ordinando per piani, vuol dire che ho già svuotato tutto il piano i-esimo // Se Safe, allora definisco il collegamento if ( bSafe) { pCrvLink->AddPoint( ptStart) ; dEndElev = abs( vStepInfo[i].dDepth - vStepInfo[i+1].dDepth) ; pCrvLink->AddLine( ptEnd + dEndElev * vtTool) ; #if ENBALE_DEBUG_LINK int nCrv = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLay, pCrvLink->Clone()) ; m_pGeomDB->SetMaterial( nCrv, LIME) ; #endif return true ; } // Se non Safe, allora cerco tra gli Step percorsi in precedenza quelli con cui il collegamento // lineare non interferisce con la regione limite, tra tutti quelli validi cerco quello più vicino // e al di sopra dello step corrente double dCurrDepth = vStepInfo[i].dDepth ; double dMinDepthAbove = INFINITO ; bool bFound = false ; for ( int nStep = i - 1 ; nStep >= 0 ; -- nStep) { bSafe = false ; if ( ! CheckSafetyLinearLink( ptStart, ptEnd, vStepInfo[nStep].pSfrLimit, vtTool, bSafe)) return false ; if ( bSafe && vStepInfo[nStep].dDepth > dCurrDepth && vStepInfo[nStep].dDepth < dMinDepthAbove) { dMinDepthAbove = vStepInfo[nStep].dDepth ; bFound = true ; } } // Se ho trovato un step più alto fatto in precedenza valido, allora l'elevazione iniziale è la // differenza tra le profondità, altrimenti mi alzo dell'intera profondità dello step corrente double dStartElev = ( bFound ? abs( dMinDepthAbove - dCurrDepth) + dSafeZ : abs( dCurrDepth) + dSafeZ) ; Point3d ptUp = ptStart + dStartElev * vtTool ; dEndElev = abs( ( ptEnd - ptUp) * vtTool) ; pCrvLink->AddPoint( ptStart) ; pCrvLink->AddLine( ptUp) ; pCrvLink->AddLine( ptEnd + dEndElev * vtTool) ; #if ENBALE_DEBUG_LINK int nCrv = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLay, pCrvLink->Clone()) ; m_pGeomDB->SetMaterial( nCrv, LIME) ; #endif return true ; } break ; case PLANAR : { // ---------- il percorso successivo si trova allo stesso step del corrente ---------- // Devo controllare di essere fuori dalla limite corrente e fuori da tutti i Chunk di pocketing // dello stesso piano non ancora rimossi // Controllo di essere fuori dalla limite bool bSafe = false ; if ( ! CheckSafetyLinearLink( ptStart, ptEnd, vStepInfo[i].pSfrLimit, vtTool, bSafe)) return false ; // --- Se fuori dalla Limite if ( bSafe) { // Scorro i percorsi successivi per individuare i Chunks PtrOwner pSfrUncleared( CreateSurfFlatRegion()) ; if ( IsNull( pSfrUncleared)) return false ; for ( int nPath = j + 1 ; nPath < int( vStepInfo[i].vPaths.size()) ; ++ nPath) { Point3d ptMid ; vStepInfo[i].vPaths[nPath].pCrvPath->GetMidPoint( ptMid) ; int nMinChunk = -1 ; int nMinLoop = -1 ; double dMinPar = 0. ; DistPointSurfFr( ptMid, *vStepInfo[i].pSfrPock).GetParamAtMinDist( nMinChunk, nMinLoop, dMinPar) ; pSfrUncleared->AddExtLoop( vStepInfo[i].pSfrPock->GetLoop( nMinChunk, 0)) ; for ( int nL = 1 ; nL < vStepInfo[i].pSfrPock->GetLoopCount( nMinChunk) ; ++ nL) pSfrUncleared->AddIntLoop( vStepInfo[i].pSfrPock->GetLoop( nMinChunk, nL)) ; } // Controllo di essere fuori dalla superficie creata if ( ! CheckSafetyLinearLink( ptStart, ptEnd, pSfrUncleared, vtTool, bSafe)) return false ; // --- Se sono al di fuori di tutto if ( bSafe) { pCrvLink->AddPoint( ptStart) ; pCrvLink->AddLine( ptEnd) ; dEndElev = 0. ; #if ENBALE_DEBUG_LINK int nCrv = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLay, pCrvLink->Clone()) ; m_pGeomDB->SetMaterial( nCrv, LIME) ; #endif return true ; } } // Se non Safe, allora cerco tra gli Step percorsi in precedenza quelli con cui il collegamento // lineare non interferisce con la regione limite, tra tutti quelli validi cerco quello più vicino // e al di sopra dello step corrente double dCurrDepth = vStepInfo[i].dDepth ; double dMinDepthAbove = INFINITO ; bool bFound = false ; for ( int nStep = i - 1 ; nStep >= 0 ; -- nStep) { bSafe = false ; if ( ! CheckSafetyLinearLink( ptStart, ptEnd, vStepInfo[nStep].pSfrLimit, vtTool, bSafe)) return false ; if ( bSafe && vStepInfo[nStep].dDepth > dCurrDepth && vStepInfo[nStep].dDepth < dMinDepthAbove) { dMinDepthAbove = vStepInfo[nStep].dDepth ; bFound = true ; } } // Se ho trovato un step più alto fatto in precedenza valido, allora l'elevazione iniziale è la // differenza tra le profondità, altrimenti mi alzo dell'intera profondità dello step corrente double dStartElev = ( bFound ? abs( dMinDepthAbove - dCurrDepth) + dSafeZ : abs( dCurrDepth) + dSafeZ) ; Point3d ptUp = ptStart + dStartElev * vtTool ; dEndElev = abs( ( ptEnd - ptUp) * vtTool) ; pCrvLink->AddPoint( ptStart) ; pCrvLink->AddLine( ptUp) ; pCrvLink->AddLine( ptEnd + dEndElev * vtTool) ; #if ENBALE_DEBUG_LINK int nCrv = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLay, pCrvLink->Clone()) ; m_pGeomDB->SetMaterial( nCrv, LIME) ; #endif return true ; } break ; case ABOVE : { // ---------- il percorso successivo si trova al di sopra dello step del corrente ---------- // Significa che allo Step (i+1)-esimo non ho ancora rimosso nulla double dStartElev = 0. ; // Controllo di essere fuori dalla Limite e dalla regione di Pocketing allo step i+1 bool bSafe = false ; if ( ! m_bOrderZ) { // --- Se sto sgrossando per piani paralleli, allora le superficie allo step i+1 sono complessive if ( ! CheckSafetyLinearLink( ptStart, ptEnd, vStepInfo[i+1].pSfrLimit, vtTool, bSafe)) return false ; if ( bSafe) { if ( ! CheckSafetyLinearLink( ptStart, ptEnd, vStepInfo[i+1].pSfrPock, vtTool, bSafe)) return false ; } } else { // --- Se sto sfrossando per ZChunks, allora devo recuperare tutti i chunk alla quota successiva for ( int nStep = 0 ; nStep < int( vStepInfo.size()) && bSafe ; ++ nStep) { if ( abs( vStepInfo[nStep].dDepth - vStepInfo[i+1].dDepth) < 50. * EPS_SMALL) { if ( ! CheckSafetyLinearLink( ptStart, ptEnd, vStepInfo[i+1].pSfrLimit, vtTool, bSafe)) return false ; if ( bSafe) { if ( ! CheckSafetyLinearLink( ptStart, ptEnd, vStepInfo[i+1].pSfrPock, vtTool, bSafe)) return false ; } } } } // --- Se Safe, allora definisco il collegamento if ( bSafe) { pCrvLink->AddPoint( ptStart) ; dStartElev = abs( ( ptStart - ptEnd) * vtTool) ; pCrvLink->AddLine( ptStart + dStartElev * vtTool) ; pCrvLink->AddLine( ptEnd) ; dEndElev = 0. ; #if ENBALE_DEBUG_LINK int nCrv = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLay, pCrvLink->Clone()) ; m_pGeomDB->SetMaterial( nCrv, LIME) ; #endif } else { // Se non Safe, allora cerco tra gli Step percorsi in precedenza quelli con cui il collegamento // lineare non interferisce con la regione limite, tra tutti quelli validi cerco quello più vicino // e al di sopra dello step corrente double dCurrDepth = vStepInfo[i].dDepth ; double dMinDepthAbove = INFINITO ; bool bFound = false ; for ( int nStep = i - 1 ; nStep >= 0 ; -- nStep) { bSafe = false ; if ( ! CheckSafetyLinearLink( ptStart, ptEnd, vStepInfo[nStep].pSfrLimit, vtTool, bSafe)) return false ; if ( bSafe && vStepInfo[nStep].dDepth > dCurrDepth && vStepInfo[nStep].dDepth < dMinDepthAbove) { dMinDepthAbove = vStepInfo[nStep].dDepth ; bFound = true ; } } // Se ho trovato un step più alto fatto in precedenza valido, allora l'elevazione iniziale è la // differenza tra le profondità, altrimenti mi alzo dell'intera profondità dello step corrente dStartElev = ( bFound ? abs( dMinDepthAbove - dCurrDepth) + dSafeZ : abs( dCurrDepth) + dSafeZ) ; Point3d ptUp = ptStart + dStartElev * vtTool ; dEndElev = abs( ( ptEnd - ptUp) * vtTool) ; pCrvLink->AddPoint( ptStart) ; pCrvLink->AddLine( ptUp) ; pCrvLink->AddLine( ptEnd + dEndElev * vtTool) ; #if ENBALE_DEBUG_LINK int nCrv = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLay, pCrvLink->Clone()) ; m_pGeomDB->SetMaterial( nCrv, LIME) ; #endif } // se entrata da fuori... if ( vStepInfo[i+1].vPaths.front().bOutStart) { // --- controllo che il punto elevato sopra a ptEnd non sia già sulla curva di entrata da fuori // del percorso successivo ( evito di creare entrate a ZigZag con overlap) if ( vStepInfo[i+1].vPaths.front().pCrvPath->GetFirstCurve()->IsPointOn( ptStart + vtTool * dStartElev)) { double dUStartTrim = 0. ; vStepInfo[i+1].vPaths.front().pCrvPath->GetFirstCurve()->GetParamAtPoint( ptStart + vtTool * dStartElev, dUStartTrim) ; if ( dUStartTrim > EPS_PARAM) { delete( pCrvLink->RemoveFirstOrLastCurve( true)) ; #if ENBALE_DEBUG_LINK PtrOwner pCrvTrim( vStepInfo[i+1].vPaths.front().pCrvPath->GetFirstCurve()->CopyParamRange( 0., dUStartTrim)) ; if ( ! IsNull( pCrvTrim)) { int nCrv = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLay, pCrvTrim->Clone()) ; m_pGeomDB->SetMaterial( nCrv, OLIVE) ; } #endif vStepInfo[i+1].vPaths.front().pCrvPath->TrimStartAtParam( dUStartTrim) ; } } } } break ; default : return false ; } return true ; } //---------------------------------------------------------------------------- bool SurfRoughing::OrderZChunkSteps( STEPDATAMATRIX& vvDataSteps, STEPDATAMATRIX& vIndepChunkGroup, INTDBLDBLVECTOR& vMapGrpZLoc) const { vIndepChunkGroup.clear() ; vMapGrpZLoc.clear() ; // se non ho Steps non faccio nulla if ( vvDataSteps.empty()) return true ; // ordino le righe della matrice ( i piani) per Z decrescente ( Z è negativa rispetto al piano { ORIG, Z_AX}) sort( vvDataSteps.begin(), vvDataSteps.end(), []( const STEPDATAVECTOR& vSDA, const STEPDATAVECTOR& vSDB) { if ( ! vSDA.empty() && ! vSDB.empty()) return ( vSDA[0].dDepth > vSDB[0].dDepth) ; return false ; }) ; // definisco le relazioni delle superfici int nRowSize = int( vvDataSteps.size()) ; int nColSize = 0 ; for ( int i = 0 ; i < nRowSize ; ++ i) nColSize = max( nColSize, int( vvDataSteps[i].size())) ; unordered_map MapLock ; unordered_map MapUnlock ; for ( int nR = int( vvDataSteps.size()) - 1 ; nR >= 1 ; -- nR) { for ( int nC = 0 ; nC < int( vvDataSteps[nR].size()) ; ++ nC) { for ( int nRow = nR - 1 ; nRow >= 0 ; -- nRow) { bool bRowFound = false ; for ( int nCol = 0 ; nCol < int( vvDataSteps[nRow].size()) ; ++ nCol) { PtrOwner pSfrA( nullptr) ; if ( vvDataSteps[nR][nC].bIsSubStep || vvDataSteps[nRow][nCol].bIsSubStep) pSfrA.Set( vvDataSteps[nR][nC].pSfrChunk->CreateOffsetSurf( m_dSubStepToler + 50 * EPS_SMALL, ICurve::OFF_FILLET)) ; else pSfrA.Set( CloneSurfFlatRegion( vvDataSteps[nR][nC].pSfrChunk)) ; const ISurfFlatRegion* pSfrB = vvDataSteps[nRow][nCol].pSfrChunk ; if ( ! IsNull( pSfrA) && pSfrB != nullptr) { if ( ! pSfrA->Intersect( *pSfrB)) { // provo con una tolleranza leggermente più grande pSfrA->Offset( 25. * EPS_SMALL, ICurve::OFF_FILLET) ; pSfrA->Intersect( *pSfrB) ; } if ( pSfrA->IsValid() && pSfrA->GetChunkCount() > 0) { bRowFound = true ; // Il Chunk di Key nKeyLock è bloccato dal Chunk ( nR - 1, nCol) // Il Chunk di Key nKeyUnlock blocca il Chunk ( nR, nC) int nKeyLock = nR * nColSize + nC ; int nKeyUnlock = ( nRow) * nColSize + nCol ; MapLock[nKeyLock].emplace_back( make_pair( nRow, nCol)) ; MapUnlock[nKeyUnlock].emplace_back( make_pair( nR, nC)) ; } } } if ( bRowFound || ! vvDataSteps[nRow].back().bIsSubStep) break ; } } } // definisco i gruppi di Chunk indipendenti; Un insieme di Chunk risulta indipendente da un altro // insieme se l'ordine di esecuzione di essi è indifferente ; // [non esiste alcun Chunk nel gruppo A che interferisce con un Chunk del gruppo B] bool bGroup = true ; int nCont = 0 ; while ( bGroup && nCont < nRowSize * nColSize) { ++ nCont ; bGroup = false ; // cerco il primo Chunk non ancora inserito nel gruppo for ( int nR = int( vvDataSteps.size()) - 1 ; nR >= 0 && ! bGroup ; -- nR) { // scorro le colonne ( dalla prima all'ultima) [ordine casuale] for ( int nC = 0 ; nC < int( vvDataSteps[nR].size()) && ! bGroup ; ++ nC) { // se il Chunk è già in un gruppo ( quindi nullptr), passo al successivo if ( vvDataSteps[nR][nC].pSfrChunk == nullptr) continue ; // se Chunk trovato, allora ho un nuovo gruppo da analizzare bGroup = true ; // creazione dello spazio per un nuovo gruppo vIndepChunkGroup.resize( vIndepChunkGroup.size() + 1) ; INTINTVECTOR vMapIndCheck = { make_pair( nR, nC)} ; // finchè ho indici di riga-colonna da verificare while ( ! vMapIndCheck.empty()) { // memorizzo gli indici correnti int nCurrRow = vMapIndCheck.back().first ; int nCurrCol = vMapIndCheck.back().second ; // tolgo l'elemento ( non devo ricontrollarlo all'iterazione successiva) vMapIndCheck.pop_back() ; // controllo se è già stato inserito if ( vvDataSteps[nCurrRow][nCurrCol].pSfrChunk == nullptr) // (*) continue ; // [ho rimosso l'elemento ( nCurrRow, nCurrCol)] // alloco spazio di memoria vIndepChunkGroup.back().resize( vIndepChunkGroup.back().size() + 1) ; // --- Flag per Step base vIndepChunkGroup.back().back().bIsSubStep = vvDataSteps[nCurrRow][nCurrCol].bIsSubStep ; // --- Depth vIndepChunkGroup.back().back().dDepth = vvDataSteps[nCurrRow][nCurrCol].dDepth ; // --- Depth relativa vIndepChunkGroup.back().back().dRelativeDepth = vvDataSteps[nCurrRow][nCurrCol].dRelativeDepth ; // --- Coefficiente di riduzione della Feed in locale vIndepChunkGroup.back().back().dZLocCoeffFeed = vvDataSteps[nCurrRow][nCurrCol].dZLocCoeffFeed ; // --- regione di sgrossatura vIndepChunkGroup.back().back().pSfrChunk.Set( Release( vvDataSteps[nCurrRow][nCurrCol].pSfrChunk)) ; // --- regione limite vIndepChunkGroup.back().back().pSfrLimit.Set( nullptr) ; if ( ! IsNull( vvDataSteps[nCurrRow][nCurrCol].pSfrLimit) && vvDataSteps[nCurrRow][nCurrCol].pSfrLimit->IsValid()) vIndepChunkGroup.back().back().pSfrLimit.Set( Release( vvDataSteps[nCurrRow][nCurrCol].pSfrLimit)) ; // --- regione rimossa vIndepChunkGroup.back().back().pSfrRemoved.Set( nullptr) ; if ( ! IsNull( vvDataSteps[nCurrRow][nCurrCol].pSfrRemoved) && vvDataSteps[nCurrRow][nCurrCol].pSfrRemoved->IsValid()) vIndepChunkGroup.back().back().pSfrRemoved.Set( Release( vvDataSteps[nCurrRow][nCurrCol].pSfrRemoved)) ; // --- se il Chunk non è bloccato da nessun altro auto itLock = MapLock.find( nCurrRow * nColSize + nCurrCol) ; if ( itLock == MapLock.end()) ; // non faccio nulla // --- altrimenti else { // --- scorro i chunk che bloccano quello corrente for ( int i = 0 ; i < int( itLock->second.size()) ; ++ i) { int nBR = itLock->second[i].first ; int nBC = itLock->second[i].second ; INTINT Key = make_pair( nBR, nBC) ; auto itUnLock = MapUnlock.find( nBR * nColSize + nBC) ; // verifico che non ci siano altri Chunk bloccanti bool bInsert = true ; for ( int j = 0 ; j < int( itUnLock->second.size()) ; ++ j) { if ( vvDataSteps[itUnLock->second[j].first][itUnLock->second[j].second].pSfrChunk != nullptr) { INTINTVECTOR vInd = { make_pair( itUnLock->second[j].first, itUnLock->second[j].second)} ; while ( ! vInd.empty()) { int nMyCurrRow = vInd.back().first ; int nMyCurrCol = vInd.back().second ; vInd.pop_back() ; auto itUnlock = MapUnlock.find( nMyCurrRow * nColSize + nMyCurrCol) ; if ( itUnlock == MapUnlock.end()) vMapIndCheck.emplace_back( make_pair( nMyCurrRow, nMyCurrCol)) ; // --- altrimenti else { for ( int k = 0 ; k < int( itUnlock->second.size()) ; ++ k) { int nMyBR = itUnlock->second[k].first ; int nMyBC = itUnlock->second[k].second ; if ( vvDataSteps[nMyBR][nMyBC].pSfrChunk != nullptr) vInd.emplace_back( make_pair( nMyBR, nMyBC)) ; } } } bInsert = false ; // [ metto dentro alcuni valori ( nR, nC) doppi...], però ho il controllo sopra (*) } } if ( bInsert) vMapIndCheck.emplace_back( Key) ; } } } } } } // ordino i gruppi di Chunk indipendenti vMapGrpZLoc.reserve( vIndepChunkGroup.size()) ; for ( int i = 0 ; i < int( vIndepChunkGroup.size()) ; ++ i) { // scorro le curve del gruppo cercando quella più in alto ( rispetto alla Zlocale di frXY) double dZMax = - INFINITO ; double dZMin = INFINITO ; for ( StepData& myStepData : vIndepChunkGroup[i]) { Point3d ptCen ; myStepData.pSfrChunk->GetCentroid( ptCen) ; double dCurrZ = ptCen.z ; // negativa ( < 0) dZMax = max( dZMax, dCurrZ) ; // più vicina al piano { ORIG, Z_AX} dZMin = min( dZMin, dCurrZ) ; // più lontana al paino { ORIG, Z_AX} } vMapGrpZLoc.emplace_back( make_pair( i, make_pair( dZMax, dZMin))) ; } // ordino sort( vMapGrpZLoc.begin(), vMapGrpZLoc.end(), []( const INTDBLDBL& GrpA, const INTDBLDBL& GrpB) { // Se ZMax coincidenti, viene prima quello con ZMin superiore if ( abs( GrpA.second.first - GrpB.second.first) < 10. * EPS_SMALL) return ( GrpA.second.second > GrpB.second.second) ; // Se differenti, viene prima quello con ZMax superiore return ( GrpA.second > GrpB.second) ; }) ; return true ; } //---------------------------------------------------------------------------- bool SurfRoughing::OrderByZChunk( SFRGEODBINFOVECTOR& vInfoSfrGeomDB, int nTempId, const ISurfFlatRegion* pSfrSgro) const { // definisco un Frame intrinseco alla regione di sgrossatura Frame3d frXY ; Point3d ptCenter ; pSfrSgro->GetCentroid( ptCenter) ; if ( ! frXY.Set( ptCenter, pSfrSgro->GetNormVersor())) return false ; // definisco una matrice di Chunk associati ai vari piani STEPDATAMATRIX vvChunksStep ; for ( int i = 0 ; i < int( vInfoSfrGeomDB.size()) ; ++ i) { // recupero la superficie piana di lavoro [sempre valida] e la porto in locale PtrOwner pSfr( Release( vInfoSfrGeomDB[i].pSfr)) ; if ( IsNull( pSfr) || ! pSfr->IsValid() || ! pSfr->ToLoc( frXY)) return false ; // recupero la superficie limite corrente e la porto in locale PtrOwner pSfrLimit( nullptr) ; if ( ! IsNull( vInfoSfrGeomDB[i].pSfrLimit) && vInfoSfrGeomDB[i].pSfrLimit->IsValid()) { pSfrLimit.Set( Release( vInfoSfrGeomDB[i].pSfrLimit)) ; pSfrLimit->ToLoc( frXY) ; } // recupero la superficie rimossa corrente e la porto in locale PtrOwner pSfrRemoved( nullptr) ; if ( ! IsNull( vInfoSfrGeomDB[i].pSfrRemoved) && vInfoSfrGeomDB[i].pSfrRemoved->IsValid()) { pSfrRemoved.Set( Release( vInfoSfrGeomDB[i].pSfrRemoved)) ; pSfrRemoved->ToLoc( frXY) ; } // scorro i Chunks della regione piana di lavoro for ( int nC = 0 ; nC < pSfr->GetChunkCount() ; ++ nC) { // recupero il Chunk corrente PtrOwner pSfrChunk( pSfr->CloneChunk( nC)) ; if ( IsNull( pSfrChunk) || ! pSfrChunk->IsValid()) return false ; // trasferisco i parametri e le proprietà della regione al Chunk corrente pSfrChunk->SetTempProp( pSfr->GetTempProp( 0), 0) ; pSfrChunk->SetTempProp( pSfr->GetTempProp( 1), 1) ; pSfrChunk->SetTempParam( pSfr->GetTempParam( 0), 0) ; pSfrChunk->SetTempParam( pSfr->GetTempParam( 1), 1) ; // determino il rispettivo Chunk della regione limite PtrOwner pSfrRemovedChunk( nullptr) ; if ( ! IsNull( pSfrRemoved) && pSfrRemoved->IsValid()) { if ( pSfrRemoved->GetChunkCount() == 1) pSfrRemovedChunk.Set( CloneSurfFlatRegion( pSfrRemoved)) ; // anche pSfr ha 1 Chunk ( ???) else { PtrOwner pSfrChunkCL( CloneSurfFlatRegion( pSfrChunk)) ; if ( IsNull( pSfrChunkCL) || ! pSfrChunkCL->IsValid()) return false ; for ( int nCC = 0 ; nCC < pSfrRemoved->GetChunkCount() ; ++ nCC) { PtrOwner pSfrB( pSfrRemoved->CloneChunk( nCC)) ; if ( IsNull( pSfrB) || ! pSfrB->IsValid()) return false ; if ( ! pSfrB->Intersect( *pSfrChunkCL)) { // provo estendendo leggermente la regione pSfrB->Offset( 25. * EPS_SMALL, ICurve::OFF_FILLET) ; pSfrB->Intersect( *pSfrChunkCL) ; } if ( pSfrB->IsValid() && pSfrB->GetChunkCount() > 0) { pSfrRemovedChunk.Set( pSfrRemoved->CloneChunk( nCC)) ; break ; } } } } // memorizzo le superfici if ( nC == 0) vvChunksStep.resize( vvChunksStep.size() + 1) ; vvChunksStep.back().resize( vvChunksStep.back().size() + 1) ; vvChunksStep.back().back().bIsSubStep = vInfoSfrGeomDB[i].bSubStep ; vvChunksStep.back().back().dDepth = vInfoSfrGeomDB[i].dDepth ; vvChunksStep.back().back().dRelativeDepth = vInfoSfrGeomDB[i].dRelativeDepth ; vvChunksStep.back().back().dZLocCoeffFeed = vInfoSfrGeomDB[i].dZLocCoefFeed ; vvChunksStep.back().back().pSfrChunk.Set( Release( pSfrChunk)) ; vvChunksStep.back().back().pSfrLimit.Set( CloneSurfFlatRegion( pSfrLimit)) ; vvChunksStep.back().back().pSfrRemoved.Set( Release( pSfrRemovedChunk)) ; } } // definisco la mappa per l'ordine dei gruppi indipendenti di Chunks STEPDATAMATRIX vvIndepChunkGroup ; INTDBLDBLVECTOR vMapGrpZLoc ; if ( ! OrderZChunkSteps( vvChunksStep, vvIndepChunkGroup, vMapGrpZLoc)) return false ; #if ENABLE_DEBUG_ORDER_ZCHUNK int nGrp = m_pGeomDB->AddGroup( GDB_ID_NULL, GDB_ID_ROOT, GLOB_FRM) ; for ( int i = 0 ; i < int( vMapGrpZLoc.size()) ; ++ i) { Color myCol = Color( double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, .5) ; int nLay = m_pGeomDB->AddGroup( GDB_ID_NULL, nGrp, GLOB_FRM) ; for ( int j = 0 ; j < int( vvIndepChunkGroup[vMapGrpZLoc[i].first].size()) ; ++ j) { int a = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLay, CloneSurfFlatRegion( vvIndepChunkGroup[vMapGrpZLoc[i].first][j].pSfrChunk)) ; m_pGeomDB->SetMaterial( a, myCol) ; m_pGeomDB->SetName( a, ( "(" + to_string( vMapGrpZLoc[i].first) + ", " + to_string( j) + ")").c_str()) ; } } #endif vInfoSfrGeomDB.clear() ; // scorro i gruppi ordinati for ( int i = 0 ; i < int( vMapGrpZLoc.size()) ; ++ i) { // recupero l'indice del gruppo int nGroup = vMapGrpZLoc[i].first ; // --- inserisco gli Steps for ( int j = int( vvIndepChunkGroup[nGroup].size()) - 1 ; j >= 0 ; -- j) { if ( ! vvIndepChunkGroup[nGroup][j].bIsSubStep) { vInfoSfrGeomDB.resize( vInfoSfrGeomDB.size() + 1) ; // --- regione di sgrossatura vvIndepChunkGroup[nGroup][j].pSfrChunk->ToGlob( frXY) ; vInfoSfrGeomDB.back().pSfr.Set( Release( vvIndepChunkGroup[nGroup][j].pSfrChunk)) ; // --- regione limite vInfoSfrGeomDB.back().pSfrLimit.Set( nullptr) ; if ( ! IsNull( vvIndepChunkGroup[nGroup][j].pSfrLimit) && vvIndepChunkGroup[nGroup][j].pSfrLimit->IsValid()) { vvIndepChunkGroup[nGroup][j].pSfrLimit->ToGlob( frXY) ; vInfoSfrGeomDB.back().pSfrLimit.Set( Release( vvIndepChunkGroup[nGroup][j].pSfrLimit)) ; } // --- regione rimossa vInfoSfrGeomDB.back().pSfrRemoved.Set( nullptr) ; if ( ! IsNull( vvIndepChunkGroup[nGroup][j].pSfrRemoved) && vvIndepChunkGroup[nGroup][j].pSfrRemoved->IsValid()) { vvIndepChunkGroup[nGroup][j].pSfrRemoved->ToGlob( frXY) ; vInfoSfrGeomDB.back().pSfrRemoved.Set( Release( vvIndepChunkGroup[nGroup][j].pSfrRemoved)) ; } // --- Flag per Step base vInfoSfrGeomDB.back().bSubStep = vvIndepChunkGroup[nGroup][j].bIsSubStep ; // --- Depth vInfoSfrGeomDB.back().dDepth = vvIndepChunkGroup[nGroup][j].dDepth ; // --- Depth relativa vInfoSfrGeomDB.back().dRelativeDepth = vvIndepChunkGroup[nGroup][j].dRelativeDepth ; // --- Coefficiente di riduzione della Feed in locale vInfoSfrGeomDB.back().dZLocCoefFeed = vvIndepChunkGroup[nGroup][j].dZLocCoeffFeed ; } } // --- inserisco i SubSteps --- INTVECTOR vSubStepInd ; for ( int j = int( vvIndepChunkGroup[nGroup].size()) - 1 ; j >= 0 ; -- j) { bool bNewGap = ( ! vSubStepInd.empty() && vvIndepChunkGroup[nGroup][j].dDepth > vvIndepChunkGroup[nGroup][vSubStepInd.back()].dDepth) ; if ( vvIndepChunkGroup[nGroup][j].bIsSubStep && ! bNewGap) vSubStepInd.emplace_back( j) ; if ( ! vvIndepChunkGroup[nGroup][j].bIsSubStep || bNewGap || j == 0) { for ( int k = int( vSubStepInd.size()) - 1 ; k >= 0 ; -- k) { // recupero l'indice del SubStep int nInd = vSubStepInd[k] ; vInfoSfrGeomDB.resize( vInfoSfrGeomDB.size() + 1) ; // --- regione di sgrossatura vvIndepChunkGroup[nGroup][nInd].pSfrChunk->ToGlob( frXY) ; vInfoSfrGeomDB.back().pSfr.Set( Release( vvIndepChunkGroup[nGroup][nInd].pSfrChunk)) ; // --- regione limite vInfoSfrGeomDB.back().pSfrLimit.Set( nullptr) ; if ( ! IsNull( vvIndepChunkGroup[nGroup][nInd].pSfrLimit) && vvIndepChunkGroup[nGroup][nInd].pSfrLimit->IsValid()) { vvIndepChunkGroup[nGroup][nInd].pSfrLimit->ToGlob( frXY) ; vInfoSfrGeomDB.back().pSfrLimit.Set( Release( vvIndepChunkGroup[nGroup][nInd].pSfrLimit)) ; } // --- regione rimossa vInfoSfrGeomDB.back().pSfrRemoved.Set( nullptr) ; if ( ! IsNull( vvIndepChunkGroup[nGroup][nInd].pSfrRemoved) && vvIndepChunkGroup[nGroup][nInd].pSfrRemoved->IsValid()) { vvIndepChunkGroup[nGroup][nInd].pSfrRemoved->ToGlob( frXY) ; vInfoSfrGeomDB.back().pSfrRemoved.Set( Release( vvIndepChunkGroup[nGroup][nInd].pSfrRemoved)) ; } // --- Flag per Step base vInfoSfrGeomDB.back().bSubStep = vvIndepChunkGroup[nGroup][nInd].bIsSubStep ; // --- Depth vInfoSfrGeomDB.back().dDepth = vvIndepChunkGroup[nGroup][nInd].dDepth ; // --- Depth relativa vInfoSfrGeomDB.back().dRelativeDepth = vvIndepChunkGroup[nGroup][nInd].dRelativeDepth ; // --- Coefficiente di riduzione della Feed in locale vInfoSfrGeomDB.back().dZLocCoefFeed = vvIndepChunkGroup[nGroup][nInd].dZLocCoeffFeed ; } vSubStepInd.clear() ; if ( bNewGap && vvIndepChunkGroup[nGroup][j].bIsSubStep) vSubStepInd = { j} ; } } } return true ; } //---------------------------------------------------------------------------- bool SurfRoughing::AddRoughing( const INTINTVECTOR& vPocket, const Vector3d& vtTool, double dDepth, double dStep, double dSubStep, bool bSplitArcs) { // controllo dei parametri if ( vPocket.empty()) return true ; // calcolo i percorsi di svuotatura per ogni Step/SubStep STEPINFOSRVECTOR vStepInfo ; if ( ! CalcPaths( vPocket, vStepInfo)) return false ; #if ENABLE_DEBUG_FEEDS nGrpDebugFeed = m_pGeomDB->AddGroup( GDB_ID_NULL, GDB_ID_ROOT, GLOB_FRM) ; nLayDebugFeed = m_pGeomDB->AddGroup( GDB_ID_NULL, nGrpDebugFeed, GLOB_FRM) ; m_pGeomDB->SetName( nGrpDebugFeed, "Feed") ; #endif // recupero distanze di sicurezza double dSafeZ = GetSafeZ() ; // lunghezza di approccio/retrazione double dAppr = m_Params.m_dStartPos ; // elevazione sopra al punto attuale double dCurrElev ; // punto finale del percorso precedente al corrente Point3d ptEnd = P_INVALID ; // recupero parametro di Feed minima double dMinFeed = GetFeed() / FEED_MAX_REDUCE ; if ( GetValInNotes( m_Params.m_sUserNotes, UN_MINFEED, dMinFeed)) dMinFeed = Clamp( dMinFeed, GetFeed() / FEED_MAX_REDUCE, GetFeed()) ; // scorro il vettore dei piani di pocketing for ( int i = 0 ; i < ssize( vStepInfo) ; ++ i) { // riferimento alle informazioni relative allo step i-esimo StepInfoSR& currStep = vStepInfo[i] ; // scorro i percorsi calcolati per il piano di pocketing i-esimo for ( int j = 0 ; j < ssize( currStep.vPaths) ; ++ j) { // riferimento alle informazioni relative al percorso j-esimo del piano di pocketing i-esimo PathInfoSR& currPath = currStep.vPaths[j] ; // ciclo sulle curve elementari del percorso attuale int nMaxInd = currPath.pCrvPath->GetCurveCount() - 1 ; for ( int k = 0 ; k <= nMaxInd ; ++ k) { // curva corrente const ICurve* pCrvC = currPath.pCrvPath->GetCurve( k) ; // copio la curva PtrOwner pCurve( pCrvC->Clone()) ; if ( IsNull( pCurve)) return false ; // coefficiente feed ( riduzione di feed per sezione di taglio superiore al previsto ) double dTempParam ; currPath.pCrvPath->GetCurveTempParam( k, dTempParam) ; double dCoeffFeed = min( 1., ( dTempParam > EPS_SMALL ? dTempParam /= 1000 : 1) * currStep.dZlocCoeffFeed) ; // se prima entità if ( k == 0) { // dati inizio entità Point3d ptStart ; pCurve->GetStartPoint( ptStart) ; Vector3d vtStart ; pCurve->GetStartDir( vtStart) ; // flag approccio libero in aria if ( currPath.bOutStart) dCoeffFeed = ( dTempParam > EPS_SMALL ? dTempParam : 1) ; // calcolo ptP1 per LeadIn iniziale Point3d ptP1 ; if ( ! CalcLeadInStart( ptStart, vtTool, currPath.pCvrRet, ptP1)) { m_pMchMgr->SetLastError( 3013, "Error in SurfRoughing : LeadIn not computable") ; return false ; } // determino l'elevazione sull'inizio dell'attacco della prima curva globale bool bAbsFirst = ( i == 0 && j == 0) ; if ( bAbsFirst) dCurrElev = - currStep.dDepth ; dCurrElev -= ( ptP1 - ptStart) * vtTool ; // se attacco a zigzag o a spirale o a scivolo, l'elevazione va nell'attacco if ( GetLeadInType() != POCKET_LI_NONE) { double dMyLIO_ELEV_TOL = min( LIO_ELEV_TOL, dSafeZ) ; // se prima entità in assoluto if ( bAbsFirst) { ptP1 += vtTool * ( dCurrElev + dMyLIO_ELEV_TOL) ; dCurrElev = - min( LIO_ELEV_TOL, dSafeZ) ; } // altrimenti... else if ( ! currPath.bOutStart) ptP1 += vtTool * ( - currStep.dRelativeDepth + dMyLIO_ELEV_TOL) ; } // approccio al punto iniziale double dMySafeZ = ( bAbsFirst ? dSafeZ : 0.) ; Point3d ptMyPos ; GetCurrPos( ptMyPos) ; double dMyElev = ( bAbsFirst ? dCurrElev : ( ptMyPos - ptP1) * vtTool) ; double dMyAppr = ( bAbsFirst ? dAppr : 0.) ; if ( ! AddApproach( ptP1, vtTool, dMySafeZ, dMyElev, dMyAppr, currPath.bOutStart, bAbsFirst)) { m_pMchMgr->SetLastError( 3011, "Error in SurfRoughing : Approach not computable") ; return false ; } // aggiungo attacco SetFeed( GetStartFeed()) ; bool bNoneForced = ( currPath.bOutStart || currPath.bSingleCrv || ( currStep.nSubType == SURFROU_SUB_ZIGZAG && ! currPath.bIsZigZagOneWayBorder) || ( currStep.nSubType == SURFROU_SUB_ONEWAY && ! currPath.bIsZigZagOneWayBorder)) ; if ( ! AddLeadIn( ptP1, ptStart, vtStart, vtTool, currStep.pSfrPock, ( ( currStep.nSubType == SURFROU_SUB_SPIRALIN || currStep.nSubType == SURFROU_SUB_SPIRALOUT)) ? Get( currPath.pCvrRet) : nullptr, ( currStep.nSubType == SURFROU_SUB_SPIRALOUT) ? currStep.bInverted : ! currStep.bInverted, bSplitArcs, bNoneForced, false)) { m_pMchMgr->SetLastError( 3013, "Error in SurfRoughing : LeadIn not computable") ; return false ; } } // elaborazioni sulla curva corrente (sempre un segmento di retta) if ( pCurve->GetType() == CRV_LINE) { ICurveLine* pLine = GetCurveLine( pCurve) ; Point3d ptP3 = pLine->GetEnd() ; Vector3d vtMove ; pLine->GetStartDir( vtMove) ; SetFeed( Clamp( dCoeffFeed * GetFeed(), dMinFeed, GetFeed())) ; #if ENABLE_DEBUG_FEEDS DrawFeed( pCurve->Clone(), dCoeffFeed * GetFeed(), nLayDebugFeed) ; #endif if ( AddLinearMove( ptP3, bSplitArcs) == GDB_ID_NULL) return false ; } else if ( pCurve->GetType() == CRV_ARC) { ICurveArc* pArc = GetCurveArc( pCurve) ; SetFeed( Clamp( dCoeffFeed * GetFeed(), dMinFeed, GetFeed())) ; #if ENABLE_DEBUG_FEEDS DrawFeed( pCurve->Clone(), dCoeffFeed * GetFeed(), nLayDebugFeed) ; #endif SetFeed( dCoeffFeed * GetFeed()) ; if ( AddCurveMove( pArc, bSplitArcs) == GDB_ID_NULL) return false ; } // se ultima entità if ( k == nMaxInd) { // dati fine entità pCurve->GetEndPoint( ptEnd) ; Vector3d vtEnd ; pCurve->GetEndDir( vtEnd) ; // se sono l'ultima entità globale del percorso if ( i == ssize( vStepInfo) - 1 && j == ssize( currStep.vPaths) - 1) { // aggiungo LeadOut Point3d ptP1 ; SetFeed( GetEndFeed()) ; if ( ! AddLeadOut( ptEnd, vtEnd, vtTool, ( ( currStep.nSubType == SURFROU_SUB_SPIRALIN || currStep.nSubType == SURFROU_SUB_SPIRALOUT)) ? Get( currPath.pCvrRet) : nullptr, bSplitArcs, false, ptP1)) { m_pMchMgr->SetLastError( 3014, "Error in SurfRoughing : LeadOut not computable") ; return false ; } // aggiungo retroazione finale if ( ! AddRetract( ptP1, vtTool, dSafeZ, - currStep.dDepth, dAppr)) { m_pMchMgr->SetLastError( 3015, "Error in SurfRoughing : Retract not computable") ; return false ; } } // se ho un percorso successivo else { // definisco e creo il link PtrOwner pCrvLink( CreateCurveComposite()) ; if ( IsNull( pCrvLink) || ! GetLinkFromPaths( vStepInfo, i, j, ptEnd, vtTool, dSafeZ, 0., dCurrElev, pCrvLink)) { m_pMchMgr->SetLastError( 3034, "Error in SurfRoughing : Linking paths failed") ; return false ; } // imposto EndFeed e aggiungo il Link SetFeed( GetEndFeed()) ; #if ENABLE_DEBUG_FEEDS DrawFeed( pCrvLink->Clone(), GetEndFeed(), nLayDebugFeed) ; #endif AddCurveMove( pCrvLink, bSplitArcs) ; } } } } } // aggiorno per sicurezza la ProgressBar nel caso di Step vuoti ExeProcessEvents( 100, 0) ; return true ; } //---------------------------------------------------------------------------- bool SurfRoughing::AddApproach( const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dElev, double dAppr, bool bOutStart, bool bAbsFirst) { if ( bAbsFirst) 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 ( bAbsFirst && 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 ( bAbsFirst && 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) ; bool bStartFeed = ( bOutStart || m_TParams.m_nType == TT_MILL_NOTIP) ; SetFeed( bStartFeed ? GetStartFeed() : GetTipFeed()) ; if ( AddLinearMove( ptP) == GDB_ID_NULL) return false ; } else { // affondo diretto al punto iniziale SetFlag( 0) ; if ( bAbsFirst && AddRapidStart( ptP) == GDB_ID_NULL) return false ; } return true ; } //---------------------------------------------------------------------------- bool SurfRoughing::AddLinkApproach(const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dElev, double dAppr, bool bOutMove) { // se sopra attacco c'è spazio per approccio if ( ( dElev + dAppr) > 10 * EPS_SMALL) { // 1b -> punto appena sopra inizio Point3d ptP1b = ptP + vtTool * ( dElev + dAppr) ; if ( ( dElev + dAppr) > EPS_SMALL) { SetFlag( 0) ; if ( AddRapidMove( ptP1b) == GDB_ID_NULL) return false ; } // affondo al punto iniziale SetFlag( 0) ; SetFeed( bOutMove ? GetStartFeed() : GetTipFeed()) ; if ( AddLinearMove( ptP) == GDB_ID_NULL) return false ; } else { // affondo diretto al punto iniziale SetFlag( 0) ; if ( AddRapidMove( ptP) == GDB_ID_NULL) return false ; } return true ; } //---------------------------------------------------------------------------- bool SurfRoughing::AddLinkRetract( const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dElev, double dAppr) { // se sopra uscita c'è spazio per approccio if ( ( dElev + dAppr) > 10 * EPS_SMALL) { // 4 -> movimento di risalita sopra il punto finale SetFeed( GetEndFeed()) ; Point3d ptP4 = ptP + vtTool * ( dElev + dAppr) ; if ( AddLinearMove( ptP4) == GDB_ID_NULL) return false ; } return true ; } //---------------------------------------------------------------------------- bool SurfRoughing::AddRetract( const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dElev, double dAppr) { // se sopra uscita c'è spazio per sicurezza o approccio double dSafeDist = dSafeZ ; if ( dElev + max( dSafeDist, dAppr) > 10 * EPS_SMALL) { if ( dSafeDist < dAppr + 10 * EPS_SMALL) { // 4 -> movimento di risalita sopra il punto finale SetFeed( GetEndFeed()) ; Point3d ptP4 = ptP + vtTool * ( dElev + dAppr) ; if ( AddLinearMove( ptP4) == GDB_ID_NULL) return false ; } else { // 4a -> movimento di risalita appena sopra il punto finale Point3d ptP4a = ptP + vtTool * ( dElev + dAppr) ; if ( dElev + dAppr > EPS_SMALL) { SetFeed( GetEndFeed()) ; if ( AddLinearMove( ptP4a) == GDB_ID_NULL) return false ; } // 4b -> movimento di risalita sopra il punto finale Point3d ptP4b = ptP4a + vtTool * ( dSafeDist - dAppr) ; if ( AddRapidMove( ptP4b) == GDB_ID_NULL) return false ; } } return true ; } //---------------------------------------------------------------------------- bool SurfRoughing::CalcLeadInStart( const Point3d& ptStart, const Vector3d& vtTool, const ICurveComposite* pRCrv, Point3d& ptP1) const { // Assegno tipo e parametri int nType = GetLeadInType() ; if ( nType == SURFROU_LI_GLIDE && ( pRCrv == nullptr || pRCrv->GetCurveCount() == 0)) nType = SURFROU_LI_NONE ; // Calcolo punto iniziale switch ( nType) { case SURFROU_LI_NONE : case SURFROU_LI_ZIGZAG : case SURFROU_LI_HELIX : ptP1 = ptStart ; return true ; case SURFROU_LI_GLIDE : { double dLen, dU ; if ( ! pRCrv->GetLength( dLen) || ! pRCrv->GetParamAtLength( dLen - m_Params.m_dLiTang, dU) || ! pRCrv->GetPointD1D2( dU, ICurve::FROM_MINUS, ptP1)) { if ( ! pRCrv->GetStartPoint( ptP1)) return false ; } ptP1 += vtTool * ( vtTool * ( ptStart - ptP1)) ; return true ; } default : return false ; } } //---------------------------------------------------------------------------- bool SurfRoughing::AddLeadIn( const Point3d& ptP1, const Point3d& ptStart, const Vector3d& vtStart, const Vector3d& vtN, const ISurfFlatRegion* pSfr, const ICurveComposite* pRCrv, bool bAtLeft, bool bSplitArcs, bool bNoneForced, bool bSkipControl) { // Assegno il tipo int nType = GetLeadInType() ; if ( bNoneForced || AreSamePointEpsilon( ptP1, ptStart, 10 * EPS_SMALL) || ( nType == SURFROU_LI_GLIDE && ( pRCrv == nullptr || pRCrv->GetCurveCount() == 0))) nType = SURFROU_LI_NONE ; // Se elica e fattibile lo creo if ( nType == SURFROU_LI_HELIX) { // vettore dal punto al centro elica Vector3d vtCen = vtStart ; vtCen.Rotate( vtN, 0, ( bAtLeft ? 1 : - 1)) ; // dati dell'elica double dRad = min( 0.5 * min( m_Params.m_dLiTang, m_TParams.m_dDiam), m_dMaxHelixRad) ; Point3d ptCen = ptP1 + vtCen * dRad ; double dDeltaN = ( ptStart - ptP1) * vtN ; double dAngCen = ceil( - dDeltaN / ( m_Params.m_dLiElev + 20 * EPS_SMALL)) * ( bAtLeft ? ANG_FULL : - ANG_FULL) ; // verifico se fattibile if ( bSkipControl || VerifyLeadInHelix( pSfr, ptStart, ptCen, dRad)) { // creo l'elica PtrOwner pArc( CreateCurveArc()) ; if ( IsNull( pArc) || ! pArc->Set( ptCen, vtN, dRad, - vtCen, dAngCen, dDeltaN)) return false ; // dovendo creare l'elica, sono nel materiale, quindi regolo la Feed Vector3d vtTanHelix ; pArc->GetStartDir( vtTanHelix) ; SetFeed( GetRightStartFeed( vtTanHelix, vtN)) ; #if ENABLE_DEBUG_FEEDS DrawFeed( pArc->Clone(), GetRightStartFeed( vtTanHelix, vtN), nLayDebugFeed) ; #endif // 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) ; Vector3d vtTanZigZag = ( ptPa - vtN * 0.25 * dStep) - ptP1 ; SetFeed( GetRightStartFeed( vtTanZigZag, vtN)) ; // verifico se fattibile if ( bSkipControl || VerifyLeadInZigZag( pSfr, ptStart, ptPa, ptPb)) { for ( int i = 1 ; i <= nStep ; ++ i) { #if ENABLE_DEBUG_FEEDS PtrOwner pLine( CreateCurveLine()) ; Point3d ptCurr ; GetCurrPos( ptCurr) ; pLine->Set( ptCurr, ptPa - vtN * ( i - 0.75) * dStep) ; DrawFeed( pLine->Clone(), GetRightStartFeed( vtTanZigZag, vtN), nLayDebugFeed) ; #endif if ( AddLinearMove( ptPa - vtN * ( i - 0.75) * dStep, bSplitArcs, MCH_CL_LEADIN) == GDB_ID_NULL) return false ; #if ENABLE_DEBUG_FEEDS GetCurrPos( ptCurr) ; pLine->Set( ptCurr, ptPb - vtN * ( i - 0.25) * dStep) ; DrawFeed( pLine->Clone(), GetRightStartFeed( vtTanZigZag, vtN), nLayDebugFeed) ; #endif if ( AddLinearMove( ptPb - vtN * ( i - 0.25) * dStep, bSplitArcs, MCH_CL_LEADIN) == GDB_ID_NULL) return false ; } #if ENABLE_DEBUG_FEEDS PtrOwner pLine( CreateCurveLine()) ; Point3d ptCurr ; GetCurrPos( ptCurr) ; pLine->Set( ptCurr, ptStart) ; DrawFeed( pLine->Clone(), GetRightStartFeed( vtTanZigZag, vtN), nLayDebugFeed) ; #endif 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) ; // assegno le Feed Point3d ptS ; pCrv->GetStartPoint( ptS) ; Point3d ptE ; pCrv->GetEndPoint( ptE) ; Vector3d vtFeedMove = ptE - ptS ; SetFeed( GetRightStartFeed( vtFeedMove, vtN)) ; #if ENABLE_DEBUG_FEEDS DrawFeed( pCrv->Clone(), GetRightStartFeed( vtFeedMove, vtN), nLayDebugFeed) ; #endif // 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)) { Vector3d vtMove = ptStart - ptCurr ; vtMove.Normalize() ; double dElev = 0. ; bool bInMaterial = true ; if ( GetElevation( m_nPhase, ptCurr, ptStart, vtN, GetRadiusForStartEndElevation(), m_TParams.m_dLen, vtN, dElev) && dElev < 10. * EPS_SMALL) bInMaterial = false ; // Feed di Testa SetFeed( bInMaterial ? GetTipFeed() : GetStartFeed()) ; #if ENABLE_DEBUG_FEEDS PtrOwner pLine( CreateCurveLine()) ; pLine->Set( ptCurr, ptStart) ; DrawFeed( pLine->Clone(), bInMaterial ? GetTipFeed() : GetStartFeed(), nLayDebugFeed) ; #endif if ( AddLinearMove( ptStart, bSplitArcs, MCH_CL_LEADIN) == GDB_ID_NULL) return false ; } return true ; } // Altrimenti errore return false ; } //---------------------------------------------------------------------------- bool SurfRoughing::AddLeadOut( const Point3d& ptEnd, const Vector3d& vtEnd, const Vector3d& vtN, const ICurveComposite* pRCrv, bool bSplitArcs, bool bNoneForced, Point3d& ptP1) { // assegno i parametri int nType = GetLeadOutType() ; if ( bNoneForced || ( nType == SURFROU_LO_GLIDE && ( pRCrv == nullptr || pRCrv->GetCurveCount() == 0))) nType = SURFROU_LO_NONE ; // eseguo a seconda del tipo switch ( nType) { case SURFROU_LO_NONE : { // nessuna uscita ptP1 = ptEnd ; return true ; } case SURFROU_LO_GLIDE : { // recupero la parte richiesta della curva di ritorno PtrOwner pCrv ; double dU ; if ( pRCrv->GetParamAtLength( m_Params.m_dLoTang, dU)) { if ( ! pCrv.Set( ConvertCurveToComposite( pRCrv->CopyParamRange( 0, dU)))) return false ; } else { if ( ! pCrv.Set( pRCrv->Clone())) return false ; } // la porto alla giusta quota Point3d ptIni ; pCrv->GetStartPoint( ptIni) ; Vector3d vtMove = ptEnd - ptIni ; pCrv->Translate( vtMove) ; Point3d ptFin ; pCrv->GetEndPoint( ptFin) ; ptFin += vtN * 1.0 ; pCrv->ModifyEnd( ptFin) ; // emetto (con eventuale spezzatura) AddCurveMove( pCrv, bSplitArcs, MCH_CL_LEADOUT) ; // determino elevazione su fine uscita ptP1 = ptFin ; return true ; } default : return false ; } } //---------------------------------------------------------------------------- double SurfRoughing::GetRightFeed( const Vector3d& vtMove, const Vector3d& vtTool) const { // Determino i versori Vector3d vtM = vtMove ; vtM.Normalize() ; Vector3d vtT = vtTool ; vtT.Normalize() ; // Angolo tra movimento e versore utensile double dCosMove = vtM * vtT ; // Se l'utensile non ha movimento significativo di punta, si restituisce la feed standard if ( dCosMove > - COS_ORTO_ANG_SMALL) return GetFeed() ; // Altrimenti non si deve superare la massima velocità di punta prevista return min( GetFeed(), GetTipFeed() / abs( dCosMove)) ; } //------------------------------------------------------------------ double SurfRoughing::GetRightStartFeed( 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 GetStartFeed() ; // Altrimenti non si deve superare la massima velocità di punta prevista return min( GetStartFeed(), 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 ICRVCOMPOPOVECTOR& vCrvCheck, const Frame3d& frLocXY) const { // controllo dei parametri if ( pCompo == nullptr || ! pCompo->IsValid()) return false ; // eseguo le modifiche su una copia della curva originale in locale al frameXY PtrOwner pCompoLoc( CloneCurveComposite( pCompo)) ; if ( IsNull( pCompoLoc)) return false ; pCompoLoc->ToLoc( frLocXY) ; // ricavo il punto iniziale e finale Point3d ptStart ; pCompoLoc->GetStartPoint( ptStart) ; Point3d ptEnd ; pCompoLoc->GetEndPoint( ptEnd) ; // merge per uniformità bool bOk = pCompoLoc->MergeCurves( 200. * EPS_SMALL, 200. * EPS_ANG_SMALL, false) ; // rimozione Spikes o Curve Z bOk = bOk && pCompoLoc->RemoveSmallDefects( 150. * EPS_SMALL, 2. * ANG_TOL_STD_DEG, true) ; // interpolazione mediante linee ed archi PolyArc PA ; bOk = bOk && pCompoLoc->ApproxWithArcsEx( 50. * EPS_SMALL, ANG_TOL_STD_DEG, LIN_FEA_STD, PA) && pCompoLoc->Clear() && pCompoLoc->FromPolyArc( PA) ; // controllo aggiuntivo sui punti iniziali e finali che siano gli stessi Point3d ptNewStart, ptNewEnd ; bOk = bOk && pCompoLoc->GetStartPoint( ptNewStart) && pCompoLoc->GetEndPoint( ptNewEnd) && AreSamePointApprox( ptNewStart, ptStart) && AreSamePointApprox( ptNewEnd, ptEnd) ; // controllo che non si siano create auto-intersezioni SelfIntersCurve SIC( *pCompoLoc) ; bOk = bOk && ( SIC.GetCrossIntersCount() == 0) ; // controllo che non si siano create intersezioni con le altre curve in punti interni for ( int i = 0 ; i < ssize( vCrvCheck) && bOk ; ++ i) { PtrOwner pCrvCheckLocXY( CloneCurveComposite( vCrvCheck[i])) ; bOk = bOk && ( ! IsNull( pCrvCheckLocXY)) && pCrvCheckLocXY->IsValid() ; if ( bOk) { pCrvCheckLocXY->ToLoc( frLocXY) ; IntersCurveCurve ICC( *pCrvCheckLocXY, *pCompoLoc) ; for ( int j = 0 ; j < ICC.GetIntersCount() && bOk ; ++ j) { IntCrvCrvInfo aInfo ; bOk = ICC.GetIntCrvCrvInfo( j, aInfo) ; bOk = bOk && ( AreSamePointApprox( ptStart, aInfo.IciA[0].ptI) || AreSamePointApprox( ptEnd, aInfo.IciA[0].ptI)) ; } } } // se tutto bene, sostiuisco la curva originale con la modificata if ( bOk) { pCompoLoc->ToGlob( frLocXY) ; pCompo->CopyFrom( pCompoLoc) ; } 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 ; ICRVCOMPOPOVECTOR vCrvEmpty ; // recupero il frame localeXY della regione piana Frame3d frLoc ; Point3d ptC ; pSfr->GetCentroid( ptC) ; frLoc.Set( ptC, pSfr->GetNormVersor()) ; // scorro tutti i loops di tutte le parti for ( int nC = 0 ; nC < pSfr->GetChunkCount() ; ++ nC) { for ( int nL = 0 ; nL < pSfr->GetLoopCount( nC) ; ++ nL) { // recupero la curva di Loop e la semplifico PtrOwner pCompoLoop( ConvertCurveToComposite( pSfr->GetLoop( nC, nL))) ; if ( IsNull( pCompoLoop) || ! SimplifyCurve( pCompoLoop, vCrvEmpty, frLoc)) return false ; // inserisco le curve nella nuova regione (il primo loop di ogni parte è esterno) if ( nL == 0) { if ( ! pSfrSimple->AddExtLoop( Release( pCompoLoop))) return false ; } else { if ( ! pSfrSimple->AddIntLoop( Release( pCompoLoop))) return false ; } } } // se superficie semplificata valida, la sostituisco if ( pSfrSimple->IsValid()) return ( pSfr->CopyFrom( pSfrSimple)) ; return true ; } //---------------------------------------------------------------------------- bool SurfRoughing::RemoveChunksUnderTolerance( ISurfFlatRegion* pSfr, double dTol, ISurfFlatRegion* pSfrLimit, ISurfFlatRegion* pSfrToUpdate) 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 ( dTol < EPS_SMALL) // se tolleranza non presente, non faccio nulla return true ; // se non ho superfici da non rovinare, allora non devo fare nulla (sarà tutto aperto) if ( pSfrLimit == nullptr || ! pSfrLimit->IsValid() || pSfrLimit->GetChunkCount() == 0) return true ; // scorro tutti i chunk della superficie for ( int nC = 0 ; nC < pSfr->GetChunkCount() ; ++ nC) { // verifico se l'Offset massimo del chunk è sopra alla tolleranza double dMaxOffs = EPS_SMALL ; pSfr->GetChunkMaxOffset( nC, dMaxOffs) ; // rimuovo il Chunk c-esimo se l'Offset massimo è minore della tolleranza if ( dMaxOffs < dTol) { // devo evitare di rimuovere le isole aperte (queste, se rimosse, lasciano delle // punte di materiale che non vengono rimosse in quanto sempre scartate) // piccolo Offset alla regione limite double dOffs = m_TParams.m_dDiam / 2. + GetOffsR() + 30 * EPS_SMALL ; PtrOwner pSfrLimitOffs( pSfrLimit->CreateOffsetSurf( dOffs, ICurve::OFF_FILLET)) ; if ( IsNull( pSfrLimitOffs) || ! pSfrLimitOffs->IsValid()) return false ; // se il Chunk non tocca tale regione, allora lo conservo PtrOwner pSfrChunk( pSfr->CloneChunk( nC)) ; if ( IsNull( pSfrChunk) || ! pSfrChunk->IsValid()) return false ; pSfrChunk->Intersect( *pSfrLimitOffs) ; if ( IsNull( pSfrChunk) || ! pSfrChunk->IsValid() || pSfrChunk->GetChunkCount() == 0) continue ; // se ho una regione da aggiornare if ( pSfrToUpdate != nullptr && pSfrToUpdate->IsValid()) { PtrOwner pSfrChunk( pSfr->CloneChunk( nC)) ; if ( ! IsNull( pSfrChunk) || pSfrChunk->IsValid()) { pSfrChunk->Offset( 50. * EPS_SMALL, ICurve::OFF_FILLET) ; // si prova... pSfrToUpdate->Subtract( *pSfrChunk) ; // si prova... } } pSfr->EraseChunk( nC) ; -- nC ; } } return true ; } //---------------------------------------------------------------------------- bool SurfRoughing::CloseOpenEdgesUnderTolerance( ISurfFlatRegion* pSfr, double dToler) { /* Nei SubSteps capita spesso che ci siano dei lati aperti molto piccoli o delle sequenze di lati Aperti-Chiusi alternati tutti molto corti ( es. Laurana50K). Chiudo tutti i tratti aperti piccoli */ // controllo dei parametri if ( pSfr == nullptr || ! pSfr->IsValid()) return false ; if ( dToler < 10 * EPS_SMALL) // se tolleranza non presente, non faccio nulla return true ; // inizializzo la superficie da restituire PtrOwner pSfrRegular( CreateSurfFlatRegion()) ; if ( IsNull( pSfrRegular)) return false ; // recupero il frame locale XY della superficie Frame3d frLoc ; Point3d ptC ; pSfr->GetCentroid( ptC) ; frLoc.Set( ptC, pSfr->GetNormVersor()) ; // scorro tutti i chunk della superficie for ( int nC = 0 ; nC < pSfr->GetChunkCount() ; ++ nC) { // creo una superficie di test PtrOwner pSfrTest( CreateSurfFlatRegion()) ; if ( IsNull( pSfrTest)) return false ; // scorro tutti i loop bool bOk = true ; for ( int nL = 0 ; bOk && nL < pSfr->GetLoopCount( nC) ; ++ nL) { // recupero il loop come curva composita PtrOwner pCrvLoop( ConvertCurveToComposite( pSfr->GetLoop( nC, nL))) ; if ( IsNull( pCrvLoop) || ! pCrvLoop->IsValid()) return false ; // ricavo tratti di proprietà uniformi ------------- ICRVCOMPOPOVECTOR vpCrvs ; GetHomogeneousParts( pCrvLoop, vpCrvs) ; // memorizzo i tratti Closed ICRVCOMPOPOVECTOR vCrvClose ; for ( int i = 0 ; i < int( vpCrvs.size()) ; ++ i) { if ( vpCrvs[i]->GetTempProp( 0) == TEMP_PROP_CLOSE_EDGE) vCrvClose.emplace_back( CloneCurveComposite( vpCrvs[i])) ; } // scorro tutti i tratti aperti e riconcateno il loop PtrOwner pCrvNewLoop( CreateCurveComposite()) ; if ( IsNull( pCrvNewLoop)) return false ; for ( int i = 0 ; i < int( vpCrvs.size()) ; ++ i) { // se tratto aperto e non coincidente con tutta la curva if ( vpCrvs[i]->GetTempProp( 0) == TEMP_PROP_OPEN_EDGE && int( vpCrvs.size()) != 1) { // semplifico il loop per avere curve più uniformi SimplifyCurve( vpCrvs[i], vCrvClose, frLoc) ; // riporto le proprietà vpCrvs[i]->SetTempProp( TEMP_PROP_OPEN_EDGE) ; for ( int j = 0 ; j < vpCrvs[i]->GetCurveCount() ; ++ j) vpCrvs[i]->SetCurveTempProp( j, TEMP_PROP_OPEN_EDGE, 0) ; // controllo la lunghezza delle curve double dLen = EPS_SMALL ; vpCrvs[i]->GetLength( dLen) ; // se più corto della tolleranza if ( dLen < dToler) { vpCrvs[i]->SetTempProp( TEMP_PROP_CLOSE_EDGE, 0) ; for ( int j = 0 ; j < vpCrvs[i]->GetCurveCount() ; ++ j) vpCrvs[i]->SetCurveTempProp( j, TEMP_PROP_CLOSE_EDGE, 0) ; } } pCrvNewLoop->AddCurve( Release( vpCrvs[i])) ; } // inserisco i nuovi loop nella superficie regolare if ( nL == 0) bOk = bOk && pSfrTest->AddExtLoop( Release( pCrvNewLoop)) ; else bOk = bOk && pSfrTest->AddIntLoop( Release( pCrvNewLoop)) ; } // se il chunk è stato creato correttamente, allora lo aggiungo if ( bOk && pSfrTest->IsValid()) { if ( pSfrRegular->IsValid() && pSfrRegular->GetChunkCount() > 0) { if ( ! pSfrRegular->Add( *pSfrTest)) { PtrOwner pSfrChunkCL( CloneSurfFlatRegion( pSfr->CloneChunk( nC))) ; if ( IsNull( pSfrChunkCL) || ! pSfrChunkCL->IsValid()) return false ; if ( ! pSfrRegular->Add( *pSfrChunkCL)) return false ; } } else { if ( ! pSfrRegular.Set( pSfrTest)) return false ; } } // se errore nella creazione del Chunk, clono l'originale else { PtrOwner pSfrChunkCL( CloneSurfFlatRegion( pSfr->CloneChunk( nC))) ; if ( IsNull( pSfrChunkCL) || ! pSfrChunkCL->IsValid()) return false ; if ( pSfrRegular->IsValid() && pSfrRegular->GetChunkCount() > 0) { if ( ! pSfrRegular->Add( *pSfrChunkCL)) return false ; } else { if ( ! pSfrRegular.Set( pSfrChunkCL)) return false ; } } } // resituisco la superficie pSfr->CopyFrom( pSfrRegular) ; return true ; } //---------------------------------------------------------------------------- bool SurfRoughing::ModifySurfForOpenCloseEdges( ISurfFlatRegion* pSfr, const Vector3d& vtTool, const ICurveComposite* pCrvCompo) const { // controllo dei parametri if ( pSfr == nullptr || pCrvCompo == nullptr || ! pCrvCompo->IsValid()) return false ; if ( ! pSfr->IsValid()) return true ; /* NB. Questa funzione è richiamata per i sub steps. Alcuni subStep potrebbero avere dei lati aperti molto vicini ai lati chiusi della curva scelta per la sgrossatura; modifico la superficie di riferimento per la scelta dei lati Aperti/Chiusi estendendola con le regione generate dalle FatCurve dei tratti chiusi */ // ricavo i tratti chiusi della curva di sgrossatura ICRVCOMPOPOVECTOR vpCrvs ; if ( ! GetHomogeneousParts( pCrvCompo, vpCrvs)) return false ; // scorro tutti i tratti chiusi e li aggiungo alla superficie da non rovinare for ( int i = 0 ; i < int( vpCrvs.size()) ; ++ i) { if ( vpCrvs[i]->GetTempProp( 0) == TEMP_PROP_CLOSE_EDGE) { vpCrvs[i]->SetExtrusion( vtTool) ; PtrOwner pSfrFat( GetSurfFlatRegionFromFatCurve( vpCrvs[i]->Clone(), m_TParams.m_dDiam / 2, false, false)) ; if ( ! IsNull( pSfrFat) && pSfrFat->IsValid()) { if ( pSfr->IsValid()) { pSfr->Subtract( *pSfrFat) ; if ( ! pSfr->IsValid()) return true ; } } } } return true ; } //---------------------------------------------------------------------------- bool SurfRoughing::ChooseCloseOrOpenEdge( ISurfFlatRegion* pSfr, const ISurfFlatRegion* pSfrRef) const { // controllo parametri : if ( pSfr == nullptr || ! pSfr->IsValid()) return true ; // <- se superficie non valida, allora non ho niente da impostare sui suoi lati if ( pSfrRef == nullptr || ! pSfrRef->IsValid()) return false ; // recupero la regione di riferimento ( effettuerò un piccolo Offset per tolleranza) PtrOwner pSfrRef_Offs( CloneSurfFlatRegion( pSfrRef)) ; if ( IsNull( pSfrRef_Offs)) return false ; pSfrRef_Offs->Offset( - 50 * EPS_SMALL, ICurve::OFF_FILLET) ; // salvo le informazioni del loop relativi alla flatRegion di classificazione struct SurfRef_Info { bool bIsExternal = true ; int nInternalLoops = 0 ; BBox3d bBox ; PolyLine PL_Loop ; } ; vector vSfrRef_info ; // assegno le info dei Loop della superficie di riferimento for ( int nC = 0 ; nC < pSfrRef_Offs->GetChunkCount() ; ++ nC) { for ( int nL = 0 ; nL < pSfrRef_Offs->GetLoopCount( nC) ; ++ nL) { SurfRef_Info mySurfRef_Info ; mySurfRef_Info.bIsExternal = ( nL == 0) ; if ( mySurfRef_Info.bIsExternal) mySurfRef_Info.nInternalLoops = pSfrRef_Offs->GetLoopCount( nC) - 1 ; PtrOwner pCrv( pSfrRef_Offs->GetLoop( nC, nL)) ; pCrv->ApproxWithLines( 10 * EPS_SMALL, 15, ICurve::APL_STD, mySurfRef_Info.PL_Loop) ; if ( ! mySurfRef_Info.bIsExternal) mySurfRef_Info.PL_Loop.Invert() ; mySurfRef_Info.PL_Loop.GetLocalBBox( mySurfRef_Info.bBox) ; vSfrRef_info.emplace_back( mySurfRef_Info) ; } } // per ogni curva dei Loop della FlatRegion vengono presi 4 punti di controllo equidistanti. // " IL LATO E' APERTO <=> TUTTI I PUNTI DI CONTROLLO NON SONO DENTRO A pSfrRef " /* Invece di classificare i punti con la FlatRegion stessa è stata creata una struttura che contiene le PolyLine dei singoli loop. Quando io classifico un punto rispetto ad una regione piana, vengono presi tutti i loops e, una volta trasformati in PolyLine, viene classificato il punto rispetto ad esse. Invece di approssimare tutti i Loop da curve composite e Polyline per ogni punto ( per classificarlo), vengono direttamente salvate le PolyLine, in modo che questo passaggio sia fatto solo una volta all'inizio */ const int NUM_POINTS = 4 ; // scorro tutti i loop for ( int nC = 0 ; nC < pSfr->GetChunkCount() ; ++ nC) { for ( int nL = 0 ; nL < pSfr->GetLoopCount( nC) ; ++ nL) { // recupero la curva composita del Loop PtrOwner pCrvCompoLoop( ConvertCurveToComposite( pSfr->GetLoop( nC, nL))) ; if ( IsNull( pCrvCompoLoop) || ! pCrvCompoLoop->IsValid()) return false ; // scorro ogni sua sottocurva for ( int nU = 0 ; nU < pCrvCompoLoop->GetCurveCount() ; ++ nU) { // metto a 1 la TmpProp della sottocurva corrente della superficie pSfr->SetCurveTempProp( nC, nL, nU, TEMP_PROP_OPEN_EDGE, 0) ; // recupero la sottocurva const ICurve* pCrv = pCrvCompoLoop->GetCurve( nU) ; if ( pCrv == nullptr) return false ; // recupero i NUM_POINTS punti bool bIsOut = true ; for ( int nP = 0 ; nP < NUM_POINTS + 1 ; ++ nP) { double dPar = ( 1. / ( 1. * NUM_POINTS)) * nP ; 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( nC, nL, nU, TEMP_PROP_CLOSE_EDGE, 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::CheckSafetyLinearLink( const Point3d& ptCurr, const Point3d& ptDest, const ISurfFlatRegion* pSfrCheck, const Vector3d& vtTool, bool& bSafe) const { // controllo dei parametri if ( ! ptCurr.IsValid() || ! ptDest.IsValid() || ! vtTool.IsValid()) return false ; bSafe = true ; // porto ptDest alla stessa quota di ptCurr secondo vtTool Plane3d plProj ; if ( ! plProj.Set( ptCurr, vtTool)) return false ; Point3d ptDestProj = ProjectPointOnPlane( ptDest, plProj) ; if ( AreSamePointApprox( ptDestProj, ptCurr)) { bSafe = true ; return true ; } // controllo se la retta che collega ptCurr a ptDesProj è interna o esterna alla regione limite // devo prima creare un frame Locale XY if ( pSfrCheck != nullptr && pSfrCheck->IsValid()) { PtrOwner pSfrCheckLoc( CloneSurfFlatRegion( pSfrCheck)) ; PtrOwner pLineLoc( CreateCurveLine()) ; Frame3d frLoc ; if ( IsNull( pSfrCheckLoc) || ! frLoc.Set( ptCurr, vtTool) || ! ptDestProj.ToLoc( frLoc) || ! pSfrCheckLoc->ToLoc( frLoc) || ! pSfrCheckLoc->Offset( m_TParams.m_dDiam / 2. - 10. * EPS_SMALL, ICurve::OFF_FILLET) || ! pLineLoc->Set( ORIG, ptDestProj)) return false ; for ( int nC = 0 ; nC < pSfrCheckLoc->GetChunkCount() && bSafe ; ++ nC) { CRVCVECTOR ccClass ; bSafe = ( pSfrCheckLoc->GetCurveClassification( *pLineLoc, EPS_SMALL, ccClass) && int( ccClass.size()) == 1 && ccClass[0].nClass == CRVC_OUT) ; } } return true ; } //---------------------------------------------------------------------------- bool SurfRoughing::VerifyLeadInHelix( const ISurfFlatRegion* pSfr, const Point3d& ptStart, const Point3d& ptCen, double dHelixRad) const { // controllo validità dei parametri if ( pSfr == nullptr || ! pSfr->IsValid()) return false ; Vector3d vtN = pSfr->GetNormVersor() ; // porto il centro sullo stesso piano del contorno Point3d ptCenL = ptCen - ( ptCen - ptStart) * vtN * vtN ; // Offset della regione PtrOwner pSfrOffs( pSfr->CreateOffsetSurf( - m_TParams.m_dDiam / 2 - dHelixRad + 10 * EPS_SMALL, ICurve::OFF_FILLET)) ; if ( IsNull( pSfrOffs) || ! pSfrOffs->IsValid()) return false ; // controllo se l'elica è valida bool bIsInside ; return ( IsPointInsideSurfFr( ptCenL, pSfrOffs, 0., bIsInside) && bIsInside) ; } //---------------------------------------------------------------------------- bool SurfRoughing::VerifyLeadInZigZag( const ISurfFlatRegion* pSfr, const Point3d& ptStart, const Point3d& ptPa, const Point3d& ptPb) const { // controllo validità dei parametri if ( pSfr == nullptr || ! pSfr->IsValid()) return false ; Vector3d vtN = pSfr->GetNormVersor() ; // porto i punti sullo stesso piano del contorno Point3d ptPaL = ptPa - ( ptPa - ptStart) * vtN * vtN ; Point3d ptPbL = ptPb - ( ptPb - ptStart) * vtN * vtN ; // Offset della regione PtrOwner pSfrOffs( pSfr->CreateOffsetSurf( - m_TParams.m_dDiam / 2 + 10 * EPS_SMALL, ICurve::OFF_FILLET)) ; if ( IsNull( pSfrOffs) || ! pSfrOffs->IsValid()) return false ; // controllo se i due punti sono validi bool bIsInside ; return ( IsPointInsideSurfFr( ptPaL, pSfrOffs, 0., bIsInside) && bIsInside && IsPointInsideSurfFr( ptPbL, pSfrOffs, 0., bIsInside) && bIsInside) ; } //---------------------------------------------------------------------------- bool SurfRoughing::GetHomogeneousParts( const ICurveComposite* pCrvCompo, ICRVCOMPOPOVECTOR& vpCrvs) const { // controllo dei parametri if ( pCrvCompo == nullptr || ! pCrvCompo->IsValid()) return false ; vpCrvs.clear() ; // scorro tutte le curve semplici nella composita int nCurrTempProp ; int nParStart = 0 ; for ( int i = 0 ; i < pCrvCompo->GetCurveCount() ; ++ i) { // ricavo la TmpProp int nTempProp ; pCrvCompo->GetCurveTempProp( i, nTempProp) ; if ( i == 0) { nCurrTempProp = nTempProp ; nParStart = i ; } // se TmpProp differiscono, ricavo il tratto di curva omogeneo else if ( nCurrTempProp != nTempProp) { PtrOwner pCrv( ConvertCurveToComposite( pCrvCompo->CopyParamRange( nParStart, i))) ; if ( IsNull( pCrv)) return false ; pCrv->SetTempProp( nCurrTempProp) ; // globale, al tratto di curva nel vettore vpCrvs.emplace_back( Release( pCrv)) ; nCurrTempProp = nTempProp ; nParStart = i ; } } // ultima curva... PtrOwner pCrvLast( ConvertCurveToComposite( pCrvCompo->CopyParamRange( nParStart, pCrvCompo->GetCurveCount()))) ; if ( ! IsNull( pCrvLast)) { pCrvLast->SetTempProp( nCurrTempProp) ; vpCrvs.emplace_back( Release( pCrvLast)) ; } if ( vpCrvs.size() > 1) { // unisco il primo e l'ultimo se estremi compatibili Point3d ptE ; vpCrvs.back()->GetEndPoint( ptE) ; Point3d ptS ; vpCrvs[0]->GetStartPoint( ptS) ; if ( AreSamePointApprox( ptS, ptE) && vpCrvs[0]->GetTempProp() == vpCrvs.back()->GetTempProp()) { vpCrvs[0]->AddCurve( Release( vpCrvs.back()), false) ; vpCrvs.erase( vpCrvs.end() - 1) ; } } return true ; } //---------------------------------------------------------------------------- // Debug Functions //---------------------------------------------------------------------------- void SurfRoughing::DrawLoopsSurf( const ISurfFlatRegion* pSfr, bool bUniform, Color Col, bool bAlphaCoverage, string sName) const { if ( pSfr == nullptr || ! pSfr->IsValid()) return ; int nIdGroup = m_pGeomDB->AddGroup( GDB_ID_NULL, GDB_ID_ROOT, GLOB_FRM) ; m_pGeomDB->SetName( nIdGroup, sName) ; int nIdLayer = m_pGeomDB->AddGroup( GDB_ID_NULL, nIdGroup, GLOB_FRM) ; m_pGeomDB->SetName( nIdLayer, sName) ; int nInd = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nIdLayer, pSfr->Clone()) ; Color myColor = Col ; if ( bAlphaCoverage) myColor.Set( myColor.GetRed() / 2., myColor.GetGreen() / 2., myColor.GetBlue() / 2., myColor.GetAlpha() / 2.) ; m_pGeomDB->SetMaterial( nInd, myColor) ; for ( int nC = 0 ; nC < pSfr->GetChunkCount() ; ++ nC) { for ( int nL = 0 ; nL < pSfr->GetLoopCount( nC) ; ++ nL) { PtrOwner pCrvCompo( ConvertCurveToComposite( pSfr->GetLoop( nC, nL))) ; for ( int nU = 0 ; nU < pCrvCompo->GetCurveCount() ; ++ nU) { int nProp0 ; pCrvCompo->GetCurveTempProp( nU, nProp0, 0) ; int nProp1 ; pCrvCompo->GetCurveTempProp( nU, nProp1, 1) ; int nInd = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nIdLayer, pCrvCompo->GetCurve( nU)->Clone()) ; m_pGeomDB->SetMaterial( nInd, bUniform ? WHITE : ( nProp0 == 0 ? ( bAlphaCoverage ? AQUA : BLUE) : ( bAlphaCoverage ? ORANGE : RED))) ; } } } return ; } //---------------------------------------------------------------------------- void SurfRoughing::DrawFeed( const ICurve* pCrv, double dFeed, int nLay) const { if ( pCrv == nullptr) return ; // recupero parametro di Feed minima double dMinFeed = GetFeed() / FEED_MAX_REDUCE ; if ( GetValInNotes( m_Params.m_sUserNotes, UN_MINFEED, dMinFeed)) dMinFeed = Clamp( dMinFeed, GetFeed() / FEED_MAX_REDUCE, GetFeed()) ; double myAngle = 120 * ( ( ( dFeed - dMinFeed) / ( GetFeed() - dMinFeed))) ; int nInd = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLay, pCrv->Clone()) ; m_pGeomDB->SetMaterial( nInd, GetColorFromHSV( HSV( myAngle, 1., 1.))) ; return ; return ; } //---------------------------------------------------------------------------- void SurfRoughing::DrawNormalShaderSurfTm( const ISurfTriMesh* pStm, string sName) const { if ( pStm == nullptr || ! pStm->IsValid()) return ; int nIdGroup = m_pGeomDB->AddGroup( GDB_ID_NULL, GDB_ID_ROOT, GLOB_FRM) ; m_pGeomDB->SetName( nIdGroup, "ShaderStm") ; int nIdLayer = m_pGeomDB->AddGroup( GDB_ID_NULL, nIdGroup, GLOB_FRM) ; m_pGeomDB->SetName( nIdLayer, sName) ; for ( int nT = 0 ; nT < pStm->GetTriangleCount() ; ++ nT) { PtrOwner pStmTria( pStm->CloneTriangle( nT)) ; int nId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nIdLayer, pStmTria->Clone()) ; Vector3d vtN ; pStmTria->GetFacetNormal( 0, vtN) ; m_pGeomDB->SetMaterial( nId, Color( abs( vtN.x), abs( vtN.y), abs( vtN.z))) ; } return ; }