//---------------------------------------------------------------------------- // EgalTech 2017-2022 //---------------------------------------------------------------------------- // File : Pocketing.cpp Data : 24.08.22 Versione : 2.4h2 // Contenuto : Implementazione gestione svuotature. // // // // Modifiche : 04.02.17 DS Creazione modulo. // 24.02.22 DS Corretta ed estesa VerifyPathFromBottom. // // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "MachMgr.h" #include "DllMain.h" #include "Pocketing.h" #include "OperationConst.h" #include "MachiningConst.h" #include "GeoConst.h" #include "/EgtDev/Include/EGkCurveLine.h" #include "/EgtDev/Include/EGkCurveArc.h" #include "/EgtDev/Include/EGkBiArcs.h" #include "/EgtDev/Include/EGkArcSpecial.h" #include "/EgtDev/Include/EGkChainCurves.h" #include "/EgtDev/Include/EGkOffsetCurve.h" #include "/EgtDev/Include/EGkCurveAux.h" #include "/EgtDev/Include/EGkSfrCreate.h" #include "/EgtDev/Include/EGkSurfTriMesh.h" #include "/EgtDev/Include/EGkExtText.h" #include "/EgtDev/Include/EGkCurveLocal.h" #include "/EgtDev/Include/EGkDistPointCurve.h" #include "/EgtDev/Include/EGkUserObjFactory.h" #include "/EgtDev/Include/EGkIntervals.h" #include "/EgtDev/Include/EGkStringUtils3d.h" #include "/EgtDev/Include/EGnStringKeyVal.h" #include "/EgtDev/Include/EgtPointerOwner.h" #include "/EgtDev/Include/EgtNumUtils.h" #include "/EgtDev/Include/EGkLinePntMinDistCurve.h" #include "/EgtDev/Include/EGkDistPointCurve.h" #include "/EgtDev/Include/EGkMedialAxis.h" #include "/EgtDev/Include/EGkFilletChamfer.h" #include "/EgtDev/Include/EGkCurveBezier.h" #include "/EgtDev/Include/EGkGeoPoint3d.h" #include "/EgtDev/Include/EGkIntersCurves.h" #include "/EgtDev/Include/EGkLinePntTgCurve.h" #include "/EgtDev/Include/EGkSfrCreate.h" #include "/EgtDev/Include/EGkStmStandard.h" #include "/EgtDev/Include/EGkIntersPlaneSurfTm.h" #include "/EgtDev/Include/EGkDistPointSurfTm.h" #include "/EgtDev/Include/EGkStmFromCurves.h" #include "/EgtDev/Include/EGkStmFromTriangleSoup.h" #include using namespace std ; //------------------------------ Errors -------------------------------------- // 2401 = "Error in Pocketing : UpdateToolData failed" // 2402 = "Error in Pocketing : Open Contour" // 2403 = "Error in Pocketing : Contour Not Flat" // 2404 = "Error in Pocketing : Tool Not Perpendicular to Flat Area" // 2405 = "Error in Pocketing : Empty RawBox" // 2406 = "Error in Pocketing : Depth not computable" // 2408 = "Error in Pocketing : Entity GetElevation" // 2409 = "Error in Pocketing : missing aggregate from bottom" // 2410 = "Error in Pocketing : path too far from part sides" // 2411 = "Error in Pocketing : toolpath allocation failed" // 2412 = "Error in Pocketing : Offset not computable" // 2413 = "Error in Pocketing : Toolpath not computable" // 2414 = "Error in Pocketing : Approach not computable" // 2415 = "Error in Pocketing : LeadIn not computable" // 2416 = "Error in Pocketing : LeadOut not computable" // 2417 = "Error in Pocketing : Retract not computable" // 2418 = "Error in Pocketing : Link not computable" // 2419 = "Error in Pocketing : Linear Approx not computable" // 2420 = "Error in Pocketing : Return toolpath not computable" // 2421 = "Error in Pocketing : Chaining failed" // 2422 = "Error in Pocketing : Tool MaxMaterial too small (xxx)" // 2423 = "Error in Pocketing : axes values not calculable" // 2424 = "Error in Pocketing : outstroke xxx" // 2425 = "Error in Pocketing : link movements not calculable" // 2426 = "Error in Pocketing : link outstroke xxx" // 2427 = "Error in Pocketing : post apply not calculable" // 2428 = "Error in Pocketing : Tool loading failed" // 2429 = "Error in Pocketing : machining depth (xxx) bigger than MaxDepth (yyy)" // 2430 = "Error in Pocketing : adjust open edges failed" // 2431 = "Error in Pocketing : LeadIn with Mill NoTip in material" // 2451 = "Warning in Pocketing : Skipped entity (xx)" // 2452 = "Warning in Pocketing : No machinable pocket" // 2453 = "Warning in Pocketing : Tool name changed (xx)" // 2454 = "Warning in Pocketing : Tool data changed (xx)" // 2455 = "Warning in Pocketing : skipped Path too short" // 2456 = "Warning in Pocketing : machining step too small (xx)" // 2457 = "Warning in Pocketing : machining step (xxx) bigger than MaxMaterial (yyy)" // 2458 = "Warning in Pocketing : machining depth (xxx) bigger than MaxMaterial (yyy)" //---------------------------------------------------------------------------- static string KEY_OPEN = "OPEN" ; static const std::string BOX_NAME = "Box" ; static int LINK_CURVE_PROP = -3 ; static double FEED_DIVISOR = 1000.0 ; //---------------------------------------------------------------------------- USEROBJ_REGISTER( GetOperationClass( OPER_POCKETING), Pocketing) ; //---------------------------------------------------------------------------- const string& Pocketing::GetClassName( void) const { return USEROBJ_GETNAME( Pocketing) ; } //---------------------------------------------------------------------------- Pocketing* Pocketing::Clone( void) const { // alloco oggetto Pocketing* pPock = new(nothrow) Pocketing ; // eseguo copia dei dati if ( pPock != nullptr) { try { pPock->m_vId = m_vId ; pPock->m_pMchMgr = m_pMchMgr ; pPock->m_nPhase = m_nPhase ; pPock->m_Params = m_Params ; pPock->m_TParams = m_TParams ; pPock->m_dTHoldBase = m_dTHoldBase ; pPock->m_dTHoldLen = m_dTHoldLen ; pPock->m_dTHoldDiam = m_dTHoldDiam ; pPock->m_nStatus = m_nStatus ; pPock->m_nPockets = m_nPockets ; pPock->m_bTiltingTab = m_bTiltingTab ; pPock->m_vtTiltingAx = m_vtTiltingAx ; pPock->m_bAboveHead = m_bAboveHead ; pPock->m_bAggrBottom = m_bAggrBottom ; pPock->m_bOpenOutRaw = m_bOpenOutRaw ; pPock->m_dOpenMinSafe = m_dOpenMinSafe ; } catch( ...) { delete pPock ; return nullptr ; } } // ritorno l'oggetto return pPock ; } //---------------------------------------------------------------------------- bool Pocketing::Dump( string& sOut, bool bMM, const char* szNewLine) const { sOut += GetClassName() + "[mm]" + szNewLine ; sOut += KEY_PHASE + EQUAL + ToString( m_nPhase) + szNewLine ; sOut += KEY_IDS + EQUAL + ToString( m_vId) + szNewLine ; for ( int i = 0 ; i < m_Params.GetSize() ; ++ i) sOut += m_Params.ToString( i) + szNewLine ; for ( int i = 0 ; i < m_TParams.GetSize() ; ++ i) sOut += m_TParams.ToString( i) + szNewLine ; sOut += KEY_NUM + EQUAL + ToString( m_nPockets) + szNewLine ; sOut += KEY_STAT + EQUAL + ToString( m_nStatus) + szNewLine ; return true ; } //---------------------------------------------------------------------------- bool Pocketing::Save( int nBaseId, STRVECTOR& vString) const { try { int nSize = 1 + m_Params.GetSize() + m_TParams.GetSize() + 3 ; vString.insert( vString.begin(), nSize, "") ; int k = - 1 ; if ( ! SetVal( KEY_IDS, m_vId, vString[++k])) return false ; for ( int i = 0 ; i < m_Params.GetSize() ; ++ i) { string sParam = m_Params.ToString( i) ; if ( ! sParam.empty()) vString[++k] = sParam ; } for ( int i = 0 ; i < m_TParams.GetSize() ; ++ i) vString[++k] = m_TParams.ToString( i) ; if ( ! SetVal( KEY_PHASE, m_nPhase, vString[++k])) return false ; if ( ! SetVal( KEY_NUM, m_nPockets, vString[++k])) return false ; if ( ! SetVal( KEY_STAT, m_nStatus, vString[++k])) return false ; vString.resize( k + 1) ; } catch( ...) { return false ; } return true ; } //---------------------------------------------------------------------------- bool Pocketing::Load( const STRVECTOR& vString, int nBaseGdbId) { int nSize = int( vString.size()) ; // lista identificativi geometrie da lavorare int k = - 1 ; if ( k >= nSize - 1 || ! GetVal( vString[++k], KEY_IDS, m_vId)) return false ; for ( auto& Sel : m_vId) Sel.nId += nBaseGdbId ; // parametri lavorazione for ( int i = 0 ; i < m_Params.GetSize() ; ++ i) { int nKey ; if ( k >= nSize - 1 || ! m_Params.FromString( vString[++k], nKey) || nKey != i) { if ( m_Params.IsOptional( i)) -- k ; else return false ; } } // parametri utensile for ( int i = 0 ; i < m_TParams.GetSize() ; ++ i) { int nKey ; if ( k >= nSize - 1 || ! m_TParams.FromString( vString[++k], nKey) || nKey != i) return false ; } // parametri di stato while ( k < nSize - 1) { // separo chiave da valore string sKey, sVal ; SplitFirst( vString[++k], "=", sKey, sVal) ; // leggo if ( sKey == KEY_PHASE) { if ( ! FromString( sVal, m_nPhase)) return false ; } else if ( sKey == KEY_NUM) { if ( ! FromString( sVal, m_nPockets)) return false ; } else if ( sKey == KEY_STAT) { if ( ! FromString( sVal, m_nStatus)) return false ; } } return true ; } //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- Pocketing::Pocketing( void) { m_Params.m_sName = "*" ; m_Params.m_sToolName = "*" ; m_TParams.m_sName = "*" ; m_TParams.m_sHead = "*" ; m_dTHoldBase = 0 ; m_dTHoldLen = 0 ; m_dTHoldDiam = 0 ; m_dMaxHelixRad = INFINITO ; m_nStatus = MCH_ST_TO_VERIFY ; m_nPockets = 0 ; m_bTiltingTab = false ; m_bAboveHead = true ; m_bAggrBottom = false ; m_bOpenOutRaw = false ; m_dOpenMinSafe = 0 ; } //---------------------------------------------------------------------------- bool Pocketing::Prepare( const string& sMillName) { // verifico il gestore lavorazioni if ( m_pMchMgr == nullptr) return false ; // recupero il gestore DB utensili della macchina corrente ToolsMgr* pTMgr = m_pMchMgr->GetCurrToolsMgr() ; if ( pTMgr == nullptr) return false ; // recupero il gestore DB lavorazioni della macchina corrente MachiningsMgr* pMMgr = m_pMchMgr->GetCurrMachiningsMgr() ; if ( pMMgr == nullptr) return false ; // ricerca della lavorazione di libreria con il nome indicato const PocketingData* pDdata = GetPocketingData( pMMgr->GetMachining( sMillName)) ; if ( pDdata == nullptr) return false ; m_Params = *pDdata ; // ricerca dell'utensile usato dalla lavorazione const ToolData* pTdata = pTMgr->GetTool( m_Params.m_ToolUuid) ; if ( pTdata == nullptr) return false ; m_TParams = *pTdata ; m_Params.m_sToolName = m_TParams.m_sName ; return true ; } //---------------------------------------------------------------------------- bool Pocketing::SetParam( int nType, bool bVal) { switch ( nType) { case MPA_INVERT : if ( bVal != m_Params.m_bInvert) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_bInvert = bVal ; return true ; case MPA_TOOLINVERT : if ( bVal != m_Params.m_bToolInvert) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_bToolInvert = bVal ; return true ; } return false ; } //---------------------------------------------------------------------------- bool Pocketing::SetParam( int nType, int nVal) { switch ( nType) { case MPA_LEADINTYPE : if ( ! m_Params.VerifyLeadInType( nVal)) return false ; if ( nVal != m_Params.m_nLeadInType) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_nLeadInType = nVal ; return true ; case MPA_LEADOUTTYPE : if ( ! m_Params.VerifyLeadOutType( nVal)) return false ; if ( nVal != m_Params.m_nLeadOutType) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_nLeadOutType = nVal ; return true ; case MPA_SCC : if ( ! m_Params.VerifySolCh( nVal)) return false ; if ( nVal != m_Params.m_nSolCh) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_nSolCh = nVal ; return true ; case MPA_SUBTYPE : if ( ! m_Params.VerifySubType( nVal)) return false ; if ( nVal != m_Params.m_nSubType) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_nSubType = nVal ; return true ; } return false ; } //---------------------------------------------------------------------------- bool Pocketing::SetParam( int nType, double dVal) { switch ( nType) { case MPA_SPEED : if ( ! m_TParams.VerifySpeed( dVal)) return false ; if ( abs( m_TParams.m_dSpeed - dVal) < EPS_MACH_ANG_PAR) dVal = 0 ; if ( abs( dVal - m_Params.m_dSpeed) > EPS_MACH_ANG_PAR) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dSpeed = dVal ; return true ; case MPA_FEED : if ( abs( m_TParams.m_dFeed - dVal) < EPS_MACH_LEN_PAR) dVal = 0 ; if ( abs( dVal - m_Params.m_dFeed) > EPS_MACH_LEN_PAR) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dFeed = dVal ; return true ; case MPA_STARTFEED : if ( abs( m_TParams.m_dStartFeed - dVal) < EPS_MACH_LEN_PAR) dVal = 0 ; if ( abs( dVal - m_Params.m_dStartFeed) > EPS_MACH_LEN_PAR) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dStartFeed = dVal ; return true ; case MPA_ENDFEED : if ( abs( m_TParams.m_dEndFeed - dVal) < EPS_MACH_LEN_PAR) dVal = 0 ; if ( abs( dVal - m_Params.m_dEndFeed) > EPS_MACH_LEN_PAR) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dEndFeed = dVal ; return true ; case MPA_TIPFEED : if ( abs( m_TParams.m_dTipFeed - dVal) < EPS_MACH_LEN_PAR) dVal = 0 ; if ( abs( dVal - m_Params.m_dTipFeed) > EPS_MACH_LEN_PAR) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dTipFeed = dVal ; return true ; case MPA_OFFSR : if ( abs( m_TParams.m_dOffsR - dVal) < EPS_MACH_LEN_PAR) dVal = UNKNOWN_PAR ; if ( abs( dVal - m_Params.m_dOffsR) > EPS_MACH_LEN_PAR) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dOffsR = dVal ; return true ; case MPA_OFFSL : if ( abs( m_TParams.m_dOffsL - dVal) < EPS_MACH_LEN_PAR) dVal = UNKNOWN_PAR ; if ( abs( dVal - m_Params.m_dOffsL) > EPS_MACH_LEN_PAR) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dOffsL = dVal ; return true ; case MPA_DEPTH : { string sVal = ToString( dVal) ; if ( sVal != m_Params.m_sDepth) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_sDepth = sVal ; } return true ; case MPA_STARTPOS : if ( abs( dVal - m_Params.m_dStartPos) > EPS_MACH_LEN_PAR) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dStartPos = dVal ; return true ; case MPA_STEP : if ( abs( dVal - m_Params.m_dStep) > EPS_MACH_LEN_PAR) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dStep = dVal ; return true ; case MPA_SIDESTEP : if ( abs( dVal - m_Params.m_dSideStep) > EPS_MACH_LEN_PAR) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dSideStep = dVal ; return true ; case MPA_SIDEANGLE : if ( abs( dVal - m_Params.m_dSideAngle) > EPS_MACH_LEN_PAR) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dSideAngle = dVal ; return true ; case MPA_LITANG : if ( abs( dVal - m_Params.m_dLiTang) > EPS_MACH_LEN_PAR) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dLiTang = dVal ; return true ; case MPA_LIELEV : if ( abs( dVal - m_Params.m_dLiElev) > EPS_MACH_LEN_PAR) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dLiElev = dVal ; return true ; case MPA_LOTANG : if ( abs( dVal - m_Params.m_dLoTang) > EPS_MACH_LEN_PAR) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dLoTang = dVal ; return true ; case MPA_EPICYCLESRAD : if ( abs( dVal - m_Params.m_dEpicyclesRad) > EPS_MACH_LEN_PAR) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dEpicyclesRad = dVal ; return true ; case MPA_EPICYCLESDIST : if ( abs( dVal - m_Params.m_dEpicyclesDist) > EPS_MACH_LEN_PAR) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_dEpicyclesDist = dVal ; return true ; } return false ; } //---------------------------------------------------------------------------- bool Pocketing::SetParam( int nType, const string& sVal) { switch ( nType) { case MPA_TOOL : { const ToolData* pTdata ; if ( ! m_Params.VerifyTool( m_pMchMgr->GetCurrToolsMgr(), sVal, pTdata)) return false ; if ( ! SameTool( m_TParams, *pTdata)) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_sToolName = sVal ; m_Params.m_ToolUuid = pTdata->m_Uuid ; m_TParams = *pTdata ; } return true ; case MPA_DEPTH_STR : if ( sVal != m_Params.m_sDepth) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_sDepth = sVal ; return true ; case MPA_SYSNOTES : if ( sVal != m_Params.m_sSysNotes) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_sSysNotes = sVal ; return true ; case MPA_USERNOTES : if ( sVal != m_Params.m_sUserNotes) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_sUserNotes = sVal ; return true ; case MPA_INITANGS : if ( sVal != m_Params.m_sInitAngs) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_sInitAngs = sVal ; return true ; case MPA_BLOCKEDAXIS : if ( sVal != m_Params.m_sBlockedAxis) m_nStatus |= MCH_ST_PARAM_MODIF ; m_Params.m_sBlockedAxis = sVal ; return true ; } return false ; } //---------------------------------------------------------------------------- bool Pocketing::SetGeometry( const SELVECTOR& vIds) { // verifico validità gestore DB geometrico if ( m_pGeomDB == nullptr) return false ; // reset della geometria corrente m_vId.clear() ; // verifico che gli identificativi rappresentino delle entità ammissibili (tutte curve o tutte facce) int nType = GEO_NONE ; for ( const auto& Id : vIds) { // test sull'entità int nSubs ; if ( ! VerifyGeometry( Id, nSubs, nType)) { string sInfo = "Warning in Pocketing : Skipped entity " + ToString( Id) ; m_pMchMgr->SetWarning( 2451, sInfo) ; continue ; } // posso aggiungere alla lista m_vId.emplace_back( Id) ; } // aggiorno lo stato m_nStatus |= MCH_ST_GEO_MODIF ; // restituisco presenza geometria da lavorare return ( ! m_vId.empty() || vIds.empty()) ; } //---------------------------------------------------------------------------- bool Pocketing::Preview( bool bRecalc) { // reset numero percorsi di svuotatura generati m_nPockets = 0 ; // verifico validità gestore DB geometrico e Id del gruppo if ( m_pGeomDB == nullptr || ! m_pGeomDB->ExistsObj( m_nOwnerId)) return false ; // recupero gruppo per geometria ausiliaria int nAuxId = m_pGeomDB->GetFirstNameInGroup( m_nOwnerId, MCH_AUX) ; bool bChain = false ; // se non c'è, lo aggiungo if ( nAuxId == GDB_ID_NULL) { nAuxId = m_pGeomDB->AddGroup( GDB_ID_NULL, m_nOwnerId, Frame3d()) ; if ( nAuxId == GDB_ID_NULL) return false ; m_pGeomDB->SetName( nAuxId, MCH_AUX) ; m_pGeomDB->SetStatus( nAuxId, GDB_ST_OFF) ; bChain = true ; } // altrimenti, se chiesto ricalcolo, lo svuoto else if ( bRecalc) { m_pGeomDB->EmptyGroup( nAuxId) ; bChain = true ; } // aggiorno dati geometrici dell'utensile if ( ! UpdateToolData()) { m_pMchMgr->SetLastError( 2401, "Error in Pocketing : UpdateToolData failed") ; return false ; } // rendo corrente l'utensile usato nella lavorazione if ( ! m_pMchMgr->SetCalcTool( m_TParams.m_sName, m_TParams.m_sHead, m_TParams.m_nExit)) { m_pMchMgr->SetLastError( 2428, "Error in Pocketing : Tool loading failed") ; return false ; } // recupero i dati del portautensile int nToolId = m_pMchMgr->GetCalcTool() ; m_dTHoldBase = 0 ; m_pGeomDB->GetInfo( nToolId, TTH_BASE, m_dTHoldBase) ; m_dTHoldLen = 0 ; m_pGeomDB->GetInfo( nToolId, TTH_LEN, m_dTHoldLen) ; m_dTHoldDiam = 0 ; m_pGeomDB->GetInfo( nToolId, TTH_DIAM, m_dTHoldDiam) ; // se necessario, eseguo concatenamento ed inserisco i percorsi sotto la geometria ausiliaria if ( bChain && ! Chain( nAuxId)) { m_pMchMgr->SetLastError( 2421, "Error in Pocketing : Chaining failed") ; return false ; } // recupero gruppo per geometria di Preview int nPvId = m_pGeomDB->GetFirstNameInGroup( m_nOwnerId, MCH_PV) ; // se non c'è, lo aggiungo if ( nPvId == GDB_ID_NULL) { nPvId = m_pGeomDB->AddGroup( GDB_ID_NULL, m_nOwnerId, Frame3d()) ; if ( nPvId == GDB_ID_NULL) return false ; m_pGeomDB->SetName( nPvId, MCH_PV) ; } // altrimenti lo svuoto else m_pGeomDB->EmptyGroup( nPvId) ; // lavoro ogni singola catena int nPathId = m_pGeomDB->GetFirstGroupInGroup( nAuxId) ; while ( nPathId != GDB_ID_NULL) { if ( ! ProcessPath( nPathId, nPvId, GDB_ID_NULL)) return false ; nPathId = m_pGeomDB->GetNextGroup( nPathId) ; } return true ; } //---------------------------------------------------------------------------- bool Pocketing::Apply( bool bRecalc, bool bPostApply) { // reset numero percorsi di svuotatura generati int nCurrPockets = m_nPockets ; m_nPockets = 0 ; // reset raggio massimo attacco ad elica nel caso di cerchi m_dMaxHelixRad = INFINITO ; // verifico validità gestore DB geometrico e Id del gruppo if ( m_pGeomDB == nullptr || ! m_pGeomDB->ExistsObj( m_nOwnerId)) return false ; // aggiorno dati geometrici dell'utensile bool bToolChanged = true ; if ( ! UpdateToolData( &bToolChanged)) { m_pMchMgr->SetLastError( 2401, "Error in Pocketing : UpdateToolData failed") ; return false ; } // verifico se necessario continuare nell'aggiornamento if ( !bRecalc && !bToolChanged && ( m_nStatus == MCH_ST_OK || ( !bPostApply && m_nStatus == MCH_ST_NO_POSTAPPL))) { // confermo i percorsi di lavorazione m_nPockets = nCurrPockets ; LOG_DBG_INFO( GetEMkLogger(), "Pocketing apply skipped : status already ok") ; // eseguo aggiornamento assi macchina e collegamento con operazione precedente if ( ! Update( bPostApply)) return false ; LOG_DBG_INFO( GetEMkLogger(), "Update done") ; // esco con successo return true ; } m_nStatus = MCH_ST_TO_VERIFY ; // recupero gruppo per geometria ausiliaria int nAuxId = m_pGeomDB->GetFirstNameInGroup( m_nOwnerId, MCH_AUX) ; bool bChain = false ; // se non c'è, lo aggiungo if ( nAuxId == GDB_ID_NULL) { nAuxId = m_pGeomDB->AddGroup( GDB_ID_NULL, m_nOwnerId, Frame3d()) ; if ( nAuxId == GDB_ID_NULL) return false ; m_pGeomDB->SetName( nAuxId, MCH_AUX) ; m_pGeomDB->SetStatus( nAuxId, GDB_ST_OFF) ; bChain = true ; } // altrimenti, se chiesto ricalcolo, lo svuoto else if ( bRecalc) { m_pGeomDB->EmptyGroup( nAuxId) ; bChain = true ; } // rendo corrente l'utensile usato nella lavorazione if ( ! m_pMchMgr->SetCalcTool( m_TParams.m_sName, m_TParams.m_sHead, m_TParams.m_nExit)) { m_pMchMgr->SetLastError( 2428, "Error in Pocketing : Tool loading failed") ; return false ; } // recupero i dati del portautensile int nToolId = m_pMchMgr->GetCalcTool() ; m_dTHoldBase = 0 ; m_pGeomDB->GetInfo( nToolId, TTH_BASE, m_dTHoldBase) ; m_dTHoldLen = 0 ; m_pGeomDB->GetInfo( nToolId, TTH_LEN, m_dTHoldLen) ; m_dTHoldDiam = 0 ; m_pGeomDB->GetInfo( nToolId, TTH_DIAM, m_dTHoldDiam) ; // se necessario, eseguo concatenamento ed inserisco i percorsi sotto la geometria ausiliaria if ( bChain && ! Chain( nAuxId)) { m_pMchMgr->SetLastError( 2421, "Error in Pocketing : Chaining failed") ; return false ; } // recupero gruppo per geometria di lavorazione (Cutter Location) int nClId = m_pGeomDB->GetFirstNameInGroup( m_nOwnerId, MCH_CL) ; // se non c'è, lo aggiungo if ( nClId == GDB_ID_NULL) { nClId = m_pGeomDB->AddGroup( GDB_ID_NULL, m_nOwnerId, Frame3d()) ; if ( nClId == GDB_ID_NULL) return false ; m_pGeomDB->SetName( nClId, MCH_CL) ; } // altrimenti lo svuoto else m_pGeomDB->EmptyGroup( nClId) ; // lavoro ogni singola catena bool bOk = true ; if ( ! ProcessPath( nAuxId, GDB_ID_NULL, nClId)) bOk = false ; 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(), "Pocketing apply done") ; return true ; } //---------------------------------------------------------------------------- bool Pocketing::Update( bool bPostApply) { // verifico validità gestore DB geometrico e Id del gruppo if ( m_pGeomDB == nullptr || ! m_pGeomDB->ExistsObj( m_nOwnerId)) return false ; // se lavorazione vuota, esco if ( m_nPockets == 0) { m_pMchMgr->SetWarning( 2452, "Warning in Pocketing : No machinable pocket") ; return true ; } // imposto eventuale asse bloccato da lavorazione 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( 2423, "Error in Pocketing : axes values not calculable") ; else m_pMchMgr->SetLastError( 2424, "Error in Pocketing : outstroke ") ; return false ; } // gestione movimenti all'inizio di ogni singolo percorso di lavorazione e alla fine della lavorazione if ( ! AdjustStartEndMovements()) { string sInfo = m_pMchMgr->GetOutstrokeInfo() ; if ( sInfo.empty()) m_pMchMgr->SetLastError( 2425, "Error in Pocketing : link movements not calculable") ; else m_pMchMgr->SetLastError( 2426, "Error in Pocketing : link outstroke ") ; return false ; } // assegno estremi degli assi dei vari percorsi di lavorazione e della lavorazione nel suo complesso CalcAndSetAxesBBox() ; // esecuzione eventuali personalizzazioni string sErr ; if ( bPostApply && ! PostApply( sErr)) { if ( ! IsEmptyOrSpaces( sErr)) m_pMchMgr->SetLastError( 2427, sErr) ; else m_pMchMgr->SetLastError( 2427, "Error in Pocketing : post apply not calculable") ; return false ; } return true ; } //---------------------------------------------------------------------------- bool Pocketing::GetParam( int nType, bool& bVal) const { switch ( nType) { case MPA_INVERT : bVal = m_Params.m_bInvert ; return true ; case MPA_TOOLINVERT : bVal = m_Params.m_bToolInvert ; return true ; } bVal = false ; return false ; } //---------------------------------------------------------------------------- bool Pocketing::GetParam( int nType, int& nVal) const { switch ( nType) { case MPA_TYPE : nVal = MT_POCKETING ; return true ; case MPA_LEADINTYPE : nVal = m_Params.m_nLeadInType ; return true ; case MPA_LEADOUTTYPE : nVal = m_Params.m_nLeadOutType ; return true ; case MPA_SCC : nVal = m_Params.m_nSolCh ; return true ; case MPA_SUBTYPE : nVal = m_Params.m_nSubType ; return true ; } nVal = 0 ; return false ; } //---------------------------------------------------------------------------- bool Pocketing::GetParam( int nType, double& dVal) const { switch ( nType) { case MPA_SPEED : dVal = GetSpeed() ; return true ; case MPA_FEED : dVal = GetFeed() ; return true ; case MPA_STARTFEED : dVal = GetStartFeed() ; return true ; case MPA_ENDFEED : dVal = GetEndFeed() ; return true ; case MPA_TIPFEED : dVal = GetTipFeed() ; return true ; case MPA_OFFSR : dVal = GetOffsR() ; return true ; case MPA_OFFSL : dVal = GetOffsL() ; return true ; case MPA_STARTPOS : dVal = m_Params.m_dStartPos ; return true ; case MPA_STEP : dVal = m_Params.m_dStep ; return true ; case MPA_SIDESTEP : dVal = m_Params.m_dSideStep ; return true ; case MPA_SIDEANGLE : dVal = m_Params.m_dSideAngle ; return true ; case MPA_LITANG : dVal = m_Params.m_dLiTang ; return true ; case MPA_LIELEV : dVal = m_Params.m_dLiElev ; return true ; case MPA_LOTANG : dVal = m_Params.m_dLoTang ; return true ; case MPA_EPICYCLESRAD : dVal = m_Params.m_dEpicyclesRad ; return true ; case MPA_EPICYCLESDIST : dVal = m_Params.m_dEpicyclesDist ; return true ; } dVal = 0 ; return false ; } //---------------------------------------------------------------------------- bool Pocketing::GetParam( int nType, string& sVal) const { switch ( nType) { case MPA_NAME : sVal = m_Params.m_sName ; return true ; case MPA_TOOL : sVal = m_Params.m_sToolName ; return true ; case MPA_DEPTH_STR : sVal = m_Params.m_sDepth ; return true ; case MPA_TUUID : sVal = ToString( m_Params.m_ToolUuid) ; return true ; case MPA_UUID : sVal = ToString( m_Params.m_Uuid) ; return true ; case MPA_SYSNOTES : sVal = m_Params.m_sSysNotes ; return true ; case MPA_USERNOTES : sVal = m_Params.m_sUserNotes ; return true ; case MPA_INITANGS : sVal = m_Params.m_sInitAngs ; return true ; case MPA_BLOCKEDAXIS : sVal = m_Params.m_sBlockedAxis ; return true ; } sVal = "" ; return false ; } //---------------------------------------------------------------------------- const ToolData& Pocketing::GetToolData( void) const { return m_TParams ; } //---------------------------------------------------------------------------- bool Pocketing::UpdateToolData( bool* pbChanged) { // recupero il gestore DB utensili della macchina corrente ToolsMgr* pTMgr = m_pMchMgr->GetCurrToolsMgr() ; if ( pTMgr == nullptr) return false ; // recupero l'utensile nel DB utensili const ToolData* pTdata = pTMgr->GetTool( m_Params.m_ToolUuid) ; if ( pTdata == nullptr) return false ; // 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 Pocketing : tool name changed (" + m_Params.m_sToolName + "->" + m_TParams.m_sName + ")" ; m_pMchMgr->SetWarning( 2453, sInfo) ; m_Params.m_sToolName = m_TParams.m_sName ; } if ( bChanged) { string sInfo = "Warning in Pocketing : tool data changed (" + m_Params.m_sToolName + ")" ; m_pMchMgr->SetWarning( 2454, sInfo) ; } // se definito parametro di ritorno, lo assegno if ( pbChanged != nullptr) *pbChanged = bChanged ; return true ; } //---------------------------------------------------------------------------- bool Pocketing::GetGeometry( SELVECTOR& vIds) const { // restituisco l'elenco delle entità vIds = m_vId ; return true ; } //---------------------------------------------------------------------------- bool Pocketing::VerifyGeometry( SelData Id, int& nSubs, int& nType) { // ammessi : curve, testi, facce di trimesh o regioni const IGeoObj* pGObj = m_pGeomDB->GetGeoObj( Id.nId) ; if ( pGObj == nullptr) return false ; // se ammesse curve ed è tale if ( ( nType == GEO_NONE || nType == GEO_CURVE) && ( pGObj->GetType() & GEO_CURVE) != 0) { nType = GEO_CURVE ; const ICurve* pCurve = nullptr ; // se direttamente la curva if ( Id.nSub == SEL_SUB_ALL) { pCurve = ::GetCurve( pGObj) ; if ( pCurve == nullptr) return false ; if ( pCurve->GetType() == CRV_COMPO) nSubs = ::GetCurveComposite( pCurve)->GetCurveCount() ; else nSubs = 0 ; } // altrimenti sottocurva di composita else { const ICurveComposite* pCompo = GetCurveComposite( pGObj) ; pCurve = ( pCompo != nullptr ? pCompo->GetCurve( Id.nSub) : nullptr) ; if ( pCurve == nullptr) return false ; nSubs = 0 ; } return true ; } // se altrimenti ammessi testi ed è tale else if ( ( nType == GEO_NONE || nType == EXT_TEXT) && pGObj->GetType() == EXT_TEXT) { nType = EXT_TEXT ; const IExtText* pText = ::GetExtText( pGObj) ; if ( pText == nullptr) return false ; nSubs = 0 ; return true ; } // se altrimenti ammesse superfici trimesh ed è tale else if ( ( nType == GEO_NONE || nType == SRF_TRIMESH) && pGObj->GetType() == SRF_TRIMESH) { nType = SRF_TRIMESH ; const ISurfTriMesh* pSurf = ::GetSurfTriMesh( pGObj) ; if ( pSurf == nullptr) return false ; // se direttamente la superficie if ( Id.nSub == SEL_SUB_ALL) { // deve avere una sola faccia if ( pSurf->GetFacetCount() != 1) return false ; nSubs = 1 ; } // altrimenti faccia di superficie trimesh else { // se faccia non esistente if ( Id.nSub >= pSurf->GetFacetCount()) return false ; nSubs = 0 ; } return true ; } // se altrimenti ammesse regioni ed è tale else if ( ( nType == GEO_NONE || nType == SRF_FLATRGN) && pGObj->GetType() == SRF_FLATRGN) { nType = SRF_FLATRGN ; const ISurfFlatRegion* pReg = ::GetSurfFlatRegion( pGObj) ; if ( pReg == nullptr) return false ; // se direttamente la regione if ( Id.nSub == SEL_SUB_ALL) { nSubs = pReg->GetChunkCount() ; } // altrimenti chunk di regione else { // se chunk non esistente if ( Id.nSub >= pReg->GetChunkCount()) return false ; // tutto bene nSubs = 0 ; } return true ; } // altrimenti errore else return false ; } //---------------------------------------------------------------------------- bool Pocketing::GetCurves( SelData Id, ICURVEPLIST& lstPC) { // ammessi : curve, testi, facce di trimesh o regioni const IGeoObj* pGObj = m_pGeomDB->GetGeoObj( Id.nId) ; if ( pGObj == nullptr) return false ; // ne recupero il riferimento globale Frame3d frGlob ; if ( ! m_pGeomDB->GetGlobFrame( Id.nId, frGlob)) return false ; // se curva if (( pGObj->GetType() & GEO_CURVE) != 0) { PtrOwner pCurve ; // se direttamente curva if ( Id.nSub == SEL_SUB_ALL) { // recupero la curva const ICurve* pOriCurve = ::GetCurve( pGObj) ; if ( pOriCurve == nullptr) return false ; PtrOwner pOriCurveCompo( CreateCurveComposite()) ; pOriCurveCompo->AddCurve( pOriCurve->Clone()) ; double dThick ; pOriCurve->GetThickness( dThick) ; Vector3d vtExtr ; pOriCurve->GetExtrusion( vtExtr) ; pOriCurveCompo->SetExtrusion( vtExtr) ; pOriCurveCompo->SetThickness( dThick) ; pCurve.Set( pOriCurveCompo) ; // recupero eventuali informazioni per lati aperti SetCurveAllTempProp( Id.nId, pCurve) ; // se estrusione mancante, imposto default if ( ! pCurve->GetExtrusion( vtExtr) || vtExtr.IsSmall()) pCurve->SetExtrusion( Z_AX) ; } // altrimenti sottocurva di composita else { // recupero la composita const ICurveComposite* pCompo = GetCurveComposite( pGObj) ; if ( pCompo == nullptr) return false ; // recupero la curva semplice const ICurve* pOriCurve = ::GetCurve( pCompo->GetCurve( Id.nSub)) ; if ( pOriCurve == nullptr) return false ; // la duplico pCurve.Set( pOriCurve->Clone()) ; // reset proprietà temporanee ResetCurveAllTempProp( pCurve) ; // recupero estrusione e spessore Vector3d vtExtr ; if ( ! pCompo->GetExtrusion( vtExtr) || vtExtr.IsSmall()) vtExtr = Z_AX ; pCurve->SetExtrusion( vtExtr) ; double dThick ; if ( pCompo->GetThickness( dThick)) pCurve->SetThickness( dThick) ; } if ( IsNull( pCurve)) return false ; // la porto in globale pCurve->ToGlob( frGlob) ; // salvo come TmpProp0 -> l'id della curva pCurve->SetTempProp( Id.nId, 0) ; // salvo come TmpProp0 -> -1 ( non ho lati adiacenti) pCurve->SetTempProp( 1, -1) ; // la restituisco lstPC.emplace_back( Release( pCurve)) ; return true ; } // se altrimenti testo else if ( pGObj->GetType() == EXT_TEXT) { // recupero il testo const IExtText* pText = ::GetExtText( pGObj) ; if ( pText == nullptr) return false ; // recupero l'outline del testo if ( ! pText->GetOutline( lstPC)) return false ; // reset proprietà temporanee ( nProp0 = 0, nProp1 = -1) for ( auto pCrv : lstPC) ResetCurveAllTempProp( pCrv) ; // porto le curve in globale for ( auto pCrv : lstPC) pCrv->ToGlob( frGlob) ; // salvo come TmpProp0 -> l'id della superificie ( per ogni loop ) // salvo come TmpProp1 -> -1 ( non ho lati adiacenti) for ( auto pCrv : lstPC) { pCrv->SetTempProp( Id.nId, 0) ; pCrv->SetTempProp( -1, 1) ; } // ritorno return true ; } // se altrimenti superficie else if ( pGObj->GetType() == SRF_TRIMESH) { // recupero la trimesh const ISurfTriMesh* pSurf = ::GetSurfTriMesh( pGObj) ; if ( pSurf == nullptr) return false ; // recupero l'indice della faccia int nFacet = ( ( Id.nSub == SEL_SUB_ALL) ? 0 : Id.nSub) ; // recupero i contorni della faccia POLYLINEVECTOR vPL ; pSurf->GetFacetLoops( nFacet, vPL) ; if ( vPL.empty()) return false ; // recupero la normale esterna della faccia Vector3d vtN ; if ( ! pSurf->GetFacetNormal( nFacet, vtN)) return false ; // creo la curva a partire dei loop for ( int i = 0 ; i < int( vPL.size()) ; i++) { PtrOwner pCrvCompo( CreateCurveComposite()) ; pCrvCompo->FromPolyLine( vPL[i]) ; if ( ! pCrvCompo->IsValid()) return false ; // reset delle proprietà temporanee ResetCurveAllTempProp( pCrvCompo) ; // determino eventuali lati aperti e aggiorno proprietà del contorno int nInd = 0 ; double dPar ; bool bFound = vPL[i].GetFirstU( dPar, true) ; while ( bFound) { // recupero il flag int nFlag = int( dPar) ; // se non c'è nulla di adiacente, lato aperto if ( nFlag == SVT_NULL) pCrvCompo->SetCurveTempProp( nInd, 1) ; // altrimenti verifico se la faccia adiacente forma diedro convesso o concavo else { bool bAdjac ; Point3d ptP1, ptP2 ; double dAng ; if ( ! pSurf->GetFacetsContact( nFacet, nFlag, bAdjac, ptP1, ptP2, dAng)) dAng = - ANG_RIGHT ; if ( dAng > - EPS_ANG_SMALL) pCrvCompo->SetCurveTempProp( nInd, 1) ; else // salvo come prop 1 la faccia adiacente pCrvCompo->SetCurveTempProp( nInd, nFlag, 1) ; } // passo al successivo ++nInd ; bFound = vPL[i].GetNextU( dPar, true) ; } // assegno l'estrusione dalla normale alla faccia pCrvCompo->SetExtrusion( vtN) ; // --------------------------------- Proiezioni lati adiacenti -------------------------------------- // 1) Creo una regione piana dalla curva esterna PtrOwner pSrfpCompo( CreateSurfFlatRegion()) ; if ( IsNull( pSrfpCompo)) return false ; pSrfpCompo->AddExtLoop( pCrvCompo->Clone()) ; if ( IsNull( pSrfpCompo) || pSrfpCompo->GetChunkCount() == 0) return false ; bool bIspCompoMod = false ; INTVECTOR vBannedId{ -1, nFacet} ; // 2) scorro tutte le curve del bordo esterno for ( int j = 0 ; j < pCrvCompo->GetCurveCount() ; ++ j) { int nProp = 0 ; // 3) controllo che nella seconda temp prop ho una faccia adiancente non già considerata da un altro bordo // e creo un vettore con gli Id delle facce del bordo laterale adiacente alla curva j della pCrvCompo if ( pCrvCompo->GetCurveTempProp( j, nProp, 1) && nProp != -1 //-> se la curva j ha una faccia adiacente... && find( vBannedId.begin(), vBannedId.end(), nProp) == vBannedId.end() //-> ...non già considerata da altre curve... && GetSurfByAdj( pSurf, vBannedId, nProp)) { //-> ...e riesco a ricavare tutte le facce del bordo // 4) creo una regione piana con tutte le facce proiettate contenute PtrOwner pSfrProj( CreateSurfFlatRegion()) ; if ( ! IsNull( pSfrProj) && ProjectEdgesOnSelFace( pSrfpCompo, pSurf, vBannedId, nFacet, pSfrProj)) { // sto modificando le singole superifici, quindi superificie del bordo esterno e superificie delle isole if ( i == 0) { if ( ! pSrfpCompo->Subtract( *pSfrProj)) return false ; } else { if ( ! pSrfpCompo->Add( *pSfrProj)) return false ; } bIspCompoMod = true ; } } } // Ho creato una nuova FlatRegion. // *** Se la curva originale è quella esterna -> tolgo le proiezioni ( non devo passare con il tool in quelle aree ) // *** Se la curva originale è quella di un'isola -> aggiungo le proiezioni ( così estraendo poi la curva mi trovo // con un'isola più grande, comprendendo quindi le parti proiettare dove il tool non può passare ) // se questa nuova superificie è modificata rispetto a quella selezionata, devo aggiornare le curve, con quelle // della nuova FlatRegion if ( bIspCompoMod) { // scorro ora il bordo della mia superificie if( pSrfpCompo->GetChunkCount() == 0) return false ; PtrOwner pCrvBorder( GetCurveComposite( pSrfpCompo->GetLoop( 0, 0))) ; if ( IsNull( pCrvBorder) || pCrvBorder->GetCurveCount() == 0) return false ; for ( int c = 0 ; c < pCrvBorder->GetCurveCount() ; ++ c) { int nStat = 0 ; if ( ! SetTmpPropByOverlap( pCrvBorder, c, pCrvCompo, nStat)) return false ; if ( nStat == 0 || nStat == 2) { // se non c'è overlap o geometria complessa pCrvBorder->SetCurveTempProp( c, 0, 0) ; // lato chiuso pCrvBorder->SetCurveTempProp( c, -1, 1) ; // lato esterno non definito } } // risetto le proprietà iniziali della curva pCrvCompo->Clear() ; pCrvCompo->AddCurve( Release( pCrvBorder)) ; } // ------------------------------------------------------------------------------------------ // assegno l'estrusione dalla normale alla faccia pCrvCompo->SetExtrusion( vtN) ; // porto la curva nel sistema di riferimento globale pCrvCompo->ToGlob( frGlob) ; // unisco le eventuali parti allineate ( mantenendo le proprietà ) pCrvCompo->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL, true, true) ; // sistemazioni varie AdjustCurveFromSurf( pCrvCompo, TOOL_ORTHO, FACE_CONT, 0) ; // salvo come TmpProp0 -> l'id della superificie pCrvCompo->SetTempProp( Id.nId, 0) ; // salvo come TmpProp1 -> il numero della faccia selezionata pCrvCompo->SetTempProp( nFacet, 1) ; // la restituisco lstPC.emplace_back( Release( pCrvCompo)) ; } return true ; } // se altrimenti regione else if ( pGObj->GetType() == SRF_FLATRGN) { // recupero la regione const ISurfFlatRegion* pReg = ::GetSurfFlatRegion( pGObj) ; if ( pReg == nullptr) return false ; // recupero la normale della regione Vector3d vtN = pReg->GetNormVersor() ; if ( vtN.IsSmall()) return false ; // determino intervallo di chunk int nCstart = 0 ; int nCend = pReg->GetChunkCount() ; if ( Id.nSub != SEL_SUB_ALL) { nCstart = Id.nSub ; nCend = nCstart + 1 ; } // ciclo sui chunk for ( int nC = nCstart ; nC < nCend ; ++ nC) { // recupero i contorni del chunk for ( int nL = 0 ; nL < pReg->GetLoopCount( nC) ; ++ nL) { PtrOwner pCrvCompo( CreateCurveComposite()) ; if ( IsNull( pCrvCompo) || ! pCrvCompo->AddCurve( pReg->GetLoop( nC, nL))) return false ; // reset proprietà temporanee ( per ogni sottocurva -> nProp0 = 0, nProp1 = -1) ResetCurveAllTempProp( pCrvCompo) ; // assegno l'estrusione dalla normale alla regione pCrvCompo->SetExtrusion( vtN) ; // unisco le eventuali parti allineate pCrvCompo->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL) ; // la porto in globale pCrvCompo->ToGlob( frGlob) ; // imposto come TmpProp0 -> l'id della superificie pCrvCompo->SetTempProp( Id.nId, 0) ; //imposto come TmpProp1 -> -1 ( non ho facce adiancenti ) pCrvCompo->SetTempProp( -1, 1) ; // sistemazioni varie AdjustCurveFromSurf( pCrvCompo, TOOL_ORTHO, FACE_CONT, 0) ; // la restituisco lstPC.emplace_back( Release( pCrvCompo)) ; } } return true ; } // altrimenti errore else return false ; } //---------------------------------------------------------------------------- bool Pocketing::SetCurveAllTempProp( int nCrvId, ICurve* pCurve) { if ( pCurve == nullptr) return false ; // reset proprietà temporanee ResetCurveAllTempProp( pCurve) ; // verifico se presenti info per lati aperti if ( ! m_pGeomDB->ExistsInfo( nCrvId, KEY_OPEN)) return true ; // recupero info sui lati aperti INTVECTOR vOpen ; m_pGeomDB->GetInfo( nCrvId, KEY_OPEN, vOpen) ; // se curva composita ICurveComposite* pCC = GetCurveComposite( pCurve) ; if ( pCC != nullptr) { for ( int j : vOpen) pCC->SetCurveTempProp( j, 1) ; } // altrimenti else { if ( ! vOpen.empty() && vOpen[0] == 0) pCurve->SetTempProp( 1) ; } return true ; } //---------------------------------------------------------------------------- bool Pocketing::ResetCurveAllTempProp( ICurve* pCurve) { if ( pCurve == nullptr) return false ; pCurve->SetTempProp( 0) ; ICurveComposite* pCC = GetCurveComposite( pCurve) ; if ( pCC != nullptr) { for ( int i = 0 ; i < pCC->GetCurveCount() ; ++ i) { pCC->SetCurveTempProp( i, 0, 0) ; pCC->SetCurveTempProp( i, -1, 1) ; } } return true ; } //---------------------------------------------------------------------------- bool Pocketing::Chain( int nGrpDestId) { // vettore puntatori alle curve ICURVEPOVECTOR vpCrvs ; vpCrvs.reserve( m_vId.size()) ; // vettore selettori delle curve originali SELVECTOR vInds ; // recupero tutte le curve e le porto in globale for ( const auto& Id : m_vId) { // prendo le curve ICURVEPLIST lstPC ; if ( ! GetCurves( Id, lstPC)) { string sInfo = "Warning in Pocketing : Skipped entity " + ToString( Id) ; m_pMchMgr->SetWarning( 2451, sInfo) ; } for ( auto pCrv : lstPC) { vpCrvs.emplace_back( pCrv) ; vInds.emplace_back( Id) ; } } // preparo i dati per il concatenamento bool bFirst = true ; Point3d ptNear = ORIG ; double dToler = 10 * EPS_SMALL ; ChainCurves chainC ; chainC.Init( true, dToler, int( vpCrvs.size())) ; for ( size_t i = 0 ; i < vpCrvs.size() ; ++ i) { // recupero la curva e il suo riferimento ICurve* pCrv = vpCrvs[i] ; if ( pCrv == nullptr) continue ; // recupero i dati della curva necessari al concatenamento e li assegno Point3d ptStart, ptEnd ; Vector3d vtStart, vtEnd ; if ( ! pCrv->GetStartPoint( ptStart) || ! pCrv->GetStartDir( vtStart) || ! pCrv->GetEndPoint( ptEnd) || ! pCrv->GetEndDir( vtEnd)) return false ; if ( ! chainC.AddCurve( int( i + 1), ptStart, vtStart, ptEnd, vtEnd)) return false ; // se prima curva, assegno inizio della ricerca if ( bFirst) { ptNear = ptStart + 10 * EPS_SMALL * vtStart ; bFirst = false ; } } // recupero i percorsi concatenati int nCount = 0 ; INTVECTOR vnId2 ; while ( chainC.GetChainFromNear( ptNear, false, vnId2)) { // creo una curva composita PtrOwner pCrvCompo( CreateCurveComposite()) ; if ( IsNull( pCrvCompo)) return false ; // estrusione e spessore Vector3d vtExtr = Z_AX ; double dThick = 0 ; // vettore Id originali SELVECTOR vId2 ; vId2.reserve( vnId2.size()) ; // recupero le curve semplici e le inserisco nella curva composita for ( size_t i = 0 ; i < vnId2.size() ; ++ i) { int nId = abs( vnId2[i]) - 1 ; bool bInvert = ( vnId2[i] < 0) ; vId2.emplace_back( vInds[nId]) ; // recupero la curva ICurve* pCrv = vpCrvs[nId] ; // se necessario, la inverto if ( bInvert) pCrv->Invert() ; // recupero eventuali estrusione e spessore Vector3d vtTemp ; if ( pCrv->GetExtrusion( vtTemp)) { vtExtr = vtTemp ; double dTemp ; if ( pCrv->GetThickness( dTemp) && abs( dTemp) > abs( dThick)) dThick = dTemp ; } // riporto le proprietà temporanee pCrvCompo->SetTempProp( vpCrvs[nId]->GetTempProp( 0), 0) ; pCrvCompo->SetTempProp( vpCrvs[nId]->GetTempProp( 1), 1) ; // la aggiungo alla curva composta if ( ! pCrvCompo->AddCurve( ::Release( vpCrvs[nId]), true, dToler)) return false ; } // se non sono state inserite curve, vado oltre if ( pCrvCompo->GetCurveCount() == 0) continue ; // imposto estrusione e spessore pCrvCompo->SetExtrusion( vtExtr) ; pCrvCompo->SetThickness( dThick) ; // aggiorno il nuovo punto vicino pCrvCompo->GetEndPoint( ptNear) ; // se utile, approssimo con archi if ( ! ApproxWithArcsIfUseful( pCrvCompo, true)) return false ; // recupero eventuali lati aperti INTVECTOR vOpen ; for ( int i = 0 ; i < int( pCrvCompo->GetCurveCount()) ; ++ i) { int nProp = 0 ; if ( pCrvCompo->GetCurveTempProp( i, nProp) && nProp == 1) vOpen.emplace_back( i) ; } // creo nuovo gruppo int nPathId = m_pGeomDB->AddGroup( GDB_ID_NULL, nGrpDestId, Frame3d()) ; if ( nPathId == GDB_ID_NULL) return false ; m_pGeomDB->SetName( nPathId, MCH_PATH + ToString( ++ nCount)) ; m_pGeomDB->SetInfo( nPathId, KEY_IDS, ToString( vId2)) ; // inserisco la curva composita nel gruppo destinazione int nNewId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nPathId, ::Release( pCrvCompo)) ; if ( nNewId == GDB_ID_NULL) return false ; // salvo info con eventuali lati aperti if ( ! vOpen.empty()) m_pGeomDB->SetInfo( nNewId, KEY_OPEN, vOpen) ; } return true ; } //---------------------------------------------------------------------------- bool Pocketing::ProcessPath( int nAuxId, int nPvId, int nClId) { // ========= GRUPPO TMP =================== // recupero gruppo per geometria temporanea ( Gruppo TMP ) 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 eventuale flag di lato aperto forzato fuori dal grezzo int nOpenOutRaw ; m_bOpenOutRaw = ( FromString( ExtractInfo(m_Params.m_sUserNotes, "OpenOutRaw="), nOpenOutRaw) && nOpenOutRaw != 0) ; // creo una superificie temporanea generata da tutte le curve ( curve modificate se valide ) SurfFlatRegionByContours SrfByC ; // superificie totale generata da tutte le curve concatenate Plane3d plAux ; bool bFirstPlane = true ; // piano Ausiliario per verificare che le curve siano complanari Vector3d vtExtr ; double dThick = -INFINITO ; // spessore più grande tra le curve int nPathId = m_pGeomDB->GetFirstGroupInGroup( nAuxId) ; // indici da associare alla SurfFlatRegion da svuotare : // Ogni curva che definirà un loop nella flat Region avrà la seguente struttura : // { nProp0, nProp1 } = { Id elemento selezionato, id faccia adiacente (solo per Trimesh) } // Per ogni curva di questi loop avrò : // { nProp0, nProp1 } = { (0 -> chiuso, 1 -> aperto) , id faccia adiacente ( solo per Trimesh )} int nProp0 = -1 ; int nProp1 = -1 ; while ( nPathId != GDB_ID_NULL) { // Scorro tutte le curve concatenate per creare la superficie da lavorare int nPi = m_pGeomDB->GetFirstInGroup( nPathId) ; const IGeoObj* pGObj = m_pGeomDB->GetGeoObj( nPi) ; if ( pGObj == nullptr) return false ; const ICurve* pOriCurve = ::GetCurve( pGObj) ; if ( pOriCurve == nullptr) return false ; PtrOwner pCompoOriCrv( GetCurveComposite( pOriCurve->Clone())) ; if ( IsNull( pCompoOriCrv)) return false ; // ricavo le proprietà della curva nProp0 = pCompoOriCrv->GetTempProp( 0) ; // id selezionato nProp1 = pCompoOriCrv->GetTempProp( 1) ; // lato adiancente per Trimesh bool bSomeOpen = m_pGeomDB->ExistsInfo( nPi, KEY_OPEN) ; if ( bSomeOpen) { int nOpen ; if ( FromString( ExtractInfo( m_Params.m_sUserNotes, "Open="), nOpen) && nOpen == 0) bSomeOpen = false ; } // annullo i flag di tratto aperto for ( int i = 0 ; i < int( pCompoOriCrv->GetCurveCount()) ; ++i) pCompoOriCrv->SetCurveTempProp( i, 0, 0) ; // alla sottocurva // aggiorno flag per lati aperti if ( bSomeOpen) { INTVECTOR vOpen ; m_pGeomDB->GetInfo( nPi, KEY_OPEN, vOpen) ; for ( int j : vOpen) pCompoOriCrv->SetCurveTempProp( j, 1, 0) ; // alla sottocurva } // unisco le parti allineate (tranne inizio-fine se chiusa) if ( ! pCompoOriCrv->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL, false, true)) return false ; // recupero estrusione e spessore Vector3d vtExtr_p = Z_AX ; pCompoOriCrv->GetExtrusion( vtExtr_p) ; double dThick_p ; pCompoOriCrv->GetThickness( dThick_p) ; // verifico sia piana e se necessario la appiattisco PtrOwner pFlatCrv( FlattenCurve( *pCompoOriCrv, 50 * EPS_SMALL, 50 * EPS_ANG_SMALL, FLTCRV_USE_EXTR)) ; if ( IsNull( pFlatCrv)) { Plane3d plPlane ; if ( ! pCompoOriCrv->IsFlat( plPlane, true, 50 * EPS_SMALL)) m_pMchMgr->SetLastError( 2403, "Error in Pocketing : Contour Not Flat") ; else m_pMchMgr->SetLastError( 2404, "Error in Pocketing : Tool Not Perpendicular to Flat Area") ; return false; } pFlatCrv->GetExtrusion( vtExtr_p) ; pCompoOriCrv->Clear() ; pCompoOriCrv->AddCurve( Release( pFlatCrv)) ; pCompoOriCrv->SetExtrusion( vtExtr_p) ; pCompoOriCrv->SetThickness( dThick_p) ; // setto come proprietà temperanea il suo Id pCompoOriCrv->SetTempProp( nProp0, 0) ; // a tutta la curva ( id selezionato ) pCompoOriCrv->SetTempProp( nProp1, 1) ; // a tutta la curva ( se Trimesh, faccia adiacente ) //int r = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCompoOriCrv->Clone()) ; //m_pGeomDB->SetMaterial( r, RED) ; // controllo che le curve siano complanari e con stessa estrusione (la prima come riferimento) Plane3d plAct ; pCompoOriCrv->IsFlat( plAct) ; if ( bFirstPlane) { plAux = plAct ; bFirstPlane = false ; pCompoOriCrv->GetThickness( dThick_p) ; dThick = dThick_p ; // prima come riferimento vtExtr = vtExtr_p ; // prima come riferimento SrfByC.AddCurve( pCompoOriCrv->Clone()) ; } else { Vector3d vtN1, vtN2 ; if ( abs( plAct.GetDist() - plAux.GetDist()) < 5 * EPS_SMALL && AreSameOrOppositeVectorApprox( plAct.GetVersN(), plAux.GetVersN()) // se stessa normale && AreSameVectorApprox( vtExtr, vtExtr_p)) { // se stessa estrusione PtrOwner pCrvProjected( ProjectCurveOnPlane( *pCompoOriCrv, plAux)) ; pCrvProjected->SetExtrusion( vtExtr) ; // prendo Thickness Massima tra tutte le curve dei chunks double dCurrThick ; pCompoOriCrv->GetThickness( dCurrThick) ; if ( dCurrThick > dThick) dThick = dCurrThick ; pCrvProjected->SetThickness( dCurrThick) ; SrfByC.AddCurve( pCrvProjected->Clone()) ; } } nPathId = m_pGeomDB->GetNextGroup( nPathId) ; // aggiorno il PathId con il successivo nel gruppo } // creazione della superficie da lavorare completa ( dall'unione di tutte le curve concatenate) PtrOwner pSrfPock( SrfByC.GetSurf()) ; if ( IsNull( pSrfPock) || pSrfPock->GetChunkCount() == 0) return false ; // normale della superifice finale || extrusione prima curva selezionata if ( AreOppositeVectorApprox( vtExtr, pSrfPock->GetNormVersor())) pSrfPock->Invert() ; if ( m_Params.m_bToolInvert) { // eventuale inversione direzione utensile vtExtr.Invert() ; pSrfPock->Invert() ; dThick = -dThick ; } // recupero il box del grezzo in globale BBox3d b3Raw ; BBox3d b3Chunk ; pSrfPock->GetBBox( GLOB_FRM, b3Chunk) ; if ( ! GetRawGlobBox( m_nPhase, b3Chunk, 0.5 * m_TParams.m_dTDiam, b3Raw) || b3Raw.IsEmpty()) { m_pMchMgr->SetLastError( 2405, "Error in Pocketing : Empty RawBox") ; return false ; } // recupero distanza da fondo dei grezzi interessati dal percorso double dRbDist = 0 ; double dAllRbDist = 0 ; if ( AreSameVectorApprox( vtExtr, Z_AX)) { if ( ! GetDistanceFromRawBottom( m_nPhase, b3Chunk, m_TParams.m_dTDiam, dRbDist, dAllRbDist)) return false ; } // valuto l'espressione dell'affondamento ExeLuaSetGlobNumVar( "TH", abs( dThick)) ; ExeLuaSetGlobNumVar( "RB", dRbDist) ; double dDepth ; string sMyDepth = m_Params.m_sDepth ; if ( ! ExeLuaEvalNumExpr( ToUpper( sMyDepth), &dDepth)) { m_pMchMgr->SetLastError( 2406, "Error in Pocketing : Depth not computable") ; return false ; } // se spessore positivo, lo sottraggo dal risultato if ( dThick > 0) dDepth -= dThick ; // sottraggo eventuale offset longitudinale dDepth -= GetOffsL() ; // assegno il versore fresa Vector3d vtTool = vtExtr ; m_bAggrBottom = false ; // calcolo l'elevazione massima double dElev = -INFINITO ; for ( int c = 0; c < pSrfPock->GetChunkCount() ; c++) { double dCurrElev ; PtrOwner pCvrCompo( GetCurveComposite( pSrfPock->GetLoop( c,0))) ; if ( CalcRegionElevation( pCvrCompo, vtTool, dDepth, 0.5 * m_TParams.m_dDiam, dCurrElev)) { if ( dCurrElev < EPS_SMALL && AreSameVectorApprox( vtExtr, Z_AX)) { BBox3d b3Crv ; pSrfPock->GetLoop( c, 0)->GetLocalBBox( b3Crv) ; dCurrElev = max( 0., b3Raw.GetMax().z - b3Crv.GetMin().z + min(0., dThick) + dDepth) ; } if ( dCurrElev > dElev) dElev = dCurrElev ; } else return false ; } // eventuale imposizione massima elevazione da note utente double dMaxElev ; if ( FromString( ExtractInfo( m_Params.m_sUserNotes, "MaxElev="), dMaxElev) && dElev > dMaxElev) dElev = dMaxElev ; // verifico che lo step dell'utensile sia sensato double dOkStep = ( m_Params.m_dStep > EPS_SMALL ? m_Params.m_dStep + EPS_SMALL : 0) ; const double MIN_ZSTEP = 1.0 ; if ( dOkStep >= EPS_SMALL && dOkStep < MIN_ZSTEP) { dOkStep = MIN_ZSTEP + EPS_SMALL ; string sInfo = "Warning in Pocketing : machining step too small (" + ToString( m_Params.m_dStep, 2) + ")" ; m_pMchMgr->SetWarning( 2456, sInfo) ; } // verifico che il massimo materiale dell'utensile sia sensato const double MIN_MAXMAT = 1.0 ; if ( m_TParams.m_dMaxMat < dElev && m_TParams.m_dMaxMat < MIN_MAXMAT) { string sInfo = "Error in Pocketing : Tool MaxMaterial too small (" + ToString(m_TParams.m_dMaxMat, 2) + ")" ; m_pMchMgr->SetLastError( 2422, sInfo) ; return false ; } // verifico di non superare il massimo materiale // se lo step supera la capacità dell'utensile if ( m_Params.m_dStep > m_TParams.m_dMaxMat + EPS_SMALL) { dOkStep = m_TParams.m_dMaxMat + EPS_SMALL ; string sInfo = "Warning in Pocketing : machining step (" + ToString( m_Params.m_dStep, 1) + ") bigger than MaxMaterial (" + ToString( m_TParams.m_dMaxMat, 1) + ")" ; m_pMchMgr->SetWarning( 2457, sInfo) ; } // se lavorazione singola if ( dOkStep < EPS_SMALL || dOkStep > dElev) { // se l'elevazione supera la capacità dell'utensile if ( dElev > m_TParams.m_dMaxMat + EPS_SMALL ) { string sInfo = "Warning in Pocketing : machining depth (" + ToString(dElev, 1) + ") bigger than MaxMaterial (" + ToString( m_TParams.m_dMaxMat, 1) + ")" ; m_pMchMgr->SetWarning( 2458, sInfo) ; dDepth -= dElev - m_TParams.m_dMaxMat ; dElev = m_TParams.m_dMaxMat ; } } // altrimenti lavorazione a step else { // se l'elevazione supera il massimo affondamento dell'utensile double dSafe = m_pMchMgr->GetCurrMachiningsMgr()->GetMaxDepthSafe() ; double dMaxDepth = m_TParams.m_dLen - ( m_TParams.m_dDiam > m_dTHoldDiam ? m_dTHoldBase : m_dTHoldLen) - dSafe ; if ( dElev > dMaxDepth + EPS_SMALL) { // segnalo, riduco e continuo string sInfo = "Warning in Pocketing : machining depth (" + ToString( dElev, 1) + ") bigger than MaxDepth (" + ToString( dMaxDepth, 1) + ")" ; m_pMchMgr->SetWarning( 2458, sInfo) ; dDepth -= dElev - dMaxDepth ; dElev = dMaxDepth ; } } // verifico se tavola basculante bool bTiltTab = false ; m_bTiltingTab = ( m_pMchMgr->GetCurrMachine()->GetCurrTableIsTilting( bTiltTab, m_vtTiltingAx) && bTiltTab) ; // verifico se testa da sopra (Z+) m_bAboveHead = m_pMchMgr->GetHeadAbove( m_TParams.m_sHead) ; // verifiche per svuotature dal basso m_bAggrBottom = false ; if ( ! VerifyPathFromBottom( pSrfPock, vtTool)) { return false; } // recupero nome del path string sPathName = "P1" ; // recupero eventuale minima lunghezza di attacco su lato aperto FromString( ExtractInfo( m_Params.m_sUserNotes, "OpenMinSafe="), m_dOpenMinSafe) ; // se richiesta anteprima if ( nPvId != GDB_ID_NULL) { // creo gruppo per geometria di lavorazione del percorso int nPxId = m_pGeomDB->AddGroup( GDB_ID_NULL, nPvId, Frame3d()) ; if ( nPxId == GDB_ID_NULL) return false ; m_pGeomDB->SetName( nPxId, sPathName) ; m_pGeomDB->SetMaterial( nPxId, GREEN) ; // creo l'anteprima del percorso if ( ! GeneratePocketingPv( nPxId, pSrfPock)) return false ; } // se richiesta lavorazione if ( nClId != GDB_ID_NULL) { // creo gruppo per geometria di lavorazione del percorso int nPxId = m_pGeomDB->AddGroup( GDB_ID_NULL, nClId, Frame3d()) ; if ( nPxId == GDB_ID_NULL) return false ; m_pGeomDB->SetName( nPxId, sPathName) ; m_pGeomDB->SetMaterial( nPxId, BLUE) ; // verifico se archi vanno approssimati con segmenti di retta int nSplitArcs = m_pMchMgr->GetCurrMachiningsMgr()->GetSplitArcs() ; bool bSplitArcs = ( nSplitArcs == SPLAR_ALWAYS || ( nSplitArcs == SPLAR_NO_XY_PLANE && !vtExtr.IsZplus()) || ( nSplitArcs == SPLAR_GEN_PLANE && vtExtr.IsGeneric())) ; // assegno il vettore estrazione al gruppo del percorso m_pGeomDB->SetInfo( nPxId, KEY_EXTR, vtTool) ; // assegno l'elevazione massima m_pGeomDB->SetInfo( nPxId, KEY_ELEV, dElev) ; // Imposto dati comuni SetPathId( nPxId) ; SetToolDir( vtTool) ; // Eseguo la lavorazione della superificie finale switch ( m_Params.m_nSubType) { case POCKET_SUB_ZIGZAG: if ( ! AddZigZag( pSrfPock, vtTool, vtExtr, dDepth, dElev, dOkStep, bSplitArcs)) return false ; break ; case POCKET_SUB_ONEWAY: if ( ! AddOneWay( pSrfPock, vtTool, vtExtr, dDepth, dElev, dOkStep, bSplitArcs)) return false ; break ; case POCKET_SUB_SPIRALIN: if ( ! AddSpiralIn( pSrfPock, vtTool, vtExtr, dDepth, dElev, dOkStep, bSplitArcs)) return false ; break ; case POCKET_SUB_SPIRALOUT: if ( ! AddSpiralOut( pSrfPock, vtTool, vtExtr, dDepth, dElev, dOkStep, bSplitArcs)) return false ; break ; } } m_nPockets++ ; return true ; } //---------------------------------------------------------------------------- bool Pocketing::CalcRegionElevation( const ICurveComposite* pCompo, const Vector3d& vtTool, double dDepth, double dRad, double& dElev) const { // inizializzo l'elevazione dElev = 0 ; // affondamento come vettore Vector3d vtDepth = vtTool * dDepth ; // Campiono il contorno int nMaxInd = pCompo->GetCurveCount() - 1 ; for ( int i = 0 ; i <= nMaxInd ; ++ i) { // curva corrente const ICurve* pCrvC = pCompo->GetCurve( i) ; Point3d ptStart ; pCrvC->GetStartPoint( ptStart) ; Point3d ptMid ; pCrvC->GetMidPoint( ptMid) ; Point3d ptEnd ; pCrvC->GetEndPoint( ptEnd) ; // elevazione della curva double dCurrElev ; if ( GetElevation( m_nPhase, ptStart - vtDepth, ptMid - vtDepth, ptEnd - vtDepth, vtTool, dCurrElev)) { if ( dCurrElev > dElev) dElev = dCurrElev ; } else { m_pMchMgr->SetLastError( 2408, "Error in Pocketing : Entity GetElevation") ; return false ; } } // Campiono l'interno con una griglia (uso linee parallele a X) // determino il riferimento di base Frame3d frPocket ; Point3d ptCen ; pCompo->GetCentroid( ptCen) ; frPocket.Set( ptCen, vtTool) ; // copio il contorno e lo porto nel riferimento PtrOwner pCompoL( pCompo->Clone()) ; if ( IsNull( pCompoL) || ! pCompoL->ToLoc( frPocket)) { m_pMchMgr->SetLastError( 2408, "Error in Pocketing : Entity GetElevation") ; return false ; } // ingombro del contorno in locale BBox3d b3Pocket ; pCompoL->GetLocalBBox( b3Pocket) ; Point3d ptMin ; double dDimX, dDimY, dDimZ ; b3Pocket.GetMinDim( ptMin, dDimX, dDimY, dDimZ) ; // passi in Y const double STEP = 50 ; int nYStep = max( int( ceil( ( dDimY - 20 * EPS_SMALL) / STEP)), 2) ; double dYStep = ( nYStep > 0 ? ( dDimY - 20 * EPS_SMALL) / nYStep : 0) ; // calcolo le linee di svuotatura for ( int i = 1 ; i < nYStep ; ++ i) { // definisco la linea PtrOwner pLine( CreateCurveLine()) ; const double EXP_LEN = 1.0 ; Point3d ptStart( ptMin.x - EXP_LEN, ptMin.y + 10 * EPS_SMALL + i * dYStep, ptMin.z + dDimZ) ; if ( IsNull( pLine) || ! pLine->SetPVL( ptStart, X_AX, dDimX + 2 * EXP_LEN)) { m_pMchMgr->SetLastError( 2408, "Error in Pocketing : Entity GetElevation") ; return false ; } // calcolo la classificazione della curva rispetto al contorno IntersCurveCurve intCC( *pLine, *pCompoL) ; CRVCVECTOR ccClass ; if ( intCC.GetCurveClassification( 0, EPS_SMALL, ccClass)) { // determino gli intervalli di curva interni Intervals inOk ; for ( auto& ccOne : ccClass) { if ( ccOne.nClass == CRVC_IN) { Point3d ptStart ; pLine->GetPointD1D2( ccOne.dParS, ICurve::FROM_PLUS, ptStart) ; ptStart.ToGlob( frPocket) ; Point3d ptEnd ; pLine->GetPointD1D2( ccOne.dParE, ICurve::FROM_MINUS, ptEnd) ; ptEnd.ToGlob( frPocket) ; // elevazione della curva double dCurrElev ; if ( GetElevation( m_nPhase, ptStart - vtDepth, ptEnd - vtDepth, vtTool, dCurrElev)) { if ( dCurrElev > dElev) dElev = dCurrElev ; } else { m_pMchMgr->SetLastError( 2408, "Error in Pocketing : Entity GetElevation") ; return false ; } } } } // altrimenti uso tutta la curva else { Point3d ptStart ; pLine->GetStartPoint( ptStart) ; ptStart.ToGlob( frPocket) ; Point3d ptEnd ; pLine->GetEndPoint( ptEnd) ; ptEnd.ToGlob( frPocket) ; // elevazione della curva double dCurrElev ; if ( GetElevation( m_nPhase, ptStart - vtDepth, ptEnd - vtDepth, vtTool, dCurrElev)) { if ( dCurrElev > dElev) dElev = dCurrElev ; } else { m_pMchMgr->SetLastError( 2408, "Error in Pocketing : Entity GetElevation") ; return false ; } } } return true ; } //---------------------------------------------------------------------------- bool Pocketing::VerifyPathFromBottom( const ISurfFlatRegion* pSrfPock, const Vector3d& vtTool) { // se non è svuotatura dal basso in alto, esco if ( vtTool.z > MIN_ZDIR_TOP_TOOL) return true ; // se c'è testa non dall'alto o tavola basculante, esco if ( ! m_bAboveHead || m_bTiltingTab) return true ; // recupero dati di eventuale rinvio da sotto if ( ! GetAggrBottomData( m_TParams.m_sHead, m_AggrBottom) || m_AggrBottom.nType == 0) { m_pMchMgr->SetLastError( 2409, "Error in Pocketing : missing aggregate from bottom") ; return false ; } // calcolo il minimo della massima distanza del percorso dal contorno del grezzo double dMinDist = INFINITO ; Vector3d vtMinDir ; VCT3DVECTOR vDir ; for ( int c = 0 ; c < pSrfPock->GetChunkCount() ; c++) { for ( int l = 0 ; l < pSrfPock->GetLoopCount( c) ; l++) { PtrOwner pCompo( GetCurveComposite( pSrfPock->GetLoop( c, l))) ; if ( IsNull( pCompo)) return false ; double dParS, dParE ; pCompo->GetDomain( dParS, dParE) ; for ( double dPar = dParS ; dPar < dParE + EPS_PARAM ; dPar += 0.5) { // distanza minima del punto e relativa direzione dal contorno del grezzo Point3d ptP ; double dCurrDist = INFINITO ; Vector3d vtCurrDir ; if ( pCompo->GetPointD1D2( dPar, ICurve::FROM_MINUS, ptP) && GetMinDistanceFromRawSide( m_nPhase, ptP, 0, m_AggrBottom.vtMDir, MCH_AGB_DELTAMAX_MDIR, dCurrDist, vtCurrDir) && ! vtCurrDir.IsSmallXY()) { if ( dCurrDist < dMinDist - 10 * EPS_SMALL && find_if( vDir.begin(), vDir.end(), [&]( const Vector3d& vtV) { return vtCurrDir * vtV > cos(15 * DEGTORAD); }) == vDir.end()) { // inserisco la direzione tra quelle già esplorate vDir.emplace_back( vtCurrDir) ; // determino la distanza di tutti gli altri punti dal contorno del grezzo lungo questa direzione for ( double dPar2 = dParS; dPar2 < dParE + EPS_PARAM; dPar2 += 0.5) { if ( abs( dPar2 - dPar) > EPS_PARAM) { Point3d ptQ ; double dQDist ; if ( pCompo->GetPointD1D2( dPar2, ICurve::FROM_MINUS, ptQ) && GetDistanceFromRawSide( m_nPhase, ptQ, vtCurrDir, dQDist) && dQDist > dCurrDist) dCurrDist = dQDist ; } } // se la massima distanza trovata è inferiore al minimo, lo aggiorno if ( dCurrDist < dMinDist) { dMinDist = dCurrDist ; vtMinDir = vtCurrDir ; } } } } } } // se supera il limite, errore if ( dMinDist > m_AggrBottom.dDMax) { m_pMchMgr->SetLastError( 2410, "Error in Pocketing : path too far from part sides") ; return false ; } // assegno direzione di accesso e segnalo utilizzo aggregato da sotto m_vtAggrBottom = vtMinDir ; m_bAggrBottom = true ; return true ; } //---------------------------------------------------------------------------- bool Pocketing::GeneratePocketingPv( int nPathId, const ISurfFlatRegion* pSrfPock) { // creo copia della curva composita PtrOwner pSfr( CloneSurfFlatRegion( pSrfPock)) ; if ( IsNull( pSfr)) return false ; // ne recupero il contorno PtrOwner< ICurve> pCrv2 ; pCrv2.Set( pSfr->GetLoop( 0, 0)) ; if ( IsNull( pCrv2)) return false ; // inserisco la curva nel DB int nC2Id = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nPathId, Release( pCrv2)) ; if ( nC2Id == GDB_ID_NULL) return false ; // assegno nome e colore m_pGeomDB->SetName( nC2Id, MCH_PV_CUT) ; m_pGeomDB->SetMaterial( nC2Id, RED) ; // eventuali altri contorni ( interni di contornatura chiusa) const int MAX_INT_LOOP = 1000 ; for ( int i = 1 ; i <= MAX_INT_LOOP ; ++i) { PtrOwner< ICurve> pCrv3 ; pCrv3.Set( pSfr->GetLoop( 0, i)) ; if ( IsNull( pCrv3)) break ; // inserisco la curva nel DB int nC3Id = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nPathId, Release( pCrv3)) ; if ( nC3Id == GDB_ID_NULL) return false ; // assegno nome e colore m_pGeomDB->SetName( nC3Id, MCH_PV_CUT) ; m_pGeomDB->SetMaterial( nC3Id, RED) ; } // inserisco la regione nel DB int nRId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nPathId, Release( pSfr)) ; if ( nRId == GDB_ID_NULL) return false ; m_pGeomDB->SetName( nRId, MCH_PV_RCUT) ; m_pGeomDB->SetMaterial( nRId, Color( 255, 0, 0, 60)) ; // la copio anche come regione ridotta int nRrId = m_pGeomDB->Copy( nRId, GDB_ID_NULL, nPathId) ; if ( nRrId == GDB_ID_NULL) return false ; m_pGeomDB->SetName( nRrId, MCH_PV_RRCUT) ; m_pGeomDB->SetMaterial( nRrId, INVISIBLE) ; return true ; } //---------------------------------------------------------------------------- static double GetCurveRadius( const ICurve* pCrv) { if ( pCrv == nullptr) return 0.0 ; BBox3d b3Loc ; if ( ! pCrv->GetLocalBBox( b3Loc, BBF_EXACT)) return 0.0 ; double dRad ; if ( ! b3Loc.GetRadius( dRad)) return 0.0 ; return dRad ; } //---------------------------------------------------------------------------- bool Pocketing::AddZigZag( const ISurfFlatRegion* pSrfPock, const Vector3d& vtTool, const Vector3d& vtExtr, double dDepth, double dElev, double dOkStep, bool bSplitArcs ) { // recupero distanze di sicurezza double dSafeZ = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeZ() ; double dSafeAggrBottZ = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeAggrBottZ() ; // lunghezza di approccio/retrazione double dAppr = m_Params.m_dStartPos ; // determino numero e affondamento degli step int nStep = 1 ; nStep = max( 1, static_cast( ceil( dElev / dOkStep))) ; double dStep = dElev / nStep ; // raggio utensile double dTRad = m_TParams.m_dDiam / 2 ; // Offset della regione per curva ZigZag double dOffs = dTRad + GetOffsR() ; double dExtra = (( m_TParams.m_nType != TT_MILL_POLISHING) ? min( 0.1 * m_TParams.m_dDiam, 2.0) : 0) ; int nChunks = 0 ; // indica il numero di Chunk che ottengo effettuando l'offset per i percorsi a ZigZag for( int c = 0 ; c < pSrfPock->GetChunkCount() ; ++ c) { // copio il chunk c-esimo PtrOwner pSrfChunk(( pSrfPock->CloneChunk( c))) ; if ( IsNull( pSrfChunk)) return false ; // -------------------------------------------------------------------------------------------------------- // 1) traslo il chunk c-esimo a seconda dello step e salvo la flat Region interna al grezzo // ( evito di lavorare nel vuoto sempre la stessa faccia ) // 2) Proietto il Box del grezzo del semipiano positivo definito della Flat Region ottenuta in precedenza // allargando in tangenza i lati chiusi fino al bordo di tale proiezione // ( evito di trascurare parti di grezzo nella tasche con normale non parallela alla faccia del grezzo ) ISURFFRPOVECTOR vSrfSliced( nStep) ; vector vCrvOEWithFlags( nStep) ; BOOLVECTOR vbChangedPrec( nStep, false) ; // modifico le superifici in base alla geometria del grezzo if ( ! GetParamsAtEachStep( vSrfSliced, vCrvOEWithFlags, vbChangedPrec, pSrfChunk, nStep, vtTool, dElev, dDepth, dStep)) return false ; // ciclo su tutti gli step for( int j = 1 ; j <= nStep ; ++j) { // se superificie non valida, salto allo step successivo if ( IsNull( vSrfSliced[ j-1]) || vSrfSliced[j-1]->GetChunkCount() == 0) { vSrfSliced[j-1].Set( pSrfChunk->Clone()) ; continue ; } // la superificie che lavoro è quella ottenuta in precedenza allo step j-esimo PtrOwner pSrfFinal( CloneSurfFlatRegion( vSrfSliced[j - 1])) ; if ( IsNull( pSrfFinal)) return false ; // ciclo su tutti i chunk della superificie per lo step j-esimo for( int cc = 0 ; cc < vSrfSliced[j-1]->GetChunkCount() ; ++cc) { // copio il Chunk (c)-esimo allo step (j)-esimo PtrOwner pSrfChunkFinal(( vSrfSliced[j-1]->CloneChunk( cc))) ; if ( IsNull( pSrfChunkFinal)) return false ; // superficie per ingressi ed uscite PtrOwner pSrfLeanInOut( CloneSurfFlatRegion( pSrfChunkFinal)) ; if( IsNull( pSrfLeanInOut)) return false ; // ---------------------------------------------------------------------------------- // Dopo che il chunk c-esimo è stato intersecato con il grezzo e allargato grazie alla proiezione, // salvo il bordo ( con i flag dei lati aperti ) per il caso del trapezio ottimizzato. // tuttavia, nel caso di più Chunks, devo individuare la curva originaria relativa al chunk cc-esimo // ... il chunk cc-esimo non può avere parti esterne alla sua curva originaria int nInd = 0 ; // indice del vettore delle curve esterne relativo al chunk cc-esimo // cerco la curva originale del chunk cc-esimo if(( int)vCrvOEWithFlags[j-1].size() == 1) nInd = 0 ; else { for( int k = 0 ; k < ( int)vCrvOEWithFlags[j-1].size() ; ++k) { CRVCVECTOR ccClass ; if( pSrfChunkFinal->GetCurveClassification( *vCrvOEWithFlags[j-1][k], EPS_SMALL, ccClass)) { bool bIsThis = true ; for( int kk = 0 ; kk < ( int)ccClass.size() && bIsThis ; ++kk) { if( ccClass[kk].nClass == CRVC_OUT) bIsThis = false ; } if( bIsThis) { nInd = k ; break ; } } } } // ------------------------------------------------------------------------------------ // determino il riferimento in base alla svuotatura ( per poter orientare il frame per m_dSideAngle ) Frame3d frPocket ; Point3d ptCen ; pSrfChunkFinal->GetCentroid( ptCen) ; frPocket.Set( ptCen, vtExtr) ; frPocket.Rotate( ptCen, vtExtr, m_Params.m_dSideAngle) ; // frame originario ( il frame frPocket viene modificato dalla Optmized ZigZag per orientare le // passate a seconda di some sono disposti i lati aperti) Frame3d frPocketOriByOpt ; frPocketOriByOpt.Set( frPocket.Orig(), frPocket.VersX(), frPocket.VersY(), frPocket.VersZ()) ; // porto la superificie nel nuovo sistema di riferimento pSrfChunkFinal->ToLoc( frPocket) ; // verifico se si tratta di caso ottimizzato bool bOptimizedZigZag = false ; bool bOutRawLeadIn = false ; ICRVCOMPOPOVECTOR vpCrvs ; // vettore con i paths a ZigZag per il Chunk (c)-esimo allo step (j)-esimo double dOptZigZagOffs ; if ( ! OptimizedZigZag( pSrfChunkFinal, vtTool, dDepth, dSafeZ, frPocket, vCrvOEWithFlags[j-1][nInd], bOptimizedZigZag, vpCrvs, dOptZigZagOffs)) return false ; if ( bOptimizedZigZag && ! vpCrvs.empty()) { // se sono in un caso ottimizzato ... nChunks = 1 ; // fisso il numero di chunk ad 1 per i bordi esterni ( che non verranno percorsi ) // verifico se attacco fuori dal grezzo Point3d ptStart ; vpCrvs[0]->GetStartPoint( ptStart) ; Vector3d vtDir ; vpCrvs[0]->GetStartDir( vtDir) ; ptStart += -vtDir * ( m_TParams.m_dDiam / 2 - dOptZigZagOffs + dSafeZ) ; ptStart.ToGlob( frPocket) ; ptStart += -vtTool * dDepth ; // controllo l'elevazione double dTestElev ; if ( ! GetElevation( m_nPhase, ptStart, vtTool, m_TParams.m_dDiam / 2, vtTool, dTestElev) || dTestElev < EPS_SMALL) bOutRawLeadIn = true ; // sistemo attacco ( per essere completamente fuori dal grezzo) if ( bOutRawLeadIn || m_bOpenOutRaw) vpCrvs[0]->ExtendStartByLen( m_TParams.m_dDiam / 2 - dOptZigZagOffs + dSafeZ) ; } // se non sono nel caso ottimizzato e ho un utensile che non lavora di testa // poichè ingresso non fuori dal pezzo ... -> errore if (( ! bOptimizedZigZag || ! ( bOutRawLeadIn || m_bOpenOutRaw)) && m_TParams.m_nType == TT_MILL_NOTIP) { if ( ! LeadInRawIsOk()) { m_pMchMgr->SetLastError( 2431, "Error in Pocketing : LeadIn with Mill NoTip in material") ; return false ; } } // se non sono nel caso ottimizzato, effettuo il primo Offset della regione e controllo quanti Chunks ottengo... // l'Offset contiene una quantità Extra, per stare leggermente più staccato dal bordo PtrOwner pSrfZigZag( CloneSurfFlatRegion( pSrfChunkFinal)) ; if ( ! bOptimizedZigZag) { if ( ! pSrfZigZag->Offset( - dOffs - dExtra, ICurve::OFF_FILLET)) { m_pMchMgr->SetLastError( 2412, "Error in Pocketing : Offset not computable") ; return false ; } nChunks = pSrfZigZag->GetChunkCount() ; // facendo il primo Offset il Chunk (c)-esimo può generare altri Chunks... } // effettuo un secondo Offset per ottenere le curve di contorno per ripulire la svuotatura a ZigZag // Questo offset serve per ricavare le curve che l'utensile dovrà percorrere dopo aver svuotato a ZigZag // Curva esterna ( non percorsa nel caso a ZigZag ) // Curve interne ( le isole, queste vanno percorse anche nei casi ottimizzati ) // Per le curve interne, questo Offset viene sempre fatto ( a prescindere dai casi ottimizzati ) PtrOwner pSrfForCrv( CloneSurfFlatRegion( pSrfChunkFinal)) ; if ( ! pSrfForCrv->Offset( - dOffs, ICurve::OFF_FILLET)) { m_pMchMgr->SetLastError( 2412, "Error in Pocketing : Offset not computable") ; return false ; } // memorizzo il numero di Chunks che ottengo effettuando Quest'ultimo Offset int nChunksForCrv = pSrfForCrv->GetChunkCount() ; // Avendo effettuato due Offsets ( -dOffs-dExtra e -dOffs ) non è detto che il numero di Chunks tra le nuove // superifici sia uguale... Inizio a scorre i chunks della superficie per le curve di contorno e, // per ognuna di esse, cerco il/i Chunck per il percorso a ZigZag contenuti. for ( int cfc = 0 ; cfc < nChunksForCrv ; ++ cfc) { // scorro i chunk della superificie per i bordi for ( int cfz = 0 ; cfz < nChunks ; ++ cfz) { // scorro i chunk della superificie per i percorsi ZigZag // Se sono in un caso ottimizzato, ho già ottenuto il percorso a ZigZag, quindi non devo calcolare nulla // Se invece non sono nel caso ottimizzato if ( ! bOptimizedZigZag) { // e la regione è dentro al Chunk per i contorni if ( pSrfZigZag->GetChunkSimpleClassification( cfz, *pSrfForCrv, cfc) == REGC_IN1) { // svuoto il vettore delle curve ( potrebbe essere riempito dal percorso precedente vpCrvs.clear() ; // Calcolo il percorso a ZigZag PtrOwner pSrfZigZagChunk( pSrfZigZag->CloneChunk( cfz)) ; if ( ! CalcZigZag( pSrfZigZagChunk, vpCrvs)) return false ; } // se la regione non è dentro alla curva esterna allora la ignoro // ( la ritroverò interna ad un'altra curva per i bordi successivamante o l'ho già considerata in precedenza ) else continue ; } // se lucidatura if ( m_TParams.m_nType == TT_MILL_POLISHING) { // ciclo sui percorsi for ( int k = 0 ; k < int( vpCrvs.size()) ; ++k) { // se attacco a scivolo if ( GetLeadInType() == POCKET_LI_GLIDE) { double dU; vpCrvs[k]->GetParamAtLength( m_Params.m_dLiTang, dU) ; vpCrvs[k]->AddJoint( dU) ; Point3d ptStart ; vpCrvs[k]->GetStartPoint( ptStart) ; vpCrvs[k]->ModifyStart( ptStart + vtTool * m_Params.m_dLiElev) ; } // se uscita a scivolo if ( GetLeadOutType() == POCKET_LO_GLIDE) { double dLen, dU ; vpCrvs[k]->GetLength( dLen) ; vpCrvs[k]->GetParamAtLength(dLen - m_Params.m_dLoTang, dU) ; vpCrvs[k]->AddJoint( dU) ; Point3d ptEnd ; vpCrvs[k]->GetEndPoint( ptEnd) ; vpCrvs[k]->ModifyEnd( ptEnd + vtTool * m_Params.m_dLiElev) ; } } } // ---------------------------- Disegno le curve a ZigZag (vpCrv) ------------------------- bool bStart = true ; // ciclo sui percorsi int nPath = int( vpCrvs.size()); for ( int k = 0 ; k < nPath ; ++ k) { // ciclo sulle curve elementari int nMaxInd = vpCrvs[k]->GetCurveCount() - 1 ; for ( int i = 0 ; i <= nMaxInd ; ++ i) { // curva corrente const ICurve* pCrvC = vpCrvs[k]->GetCurve( i) ; // copio la curva nel frame e nello step richiesto PtrOwner pCurve( pCrvC->Clone()) ; if ( IsNull( pCurve)) return false; pCurve->ToGlob( frPocket) ; pCurve->Translate( - vtTool * ( dDepth - dElev + j * dStep)) ; // --- se PRIMA ENTITA' --- if ( i == 0) { // dati inizio entità Point3d ptStart ; pCurve->GetStartPoint( ptStart) ; Vector3d vtStart ; pCurve->GetStartDir( vtStart) ; // determino inizio attacco Point3d ptP1 ; if ( ! CalcLeadInStart( ptStart, vtStart, vtExtr, nullptr, ptP1)) return false ; // determino elevazione su inizio attacco double dStElev ; if ( ! GetElevation( m_nPhase, ptStart - 10 * EPS_SMALL * vtTool, vtTool, GetRadiusForStartEndElevation(), vtTool, dStElev)) dStElev = j * dStep ; bool bAhUnderRaw = m_bAboveHead && ! m_bAggrBottom && ! m_bTiltingTab && GetAhPointUnderRaw( ptP1, vtTool, 0, GetRadiusForStartEndElevation(), m_TParams.m_dLen, false, dSafeZ, vtTool, dStElev) ; bool bUhAboveRaw = ! m_bAboveHead && GetUhPointAboveRaw( ptP1, vtTool, 0, GetRadiusForStartEndElevation(), m_TParams.m_dLen, false, dSafeZ, vtTool, dStElev) ; //if ( bAhUnderRaw || bUhAboveRaw) dStElev = max( dStElev, j * dStep) ; dStElev -= ( ptP1 - ptStart) * vtExtr ; // se ottimizzata e attacco nel grezzo if ( bOptimizedZigZag && !( bOutRawLeadIn || m_bOpenOutRaw)) { // se richiesto attacco a zigzag o a spirale, l'elevazione va nell'attacco if ( GetLeadInType() == POCKET_LI_ZIGZAG || GetLeadInType() == POCKET_LI_HELIX) { ptP1 += vtExtr * dStElev ; dStElev = 0 ; } } Vector3d vtDirS, vtDirE ; vpCrvs[0]->GetStartDir( vtDirS) ; vpCrvs.back()->GetEndDir( vtDirE) ; if ( nStep > 1 && j > 1 && AreOppositeVectorApprox( vtDirS, vtDirE) && bOutRawLeadIn && ( int)vpCrvs.size() == 1 && bOptimizedZigZag) { dStElev = 0 ; ptP1 = ptStart ; } // se inizio, approccio globale al punto iniziale if ( bStart) { //if ( k == 0 && j > 1 && vbChangedPrec[j-1]) // dStElev -= ( j-1) * dStep ; if ( ! AddApproach( ptP1, vtTool, dSafeZ, dSafeAggrBottZ, dStElev, dAppr, bOutRawLeadIn || m_bOpenOutRaw)) { m_pMchMgr->SetLastError( 2414, "Error in Pocketing : Approach not computable") ; return false ; } bStart = false ; } // altrimenti, approccio di collegamento else { if ( ! ( nStep > 1 && j > 1 && AreOppositeVectorApprox( vtDirS, vtDirE) && bOutRawLeadIn && ( int)vpCrvs.size() == 1 && bOptimizedZigZag)) { if ( ! AddLinkApproach( ptP1, vtTool, dSafeZ, dSafeAggrBottZ, dStElev, dAppr, bOutRawLeadIn || m_bOpenOutRaw)) { m_pMchMgr->SetLastError( 2418, "Error in Pocketing : Link not computable") ; return false; } } } // aggiungo attacco SetFeed( GetStartFeed()) ; //GetCurrPos( ptP1) ; // <----- ???? if ( ! AddLeadIn( ptP1, ptStart, vtStart, vtExtr, pSrfLeanInOut, nullptr, !m_Params.m_bInvert, bSplitArcs, bOutRawLeadIn || m_bOpenOutRaw)) { m_pMchMgr->SetLastError( 2415, "Error in Pocketing : LeadIn not computable") ; return false ; } } // elaborazioni sulla curva corrente double dMinFeed = GetFeed() * GetSideStep() / m_TParams.m_dDiam ; double dFeed = pCurve->GetTempProp( 0) / FEED_DIVISOR < dMinFeed - 50 * EPS_SMALL ? GetFeed() : pCurve->GetTempProp( 0) / FEED_DIVISOR ; SetFeed( dFeed) ; DrawColoredCrvForFeedTest( pCurve, dFeed) ; if ( pCurve->GetType() == CRV_LINE) { ICurveLine* pLine = GetCurveLine( pCurve) ; Point3d ptP3 = pLine->GetEnd() ; //SetFeed( GetFeed()) ; if ( AddLinearMove( ptP3) == GDB_ID_NULL) return false ; } else if ( pCurve->GetType() == CRV_ARC) { ICurveArc* pArc = GetCurveArc( pCurve) ; Point3d ptCen = pArc->GetCenter() ; double dAngCen = pArc->GetAngCenter() ; Vector3d vtN = pArc->GetNormVersor() ; Point3d ptP3 ; pArc->GetEndPoint(ptP3) ; //SetFeed( GetFeed()) ; if ( AddArcMove( ptP3, ptCen, dAngCen, vtN) == GDB_ID_NULL) return false ; } // --- se ULTIMA ENTITA' --- if ( i == nMaxInd) { // per caso ottimizzato -------------- Vector3d vtDirS, vtDirE ; vpCrvs[0]->GetStartDir( vtDirS) ; vpCrvs.back()->GetEndDir( vtDirE) ; if( nStep > 1 && j < nStep && AreOppositeVectorApprox( vtDirS, vtDirE) && bOutRawLeadIn && ( int)vpCrvs.size() == 1 && bOptimizedZigZag) continue ; // ----------------------------------- // dati fine entità Point3d ptEnd ; pCurve->GetEndPoint( ptEnd) ; Vector3d vtEnd ; pCurve->GetEndDir( vtEnd) ; // aggiungo uscita double dEndElev ; if ( ! GetElevation( m_nPhase, ptEnd - 10 * EPS_SMALL * vtTool, vtTool, GetRadiusForStartEndElevation(), vtTool, dEndElev)) dEndElev = j * dStep ; dEndElev = max( dEndElev, j * dStep) ; Point3d ptP1 ; SetFeed( GetEndFeed()) ; if ( ! AddLeadOut( ptEnd, vtEnd, vtExtr, nullptr, bSplitArcs, true, ptP1, dEndElev, false)) { m_pMchMgr->SetLastError( 2416, "Error in Pocketing : LeadOut not computable") ; return false ; } //dEndElev = max( dEndElev, j * dStep) ; // se lucidatura o caso ottimizzato e ultimo percorso di ultimo step, aggiungo retrazione if (( m_TParams.m_nType == TT_MILL_POLISHING || bOptimizedZigZag) && k == nPath - 1 && j == nStep) { if ( ! AddRetract( ptP1, vtTool, dSafeZ, dSafeAggrBottZ, dEndElev, dAppr)) { m_pMchMgr->SetLastError( 2418, "Error in Pocketing : Retract not computable") ; return false ; } } // altrimenti, aggiungo retrazione di collegamento else { if ( ! AddLinkRetract( ptP1, vtTool, dSafeZ, dSafeAggrBottZ, dEndElev, dAppr)) { m_pMchMgr->SetLastError( 2418, "Error in Pocketing : Link not computable") ; return false ; } } } } } } // ------------------------------------------------------------------------------ // se lucidatura non aggiungo contorno if ( m_TParams.m_nType == TT_MILL_POLISHING) continue ; // Una volta percorse le curve di ZigZag devo aggiungere le curve per il bordo // creo un vettore con tutti i loop formati, aggiustando i loro punti iniziali e portandoli nel frame della svuotatura // NB. se sono in un caso ottimizzato uso solo i loop interni ICRVCOMPOPOVECTOR vAllCrv ; for ( int l = bOptimizedZigZag ? 1 : 0 ; l < pSrfForCrv->GetLoopCount( cfc) ; ++ l) { vAllCrv.emplace_back( GetCurveComposite( pSrfForCrv->GetLoop( cfc, l))) ; } // Sistemo i punti iniziali per i nuovi Chunks ------------------------------------------ VCT3DVECTOR vVtMidOut(( int) vAllCrv.size(), V_NULL) ; BOOLVECTOR vbMidOut(( int) vAllCrv.size(), false) ; PNTVECTOR vPtStart(( int) vAllCrv.size(), Point3d( 0,0,0)) ; BOOLVECTOR vbForcedOutStart(( int) vAllCrv.size(), false) ; // se sono in un caso ottimizzato e non ho isole non ho bisogno di fare nulla... if ( ! ( bOptimizedZigZag && ( int)vAllCrv.size() == 0)) { // ... altrimenti // scorro tutte le curve da percorrere e calcolo gli ingressi... for ( int u = 0 ; u < ( int)vAllCrv.size() ; ++u) { // per ogni curva di bordo... bool bOutTmp = false ; if( ! SetBetterPtStartForSubChunks( vAllCrv[u], pSrfChunkFinal, vPtStart[u], vVtMidOut[u], bOutTmp, dOffs)) return false ; vbMidOut[u] = bOutTmp ; // vector::reference da Bit a Bool // riporto i valori nel sistema di riferimento corretto vPtStart[u].ToGlob( bOptimizedZigZag ? frPocketOriByOpt : frPocket) ; vVtMidOut[u].ToGlob( bOptimizedZigZag ? frPocketOriByOpt : frPocket) ; vAllCrv[u]->ToGlob( bOptimizedZigZag ? frPocketOriByOpt : frPocket) ; // se richiesto, la inverto if ( m_Params.m_bInvert) vAllCrv[u]->Invert() ; // setto la Feed per la curva di contorno AssignFeedForEdgeCleaning( vAllCrv[u], vCrvOEWithFlags[j-1], nInd) ; // se la curva è valida per entrata da fuori, aggiungo un piccolo tratto lineare if ( vbMidOut[u]) { // calcolo il punto fuori Point3d ptOut = vPtStart[u] + vVtMidOut[u] * ( 0.5 * m_TParams.m_dDiam + dSafeZ) ; ptOut.Translate( - vtTool * ( dDepth - dElev + j * dStep)) ; double dStElev ; bool bOutStart = ( ! GetElevation( m_nPhase, ptOut, vtTool, 0.5 * m_TParams.m_dDiam, vtTool, dStElev) || dStElev < EPS_SMALL); if ( bOutStart || m_bOpenOutRaw) { // aggiungo alla curva il tratto lineare ptOut.Translate( vtTool * ( dDepth - dElev + j * dStep)) ; vAllCrv[u]->AddLine( ptOut, false) ; AssignFeedForLineInOut( vAllCrv[u], true) ; } // verifico se ingresso da considerare fuori grezzo anche se dentro vbForcedOutStart[u] = ( vbMidOut[u] && m_bOpenOutRaw) ; // se utensile che non lavora di testa e ingresso non fuori dal pezzo, errore if ( m_TParams.m_nType == TT_MILL_NOTIP && !bOutStart && ! vbForcedOutStart[u]) { if ( ! LeadInRawIsOk()) { m_pMchMgr->SetLastError( 2431, "Error in Pocketing : LeadIn with Mill NoTip in material") ; return false; } } } } // guardo il punto finale in cui si trova la fresa dopo al percorso a ZigZag // e le riordino le curve ( e i relativi vettori ) in base alla vicinanza // ( piccola ottimizzazione per l'ordine dei percorsi sui bordi ) Point3d ptEnd ; if ( vpCrvs.size() > 0) vpCrvs.back()->GetEndPoint( ptEnd) ; if ( ! OrderCurvesByLastPntOfPath( vAllCrv, ptEnd, vPtStart, vVtMidOut, vbMidOut, vbForcedOutStart)) return false ; } // ------------------------------------------------------------------------------- // ---------------------------- Disegno le curve di contorno ---------------------- for ( int u = 0 ; u < int( vAllCrv.size()) ; ++ u) { // percorro tutte le curve ( ordinate ) // recupero la prima curva di offset disponibile PtrOwner pOffs( CreateCurveComposite()); if ( IsNull( pOffs) || ! pOffs->AddCurve( vAllCrv[u]->Clone())) { m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ; return false ; } // aggiungo la lavorazione di questa curva Point3d ptP1 ; // ciclo sulle curve elementari int nMaxInd = pOffs->GetCurveCount() - 1 ; for ( int i = 0 ; i <= nMaxInd ; ++i) { // curva corrente const ICurve* pCrvC = pOffs->GetCurve( i) ; // copio la curva PtrOwner pCurve( pCrvC->Clone()) ; if ( IsNull( pCurve)) return false ; // copio la curva nel frame e nello step richiesto pCurve->Translate( -vtTool * ( dDepth - dElev + j * dStep)) ; // --- se PRIMA ENTITA' --- if ( i == 0) { // dati inizio entità Point3d ptStart ; Vector3d vtStart ; pCurve->GetStartPoint( ptStart) ; pCurve->GetStartDir( vtStart) ; Point3d ptForElev = ptStart ; if ( vbMidOut[u] || vbForcedOutStart[u]) pCurve->GetEndPoint( ptForElev) ; // se primo step, approccio e affondo //if ( true || j == 1 || vbChangedPrec[j-1] || vSrfSliced[j-2]->GetChunkCount() > 1) { // determino inizio attacco if ( ! CalcLeadInStart( ptStart, vtStart, vtExtr, nullptr, ptP1)) return false ; // determino elevazione su inizio attacco double dStElev ; if ( ! GetElevation( m_nPhase, ptStart - 10 * EPS_SMALL * vtTool, vtTool, GetRadiusForStartEndElevation(), vtTool, dStElev)) dStElev = j * dStep ; bool bAhUnderRaw = m_bAboveHead && ! m_bAggrBottom && ! m_bTiltingTab && GetAhPointUnderRaw( ptP1, vtTool, 0, GetRadiusForStartEndElevation(), m_TParams.m_dLen, false, dSafeZ, vtTool, dStElev) ; bool bUhAboveRaw = ! m_bAboveHead && GetUhPointAboveRaw( ptP1, vtTool, 0, GetRadiusForStartEndElevation(), m_TParams.m_dLen, false, dSafeZ, vtTool, dStElev) ; //if ( bAhUnderRaw || bUhAboveRaw) dStElev = max( dStElev, j * dStep) ; dStElev -= ( ptP1 - ptStart) * vtExtr ; // se attacco a zigzag o a spirale o a scivolo, l'elevazione va nell'attacco if ( GetLeadInType() == POCKET_LI_ZIGZAG || GetLeadInType() == POCKET_LI_HELIX || GetLeadInType() == POCKET_LI_GLIDE) { ptP1 += vtExtr * dStElev; dStElev = 0 ; } // approccio al punto iniziale if ( ! AddLinkApproach( ptP1, vtTool, dSafeZ, dSafeAggrBottZ, dStElev, dAppr, vbMidOut[u] || vbForcedOutStart[u])) { m_pMchMgr->SetLastError( 2418, "Error in Pocketing : Link not computable") ; return false ; } // aggiungo attacco SetFeed( GetStartFeed()) ; if ( ! AddLeadIn( ptP1, ptStart, vtStart, vtExtr, pSrfLeanInOut, nullptr, !m_Params.m_bInvert, bSplitArcs, vbMidOut[u] || vbForcedOutStart[u])) { m_pMchMgr->SetLastError(2415, "Error in Pocketing : LeadIn not computable"); return false; } //} // altrimenti solo collegamento //else { // SetFeed( GetStartFeed()) ; // GetCurrPos( ptP1) ; // if ( ! AddLeadIn( ptP1, ptStart, vtStart, vtExtr, pSrfLeanInOut, nullptr, !m_Params.m_bInvert, bSplitArcs)) { // m_pMchMgr->SetLastError(2418, "Error in Pocketing : Link not computable") ; // return false; // } //} } // elaborazioni sulla curva corrente double dMinFeed = GetFeed() * GetSideStep() / m_TParams.m_dDiam ; double dFeed = pCurve->GetTempProp( 0) / FEED_DIVISOR < dMinFeed - 50 * EPS_SMALL ? GetFeed() : pCurve->GetTempProp( 0) / FEED_DIVISOR ; DrawColoredCrvForFeedTest( pCurve, dFeed) ; SetFeed( dFeed) ; if ( pCurve->GetType() == CRV_LINE) { ICurveLine* pLine( GetCurveLine( pCurve)) ; Point3d ptP3 = pLine->GetEnd() ; //SetFeed( GetFeed()) ; if ( AddLinearMove( ptP3) == GDB_ID_NULL) return false ; } else if ( pCurve->GetType() == CRV_ARC) { ICurveArc* pArc( GetCurveArc( pCurve)) ; Point3d ptCen = pArc->GetCenter() ; double dAngCen = pArc->GetAngCenter() ; Vector3d vtN = pArc->GetNormVersor() ; Point3d ptP3 ; pArc->GetEndPoint( ptP3) ; //SetFeed( GetFeed()); if ( AddArcMove( ptP3, ptCen, dAngCen, vtN) == GDB_ID_NULL) return false ; } // se ultima entità if ( i == nMaxInd) { // se ultimo step, uscita e retrazione di collegamento //if ( j == nStep) { // dati fine entità Point3d ptEnd ; pCurve->GetEndPoint( ptEnd) ; Vector3d vtEnd ; pCurve->GetEndDir( vtEnd) ; // aggiungo uscita double dEndElev ; if ( ! GetElevation( m_nPhase, ptEnd - 10 * EPS_SMALL * vtTool, vtTool, GetRadiusForStartEndElevation(), vtTool, dEndElev)) dEndElev = dStep ; dEndElev = max( dEndElev, j * dStep) ; SetFeed( GetEndFeed()) ; if ( ! AddLeadOut( ptEnd, vtEnd, vtExtr, nullptr, bSplitArcs, false, ptP1, dEndElev, ( u == ( int)vAllCrv.size()))) { m_pMchMgr->SetLastError( 2416, "Error in Pocketing : LeadOut not computable") ; return false ; } // se ci sono ancora curve, aggiungo retrazione di collegamento if ( pOffs->GetCurveCount() > 0) { if ( ! AddLinkRetract( ptP1, vtTool, dSafeZ, dSafeAggrBottZ, dEndElev, dAppr)) { m_pMchMgr->SetLastError( 2418, "Error in Pocketing : Link not computable") ; return false ; } } // altrimenti retrazione finale else { if ( ! AddRetract( ptP1, vtTool, dSafeZ, dSafeAggrBottZ, dEndElev, dAppr)) { m_pMchMgr->SetLastError( 2418, "Error in Pocketing : Retract not computable") ; return false ; } } //} } } } // -------------------------------------------------------------------------------- } // chiusura ciclo sui chunk cfc della superificie con Offset per contorni } // chiusura ciclo sui chunk della superificie tagliata con il grezzo } // chiusura ciclo sugli step } // chiusura ciclo sui chunks return true ; } //---------------------------------------------------------------------------- bool Pocketing::CalcZigZag( const ISurfFlatRegion* pSrfZigZag, ICRVCOMPOPOVECTOR& vpCrvs) { // check parametri if ( pSrfZigZag == nullptr) return true ; // creo il vettore dei contorni ICRVCOMPOPOVECTOR vFirstOff ; for ( int c = 0 ; c < pSrfZigZag->GetChunkCount() ; ++ c) { // sempre 1... for ( int l = 0 ; l < pSrfZigZag->GetLoopCount( c) ;++ l) { vFirstOff.emplace_back( GetCurveComposite( pSrfZigZag->GetLoop( c, l))) ; } } // ingombro del contorno offsettato BBox3d b3Pocket ; vFirstOff[0]->GetLocalBBox( b3Pocket) ; Point3d ptMin ; double dDimX, dDimY, dDimZ ; b3Pocket.GetMinDim( ptMin, dDimX, dDimY, dDimZ) ; // lunghezza del contorno offsettato double dLen ; vFirstOff[0]->GetLength( dLen) ; // passi in Y int nYStep = static_cast< int >( ceil(( dDimY - 30 * EPS_SMALL) / GetSideStep())) ; double dYStep = ( nYStep > 0 ? ( dDimY - 30 * EPS_SMALL) / nYStep : 0) ; int nRef = (( nYStep + ( m_Params.m_bInvert ? 0 : 1)) % 2) ; // tratto valido struct Section { bool bActive ; Point3d ptS ; Point3d ptE ; double dOs ; double dOe ; int nOffIndS ; int nOffIndE ; } ; struct ParIsland { double dU ; int nInd ; } ; // raccolta di tratti typedef vector> VECVECSECT ; VECVECSECT vvSec ; vvSec.resize( nYStep + 1) ; // calcolo le linee di svuotatura int nCount = 0 ; for ( int i = 0 ; i <= nYStep ; ++ i) { // determino senso bool bPlus = (( i % 2) == nRef) ; // definisco la linea PtrOwner pLine( CreateCurveLine()) ; const double EXP_LEN = 1.0 ; Point3d ptStart( ptMin.x - EXP_LEN, ptMin.y + 10 * EPS_SMALL + i * dYStep, ptMin.z + dDimZ) ; if ( IsNull( pLine) || ! pLine->SetPVL( ptStart, X_AX, dDimX + 2 * EXP_LEN)) { m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ; return false ; } if ( ! bPlus) pLine->Invert() ; // calcolo la classificazione della linea rispetto alla superificie CRVCVECTOR ccClass ; pSrfZigZag->GetCurveClassification( *pLine, EPS_SMALL, ccClass) ; for ( int j = 0 ; j < int( ccClass.size()) ; ++ j) { if ( ccClass[j].nClass == CRVC_IN) { // memorizzo il segmento Section currSec; currSec.bActive = true; PtrOwner pSeg( GetCurveLine( pLine->CopyParamRange( ccClass[j].dParS, ccClass[j].dParE))) ; Point3d ptS, ptE ; pSeg->GetStartPoint( ptS) ; pSeg->GetEndPoint( ptE) ; currSec.ptS = ptS ; currSec.ptE = ptE ; for ( int k = 0 ; k < int( vFirstOff.size()) ; ++ k) { if ( vFirstOff[k]->IsPointOn( ptS)) { currSec.nOffIndS = k ; double dUOS; vFirstOff[k]->GetParamAtPoint( ptS, dUOS) ; currSec.dOs = dUOS ; } if ( vFirstOff[k]->IsPointOn( ptE)){ currSec.nOffIndE = k ; double dUOE; vFirstOff[k]->GetParamAtPoint( ptE, dUOE) ; currSec.dOe = dUOE ; } } vvSec[i].emplace_back( currSec) ; ++nCount ; // numero di segmenti inseriti } } } int nStatus = 0 ; // 0 -> inizio oppure ho inserito una parte di isola | 2 -> sto inserendo un segmento Point3d ptS_ref ; PtrOwner pLastSeg( CreateCurveComposite()) ; // ultimo segmento nel percorso PtrOwner pCrvLink( CreateCurveComposite()) ; // ultimo link aggiunto // vettore dei link aggiunti ( per Feed ) ICRVCOMPOPOVECTOR vAddedLinks ; bool bFirstLine = true ; // flag per prima linea di ogni percorso // creo i percorsi di svuotatura vpCrvs.reserve( nCount) ; int nI = -1, nJ = -1 ; while ( true) { // se sezione non valida if ( nI < 0 || nJ < 0) { // ricerco la prima valida ( il primo segmento con bActive messo a true) for ( int k = 0 ; k < int( vvSec.size()) && nI < 0 ; ++ k) { for ( int l = 0 ; l < int( vvSec[k].size()) && nJ < 0 ; ++ l) { if ( vvSec[k][l].bActive) { nI = k ; nJ = l ; } } } // se trovata, creo nuova curva composita if ( nI >= 0 && nJ >= 0) { // creo la curva vpCrvs.emplace_back( CreateCurveComposite()) ; nStatus = 0 ; // aggiungo punto iniziale vpCrvs.back()->AddPoint( vvSec[nI][nJ].ptS) ; bFirstLine = true ; } // altrimenti, esco else break ; } // determino senso bool bPlus = (( nI % 2) == nRef) ; // aggiungo la sezione alla curva Section& Sec = vvSec[nI][nJ] ; Sec.bActive = false ; // creo i vettori con le linee Under e Above nella struttura della Section ICURVEPOVECTOR vLineAbove ; if ( nI < nYStep) { for ( int a = 0 ; a < ( int)vvSec[nI + 1].size() ; ++ a) { if ( vvSec[nI + 1][a].bActive) continue ; PtrOwner pLA( CreateCurveLine()) ; pLA->Set( vvSec[nI + 1][a].ptS, vvSec[nI + 1][a].ptE) ; vLineAbove.emplace_back( Release( pLA)) ; } } ICURVEPOVECTOR vLineUnder ; if ( nI > 0) { for ( int u = 0 ; u < ( int)vvSec[nI - 1].size() ; ++ u) { if ( vvSec[ nI - 1][u].bActive) continue ; PtrOwner pLU( CreateCurveLine()) ; pLU->Set( vvSec[nI - 1][u].ptS, vvSec[nI - 1][u].ptE) ; vLineUnder.emplace_back( Release( pLU)) ; } } // creo la linea come curva composita, aggiungerò dei Joint per ogni tratto con Feed differente PtrOwner pLineCompo( CreateCurveComposite()) ; if ( IsNull( pLineCompo)) return false ; Point3d ptE_l ; if ( bFirstLine) ptE_l = vvSec[nI][nJ].ptS ; else vpCrvs.back()->GetEndPoint( ptE_l) ; pLineCompo->AddPoint( ptE_l) ; pLineCompo->AddLine( vvSec[nI][nJ].ptE) ; if ( ! AssignFeedZigZagOneWay( pLineCompo, false, vLineAbove, vLineUnder, vAddedLinks)) // Assegno la Feed return false ; bFirstLine = false ; vpCrvs.back()->AddCurve( pLineCompo->Clone()) ; // aggiungo la curva al percorso if ( nStatus == 0) { // primo segmento per il raccordo smussato pLastSeg.Set( pLineCompo) ; pLastSeg->GetStartPoint( ptS_ref) ; } if ( nStatus == 2) { // ho precedentemente aggiunto il bordo di un'isola, quindi mi salvo il secondo segmento PtrOwner pSeg1( CloneCurveComposite( pLastSeg)) ; PtrOwner pSeg2( CloneCurveComposite( pLineCompo)) ; if ( ! CalcZigZagLink( pSeg1, pSeg2, pCrvLink)) return false ; // aggiorno il vettore delle curve ZigZag Point3d ptE_Seg1 ; pSeg1->GetEndPoint( ptE_Seg1) ; double dUS_Link = EPS_SMALL ; vpCrvs.back()->GetParamAtPoint( ptE_Seg1, dUS_Link) ; vpCrvs.back()->TrimEndAtParam( dUS_Link) ; //AssignFeedZigZagLink( pCrvLink) ; // assegno la Feed al Link if ( ! AssignFeedZigZagOneWay( pCrvLink, true, vLineAbove, vLineUnder, vAddedLinks)) return false ; vpCrvs.back()->AddCurve( pCrvLink->Clone()) ; // aggiungo il Link vpCrvs.back()->AddCurve( pSeg2->Clone()) ; // aggiungo pSeg2 // aggiorno il vettore dei Link ( nel caso sia un link tra due segmenti sullo stesso livello ) Point3d ptS1 ; pSeg1->GetStartPoint( ptS1) ; Point3d ptS2 ; pSeg2->GetStartPoint( ptS2) ; if ( abs( ptS1.y - ptS2.y) < 50 * EPS_SMALL) vAddedLinks.emplace_back( pCrvLink->Clone()) ; // pSeg2 ora diventa pSeg1 e il procedimento si itera per tutto il percorso pLastSeg.Set( Release( pSeg2)) ; } // cerco nella stessa fila o in quella successiva sezione successiva raccordabile tramite il contorno double dUstart = Sec.dOe ; int nIndexIslandE = Sec.nOffIndE ; // isola di arrivo double dUmin, dUmax ; vFirstOff[nIndexIslandE]->GetDomain( dUmin, dUmax) ; double dUspan = dUmax - dUmin ; double dUref = ( bPlus ? INFINITO : -INFINITO) ; int nNextI = -1 ; int nNextJ = -1 ; int li = nJ + 1 ; for ( int k = nI ; k <= nI + 1 && k < int( vvSec.size()) ; ++ k) { for ( int l = li ; l < int( vvSec[k].size()) ; ++ l) { if ( ! vvSec[k][l].bActive) // se sezione non attiva... non la considero continue ; if ( vvSec[k][l].nOffIndS != nIndexIslandE) // se isola diversa... non la considero continue ; double dU = vvSec[k][l].dOs ; if ( bPlus) { if ( dU < dUstart) dU += dUspan ; if ( dU < dUref) { dUref = dU ; nNextI = k ; nNextJ = l ; } } else { if ( dU > dUstart) dU -= dUspan ; if ( dU > dUref) { dUref = dU ; nNextI = k ; nNextJ = l ; } } } li = 0 ; } // se trovato, controllo il contorno dell'isola if ( nNextI != -1) { PtrOwner pCopy ; if ( bPlus) { if ( dUref > dUmax) dUref -= dUspan ; pCopy.Set( vFirstOff[nIndexIslandE]->CopyParamRange( dUstart, dUref)) ; if ( ! IsNull( pCopy)) { double dCLen ; pCopy->GetLength( dCLen) ; if ( dCLen > 0.5 * dLen) { pCopy.Set( vFirstOff[nIndexIslandE]->CopyParamRange( dUref, dUstart)) ; if ( ! IsNull( pCopy)) pCopy->Invert() ; } } } else { if ( dUref < dUmin) dUref += dUspan ; pCopy.Set( vFirstOff[nIndexIslandE]->CopyParamRange( dUref, dUstart)) ; if ( ! IsNull( pCopy)) { pCopy->Invert() ; double dCLen; pCopy->GetLength( dCLen) ; if ( dCLen > 0.5 * dLen) pCopy.Set( vFirstOff[nIndexIslandE]->CopyParamRange( dUstart, dUref)) ; } } // controllo che nel percorso scelto non ritorni indietro superando la precendete passata BBox3d b3Copy ; if ( ! IsNull( pCopy)) pCopy->GetLocalBBox( b3Copy) ; if ( ! b3Copy.IsEmpty() && ( b3Copy.GetMax().y - b3Copy.GetMin().y) < dYStep + 10 * EPS_SMALL) { // tengo la curva (non ritorno indietro più dello step) Point3d ptS, ptE ; pCrvLink->Clear() ; pCrvLink->AddCurve( pCopy->Clone()) ; vpCrvs.back()->AddCurve( Release( pCopy)) ; nStatus = 2 ; // aggiunta parte di isola // aggiungo il Link nI = nNextI ; nJ = nNextJ ; } else { nI = -1 ; nJ = -1 ; } } else { nI = -1 ; nJ = -1 ; } } return true ; } //---------------------------------------------------------- bool Pocketing::GetUnclearedRegion( ICRVCOMPOPOVECTOR& vFirstOffs, ICRVCOMPOPOVECTOR& vCrvs, ICURVEPOVECTOR& vLinks, const ICurveComposite* pCrv_orig, ISurfFlatRegion* pSrfToCut) { // controllo dei parametri if ( vFirstOffs.size() == 0 || ( int)vCrvs.size() < ( int)vFirstOffs.size()) return false ; pSrfToCut->Clear() ; // 1) creo la regione esterna PtrOwner pSrfExtern( CreateSurfFlatRegion()) ; if ( IsNull( pSrfExtern)) return false ; for ( int i = 0 ; i < int( vFirstOffs.size()) ; ++ i) { if ( i == 0) pSrfExtern->AddExtLoop( vFirstOffs[i]->Clone()) ; else { PtrOwner pCrvIntLoop( vFirstOffs[i]->Clone()) ; if( IsNull( pCrvIntLoop) || ! pCrvIntLoop->Invert() || ! pSrfExtern->AddIntLoop( pCrvIntLoop->Clone())) return false ; } } // ---- le seguenti regioni sono distinte per calcolar emeglio la Feed ---- // 2) Creo la regione svuotata dal Tool negli Offset, nei Links e sia dagli Offsets che dai Links PtrOwner pSrfTool_Offs( CreateSurfFlatRegion()) ; PtrOwner pSrfTool_Links( CreateSurfFlatRegion()) ; PtrOwner pSrfTool( CreateSurfFlatRegion()) ; if ( IsNull( pSrfTool_Offs) || IsNull( pSrfTool_Links) || IsNull( pSrfTool)) return false ; // creo un vettore che conterrà solamente i Link percorsi fino ad Ora ICRVCOMPOPOVECTOR vLinks_done ; for ( int i = m_Params.m_nSubType == POCKET_SUB_SPIRALIN ? 0 : ( int)vCrvs.size() - 1 ; m_Params.m_nSubType == POCKET_SUB_SPIRALIN ? i < int( vCrvs.size()) : i >= 0 ; m_Params.m_nSubType == POCKET_SUB_SPIRALIN ? ++ i : -- i) { // ================= LINK ================================ if ( i <= ( int)vLinks.size() && ! IsNull( vLinks[i]) && vLinks[i]->IsValid()) { // Feed PtrOwner pCompoLink_i( CreateCurveComposite()) ; if ( IsNull( pCompoLink_i)) return false ; pCompoLink_i->AddCurve( vLinks[i]->Clone()) ; if ( ! AssignFeedSpiral( pCompoLink_i, pSrfTool_Offs, true, vLinks_done, pCrv_orig, m_TParams.m_dDiam / 3)) return false ; // per Link ... PtrOwner pCrvLink_i( vLinks[i]->Clone()) ; if ( IsNull( pCrvLink_i)) return false ; PtrOwner pSrfToolRegLinki( GetSurfFlatRegionFromFatCurve( Release( pCrvLink_i), m_TParams.m_dDiam / 2 + 5 * EPS_SMALL, false, false)) ; if ( ! IsNull( pSrfToolRegLinki)) { if ( ! pSrfTool_Links->IsValid() || pSrfTool_Links->GetChunkCount() == 0) pSrfTool_Links.Set( pSrfToolRegLinki) ; else pSrfTool_Links->Add( *pSrfToolRegLinki) ; } // risetto il Link come curva composita ... vLinks[i].Set( pCompoLink_i->Clone()) ; // inserisco il Link nel vettore dei Link percorsi vLinks_done.emplace_back( Release( pCompoLink_i)) ; } // ================== OFFSET ============================= // Feed if ( ! AssignFeedSpiral( vCrvs[i], pSrfTool_Offs, false, vLinks_done, pCrv_orig, m_TParams.m_dDiam / 3)) return false ; // aggiorno la superificie svuotata PtrOwner pCrvOffs_i( CloneCurveComposite( vCrvs[i])) ; if ( IsNull( pCrvOffs_i)) return false ; PtrOwner pSrfToolRegOffi( GetSurfFlatRegionFromFatCurve( Release( pCrvOffs_i) , m_TParams.m_dDiam / 2 + 5 * EPS_SMALL, false, false)) ; if ( ! IsNull( pSrfToolRegOffi)) { if ( ! pSrfTool_Offs->IsValid() || pSrfTool_Offs->GetChunkCount() == 0) pSrfTool_Offs.Set( Release( pSrfToolRegOffi)) ; else pSrfTool_Offs->Add( *pSrfToolRegOffi) ; } } // 3) Calcolo la superificie svuotata pSrfTool.Set( pSrfTool_Offs) ; pSrfTool->Add( *pSrfTool_Links) ; // 4) Creo la regione contenente tutte le parti non svuotate pSrfToCut->CopyFrom( pSrfExtern) ; if ( ! pSrfToCut->Subtract( *pSrfTool)) return false ; return true ; } //---------------------------------------------------------- bool Pocketing::CalcZigZagLink( ICurveComposite* pCrv1, ICurveComposite* pCrv2, ICurveComposite* pCrvLink) { // controllo dei parametri if ( pCrv1 == nullptr || pCrv2 == nullptr) return false ; pCrvLink->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL) ; // prendo i parametri per il raccordo Vector3d vtS, vtE, vtH ; pCrv1->GetEndDir( vtS) ; pCrv2->GetStartDir( vtE) ; Point3d ptS, ptE, ptE1, ptS2 ; pCrv1->GetEndPoint( ptS) ; pCrv2->GetStartPoint( ptE) ; vtH = ptE - ptS ; double dLen1, dLen2 ; pCrv1->GetLength( dLen1) ; pCrv2->GetLength( dLen2) ; double dUS1, dUE1, dUS2, dUE2 ; pCrv1->GetDomain( dUS1, dUE1) ; pCrv2->GetDomain( dUS2, dUE2) ; double dAngle, dAngleH ; double dDist = Dist( ptS, ptE) ; // curve per controllo validità del collegamento PtrOwner pCrvH1( CreateCurveComposite()) ; PtrOwner pCrvH2( CreateCurveComposite()) ; PtrOwner pCrvTempLink( CreateCurveComposite()) ; PtrOwner pCrvTest( CreateCurveComposite()) ; if ( IsNull( pCrvH1) || IsNull( pCrvH2) || IsNull( pCrvTempLink) || IsNull( pCrvTest)) return false ; if ( vtS.GetAngle( vtE, dAngle) && abs( dAngle) < ANG_STRAIGHT + 5 * EPS_SMALL && abs( dAngle) > ANG_STRAIGHT - 5 * EPS_SMALL && vtH.GetAngle( vtE, dAngleH) && abs( dAngleH) < ANG_RIGHT + 5 * EPS_SMALL && abs( dAngleH) > ANG_RIGHT - 5 * EPS_SMALL && dLen1 > dDist && dLen2 > dDist && pCrvLink->GetCurveCount() == 1 && pCrvLink->GetFirstCurve()->GetType() == CRV_LINE) { // CREO UNA SEMICIRCONFERENZA double dRad = dDist / 2 ; // raggio Point3d ptNS, ptNE ; pCrv1->GetParamAtLength( dLen1 - dRad, dUE1) ; pCrv2->GetParamAtLength( dRad, dUS2) ; pCrv1->GetPointD1D2( dUE1, ICurve::FROM_MINUS, ptNS) ; // parametro di intersezione su curva 1 pCrv2->GetPointD1D2( dUS2, ICurve::FROM_PLUS, ptNE) ; // parametro di intersezione su curva 2 PtrOwner pSemiCir( CreateCurveArc()) ; if ( pSemiCir->Set2PVN( ptNS, ptNE, vtS, Z_AX)) { pCrvH1.Set( GetCurveComposite( pCrv1->CopyParamRange( dUS1, dUE1))) ; pCrvH2.Set( GetCurveComposite( pCrv2->CopyParamRange( dUS2, dUE2))) ; pCrvTempLink->AddCurve( pSemiCir->Clone()) ; } // controllo finale sui raccordi ammissibili ... if ( pCrvTest->AddCurve( pCrvH1->Clone()) && pCrvTest->AddCurve( pCrvTempLink->Clone()) && pCrvTest->AddCurve( pCrvH2->Clone())) { pCrv1->TrimEndAtParam( dUE1) ; pCrvLink->Clear() ; pCrvLink->AddCurve( Release( pCrvTempLink)) ; pCrv2->TrimStartAtParam( dUS2) ; return true ; } } else { // DEVO SMUSSARE LA CURVA FORMATA DA pCrv1 - pCrvLink ( da creare) - pCrv2 pCrvH1->AddCurve( pCrv1->Clone()) ; pCrvH2->AddCurve( pCrv2->Clone()) ; pCrvTempLink->AddCurve( pCrvLink->Clone()) ; // prendo le lunghezze necessarie double dLenSeg1 = EPS_SMALL ; double dLenSeg2 = EPS_SMALL ; double dLenI_s = EPS_SMALL ; // lunghezza prima curva del Link double dLenI_e = EPS_SMALL ; // lunghezza ultima curva del Link pCrvH1->GetLength( dLenSeg1) ; pCrvH2->GetLength( dLenSeg2) ; pCrvTempLink->GetFirstCurve()->GetLength( dLenI_s) ; pCrvTempLink->GetLastCurve()->GetLength( dLenI_e) ; // raccordo pSeg1 con pCrvLink double dTollLeft = 1 - ( dLen1 - ( m_TParams.m_dTDiam / 16)) / dLen1 ; // % parametro sinistro per smusso double dTollRight = ( m_TParams.m_dTDiam / 16) / dLenI_s ; // % parametro destro di smusso PtrOwner pCrv_Seg1_Isl( CreateCurveComposite()) ; // curva unione di pSeg1 e pCrvLink smussata pCrv_Seg1_Isl->AddCurve( pCrvH1->Clone()) ; pCrv_Seg1_Isl->AddCurve( pCrvTempLink->Clone()) ; ModifyCurveToSmoothed( pCrv_Seg1_Isl, dTollLeft, dTollRight) ; // raccordo questa curva con pSeg2 double dUS_1IH, dUE_1IH, dToTLen ; pCrv_Seg1_Isl->GetDomain( dUS_1IH, dUE_1IH) ; // dominio della curva smussata tra pSeg1 e PCrvLink pCrv_Seg1_Isl->GetLength( dToTLen) ; // nuova lunghezza della curva smussata tra pSeg1 e pCrvLink dTollLeft = 1 - ( dLenI_e - ( m_TParams.m_dTDiam / 16)) / dLenI_e ; // % paramtro sinistro per smusso dTollRight = ( m_TParams.m_dTDiam / 16) / dLen2 ; // % parametro destro per smusso PtrOwner pCrv_smoothed( CreateCurveComposite()) ; // curva unione del primo smusso con pSeg2 pCrv_smoothed->AddCurve( pCrv_Seg1_Isl->Clone()) ; pCrv_smoothed->AddCurve( pCrvH2->Clone()) ; ModifyCurveToSmoothed( pCrv_smoothed, dTollLeft, dTollRight) ; // recupero i parametri del nuovo collegamento che si è creato dallo smusso pCrvH1->Clear() ; pCrvTempLink->Clear() ; pCrvH2->Clear() ; int nStat = -1 ; for ( int u = 0 ; u < pCrv_smoothed->GetCurveCount() ; ++ u) { // recupero la curva u-esima const ICurve* pCrv = pCrv_smoothed->GetCurve( u) ; if ( pCrv->GetType() == CRV_LINE) { if ( CheckSimpleOverlap( pCrv, pCrv1, nStat, EPS_SMALL) && nStat == 1) pCrvH1->AddCurve( pCrv->Clone()) ; else if ( CheckSimpleOverlap( pCrv, pCrv2, nStat, EPS_SMALL) && nStat == 1) pCrvH2->AddCurve( pCrv->Clone()) ; } } Point3d ptCrv1_e, ptCrv2_s ; double dULink_s = EPS_SMALL ; double dULink_e = EPS_SMALL ; pCrvH1->GetEndPoint( ptCrv1_e) ; pCrv1->GetParamAtPoint( ptCrv1_e, dULink_s) ; pCrv1->TrimEndAtParam( dULink_s) ; pCrvH2->GetStartPoint( ptCrv2_s) ; pCrv2->GetParamAtPoint( ptCrv2_s, dULink_e) ; pCrv2->TrimStartAtParam( dULink_e) ; pCrv_smoothed->GetParamAtPoint( ptCrv1_e, dULink_s) ; pCrv_smoothed->GetParamAtPoint( ptCrv2_s, dULink_e) ; pCrvLink->Clear() ; pCrvLink->AddCurve( GetCurveComposite( pCrv_smoothed->CopyParamRange( dULink_s, dULink_e))) ; return true ; } return false ; } //---------------------------------------------------------- bool Pocketing::OptimizedZigZag( ISurfFlatRegion* pSrf, const Vector3d& vtTool, double dDepth, double dSafeZ, Frame3d& frPocket, ICurveComposite* pCrvOrig, bool& bOptimizedZigZag, ICRVCOMPOPOVECTOR& vpCrvs, double& dOffs) { // clono la superficie (chunk c-esimo dell'originale) PtrOwner pSrfPocket( CloneSurfFlatRegion( pSrf)) ; if ( IsNull( pSrfPocket)) return false ; // recupero la curva ORIGINALE che delimita la svuotatura (questa curva non risente dell'offset fatto dalla superificie creata dopo) PtrOwner pCrvForId( GetCurveComposite( pSrfPocket->GetLoop( 0, 0))) ; int nCrvId = pCrvForId->GetTempProp( 0) ; PtrOwner pCrvPocket( CloneCurveComposite( m_pGeomDB->GetGeoObj( nCrvId))) ; bool bSrfOriIsCut = false ; if ( IsNull( pCrvPocket)) { pCrvPocket.Set( pCrvOrig->Clone()) ; if ( IsNull( pCrvPocket) || pCrvPocket->GetCurveCount() == 0) return true ; bSrfOriIsCut = true ; } // porto la curva nel sistema di riferimento locale pCrvPocket->ToLoc( frPocket) ; // setto proprietà sulle curve if ( ! bSrfOriIsCut) SetCurveAllTempProp( nCrvId, pCrvPocket) ; pCrvPocket->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL) ; // sistemo senso antiorario visto dalla direzione di estrusione Vector3d vtPocket; pCrvPocket->GetExtrusion( vtPocket) ; Plane3d plPlane ; double dArea ; pCrvPocket->GetArea( plPlane, dArea) ; if ( plPlane.GetVersN() * vtPocket * dArea < 0) pCrvPocket->Invert() ; // recupero gli id dei lati chiusi INTVECTOR vnInfoClosed ; for ( int i = 0 ; i < pCrvPocket->GetCurveCount() ; i ++) { int nProp ; if ( pCrvPocket->GetCurveTempProp( i, nProp) && nProp == 0) vnInfoClosed.push_back( i) ; } int nClosedSides = vnInfoClosed.size() ; // modifico pCrvPocket per poterla passare a CalcZigZag bool bTwoOpposite ; Vector3d vtDir ; // direzione principale del segmento più lungo (linea) switch ( nClosedSides) { case 0 : // 0 lati CHIUSI -> tutti APERTI ZigZagOptimizedNoClosedEdges( pCrvPocket, bOptimizedZigZag, vtDir, dOffs) ; break ; case 1 : // 1 lato CHIUSO ZigZagOptimizedOneClosedEdge( pCrvPocket, vnInfoClosed[0], bOptimizedZigZag, vtDir, dOffs) ; break ; case 2 : // 2 lati CHIUSI ZigZagOptimizedTwoClosedEdges( pCrvPocket, vnInfoClosed, bOptimizedZigZag, bTwoOpposite, vtDir, dOffs) ; break ; case 3 : // 3 lati CHIUSI ZigZagOptimizedThreeClosedEdges( pCrvPocket, vnInfoClosed, bOptimizedZigZag, bTwoOpposite, vtDir, dOffs) ; break ; default : // nessuna ottimizzazione... bOptimizedZigZag = false ; break ; } if ( ! bOptimizedZigZag) return true ; if ( vtDir.IsZero()) pCrvPocket->GetStartDir( vtDir) ; double dAng ; vtDir.GetAngleXY( X_AX, dAng) ; if ( nClosedSides == 0) dAng += m_Params.m_dSideAngle ; pCrvPocket->ToGlob( frPocket) ; Frame3d frameH( frPocket) ; Point3d ptCen = frPocket.Orig() ; Vector3d vtExtr = frPocket.VersZ() ; frPocket.Rotate( ptCen, vtExtr, -dAng) ; pCrvPocket->ToLoc( frPocket) ; // vettore contenente le curve di primo Offset ottimizzate ( bordo esterno Optimized e isole ) ICRVCOMPOPOVECTOR vFirstOffsets ; vFirstOffsets.emplace_back( Release( pCrvPocket)) ; // la curva esterna modificata double dTRad = m_TParams.m_dDiam / 2 ; double dMyOffs = dTRad + GetOffsR() ; double dExtra = (( m_TParams.m_nType != TT_MILL_POLISHING) ? min( 0.1 * m_TParams.m_dDiam, 2.0) : 0) ; PtrOwner pSrfPocketClone( CloneSurfFlatRegion( pSrfPocket)) ; if ( IsNull( pSrfPocketClone)) return false ; if ( ! pSrfPocketClone->Offset( - dMyOffs - dExtra, ICurve::OFF_FILLET)) { // le isole interne vanno Offsettate m_pMchMgr->SetLastError( 2412, "Error in Pocketing : Offset not computable") ; return false ; } ICRVCOMPOPOVECTOR vCrvAllLoops ; double dMaxArea = -INFINITO; int nIndex = -1; int p = 0 ; // p è il # di loop totali for ( int cu = 0 ; cu < pSrfPocketClone->GetChunkCount() ; ++ cu) { for ( int l = 0 ; l < pSrfPocketClone->GetLoopCount( cu) ; ++ l) { // inserisco i loops portandoli nel nuovo sistema di riferimento PtrOwner pCrvLoop( GetCurveComposite( pSrfPocketClone->GetLoop( cu, l))) ; if ( IsNull( pCrvLoop)) return false ; pCrvLoop->ToGlob( frameH) ; pCrvLoop->ToLoc( frPocket) ; double dArea ; pCrvLoop->GetAreaXY( dArea) ; if ( dArea > dMaxArea) { dMaxArea = dArea ; nIndex = p ; } vCrvAllLoops.emplace_back( Release( pCrvLoop)) ; p++ ; } } for ( int i = 0 ; i < int( vCrvAllLoops.size()) ; ++ i) { if ( i != nIndex) { vFirstOffsets.emplace_back( vCrvAllLoops[i]->Clone()) ; } } // creo la superficie da svuotare ottimizzata SurfFlatRegionByContours pSrfMod ; for ( int i = 0 ; i < int( vFirstOffsets.size()) ; ++ i) pSrfMod.AddCurve( vFirstOffsets[i]->Clone()) ; PtrOwner pSrfZigZag( pSrfMod.GetSurf()) ; if ( IsNull( pSrfZigZag)) return false ; if ( AreOppositeVectorApprox( vtExtr, pSrfZigZag->GetNormVersor())) pSrfZigZag->Invert() ; // calcolo il percorso di svuotatura if ( ! CalcZigZag( pSrfZigZag, vpCrvs)) return false ; // se un lato chiuso if ( nClosedSides == 1) { // inverto il percorso vpCrvs[0]->Invert() ; // verifico se attacco fuori dal grezzo Point3d ptStart ; vpCrvs[0]->GetStartPoint( ptStart) ; Vector3d vtDir ; vpCrvs[0]->GetStartDir( vtDir) ; Point3d ptTest = ptStart + ( - vtDir) * ( m_TParams.m_dDiam / 2 - dOffs + dSafeZ) ; ptTest.ToGlob( frPocket) ; ptTest += - vtTool * dDepth ; double dTestElev ; // se è nel grezzo provo a ruotare di 90 gradi if ( GetElevation( m_nPhase, ptTest, vtTool, m_TParams.m_dDiam / 2 - dOffs, vtTool, dTestElev) && dTestElev > EPS_SMALL) { Vector3d vtDirO = vtDir ; vtDirO.Rotate( Z_AX, ( m_Params.m_bInvert ? -90 : 90)) ; Point3d ptTestO = ptStart + vtDirO * ( m_TParams.m_dDiam / 2 - dOffs + dSafeZ) ; ptTestO.ToGlob( frPocket) ; ptTestO += - vtTool * dDepth ; double dTestElevO ; // se è fuori dal grezzo uso inizio ruotato if ( ! GetElevation( m_nPhase, ptTestO, vtTool, m_TParams.m_dDiam / 2 - dOffs, vtTool, dTestElevO) || dTestElevO < EPS_SMALL) { Point3d ptNewStart = ptStart + vtDirO ; vpCrvs[0]->AddLine( ptNewStart, false) ; } } } // se due lati chiusi consecutivi o tre lati chiusi... else if (( nClosedSides == 2 || nClosedSides == 3) && ! bTwoOpposite) { // inverto il percorso vpCrvs[0]->Invert() ; // allungo opportunamente inizio e fine Point3d ptStart ; vpCrvs[0]->GetStartPoint( ptStart) ; Vector3d vtDir ; vpCrvs[0]->GetStartDir( vtDir) ; vtDir.Rotate( Z_AX, ( m_Params.m_bInvert ? -90 : 90)) ; ptStart += vtDir ; Point3d ptEnd ; vpCrvs[0]->GetEndPoint( ptEnd) ; ptEnd += OrthoCompo( ptStart - ptEnd, X_AX) ; vpCrvs[0]->AddLine( ptEnd, true) ; vpCrvs[0]->AddLine( ptStart, false) ; } // estendo la fine del percorso if ( ! ( nClosedSides == 3 && bTwoOpposite)) vpCrvs[0]->ExtendEndByLen( max( m_TParams.m_dDiam / 4 - dOffs, 0.0)) ; return true ; } //------------------------------------------------------------------ bool Pocketing::ZigZagOptimizedNoClosedEdges( ICurveComposite* pCrvPocket, bool& bOptimizedZigZag, Vector3d& vtDir, double& dOffs) { // individuo il segmento di retta più lungo int nMax = -1 ; double dMaxLen = 0 ; for ( int i = 0 ; i < int( pCrvPocket->GetCurveCount()) ; ++ i) { const ICurve* pCrv = pCrvPocket->GetCurve( i) ; if ( pCrv->GetType() == CRV_LINE) { double dLen = 0 ; pCrv->GetLength( dLen) ; if ( dLen > dMaxLen) { dMaxLen = dLen ; nMax = i ; } } } if ( nMax == -1) return true ; pCrvPocket->GetCurve( nMax)->GetStartDir( vtDir) ; // aggiorno pCrvPocket con eventuale offset per regioni residue if ( ! ZigZagOptimizedComputeOffset( pCrvPocket, vtDir, 0, {}, dOffs)) return true ; bOptimizedZigZag = true ; return true ; } //------------------------------------------------------------------ bool Pocketing::ZigZagOptimizedOneClosedEdge( ICurveComposite* pCrvPocket, int nClosedId, bool& bOptimizedZigZag, Vector3d& vtDir, double& dOffs) { // verifico che il lato chiuso sia una linea PtrOwner pCrv( CloneCurveLine( pCrvPocket->GetCurve( nClosedId))) ; if ( IsNull( pCrv)) return true ; // aggiorno pCrvPocket con eventuale offset per regioni residue pCrv->GetStartDir( vtDir) ; if ( ! ZigZagOptimizedComputeOffset( pCrvPocket, vtDir, 1, {nClosedId}, dOffs)) return true ; // setto il vettore estrusione per eseguire correttamente offset Vector3d vtExtr ; pCrvPocket->GetExtrusion( vtExtr) ; pCrv->SetExtrusion( vtExtr) ; pCrv->SimpleOffset( -m_TParams.m_dDiam / 2 - GetOffsR() + 10 * EPS_SMALL) ; pCrv->ExtendStartByLen( 300) ; pCrv->ExtendEndByLen( 300) ; // sarà la prima curva del percorso if ( ! CutCurveWithLine( pCrvPocket, pCrv)) return false ; bOptimizedZigZag = true ; return true ; } //------------------------------------------------------------------ bool Pocketing::ZigZagOptimizedTwoClosedEdges( ICurveComposite* pCrvPocket, const INTVECTOR& vnClosedIds, bool& bOptimizedZigZag, bool& bOpposite, Vector3d& vtDir, double& dOffs) { // verifico che i lati chiusi siano linee PtrOwner pCrv1( CloneCurveLine( pCrvPocket->GetCurve( vnClosedIds[0]))) ; PtrOwner pCrv2( CloneCurveLine( pCrvPocket->GetCurve( vnClosedIds[1]))) ; if ( IsNull( pCrv1) || IsNull( pCrv2)) return true ; // verifico abbiano direzioni opposte Vector3d vtDir1, vtDir2 ; pCrv1->GetStartDir( vtDir1) ; pCrv2->GetStartDir( vtDir2) ; if ( AreOppositeVectorApprox( vtDir1, vtDir2)) bOpposite = true ; else { // verifico siano consecutive Point3d ptStart1 ; pCrv1->GetStartPoint( ptStart1) ; Point3d ptEnd1 ; pCrv1->GetEndPoint( ptEnd1) ; Point3d ptStart2 ; pCrv2->GetStartPoint( ptStart2) ; Point3d ptEnd2 ; pCrv2->GetEndPoint( ptEnd2) ; if ( AreSamePointApprox( ptEnd1, ptStart2) || AreSamePointApprox( ptEnd2, ptStart1)) bOpposite = false ; else return true ; } // setto il vettore estrusione per eseguire correttamente offset Vector3d vtExtr ; pCrvPocket->GetExtrusion( vtExtr) ; pCrv1->SetExtrusion( vtExtr) ; pCrv2->SetExtrusion( vtExtr) ; // determino la curva chiusa più lunga double dLen1 ; pCrv1->GetLength( dLen1) ; double dLen2 ; pCrv2->GetLength( dLen2) ; // se non opposti, verifico che almeno una delle due sia corta if ( ! bOpposite && dLen1 > 1.5 * m_TParams.m_dDiam && dLen2 > 1.5 * m_TParams.m_dDiam) return true ; // trovo la direzione principale della svuotatura if ( dLen1 > dLen2) pCrv1->GetStartDir( vtDir) ; else pCrv2->GetStartDir( vtDir) ; // aggiorno pCrvPocket con eventuale offset per regioni residue if ( ! ZigZagOptimizedComputeOffset( pCrvPocket, vtDir, bOpposite ? 2 : 1, vnClosedIds, dOffs)) return true ; double dMyOffs = m_TParams.m_dDiam / 2 + GetOffsR() - 10 * EPS_SMALL ; pCrv1->SimpleOffset( -dMyOffs) ; pCrv1->ExtendStartByLen( 300) ; pCrv1->ExtendEndByLen( 300) ; if ( ! CutCurveWithLine( pCrvPocket, pCrv1)) return false ; // sarà la prima curva del percorso pCrv2->SimpleOffset( -dMyOffs) ; pCrv2->ExtendStartByLen( 300) ; pCrv2->ExtendEndByLen( 300) ; if ( ! CutCurveWithLine( pCrvPocket, pCrv2)) return false ; bOptimizedZigZag = true ; return true ; } //------------------------------------------------------------------ bool Pocketing::ZigZagOptimizedThreeClosedEdges( ICurveComposite* pCrvPocket, const INTVECTOR& vnClosedIds, bool& bOptimizedZigZag, bool& bOpposite, Vector3d& vtDir,double& dOffs) { // verifico che i lati chiusi siano linee PtrOwner pCrv1( CloneCurveLine( pCrvPocket->GetCurve( vnClosedIds[0]))) ; PtrOwner pCrv2( CloneCurveLine( pCrvPocket->GetCurve( vnClosedIds[1]))) ; PtrOwner pCrv3( CloneCurveLine( pCrvPocket->GetCurve( vnClosedIds[2]))) ; if ( IsNull( pCrv1) || IsNull( pCrv2) || IsNull( pCrv3)) return true ; // verifico siano consecutivi Point3d ptStart1 ; pCrv1->GetStartPoint( ptStart1) ; Point3d ptEnd1 ; pCrv1->GetEndPoint( ptEnd1) ; Point3d ptStart2 ; pCrv2->GetStartPoint( ptStart2) ; Point3d ptEnd2 ; pCrv2->GetEndPoint( ptEnd2) ; Point3d ptStart3 ; pCrv3->GetStartPoint( ptStart3) ; Point3d ptEnd3 ; pCrv3->GetEndPoint( ptEnd3) ; if ( AreSamePointApprox( ptEnd1, ptStart2) && AreSamePointApprox( ptEnd2, ptStart3)) ; else if ( AreSamePointApprox( ptEnd2, ptStart3) && AreSamePointApprox( ptEnd3, ptStart1)) { swap( pCrv1, pCrv2) ; swap( pCrv2, pCrv3) ; } else if ( AreSamePointApprox( ptEnd3, ptStart1) && AreSamePointApprox( ptEnd1, ptStart2)) { swap( pCrv1, pCrv3) ; swap( pCrv3, pCrv2) ; } else return true ; // calcolo la direzione della svuotatura e verifico che lati non siano troppo lunghi double dLen1 ; pCrv1->GetLength( dLen1) ; double dLen2 ; pCrv2->GetLength( dLen2) ; double dLen3 ; pCrv3->GetLength( dLen3) ; if ( dLen2 > dLen1 && dLen2 > dLen3) { if ( dLen1 > /*1.5 **/ m_TParams.m_dDiam / 2 + 5 * EPS_SMALL || dLen3 > /*1.5 **/ m_TParams.m_dDiam / 2 + 5 * EPS_SMALL) return true ; pCrv2->GetStartDir( vtDir) ; bOpposite = false ; } else { if ( dLen2 > /*1.5 **/ m_TParams.m_dDiam / 2 + 5 * EPS_SMALL) return true ; pCrv3->GetStartDir( vtDir) ; bOpposite = true ; } // aggiorno pCrvPocket con eventuale offset per regioni residue if ( ! ZigZagOptimizedComputeOffset( pCrvPocket, vtDir, 1, vnClosedIds, dOffs)) return true ; // setto il vettore estrusione per eseguire correttamente offset Vector3d vtExtr ; pCrvPocket->GetExtrusion( vtExtr) ; pCrv1->SetExtrusion( vtExtr) ; pCrv2->SetExtrusion( vtExtr) ; pCrv3->SetExtrusion( vtExtr) ; double dMyOffs = m_TParams.m_dDiam / 2 + GetOffsR() - 10 * EPS_SMALL ; pCrv1->SimpleOffset( - dMyOffs) ; pCrv1->ExtendStartByLen( 300) ; pCrv1->ExtendEndByLen( 300) ; if ( ! CutCurveWithLine( pCrvPocket, pCrv1)) return false ; pCrv3->SimpleOffset( -dMyOffs) ; pCrv3->ExtendStartByLen( 300) ; pCrv3->ExtendEndByLen( 300) ; if ( ! CutCurveWithLine( pCrvPocket, pCrv3)) return false ; // sarà la prima curva del percorso pCrv2->SimpleOffset( -dMyOffs) ; pCrv2->ExtendStartByLen( 300) ; pCrv2->ExtendEndByLen( 300) ; if ( ! CutCurveWithLine( pCrvPocket, pCrv2)) return false ; bOptimizedZigZag = true ; return true ; } //------------------------------------------------------------------ bool Pocketing::ZigZagOptimizedComputeOffset( ICurveComposite* pCrvPocket, const Vector3d& vtMainDir, int nOffsettedEdgesOnY, const INTVECTOR& vnClosedIds, double& dOffs) { // ricavo l'estrusione Vector3d vtExtr ; pCrvPocket->GetExtrusion( vtExtr) ; // ricavo la Thickness double dThick ; pCrvPocket->GetThickness( dThick) ; // aggiusto offset dOffs = m_TParams.m_dDiam / 2 + 5 * EPS_SMALL ; double dMinOffs = max( 0., 0.5 * m_TParams.m_dDiam - m_Params.m_dSideStep) ; dOffs = max( dOffs, dMinOffs) ; if ( dOffs > EPS_SMALL) { // calcolo offset OffsetCurve OffsCrv ; if ( ! OffsCrv.Make( pCrvPocket, dOffs, ICurve::OFF_EXTEND)) { m_pMchMgr->SetLastError( 2412, "Error in Pocketing : Offset not computable") ; return false ; } if ( OffsCrv.GetCurveCount() > 1) return false ; // aggiorno pCrvPocket pCrvPocket->Clear() ; pCrvPocket->AddCurve( OffsCrv.GetCurve()) ; pCrvPocket->SetExtrusion( vtExtr) ; pCrvPocket->SetThickness( dThick) ; } return true ; } //------------------------------------------------------------------ bool Pocketing::CutCurveWithLine( ICurveComposite* pCrvA, const ICurveLine* pCrvB) { IntersCurveCurve IntersCC( *pCrvA, *pCrvB) ; CRVCVECTOR ccClass ; IntersCC.GetCurveClassification( 1, EPS_SMALL, ccClass) ; if ( ccClass.size() != 3 || ccClass[0].nClass != CRVC_OUT || ccClass[1].nClass == CRVC_OUT || ccClass[2].nClass != CRVC_OUT) return false ; Point3d ptS, ptE ; pCrvB->GetPointD1D2( ccClass[1].dParS, ICurve::FROM_MINUS, ptS) ; pCrvB->GetPointD1D2( ccClass[1].dParE, ICurve::FROM_MINUS, ptE) ; double dParS, dParE ; pCrvA->GetParamAtPoint( ptS, dParS) ; pCrvA->GetParamAtPoint( ptE, dParE) ; PtrOwner pCrvTmp( CloneCurveComposite( pCrvA)) ; if ( IsNull( pCrvTmp)) return false ; pCrvA->Clear() ; pCrvA->AddCurve( pCrvB->CopyParamRange( ccClass[1].dParS, ccClass[1].dParE)) ; pCrvA->AddCurve( pCrvTmp->CopyParamRange( dParE, dParS)) ; return true ; } //---------------------------------------------------------------------------- bool Pocketing::AddOneWay( const ISurfFlatRegion* pSrfPock, const Vector3d& vtTool, const Vector3d& vtExtr, double dDepth, double dElev, double dOkStep, bool bSplitArcs) { // recupero distanze di sicurezza double dSafeZ = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeZ() ; double dSafeAggrBottZ = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeAggrBottZ() ; // lunghezza di approccio/retrazione double dAppr = m_Params.m_dStartPos ; // se utensile che non lavora di testa poichè ingresso non fuori dal pezzo, errore if ( m_TParams.m_nType == TT_MILL_NOTIP) { if ( ! LeadInRawIsOk()) { m_pMchMgr->SetLastError( 2431, "Error in Pocketing : LeadIn with Mill NoTip in material") ; return false; } } // determino numero e affondamento degli step int nStep = 1 ; nStep = max( 1, static_cast( ceil(dElev / dOkStep))) ; double dStep = dElev / nStep ; double dTRad = 0.5 * m_TParams.m_dDiam ; double dOffs = dTRad + GetOffsR() ; double dExtra = min( 0.1 * m_TParams.m_dDiam, 1.0) ; // copio la regione da svuotare PtrOwner pSrfToPock( pSrfPock->Clone()) ; if ( IsNull( pSrfToPock)) return false ; // creo le regioni ideali -------------------------------------------- // creo un frame di riferimento della svuotatura Frame3d frLoc ; Point3d ptC ; pSrfToPock->GetCentroid( ptC) ; Vector3d vtN = pSrfPock->GetNormVersor() ; frLoc.Set( ptC, vtN) ; pSrfToPock->ToLoc( frLoc) ; ISURFFRPOVECTOR vSrfFlat ; INTVECTOR vIndChunk ; PNTVECTOR vPtCheck ; struct PtSPtC { // struttura per punti inziali int nInd ; // indice per vettori vPtStart, vbMidOpen, vPtMidOpen, vVtMidOut Point3d ptC ; // punto check sulla curva } ; if ( ! OptimizeChunkOneWay( pSrfToPock, vSrfFlat, vIndChunk, vPtCheck)) return false ; typedef vector vPtSCheck ; vPtSCheck vNewPtStart(( int)vIndChunk.size()) ; for ( int i = 0 ; i < ( int)vIndChunk.size() ; ++ i){ vNewPtStart[i].nInd = vIndChunk[i] ; vNewPtStart[i].ptC = vPtCheck[i] ; } // riporto le superifici ideali nel sistema di riferimento globale for ( int i = 0 ; i < (int )vSrfFlat.size() ; ++ i) vSrfFlat[i]->ToGlob( frLoc) ; // ------------------------------------------------------------------ // === per ogni superificie ideale creo 2 Offsets === // - dOffs con le curve da percorrere all'inizio ( bordo da percorrere, senza mai superarlo) // - dOffs - dExtra per definire le curve interne della svuotatura ( bordo immaginario per il OneWay ) for ( int nIs = 0 ; nIs < int( vSrfFlat.size()) ; ++ nIs) { // copio la superificie ideale PtrOwner pSrfIdeal( CloneSurfFlatRegion( vSrfFlat[nIs])) ; if ( IsNull( pSrfIdeal)) return false ; ISURFFRPOVECTOR vSrfSliced( nStep) ; vector vCrvOEWithFlags( nStep) ; BOOLVECTOR vbChangedPrec( nStep, false) ; for ( int j = 1 ; j <= nStep ; ++ j) { // controllo l'intersezione/proiezione tra la superificie e il grezzo PtrOwner pCrvOPF( CreateCurveComposite()) ; Vector3d vtTrasl = -vtTool * ( dDepth - dElev + j * dStep) ; ICRVCOMPOPOVECTOR vCrvOEF ; bool bChanged = false ; PtrOwner pSrfToAdapt( CloneSurfFlatRegion( pSrfIdeal)) ; if ( AdaptSfrWithRaw( pSrfToAdapt, vtTrasl, 100.0, vCrvOEF, bChanged)) { vSrfSliced[j-1].Set( pSrfToAdapt->Clone()) ; if ( ! IsNull( vSrfSliced[j-1])) { for ( int h = 0 ; h < ( int)vCrvOEF.size() ; ++h) vCrvOEWithFlags[j-1].emplace_back( Release( vCrvOEF[h])) ; // controllo se la superificie attuale e precedente sono diverse tra loro if ( j > 1) { double dAreaPrec = 0 ; double dAreaAct = 0 ; if ( ! IsNull( vSrfSliced[j-2])) { vSrfSliced[j-2]->GetArea( dAreaPrec) ; vSrfSliced[j-1]->GetArea( dAreaAct) ; if ( abs( dAreaAct - dAreaPrec) > 500 * EPS_SMALL) vbChangedPrec[j-1] = true ; } else vbChangedPrec[j-1] = true ; } } } else { return false ; } } Point3d ptP1 ; for ( int j = 1 ; j <= nStep ; ++ j) { // se superificie non valida, salto allo step successivo if ( IsNull( vSrfSliced[ j-1]) || vSrfSliced[j-1]->GetChunkCount() == 0) { vSrfSliced[j-1].Set( vSrfFlat[nIs]->Clone()) ; continue ; } // per entrate ed uscite PtrOwner pSrfLeanInOut( CloneSurfFlatRegion( vSrfSliced[j-1])) ; if ( IsNull( pSrfLeanInOut) || pSrfLeanInOut->GetChunkCount() == 0) return false ; // === PRIMO OFFSET === // NB. Effettuando il primo Offset, il numero di chunk qui potrebbe cambiare... PtrOwner pSrfFirstOffs( CloneSurfFlatRegion( vSrfSliced[j-1])) ; if ( IsNull( pSrfFirstOffs) || pSrfFirstOffs->GetChunkCount() == 0) return false ; if ( ! pSrfFirstOffs->Offset( - dOffs, ICurve::OFF_FILLET)) { m_pMchMgr->SetLastError( 2412, "Error in Pocketing : Offset not computable") ; return false ; } // creo un frame di riferimento per ogni superificie da svuotare Frame3d frLocI ; Point3d ptC ; pSrfToPock->GetCentroid( ptC) ; Vector3d vtN = pSrfToPock->GetNormVersor() ; frLocI.Set( ptC, vtN) ; vSrfSliced[j-1]->ToLoc( frLocI) ; // salvo tutte le curve di Offset in un vettore per poi ordinarle e sistemare i punti iniziali ICRVCOMPOPOVECTOR vAllCrv ; // vettore di indici, mi dice a quale chunk la curva vAllCrv-u-esima appartiene INTVECTOR vInd ; // NB. Questa Superificie la userò solamente dopo, quando andrò creare le traettorie rettilinee per la OneWay // A questa superificie non andrò ad effettuare un ulteriore Offset con -dExtra, in quando potrei lasciare delle // regioni non svuotate ( come soluzione interseco ogni segmento di OneWay con questa superificie Offsettata di // -dOffs e tagliando ogni segmento, lo accorcio sia all'inizio che alla fine della quantità dExtra // organizzo i Chunck della superificie elaborata con il grezzo ... for ( int c = 0 ; c < vSrfSliced[j-1]->GetChunkCount() ; ++ c) { PtrOwner pSrfChuck_c( vSrfSliced[j-1]->CloneChunk( c)) ; if ( IsNull( pSrfChuck_c)) return false ; if ( ! pSrfChuck_c->Offset( - dOffs, ICurve::OFF_FILLET)) { m_pMchMgr->SetLastError( 2412, "Error in Pocketing : Offset not computable") ; return false ; } for ( int cc = 0 ; cc < pSrfChuck_c->GetChunkCount() ; ++ cc) { for ( int l = 0 ; l < pSrfChuck_c->GetLoopCount( cc) ; ++ l) { vAllCrv.emplace_back( GetCurveComposite( pSrfChuck_c->GetLoop( cc, l))) ; vInd.emplace_back( c) ; } } } if (( int)vAllCrv.size() == 0) return false ; // Sistemo i punti iniziali per i nuovi Chunks ------------------------------------------ VCT3DVECTOR vVtMidOut(( int)vAllCrv.size(), V_NULL) ; BOOLVECTOR vbMidOut(( int)vAllCrv.size(), false) ; PNTVECTOR vPtStart(( int)vAllCrv.size(), Point3d( 0,0,0)) ; BOOLVECTOR vbForcedOutStart(( int)vAllCrv.size(), false) ; // le curve ottenute andranno percorse dall'utensile for ( int u = 0 ; u < ( int)vAllCrv.size() ; ++ u) { // per ogni curva di bordo... bool bOutTmp = false ; PtrOwner pSrfCurrChunk( vSrfSliced[j-1]->CloneChunk( vInd[u])) ; if ( IsNull( pSrfCurrChunk)) return false ; if ( ! SetBetterPtStartForSubChunks( vAllCrv[u], pSrfCurrChunk, vPtStart[u], vVtMidOut[u], bOutTmp, dOffs)) return false ; vbMidOut[u] = bOutTmp ; // vector::reference da Bit a Bool PtrOwner pOffs( CreateCurveComposite()) ; // copio la curva ... if ( IsNull( pOffs) || ! pOffs->AddCurve( vAllCrv[u]->Clone())) { m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ; return false ; } // riporto i valori nel sistema di riferimento corretto vPtStart[u].ToGlob( frLocI) ; vVtMidOut[u].ToGlob( frLocI) ; vAllCrv[u]->ToGlob( frLocI) ; // se richiesto, la inverto if ( m_Params.m_bInvert) vAllCrv[u]->Invert() ; // setto la Feed per la curva di contorno AssignFeedForEdgeCleaning( vAllCrv[u], vCrvOEWithFlags[j-1]) ; // se la curva è valida per entrata da fuori, aggiungo un piccolo tratto lineare if ( vbMidOut[u]) { // calcolo il punto fuori Point3d ptOut = vPtStart[u] + vVtMidOut[u] * ( 0.5 * m_TParams.m_dDiam + dSafeZ) ; ptOut.Translate( - vtTool * ( dDepth - dElev + j * dStep)) ; double dStElev ; bool bOutStart = ( ! GetElevation( m_nPhase, ptOut, vtTool, 0.5 * m_TParams.m_dDiam, vtTool, dStElev) || dStElev < EPS_SMALL); if ( bOutStart || m_bOpenOutRaw) { // aggiungo alla curva il tratto lineare ptOut.Translate( vtTool * ( dDepth - dElev + j * dStep)) ; vAllCrv[u]->AddLine( ptOut, false) ; AssignFeedForLineInOut( vAllCrv[u], true) ; } // verifico se ingresso da considerare fuori grezzo anche se dentro vbForcedOutStart[u] = ( vbMidOut[u] && m_bOpenOutRaw) ; // se utensile che non lavora di testa e ingresso non fuori dal pezzo, errore if ( m_TParams.m_nType == TT_MILL_NOTIP && !bOutStart && !vbForcedOutStart[u]) { if ( ! LeadInRawIsOk()) { m_pMchMgr->SetLastError( 2431, "Error in Pocketing : LeadIn with Mill NoTip in material") ; return false ; } } } } // riordino le curve ( e i relativi vettori ) in base alla vicinanza // ( piccola ottimizzazione per l'ordine dei percorsi sui bordi ) Point3d ptStart ; vAllCrv[0]->GetStartPoint( ptStart) ; if ( ! OrderCurvesByLastPntOfPath( vAllCrv, ptStart, vPtStart, vVtMidOut, vbMidOut, vbForcedOutStart)) return false ; // ------------------------------------------------------------------------------- // coefficiente di riduzione feed di lavorazione di questa curva //double dFeedRid = min( GetSideStep() / m_TParams.m_dDiam, 1.0) ; // creo la superificie svuotata ( per Feed ) //PtrOwner pSrfRemoved( CreateSurfFlatRegion()) ; //if ( IsNull( pSrfRemoved)) // return false ; //for ( int u = 0 ; u < vAllCrv.size() ; ++ u) // GetDynamicClearedRegion( pSrfRemoved, vAllCrv[u]) ; // ---------------------------- Disegno le curve di contorno ---------------------- for ( int u = 0 ; u < int( vAllCrv.size()) ; ++ u) { // percorro tutte le curve ( ordinate ) // recupero la prima curva di offset disponibile PtrOwner pOffs( CreateCurveComposite()); if ( IsNull( pOffs) || ! pOffs->AddCurve( vAllCrv[u]->Clone())) { m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ; return false; } // aggiungo la lavorazione di questa curva Point3d ptP1 ; double dStElev ; // ciclo sulle curve elementari int nMaxInd = pOffs->GetCurveCount() - 1 ; for ( int i = 0 ; i <= nMaxInd ; ++i) { // curva corrente const ICurve* pCrvC = pOffs->GetCurve( i) ; // copio la curva PtrOwner pCurve( pCrvC->Clone()) ; if ( IsNull( pCurve)) return false ; // aggiungo affondamento pCurve->Translate( -vtTool * ( dDepth - dElev + j * dStep)) ; // SE PRIMA ENTITA' if ( i == 0) { // dati inizio entità Point3d ptStart ; Vector3d vtStart ; pCurve->GetStartPoint( ptStart) ; pCurve->GetStartDir( vtStart) ; Point3d ptForElev = ptStart ; if( vbMidOut[u] || vbForcedOutStart[u]) pCurve->GetEndPoint( ptForElev) ; // se primo step o la superificie rispetto allo step prima non è cambiata o il numero // di chunk è maggiore di 1, approccio e affondo //if ( true || j == 1 || vbChangedPrec[j-1] || vSrfSliced[j-2]->GetChunkCount() > 1) { // determino inizio attacco if ( ! CalcLeadInStart( ptStart, vtStart, vtExtr, nullptr, ptP1)) return false ; // determino elevazione su inizio attacco //double dStElev ; if ( ! GetElevation( m_nPhase, ptForElev - 10 * EPS_SMALL * vtTool, vtTool, GetRadiusForStartEndElevation(), vtTool, dStElev)) dStElev = j * dStep ; bool bAhUnderRaw = m_bAboveHead && ! m_bAggrBottom && ! m_bTiltingTab && GetAhPointUnderRaw( ptP1, vtTool, 0, GetRadiusForStartEndElevation(), m_TParams.m_dLen, false, dSafeZ, vtTool, dStElev) ; bool bUhAboveRaw = ! m_bAboveHead && GetUhPointAboveRaw( ptP1, vtTool, 0, GetRadiusForStartEndElevation(), m_TParams.m_dLen, false, dSafeZ, vtTool, dStElev) ; //if ( bAhUnderRaw || bUhAboveRaw) dStElev = max( dStElev, j * dStep) ; dStElev -= ( ptP1 - ptStart) * vtExtr ; // se attacco a zigzag o a spirale o a scivolo, l'elevazione va nell'attacco if ( GetLeadInType() == POCKET_LI_ZIGZAG || GetLeadInType() == POCKET_LI_HELIX || GetLeadInType() == POCKET_LI_GLIDE) { ptP1 += vtExtr * dStElev ; dStElev = 0 ; } // approccio al punto iniziale // false sempre ? if ( ! AddApproach( ptP1, vtTool, dSafeZ, dSafeAggrBottZ, dStElev, dAppr, vbMidOut[u] || vbForcedOutStart[u])) { m_pMchMgr->SetLastError( 2414, "Error in Pocketing : Approach not computable") ; return false ; } // aggiungo attacco SetFeed( GetStartFeed()) ; if ( ! AddLeadIn( ptP1, ptStart, vtStart, vtExtr, pSrfLeanInOut, nullptr, !m_Params.m_bInvert, bSplitArcs, vbMidOut[u] || vbForcedOutStart[u])) { m_pMchMgr->SetLastError( 2415, "Error in Pocketing : LeadIn not computable") ; return false ; } //} // altrimenti solo collegamento // else { // SetFeed( GetStartFeed()) ; // GetCurrPos( ptP1) ; // if ( ! AddLeadIn( ptP1, ptStart, vtStart, vtExtr, pSrfLeanInOut, nullptr, !m_Params.m_bInvert, bSplitArcs)) { // m_pMchMgr->SetLastError( 2418, "Error in Pocketing : Link not computable") ; // return false ; // } // } } // elaborazioni sulla curva corrente // elaborazioni sulla curva corrente double dMinFeed = GetFeed() * GetSideStep() / m_TParams.m_dDiam ; double dFeed = pCurve->GetTempProp( 0) / FEED_DIVISOR < dMinFeed - 50 * EPS_SMALL ? GetFeed() : pCurve->GetTempProp( 0) / FEED_DIVISOR ; DrawColoredCrvForFeedTest( pCurve, dFeed) ; SetFeed( dFeed) ; if ( pCurve->GetType() == CRV_LINE) { ICurveLine* pLine = GetCurveLine( pCurve) ; Point3d ptP3 = pLine->GetEnd() ; //SetFeed( dFeedRid * GetFeed()) ; if ( AddLinearMove( ptP3) == GDB_ID_NULL) return false ; } else if ( pCurve->GetType() == CRV_ARC) { ICurveArc* pArc = GetCurveArc( pCurve) ; Point3d ptCen = pArc->GetCenter() ; double dAngCen = pArc->GetAngCenter() ; Vector3d vtN = pArc->GetNormVersor() ; Point3d ptP3 ; pArc->GetEndPoint( ptP3) ; //SetFeed( dFeedRid * GetFeed()) ; if ( AddArcMove( ptP3, ptCen, dAngCen, vtN) == GDB_ID_NULL) return false ; } // SE ULTIMA ENTITA' if ( i == nMaxInd) { // se ultimo step, uscita e retrazione di collegamento //if ( j == nStep ) { // dati fine entità Point3d ptEnd ; pCurve->GetEndPoint( ptEnd) ; Vector3d vtEnd ; pCurve->GetEndDir( vtEnd) ; // aggiungo uscita //Point3d ptP1 ; <----------- ????????????? //double dEndElev = dElev ; //double dEndElev = dStElev ; double dEndElev ; if ( ! GetElevation( m_nPhase, ptEnd - 10 * EPS_SMALL * vtTool, vtTool, GetRadiusForStartEndElevation(), vtTool, dEndElev)) dEndElev = j * dStep ; dEndElev = max( dEndElev, j * dStep) ; SetFeed( GetEndFeed()) ; if ( ! AddLeadOut( ptEnd, vtEnd, vtExtr, nullptr, bSplitArcs, false, ptP1, dEndElev, false)) { m_pMchMgr->SetLastError( 2416, "Error in Pocketing : LeadOut not computable") ; return false ; } // aggiungo retrazione if ( ! AddLinkRetract( ptP1, vtTool, dSafeZ, dSafeAggrBottZ, dEndElev, dAppr)) { m_pMchMgr->SetLastError( 2418, "Error in Pocketing : Link not computable") ; return false ; } // } } } } // fine ciclo sulle curve di Offset i-esime // ===== SEGMENTI ========= // determino il riferimento in base alla svuotatura ( Serve per Orientare i segmenti in base al m_dSideAngle ) Frame3d frPocket ; Point3d ptCen ; pSrfFirstOffs->GetCentroid( ptCen) ; frPocket.Set( ptCen, vtExtr) ; frPocket.Rotate ( ptCen, vtExtr, m_Params.m_dSideAngle) ; pSrfFirstOffs->ToLoc( frPocket) ; BBox3d b3Pocket ; pSrfFirstOffs->GetLocalBBox( b3Pocket) ; Point3d ptMin ; double dDimX, dDimY, dDimZ ; b3Pocket.GetMinDim( ptMin, dDimX, dDimY, dDimZ) ; // passi in Y int nYStep = static_cast( ceil(( dDimY + 2 * dExtra) / GetSideStep())) ; double dYStep = ( nYStep > 0 ? ( dDimY + 2 * dExtra) / nYStep : 0) ; --nYStep ; // vettore dei segmenti al di sotto della linea corrente ( per la Feed) ICURVEPOVECTOR vLineUnder ; ICURVEPOVECTOR vLineAbove ; // in questo caso sempre vuoto ICRVCOMPOPOVECTOR vCrvLink ; // in questo caso sempre vuoto // calcolo le linee di svuotatura const double EXP_LEN = 1.0 ; //for ( int j = 1 ; j <= nStep ; ++j) { for ( int i = 1 ; i <= nYStep ; ++ i) { // definisco la linea PtrOwner pLine( CreateCurveLine()) ; Point3d ptStart( ptMin.x - EXP_LEN, ptMin.y + ( - dExtra + i * dYStep), ptMin.z + dDimZ) ; if ( IsNull( pLine) || ! pLine->SetPVL( ptStart, X_AX, dDimX + 2 * EXP_LEN)) { m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ; return false ; } // linea come composita per Feed ( la dovrò spezzare) PtrOwner pCrvCompo( CreateCurveComposite()) ; if ( IsNull( pCrvCompo)) return false ; // vettore di tutti i segmenti lineari che si formano nello step nYStep ICURVEPOVECTOR vAddedLines ; // riempio il vettore di segmenti CRVCVECTOR ccClassSeg ; pSrfFirstOffs->GetCurveClassification( *pLine, EPS_SMALL, ccClassSeg) ; for ( int w = 0 ; w < int( ccClassSeg.size()) ; ++w) { if ( ccClassSeg[w].nClass == CRVC_IN) { PtrOwner pCrvSeg( GetCurveLine( pLine->CopyParamRange( ccClassSeg[w].dParS, ccClassSeg[w].dParE))) ; double duF, dLen ; // accorcio leggermente il segmento per non toccare la prima curva di Offset if ( ! pCrvSeg->GetLength( dLen) || dLen < 2 * dExtra || ! pCrvSeg->GetParamAtLength( dLen - dExtra, duF) || ! pCrvSeg->TrimStartAtLen( dExtra) || ! pCrvSeg->TrimEndAtParam( duF)) pCrvSeg.Set( GetCurveLine( pLine->CopyParamRange( ccClassSeg[w].dParS, ccClassSeg[w].dParE))) ; Point3d ptS, ptE ; pCrvSeg->GetStartPoint( ptS) ; //pCrvSeg->GetEndPoint( ptE) ; // imposto la Feed //vAddedLines.emplace_back( pCrvSeg->Clone()) ; pCrvCompo->Clear() ; pCrvCompo->AddCurve( pCrvSeg->Clone()) ; vAddedLines.emplace_back( pCrvCompo->Clone()) ; if ( ! AssignFeedZigZagOneWay( pCrvCompo, false, vLineAbove, vLineUnder, vCrvLink)) return false ; //PtrOwner pCrvCompo( CreateCurveComposite()) ; //if ( IsNull( pCrvCompo)) // return false ; //pCrvCompo->AddCurve( pCrvSeg->Clone()) ; //if ( ! AssignFeedOneWay( pCrvSeg, pSrfRemoved) || // ! GetDynamicClearedRegion( pSrfRemoved, pCrvCompo)) // return false ; // INIZIO ptS.ToGlob( frPocket) ; ptS.Translate( -vtTool * ( dDepth - dElev + j * dStep)) ; // determino inizio attacco Point3d ptP ; if ( ! CalcLeadInStart( ptS, frPocket.VersX(), vtExtr, nullptr, ptP)) return false ; // determino elevazione su inizio attacco double dStElev ; if ( ! GetElevation( m_nPhase, ptS - 10 * EPS_SMALL * vtTool, vtTool, GetRadiusForStartEndElevation(), vtTool, dStElev)) dStElev = j * dStep ; bool bAhUnderRaw = m_bAboveHead && ! m_bAggrBottom && ! m_bTiltingTab && GetAhPointUnderRaw( ptP, vtTool, 0, GetRadiusForStartEndElevation(), m_TParams.m_dLen, false, dSafeZ, vtTool, dStElev) ; bool bUhAboveRaw = ! m_bAboveHead && GetUhPointAboveRaw( ptP, vtTool, 0, GetRadiusForStartEndElevation(), m_TParams.m_dLen, false, dSafeZ, vtTool, dStElev) ; if( bAhUnderRaw || bUhAboveRaw || ( i == 1 && w == 1)) dStElev = max( dStElev, j * dStep) ; dStElev -= ( ptP - ptS) * vtExtr ; // sempre approccio di collegamento if ( ! AddLinkApproach( ptP, vtTool, dSafeZ, dSafeAggrBottZ, dStElev, dAppr)) { m_pMchMgr->SetLastError( 2418, "Error in Pocketing : Link not computable") ; return false ; } // aggiungo attacco (forzato ad essere lineare) SetFeed( GetStartFeed()) ; if ( ! AddLeadIn( ptP, ptS, frPocket.VersX(), vtExtr, pSrfLeanInOut, nullptr, !m_Params.m_bInvert, bSplitArcs, true)) { m_pMchMgr->SetLastError( 2415, "Error in Pocketing : LeadIn not computable") ; return false ; } for ( int u = 0 ; u < pCrvCompo->GetCurveCount() ; ++ u) { //ptE.ToGlob( frPocket) ; //ptE.Translate( -vtTool * (dDepth - dElev + j * dStep)) ; const ICurve* pCurve( pCrvCompo->GetCurve( u)) ; pCurve->GetEndPoint( ptE) ; ptE.ToGlob( frPocket) ; ptE.Translate( -vtTool * ( dDepth - dElev + j * dStep)) ; // movimento al punto finale // elaborazioni sulla curva corrente double dMinFeed = GetFeed() * GetSideStep() / m_TParams.m_dDiam ; double dFeed = pCurve->GetTempProp( 0) / FEED_DIVISOR < dMinFeed - 50 * EPS_SMALL ? GetFeed() : pCurve->GetTempProp( 0) / FEED_DIVISOR ; SetFeed( dFeed) ; //PtrOwner pCrv_TestFeed( pCurve->Clone()) ; //pCrv_TestFeed->ToGlob( frPocket) ; //if ( abs( dFeed - GetMinFeed()) < EPS_SMALL) { // int rosso = m_pGeomDB->AddGeoObj(GDB_ID_NULL, GDB_ID_ROOT, pCrv_TestFeed->Clone()) ; // m_pGeomDB->SetMaterial( rosso, RED) ; //} //if ( abs( dFeed - GetMaxFeed()) < EPS_SMALL) { // int verde = m_pGeomDB->AddGeoObj(GDB_ID_NULL, GDB_ID_ROOT, pCrv_TestFeed->Clone()) ; // m_pGeomDB->SetMaterial( verde, GREEN) ; //} SetFeed( dFeed) ; //SetFeed( GetFeed()) ; if ( AddLinearMove( ptE) == GDB_ID_NULL) return false ; } // FINE Point3d ptQ ; //double dEndElev = dElev ; double dEndElev ; if ( ! GetElevation( m_nPhase, ptE - 10 * EPS_SMALL * vtTool, vtTool, GetRadiusForStartEndElevation(), vtTool, dEndElev)) dEndElev = j * dStep ; dEndElev = max( dEndElev, j * dStep) ; SetFeed( GetEndFeed()) ; if ( ! AddLeadOut( ptE, frPocket.VersX(), vtExtr, nullptr, bSplitArcs, true, ptQ, dEndElev)) { m_pMchMgr->SetLastError( 2416, "Error in Pocketing : LeadOut not computable") ; return false ; } // se ultimo movimento di ultima area, aggiungo retrazione globale if ( j == nStep && i == nYStep && w == ( int)ccClassSeg.size() - 2) { if ( ! AddRetract( ptQ, vtTool, dSafeZ, dSafeAggrBottZ, dEndElev, dAppr)) { m_pMchMgr->SetLastError( 2417, "Error in Pocketing : Retract not computable") ; return false ; } } // altrimenti aggiungo retrazione di collegamento else { if ( ! AddLinkRetract( ptQ, vtTool, dSafeZ, dSafeAggrBottZ, dEndElev, dAppr)) { m_pMchMgr->SetLastError( 2418, "Error in Pocketing : Link not computable") ; return false ; } } } } vLineUnder.clear() ; for ( int u = 0 ; u < ( int)vAddedLines.size() ; ++ u) vLineUnder.emplace_back( vAddedLines[u]->Clone()) ; } } // fine ciclo sugli step } // fine ciclo sulle superifici ideali return true ; } //---------------------------------------------------------------------------- bool Pocketing::AddSpiralIn( const ISurfFlatRegion* pSrfPock, const Vector3d& vtTool, const Vector3d& vtExtr, double dDepth, double dElev, double dOkStep, bool bSplitArcs) { // recupero distanze di sicurezza double dSafeZ = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeZ() ; double dSafeAggrBottZ = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeAggrBottZ() ; // lunghezza di approccio/retrazione double dAppr = m_Params.m_dStartPos ; // determino numero e affondamento degli step int nStep = 1 ; nStep = max( 1, static_cast( ceil( dElev / dOkStep))) ; double dStep = dElev / nStep ; // ciclo sui chunk della superificie da svuotare for ( int c = 0 ; c < pSrfPock->GetChunkCount() ; ++ c) { // copio il chunk c-esimo PtrOwner pSrfChunk( GetSurfFlatRegion( pSrfPock->CloneChunk( c))) ; if ( IsNull( pSrfChunk)) return false ; // -------------------------------------------------------------------------------------------------------- // 1) traslo il chunk c-esimo a seconda dello step e salvo la flat Region interna al grezzo // ( evito di lavorare nel vuoto sempre la stessa faccia ) // 2) Proietto il Box del grezzo del semipiano positivo definito della Flat Region ottenuta in precedenza // allargando in tangenza i lati chiusi fino al bordo di tale proiezione // ( evito di trascurare parti di grezzo nella tasche con normale non parallela alla faccia del grezzo ) ISURFFRPOVECTOR vSrfSliced( nStep) ; vector vCrvOEWithFlags( nStep) ; BOOLVECTOR vbChangedPrec( nStep, false) ; // modifico le superifici in base alla geometria del grezzo if ( ! GetParamsAtEachStep( vSrfSliced, vCrvOEWithFlags, vbChangedPrec, pSrfChunk, nStep, vtTool, dElev, dDepth, dStep)) return false ; //return false ; Point3d ptP1 ; // per LeadIn // ciclo su tutti gli step for ( int j = 1 ; j <= nStep ; ++ j) { // se superificie non valida, salto allo step successivo if ( IsNull( vSrfSliced[ j-1]) || vSrfSliced[j-1]->GetChunkCount() == 0) { vSrfSliced[j-1].Set( pSrfChunk->Clone()) ; continue ; } // la superificie che lavoro è quella ottenuta in precedenza allo step j-esimo PtrOwner pSrfFinal( CloneSurfFlatRegion( vSrfSliced[j - 1])) ; if ( IsNull( pSrfFinal)) return false ; for ( int cc = 0 ; cc < ( int)pSrfFinal->GetChunkCount() ; ++ cc) { // per ogni suo chunk cc-esimo... // il numero di chunk dopo aver intersecato e proiettato con/il grezzo può cambiare // essendo una svuotatura a spirale, facendo il primo offset del chunk cc-esimo potrei ottenere // ulteriori chunks ( ad esempio se la superificie presenta delle parti molto strette ) // MAX_REGS = 50 -> # massimo di Chunks nuovi accettati const int MAX_REGS = 50 ; int nReg = 0 ; // chunk nuovo corrente da svuotare PtrOwner pSrfChunkFinal( pSrfFinal->CloneChunk( cc)) ; // ciclo su tutte le regioni che posso ottenere col primo Offset del chunc cc-esimo while ( nReg < MAX_REGS) { // superifice per ingressi ed uscite PtrOwner pSrfLeanInOut( CloneSurfFlatRegion( pSrfChunkFinal)) ; if ( IsNull( pSrfLeanInOut)) return false ; // calcolo la spirale dall'esterno all'interno e la curva che unisce inizio e fine PtrOwner pMCrv( CreateCurveComposite()) ; // percorso di svuotatura PtrOwner pRCrv( CreateCurveComposite()) ; // percorso di ritorno if ( IsNull( pMCrv) || IsNull( pRCrv)) { m_pMchMgr->SetLastError( 2411, "Error in Pocketing : toolpath allocation failed") ; return false ; } // se lucidatura con epicicli if ( m_TParams.m_nType == TT_MILL_POLISHING && m_Params.m_dEpicyclesRad > EPS_SMALL) { // verifico che i parametri lucidatura siano sensati if ( m_Params.m_dEpicyclesDist < 100 * EPS_SMALL) { m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ; return false ; } // modifico il diametro dell'utensile per tenere conto anche del diametro degli epicicli m_TParams.m_dDiam += 2 * m_Params.m_dEpicyclesRad ; } bool bOptimizedTrap = false ; // ---------------------------------------------------------------------------------- // Dopo che il chunk c-esimo è stato intersecato con il grezzo e allargato grazie alla proiezione, // salvo il bordo ( con i flag dei lati aperti ) per il caso del trapezio ottimizzato. // tuttavia, nel caso di più Chunks, devo individuare la curva originaria relativa al chunk cc-esimo // ... il chunk cc-esimo non può avere parti esterne alla sua curva originaria int nInd = 0 ; // indice del vettore delle curve esterne relativo al chunk cc-esimo // cerco la curva originale del chunk cc-esimo if (( int)vCrvOEWithFlags[j-1].size() == 1) nInd = 0 ; else { for ( int k = 0 ; k < ( int)vCrvOEWithFlags[j-1].size() ; ++ k) { CRVCVECTOR ccClass ; if ( pSrfChunkFinal->GetCurveClassification( *vCrvOEWithFlags[j-1][k], EPS_SMALL, ccClass)) { bool bIsThis = true ; for ( int kk = 0 ; kk < ( int)ccClass.size() && bIsThis ; ++ kk) { if ( ccClass[kk].nClass == CRVC_OUT) bIsThis = false ; } if( bIsThis) { nInd = k ; break ; } } } } // ------------------------------------------------------------------------------------ Point3d ptStart ; // punto iniziale del percorso Vector3d vtMidOut ; // vettore verso l'esterno nel caso di entrata da fuori ammissibile bool bMidOut ; // ammissibilità entrata da fuori int nRegTot = nReg ; //int k = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSrfChunkFinal->Clone()) ; //m_pGeomDB->SetMaterial( k, WHITE) ; // calcolo il percorso di svuotatura if ( ! CalcSpiral( pSrfChunkFinal, nRegTot, ptStart, vtMidOut, bMidOut, bSplitArcs, pMCrv, pRCrv, vCrvOEWithFlags[j-1][nInd], bOptimizedTrap)) return false ; // se terminate le regioni, esco if ( pMCrv->GetCurveCount() == 0) break ; // passo al chunk originale successivo ++nReg ; if ( m_TParams.m_nType == TT_MILL_POLISHING && m_Params.m_dEpicyclesRad > EPS_SMALL) { // riporto il diametro dell'utensile al valore originale m_TParams.m_dDiam -= 2 * m_Params.m_dEpicyclesRad ; // aggiorno i percorsi di svuotatura con epicicli if ( ! ComputePolishingPath( pMCrv, pRCrv, bSplitArcs)) { m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ; return false ; } } // controlli per entrate da fuori al grezzo bool bOutStart = bMidOut ; if ( bOutStart && ! bOptimizedTrap) { // calcolo il punto fuori per il LeadIn Point3d ptOut = ptStart + vtMidOut * ( 0.5 * m_TParams.m_dDiam + dSafeZ) ; ptOut.Translate( -vtTool * ( dDepth - dElev + j * dStep)) ; // lo traslo allo step corrente double dStElev ; // controllo l'elevazione bOutStart = ( ! GetElevation( m_nPhase, ptOut, vtTool, 0.5 * m_TParams.m_dDiam, vtTool, dStElev) || dStElev < EPS_SMALL) ; if ( bOutStart || m_bOpenOutRaw) { // aggiungo al ritorno l'uscita if ( pRCrv->GetCurveCount() == 0) { Point3d ptStart ; pMCrv->GetStartPoint( ptStart) ; pRCrv->AddPoint( ptStart) ; } ptOut.Translate( vtTool * ( dDepth - dElev + j * dStep)) ; // lo ritraslo sulla curva // aggiungo un tratto lineare all'inizio del percorso di svuotatura pMCrv->AddLine( ptOut, false) ; // assegno la sua Feed AssignFeedForLineInOut( pMCrv, true) ; // aggiungo un tratto lineare alla fine del percorso di svuotatura pRCrv->AddLine( ptOut, true) ; // assegno la sua Feed AssignFeedForLineInOut( pRCrv, false) ; } } // calcolo gli eventuali punti fuori dal grezzo nel caso ottimizzato int nOutsideRaw = 0 ; if ( bOptimizedTrap) { AdjustTrapezoidSpiralForLeadInLeadOut( pMCrv, pRCrv, vtTool, dDepth, nOutsideRaw) ; bOutStart = ( nOutsideRaw > 0) ; // imposto la Feed AssignFeedSpiralOpt( 1, pMCrv) ; AssignFeedForReturnPath( pRCrv) ; } // verifico se l'ingresso è da considerare fuori dal grezzo anche se dentro bool bForcedOutStart = ( bMidOut && m_bOpenOutRaw) ; // se utensile che non lavora di testa e ingresso non fuori dal pezzo, errore //if ( m_TParams.m_nType == TT_MILL_NOTIP && ! bOutStart && ! bForcedOutStart) { if ( m_TParams.m_nType == TT_MILL_NOTIP && ! ( bOutStart || bForcedOutStart)) { if ( ! LeadInRawIsOk()) { m_pMchMgr->SetLastError( 2431, "Error in Pocketing : LeadIn with Mill NoTip in material") ; return false ; } } int nMaxInd = pMCrv->GetCurveCount() - 1 ; int nMaxRInd = pRCrv->GetCurveCount() - 1 ; // se sono nel caso ottimizzato e ho attacco e uscita entrambi dentro/fuori dal grezzo, // ad ogni step pari inverto la direzione della curva solamente se ho un solo chunk e la superificie successiva // non è cambiata if ( bOptimizedTrap && nOutsideRaw != 1 && j > 1 && vSrfSliced[j-2]->GetChunkCount() == 1 && ! vbChangedPrec[j-1] && ( j % 2 == 0)) pMCrv->Invert() ; // ciclo sulle curve elementari for ( int i = 0 ; i <= nMaxInd ; ++ i) { // curva corrente const ICurve* pCrvC = pMCrv->GetCurve( i) ; // copio la curva PtrOwner pCurve( pCrvC->Clone()) ; if ( IsNull( pCurve)) return false ; // aggiungo affondamento pCurve->Translate( -vtTool * (dDepth - dElev + j * dStep)) ; // se prima entità if ( i == 0) { // dati inizio entità Point3d ptStart ; pCurve->GetStartPoint( ptStart) ; Vector3d vtStart ; pCurve->GetStartDir( vtStart) ; // Entrata ... if ( j == 1 || vbChangedPrec[j-1] || vSrfSliced[j-2]->GetChunkCount() > 1 || nRegTot > 1) { // Ricalcolo il punto di attacco sopra al PtStart ( modificato in precedenza dal PtOut ) quando : // 1) sono nel primo Step o ... // 2) la superificie è diversa da quello dello step precedente o ... // 3) il numero di chunk allo step precedente è maggiore di 1 o ... // 4) dal primo offset del chunk cc-esimo ottengo più regioni o ... // determino inizio attacco if ( ! CalcLeadInStart( ptStart, vtStart, vtExtr, pRCrv, ptP1)) return false ; // determino elevazione su inizio attacco (se non trovata, elevazione è step) double dStElev ; if ( ! GetElevation( m_nPhase, ptStart - 10 * EPS_SMALL * vtTool, vtTool, GetRadiusForStartEndElevation(), vtTool, dStElev)) dStElev = dStep ; bool bAhUnderRaw = m_bAboveHead && ! m_bAggrBottom && ! m_bTiltingTab && GetAhPointUnderRaw( ptP1, vtTool, 0, GetRadiusForStartEndElevation(), m_TParams.m_dLen, false, dSafeZ, vtTool, dStElev) ; bool bUhAboveRaw = ! m_bAboveHead && GetUhPointAboveRaw( ptP1, vtTool, 0, GetRadiusForStartEndElevation(), m_TParams.m_dLen, false, dSafeZ, vtTool, dStElev) ; //if ( bAhUnderRaw || bUhAboveRaw ) dStElev = max( dStElev, j * dStep) ; dStElev -= ( ptP1 - ptStart) * vtExtr ; // se attacco a zigzag o a spirale o a scivolo, l'elevazione va nell'attacco if ( GetLeadInType() == POCKET_LI_ZIGZAG || GetLeadInType() == POCKET_LI_HELIX || GetLeadInType() == POCKET_LI_GLIDE) { ptP1 += vtExtr * dStElev ; dStElev = 0 ; } // approccio al punto iniziale if ( ! AddApproach( ptP1, vtTool, dSafeZ, dSafeAggrBottZ, dStElev, dAppr, bOutStart || bForcedOutStart)) { m_pMchMgr->SetLastError( 2414, "Error in Pocketing : Approach not computable") ; return false ; } // aggiungo attacco SetFeed( GetStartFeed()) ; if ( ! AddLeadIn( ptP1, ptStart, vtStart, vtExtr, pSrfLeanInOut, pRCrv, !m_Params.m_bInvert, bSplitArcs, bOutStart || bForcedOutStart)) { m_pMchMgr->SetLastError( 2415, "Error in Pocketing : LeadIn not computable") ; return false ; } } // altrimenti solo collegamento else { SetFeed( GetStartFeed()) ; GetCurrPos( ptP1) ; if ( ! AddLeadIn( ptP1, ptStart, vtStart, vtExtr, pSrfLeanInOut, pRCrv, !m_Params.m_bInvert, bSplitArcs, bOutStart || bForcedOutStart)) { m_pMchMgr->SetLastError( 2418, "Error in Pocketing : Link not computable") ; return false ; } } } // elaborazioni sulla curva corrente double dMinFeed = GetFeed() * GetSideStep() / m_TParams.m_dDiam ; double dFeed = pCurve->GetTempProp( 0) / FEED_DIVISOR < dMinFeed - 50 * EPS_SMALL ? GetFeed() : pCurve->GetTempProp( 0) / FEED_DIVISOR ; DrawColoredCrvForFeedTest( pCurve, dFeed) ; SetFeed( dFeed) ; if ( pCurve->GetType() == CRV_LINE) { ICurveLine* pLine = GetCurveLine( pCurve) ; Point3d ptP3 = pLine->GetEnd() ; //SetFeed( GetFeed()) ; //SetFeed( pCurve->GetTempProp( 0) / FEED_DIVISOR) ; if ( AddLinearMove( ptP3) == GDB_ID_NULL) return false ; } else if ( pCurve->GetType() == CRV_ARC) { ICurveArc* pArc = GetCurveArc( pCurve) ; Point3d ptCen = pArc->GetCenter() ; double dAngCen = pArc->GetAngCenter() ; Vector3d vtN = pArc->GetNormVersor() ; Point3d ptP3 ; pArc->GetEndPoint( ptP3) ; //SetFeed( GetFeed()) ; //SetFeed( pCurve->GetTempProp( 0) / FEED_DIVISOR) ; if ( AddArcMove( ptP3, ptCen, dAngCen, vtN) == GDB_ID_NULL) return false ; } // se ultima entità -> passo al chunk cc successivo o allo step sotto if ( i == nMaxInd) { // Uscita ... if ( j < nStep && vSrfSliced[j-1]->GetChunkCount() == 1 && ! vbChangedPrec[j] && nRegTot == 1) { // Effettuo l'uscita quando : // 1) non sono nello step intermedio e ... // 2) il numero di Chunk allo step attuale è 1 e... // 3) la superificie non è cambiata dalla precedente e... // 4) dal primo offset del chunk cc-esimo non si sono create altre regioni da svuotare // se necessario ritorno all'inizio if ( nMaxRInd >= 0) { // copio la curva di ritorno PtrOwner pRet( pRCrv->Clone()) ; if ( IsNull( pRet)) return false ; // aggiungo affondamento pRet->Translate( -vtTool * ( dDepth - dElev + j * dStep)) ; // se attacco a scivolo, accorcio della lunghezza dell'attacco if ( GetLeadInType() == POCKET_LI_GLIDE) { double dLen ; pRet->GetLength( dLen) ; if ( dLen > m_Params.m_dLiTang + 10 * EPS_SMALL) pRet->TrimEndAtLen( dLen - m_Params.m_dLiTang) ; else pRet->Clear() ; } // emetto SetFeed( GetFeed()) ; if ( pRet->GetCurveCount() > 0 && AddCurveMove( pRet) == GDB_ID_NULL) return false ; } } // atrimenti ultimo step, uscita e retrazione else { // dati fine entità Point3d ptEnd ; pCurve->GetEndPoint( ptEnd) ; Vector3d vtEnd ; pCurve->GetEndDir( vtEnd) ; // aggiungo uscita Point3d ptP1 ; double dEndElev = j * dStep ; SetFeed( GetEndFeed()) ; if ( ! AddLeadOut( ptEnd, vtEnd, vtExtr, pRCrv, bSplitArcs, false, ptP1, dEndElev, false)) { m_pMchMgr->SetLastError( 2416, "Error in Pocketing : LeadOut not computable") ; return false ; } // aggiungo retrazione if ( ! AddRetract( ptP1, vtTool, dSafeZ, dSafeAggrBottZ, dEndElev, dAppr)) { m_pMchMgr->SetLastError( 2417, "Error in Pocketing : Retract not computable") ; return false ; } } } } } } } } return true ; } //---------------------------------------------------------------------------- bool Pocketing::AddSpiralOut( const ISurfFlatRegion* pSrfPock, const Vector3d& vtTool, const Vector3d& vtExtr, double dDepth, double dElev, double dOkStep, bool bSplitArcs) { // recupero distanze di sicurezza double dSafeZ = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeZ() ; double dSafeAggrBottZ = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeAggrBottZ() ; // lunghezza di approccio/retrazione double dAppr = m_Params.m_dStartPos ; // determino numero e affondamento degli step int nStep = 1 ; nStep = max( 1, static_cast( ceil( dElev / dOkStep))) ; double dStep = dElev / nStep ; // ciclo sui chunk della superificie da svuotare for ( int c = 0 ; c < pSrfPock->GetChunkCount() ; ++ c) { // copio il chunk c-esimo PtrOwner pSrfChunk( GetSurfFlatRegion( pSrfPock->CloneChunk( c))) ; if ( IsNull( pSrfChunk)) return false ; // -------------------------------------------------------------------------------------------------------- ISURFFRPOVECTOR vSrfSliced( nStep) ; vector vCrvOEWithFlags( nStep) ; BOOLVECTOR vbChangedPrec( nStep, false) ; // modifico le superifici in base alla geometria del grezzo if ( ! GetParamsAtEachStep( vSrfSliced, vCrvOEWithFlags, vbChangedPrec, pSrfChunk, nStep, vtTool, dElev, dDepth, dStep)) return false ; Point3d ptP1 ; // ciclo su tutti gli step for ( int j = 1 ; j <= nStep ; ++ j) { // se superificie non valida, salto allo step successivo if ( IsNull( vSrfSliced[ j-1]) || vSrfSliced[j-1]->GetChunkCount() == 0) { vSrfSliced[j-1].Set( pSrfChunk->Clone()) ; continue ; } // la superificie che lavoro è quella ottenuta in precedenza allo step j-esimo PtrOwner pSrfFinal( CloneSurfFlatRegion( vSrfSliced[j - 1])) ; if( IsNull( pSrfFinal)) return false ; for( int cc = 0 ; cc < ( int)pSrfFinal->GetChunkCount() ; ++ cc) { // per ogni suo chunk cc-esimo... const int MAX_REGS = 50 ; int nReg = 0 ; PtrOwner pSrfChunkFinal(( pSrfFinal->CloneChunk( cc))) ; while ( nReg < MAX_REGS) { // superificie per ingressi ed uscite PtrOwner pSrfLeanInOut( CloneSurfFlatRegion( pSrfChunkFinal)) ; if( IsNull( pSrfLeanInOut)) return false ; // calcolo la spirale dall'interno all'esterno PtrOwner pMCrv( CreateCurveComposite()) ; PtrOwner pRCrv( CreateCurveComposite()) ; if ( IsNull( pMCrv) || IsNull( pRCrv)) { m_pMchMgr->SetLastError( 2411, "Error in Pocketing : toolpath allocation failed") ; return false ; } // se lucidatura con epicicli if ( m_TParams.m_nType == TT_MILL_POLISHING && m_Params.m_dEpicyclesRad > EPS_SMALL) { // verifico che parametri lucidatura siano sensati if ( m_Params.m_dEpicyclesDist < 100 * EPS_SMALL) { m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ; return false ; } // modifico il diametro dell'utensile per tenere conto anche del raggio degli epicicli m_TParams.m_dDiam += 2 * m_Params.m_dEpicyclesRad ; } bool bOptimizedTrap = false ; int nInd = 0 ; // cerco la curva originale del chunk cc-esimo if (( int)vCrvOEWithFlags[j-1].size() == 1) nInd = 0 ; else { for ( int k = 0 ; k < ( int)vCrvOEWithFlags[j-1].size() ; ++ k) { CRVCVECTOR ccClass ; if ( pSrfChunkFinal->GetCurveClassification( *vCrvOEWithFlags[j-1][k], EPS_SMALL, ccClass)) { bool bIsThis = true ; for ( int kk = 0 ; kk < ( int)ccClass.size() && bIsThis ; ++ kk) { if ( ccClass[kk].nClass == CRVC_OUT) bIsThis = false ; } if ( bIsThis) { nInd = k ; break ; } } } } Point3d ptStart ; Vector3d vtMidOut ; bool bMidOut ; int nRegToT = nReg ; if ( ! CalcSpiral( pSrfChunkFinal, nRegToT, ptStart, vtMidOut, bMidOut, bSplitArcs, pMCrv, pRCrv, vCrvOEWithFlags[j-1][nInd], bOptimizedTrap)) return false ; // se terminate le regioni, esco if ( pMCrv->GetCurveCount() == 0) break ; ++nReg ; if ( m_TParams.m_nType == TT_MILL_POLISHING && m_Params.m_dEpicyclesRad > EPS_SMALL) { // riporto il diametro dell'utensile al valore originale m_TParams.m_dDiam -= 2 * m_Params.m_dEpicyclesRad ; // aggiorno i percorsi di svuotatura con epicicli if ( ! ComputePolishingPath( pMCrv, pRCrv, bSplitArcs)) { m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ; return false ; } } // nel caso ottimizzato verifico se posso entrare e uscire fuori dal grezzo bool bOutStart = false ; int nOutsideRaw = 0 ; if ( bOptimizedTrap) { AdjustTrapezoidSpiralForLeadInLeadOut( pMCrv, pRCrv, vtTool, dDepth, nOutsideRaw) ; bOutStart = ( nOutsideRaw > 0) ; AssignFeedSpiralOpt( 1, pMCrv) ; AssignFeedForReturnPath( pRCrv) ; } // se utensile che non lavora di testa e ingresso non fuori dal pezzo, errore if ( m_TParams.m_nType == TT_MILL_NOTIP && ! bOutStart) { if ( ! LeadInRawIsOk()) { m_pMchMgr->SetLastError( 2431, "Error in Pocketing : LeadIn with Mill NoTip in material") ; return false ; } } // inverto i percorsi, perchè sono calcolati dall'esterno all'interno (solo nel caso non ottimizzato) if ( ! bOptimizedTrap) { pMCrv->Invert() ; pRCrv->Invert() ; } int nMaxInd = pMCrv->GetCurveCount() - 1 ; int nMaxRInd = pRCrv->GetCurveCount() - 1 ; // ciclo sugli step if ( bOptimizedTrap && nOutsideRaw != 1 && j > 1) pMCrv->Invert() ; // ciclo sulle curve elementari for ( int i = 0 ; i <= nMaxInd ; ++ i) { // curva corrente const ICurve* pCrvC = pMCrv->GetCurve( i) ; // copio la curva PtrOwner pCurve( pCrvC->Clone()) ; if ( IsNull( pCurve)) return false ; // aggiungo affondamento pCurve->Translate( -vtTool * (dDepth - dElev + j * dStep)) ; // se prima entità if ( i == 0) { // dati inizio entità Point3d ptStart ; pCurve->GetStartPoint( ptStart) ; Vector3d vtStart ; pCurve->GetStartDir( vtStart) ; // se primo step, approccio e affondo if ( j == 1 || vbChangedPrec[j-1] || vSrfSliced[j-2]->GetChunkCount() > 1 || nRegToT > 1) { // determino inizio attacco if ( ! CalcLeadInStart( ptStart, vtStart, vtExtr, pRCrv, ptP1)) { m_pMchMgr->SetLastError( 2415, "Error in Pocketing : LeadIn not computable") ; return false ; } // determino elevazione su inizio attacco double dStElev ; if ( ! GetElevation( m_nPhase, ptStart - 10 * EPS_SMALL * vtTool, vtTool, GetRadiusForStartEndElevation(), vtTool, dStElev)) dStElev = dStep ; bool bAhUnderRaw = m_bAboveHead && ! m_bAggrBottom && ! m_bTiltingTab && GetAhPointUnderRaw( ptP1, vtTool, 0, GetRadiusForStartEndElevation(), m_TParams.m_dLen, false, dSafeZ, vtTool, dStElev) ; bool bUhAboveRaw = ! m_bAboveHead && GetUhPointAboveRaw( ptP1, vtTool, 0, GetRadiusForStartEndElevation(), m_TParams.m_dLen, false, dSafeZ, vtTool, dStElev) ; //if ( bAhUnderRaw || bUhAboveRaw || ( bOutStart && !m_bAboveHead)) dStElev = max( dStElev, j* dStep) ; dStElev -= ( ptP1 - ptStart) * vtExtr ; // se attacco a zigzag o a spirale o a scivolo, l'elevazione va nell'attacco if ( GetLeadInType() == POCKET_LI_ZIGZAG || GetLeadInType() == POCKET_LI_HELIX || GetLeadInType() == POCKET_LI_GLIDE) { ptP1 += vtExtr * dStElev ; dStElev = 0 ; } // approccio al punto iniziale if ( ! AddApproach( ptP1, vtTool, dSafeZ, dSafeAggrBottZ, dStElev, dAppr, false)) { m_pMchMgr->SetLastError( 2414, "Error in Pocketing : Approach not computable") ; return false ; } // aggiungo attacco SetFeed( GetStartFeed()) ; if ( ! AddLeadIn( ptP1, ptStart, vtStart, vtExtr, pSrfLeanInOut, pRCrv, m_Params.m_bInvert, bSplitArcs, bOutStart)) { m_pMchMgr->SetLastError( 2415, "Error in Pocketing : LeadIn not computable") ; return false ; } } // altrimenti solo collegamento else { SetFeed( GetStartFeed()) ; GetCurrPos( ptP1) ; if ( ! AddLeadIn( ptP1, ptStart, vtStart, vtExtr, pSrfLeanInOut, pRCrv, m_Params.m_bInvert, bSplitArcs, bOutStart)) { m_pMchMgr->SetLastError( 2418, "Error in Pocketing : Link not computable") ; return false ; } } } // elaborazioni sulla curva corrente double dMinFeed = GetFeed() * GetSideStep() / m_TParams.m_dDiam ; double dFeed = pCurve->GetTempProp( 0) / FEED_DIVISOR < dMinFeed - 50 * EPS_SMALL ? GetFeed() : pCurve->GetTempProp( 0) / FEED_DIVISOR ; DrawColoredCrvForFeedTest( pCurve, dFeed) ; SetFeed( dFeed) ; if ( pCurve->GetType() == CRV_LINE) { ICurveLine* pLine = GetCurveLine( pCurve) ; Point3d ptP3 = pLine->GetEnd() ; //SetFeed( GetFeed()) ; //SetFeed( pCurve->GetTempProp( 0) / FEED_DIVISOR) ; if ( AddLinearMove( ptP3) == GDB_ID_NULL) return false ; } else if ( pCurve->GetType() == CRV_ARC) { ICurveArc* pArc = GetCurveArc( pCurve) ; Point3d ptCen = pArc->GetCenter() ; double dAngCen = pArc->GetAngCenter() ; Vector3d vtN = pArc->GetNormVersor() ; Point3d ptP3 ; pArc->GetEndPoint( ptP3) ; //SetFeed( GetFeed()); //SetFeed( pCurve->GetTempProp( 0 ) / FEED_DIVISOR) ; if ( AddArcMove( ptP3, ptCen, dAngCen, vtN) == GDB_ID_NULL) return false ; } // se ultima entità if ( i == nMaxInd) { // se step intermedio if ( j < nStep && vSrfSliced[j-1]->GetChunkCount() == 1 && !vbChangedPrec[j] && nRegToT == 1) { // se necessario ritorno all'inizio if ( nMaxRInd >= 0) { // copio la curva di ritorno PtrOwner pRet( pRCrv->Clone()) ; if ( IsNull( pRet)) return false ; // aggiungo affondamento pRet->Translate( -vtTool * ( dDepth - dElev + j * dStep)) ; // se attacco a scivolo, accorcio della lunghezza dell'attacco if ( GetLeadInType() == POCKET_LI_GLIDE) { double dLen ; pRet->GetLength( dLen) ; if ( dLen > m_Params.m_dLiTang + 10 * EPS_SMALL) pRet->TrimEndAtLen( dLen - m_Params.m_dLiTang) ; else pRet->Clear() ; } // emetto SetFeed( GetFeed()) ; if ( pRet->GetCurveCount() > 0 && AddCurveMove( pRet) == GDB_ID_NULL) return false ; } } // atrimenti ultimo step, uscita e retrazione else { // dati fine entità Point3d ptEnd ; pCurve->GetEndPoint( ptEnd) ; Vector3d vtEnd ; pCurve->GetEndDir( vtEnd) ; // aggiungo uscita Point3d ptQ ; double dEndElev = j * dStep ; SetFeed( GetEndFeed()) ; if ( ! AddLeadOut( ptEnd, vtEnd, vtExtr, pRCrv, bSplitArcs, false, ptQ, dEndElev, false)) { m_pMchMgr->SetLastError( 2416, "Error in Pocketing : LeadOut not computable") ; return false ; } // aggiungo retrazione if ( ! AddRetract( ptQ, vtTool, dSafeZ, dSafeAggrBottZ, dEndElev, dAppr)) { m_pMchMgr->SetLastError( 2417, "Error in Pocketing : Retract not computable") ; return false ; } } } } } } } } return true ; } //---------------------------------------------------------------------------- bool Pocketing::CalcSpiral( const ISurfFlatRegion* pSrfPock, int& nReg, Point3d& ptStart, Vector3d& vtMidOut , bool& bMidOut, bool bSplitArcs,ICurveComposite* pMCrv, ICurveComposite* pRCrv, ICurveComposite* pCrvOEWithFlags, bool& bOptimizedTrap) { // inizializzo i risultati pMCrv->Clear() ; pRCrv->Clear() ; // primo offset pari al raggio utensile + sovramateriale double dTRad = 0.5 * m_TParams.m_dDiam ; double dOffs = dTRad + GetOffsR() ; // recupero il versore normale della superificie, ruotandola nel piano XY PtrOwner pSrfToWork( pSrfPock->Clone()) ; if ( IsNull( pSrfToWork) || pSrfToWork->GetChunkCount() == 0) return false; // controllo se ho isole per i casi ottimizzati bool bHasIsland = pSrfPock->GetLoopCount( 0) > 1 ; // se non ho isole allora controllo casi ottimizzati if ( ! bHasIsland) { // caso spirale PtrOwner pCrvBorder( GetCurveComposite( pSrfPock->GetLoop( 0, 0))) ; Point3d ptCen ; Vector3d vtN ; double dRad ; bool bCCW ; //m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCrvBorder->Clone()) ; if ( pCrvBorder->IsACircle( 100 * EPS_SMALL, ptCen, vtN, dRad, bCCW)) { double dIntRad = 0 ; if ( m_Params.m_nSubType == POCKET_SUB_SPIRALOUT && GetLeadInType() == POCKET_LI_HELIX) { dIntRad = min( 0.5 * min( m_Params.m_dLiTang, m_TParams.m_dDiam), dRad - dOffs) ; m_dMaxHelixRad = dIntRad ; } if ( nReg == 0) { bool bOk = CalcCircleSpiral( ptCen, vtN, dRad - dOffs, dIntRad, bSplitArcs, pMCrv, pRCrv) ; if ( bOk) { pMCrv->GetStartPoint( ptStart) ; nReg = 1 ; pMCrv->GetStartDir( vtMidOut) ; Vector3d vtExtr ; pMCrv->GetExtrusion( vtExtr) ; vtMidOut.Rotate( vtExtr, 0, m_Params.m_bInvert ? 1 : -1) ; bMidOut = pCrvBorder->GetFirstCurve()->GetTempProp() == 1 ; return true ; } else return false ; } else return true ; } // caso trapezoide pCrvOEWithFlags->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL, true, true) ; Point3d pt ; Vector3d vtB1, vtL1, vtB2 ; if ( pCrvOEWithFlags->IsATrapezoid( 100 * EPS_SMALL, pt, vtB1, vtL1, vtB2)) { Vector3d vtDir( vtB1), vtOtherDir( vtL1) ; // se parallelogramma scelgo come base i lati lunghi Vector3d vtL2( - vtB1 + vtL1 + vtB2) ; if ( AreSameOrOppositeVectorApprox( vtL1, vtL2)) { if ( vtL1.Len() > vtB1.Len()) swap( vtDir, vtOtherDir) ; } vtDir.Normalize() ; Vector3d vtOrtho = OrthoCompo( vtOtherDir, vtDir) ; double dPocketSize = vtOrtho.Len() ; double dMaxOptSize ; FromString( ExtractInfo( m_Params.m_sUserNotes, "MaxOptSize="), dMaxOptSize) ; if ( dPocketSize < m_TParams.m_dDiam + EPS_SMALL && ( ! FromString( ExtractInfo( m_Params.m_sUserNotes, "MaxOptSize="), dMaxOptSize) || dPocketSize < dMaxOptSize)) { if ( nReg == 0) { CalcTrapezoidSpiral( pCrvOEWithFlags, vtDir, dPocketSize, pMCrv, pRCrv, bOptimizedTrap) ; if ( bOptimizedTrap) { nReg = 1 ; return true ; } } else return true ; } } } // porto il Chunk c-esimo nel sistema di riferimento locale (assieme al punto inziale) Vector3d vtExtr = pSrfToWork->GetNormVersor() ; Point3d ptCen ; pSrfToWork->GetCentroid( ptCen) ; Frame3d frPocket ; frPocket.Set( ptCen, vtExtr) ; pSrfToWork->ToLoc( frPocket) ; // ciclo di offset verso l'interno const int MAX_ITER = 1000 ; int nIter = 0 ; ICRVCOMPOPOVECTOR vOffs ; // vettore delle curve di offset ICRVCOMPOPOVECTOR vOffsFirstCurve ; // curve di primo offset PtrOwner pSrfAct( CloneSurfFlatRegion( pSrfToWork)) ; // regione attuale PtrOwner pSrfPrec( CloneSurfFlatRegion( pSrfToWork)) ; // regione precedente if( IsNull( pSrfAct) || IsNull( pSrfPrec) || pSrfAct->GetChunkCount() == 0 || pSrfPrec->GetChunkCount() == 0) return false ; while ( nIter < MAX_ITER) { // salvo la regione pSrfPrec.Set( pSrfAct->Clone()) ; if ( ! pSrfAct->Offset( - dOffs, ICurve::OFF_FILLET)) { int nbadOffs = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSrfPrec->Clone()) ; m_pGeomDB->Save( nbadOffs, "C:\\Users\\riccardo.elitropi\\Desktop\\Err_offs" + ToString( nbadOffs) + "__m" + ToString( dOffs) + ".nge") ; return false ; } // estraggo il contorno della FlatRegion (ciclo i Chunks e prendo i rispettivi Loops) if ( nIter == 0) { PtrOwner pSrfChunknReg( pSrfAct->CloneChunk( nReg)) ; nReg = pSrfAct->GetChunkCount() ; // modifico nReg per le uscite if ( IsNull( pSrfChunknReg)) // se supero i chunk ottenuti return true ; pSrfAct.Set( pSrfChunknReg) ; } int nChunks = pSrfAct->GetChunkCount(); for ( int i = 0 ; i < nChunks ; ++ i) { // per ogni chunk... int nLoops = pSrfAct->GetLoopCount( i) ; for ( int j = 0 ; j < nLoops ; ++ j) { // per ogni loop... PtrOwner ptoCCBorder( GetCurveComposite( pSrfAct->GetLoop( i, j))) ; if ( j > 0) // inverto l'orientamento delle curve interne (offset delle isole trovate) ptoCCBorder->Invert() ; // controllo quali regioni di Offset possono essere sostituite bool bInsert = true ; if ( ! CheckIfOffsetIsNecessary( ptoCCBorder, dOffs, ( int)vOffs.size(), nIter, vtExtr, bInsert)) return false ; if ( bInsert) { vOffs.emplace_back( Release( ptoCCBorder)) ; } PtrOwner ptoCCExtBorder( GetCurveComposite( pSrfAct->GetLoop( i, j))) ; if ( nIter == 0) { // salvo il bordo per i link (non invertiti) vOffsFirstCurve.emplace_back( Release( ptoCCExtBorder)) ; } } } bool bSmallRad = ( nIter == 0 ? dOffs < dTRad + GetOffsR() + EPS_ZERO : dOffs < dTRad + EPS_ZERO) ; if ( nChunks > 0) { dOffs = GetSideStep() ; } else if ( ! bSmallRad) { pSrfAct.Set( pSrfPrec) ; dOffs = ( nIter == 0 ? dTRad + GetOffsR() : dTRad) ; } else break ; ++ nIter ; } // se non ho trovato curve di Offset allora esco if (( int)vOffs.size() == 0) return true ; // cambio il punto iniziale della prima Curva di Offset Point3d ptNewStart ; double dOffR ; if (( int)vOffs.size() > 1) dOffR = dTRad + GetOffsR() ; else dOffR = dOffs ; if ( SetBetterPtStartForSubChunks( vOffs[0], pSrfToWork, ptStart, vtMidOut, bMidOut, dOffR)) vOffs[0]->GetStartPoint( ptNewStart) ; else return false ; // se richiesta inversione for ( int i = 0 ; i < ( int)vOffs.size() && m_Params.m_bInvert ; ++ i) vOffs[i]->Invert() ; // smusso le curve di offset ( ad eccezione della prima) ICRVCOMPOPOVECTOR vOffsClosedCurves( vOffs.size()) ; // vettore con tutte le curve di Offset Chiuse for ( int i = 0 ; i < int( vOffs.size()) ; ++i ) { if ( i != 0) ModifyCurveToSmoothed( vOffs[i], 0.01, 0.01) ; vOffs[i]->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL, true, true) ; vOffsClosedCurves[i].Set( vOffs[i]->Clone()) ; } for ( int i = 0 ; i < int( vOffsFirstCurve.size()) ; ++ i) { if ( i != 0) ModifyCurveToSmoothed( vOffsFirstCurve[i], 0.01, 0.01) ; vOffsFirstCurve[i]->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL) ; } // setto il punto iniziale della svuotatura double dNewUS ; vOffs[0]->GetParamAtPoint( ptNewStart, dNewUS) ; vOffs[0]->ChangeStartPoint( dNewUS) ; // riordino le curve cambiando il loro punto di inizio e creando poi i collegamenti int nClosestInd = -1 ; int nFlag ; double dDist = INFINITO ; Point3d ptHelp ; ICURVEPOVECTOR vLinks( vOffs.size()) ; for ( int i = 0 ; i < int( vOffs.size()) - 1 ; ++ i) { Point3d ptS ; if ( ! vOffs[i]->GetStartPoint( ptS)) return false ; // setto i default delle variabili if ( ! DistPointCurve( ptS, *vOffs[i+1]).GetMinDistPoint( EPS_SMALL, ptHelp, nFlag)) return false ; dDist = INFINITO ; for ( int j = i + 1 ; j <= int( vOffs.size()) - 1 ; ++ j) { // cerco il punto più vicino della curva Point3d ptE ; if ( ! DistPointCurve( ptS, *vOffs[j]).GetMinDistPoint( EPS_SMALL, ptE, nFlag)) return false ; if ( dDist > Dist( ptS, ptE) ) { dDist = Dist( ptS, ptE) ; nClosestInd = j ; ptHelp.Set( ptE.x, ptE.y, ptE.z) ; } } // avendo la curva più vicina ... // 1) scambio la curva i con la curva nClosestInd if ( nClosestInd != i + 1) { PtrOwner ptoCCHelp( Release( vOffs[i + 1])) ; vOffs[i + 1].Set( vOffs[nClosestInd]) ; vOffs[nClosestInd].Set( ptoCCHelp) ; } // 2) cambio il suo punto iniziale ... double dU ; Point3d ptNE( ptHelp.x, ptHelp.y, ptHelp.z) ; if ( ! vOffs[i + 1]->GetParamAtPoint( ptNE, dU)) return false ; vOffs[i + 1]->ChangeStartPoint( dU) ; // 2.1) Accorcio la curva per velocizzare ... if(( int)vOffs.size() > 1) { // accorcio se ho almeno due Offset // copio le curve i e i+1 nel caso non riesca a tagliarle ... double dUNS, dUNE ; PtrOwner pCrvTest( CreateCurveComposite()) ; // possibile collegamento tra la curva i ed i+1 PtrOwner pOff_i0( CloneCurveComposite( vOffs[i])) ; PtrOwner pOff_i1( CloneCurveComposite( vOffs[i + 1])) ; // cerco di tagliare le curve, ottenendo il collegamento // NB. se la curva di offset è la prima, non devo tagliarla, accorcio solo le successive ... if ( ! CutCurveToConnect( vOffs[i], vOffs[i+1], vOffsClosedCurves, vOffsFirstCurve, pCrvTest, i == 0 ? 0 : 0.01)) { // se non sono riuscito, ritorno alla configurazione iniziale PtrOwner pCrvLink( CreateCurveComposite()) ; Vector3d vS, vE ; vOffs[i].Set( pOff_i0) ; vOffs[i+1].Set( pOff_i1) ; if ( ! vOffs[i]->GetStartDir( vS) || ! vOffs[i+1]->GetStartDir( vE)) return false ; if ( CalcBoundedSmootedLink( ptS, vS, ptNE, vE, 0.5, vOffsFirstCurve, pCrvLink)) vLinks[i + 1].Set( pCrvLink) ; // aggiorno il collegamento else { m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ; return false ; } continue ; } if ( ! pCrvTest->GetStartPoint( ptS) || ! pCrvTest->GetEndPoint( ptNE) || ! vOffs[i]->GetParamAtPoint( ptS, dUNS) || ! vOffs[i+1]->GetParamAtPoint( ptNE, dUNE)) return false ; // imposto il nuovo punto inziale della curva successiva vOffs[i+1]->ChangeStartPoint( dUNE) ; PtrOwner pCrvNewOffS( CloneCurveComposite( vOffs[i])) ; if( dUNS > EPS_SMALL) { // se parametro di trim sufficientemente grande pCrvNewOffS.Set( GetCurveComposite( vOffs[i]->CopyParamRange( 0, dUNS))) ; // sostituisco la curva i-esima con quella tagliata vOffs[i]->Clear() ; vOffs[i].Set( pCrvNewOffS) ; } // aggiorno il collegamento vLinks[i + 1].Set( pCrvTest) ; } } // copio il vettore degli Offset per settare poi la Feed ICRVCOMPOPOVECTOR vOffsFeed ; vOffsFeed.reserve(( int)vOffs.size()) ; for ( int i = 0 ; i < ( int)vOffs.size() ; ++ i) vOffsFeed.emplace_back( vOffs[i]->Clone()) ; // 3) controllo eventuali parti non svuotate... pCrvOEWithFlags->ToLoc( frPocket) ; PtrOwner pSrfToCut( CreateSurfFlatRegion()) ; if ( GetUnclearedRegion( vOffsFirstCurve, vOffs, vLinks, pCrvOEWithFlags, pSrfToCut)) { // 4) Modifico i percorsi if ( ! RemoveExtraParts( pSrfToCut, vOffs, vOffsClosedCurves, vOffsFirstCurve, vLinks)) return false ; } // calcolo il percorso di ritorno if (( int)vOffs.size() >= 2) { pRCrv->Clear() ; // punto inziale e finale | vettore iniziale e finale Point3d ptStart ; vOffs.back()->GetEndPoint( ptStart) ; Point3d ptEnd ; vOffs.front()->GetStartPoint( ptEnd) ; Vector3d vtStart ; vOffs.back()->GetEndDir( vtStart) ; Vector3d vtEnd ; vOffs.front()->GetStartDir( vtEnd) ; // calcolo il ritorno (garantendo che non esca dalla svuotatura) PtrOwner pCrvLink( CreateCurveComposite()) ; if ( CalcBoundedSmootedLink( ptStart, vtStart, ptEnd, vtEnd, 0.5, vOffsFirstCurve, pCrvLink)) { pRCrv->AddCurve( Release( pCrvLink)) ; pRCrv->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL, false) ; // se necessario, approssimo archi con rette if ( bSplitArcs && ! ApproxWithLines( pRCrv)) { m_pMchMgr->SetLastError( 2421, "Error in Pocketing : Linear Approx not computable") ; return false ; } VerifyArcs( pRCrv) ; } else { m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ; return false ; } // Feed per percorso di ritorno AssignFeedForReturnPath( pRCrv) ; } // creo il percorso di lavoro a partire dalla raccolta degli offset e dei collegamenti for ( int i = 0 ; i < int( vOffs.size()) ; ++i) { // se collegamento da aggiungere if ( ! IsNull( vLinks[i])) { int nCrvsCount0 = pMCrv->GetCurveCount() ; // accodo nel percorso di lavorazione if ( ! pMCrv->AddCurve( vLinks[i]->Clone())) return false ; // nel caso di lucidatura setto proprietà alle curve di collegamento per poterle identificare if ( m_TParams.m_nType == TT_MILL_POLISHING) { for ( int j = nCrvsCount0 ; j < pMCrv->GetCurveCount() ; ++ j) pMCrv->SetCurveTempProp( j, LINK_CURVE_PROP) ; } } pMCrv->AddCurve( vOffs[i]->Clone()) ; } // verifico il percorso di lavoro if ( pMCrv->GetCurveCount() == 0) { m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ; return false ; } // se necessario, approssimo archi con rette if ( bSplitArcs && ! ApproxWithLines( pMCrv)) { m_pMchMgr->SetLastError( 2421, "Error in Pocketing : Linear Approx not computable") ; return false ; } // eventuale sistemazione archi VerifyArcs( pMCrv) ; // setto estrusione pMCrv->SetExtrusion( vtExtr) ; // riporto tutto nel sistema di riferimento originale pMCrv->ToGlob( frPocket) ; pRCrv->ToGlob( frPocket) ; ptStart.ToGlob( frPocket) ; vtMidOut.ToGlob( frPocket) ; pCrvOEWithFlags->ToGlob( frPocket) ; return true ; } //---------------------------------------------------------------------------- bool Pocketing::ModifyCurveToSmoothed( ICurveComposite* pCrv, double dRightPer, double dLeftPer) { // controllo parametri if ( pCrv == nullptr) return false ; ICURVEPOVECTOR vCrvStepsToFill ; // vettore delle Curve da raccordare (curve della composita) ICURVEPOVECTOR vCrvArcs ; // vettore contenente gli Archi (tra le curve della composita) INTVECTOR vArcsToJump ; // vettore di indici per gli archi saltati (nel caso non si riesca a raccordare ...) // se nella composita ho meno di due curve allora non c'è nulla da raccordare const ICurve* pMyCrv = pCrv->GetFirstCurve() ; while ( pMyCrv != nullptr) { vCrvStepsToFill.emplace_back( pMyCrv->Clone()) ; pMyCrv = pCrv->GetNextCurve() ; } if ( vCrvStepsToFill.size() < 2) return false ; // controllo se la curva è chiusa (nel caso inserisco nel vettore la prima curva due volte, all'inizio e alla fine) if ( pCrv->IsClosed()) { const ICurve* pMyCrvFirst = pCrv->GetFirstCurve() ; vCrvStepsToFill.emplace_back( pMyCrvFirst->Clone()) ; } double dUE_ref, dUS_ref, dRadius, dPar1, dPar2 ; // riempio il vettore degli archi, scorro tutte le curve da raccordare ( la i-esima e la (i+1)-esima ) for ( int i = 0 ; i < int( vCrvStepsToFill.size()) - 1 ; ++ i) { // controllo che le curve non siano già tangenti Vector3d vtS, vtE ; if ( ! vCrvStepsToFill[i]->GetEndDir( vtS) || ! vCrvStepsToFill[i+1]->GetStartDir( vtE)) continue ; if ( AreSameVectorApprox( vtS, vtE)) { vCrvArcs.emplace_back( CreateCurveComposite()) ; // arco nullo vArcsToJump.push_back( i) ; // da scartare continue ; } // cerco i paramentri al dRightPer% e dLeftPer% della lunghezza della prima e della seconda curva ( per raccordarli ) double dU_cm_S = 0 ; double dULast1 = 1 ; double dULast2 = 1 ; vCrvStepsToFill[i]->GetDomain( dU_cm_S, dULast1) ; dUE_ref = ( 1 - dRightPer) * dULast1 ; vCrvStepsToFill[i+1]->GetDomain( dU_cm_S, dULast2) ; dUS_ref = dLeftPer * dULast2 ; // prendo i punti sulle due curve rispetto a tali parametri Point3d ptS, ptE ; if ( ! vCrvStepsToFill[i]->GetPointD1D2( dUE_ref, ICurve::FROM_PLUS, ptS) || ! vCrvStepsToFill[i+1]->GetPointD1D2( dUS_ref, ICurve::FROM_MINUS, ptE)) return false ; dRadius = Dist( ptS, ptE) ; // uso come raggio la distanza tra i due punti int nMaxTestForArcs = 3 ; // tentativi per creare l'arco int nIterForArcs = 0 ; bool IntersBTWArcs = false ; // creo l'arco di raccordo PtrOwner pCrvArc( CreateFillet( *vCrvStepsToFill[i], ptS, *vCrvStepsToFill[i+1], ptE, Z_AX, dRadius, dPar1, dPar2)) ; // controllo che l'arco creato non sia troppo piccolo double dArcLen ; if ( ! IsNull( pCrvArc) && pCrvArc->IsValid() && (! pCrvArc->GetLength( dArcLen) || dArcLen < 5 * EPS_SMALL)) { vCrvArcs.emplace_back( Release( pCrvArc)) ; // arco nullo vArcsToJump.push_back( i) ; // da scartare continue ; } if ( i != 0 && vArcsToJump[i-1] == -1 && ! IsNull( pCrvArc) && pCrvArc->IsValid()) { // dal secondo arco in poi controllo che non ci siano intersezioni tra essi IntersCurveCurve intCCH( *pCrvArc, *vCrvArcs[i-1]) ; if ( intCCH.GetIntersCount() > 0 ) IntersBTWArcs = true ; } // se ho intersezioni tra archi o l'arco creato non è valido, allora provo altre nMaxTestForArcs volte a ricrearlo avvicinando i punti while (( IsNull( pCrvArc) || IntersBTWArcs) && nIterForArcs < nMaxTestForArcs) { dUE_ref = ( dULast1 + dUE_ref ) * 0.5 ; dUS_ref = dUS_ref * 0.5 ; if ( ! vCrvStepsToFill[i]->GetPointD1D2( dUE_ref, ICurve::FROM_PLUS, ptS) || ! vCrvStepsToFill[i+1]->GetPointD1D2( dUS_ref, ICurve::FROM_MINUS, ptE)) return false ; dRadius = Dist( ptS, ptE) ; pCrvArc.Set( CreateFillet( *vCrvStepsToFill[i], ptS, *vCrvStepsToFill[i+1], ptE, Z_AX, dRadius, dPar1, dPar2)) ; nIterForArcs++ ; IntersBTWArcs = false ; if ( i != 0 && vArcsToJump[i-1] == -1 && ! IsNull( pCrvArc) && pCrvArc->IsValid()) { // dal secondo arco in poi controllo che non ci siano intersezioni tra essi IntersCurveCurve intCCH( *pCrvArc, *vCrvArcs[i-1]) ; if ( intCCH.GetIntersCount() > 0) IntersBTWArcs = true ; } } if ( IsNull( pCrvArc) || ! pCrvArc->IsValid()) { // se ancora non riesco... salto l'arco vCrvArcs.emplace_back( CreateCurveArc()) ; // arco nullo vArcsToJump.push_back( i) ; // da scartare continue ; } // se ho creato l'arco lo memorizzo vCrvArcs.emplace_back( Release( pCrvArc)) ; // arco valido vArcsToJump.push_back( -1) ; // da considerare } // creo la curva che restituirò PtrOwner pCrvCO_temp( CreateCurveComposite()) ; if ( IsNull( pCrvCO_temp)) return false ; Point3d ptArcHelp, ptFirstPoint ; // unisco la curva i-esima con l'arco i-esimo (non guardo l'ultima curva nel vettore, controllo dopo il caso di curva chiusa) for ( int i = 0 ; i < int( vCrvStepsToFill.size()) - 1 ; ++ i) { if ( vArcsToJump[i] == -1) { // se esiste l'arco ... Point3d ptArcS, ptArcE ; if ( ! vCrvArcs[i]->GetStartPoint( ptArcS) || ! vCrvArcs[i]->GetEndPoint( ptArcE) || ! vCrvStepsToFill[i]->GetParamAtPoint( ptArcS, dUE_ref) || ! vCrvStepsToFill[i+1]->GetParamAtPoint( ptArcE, dUS_ref)) return false ; if ( i == 0) { // ... e sono nella prima iterazione ... if ( ! pCrv->IsClosed()) { // ... e se la curva è aperta -> la inserisco nel nuovo percorso if ( ! pCrvCO_temp->AddCurve( GetCurve( vCrvStepsToFill[0]->CopyParamRange( 0, dUE_ref)))) return false ; } ptFirstPoint = ptArcS ; // ... e se la curva è chiusa -> non la inserisco nel nuovo percorso } else { // ... e non sono nella prima iterazione (non ha importanza se la curva è chiusa o aperta...) if ( ! vCrvStepsToFill[i]->GetParamAtPoint( ptArcHelp, dUS_ref) || ! pCrvCO_temp->AddCurve( GetCurve( vCrvStepsToFill[i]->CopyParamRange( dUS_ref, dUE_ref)))) return false ; // aggiungo la curva 'tagliata per il raccordo' } if ( ! pCrvCO_temp->AddCurve( vCrvArcs[i]->Clone())) // aggiungo l'arco di raccordo return false ; ptArcHelp = ptArcE ; } else { // se non esiste l'arco ... if ( i == 0 ) { // e sono nella prima iterazione... if ( ! vCrvStepsToFill[0]->GetEndPoint( ptArcHelp)) return false ; if ( ! pCrv->IsClosed()) { // ...e se aperta // aggiungo la prima curva per intero if ( ! vCrvStepsToFill[0]->GetParamAtPoint( ptArcHelp, dUE_ref) || ! pCrvCO_temp->AddCurve( GetCurve( vCrvStepsToFill[0]->CopyParamRange( 0, dUE_ref)))) return false ; } ptFirstPoint = ptArcHelp ; } else { // ... e non sono nella prima iterazione (non ha importanza se la curva è chiusa o aperta...) double dUS_cm ; if ( ! vCrvStepsToFill[i]->GetParamAtPoint( ptArcHelp, dUS_ref) || ! vCrvStepsToFill[i]->GetDomain( dUS_cm, dUE_ref) || ! pCrvCO_temp->AddCurve( GetCurve( vCrvStepsToFill[i]->CopyParamRange( dUS_ref, dUE_ref))) || ! vCrvStepsToFill[i]->GetEndPoint( ptArcHelp)) return false ; } } } // ultima curva... if ( pCrv->IsClosed()) { // se curva chiusa... if ( ! vCrvStepsToFill[0]->GetParamAtPoint( ptArcHelp, dUS_ref) || ! vCrvStepsToFill[0]->GetParamAtPoint( ptFirstPoint, dUE_ref) || ! pCrvCO_temp->AddCurve( GetCurve( vCrvStepsToFill[0]->CopyParamRange( dUS_ref, dUE_ref)))) return false ; } else { // se curva aperta... ( non ha importanza l'esistenza o meno degli archi...) double dUS_cm ; if ( ! vCrvStepsToFill.back()->GetParamAtPoint( ptArcHelp, dUS_ref) || ! vCrvStepsToFill.back()->GetDomain( dUS_cm, dUE_ref) || ! pCrvCO_temp->AddCurve( GetCurve( vCrvStepsToFill.back()->CopyParamRange( dUS_ref, dUE_ref)))) return false ; } // ripristino il punto inziale se la curva è chiusa double dNewDU ; if ( ! pCrv->IsClosed()) { if ( ! pCrvCO_temp->GetParamAtPoint( ptArcHelp, dNewDU)) return false ; pCrvCO_temp->ChangeStartPoint( dNewDU) ; } pCrv->Clear() ; pCrv->AddCurve( Release( pCrvCO_temp)) ; return true ; } //---------------------------------------------------------------------------- bool Pocketing::CutCurveToConnect( ICurveComposite* pCrvS, ICurveComposite* pCrvE, ICRVCOMPOPOVECTOR& vOffsCL, ICRVCOMPOPOVECTOR& vFirstOffset, ICurveComposite* pCrvLink, double dLenPercS, double dLenPercE, int nMaxIter) { // controllo i parametri if ( pCrvS == nullptr || pCrvE == nullptr ) return false ; pCrvLink->Clear() ; PtrOwner ptCrvFinal( CreateCurveComposite()) ; if ( IsNull( ptCrvFinal)) return false ; // Prendo i punti, i vettori tangenti e i parametri di essi per le curve Point3d ptSS, ptSE, ptES, ptEE ; Vector3d vS, vE ; double dUSS, dUSE, dUES, dUEE, dLenS, dLenE ; dUSS = 0; dUSE = 0; pCrvS->GetEndPoint( ptSE) ; pCrvS->GetStartPoint( ptSS); pCrvE->GetStartPoint( ptES); pCrvE->GetEndPoint( ptEE) ; pCrvS->GetEndDir( vS) ; pCrvE->GetStartDir( vE) ; pCrvS->GetDomain( dUSS, dUSE) ; pCrvE->GetDomain( dUES, dUEE) ; pCrvS->GetLength( dLenS) ; pCrvE->GetLength( dLenE) ; // se ho una curva di primo Offset allora non devo accorciarla ... for ( int i = 0 ; i < int( vFirstOffset.size()) ; ++ i) { if ( vFirstOffset[i]->IsPointOn( ptSS) && vFirstOffset[i]->IsPointOn( ptSE)) dLenPercS = 0 ; if ( vFirstOffset[i]->IsPointOn( ptES) && vFirstOffset[i]->IsPointOn( ptEE)) dLenPercE = 0 ; } double dLStepS = dLenPercS * dLenS ; double dLStepE = dLenPercE * dLenE ; dLenE = 0 ; // calcolo i possibili BiArchi tra le due curve int nIter = 0 ; while ( nIter < nMaxIter) { // calcolo il BiArco PtrOwner ptBiArc( CreateCurveComposite()) ; if ( ! CalcBoundedSmootedLink( ptSE, vS, ptES, vE, 0.5, vFirstOffset, ptBiArc) || ptBiArc->GetCurveCount() == 0) return false ; ptCrvFinal->Clear() ; ptCrvFinal.Set( ptBiArc->Clone()) ; if ( dLenPercE == 0 && dLenPercS == 0 ) break ; // se il BiArco creato interseca le altre curve di Offset allora mi fermo... bool bInterr = false ; for ( int i = 0 ; i < int( vOffsCL.size()) && ! bInterr ; ++ i) { if ( vOffsCL[i]->IsPointOn( ptSE) || vOffsCL[i]->IsPointOn( ptES)) continue ; CRVCVECTOR ccClass ; IntersCurveCurve intCC( *ptBiArc, *vOffsCL[i]) ; intCC.GetCurveClassification( 0, EPS_SMALL, ccClass) ; if ( ccClass.size() > 1) // se intersezione bInterr = true ; } if ( bInterr) break ; // così come ultimo arco ho quello precedente (valido) // se ho trovato un BiArco valido, allora accorcio le due curve di Offset dLenS -= dLStepS ; dLenE += dLStepE ; // ricalcolo il punto iniziale e finale pCrvS->GetParamAtLength( dLenS, dUSE) ; pCrvS->GetPointD1D2( dUSE, ICurve::FROM_MINUS, ptSE) ; pCrvE->GetParamAtLength( dLenE, dUES) ; pCrvE->GetPointD1D2( dUES, ICurve::FROM_PLUS, ptES) ; // ricalcolo il vettore tangente iniziale e finale PtrOwner pCrvS_clone( pCrvS->Clone()) ; // curva di Offset iniziale accorciata PtrOwner pCrvE_clone( pCrvE->Clone()) ; // curva di Offset finale accorciata pCrvS_clone->ChangeStartPoint( dUSE) ; pCrvE_clone->ChangeStartPoint( dUES) ; pCrvS_clone->GetStartDir( vS) ; pCrvE_clone->GetStartDir( vE) ; ++ nIter ; } pCrvLink->AddCurve( ptCrvFinal->Clone()) ; // ultimo arco valido trovato return true ; } //---------------------------------------------------------------------------- bool Pocketing::RemoveExtraParts( ISurfFlatRegion* pSrfToCut, ICRVCOMPOPOVECTOR& vOffs, ICRVCOMPOPOVECTOR& vOffsClosedCurves, ICRVCOMPOPOVECTOR& vOffsFirstCurve, ICURVEPOVECTOR& vLinks) { if ( pSrfToCut == nullptr || ( int)vOffs.size() == 0) return true ; // ciclo tutti i chunk della regione da tagliare for ( int i = 0 ; i < pSrfToCut->GetChunkCount() ; ++ i) { // regione i-esima da rimuovere ( chunk i-esimo ) PtrOwner pSrfChunkToCut( pSrfToCut->CloneChunk( i)) ; if ( IsNull( pSrfChunkToCut)) return false ; // Curva nel caso la regione si svuoti con MedialAxis PtrOwner pCrvPath( CreateCurveComposite()) ; if ( IsNull( pCrvPath)) return false ; // nel caso la regione si svuoti con un centroide -> ptGoTo è il centroide // nel caso la regione si svuoti con un medial Axis -> ptGoTo è il punto iniziale // -> ptGoTo è il punto finale Point3d ptGoTo, ptGoToI ; // flag : 0 -> non faccio nulla | 1 -> svuoto con centroide | 2 -> svuoto con un percorso int nOptFlag = 0 ; // ricavo il flag // ptGoTo è il centroide, pCrvPath è la curva da seguire per svuotare la regione ( nel caso non basi il centroide ) if ( ! RemoveExtraPartByMedialAxis( pSrfChunkToCut, vOffsFirstCurve, nOptFlag, ptGoTo, pCrvPath) || nOptFlag == 0) continue ; if ( nOptFlag == 2 ) // se ho una curva di Medial Axis, ricavo il punto iniziale e finale if ( ! pCrvPath->GetStartPoint( ptGoTo) || ! pCrvPath->GetEndPoint( ptGoToI)) continue ; // una volta trovata la curva di medial Axis ( se la regione non si svuota semplicemente passando per il // centroide, controllo in quale direzione è più conveniente percorrerla ... ( I = Inverso ) PtrOwner pCrvH1( CreateCurveComposite()) ; PtrOwner pCrvH2( CreateCurveComposite()) ; PtrOwner pCrvH1I( CreateCurveComposite()) ; PtrOwner pCrvH2I( CreateCurveComposite()) ; if ( IsNull( pCrvH1) || IsNull( pCrvH2) || IsNull( pCrvH2) || IsNull( pCrvH2I)) return false ; int nIndexO = 0 ; int nIndexOI = 0 ; // cerco il punto pià vicino a ptGoTo sugli tra i vari Offset ( escludendo il primo ) // NB. PtGoTo è il centroide o il punto iniziale del percorso di medial Axis non invertito if ( ! CutOffsetToClosestPoint( vOffs, ptGoTo, pCrvH1, pCrvH2, nIndexO)) continue ; if ( nOptFlag == 2) // se ho un percorso di Medial Axis, lo cerco anche per PtGoToI if ( ! CutOffsetToClosestPoint( vOffs, ptGoToI, pCrvH1I, pCrvH2I, nIndexOI)) continue ; // A) SE IL PUNTO PIU' VICINO E' SU UN ESTREMO DELL'OFFSET... -> Cerco un punto sui collegamenti // ( controllo solo i punti trovati sugli offset mediante Medial Axis non invertiti ) if ( IsNull( pCrvH1) || IsNull( pCrvH2) || pCrvH1->GetCurveCount() == 0 || pCrvH2->GetCurveCount() == 0) { bool bFound, bFoundI ; int nIndexL, nIndexLI ; if ( ! CutLinkToClosestPoint( vLinks, vOffs, ptGoTo, pCrvH1, pCrvH2, bFound, nIndexL)) continue ; if( nOptFlag == 2) { // nel caso curva di Medial Axis, controllo anche nel caso invertito if ( ! CutLinkToClosestPoint( vLinks, vOffs, ptGoToI, pCrvH1I, pCrvH2I, bFoundI, nIndexLI)) continue ; } // link finale scelto... PtrOwner ptCrvNewLink( CreateCurveComposite()) ; if ( IsNull( ptCrvNewLink)) return false ; if ( nOptFlag == 1) { // se svuoto con centroide, aggiusto il link con una circonferenza ( BiArco alla peggio) if ( ! GetNewCurvetWithCentroid( pCrvH1, pCrvH2, ptGoTo, bFound, vOffsFirstCurve, ptCrvNewLink)) continue ; } else if ( nOptFlag == 2) { // se svuoto con curva di medial Axis... bool bSucc = true ; bool bSuccI = true ; // ricavo il nuovo Offset con la curva di medial Axis aggiunta if ( ! GetNewCurvetWithPath( pCrvH1, pCrvH2, pCrvPath, vOffsFirstCurve, vOffsClosedCurves, ptCrvNewLink)) bSucc = false ; PtrOwner pCrvPathI( pCrvPath->Clone()) ; pCrvPathI->Invert() ; PtrOwner ptCrvNewLinkI( CreateCurveComposite()) ; if ( IsNull( ptCrvNewLinkI)) return false ; // ricavo il nuovo Offset con la curva di medial Axis Invertita aggiunta if ( ! GetNewCurvetWithPath( pCrvH1I, pCrvH2I, pCrvPathI, vOffsFirstCurve, vOffsClosedCurves, ptCrvNewLinkI)) bSuccI = false ; // scelgo il miglior percorso ottenuto ( sempre verificando che siano validi...) int nC = 0 ; if ( bSucc && bSuccI) { // se entrambi i percorsi sono validi allora li confronto if ( ChoosePath( ptCrvNewLink, ptCrvNewLinkI, 0, 0.25, 5 * 1000 * EPS_SMALL, nC) && nC == 1) { ptCrvNewLink.Set( ptCrvNewLinkI) ; nIndexL = nIndexLI ; } } else if ( ! bSucc) { // altrimenti tengo l'unico valido ptCrvNewLink.Set( ptCrvNewLinkI) ; nIndexL = nIndexLI ; } } vLinks[nIndexL].Set( ptCrvNewLink) ; // setto il nuovo Link } else { // B) SE NON SONO AD UN ESTREMO DELLA CURVA DI OFFSET // nuovo Offset da restituire PtrOwner ptCrvNewOffs( CreateCurveComposite()) ; if ( IsNull( ptCrvNewOffs)) return false ; if ( nOptFlag == 1) { // se svuoto con centroide, aggiusto il link con una circonferenza ( BiArco alla peggio) if ( ! GetNewCurvetWithCentroid( pCrvH1, pCrvH2, ptGoTo, true, vOffsFirstCurve, ptCrvNewOffs)) continue ; } else if ( nOptFlag == 2) { // nel caso aggiungo un medial Axis non agli estremi di un Offset bool bSucc = true ; bool bSuccI = true ; // come prima controllo il percorso normal ed invertito if ( ! GetNewCurvetWithPath( pCrvH1, pCrvH2, pCrvPath, vOffsFirstCurve, vOffsClosedCurves, ptCrvNewOffs)) bSucc = false ; PtrOwner pCrvPathI( pCrvPath->Clone()) ; pCrvPathI->Invert() ; PtrOwner ptCrvNewOffsI( CreateCurveComposite()) ; if ( IsNull( ptCrvNewOffsI)) return false ; if ( ! GetNewCurvetWithPath( pCrvH1I, pCrvH2I, pCrvPathI, vOffsFirstCurve, vOffsClosedCurves, ptCrvNewOffsI)) bSuccI = false ; int nC = 0 ; // se entrambi i percorsi sono validi allora li confronto if ( bSucc && bSuccI) { if ( ChoosePath( ptCrvNewOffs, ptCrvNewOffsI, 0, 0.5, 5 * 1000 * EPS_SMALL, nC) && nC == 1) { ptCrvNewOffs.Set( ptCrvNewOffsI) ; nIndexO = nIndexOI ; } } else if ( ! bSucc) { // altrimenti tengo l'unico valido ptCrvNewOffs.Set( ptCrvNewOffsI) ; nIndexO = nIndexOI ; } } vOffs[nIndexO].Set( ptCrvNewOffs) ; // setto il nuovo Offset } } return true ; } //--------------------------------------------------------------------------- bool Pocketing::GetCurveWeightInfo( const ICurveComposite* pCrvCompo, double dMaxLen, double& dToTRot, int& nSmallArcs, int& nSmallLines) { dToTRot = 0 ; nSmallArcs = 0 ; nSmallLines = 0 ; if ( pCrvCompo == nullptr) return true ; int nLines = 0 ; PtrOwner pCrvLineOld( CreateCurveLine()) ; if ( IsNull( pCrvLineOld)) return false ; // scorro tutte le curve della composita const ICurve* pMyCrv = pCrvCompo->GetFirstCurve() ; while ( pMyCrv != nullptr) { if ( pMyCrv->GetType() == CRV_ARC) { // nel caso di archi ... nLines = 0 ; PtrOwner pCrvArc( GetCurveArc( pMyCrv->Clone())) ; double dAngCenter = abs( pCrvArc->GetAngCenter()) ; dToTRot += abs( dAngCenter) ; double dLen = 0 ; if ( pCrvArc->GetLength( dLen) && dLen < dMaxLen) ++ nSmallArcs ; } else if ( pMyCrv->GetType() == CRV_LINE) { // nel caso di linee ... ++ nLines ; if ( nLines == 1) pCrvLineOld.Set( GetCurveLine( pMyCrv->Clone())) ; else { PtrOwner pNewMyCrv( GetCurveLine( pMyCrv->Clone())) ; Vector3d vtNew, vtOld ; pCrvLineOld->GetEndDir( vtOld) ; pNewMyCrv->GetStartDir( vtNew) ; double dAngCorner ; vtOld.GetAngle( vtNew, dAngCorner) ; dToTRot += abs( dAngCorner) ; pCrvLineOld.Set( pNewMyCrv) ; nLines = 0 ; } double dLen = 0 ; if ( pMyCrv->GetLength( dLen) && dLen < dMaxLen) ++ nSmallLines ; } pMyCrv = pCrvCompo->GetNextCurve() ; } return true ; } //--------------------------------------------------------------------------- bool Pocketing::ChoosePath( const ICurveComposite* pCrv1, const ICurveComposite* pCrv2, int nP, double dPerP, double dMaxLen, int& nC) { // controllo dei parametri if ( pCrv1 == nullptr || pCrv2 == nullptr || ! ( nP == 0 || nP == 1) || dPerP > 1 || dPerP < 0 || dMaxLen < EPS_SMALL) return false ; // # di archi piccoli tra le due curve int dSmallArcs1 = 0 ; int dSmallArcs2 = 0 ; // # di segmenti piccoli tra le due curve int dSmallLines1 = 0 ; int dSmallLines2 = 0 ; // ------------- lunghezze -------------- double dLen1 = 0 ; double dLen2 = 0 ; pCrv1->GetLength( dLen1) ; pCrv2->GetLength( dLen2) ; double CL1, CL2 ; // rapporto tra lunghezza corrente e massima if ( dLen1 < EPS_SMALL && dLen2 < EPS_SMALL) { CL1 = 0 ; CL2 = 0 ; } else { CL1 = dLen1 / max( dLen1, dLen2) ; CL2 = dLen2 / max( dLen1, dLen2) ; } // ------------- rotazioni -------------- double dRot1 = 0 ; double dRot2 = 0 ; if ( ! GetCurveWeightInfo( pCrv1, dMaxLen, dRot1, dSmallArcs1, dSmallLines1) || ! GetCurveWeightInfo( pCrv2, dMaxLen, dRot2, dSmallArcs2, dSmallLines2)) return false ; double CR1, CR2 ; // rapporto tra la somma de rotazione degli angoli correnti e quella massima if ( dRot1 == 0 && dRot2 == 0) { CR1 = 0 ; CR2 = 0 ; } else { CR1 = dRot1 / max( dRot1, dRot2) ; CR2 = dRot2 / max( dRot1, dRot2) ; } // funzione peso ( bilancio tra lunghezze e rotazioni complessive pesate ) double Fp1 = ( nP == 0 ? dPerP : ( 1 - dPerP)) * ( CL1 + dSmallLines1) + ( nP == 0 ? ( 1 - dPerP) : dPerP) * ( CR1 + dSmallArcs1) ; double Fp2 = ( nP == 0 ? dPerP : ( 1 - dPerP)) * ( CL2 + dSmallLines2) + ( nP == 0 ? ( 1 - dPerP) : dPerP) * ( CR2 + dSmallArcs2) ; // scelta della prima o della seconda curva nC = ( Fp1 > Fp2 ? 1 : 0) ; return true ; } //--------------------------------------------------------------------------- bool Pocketing::CutOffsetToClosestPoint( ICRVCOMPOPOVECTOR& vCurves, const Point3d& ptFocus, ICurveComposite* pCrv1, ICurveComposite* pCrv2, int& nIndex) { // controllo di avere almeno un offset... if (( int)vCurves.size() == 0) return false ; // variabili iniziali Point3d ptCl_H ; double dDistance = INFINITO ; int nFlag ; pCrv1->Clear() ; pCrv2->Clear() ; nIndex = -1 ; Point3d ptCL ; // scorro tutti gli offset ad eccezione del primo ( a meno di averne uno solo ) for ( int j = ( int)vCurves.size() == 1 ? 0 : 1 ; j < int( vCurves.size()) ; ++ j) { // non ho offset nulli, però controllo... if( IsNull( vCurves[j])) continue ; // prendo il punto più vicino if ( ! DistPointCurve( ptFocus, *vCurves[j]).GetMinDistPoint( EPS_SMALL, ptCl_H, nFlag)) continue ; // cerco il punto in assoluto più vicino if ( dDistance > Dist( ptCl_H, ptFocus)) { dDistance = Dist( ptCl_H, ptFocus) ; ptCL = ptCl_H ; nIndex = j ; } } // se non ho trovato nulla, esco if ( nIndex < 0) return false ; // ricavo le due curve ( l'Offset viene spezzato in due sottocurve mediante il punto trovato) double dUTan, dUS, dUE ; vCurves[nIndex]->GetParamAtPoint( ptCL, dUTan) ; pCrv1->AddCurve( vCurves[nIndex]->Clone()) ; pCrv1->TrimEndAtParam( dUTan) ; pCrv2->AddCurve( vCurves[nIndex]->Clone()) ; pCrv2->TrimStartAtParam( dUTan) ; return true ; } //--------------------------------------------------------------------------- bool Pocketing::CutLinkToClosestPoint( ICURVEPOVECTOR& vCurves, ICRVCOMPOPOVECTOR& vOffs, const Point3d& ptFocus, ICurveComposite* pCrv1, ICurveComposite* pCrv2, bool& bFound, int& nIndex) { // variabili iniziali double dDistance = INFINITO ; Point3d ptCl_H ; int nFlag ; pCrv1->Clear() ; pCrv2->Clear() ; Point3d ptCL ; nIndex = - 1 ; bFound = false ; // scorro tutti i link cercando il più vicino for ( int j = 0 ; j < int( vCurves.size()) ; ++ j) { // escludo i links nulli ... if( IsNull( vCurves[j])) continue ; // distanza minima tra link e curva if ( ! DistPointCurve( ptFocus, *vCurves[j]).GetMinDistPoint( EPS_SMALL, ptCl_H, nFlag)) continue ; // cerco la distanza minimia assoluta ( non deve essere sopra un Offset ) if ( dDistance > Dist( ptCl_H, ptFocus) && ! ( vOffs[j-1]->IsPointOn( ptCl_H) || vOffs[j]->IsPointOn( ptCl_H))) { dDistance = Dist( ptCl_H, ptFocus) ; nIndex = j ; bFound = true ; } } // se non ho trovato nulla, esco if( nIndex < 0) return false ; // ricavo le due curve ( il link viene spezzato in due sottocurve mediante il punto trovato ) double dUS, dUE, dUTan ; vCurves[nIndex]->GetParamAtPoint( ptCL, dUTan) ; pCrv1->AddCurve( vCurves[nIndex]->Clone()) ; pCrv1->TrimEndAtParam( dUTan) ; pCrv2->AddCurve( vCurves[nIndex]->Clone()) ; pCrv2->TrimStartAtParam( dUTan) ; return true ; } //---------------------------------------------------------------------------- bool Pocketing::GetNewCurvetWithCentroid( const ICurveComposite* pCrvH1, const ICurveComposite* pCrvH2, Point3d& ptC, bool bCir, ICRVCOMPOPOVECTOR& VFirstOff, ICurveComposite* pCrvNewCurve) { PtrOwner pPath1( CreateCurveComposite()) ; PtrOwner pPath2( CreateCurveComposite()) ; if ( IsNull( pPath1) || IsNull( pPath2)) return false ; pCrvNewCurve->Clear() ; Point3d ptS, ptE = ptC ; Vector3d vtTanS, vtTanE ; if ( bCir) { // creo una circonferenza // prendo il punto iniziale if ( pCrvH1 == nullptr || pCrvH1->GetFirstCurve() == nullptr) { if ( ! pCrvH2->GetStartPoint( ptS)) return false ; } else { if ( ! pCrvH1->GetEndPoint( ptS)) return false ; } // creo la circonferenza if ( ! CalcBoundedSmootedLink( ptS, vtTanS, ptE, vtTanE, 0, VFirstOff, pPath1)) return false ; Vector3d vtS_cir ; pPath1->GetStartDir( vtS_cir) ; Vector3d vtS_CrvH1 ; pCrvH1->GetEndDir( vtS_CrvH1) ; if ( ! AreSameVectorApprox( vtS_cir, vtS_CrvH1)) pPath1->Invert() ; // Assegno la Feed if ( ! AssignFeedCrvOnUnclearedRegions( pPath1)) return false ; // controllo che la circonferenza sia ammissibile ( solo che non esca dalle prime curve di Offset ) Point3d ptCrvS ; pPath1->GetStartPoint( ptCrvS) ; if ( ! CutCurveByOffsets( pPath1, VFirstOff)) // taglio la curva sugli Offsets return false ; double dUCrvS ; ModifyCurveToSmoothed( pPath1, 0.075, 0.075) ; if ( pPath1->IsClosed()) { pPath1->GetParamAtPoint( ptCrvS, dUCrvS) ; pPath1->ChangeStartPoint( dUCrvS) ; } // creo la nuova curva con la circonferenza if ( pCrvH1 != nullptr && pCrvH1->GetFirstCurve() != nullptr) if ( ! pCrvNewCurve->AddCurve( pCrvH1->Clone())) // aggiungo inizio return false ; if ( ! pCrvNewCurve->AddCurve( pPath1->Clone())) // aggiungo la circonferenza return false ; if ( pCrvH2 != nullptr && pCrvH2->GetFirstCurve() != nullptr) if ( ! pCrvNewCurve->AddCurve(( pCrvH2->Clone()))) // aggiungo la fine return false ; } else { // creo un BiArco // prendo il vettore tangente e il punto iniziale if ( pCrvH1 == nullptr || pCrvH1->GetFirstCurve() == nullptr) { if ( ! pCrvH2->GetStartDir( vtTanS) || ! pCrvH2->GetStartPoint( ptS)) return false ; } else { if ( ! pCrvH1->GetEndDir( vtTanS) || ! pCrvH1->GetEndPoint( ptS)) return false ; } // creo i due Biarchi if ( ! CalcBoundedSmootedLink( ptS, vtTanS, ptE, vtTanS, 0.5, VFirstOff, pPath1) || ! CalcBoundedSmootedLink( ptE, vtTanS, ptS, vtTanS, 0.5, VFirstOff, pPath2)) return false ; // Assegno la Feed a queste nuove curve if ( ! AssignFeedCrvOnUnclearedRegions( pPath1) || ! AssignFeedCrvOnUnclearedRegions( pPath2)) return false ; // creo la nuova curva con il doppio Biarco if ( pCrvH1 != nullptr && pCrvH1->GetFirstCurve() != nullptr) if ( ! pCrvNewCurve->AddCurve( pCrvH1->Clone())) // aggiungo inizio return false ; if ( ! pCrvNewCurve->AddCurve( pPath1->Clone()) || ! pCrvNewCurve->AddCurve( pPath2->Clone())) // aggiungo i due BiArchi return false ; if ( pCrvH2 != nullptr && pCrvH2->GetFirstCurve() != nullptr) if ( ! pCrvNewCurve->AddCurve(( pCrvH2->Clone()))) // aggiungo la fine return false ; } return true ; } //---------------------------------------------------------------------------- bool Pocketing::GetNewCurvetWithPath( const ICurveComposite* pCrvH1, const ICurveComposite* pCrvH2, ICurveComposite* pCrvPath, ICRVCOMPOPOVECTOR& VFirstOff, ICRVCOMPOPOVECTOR& VoffsCl, ICurveComposite* pCrvNewCurve) { PtrOwner pPath1( CreateCurveComposite()) ; PtrOwner pPath2( CreateCurveComposite()) ; if ( IsNull( pPath1) || IsNull( pPath2) || pCrvPath == nullptr) return false ; pCrvNewCurve->Clear() ; Point3d ptS, ptE, ptH ; Vector3d vtTanS, vtTanE, vtH ; if ( ! pCrvPath->GetStartPoint( ptE) || ! pCrvPath->GetStartDir( vtTanE) || ! pCrvPath->GetEndPoint( ptH) || ! pCrvPath->GetEndDir( vtH)) return false ; if ( pCrvH1 == nullptr || pCrvH1->GetFirstCurve() == nullptr) { if ( ! pCrvH2->GetStartPoint( ptS) || ! pCrvH2->GetStartDir( vtTanS)) return false ; } else { if ( ! pCrvH1->GetEndPoint( ptS) || ! pCrvH1->GetEndDir( vtTanS)) return false ; } // creo i due Biarchi if ( ! CalcBoundedSmootedLink( ptS, vtTanS, ptE, vtTanE, 0.5, VFirstOff, pPath1)) if ( ! CalcBoundedLink( ptS, ptE, VFirstOff, pPath1)) return false ; if ( ! CalcBoundedSmootedLink( ptH, vtH, ptS, vtTanS, 0.5, VFirstOff, pPath2)) if ( ! CalcBoundedLink( ptH, ptS, VFirstOff, pPath2)) return false ; // creo la curva formata da BiArco1 - Path - BiArco 2 PtrOwner pCrvToAdd( CreateCurveComposite()) ; if ( IsNull( pCrvToAdd) || ! pCrvToAdd->AddCurve( pPath1->Clone()) || ! pCrvToAdd->AddCurve( pCrvPath->Clone()) || ! pCrvToAdd->AddCurve( pPath2->Clone())) return false ; // cerco di togliere le auto intersezioni tra i biarchi e le curve di Medial Axis if ( ! ManageSmoothAndAutoInters( pCrvToAdd, pCrvPath, pPath1, pPath2, VoffsCl)) return false ; // alla curva ottenuta setto la Feed if ( ! AssignFeedCrvOnUnclearedRegions( pCrvToAdd)) return false ; // curva finale if ( pCrvH1 != nullptr && pCrvH1->GetFirstCurve() != nullptr) if ( ! pCrvNewCurve->AddCurve( pCrvH1->Clone())) // aggiungo inizio return false ; if ( ! pCrvNewCurve->AddCurve( pCrvToAdd->Clone())) { // aggiungo BiArco - Path - BiArco // nel caso non funzioni questo raccordo, recupero un biarco valido e uso questo ... Vector3d vtHS, vtHE ; Point3d ptHS, ptHE ; pCrvNewCurve->GetEndPoint( ptHS) ; pCrvNewCurve->GetEndDir( vtHS) ; pCrvToAdd->GetStartPoint( ptHE) ; pCrvToAdd->GetStartDir( vtHE) ; PtrOwner pCrvBiArcHelper( CreateCurveComposite()) ; if ( ! CalcBoundedSmootedLink( ptHS, vtHS, ptHE, vtHE, 0.5, VFirstOff, pCrvBiArcHelper)) if ( ! CalcBoundedLink( ptHS, ptHE, VFirstOff, pCrvBiArcHelper)) return false ; // assegno la Feed ... if ( ! AssignFeedCrvOnUnclearedRegions( pCrvBiArcHelper)) return false ; if ( ! pCrvNewCurve->AddCurve( Release( pCrvBiArcHelper)) || ! pCrvNewCurve->AddCurve( pCrvToAdd->Clone())) return false ; } if ( pCrvH2 != nullptr && pCrvH2->GetFirstCurve() != nullptr) { if ( ! pCrvNewCurve->AddCurve( pCrvH2->Clone())) { // aggiungo fine // nel caso non funzioni questo raccordo, recupero un biarco valido e uso questo ... int nTry = 1 ; int nMaxTry = 10 ; bool bFound = false ; while ( nTry < nMaxTry && ! bFound) { Vector3d vtHS, vtHE ; Point3d ptHS, ptHE ; pCrvNewCurve->GetEndPoint( ptHS) ; pCrvNewCurve->GetEndDir( vtHS) ; pCrvH2->GetStartPoint( ptHE) ; pCrvH2->GetStartDir( vtHE) ; PtrOwner pCrvBiArcHelper( CreateCurveComposite()) ; if ( ! CalcBoundedSmootedLink( ptHS, vtHS, ptHE, vtHE, 0.5, VFirstOff, pCrvBiArcHelper)) if ( ! CalcBoundedLink( ptHS, ptHE, VFirstOff, pCrvBiArcHelper) ) return false ; // assegno la Feed ... if ( ! AssignFeedCrvOnUnclearedRegions( pCrvBiArcHelper)) return false ; if ( ! pCrvNewCurve->AddCurve( pCrvBiArcHelper->Clone()) || ! pCrvNewCurve->AddCurve( pCrvH2->Clone())) { ++nTry ; } else { bFound = true ; } } if ( ! bFound) return false ; } } return true ; } //---------------------------------------------------------------------------- bool Pocketing::ManageSmoothAndAutoInters( ICurveComposite* pCrv, ICurveComposite* pCrvPath, ICurveComposite* pPath1, ICurveComposite* pPath2, ICRVCOMPOPOVECTOR& vOffsCL) { // controllo parametri if ( pCrv == nullptr) return false ; // check AutoIntersezioni... SelfIntersCurve SICrv( *pCrv) ; if ( SICrv.GetCrossOrOverlapIntersCount() > 0) { // se ci sono autointersezioni Vector3d vTanE ; Point3d ptHS ; pCrvPath->GetEndDir( vTanE) ; pCrvPath->GetEndPoint( ptHS) ; bool bFound = false ; int nIter = -45 ; while ( ! bFound && nIter < 45) { vTanE.Rotate( Z_AX, 90 - nIter) ; // vettore perpendicolare PtrOwner pLine( CreateCurveLine()) ; pLine->SetPVL( ptHS, vTanE, m_TParams.m_dDiam / 3 - 5 * EPS_SMALL) ; // segmento uscente CRVCVECTOR ccClass ; IntersCurveCurve intCC( *pLine, *pCrv) ; intCC.GetCurveClassification( 0, EPS_SMALL, ccClass) ; if (( int)ccClass.size() > 1) // se intersezione con parte precedente inverto la direzione pLine->SetPVL( ptHS, - vTanE, m_TParams.m_dDiam / 3 - 5 * EPS_SMALL) ; if ( IsNull( pLine) || ! pLine->IsValid()) break ; // punto finale segmento uscente Point3d ptEndLine ; pLine->GetEndPoint( ptEndLine) ; Point3d ptNear ; double dUS, dUE ; pPath2->GetDomain( dUS, dUE) ; PtrOwner pCrvHelper(( pPath2->CopyParamRange( dUS, dUE - 0.5))) ; pCrvHelper->GetEndPoint( ptNear) ; PtrOwner pLine1( GetLinePointTgCurve( ptEndLine, *pPath2, ptNear)) ; // segmento tangente if ( IsNull( pLine1) || ! pLine1->IsValid()) break ; // creo la nuova curva formata da BiArco 1 - Path - Segmento uscente - Segmento tangente - parte restante di Biarco 2 Point3d ptELine1 ; pLine1->GetEndPoint( ptELine1) ; pPath2->GetParamAtPoint( ptELine1, dUS) ; PtrOwner pNewPath2( GetCurveComposite( pPath2->CopyParamRange( dUS, dUE))) ; // creo la curva formata dai due segmenti ma smussati tra loro... PtrOwner pCrvTwoSeg( CreateCurveComposite()) ; if ( ! pCrvTwoSeg->AddCurve( pCrvPath->Clone()) || ! pCrvTwoSeg->AddCurve( pLine->Clone()) || ! pCrvTwoSeg->AddCurve( pLine1->Clone())) return false ; ModifyCurveToSmoothed( pCrvTwoSeg, 0.2, 0.2) ; PtrOwner ptNewCrv( CreateCurveComposite()) ; if ( ptNewCrv->AddCurve( pPath1->Clone()) && ptNewCrv->AddCurve( pCrvTwoSeg->Clone()) && ptNewCrv->AddCurve( pNewPath2->Clone())) { SelfIntersCurve SICrvLoop( *ptNewCrv) ; if ( SICrvLoop.GetCrossOrOverlapIntersCount() == 0) { pCrv->Clear() ; pCrv->AddCurve( Release( ptNewCrv)) ; bFound = true ; } else { // se trovo autointersezioni, ripeto cambiando l'angolo del segmento uscente ++nIter ; } } else break ; } } // smusso questa curva sulle varie curve di offsets Point3d ptCheck1, ptCheck2 ; PtrOwner pCrvH( pCrv->Clone()) ; // copia della curva if ( ! CutCurveByOffsets( pCrv, vOffsCL)) { // taglio la curva sugli Offsets pCrv->Clear() ; pCrv->AddCurve( Release( pCrvH)) ; } else { // controllo che i punti iniziali coincidano pCrv->GetStartPoint( ptCheck1) ; pCrvH->GetStartPoint( ptCheck2) ; if ( ! AreSamePointApprox( ptCheck1, ptCheck2)) { // se i punti iniziali della curva prima e dopo lo smusso non coincidono ... pCrv->Clear() ; pCrv->AddCurve( Release( pCrvH)) ; } } return true ; } //---------------------------------------------------------------------------- bool Pocketing::RemoveFirstLoopFromSfr( ISurfFlatRegion* pSrfOrig) { if ( pSrfOrig == nullptr) return true ; PtrOwner pSrfRes( CreateSurfFlatRegion()) ; if ( IsNull( pSrfRes)) return false ; for ( int c = 1 ; c < pSrfOrig->GetChunkCount() ; ++ c) { PtrOwner pSrfHelp( CreateSurfFlatRegion()) ; if ( IsNull( pSrfHelp)) return false ; PtrOwner pCrvMiniChunkBorder( GetCurveComposite( pSrfOrig->GetLoop( c, 0))) ; pSrfHelp->AddExtLoop( pCrvMiniChunkBorder->Clone()) ; if ( c == 1) pSrfRes.Set( pSrfHelp->Clone()) ; else pSrfRes->Add( *( pSrfHelp)) ; } pSrfOrig->Clear() ; pSrfOrig->CopyFrom( pSrfRes) ; return true ; } //---------------------------------------------------------------------------- bool Pocketing::RemoveExtraPartByMedialAxis( const ISurfFlatRegion* pChunkToCut, ICRVCOMPOPOVECTOR& vOffsFirstCurve, int& nOptFlag, Point3d& ptCentroid, ICurveComposite* pCrvPath) { // nOptFlag : 0 -> non faccio nulla | 1 -> svuoto con un centroide | 2 -> svuoto con un percorso // variabili iniziali nOptFlag = 2 ; bool bForceCentroid = false ; if ( pChunkToCut == nullptr) return false ; // curva che l'utensile dovrà seguire per svuotare la regione e curva di ingombro del tool PtrOwner pCrvStepByStepPath( CreateCurveComposite()) ; if ( IsNull( pCrvStepByStepPath)) return false ; // copie del chunk che devo svuotare PtrOwner pSrfChunkToCutClone( pChunkToCut->Clone()) ; double dArea = INFINITO ; ICRVCOMPOPOVECTOR vCrvCoMedAxi ; // vettore dei medial Axis PNTVECTOR vPtCentroid ; // vettore di centroidi int nIter = 0 ; // numero di iterazioni while ( pSrfChunkToCutClone->IsValid() && pSrfChunkToCutClone->GetChunkCount() != 0 && pSrfChunkToCutClone->GetArea( dArea) && dArea > 10 * EPS_SMALL) { // finchè restano parti non svuotate la cui area totale è suffcientemente grande... if ( nIter > 25) // troppi tentativi... break ; nIter++ ; PtrOwner pSrfBiggerChunk( pSrfChunkToCutClone->CloneChunk( 0)) ; if( IsNull( pSrfBiggerChunk)) return false ; if( ! pSrfBiggerChunk->IsValid()) break ; double dAreaExt ; // se l'area del chunk è piccola... rimuovo il chunk dalla superficie da svuotare if ( pSrfBiggerChunk->GetArea( dAreaExt) && dAreaExt < 10 * EPS_SMALL) { if ( ! RemoveFirstLoopFromSfr( pSrfChunkToCutClone)) return false ; if( IsNull( pSrfChunkToCutClone) || ! pSrfChunkToCutClone->IsValid()) break ; continue ; } // prendo il centroide del chunk Point3d ptC ; if ( ! pSrfBiggerChunk->GetCentroid( ptC)) break ; // creo la superificie che racchiude il mio tool PtrOwner pCrvToolShape( CreateCurveArc()) ; if ( IsNull( pCrvToolShape)) return false ; pCrvToolShape->SetXY( ptC, m_TParams.m_dDiam / 2 + 5 * EPS_SMALL) ; PtrOwner pSrfTool( CreateSurfFlatRegion()) ; if ( IsNull( pSrfTool) || ! pSrfTool->AddExtLoop( Release( pCrvToolShape)) || ! pSrfTool->IsValid()) break ; PtrOwner pSrfTest( CloneSurfFlatRegion( pSrfBiggerChunk)) ; if( IsNull( pSrfTest)) return false ; pSrfTest->Subtract( *pSrfTool) ; if( IsNull( pSrfTest) || ! pSrfTest->IsValid() || ! pSrfTest->GetArea( dArea) || dArea < 10 * EPS_SMALL || bForceCentroid) { if ( nIter == 1) { // se prima iterazione -> ritorno il centroide com punto nOptFlag = 1 ; ptCentroid = ptC ; return true ; } else { // se non sono alla prima iterazione -> memorizzo il centroide nel vettore // controllo di non aver trovato un centroide già inserito ( per simmetria del chunk) for ( int cen = 0 ; cen < int( vPtCentroid.size()) ; ++ cen) { if ( AreSamePointApprox( vPtCentroid[cen], ptC)) { pSrfChunkToCutClone->Clear() ; break ; } } vPtCentroid.push_back( ptC) ; pSrfChunkToCutClone->Subtract( *pSrfTool) ; if( IsNull( pSrfChunkToCutClone) || ! pSrfChunkToCutClone->IsValid()) break ; continue ; } } bForceCentroid = false ; // 1) ricavo il bordo della regione PtrOwner pCrvBorder( pSrfBiggerChunk->GetLoop( 0, 0)) ; if ( IsNull( pCrvBorder) || ! pCrvBorder->IsValid()) return false ; // 2) ricavo il medial Axis del bordo PolyLine PlMedAx ; if ( ! CurveSimpleMedialAxis( pCrvBorder, PlMedAx)) { bForceCentroid = true ; -- nIter ; continue ; } PtrOwner pCrvMedAx( CreateCurveComposite()) ; if ( IsNull( pCrvMedAx)) return false ; if ( ! pCrvMedAx->FromPolyLine( PlMedAx)) { // se questo medial Axis è troppo piccolo e la polyLine non è convertitibile in curva composita ... bForceCentroid = true ; // 2a) forzo ad andare nel centroide -- nIter ; // 2b) scalo una iterzione continue ; } pCrvMedAx->MergeCurves( 100 * EPS_SMALL, 100 * EPS_ANG_SMALL, false) ; PolyArc PlMedAxArc ; pCrvMedAx->ApproxWithArcsEx( 500 * EPS_SMALL, ANG_TOL_STD_DEG, LIN_FEA_STD, PlMedAxArc) ; pCrvMedAx->Clear() ; if( ! pCrvMedAx->FromPolyArc( PlMedAxArc)) { bForceCentroid = true ; -- nIter ; continue ; } // smusso la curva ModifyCurveToSmoothed( pCrvMedAx, 0.025, 0.025) ; // se curva valida la inserisco nel vettore, altrimenti forzo il centroide if ( pCrvMedAx->IsValid()) vCrvCoMedAxi.emplace_back( pCrvMedAx->Clone()) ; else { bForceCentroid = true ; -- nIter ; continue ; } // 3) guardo quale regione svuoto con questa curva PtrOwner pSrfRemoved( GetSurfFlatRegionFromFatCurve( Release( pCrvMedAx), m_TParams.m_dDiam / 2 + 5 * EPS_SMALL, false, false)) ; if ( IsNull( pSrfRemoved) || ! pSrfRemoved->IsValid()) break ; // 4) aggiorno la regione togliendo la parte percorsa dal tool if ( ! pSrfChunkToCutClone->Subtract( *pSrfRemoved)) break ; if ( IsNull( pSrfChunkToCutClone) || ! pSrfChunkToCutClone->IsValid()) break ; } // se entrambi i vettori sono vuoti l'area originaria era più piccola di 10 * EPS_SMALL -> non faccio nulla if (( int)vCrvCoMedAxi.size() == 0 && ( int)vPtCentroid.size() == 0) { nOptFlag = 0 ; return true ; } // ora collego la varie curve medial Axis trovate tra loro (ottenendo quindi una curva che svuota tutta la regione) PtrOwner pCrvCoBackLink( CreateCurveComposite()) ; // curva che collega primo e ultimo medial Axis if ( IsNull( pCrvCoBackLink)) return false ; Point3d ptSOriginal, ptEOriginal ; Vector3d vtSOriginal, vtEOriginal ; // parametri iniziali del primo e ultimo medial Axis trovato if ( ! vCrvCoMedAxi[0]->GetStartPoint( ptSOriginal) || ! vCrvCoMedAxi.back()->GetEndPoint( ptEOriginal) || ! vCrvCoMedAxi[0]->GetStartDir( vtSOriginal) || ! vCrvCoMedAxi.back()->GetEndDir( vtEOriginal)) return false ; pCrvPath->AddCurve( vCrvCoMedAxi[0]->Clone()) ; // inserisco il primo medial Axis nel percorso finale for ( int i = 1 ; i < int( vCrvCoMedAxi.size()) ; ++ i) { // scorro i restanti Point3d ptS, ptE ; Vector3d vtS, vtE ; // parametri iniziali del medialAxis i-esimo e (i-1)esimo if ( ! vCrvCoMedAxi[i]->GetStartPoint( ptE) || ! vCrvCoMedAxi[i-1]->GetEndPoint( ptS) || ! vCrvCoMedAxi[i]->GetStartDir( vtE) || ! vCrvCoMedAxi[i-1]->GetEndDir( vtS)) return false ; PtrOwner pCrvLink( CreateCurveComposite()) ; if ( IsNull( pCrvLink)) return false ; if ( ! CalcBoundedSmootedLink( ptS, vtS, ptE, vtE, 0.5, vOffsFirstCurve, pCrvLink)) if ( ! CalcBoundedLink( ptS, ptE, vOffsFirstCurve, pCrvLink)) return false ; if ( ! pCrvPath->AddCurve( pCrvLink->Clone()) || ! pCrvPath->AddCurve( vCrvCoMedAxi[i]->Clone())) return false ; } if ( ! AreSamePointEpsilon( ptEOriginal, ptSOriginal, EPS_SMALL)) if ( ! CalcBoundedSmootedLink( ptEOriginal, vtEOriginal, ptSOriginal, vtSOriginal, 0.5, vOffsFirstCurve, pCrvCoBackLink)) if ( ! CalcBoundedLink( ptEOriginal, ptSOriginal, vOffsFirstCurve, pCrvCoBackLink)) return false ; // creo un percorso chiuso ... //PtrOwner pCrvPathClosed( CloneCurveComposite( pCrvPath)) ; //if ( IsNull( pCrvPathClosed)) // return false ; //pCrvPathClosed->AddCurve( pCrvCoBackLink->Clone()) ; // percorso chiuso con tutti i medial Axis Collegati // se ho trovato dei centroidi li unisco nei punti più vicini a questo percorso for ( int i = 0 ; i < int( vPtCentroid.size()) ; ++ i) { // 1) cerco il punto sulla curva più vicino al centroide i Point3d ptClosestOnPath ; int nFlag ; if ( ! DistPointCurve( vPtCentroid[i], *pCrvPath).GetMinDistPoint( EPS_SMALL, ptClosestOnPath, nFlag)) return false ; // 2) spezzo la curva al paramtro del punto più vicino double dU ; if ( ! pCrvPath->GetParamAtPoint( ptClosestOnPath, dU)) return false ; PtrOwner pCrvA( GetCurveComposite( pCrvPath->CopyParamRange( 0, dU))) ; if( IsNull( pCrvA)) return false ; PtrOwner pCrvB( GetCurveComposite( pCrvPath->CopyParamRange( dU, pCrvPath->GetCurveCount()))) ; if( IsNull( pCrvB)) return false ; // 3) prendo il vettore tangente al percorso nel punto trovato nel pCrvPath Vector3d vtTanCpt ; Point3d ptH ; if ( ! pCrvPath->GetPointTang( dU, ICurve::FROM_MINUS, ptH, vtTanCpt)) return false ; // 4) collego i due punti (centroide e punto più vicino alla curva) PtrOwner pCrvPath1( CreateCurveComposite()) ; if ( IsNull( pCrvPath1)) return false ; if ( ! CalcBoundedSmootedLink( ptClosestOnPath, vtTanCpt, vPtCentroid[i], vtTanCpt, 0, vOffsFirstCurve, pCrvPath1)) if ( ! CalcBoundedLink( ptClosestOnPath, vPtCentroid[i], vOffsFirstCurve, pCrvPath1)) return false ; pCrvPath->Clear() ; pCrvPath->AddCurve( Release( pCrvA)) ; if( ! pCrvPath->AddCurve( Release( pCrvPath1))) return false ; pCrvPath->AddCurve( Release( pCrvB)) ; } // la curva resitituita è una curva aperta che ha come primo punto il punto iniziale del primo medialAxis // la curva restituita collega tutti i medial Axis tra di loro // la curva restitutita collega tutti i centroidi con delle circonferenze // la curva restituita ha come punto finale l'ultimo punto dell'ultimo medial Axis return true ; } //---------------------------------------------------------------------------- bool Pocketing::CalcBoundedLink( const Point3d& ptStart, const Point3d& ptEnd, ICRVCOMPOPOVECTOR& vOffIslands, ICurveComposite* pCrvLink) { pCrvLink->Clear() ; // recupero il vettore estrusione dal bordo esterno offsettato della superficie Vector3d vtExtr ; vOffIslands[0]->GetExtrusion( vtExtr) ; // determino il riferimento naturale della svuotatura (OCS con il vettore estrusione come asse Z) Frame3d frLoc ; frLoc.Set( ORIG, vtExtr) ; // non serve collegare (può capitare nel tagliare percorsi con isole complesse) if ( AreSamePointApprox( ptStart, ptEnd)) return true ; // porto la curva di contenimento in locale a questo riferimento vector vOffsExtr ; for ( int i = 0 ; i < int( vOffIslands.size()) ; ++ i) { CurveLocal CrvOutLoc( vOffIslands[i], GLOB_FRM, frLoc) ; vOffsExtr.push_back( CrvOutLoc) ; } // creo la retta che li unisce PtrOwner pLine( CreateCurveComposite()) ; if ( ! pLine->AddPoint( ptStart) || ! pLine->AddLine( ptEnd)) return false ; pLine->SetExtrusion( vtExtr) ; // la porto in locale al riferimento della svuotatura CurveLocal LineLoc( pLine, GLOB_FRM, frLoc) ; // ... per le intersezioni // creo la nuova curva formata dai tratti di linee INTERNI alle isole e dai tratti sul bordo degli offset PtrOwner pCompo( pLine->Clone()) ; if ( IsNull( pCompo) ) return false ; if ( ! pCompo->LocToLoc( GLOB_FRM, frLoc) ) return false; PtrOwner pCompoHelp( pLine->Clone()) ; if ( IsNull( pCompoHelp)) return false ; if ( ! pCompoHelp->LocToLoc( GLOB_FRM, frLoc)) return false ; // scorro il vettore degli indici degli offset delle isole intersecati for ( int i = 0 ; i < int( vOffIslands.size()) ; i++) { CRVCVECTOR ccClass ; IntersCurveCurve intCC( *pCompo, *vOffIslands[i]) ; intCC.GetCurveClassification( 0, EPS_SMALL, ccClass) ; if ( ! pCompoHelp->Clear()) return false ; for ( int j = 0 ; j < int( ccClass.size()) ; ++j ) { // per ogni intersezione j con l'offset dell'isola i if ( ccClass[j].nClass == CRVC_OUT) { // se ho intersezione spezzo il segmento Point3d ptS ; pCompo->GetPointD1D2( ccClass[j].dParS, ICurve::FROM_PLUS, ptS) ; double dOffS ; vOffIslands[i]->GetParamAtPoint( ptS, dOffS) ; Point3d ptE ; pCompo->GetPointD1D2( ccClass[j].dParE, ICurve::FROM_MINUS, ptE) ; double dOffE ; vOffIslands[i]->GetParamAtPoint( ptE, dOffE) ; // recupero i due possibili percorsi e uso il più corto PtrOwner pCrvA( GetCurve( vOffIslands[i]->CopyParamRange( dOffS, dOffE))) ; PtrOwner pCrvB( GetCurve( vOffIslands[i]->CopyParamRange( dOffE, dOffS))) ; if ( IsNull( pCrvA) || IsNull( pCrvB) ) return false ; double dLenA ; pCrvA->GetLength( dLenA) ; double dLenB ; pCrvB->GetLength( dLenB) ; if ( dLenA < dLenB ) { pCompoHelp->AddCurve( Release( pCrvA)) ; } else { pCrvB->Invert() ; pCompoHelp->AddCurve( Release( pCrvB)) ; } } else { // se non interseco pCompoHelp->AddCurve( pCompo->CopyParamRange( ccClass[j].dParS, ccClass[j].dParE)) ; } } pCompo->Clear() ; pCompo->AddCurve( pCompoHelp->Clone()) ; } // riporto pCompo nel sistema di riferimento originale if ( ! pCompo->LocToLoc( frLoc, GLOB_FRM)) return false ; pCrvLink->AddCurve( Release( pCompo)) ; return true ; } //------------------------------------------------------------------------------ bool Pocketing::CalcBoundedSmootedLink( const Point3d& ptStart, const Vector3d& vtStart, const Point3d& ptEnd, const Vector3d& vtEnd, double dParMeet, ICRVCOMPOPOVECTOR& vOffIslands, ICurveComposite* pCrvLink) { // creo il BiArc che unisce i due punti double dAngStart, dAngEnd ; vtStart.GetAngleXY( X_AX, dAngStart) ; vtEnd.GetAngleXY( X_AX, dAngEnd) ; PtrOwner pBiArcLink ; if ( dParMeet != 0) pBiArcLink.Set( GetBiArc( ptStart, -dAngStart, ptEnd, -dAngEnd, dParMeet)) ; else { PtrOwner pCrvCir( CreateCurveArc()) ; if ( IsNull( pCrvCir)) return false ; pCrvCir->SetCPAN( Media( ptStart, ptEnd), ptStart, m_Params.m_bInvert ? 360 : - 360, 0, Z_AX) ; pBiArcLink.Set( pCrvCir->Clone()) ; pCrvLink->AddCurve( pBiArcLink->Clone()) ; return true ; } if ( IsNull( pBiArcLink)) return CalcBoundedLink( ptStart, ptEnd, vOffIslands, pCrvLink) ; // se BiArco troppo grande allora lo modifico double dLenBiArc ; pBiArcLink->GetLength( dLenBiArc) ; if ( dLenBiArc > 200 * 1000 * EPS_SMALL) { PtrOwner pCrvNewBiArcS( CreateCurveComposite()) ; ModifyBiArc( pBiArcLink, 0.2, pCrvNewBiArcS) ; pBiArcLink.Set( pCrvNewBiArcS) ; } // creo la nuova curva formata inizialmente dai tratti di archi PtrOwner pCompo( GetCurveComposite( pBiArcLink->Clone())) ; if ( IsNull( pCompo)) return false ; PtrOwner pCompoHelp( GetCurveComposite( pBiArcLink->Clone())) ; if ( IsNull( pCompoHelp)) return false ; // scorro tutte le curve per controllare le intersezioni ... for ( int i = 0 ; i < int( vOffIslands.size()) ; ++ i) { CRVCVECTOR ccClass ; IntersCurveCurve intCC( *pCompo, *vOffIslands[i]) ; intCC.GetCurveClassification( 0, EPS_SMALL, ccClass) ; if ( ! pCompoHelp->Clear()) return false ; for ( int j = 0 ; j < int( ccClass.size()) ; ++ j) { // per ogni intersezione j con l'offset dell'isola i if ( ccClass[j].nClass == CRVC_OUT && ccClass.size() > 1) { // se ho intersezione spezzo il segmento Point3d ptS ; pCompo->GetPointD1D2( ccClass[j].dParS, ICurve::FROM_PLUS, ptS) ; double dOffS ; vOffIslands[i]->GetParamAtPoint( ptS, dOffS, 1500 * EPS_SMALL) ; Point3d ptE ; pCompo->GetPointD1D2( ccClass[j].dParE, ICurve::FROM_MINUS, ptE) ; double dOffE ; vOffIslands[i]->GetParamAtPoint( ptE, dOffE, 1500 * EPS_SMALL) ; // recupero i due possibili percorsi e uso il più corto PtrOwner pCrvA( GetCurve( vOffIslands[i]->CopyParamRange( dOffS, dOffE))) ; PtrOwner pCrvB( GetCurve( vOffIslands[i]->CopyParamRange( dOffE, dOffS))) ; if ( IsNull( pCrvA) || IsNull( pCrvB)) return CalcBoundedLink( ptStart, ptEnd, vOffIslands, pCrvLink) ; double dLenA ; pCrvA->GetLength( dLenA) ; double dLenB ; pCrvB->GetLength( dLenB) ; if ( j != 0) { if ( dLenA < dLenB) { if ( ! pCompoHelp->AddCurve( Release( pCrvA))) return CalcBoundedLink( ptStart, ptEnd, vOffIslands, pCrvLink) ; } else { pCrvB->Invert() ; if ( ! pCompoHelp->AddCurve( Release( pCrvB))) return CalcBoundedLink( ptStart, ptEnd, vOffIslands, pCrvLink) ; } } else { pCrvB->Invert() ; if ( ! pCompoHelp->AddCurve( Release( pCrvB))) return CalcBoundedLink( ptStart, ptEnd, vOffIslands, pCrvLink) ; } } else { // se non interseco if ( ! pCompoHelp->AddCurve( pCompo->CopyParamRange( ccClass[j].dParS, ccClass[j].dParE))) return CalcBoundedLink( ptStart, ptEnd, vOffIslands, pCrvLink) ; } } pCompo->Clear() ; if ( ! pCompo->AddCurve( pCompoHelp->Clone())) if ( ! CalcBoundedLink( ptStart, ptEnd, vOffIslands, pCrvLink)) return false ; } // se il BiArco è troppo piccolo allora lo approssimo con un segmento BBox3d bBox3 ; if ( pCompo->GetLocalBBox( bBox3)) { double dRadBB ; if ( bBox3.GetRadius( dRadBB) && dRadBB < 500 * EPS_SMALL) { if ( ! CalcBoundedLink( ptStart, ptEnd, vOffIslands, pCrvLink)) return false ; return true ; } } ModifyCurveToSmoothed( pCompo, 0.05, 0.05) ; pCrvLink->AddCurve( Release( pCompo)) ; return true ; } //----------------------------------------------------------------------------- bool Pocketing::ModifyBiArc( ICurve* pBiArcLink, double dToll, ICurveComposite* pNewBiArc) { if ( pBiArcLink == nullptr) return false ; if ( dToll > 0.99 || dToll < 0.01) return false ; pNewBiArc->Clear() ; double dUS, dUE ; pBiArcLink->GetDomain( dUS, dUE) ; PtrOwner pArc1( GetCurve( pBiArcLink->CopyParamRange( dUS, (dUS + dUE) / 2))) ; PtrOwner pArc2( GetCurve( pBiArcLink->CopyParamRange(( dUS + dUE ) / 2, dUE))) ; if ( IsNull(pArc1) || ! pArc1->IsValid() || IsNull( pArc2) || ! pArc2->IsValid()) return false ; // primo pezzo pArc1->GetDomain( dUS, dUE) ; PtrOwner pArc1A( GetCurve( pArc1->CopyParamRange( dUS, dUS + ( dUE - dUS ) * dToll))) ; // Arc1 PtrOwner pArc1B( GetCurve( pArc1->CopyParamRange( dUE - ( dUE - dUS ) * dToll, dUE))) ; // Arc2 Point3d pt1A, pt1B ; pArc1A->GetEndPoint( pt1A) ; pArc1B->GetStartPoint( pt1B) ; PtrOwner pLine1( CreateCurveLine()) ; pLine1->Set( pt1A, pt1B) ; // Linea // secondo pezzo pArc2->GetDomain( dUS, dUE) ; PtrOwner pArc2A( GetCurve( pArc2->CopyParamRange( dUS, dUS + ( dUE - dUS ) * dToll))) ; // Arc1 PtrOwner pArc2B( GetCurve( pArc2->CopyParamRange( dUE - ( dUE - dUS ) * dToll, dUE))) ; // Arc2 Point3d pt2A, pt2B ; pArc2A->GetEndPoint( pt2A) ; pArc2B->GetStartPoint( pt2B) ; PtrOwner pLine2( CreateCurveLine()) ; pLine2->Set( pt2A, pt2B) ; // Linea if ( ! pNewBiArc->AddCurve( Release( pArc1A)) || ! pNewBiArc->AddCurve( Release( pLine1)) || ! pNewBiArc->AddCurve( Release( pArc1B)) || ! pNewBiArc->AddCurve( Release( pArc2A)) || ! pNewBiArc->AddCurve( Release( pLine2)) || ! pNewBiArc->AddCurve( Release( pArc2B))) return false ; return true ; } //------------------------------------------------------------------------------ bool Pocketing::CutCurveByOffsets( ICurveComposite* pCurve, ICRVCOMPOPOVECTOR& vOffs) { // controllo parametri ingresso if (( int)vOffs.size() == 0) return true ; ICRVCOMPOPOVECTOR vOffOrig( vOffs.size()) ; for ( int i = 0 ; i < int( vOffs.size()) ; ++ i) { vOffOrig[i].Set( vOffs[i]->Clone()) ; } Point3d ptStart ; if ( ! pCurve->GetStartPoint( ptStart)) return false ; PtrOwner pCompo( pCurve->Clone()) ; PtrOwner pCompoHelp( pCurve->Clone()) ; PtrOwner pOffCheck( CreateCurveComposite()) ; if ( IsNull( pCompoHelp) || IsNull( pCompo) || IsNull( pOffCheck)) return false ; int nTypeOfCut = -1 ; for ( int i = 0; i < int( vOffOrig.size()) ; ++ i) { if ( vOffOrig[i]->IsPointOn( ptStart)) pOffCheck.Set( vOffOrig[i]->Clone()) ; CRVCVECTOR ccClass ; IntersCurveCurve intCC( *pCompo, *vOffOrig[i]) ; intCC.GetCurveClassification( 0, 10 * EPS_SMALL, ccClass) ; if ( ! pCompoHelp->Clear()) return false ; if ( ccClass.size() > 1) { if ( ccClass[0].nClass == CRVC_IN) nTypeOfCut = CRVC_OUT ; else nTypeOfCut = CRVC_IN ; for ( int j = 0 ; j < int( ccClass.size()) ; ++ j) { if ( ccClass[j].nClass == nTypeOfCut) { Point3d ptS ; pCompo->GetPointD1D2( ccClass[j].dParS, ICurve::FROM_PLUS, ptS) ; double dOffS ; vOffOrig[i]->GetParamAtPoint( ptS, dOffS) ; Point3d ptE ; pCompo->GetPointD1D2( ccClass[j].dParE, ICurve::FROM_MINUS, ptE) ; double dOffE ; vOffOrig[i]->GetParamAtPoint( ptE, dOffE) ; // recupero i due possibili percorsi e uso il più corto PtrOwner pCrvA( GetCurve( vOffOrig[i]->CopyParamRange( dOffS, dOffE))) ; PtrOwner pCrvB( GetCurve( vOffOrig[i]->CopyParamRange( dOffE, dOffS))) ; if ( IsNull( pCrvA) || IsNull( pCrvB)) return false ; double dLenA ; pCrvA->GetLength( dLenA) ; double dLenB ; pCrvB->GetLength( dLenB) ; if ( dLenA < dLenB) { CRVCVECTOR ccClassA ; IntersCurveCurve intCCA( *pCrvA, *pOffCheck) ; intCCA.GetCurveClassification( 0, 10 * EPS_SMALL, ccClassA) ; if ( ccClassA.size() > 0 && i == vOffOrig.size() - 1 && ccClassA[0].nClass == CRVC_ON_M) { if ( ! pCompoHelp->AddCurve( pCompo->CopyParamRange( ccClass[j].dParS, ccClass[j].dParE))) return false ; continue ; } if ( ! pCompoHelp->AddCurve( Release( pCrvA))) return false ; } else { pCrvB->Invert() ; CRVCVECTOR ccClassB ; IntersCurveCurve intCCB( *pCrvB, *pOffCheck) ; intCCB.GetCurveClassification( 0, 10 * EPS_SMALL, ccClassB) ; if ( ccClassB.size() > 0 && i == vOffOrig.size() - 1 && ccClassB[0].nClass == CRVC_ON_M) { if ( ! pCompoHelp->AddCurve( pCompo->CopyParamRange( ccClass[j].dParS, ccClass[j].dParE))) return false ; continue ; } if ( ! pCompoHelp->AddCurve( Release( pCrvB))) return false ; } } else { if ( ! pCompoHelp->AddCurve( pCompo->CopyParamRange( ccClass[j].dParS, ccClass[j].dParE))) return false ; } } pCompo->Clear() ; pCompo->AddCurve( pCompoHelp->Clone()) ; } } pCurve->Clear() ; pCurve->AddCurve( Release( pCompo)) ; return true ; } //------------------------------------------------------------------------------ bool Pocketing::CalcBoundedLinkWithBiArcs( const Point3d& ptStart, const Vector3d& vtStart, const Point3d& ptEnd, const Vector3d& vtEnd, const ICurve* pCrvBound, ICurveComposite* pCrvLink) { double dAngStart, dAngEnd ; vtStart.GetAngleXY( X_AX, dAngStart) ; vtEnd.GetAngleXY( X_AX, dAngEnd) ; PtrOwner pBiArcLink( GetBiArc( ptStart, -dAngStart, ptEnd, -dAngEnd, 0.5)) ; if ( IsNull( pBiArcLink)) return false ; // verifico se esce dalla svuotatura CRVCVECTOR ccClass ; IntersCurveCurve intCC( *pBiArcLink, *pCrvBound) ; intCC.GetCurveClassification( 0, EPS_SMALL, ccClass) ; // se nessuno o un solo tratto e interno, il biarco è il collegamento if ( ccClass.empty() || ( ccClass.size() == 1 && ccClass[0].nClass == CRVC_IN)) { pCrvLink->AddCurve( Release( pBiArcLink)) ; } // altrimenti creo un percorso con biarchi e opportuni tratti della curva di contenimento else { PtrOwner pCompo( CreateCurveComposite()) ; if ( IsNull( pCompo)) return false ; double dPar1, dPar2 ; Point3d ptMinDist1, ptMinDist2 ; Vector3d vtDir1, vtDir2 ; double dAng1, dAng2 ; int nFlag ; DistPointCurve distPtSCrv( ptStart, *pCrvBound) ; distPtSCrv.GetParamAtMinDistPoint( 0, dPar1, nFlag) ; pCrvBound->GetPointTang( dPar1, ICurve::FROM_MINUS, ptMinDist1, vtDir1) ; vtDir1.GetAngleXY( X_AX, dAng1) ; DistPointCurve distPtECrv( ptEnd, *pCrvBound) ; distPtECrv.GetParamAtMinDistPoint( 0, dPar2, nFlag) ; pCrvBound->GetPointTang( dPar2, ICurve::FROM_MINUS, ptMinDist2, vtDir2) ; vtDir2.GetAngleXY( X_AX, dAng2) ; pCompo->AddCurve( GetBiArc( ptStart, -dAngStart, ptMinDist1, -dAng1, 0.5)) ; // primo biarco pCompo->AddCurve( pCrvBound->CopyParamRange( dPar1, dPar2)) ; // tratto di pCrvBound pCompo->AddCurve( GetBiArc( ptMinDist2, -dAng2, ptEnd, -dAngEnd, 0.5)) ; // secondo biarco pCrvLink->AddCurve( Release( pCompo)) ; } return true ; } //---------------------------------------------------------------------------- bool Pocketing::CalcCircleSpiral( const Point3d& ptCen, const Vector3d& vtN, double dOutRad, double dIntRad, bool bSplitArcs, ICurveComposite* pMCrv, ICurveComposite* pRCrv) { // raggio della circonferenza esterna if ( dOutRad < 10 * EPS_SMALL) { m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ; return false ; } // imposto versore estrusione sulle curve composite pMCrv->SetExtrusion( vtN) ; pRCrv->SetExtrusion( vtN) ; // creo e inserisco la circonferenza esterna PtrOwner pArc( CreateCurveArc()) ; if ( IsNull( pArc) || ! pArc->Set( ptCen, vtN, dOutRad)) { m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ; return false ; } // creo la superificie per la Feed PtrOwner pSrfRemoved( CreateSurfFlatRegion()) ; if ( IsNull( pSrfRemoved)) return false ; ICRVCOMPOPOVECTOR vLinksDone ; Vector3d vtDir = pArc->GetStartVersor() ; pMCrv->AddCurve( Release( pArc)) ; // se richiesta percorrenza invertita if ( m_Params.m_bInvert) pMCrv->Invert() ; // se raggio esterno maggiore dell'interno if ( dOutRad > dIntRad + 10 * EPS_SMALL) { // aggiungo le semicirconferenze della spirale ( devono essere in numero dispari) int nStep = int( ceil( ( dOutRad - dIntRad) / ( 0.5 * GetSideStep()))) ; if ( IsEven( nStep)) nStep += 1 ; double dStep = ( dOutRad - dIntRad) / nStep ; for ( int i = 1 ; i <= nStep ; ++ i) { if ( ! IsEven( i)) pMCrv->AddArcTg( ptCen - vtDir * ( dOutRad - i * dStep)) ; else pMCrv->AddArcTg( ptCen + vtDir * ( dOutRad - i * dStep)) ; } // aggiungo la circonferenza interna pMCrv->AddArcTg( ptCen + vtDir * dIntRad) ; pMCrv->AddArcTg( ptCen - vtDir * dIntRad) ; } // verifico il percorso di lavoro if ( pMCrv->GetCurveCount() == 0) { m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ; return false ; } // se necessario, approssimo con rette if ( bSplitArcs && ! ApproxWithLines( pMCrv)) { m_pMchMgr->SetLastError( 2421, "Error in Pocketing : Linear Approx not computable") ; return false ; } // Assegno la Feed al percorso AssignFeedSpiralOpt( 0, pMCrv) ; // eventuale sistemazione archi VerifyArcs( pMCrv) ; // calcolo l'eventuale percorso di ritorno Point3d ptStart ; pMCrv->GetStartPoint( ptStart) ; Point3d ptEnd ; pMCrv->GetEndPoint( ptEnd) ; Vector3d vtStart ; pMCrv->GetStartDir( vtStart) ; if ( ! AreSamePointApprox( ptStart, ptEnd)) { PtrOwner pArc2( CreateCurveArc()) ; if ( IsNull( pArc2) || ! pArc2->Set2PVN( ptStart, ptEnd, - vtStart, vtN)) { m_pMchMgr->SetLastError( 2420, "Error in Pocketing : Return toolpath not computable") ; return false ; } pRCrv->AddCurve( Release( pArc2)) ; // inverto e eventualmente sistemo archi pRCrv->Invert() ; // setto la feed per il percorso di ritorno AssignFeedForReturnPath( pRCrv) ; VerifyArcs( pRCrv) ; } return true ; } //---------------------------------------------------- bool Pocketing::CalcTrapezoidSpiral( ICurveComposite* pCrvPocket, const Vector3d& vtDir, double dPocketSize, ICurveComposite* pMCrv, ICurveComposite* pRCrv, bool& bOptimizedTrap) { bOptimizedTrap = false ; Vector3d vtExtr ; pCrvPocket->GetExtrusion( vtExtr) ; // eventuale approssimazione della curva con polyline per ottenere la stessa curva calcolata in ICurveComposite::IsATrapezoid if ( pCrvPocket->GetCurveCount() > 4) { PolyLine PL ; if ( ! pCrvPocket->ApproxWithLines( 100 * EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_STD, PL)) return false ; pCrvPocket->Clear() ; pCrvPocket->FromPolyLine( PL) ; pCrvPocket->SetExtrusion( vtExtr) ; } // sistemo senso antiorario visto dalla direzione di estrusione Plane3d plPlane ; double dArea ; pCrvPocket->GetArea( plPlane, dArea) ; if ( plPlane.GetVersN() * vtExtr * dArea < 0) pCrvPocket->Invert() ; // passo in un sistema di riferimento locale avente asse X allineato con uno dei due lati paralleli (possibilmente aperto) e centro nel // punto iniziale del lato Frame3d frLoc ; if ( ! CalcTrapezoidSpiralLocalFrame( pCrvPocket, vtDir, frLoc)) return false ; pCrvPocket->ToLoc( frLoc) ; // recupero flag aperto/chiuso dei lati (0=chiuso, 1=aperto) INTVECTOR vnProp( 4, 0) ; for ( int i = 0 ; i < 4 ; i++) pCrvPocket->GetCurveTempProp( i, vnProp[i]) ; // verifico le dimensioni della svuotatura double dLen0 = 0, dLen2 = 0 ; pCrvPocket->GetCurve( 0)->GetLength( dLen0) ; pCrvPocket->GetCurve( 2)->GetLength( dLen2) ; if ( vnProp[0] == 0 && abs( dPocketSize - m_TParams.m_dDiam) > EPS_SMALL) return false ; if ( vnProp[1] == 0 && vnProp[3] == 0) { if ( dLen0 < m_TParams.m_dDiam - EPS_SMALL || dLen2 < m_TParams.m_dDiam - EPS_SMALL) return false ; } // calcolo la larghezza massima della svuotatura (riferimento con X parallelo a primo lato chiuso) Point3d ptOrig ; pCrvPocket->GetCurve( 1)->GetStartPoint( ptOrig) ; Vector3d vtX ; pCrvPocket->GetCurve( 1)->GetStartDir( vtX) ; Frame3d frDim ; frDim.Set( ptOrig, Z_AX, vtX) ; frDim.Invert() ; BBox3d b3Dim ; pCrvPocket->GetBBox( frDim, b3Dim, BBF_EXACT) ; double dMaxLarg = b3Dim.GetDimY() ; // calcolo percorso di svuotatura // se lati obliqui sono entrambi chiusi e dimensione svuotatura è maggiore di diametro fresa e minore del doppio gestione speciale if ( vnProp[0] != 0 && vnProp[2] != 0 && vnProp[3] == 0 && vnProp[1] == 0 && dMaxLarg > m_TParams.m_dDiam + 10 * EPS_SMALL && max( dLen0, dLen2) < 2 * m_TParams.m_dDiam + EPS_SMALL) { if ( ! SpecialAdjustTrapezoidSpiralForAngles( pMCrv, pCrvPocket)) { pMCrv->Clear() ; return false ; } } else { double dYCoord = dPocketSize - 0.5 * m_TParams.m_dDiam ; if ( vnProp[0] != 0) dYCoord -= GetOffsR() ; if ( vnProp[0] != 0 && vnProp[2] != 0) dYCoord = 0.5 * dPocketSize ; // se entrambi i lati paralleli sono aperti mi posiziono a metà della svuotatura double dXCoordStart, dXCoordEnd ; if ( ! CalcTrapezoidSpiralXCoord( pCrvPocket, true, dYCoord, dXCoordStart, dPocketSize)) return false ; if ( ! CalcTrapezoidSpiralXCoord( pCrvPocket, false, dYCoord, dXCoordEnd, dPocketSize)) return false ; if ( dXCoordStart > dXCoordEnd + 500 * EPS_SMALL) return false ; Point3d ptStart( dXCoordStart, dYCoord) ; Point3d ptEnd( dXCoordEnd, dYCoord) ; if ( AreSamePointEpsilon( ptStart, ptEnd, 500 * EPS_SMALL) && vnProp[0] != 0) { Vector3d vtDir1, vtDir3 ; pCrvPocket->GetCurve( 1)->GetStartDir( vtDir1) ; pCrvPocket->GetCurve( 3)->GetStartDir( vtDir3) ; // gestisco il caso speciale di un parallelogramma in cui anche l'altra dimensione della svuotatura è pari al diametro utensile if ( AreOppositeVectorApprox( vtDir1, vtDir3)) { PtrOwner pLine1( GetCurveLine( pCrvPocket->GetCurve( 1)->Clone())) ; PtrOwner pLine3( GetCurveLine( pCrvPocket->GetCurve( 3)->Clone())) ; if ( IsNull( pLine1) || IsNull( pLine3)) return true ; if ( ! pLine1->SimpleOffset( - 0.5 * m_TParams.m_dDiam - GetOffsR()) || ! pLine3->SimpleOffset( - 0.5 * m_TParams.m_dDiam - GetOffsR())) return true ; Point3d ptS, ptE ; if ( vtDir3 * X_AX > EPS_SMALL) { pLine1->GetStartPoint( ptS) ; pLine3->GetStartPoint( ptE) ; } else { pLine1->GetEndPoint( ptE) ; pLine3->GetEndPoint( ptS) ; } pMCrv->AddPoint( ptS) ; if ( vnProp[2] != 0) pMCrv->AddLine( ptE) ; else pMCrv->AddLine( ptStart) ; pMCrv->SetCurveTempProp( 0, 1) ; } } else { if ( ! pMCrv->AddPoint( ptStart)) return true ; if ( ! pMCrv->AddLine( ptEnd)) return true ; // aggiustamenti al percorso per rimuovere materiale residuo negli angoli if ( vnProp[0] != 0) { if ( vnProp[3] == 0 && ! AdjustTrapezoidSpiralForAngles( pMCrv, pCrvPocket, true)) { pMCrv->Clear() ; return false ; } if ( vnProp[1] == 0 && ! AdjustTrapezoidSpiralForAngles( pMCrv, pCrvPocket, false)) { pMCrv->Clear() ; return false ; } } } } if ( pMCrv->GetCurveCount() == 0) return true ; pMCrv->ToGlob( frLoc) ; if ( ! m_Params.m_bInvert) { pMCrv->Invert() ; // inverto le proprietà in modo che nProp3 sia sempre legata al punto iniziale e nProp1 a quello finale swap( vnProp[1], vnProp[3]) ; } // segno i lati aperti come temp prop della curva int nOpenEdges = vnProp[0] + vnProp[1] * 2 + vnProp[3] * 8 ; pMCrv->SetTempProp( nOpenEdges, 0) ; pMCrv->SetExtrusion( vtExtr) ; bOptimizedTrap = true ; return true ; } //---------------------------------------------------- bool Pocketing::CalcTrapezoidSpiralLocalFrame( ICurveComposite* pCrvPocket, const Vector3d& vtDir, Frame3d& frLoc) { // cerco i lati paralleli a vtDir int nBaseId = -1 ; for ( int i = 0 ; i < pCrvPocket->GetCurveCount() ; i ++) { Vector3d vtEdge ; pCrvPocket->GetCurve( i)->GetStartDir( vtEdge) ; if ( AreSameOrOppositeVectorApprox( vtEdge, vtDir)) { nBaseId = i ; break ; } } if ( nBaseId != 0 && nBaseId != 1) return false ; // imposto come lato iniziale per la curva uno dei lati paralleli a vtDir (possibilmente aperto) int nProp0, nProp2 ; pCrvPocket->GetCurveTempProp( nBaseId, nProp0) ; pCrvPocket->GetCurveTempProp( nBaseId + 2, nProp2) ; if ( nProp0 == 0 && nProp2 != 0) pCrvPocket->ChangeStartPoint( nBaseId + 2) ; else pCrvPocket->ChangeStartPoint( nBaseId) ; Point3d ptOrig ; pCrvPocket->GetStartPoint( ptOrig) ; Vector3d vtExtr ; pCrvPocket->GetExtrusion( vtExtr) ; Vector3d vtX ; pCrvPocket->GetStartDir( vtX) ; return frLoc.Set( ptOrig, vtExtr, vtX) ; } //------------------------------------------------------ bool Pocketing::CalcTrapezoidSpiralXCoord( const ICurveComposite* pCrvPocket, bool bStart, double dYCoord, double& dXCoord, double dPocketSize) { // se open int nCrvId = ( bStart ? 3 : 1) ; int nProp ; if ( pCrvPocket->GetCurveTempProp( nCrvId, nProp) && nProp != 0) { Point3d pt1, pt2 ; pCrvPocket->GetCurve( nCrvId)->GetStartPoint( pt1) ; pCrvPocket->GetCurve( nCrvId)->GetEndPoint( pt2) ; if ( bStart) dXCoord = min( pt1.x, pt2.x) ; else dXCoord = max( pt1.x, pt2.x) ; } // se closed else { double dRad = 0.5 * m_TParams.m_dDiam + GetOffsR() ; double dVal ; Vector3d vtRef ; pCrvPocket->GetCurve( nCrvId)->GetStartDir( vtRef) ; double dCosAlpha = vtRef * X_AX ; if ( dRad * dCosAlpha < dYCoord && dYCoord < dPocketSize + dRad * dCosAlpha) { double dSinAlpha = ( vtRef ^ X_AX).Len() ; if ( abs( dSinAlpha) < EPS_SMALL) return false ; dVal = 1.0 / dSinAlpha * ( dRad - dYCoord * dCosAlpha) ; } else if ( dYCoord < dRad * dCosAlpha) dVal = sqrt( dRad * dRad - dYCoord * dYCoord) ; else { double dLen ; pCrvPocket->GetCurve( nCrvId)->GetLength( dLen) ; dVal = - dLen * dCosAlpha + sqrt( dRad * dRad - dYCoord * dYCoord) ; } Point3d ptRef ; if ( bStart) { pCrvPocket->GetCurve( nCrvId)->GetEndPoint( ptRef) ; dXCoord = ptRef.x + dVal ; } else { pCrvPocket->GetCurve( nCrvId)->GetStartPoint( ptRef) ; dXCoord = ptRef.x - dVal ; } } return true ; } //---------------------------------------------------- bool Pocketing::AdjustTrapezoidSpiralForAngles( ICurveComposite* pMCrv, const ICurveComposite* pCrvPocket, bool bStart) { PtrOwner pCompo( CreateCurveComposite()) ; if ( ! bStart) pMCrv->Invert() ; Point3d ptTmp ; pMCrv->GetStartPoint( ptTmp) ; double dYCoord = ptTmp.y ; // quota verticale del percorso di svuotatura pCrvPocket->GetCurve( 2)->GetStartPoint( ptTmp) ; double dPocketSize = ptTmp.y ; int nCrvId = ( bStart ? 3 : 1) ; PtrOwner pLine( GetCurveLine( pCrvPocket->GetCurve( nCrvId)->Clone())) ; pLine->SimpleOffset( - 0.5 * m_TParams.m_dDiam - GetOffsR()) ; Point3d ptP1, ptP2 ; pLine->GetStartPoint( ptP1) ; pLine->GetEndPoint( ptP2) ; if ( ! bStart) swap( ptP1, ptP2) ; int nProp2 ; // lato opposto a quello di riferimento aperto if ( pCrvPocket->GetCurveTempProp( 2, nProp2) && nProp2 != 0) { // caso 1 : pLine ha un estremo sopra e uno sotto il percorso di svuotatura pMCrv if ( ptP2.y < dYCoord && dYCoord < ptP1.y) { // creo tratto da ptP2 a ptP1 pCompo->AddPoint( ptP2) ; pCompo->AddLine( ptP1) ; // trovo il punto di pMCrv da cui ripartire per non lasciare aree residue pLine->SimpleOffset( - 0.5 * m_TParams.m_dDiam) ; pLine->ExtendStartByLen( EPS_SMALL) ; pLine->ExtendEndByLen( EPS_SMALL) ; IntersCurveCurve intCC( *pLine, *pCrvPocket) ; if ( intCC.GetIntersCount() == 0) return false ; IntCrvCrvInfo aInfo ; intCC.GetIntCrvCrvInfo( 0, aInfo) ; double dDeltaX = sqrt( m_TParams.m_dDiam * m_TParams.m_dDiam / 4 - dYCoord * dYCoord) ; if ( ! bStart) dDeltaX *= -1 ; Point3d ptCrv( aInfo.IciA[0].ptI.x + dDeltaX, dYCoord) ; double dPar = 0 ; if ( ! pMCrv->GetParamAtPoint( ptCrv, dPar)) { dPar = 0.5 ; pMCrv->GetPointD1D2( dPar, ICurve::FROM_MINUS, ptCrv) ; } pMCrv->TrimStartAtParam( dPar) ; if ( ptP1.y > dPocketSize) { // se ptP1 è esterno alla svuotatura scambio i punti in modo da usare ptP2 per il biarco ( così da non farlo fuoriuscire troppo) swap( ptP1, ptP2) ; pCompo->Invert() ; } // creo biarco fra ptP1 e ptCrv Vector3d vtDir ; pCompo->GetStartDir( vtDir) ; double dAng ; vtDir.GetAngleXY( X_AX, dAng) ; PtrOwner pBiArc( GetBiArc( ptP1, - dAng, ptCrv, bStart ? 0 : 180, 0.8)) ; bool bUseBiArc = false ; if ( ! IsNull( pBiArc)) { // verifico che con il biarco non si oltrepassi il lato obliquo chiuso della svuotatura IntersCurveCurve intCC2( *pBiArc, *pCompo) ; if ( intCC2.GetIntersCount() == 1) bUseBiArc = true ; } if ( bUseBiArc) pCompo->AddCurve( Release( pBiArc)) ; else { double dParLine = ( dYCoord - ptP2.y) / ( ptP1.y - ptP2.y) ; Point3d ptOnLine = Media( ptP2, ptP1, dParLine) ; pCompo->AddLine( ptOnLine) ; pCompo->AddLine( ptCrv) ; } } // caso 2 : pLine è completamente sopra/sotto la linea di svuotatura else { // se è sopra modifiche per ricondurmi al caso in cui è sotto if ( ptP2.y > dYCoord) { pLine->Invert() ; swap( ptP1, ptP2) ; } // trovo l'intersezione fra il prolungamento della linea e pMCrv if ( bStart) pLine->ExtendStartByLen( 1000) ; else pLine->ExtendEndByLen( 1000) ; IntersCurveCurve intCC ( *pLine, *pMCrv) ; if ( intCC.GetIntersCount() == 0) return false ; IntCrvCrvInfo aInfo ; intCC.GetIntCrvCrvInfo( 0, aInfo) ; Point3d ptInt ; ptInt = aInfo.IciA[0].ptI ; double dPar = 0 ; pMCrv->GetParamAtPoint( ptInt, dPar) ; pMCrv->TrimStartAtParam( dPar) ; pCompo->AddPoint( ptP2) ; pCompo->AddLine( ptInt) ; } } // se il lato opposto a quello di riferimento � chiuso bisogna distinguere i casi else { bool bStartPnt = false ; if ( ptP2.y < dYCoord) { bStartPnt = pCompo->AddPoint( ptP2) ; } else { Vector3d vtDir ; pLine->GetStartDir( vtDir) ; if ( bStart) vtDir.Invert() ; Point3d ptP2N = ptP2 - m_TParams.m_dDiam / 2 * abs( vtDir.x / vtDir.y) * vtDir ; if ( ptP2N.y < dYCoord) bStartPnt = pCompo->AddPoint( ptP2N) ; } if ( bStartPnt) { Point3d ptCrv ; pMCrv->GetStartPoint( ptCrv) ; pCompo->AddLine( ptCrv) ; } } // setto temp prop per ricordare che è curva aggiuntiva per pulire angoli for ( int i = 0 ; i < pCompo->GetCurveCount() ; i++) pCompo->SetCurveTempProp( i, 1) ; pMCrv->AddCurve( Release( pCompo), false) ; if ( ! bStart) pMCrv->Invert() ; // ripristino la direzione originaria return true ; } //---------------------------------------------------- bool Pocketing::SpecialAdjustTrapezoidSpiralForAngles( ICurveComposite* pMCrv, const ICurveComposite* pCrvPocket) { // calcolo gli offset dei lati obliqui PtrOwner pLineS( GetCurveLine( pCrvPocket->GetCurve( 3)->Clone())) ; pLineS->SimpleOffset( - 0.5 * m_TParams.m_dDiam - GetOffsR()) ; pLineS->Invert() ; PtrOwner pLineE( GetCurveLine( pCrvPocket->GetCurve( 1)->Clone())) ; pLineE->SimpleOffset( - 0.5 * m_TParams.m_dDiam - GetOffsR()) ; pLineE->Invert() ; Point3d ptS, ptE ; pLineS->GetEndPoint( ptS) ; pLineE->GetStartPoint( ptE) ; Vector3d vtS, vtE ; pLineS->GetStartDir( vtS) ; pLineE->GetStartDir( vtE) ; PtrOwner pLineLink( CreateCurveLine()) ; pLineLink->Set( ptS, ptE) ; pMCrv->Clear() ; if ( ! pMCrv->AddCurve( Release( pLineS))) return false ; // creo raccordi bool bUseBiArcs = false ; Vector3d vtDir, vtDir2 ; pLineLink->GetStartDir( vtDir) ; pCrvPocket->GetStartDir( vtDir2) ; if ( Dist( ptS, ptE) > 500 * EPS_SMALL && AreSameOrOppositeVectorApprox( vtDir, vtDir2)) { Point3d ptCrv1, ptCrv2 ; pLineLink->GetPointD1D2( 0.3, ICurve::FROM_MINUS, ptCrv1) ; pLineLink->GetPointD1D2( 0.7, ICurve::FROM_MINUS, ptCrv2) ; // primo raccordo double dAng ; vtS.GetAngleXY( X_AX, dAng) ; PtrOwner pBiArc1( GetBiArc( ptS, - dAng, ptCrv1, 0, 0.5)) ; // secondo raccordo vtE.GetAngleXY( X_AX, dAng) ; PtrOwner pBiArc2( GetBiArc( ptE, dAng, ptCrv2, 180, 0.5)) ; pBiArc2->Invert() ; if ( ! IsNull( pBiArc1) && ! IsNull( pBiArc2)) { bUseBiArcs = true ; pMCrv->AddCurve( Release( pBiArc1)) ; pMCrv->AddLine( ptCrv2) ; pMCrv->AddCurve( Release( pBiArc2)) ; } } // se non è stato possibile creare raccordo, unisco linearmente if ( ! bUseBiArcs) pMCrv->AddCurve( Release( pLineLink)) ; if ( ! pMCrv->AddCurve( Release( pLineE))) return false ; // setto temp prop per ricordare curve aggiuntive per pulire angoli pMCrv->SetCurveTempProp( 0, 1) ; pMCrv->SetCurveTempProp( pMCrv->GetCurveCount() - 1, 1) ; return true ; } //---------------------------------------------------- bool Pocketing::AdjustTrapezoidSpiralForLeadInLeadOut( ICurveComposite* pCompo, ICurveComposite* pRCrv, const Vector3d& vtTool, double dDepth, int& nOutsideRaw) { // recupero la direzione principale della svuotatura Vector3d vtMainDir ; for ( int i = 0 ; i < pCompo->GetCurveCount() ; i++) { int nProp ; if ( pCompo->GetCurveTempProp( i, nProp) && nProp == 0) { // se non è lato aggiuntivo per la pulitura angoli recupero la sua direzione pCompo->GetCurve( i)->GetStartDir( vtMainDir) ; break ; } } // start point bool bStartOutside = false ; ComputeTrapezoidSpiralLeadInLeadOut( pCompo, vtMainDir, true, vtTool, dDepth, bStartOutside) ; // end point bool bEndOutside = false ; ComputeTrapezoidSpiralLeadInLeadOut( pCompo, vtMainDir, false, vtTool, dDepth, bEndOutside) ; // eventuale inversione della curva per partire sempre dall'esterno del grezzo if ( bEndOutside && ! bStartOutside) pCompo->Invert() ; nOutsideRaw = 0 ; if ( bStartOutside && bEndOutside) nOutsideRaw = 2 ; else if ( bStartOutside || bEndOutside) { nOutsideRaw = 1 ; // calcolo percorso di ritorno pRCrv->Clear() ; pRCrv->AddCurve( pCompo->Clone()) ; pRCrv->Invert() ; } return true ; } //---------------------------------------------------- bool Pocketing::ComputeTrapezoidSpiralLeadInLeadOut( ICurveComposite* pCompo, const Vector3d& vtMainDir, bool bLeadIn, const Vector3d& vtTool, double dDepth, bool& bIsOutsideRaw) { bIsOutsideRaw = false ; Point3d ptP ; Vector3d vtDir ; if ( bLeadIn) { pCompo->GetStartPoint( ptP) ; pCompo->GetStartDir( vtDir) ; } else { pCompo->GetEndPoint( ptP) ; pCompo->GetEndDir( vtDir) ; } // per non farlo coincedere esttamente con la faccia del grezzo ( per CalcElev) //ptP += 20 * EPS_SMALL *vtDir ; Vector3d vtExtr ; pCompo->GetExtrusion( vtExtr) ; // recupero info sui lati aperti int nPropOpen = pCompo->GetTempProp( 0) ; bool bEdgeOpen = (( nPropOpen & ( bLeadIn ? 8 : 2)) > 0) ; bool bBaseOpen = (( nPropOpen & 1) > 0) ; // recupero info per capire se sto considerando un lato aggiuntivo per pulire angoli int nIdCrv = ( bLeadIn ? 0 : pCompo->GetCurveCount() - 1) ; int nExtraEdge ; pCompo->GetCurveTempProp( nIdCrv, nExtraEdge) ; double dSafeZ = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeZ() ; // tento con allungamento se lato inclinato è aperto oppure se sto considerando un lato aggiuntivo per pulire angoli if ( bEdgeOpen || nExtraEdge == 1) { Vector3d vtDirP = ( bLeadIn ? -vtDir : vtDir) ; // se forzato come fuori dal grezzo if ( m_bOpenOutRaw) { Point3d ptNewStart = ptP + vtDirP * ( m_TParams.m_dDiam / 2 + max( dSafeZ, m_dOpenMinSafe)) ; pCompo->AddLine( ptNewStart, ! bLeadIn) ; bIsOutsideRaw = true ; return true ; } // recupero la distanza dal bordo del grezzo lungo la direzione di allungamento double dDist ; Vector3d vtNorm ; //if ( ! CalcDistanceFromRawSurface( m_nPhase, ptP, vtDirP, dDist, vtNorm)) // return false ; if( ! GetSignedDistFromStmRaw( m_nPhase, ptP, vtDirP, dDist, vtNorm)) return false ; if ( abs( dDist) < EPS_SMALL) { ptP -= vtDirP ; if ( ! CalcDistanceFromRawSurface( m_nPhase, ptP, vtDirP, dDist, vtNorm)) return false ; } // calcolo eventuali fattori correttivi (se uscita approx. con fianco utensile) double dCorr = 1 ; double dDistRef = dDist ; double dDistMin ; Vector3d vtNormMin ; if ( abs( vtTool * vtNorm) < 0.5 && GetSignedDistFromStmRaw( m_nPhase, ptP, vtDir, dDistMin, vtNorm)) { if ( abs( dDistMin) < abs( dDist) && abs( dDistMin) > EPS_SMALL) { dDistRef = dDistMin ; dCorr = dDist / dDistMin ; } } // se vicino al bordo del grezzo if ( abs( dDistRef) < m_TParams.m_dDiam / 2 + EPS_SMALL) { Point3d ptTest = ptP + vtDirP * ( - dDist + ( m_TParams.m_dDiam / 2 + max( dSafeZ, m_dOpenMinSafe)) * dCorr) ; ptTest += - vtTool * dDepth ; double dTestElev ; // se è fuori dal grezzo if ( ! GetElevation( m_nPhase, ptTest, vtTool, m_TParams.m_dDiam / 2, vtTool, dTestElev) || dTestElev < EPS_SMALL) { Point3d ptNewStart = ptP + vtDirP * ( - dDist + ( m_TParams.m_dDiam / 2 + max( dSafeZ, m_dOpenMinSafe)) * dCorr) ; pCompo->AddLine( ptNewStart, ! bLeadIn) ; bIsOutsideRaw = true ; } } } // tento con attacco ruotato di 90° se non sto considerando un tratto aggiuntivo per pulire angoli if ( bBaseOpen && ! bIsOutsideRaw && nExtraEdge == 0) { Vector3d vtDirO = vtDir ; vtDirO.Rotate( vtExtr, ( m_Params.m_bInvert ? -90 : 90)) ; // calcolo distanza dal bordo del grezzo lungo vtDirO double dDist ; Vector3d vtNorm ; //if ( ! CalcDistanceFromRawSurface( m_nPhase, ptP, vtDirO, dDist, vtNorm)) // return false ; if ( ! GetSignedDistFromStmRaw( m_nPhase, ptP, vtDirO, dDist, vtNorm)) return false ; // se vicino al bordo del grezzo if ( dDist < m_TParams.m_dDiam / 2 + EPS_SMALL) { Point3d ptTestO = ptP + vtDirO * ( - dDist + m_TParams.m_dDiam / 2 + max( dSafeZ, m_dOpenMinSafe)) ; ptTestO += - vtTool * dDepth ; double dTestElevO ; // se è fuori dal grezzo uso inizio ruotato if ( ! GetElevation( m_nPhase, ptTestO, vtTool, m_TParams.m_dDiam / 2, vtTool, dTestElevO) || dTestElevO < EPS_SMALL) { Point3d ptNewStart = ptP + vtDirO * ( - dDist + m_TParams.m_dDiam / 2 + max( dSafeZ, m_dOpenMinSafe)) ; pCompo->AddLine( ptNewStart, ! bLeadIn) ; bIsOutsideRaw = true ; } } } return true ; } //---------------------------------------------------------------------------- bool Pocketing::ComputePolishingPath( ICurveComposite* pMCrv, ICurveComposite* pRCrv, bool bSplitArcs) { PtrOwner pCompo( CreateCurveComposite()) ; PtrOwner pCrvBound( CreateCurveComposite()) ; // curva bound da usare per CalcBoundedLink ICRVCOMPOPOVECTOR vpCrvsEp ; Frame3d frLoc ; Vector3d vtExtr ; pMCrv->GetExtrusion( vtExtr) ; frLoc.Set( ORIG, vtExtr) ; pMCrv->ToLoc( frLoc) ; for ( int i = 0 ; i < pMCrv->GetCurveCount() ; i ++) { int nProp = 0 ; if ( ! pMCrv->GetCurveTempProp( i, nProp)) return false ; // se è un tratto di collegamento ho concluso percorso su cui aggiungere epicicli if ( nProp == LINK_CURVE_PROP) { if ( pCompo->IsValid()) { PtrOwner pCrvEp( CreateCurveComposite()) ; // la curva di bound è l'offset che calcolo in AddEpicycles per la prima curva compo trovata in pMCrv bool bAddEp = ( ! pCrvBound->IsValid()) ? AddEpicycles( pCompo, pCrvEp, pCrvBound) : AddEpicycles( pCompo, pCrvEp) ; if ( ! bAddEp) return false ; vpCrvsEp.emplace_back( Release( pCrvEp)) ; pCompo.Set( CreateCurveComposite()) ; } } // se non è tratto di collegamento lo aggiungo alla curva else { if ( ! pCompo->AddCurve( pMCrv->GetCurve(i)->Clone())) return false ; } } // ultima curva if ( ! IsNull( pCompo)) { PtrOwner pCrvEp( CreateCurveComposite()) ; if ( ! AddEpicycles( pCompo, pCrvEp)) return false ; vpCrvsEp.emplace_back( Release( pCrvEp)) ; } // calcolo i collegamenti ICURVEPOVECTOR vLinks( vpCrvsEp.size()) ; for ( int i = 1 ; i < int( vpCrvsEp.size()) ; ++ i) { // punti e direzioni di inizio e fine Point3d ptStart ; Vector3d vtStart ; vpCrvsEp[i-1]->GetEndPoint( ptStart) ; vpCrvsEp[i-1]->GetEndDir( vtStart) ; Point3d ptEnd ; Vector3d vtEnd ; vpCrvsEp[i]->GetStartPoint( ptEnd) ; vpCrvsEp[i]->GetStartDir( vtEnd) ; // calcolo il collegamento con biarchi (garantendo che non esca dalla svuotatura) PtrOwner pCrvLink( CreateCurveComposite()) ; if ( CalcBoundedLinkWithBiArcs( ptStart, vtStart, ptEnd, vtEnd, pCrvBound, pCrvLink)) { vLinks[i].Set( pCrvLink) ; } else { m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ; return false ; } } // calcolo il percorso di ritorno pRCrv->Clear() ; if ( vpCrvsEp.size() >= 2) { // punti di inizio e fine Point3d ptStart ; Vector3d vtStart ; vpCrvsEp.back()->GetEndPoint( ptStart) ; vpCrvsEp.back()->GetEndDir( vtStart) ; Point3d ptEnd ; Vector3d vtEnd ; vpCrvsEp.front()->GetStartPoint( ptEnd) ; vpCrvsEp.front()->GetStartDir( vtEnd) ; // calcolo il ritorno con biarchi (garantendo che non esca dalla svuotatura) PtrOwner pCrvLink( CreateCurveComposite()) ; if ( CalcBoundedLinkWithBiArcs( ptStart, vtStart, ptEnd, vtEnd, pCrvBound, pCrvLink)) { pRCrv->AddCurve( Release( pCrvLink)) ; pRCrv->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL, false) ; // se necessario, approssimo archi con rette if ( bSplitArcs && ! ApproxWithLines( pRCrv)) { m_pMchMgr->SetLastError( 2421, "Error in Pocketing : Linear Approx not computable") ; return false ; } VerifyArcs( pRCrv) ; } else { m_pMchMgr->SetLastError( 2413, "Error in Pocketing : Toolpath not computable") ; return false ; } } // creo il percorso di lavoro a partire dalla raccolta delle curve con epicicli e dei collegamenti pMCrv->Clear() ; for ( int i = 0 ; i < int( vpCrvsEp.size()) ; ++ i) { // se collegamento da aggiungere if ( ! IsNull( vLinks[i])) { // accodo nel percorso di lavorazione pMCrv->AddCurve( Release( vLinks[i])) ; } // aggiungo la curva pMCrv->AddCurve( Release( vpCrvsEp[i])) ; } // se necessario, approssimo archi con rette if ( bSplitArcs && ! ApproxWithLines( pMCrv)) { m_pMchMgr->SetLastError( 2421, "Error in Pocketing : Linear Approx not computable") ; return false ; } VerifyArcs( pMCrv) ; pMCrv->ToGlob( frLoc) ; pRCrv->ToGlob( frLoc) ; return true ; } //---------------------------------------------------------------------------- bool Pocketing::AddEpicycles( ICurveComposite* pCompo, ICurveComposite * pCrv, ICurveComposite * pCrvBound) { if ( m_Params.m_bInvert) pCompo->Invert() ; // oriento la curva in senso antiorario OffsetCurve OffsCrv ; double dOffs = m_Params.m_dEpicyclesRad ; if ( ! OffsCrv.Make( pCompo, dOffs, ICurve::OFF_FILLET)) { m_pMchMgr->SetLastError( 2412, "Error in Pocketing : Offset not computable") ; return false ; } if ( OffsCrv.GetCurveCount() > 1) return false ; PtrOwner pCrvOffs( GetCurveComposite( OffsCrv.GetCurve())) ; if ( IsNull( pCrvOffs)) return false ; // verifico se devo resitituire la curva offsettata if ( pCrvBound) pCrvBound->AddCurve( pCrvOffs->Clone()) ; pCrv->Clear() ; double dParPrec = 0 ; for ( int i = 0 ; i < pCompo->GetCurveCount() ; i++) { // calcolo distanza epicili specifica per quel tratto double dLen ; pCompo->GetCurve( i)->GetLength( dLen) ; int nStep = max( 1, static_cast( ceil( ( dLen) / m_Params.m_dEpicyclesDist))) ; double dStep = 1.0 / nStep ; for ( int k = 1 ; k <= nStep ; k ++) { // creo epiciclo PtrOwner pCrvArc( CreateCurveArc()) ; Point3d ptCen ; Vector3d vtDir ; pCompo->GetCurve( i)->GetPointD1D2( k * dStep, ICurve::FROM_MINUS, ptCen, &vtDir) ; vtDir.Normalize() ; vtDir.Rotate( Z_AX, - 90) ; Point3d pt = ptCen + vtDir * m_Params.m_dEpicyclesRad ; pCrvArc->Set( ptCen, Z_AX, m_Params.m_dEpicyclesRad) ; double dU ; pCrvArc->GetParamAtPoint( pt, dU) ; pCrvArc->ChangeStartPoint( dU) ; // aggiungo tratto della curva offsettata double dPar ; pCrvOffs->GetParamAtPoint( pt, dPar) ; bool bAdd = pCrv->AddCurve( pCrvOffs->CopyParamRange( dParPrec, dPar)) ; // aggiungo epiciclo if ( ! pCrv->AddCurve( Release( pCrvArc))) { // se fallisco nell'aggiungere l'epiciclo tento nuovamente spostandolo di EPS_SMALL if ( bAdd) PtrOwner pCrvErased( pCrv->RemoveFirstOrLastCurve( true)) ; k -- ; dStep -= EPS_SMALL ; if ( dStep < EPS_SMALL) return false ; } else dParPrec = dPar ; } } // se necessario ripristino orientamento originale if ( m_Params.m_bInvert) pCrv->Invert() ; return true ; } //---------------------------------------------------------------------------- bool Pocketing::AddApproach( const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dSafeAggrBottZ, double dElev, double dAppr, bool bOutStart) { SetFlag( 1) ; // se con aggregato da sotto o equivalente (rinvio a 90 gradi su testa 5 assi) bool bBottomOutStart = false ; if ( m_bAggrBottom) { // distanza dal bordo del pezzo (se negativa il punto è fuori dal grezzo) double dDistBottom ; if ( ! GetDistanceFromRawSide( m_nPhase, ptP, m_vtAggrBottom, dDistBottom)) dDistBottom = 0 ; bBottomOutStart = ( dDistBottom < - 10 * EPS_SMALL) ; // aggiuntivo in Z double dAggZ = ( bBottomOutStart ? 0. : max( dElev + max( dSafeAggrBottZ, dAppr), 0.)) ; // pre-approccio Point3d ptP0 = ptP - Z_AX * dAggZ + m_vtAggrBottom * ( dDistBottom + m_AggrBottom.dEncH + dSafeZ) ; Point3d ptP00 = ptP0 + Z_AX * ( m_AggrBottom.dEncV + m_TParams.m_dLen + dAggZ - dElev) ; // se rinvio da sotto che richiede speciale rotazione if ( m_AggrBottom.nType == 1) { Vector3d vtAux = m_vtAggrBottom ; vtAux.Rotate( Z_AX, 0, 1) ; SetAuxDir( vtAux) ; if ( AddRapidStart( ptP00, MCH_CL_AGB_DWN) == GDB_ID_NULL) return false ; SetAuxDir( m_vtAggrBottom) ; SetFlag( 0) ; if ( AddRapidMove( ptP0, MCH_CL_AGB_IN) == GDB_ID_NULL) return false ; } // altrimenti rinvio normale else { SetAuxDir( m_vtAggrBottom) ; if ( AddRapidStart( ptP0, MCH_CL_AGB_IN) == GDB_ID_NULL) return false ; SetFlag( 0) ; } } // se sopra attacco c'è spazio per sicurezza o approccio double dSafeDist = ( m_bAggrBottom ? dSafeAggrBottZ : dSafeZ) ; if ( ! bBottomOutStart && dElev + max( dSafeDist, dAppr) > 10 * EPS_SMALL) { // se distanza di sicurezza minore di distanza di inizio if ( dSafeDist < dAppr + 10 * EPS_SMALL) { // 1 -> punto sopra inizio Point3d ptP1 = ptP + vtTool * ( dElev + dAppr) ; if ( ( ! m_bAggrBottom && AddRapidStart( ptP1) == GDB_ID_NULL) || ( m_bAggrBottom && AddRapidMove( ptP1) == GDB_ID_NULL)) return false ; } else { // 1a -> punto sopra inizio Point3d ptP1b = ptP + vtTool * ( dElev + dAppr) ; Point3d ptP1a = ptP1b + vtTool * ( dSafeDist - dAppr) ; if ( ( ! m_bAggrBottom && AddRapidStart( ptP1a) == GDB_ID_NULL) || ( m_bAggrBottom && AddRapidMove( ptP1a) == GDB_ID_NULL)) return false ; // 1b -> punto appena sopra inizio if ( ( dElev + dAppr) > EPS_SMALL) { SetFlag( 0) ; if ( AddRapidMove( ptP1b) == GDB_ID_NULL) return false ; } } // affondo al punto iniziale SetFlag( 0) ; SetFeed( bOutStart ? GetStartFeed() : GetTipFeed()) ; if ( AddLinearMove( ptP) == GDB_ID_NULL) return false ; } else { // affondo diretto al punto iniziale SetFlag( 0) ; if ( ( ! m_bAggrBottom && AddRapidStart( ptP) == GDB_ID_NULL) || ( m_bAggrBottom && AddRapidMove( ptP) == GDB_ID_NULL)) return false ; } return true ; } //---------------------------------------------------------------------------- bool Pocketing::AddLinkApproach( const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dSafeAggrBottZ, double dElev, double dAppr, bool bOutStart) { // 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( bOutStart ? 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 Pocketing::AddLinkRetract( const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dSafeAggrBottZ, double dElev, double dAppr) { // se sopra uscita c'è spazio per approccio if ( ( dElev + dAppr) > 10 * EPS_SMALL) { // 4 -> movimento di risalita sopra il punto finale SetFeed( GetEndFeed()) ; Point3d ptP4 = ptP + vtTool * ( dElev + dAppr) ; if ( AddLinearMove( ptP4) == GDB_ID_NULL) return false ; } return true ; } //---------------------------------------------------------------------------- bool Pocketing::AddRetract( const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dSafeAggrBottZ, double dElev, double dAppr) { // se con aggregato da sotto o equivalente (rinvio a 90 gradi su testa 5 assi) bool bBottomOutStart = false ; double dDistBottom ; if ( m_bAggrBottom) { // distanza dal bordo del pezzo if ( ! GetDistanceFromRawSide( m_nPhase, ptP, m_vtAggrBottom, dDistBottom)) dDistBottom = 0 ; bBottomOutStart = ( dDistBottom < - 10 * EPS_SMALL) ; } // se sopra uscita c'è spazio per sicurezza o approccio double dSafeDist = ( m_bAggrBottom ? dSafeAggrBottZ : dSafeZ) ; if ( ! bBottomOutStart && dElev + max( dSafeDist, dAppr) > 10 * EPS_SMALL) { if ( dSafeDist < dAppr + 10 * EPS_SMALL) { // 4 -> movimento di risalita sopra il punto finale SetFeed( GetEndFeed()) ; Point3d ptP4 = ptP + vtTool * ( dElev + dAppr) ; if ( AddLinearMove( ptP4) == GDB_ID_NULL) return false ; } else { // 4a -> movimento di risalita appena sopra il punto finale Point3d ptP4a = ptP + vtTool * ( dElev + dAppr) ; if ( dElev + dAppr > EPS_SMALL) { SetFeed( GetEndFeed()) ; if ( AddLinearMove( ptP4a) == GDB_ID_NULL) return false ; } // 4b -> movimento di risalita sopra il punto finale Point3d ptP4b = ptP4a + vtTool * ( dSafeDist - dAppr) ; if ( AddRapidMove( ptP4b) == GDB_ID_NULL) return false ; } } // se con aggregato da sotto o equivalente (rinvio a 90 gradi su testa 5 assi) if ( m_bAggrBottom) { // aggiuntivo in Z double dAggZ = ( bBottomOutStart ? 0. : max( dElev + max( dSafeAggrBottZ, dAppr), 0.)) ; // post-retract Point3d ptP0 = ptP - Z_AX * dAggZ + m_vtAggrBottom * ( dDistBottom + m_AggrBottom.dEncH + dSafeZ) ; Point3d ptP00 = ptP0 + Z_AX * ( m_AggrBottom.dEncV + m_TParams.m_dLen + dAggZ - dElev) ; if ( AddRapidMove( ptP0, MCH_CL_AGB_OUT) == GDB_ID_NULL) return false ; // se rinvio da sotto che richiede speciale rotazione if ( m_AggrBottom.nType == 1) { Vector3d vtAux = m_vtAggrBottom ; vtAux.Rotate( Z_AX, 0, 1) ; SetAuxDir( vtAux) ; if ( AddRapidMove( ptP00, MCH_CL_AGB_UP) == GDB_ID_NULL) return false ; } } return true ; } //---------------------------------------------------------------------------- bool Pocketing::CalcLeadInStart( const Point3d& ptStart, const Vector3d& vtStart, const Vector3d& vtN, const ICurveComposite* pRCrv, Point3d& ptP1) const { // Assegno tipo e parametri int nType = GetLeadInType() ; if ( nType == POCKET_LI_GLIDE && ( pRCrv == nullptr || pRCrv->GetCurveCount() == 0)) nType = POCKET_LI_NONE ; // Calcolo punto iniziale switch ( nType) { case POCKET_LI_NONE : case POCKET_LI_ZIGZAG : case POCKET_LI_HELIX : ptP1 = ptStart ; return true ; case POCKET_LI_GLIDE : { double dLen, dU ; if ( ! pRCrv->GetLength( dLen) || ! pRCrv->GetParamAtLength( dLen - m_Params.m_dLiTang, dU) || ! pRCrv->GetPointD1D2( dU, ICurve::FROM_MINUS, ptP1)) { if ( ! pRCrv->GetStartPoint( ptP1)) return false ; } ptP1 += vtN * ( vtN * ( ptStart - ptP1)) ; return true ; } default : return false ; } } //---------------------------------------------------------------------------- bool Pocketing::AddLeadIn( const Point3d& ptP1, const Point3d& ptStart, const Vector3d& vtStart, const Vector3d& vtN, ISurfFlatRegion* pSrfChunk, 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 == POCKET_LI_GLIDE && ( pRCrv == nullptr || pRCrv->GetCurveCount() == 0))) nType = POCKET_LI_NONE ; // Se elica e fattibile lo creo if ( nType == POCKET_LI_HELIX) { // vettore dal punto al centro elica Vector3d vtCen = vtStart ; vtCen.Rotate( vtN, 0, ( bAtLeft ? 1 : - 1)) ; // dati dell'elica double dRad = min( 0.5 * min( m_Params.m_dLiTang, m_TParams.m_dDiam), m_dMaxHelixRad) ; Point3d ptCen = ptP1 + vtCen * dRad ; double dDeltaN = ( ptStart - ptP1) * vtN ; double dAngCen = ceil( - dDeltaN / ( m_Params.m_dLiElev + 20 * EPS_SMALL)) * ( bAtLeft ? ANG_FULL : - ANG_FULL) ; // verifico se fattibile if ( bSkipControl || VerifyLeadInHelix( pSrfChunk, ptCen, dRad)) { // creo l'elica PtrOwner pArc( CreateCurveArc()) ; if ( IsNull( pArc) || ! pArc->Set( ptCen, vtN, dRad, - vtCen, dAngCen, dDeltaN)) return false ; // eventuale spezzatura if ( bSplitArcs) { PtrOwner pCompo( CreateCurveComposite()) ; if ( IsNull( pCompo) || ! pCompo->AddCurve( Release( pArc)) || ! ApproxWithLines( pCompo)) return false ; return ( AddCurveMove( pCompo, MCH_CL_LEADIN) != GDB_ID_NULL) ; } else { // emetto l'elica return ( AddCurveMove( pArc, MCH_CL_LEADIN) != GDB_ID_NULL) ; } } // altrimenti zigzag else nType = POCKET_LI_ZIGZAG ; } // Se zigzag e fattibile lo creo if ( nType == POCKET_LI_ZIGZAG) { // dati dello zigzag double dDeltaN = ( ptStart - ptP1) * vtN ; int nStep = int( ceil( - dDeltaN / ( m_Params.m_dLiElev + 20 * EPS_SMALL))) ; double dStep = - dDeltaN / nStep ; Point3d ptPa = ptP1 + vtStart * 0.5 * min( m_Params.m_dLiTang, m_TParams.m_dDiam) ; Point3d ptPb = ptP1 - vtStart * 0.5 * min( m_Params.m_dLiTang, m_TParams.m_dDiam) ; // verifico se fattibile if ( bSkipControl || VerifyLeadInZigZag( pSrfChunk, ptPa, ptPb)) { for ( int i = 1 ; i <= nStep ; ++ i) { if ( AddLinearMove( ptPa - vtN * ( i - 0.75) * dStep, MCH_CL_LEADIN) == GDB_ID_NULL) return false ; if ( AddLinearMove( ptPb - vtN * ( i - 0.25) * dStep, MCH_CL_LEADIN) == GDB_ID_NULL) return false ; } return ( AddLinearMove( ptStart, MCH_CL_LEADIN) != GDB_ID_NULL) ; } // altrimenti diretto else { nType = POCKET_LI_NONE ; if ( m_TParams.m_nType == TT_MILL_NOTIP) return false ; } } // Se a scivolo e fattibile if ( nType == POCKET_LI_GLIDE) { if ( pRCrv != nullptr) { // recupero la parte richiesta della curva di ritorno PtrOwner pCrv ; double dLen, dU ; if ( pRCrv->GetLength( dLen) && pRCrv->GetParamAtLength( dLen - m_Params.m_dLiTang, dU)) { double dParS, dParE ; pRCrv->GetDomain( dParS, dParE) ; if ( ! pCrv.Set( CreateCurveComposite()) || ! pCrv->AddCurve( pRCrv->CopyParamRange( dU, dParE))) return false ; } else { if ( ! pCrv.Set( pRCrv->Clone())) return false ; } pCrv->SetExtrusion( vtN) ; // la porto alla giusta quota Point3d ptFin ; pCrv->GetEndPoint( ptFin) ; Vector3d vtMove = ptStart - ptFin ; pCrv->Translate( vtMove) ; // assegno la corretta pendenza double dNini = ( ptP1 - ORIG) * vtN ; double dNfin = ( ptStart - ORIG) * vtN ; AdjustCurveSlope( pCrv, dNini, dNfin) ; // eventuale spezzatura if ( bSplitArcs && ! ApproxWithLines( pCrv)) return false ; // emetto return ( AddCurveMove( pCrv) != GDB_ID_NULL) ; } // altrimenti diretto else nType = POCKET_LI_NONE ; } // Se diretto if ( nType == POCKET_LI_NONE) { Point3d ptCurr = ptP1 ; GetCurrPos( ptCurr) ; if ( ! AreSamePointApprox( ptCurr, ptStart)) { if ( AddLinearMove( ptStart, MCH_CL_LEADIN) == GDB_ID_NULL) return false ; } return true ; } // Altrimenti errore return false ; } //---------------------------------------------------------------------------- bool Pocketing::AddLeadOut( const Point3d& ptEnd, const Vector3d& vtEnd, const Vector3d& vtN, const ICurveComposite* pRCrv, bool bSplitArcs, bool bNoneForced, Point3d& ptP1, double& dElev, bool bRecalcElev) { bool bOppositeHome ; return AddLeadOut( ptEnd, vtEnd, vtN, pRCrv, bSplitArcs, bNoneForced, ptP1, dElev, bOppositeHome, bRecalcElev) ; } //---------------------------------------------------------------------------- bool Pocketing::AddLeadOut( const Point3d& ptEnd, const Vector3d& vtEnd, const Vector3d& vtN, const ICurveComposite* pRCrv, bool bSplitArcs, bool bNoneForced, Point3d& ptP1, double& dElev, bool& bOppositeHome, bool bRecalcElev) { // assegno i parametri int nType = GetLeadOutType() ; if ( bNoneForced || ( nType == POCKET_LO_GLIDE && ( pRCrv == nullptr || pRCrv->GetCurveCount() == 0))) nType = POCKET_LO_NONE ; // eseguo a seconda del tipo switch ( nType) { case POCKET_LO_NONE : { // nessuna uscita ptP1 = ptEnd ; // determino elevazione su fine uscita if ( bRecalcElev) { double dEndElev ; if ( GetElevation( m_nPhase, ptP1 - 10 * EPS_SMALL * vtN, vtN, GetRadiusForStartEndElevation(), vtN, dEndElev)) dElev = dEndElev ; } // correzione per punto sotto il grezzo con testa normale da sopra double dSafeZ = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeZ() ; bool bAhUnderRaw = m_bAboveHead && ! m_bAggrBottom && ! m_bTiltingTab && GetAhPointUnderRaw( ptP1, vtN, 0, GetRadiusForStartEndElevation(), m_TParams.m_dLen, false, dSafeZ, vtN, dElev) ; bool bUhAboveRaw = ! m_bAboveHead && GetUhPointAboveRaw( ptP1, vtN, 0, GetRadiusForStartEndElevation(), m_TParams.m_dLen, false, dSafeZ, vtN, dElev) ; bOppositeHome = ( bAhUnderRaw || bUhAboveRaw) ; return true ; } case POCKET_LO_GLIDE : { // recupero la parte richiesta della curva di ritorno PtrOwner pCrv ; double dU ; if ( pRCrv->GetParamAtLength( m_Params.m_dLoTang, dU)) { if ( ! pCrv.Set( CreateCurveComposite()) || ! pCrv->AddCurve( pRCrv->CopyParamRange( 0, dU))) return false ; } else { if ( ! pCrv.Set( pRCrv->Clone())) return false ; } // la porto alla giusta quota Point3d ptIni ; pCrv->GetStartPoint( ptIni) ; Vector3d vtMove = ptEnd - ptIni ; pCrv->Translate( vtMove) ; Point3d ptFin ; pCrv->GetEndPoint( ptFin) ; ptFin += vtN * 1.0 ; pCrv->ModifyEnd( ptFin) ; // eventuale spezzatura if ( bSplitArcs && ! ApproxWithLines( pCrv)) return false ; // emetto AddCurveMove( pCrv) ; // determino elevazione su fine uscita ptP1 = ptFin ; if( bRecalcElev) { double dEndElev ; if ( GetElevation( m_nPhase, ptP1 - 10 * EPS_SMALL * vtN, vtN, GetRadiusForStartEndElevation(), vtN, dEndElev)) dElev = dEndElev ; } // correzione per punto sotto il grezzo con testa normale da sopra double dSafeZ = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeZ() ; bool bAhUnderRaw = m_bAboveHead && ! m_bAggrBottom && ! m_bTiltingTab && GetAhPointUnderRaw( ptP1, vtN, 0, GetRadiusForStartEndElevation(), m_TParams.m_dLen, false, dSafeZ, vtN, dElev) ; bool bUhAboveRaw = ! m_bAboveHead && GetUhPointAboveRaw( ptP1, vtN, 0, GetRadiusForStartEndElevation(), m_TParams.m_dLen, false, dSafeZ, vtN, dElev) ; bOppositeHome = ( bAhUnderRaw || bUhAboveRaw) ; return true ; } default : bOppositeHome = false ; return false ; } } //---------------------------------------------------------------------------- double Pocketing::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 Pocketing::GetParamOnOpenSide( const ICurveComposite* pCompo, const ICRVCOMPOPOVECTOR& vOtherCrv, Point3d& ptMid, Vector3d& vtMidOrt) { //int Y = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCompo->Clone()) ; //m_pGeomDB->SetMaterial( Y, YELLOW) ; // recupero il vettore estrusione Vector3d vtExtr = Z_AX ; pCompo->GetExtrusion( vtExtr) ; // verifico se tutti i lati sono aperti bool bAllOpen = true ; const ICurve* pMyCrv = pCompo->GetFirstCurve() ; while ( pMyCrv != nullptr) { if ( pMyCrv->GetTempProp() != 1) { bAllOpen = false ; break ; } pMyCrv = pCompo->GetNextCurve() ; } // richiedo lunghezza superiore a diametro utensile più doppio offset radiale double dRefLen = ( bAllOpen ? 0 : m_TParams.m_dDiam + 2 * GetOffsR() - EPS_SMALL) ; double dMaxLen = dRefLen ; // ciclo sulle singole curve bool bFound = false ; const ICurve* pPrevCrv = pCompo->GetLastCurve() ; double dLenPrev = 0 ; if ( pPrevCrv != nullptr && pPrevCrv->GetTempProp() == 1) pPrevCrv->GetLength( dLenPrev) ; const ICurve* pCrv = pCompo->GetFirstCurve() ; while ( pCrv != nullptr) { // analizzo la curva successiva const ICurve* pNextCrv = pCompo->GetNextCurve() ; bool bNextOk = ( pNextCrv != nullptr) ; if ( ! bNextOk) pNextCrv = pCompo->GetFirstCurve() ; double dLenNext = 0 ; if ( pNextCrv != nullptr && pNextCrv->GetTempProp() == 1) pNextCrv->GetLength( dLenNext) ; // verifico la curva corrente if ( pCrv->GetTempProp() == 1) { // contributo dalle entità adiacenti (se non tutte aperte) double dLenAgg = 0 ; if ( ! bAllOpen) { if ( pPrevCrv != nullptr && pPrevCrv->GetTempProp() == 1) { Vector3d vtPrevEnd ; pPrevCrv->GetEndDir( vtPrevEnd) ; Vector3d vtStart ; pCrv->GetStartDir( vtStart) ; dLenAgg += max( 0.4, vtPrevEnd * vtStart) * dLenPrev ; } if ( pNextCrv != nullptr && pNextCrv->GetTempProp() == 1) { Vector3d vtEnd ; pCrv->GetEndDir( vtEnd) ; Vector3d vtNextStart ; pNextCrv->GetStartDir( vtNextStart) ; dLenAgg += max( 0.4, vtEnd * vtNextStart) * dLenNext ; } } // entità corrente double dLen = 0 ; if ( pCrv->GetLength( dLen)) { const double LEN_TOL = 1 ; // se di lunghezza praticamente uguale if ( bFound && dLen + dLenAgg > dRefLen && abs( dLen + dLenAgg - dMaxLen) < LEN_TOL) { Point3d ptTest ; pCrv->GetMidPoint( ptTest) ; if (( m_bAboveHead && ptTest.z > ptMid.z + 100 * EPS_SMALL) || ( ! m_bAboveHead && ptTest.z < ptMid.z - 100 * EPS_SMALL) || ( abs( ptTest.z - ptMid.z) < 100 * EPS_SMALL && ptTest.y < ptMid.y - 100 * EPS_SMALL)) { dMaxLen = max( dMaxLen, dLen + dLenAgg) ; ptMid = ptTest ; // vettore ortogonale verso l'esterno (ruotato -90deg attorno a estrusione) pCrv->GetMidDir( vtMidOrt) ; vtMidOrt.Rotate( vtExtr, 0, -1) ; } } // se più lunga ( o non già trovata ) else if ( dLen + dLenAgg > dMaxLen || !bFound) { dMaxLen = dLen + dLenAgg ; double dParIn ; // cerco il parametro di tale curva (0 < dParIn < 1) migliore per entrata if ( GetParamForPtStartOnEdge( pCrv, pCompo, vOtherCrv, dParIn)) { pCrv->GetPointD1D2( dParIn, ICurve::FROM_PLUS, ptMid) ; PtrOwner pCompoClone( CloneCurveComposite( pCompo)) ; if( IsNull( pCompoClone)) return false ; double dU ; pCompoClone->GetParamAtPoint( ptMid, dU) ; pCompoClone->ChangeStartPoint( dU) ; pCompoClone->GetStartDir( vtMidOrt) ; vtMidOrt.Rotate( vtExtr, 0, -1) ; bFound = true ; } } dLenPrev = dLen ; } } else dLenPrev = 0 ; // vado alla successiva pPrevCrv = pCrv ; pCrv = ( bNextOk ? pNextCrv : nullptr) ; } return bFound ; } //---------------------------------------------------------------------------- bool Pocketing::AdjustContourWithOpenEdges( ICurveComposite* pCompo, ICRVCOMPOPOVECTOR& vCrvIsl, double dTool_Diam, double dOffR, double dSideStep, const Vector3d& vtTrasl, ISurfTriMesh* pStmRaw, bool bInVsOut) { // vettore estrusione Vector3d vtExtr ; pCompo->GetExtrusion( vtExtr) ; // calcolo riferimento nel piano della svuotatura Frame3d frPocket ; Point3d ptStart ; pCompo->GetStartPoint( ptStart) ; frPocket.Set( ptStart, vtExtr) ; // sposto l'inizio a metà del tratto più lungo AdjustContourStart( pCompo, vCrvIsl) ; // raggio di riferimento per offset double dOutEdge = 0.5 * dTool_Diam ; if ( m_Params.m_nSubType == POCKET_SUB_SPIRALIN || m_Params.m_nSubType == POCKET_SUB_ZIGZAG) dOutEdge = max( dOutEdge, dTool_Diam - dSideStep) ; double dRad = dOutEdge + dOffR ; // estraggo parti con proprietà uniforme in un vettore ICURVEPOVECTOR vpCrvs ; int nCurrTempProp ; int nParStart = 0 ; for ( int i = 0 ; i < pCompo->GetCurveCount() ; ++ i) { int nTempProp ; pCompo->GetCurveTempProp( i, nTempProp) ; if ( i == 0) { nCurrTempProp = nTempProp ; nParStart = i ; } else if ( nCurrTempProp != nTempProp) { PtrOwner pCrv( pCompo->CopyParamRange( nParStart, i)) ; if ( IsNull( pCrv)) return false ; pCrv->SetTempProp( nCurrTempProp) ; pCrv->SetExtrusion( vtExtr) ; vpCrvs.emplace_back( Release( pCrv)) ; nCurrTempProp = nTempProp ; nParStart = i ; } } PtrOwner pCrv( pCompo->CopyParamRange( nParStart, pCompo->GetCurveCount())) ; if ( IsNull( pCrv)) return false ; pCrv->SetTempProp( nCurrTempProp) ; pCrv->SetExtrusion( vtExtr) ; vpCrvs.emplace_back( Release( pCrv)) ; // offsetto del raggio le curve aperte for ( int i = 0 ; i < int( vpCrvs.size()) ; ++ i) { if ( vpCrvs[i]->GetTempProp() == 1) { OffsetCurve OffsCrv ; if ( ! OffsCrv.Make( vpCrvs[i], dRad, ICurve::OFF_FILLET)) { m_pMchMgr->SetLastError( 2412, "Error in Pocketing : Offset not computable") ; return false ; } int nCrv_offs = OffsCrv.GetCurveCount() ; if ( nCrv_offs == 0) { // determino la curva ad amo Point3d ptEnd ; vpCrvs[i-1]->GetEndPoint( ptEnd) ; Vector3d vtTg ; vpCrvs[i-1]->GetEndDir( vtTg) ; Vector3d vtOrt = vtTg ; vtOrt.Rotate( vtExtr, 0, -1) ; Point3d ptArc = ptEnd + ( 1.05 * dTool_Diam + 2 * dOffR ) * vtOrt ; //Point3d ptLine = ptArc - 5 * dDiam * vtTg ; PtrOwner pCrvArc( CreateCurveArc()) ; if ( IsNull( pCrvArc)) return false ; pCrvArc->SetExtrusion( vtExtr) ; pCrvArc->Set2PVN( ptEnd, ptArc, vtTg, vtExtr) ; PtrOwner pJCrv( CreateCurveComposite()) ; if ( IsNull( pJCrv)) return false ; pJCrv->AddCurve( Release( pCrvArc)) ; // determino la curva ad amo vpCrvs[i+1]->GetStartDir( vtTg) ; vtOrt = vtTg ; vtOrt.Rotate( vtExtr, 0, -1) ; ptArc = ptStart + ( 1.05 * dTool_Diam + 2 * dOffR ) * vtOrt ; Point3d ptLine = ptArc + 5 * ( 1.05 * dTool_Diam + 2 * dOffR ) * vtTg ; PtrOwner pJCrv1( CreateCurveComposite()) ; if ( IsNull( pJCrv1)) return false ; pJCrv1->SetExtrusion( vtExtr) ; pJCrv1->AddPoint( ptLine) ; pJCrv1->AddLine( ptArc) ; pJCrv1->AddArcTg( ptStart) ; pJCrv->ToLoc( frPocket) ; pJCrv1->ToLoc( frPocket) ; IntersCurveCurve intCC( *pJCrv, *pJCrv1) ; pJCrv->ToGlob( frPocket) ; pJCrv1->ToGlob( frPocket) ; IntCrvCrvInfo aInfo ; if ( intCC.GetIntersCount() > 0) { if ( intCC.GetIntCrvCrvInfo( 0, aInfo)) { PtrOwner pCrvFinal( CreateCurveComposite()) ; PtrOwner PJ_Cut( pJCrv->CopyParamRange( 0, aInfo.IciA[0].dU)) ; PtrOwner PJ1_Cut( pJCrv1->CopyParamRange( 0, aInfo.IciB[0].dU)) ; PJ1_Cut->Invert() ; pCrvFinal->AddCurve( Release( PJ_Cut)) ; pCrvFinal->AddCurve( Release( PJ1_Cut)) ; for ( int u = 0 ; u < pCrvFinal->GetCurveCount() ; ++ u) pCrvFinal->SetCurveTempProp( u, 0, 0) ; vpCrvs[i].Set( Release( pCrvFinal)) ; vpCrvs[i]->SetTempProp( 0) ; } } else continue ; } PtrOwner pCrvlonger( OffsCrv.GetLongerCurve()) ; //int W = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCrvlonger->Clone()) ; //m_pGeomDB->SetMaterial( W, WHITE) ; while ( ! IsNull( pCrvlonger)) { if ( pCrvlonger->IsClosed() && nCrv_offs > 1) { PtrOwner pCrvCompo( CreateCurveComposite()) ; pCrvCompo->AddCurve( Release( pCrvlonger)) ; for ( int u = 0 ; u < pCrvCompo->GetCurveCount() ; ++ u) pCrvCompo->SetCurveTempProp( u, 1, 0) ; vCrvIsl.emplace_back( pCrvCompo->Clone()) ; } else vpCrvs[i].Set( Release( pCrvlonger)) ; pCrvlonger.Set( OffsCrv.GetLongerCurve()) ; } PtrOwner pCrvRange( CreateCurveComposite()) ; pCrvRange->AddCurve( vpCrvs[i]->Clone()) ; for ( int j = 0 ; j < pCrvRange->GetCurveCount() ; ++ j) pCrvRange->SetCurveTempProp( j, 1, 0) ; vpCrvs[i].Set( pCrvRange) ; vpCrvs[i]->SetTempProp( 1) ; } } //int green = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCompo->Clone()) ; //m_pGeomDB->SetMaterial( green, GREEN) ; // clono la pCompo PtrOwner pCompo_clone( CloneCurveComposite( pCompo)) ; // reinserisco le curve, chiudendo eventuali gap pCompo->Clear() ; pCompo->SetExtrusion( vtExtr) ; bool bOpenCurr = false ; double dDiam = 1.05 * dTool_Diam + 2 * dOffR ; for ( int i = 0 ; i < int( vpCrvs.size()) ; ++ i) { // stato curve bool bOpenPrev = bOpenCurr ; bOpenCurr = ( vpCrvs[i]->GetTempProp() != 0) ; // chiudo eventuale gap if ( i > 0) { Point3d ptEnd ; pCompo->GetEndPoint( ptEnd) ; Point3d ptStart ; vpCrvs[i]->GetStartPoint( ptStart) ; if ( ! AreSamePointEpsilon( ptEnd, ptStart, 10 * EPS_SMALL)) { // se passo da chiuso ad aperto if ( ! bOpenPrev && bOpenCurr) { // ----------------------------------------------------------------------------------- PtrOwner pHHHH( CreateCurveComposite()) ; pHHHH->AddCurve( vpCrvs[i]->Clone()) ; Point3d ptS ; pCompo->GetEndPoint( ptS) ; Point3d ptE ; vpCrvs[i+1]->GetStartPoint( ptE) ; PtrOwner pCrvNew( CreateCurveComposite()) ; if ( ! bInVsOut && AdjustPathOutsideRawForOpenEdges( pCompo_clone, vCrvIsl, pHHHH, ptS, ptE, dRad, dDiam, pCrvNew, vtTrasl, pStmRaw, bInVsOut)) { vpCrvs[i].Set( Release( pCrvNew)) ; vpCrvs[i]->GetStartPoint( ptStart) ; } //int BRO = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, vpCrvs[i]->Clone()) ; //m_pGeomDB->SetMaterial( BRO, BROWN) ; // ----------------------------------------------------------------------------------- // determino la curva ad amo Vector3d vtTg ; pCompo->GetEndDir( vtTg) ; Vector3d vtOrt = vtTg ; vtOrt.Rotate( vtExtr, 0, 1) ; Point3d ptArc = ptEnd + dDiam * vtOrt ; //Point3d ptLine = ptArc - 5 * dDiam * vtTg ; PtrOwner pCrvArc( CreateCurveArc()) ; if ( IsNull( pCrvArc)) return false ; pCrvArc->SetExtrusion( vtExtr) ; pCrvArc->Set2PVN( ptEnd, ptArc, vtTg, vtExtr) ; PtrOwner pJCrv( CreateCurveComposite()) ; if ( IsNull( pJCrv)) return false ; pJCrv->AddCurve( Release( pCrvArc)) ; //int y = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pJCrv->Clone()) ; //m_pGeomDB->SetMaterial( y, YELLOW) ; // assegno alle sue sottocurve la proprietà di curva aperta for ( int u = 0 ; u < pJCrv->GetCurveCount() ; ++ u) pJCrv->SetCurveTempProp( u, 1, 0) ; // calcolo l'intersezione nel piano della svuotatura dell'amo con la curva aperta pJCrv->ToLoc( frPocket) ; vpCrvs[i]->ToLoc( frPocket) ; IntersCurveCurve intCC( *pJCrv, *vpCrvs[i]) ; pJCrv->ToGlob( frPocket) ; vpCrvs[i]->ToGlob( frPocket) ; // taglio opportunamente le curve bool bFound = false ; IntCrvCrvInfo aInfo ; if ( intCC.GetIntersCount() > 0 && !bInVsOut) { // cerco la prima intersezione che entra nella curva aperta for ( int j = 0 ; j < intCC.GetIntersCount() ; ++ j) { if ( intCC.GetIntCrvCrvInfo( j, aInfo) && aInfo.IciA[0].nPrevTy == ICCT_OUT) { bFound = true ; break ; } } } if ( bFound) { pJCrv->TrimEndAtParam( aInfo.IciA[0].dU) ; vpCrvs[i]->TrimStartAtParam( aInfo.IciB[0].dU) ; pCompo->AddCurve( ::Release( pJCrv), true, 10 * EPS_SMALL) ; } else { pCompo->AddLine( ptStart) ; pCompo->SetCurveTempProp( pCompo->GetCurveCount() - 1, bInVsOut ? 0 : 1, 0) ; // segmento aggiunto } } // se passo da aperto a chiuso else if ( bOpenPrev && ! bOpenCurr) { // determino la curva ad amo Vector3d vtTg ; vpCrvs[i]->GetStartDir( vtTg) ; Vector3d vtOrt = vtTg ; vtOrt.Rotate( vtExtr, 0, 1) ; Point3d ptArc = ptStart + dDiam * vtOrt ; Point3d ptLine = ptArc + 5 * dDiam * vtTg ; PtrOwner pJCrv( CreateCurveComposite()) ; if ( IsNull( pJCrv)) return false ; pJCrv->SetExtrusion( vtExtr) ; pJCrv->AddPoint( ptLine) ; pJCrv->AddLine( ptArc) ; pJCrv->AddArcTg( ptStart) ; pJCrv->RemoveFirstOrLastCurve( false) ; //int a = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pJCrv->Clone()) ; //m_pGeomDB->SetMaterial( a, ORANGE) ; // assegno alle sue sottocurve la proprietà di curva aperta for ( int u = 0 ; u < pJCrv->GetCurveCount() ; ++ u) pJCrv->SetCurveTempProp( u, 1, 0) ; // calcolo l'intersezione nel piano della svuotatura dell'amo con la curva aperta PtrOwner pLCrv( CreateCurveComposite()) ; if ( IsNull( pLCrv)) return false ; pLCrv->AddCurve( pCompo->GetLastCurve()->Clone()) ; if ( pCompo->GetCurveCount() >= 2) pLCrv->AddCurve( pCompo->GetPrevCurve()->Clone(), false) ; double dUL = pLCrv->GetCurveCount() ; //int A = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pLCrv->Clone()) ; //m_pGeomDB->SetMaterial( A, AQUA) ; pJCrv->ToLoc( frPocket) ; pLCrv->ToLoc( frPocket) ; IntersCurveCurve intCC( *pJCrv, *pLCrv) ; pJCrv->ToGlob( frPocket) ; pLCrv->ToGlob( frPocket) ; // taglio opportunamente le curve IntCrvCrvInfo aInfo ; if ( intCC.GetIntCrvCrvInfo( 0, aInfo) && !bInVsOut) { double dUs, dUe ; pCompo->GetDomain( dUs, dUe) ; pCompo->TrimEndAtParam( dUe - dUL + aInfo.IciB[0].dU) ; pJCrv->TrimStartAtParam( aInfo.IciA[0].dU) ; pCompo->AddCurve( ::Release( pJCrv), true, 10 * EPS_SMALL) ; } else { pCompo->AddLine( ptStart) ; pCompo->SetCurveTempProp( pCompo->GetCurveCount() - 1, bInVsOut ? 0 : 1, 0) ; // segmento come curva aperta } } else { pCompo->AddLine( ptStart) ; pCompo->SetCurveTempProp( pCompo->GetCurveCount() - 1, 1, 0) ; // segmento come curva aperta } } } // aggiungo la curva pCompo->AddCurve( ::Release( vpCrvs[i]), true, 10 * EPS_SMALL) ; //int p = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCompo->Clone()) ; //m_pGeomDB->SetMaterial( p, PURPLE) ; } // non dovrebbe esserci un gap, ma meglio prevenire problemi pCompo->Close() ; //int LI = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCompo->Clone()) ; //m_pGeomDB->SetMaterial( LI, LIME) ; return true ; } //--------------------------------------------------------------------------- bool Pocketing::AdjustPathOutsideRawForOpenEdges( const ICurveComposite* pCompo, const ICRVCOMPOPOVECTOR& vCrvIsland, ICurveComposite* pCrvOpenOffs, const Point3d& ptCrvOpenS, const Point3d& ptCrvOpenE, const double dRad, const double dDiam, ICurveComposite* pNewCrv, const Vector3d& vtTrasl, ISurfTriMesh* pStmRaw, bool bInVsOut) { // controllo la validtà dei parametri if ( pCompo == nullptr || ! pCompo->IsValid() || pCompo->GetCurveCount() == 0 || pCrvOpenOffs == nullptr || ! pCrvOpenOffs->IsValid() || pCrvOpenOffs->GetCurveCount() == 0) return false ; // recupero l'estrusione della curva di bordo Vector3d vtExtr ; pCompo->GetExtrusion( vtExtr) ; // -------------- RECUPERO DELLA CURVA ESTERNA PRIMA E DOPO IL LATO APERTO CORRENTE -------------- double dUTrimS, dUTrimE ; PtrOwner pCompo_Prec( CloneCurveComposite( pCompo)) ; pCompo_Prec->GetParamAtPoint( ptCrvOpenS, dUTrimS) ; pCompo_Prec->TrimEndAtParam( dUTrimS) ; PtrOwner pCompo_Succ( CloneCurveComposite( pCompo)) ; pCompo_Succ->GetParamAtPoint( ptCrvOpenE, dUTrimE) ; pCompo_Succ->TrimStartAtParam( dUTrimE) ; PtrOwner pCrvOpen( CloneCurveComposite( pCompo)) ; pCrvOpen->TrimStartEndAtParam( dUTrimS, dUTrimE) ; PtrOwner pCompo_noOpenCrv( CloneCurveComposite( pCompo_Succ)) ; pCompo_noOpenCrv->AddCurve( pCompo_Prec->Clone()) ; // recupero i punti e i vettori tangenti iniziali e finali del lato aperto Point3d ptSTART ; pCrvOpenOffs->GetStartPoint( ptSTART) ; Point3d ptEND ; pCrvOpenOffs->GetEndPoint( ptEND) ; Vector3d vtSTART ; pCrvOpenOffs->GetStartDir( vtSTART) ; Vector3d vtEND ; pCrvOpenOffs->GetEndDir( vtEND) ; // -------------- CREAZIONE DELLA REGIONE DI INFLUENZA -------------- // 1) Creo una copia della curva PtrOwner pCrvOpen_clone( CloneCurveComposite( pCrvOpen)) ; if ( IsNull( pCrvOpen_clone) || ! pCrvOpen_clone->IsValid()) return false ; // 2) Controllo la lunghezza della curva double dLen ; if ( ! pCrvOpen_clone->GetLength( dLen) || dLen < dDiam + EPS_SMALL) return false ; // 3) Accorcio l'inizio e la fine del raggio dell'utensile double dUS, dUE ; pCrvOpen_clone->GetParamAtLength( dRad, dUS) ; pCrvOpen_clone->GetParamAtLength( dLen - dRad, dUE) ; pCrvOpen_clone->TrimStartEndAtParam( dUS, dUE) ; bool bOk = true ; // 4) Creo regione squadrata da questa curva PtrOwner pSfrInc( GetSurfFlatRegionFromFatCurve( Release( pCrvOpen_clone), dRad, true, false)) ; if ( IsNull( pSfrInc) || ! pSfrInc->IsValid()) { Point3d ptE ; pCrvOpenOffs->GetEndPoint( ptE) ; PtrOwner pCrv_CompoHelp( CreateCurveComposite()) ; pCrv_CompoHelp->AddCurve( pCrvOpen->Clone()) ; pCrv_CompoHelp->AddLine( ptE) ; PtrOwner pCrvOpenOffs_Clone( CloneCurveComposite( pCrvOpenOffs)) ; pCrvOpenOffs_Clone->Invert() ; pCrv_CompoHelp->AddCurve( Release( pCrvOpenOffs_Clone)) ; pCrvOpen->GetStartPoint( ptE) ; pCrv_CompoHelp->AddLine( ptE) ; pSfrInc.Set( CreateSurfFlatRegion()) ; pSfrInc->AddExtLoop( Release( pCrv_CompoHelp)) ; //m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSfrInc->Clone()) ; bOk = false ; if ( IsNull( pSfrInc) || ! pSfrInc->IsValid()) return false ; } // -------------- AGGIORNAMENTO DELLA REGIONE DI INFLUENZA -------------- // creo un vettore con la pCompo senza lato aperto e le isole contenute al suo interno ICRVCOMPOPOVECTOR vCrvToCheck ; vCrvToCheck.emplace_back( pCompo_noOpenCrv->Clone()) ; // la curva esterna in prima posizione for ( int i = 0 ; i < ( int)vCrvIsland.size() ; ++ i) vCrvToCheck.emplace_back( vCrvIsland[i]->Clone()) ; // scorro il vettore creato... for ( int c = 0 ; c < ( int)vCrvToCheck.size() ; ++ c) { // 1) recupero la curva corrente PtrOwner pCrvCurr( CloneCurveComposite( vCrvToCheck[c])) ; if ( IsNull( pCrvCurr) || ! pCrvCurr->IsValid()) return false ; CRVCVECTOR ccClass ; if ( pSfrInc->GetCurveClassification( *pCrvCurr, EPS_SMALL, ccClass)) { for ( int i = 0 ; i < ( int)ccClass.size() ; ++ i) { if ( ccClass[i].nClass == CRVC_IN) { // 2) Trovo il tratto di curva interno PtrOwner pCrvCurrPartIn( GetCurveComposite( pCrvCurr->CopyParamRange( ccClass[i].dParS, ccClass[i].dParE))) ; if ( IsNull( pCrvCurrPartIn) || ! pCrvCurrPartIn->IsValid()) continue ; pCrvCurrPartIn->SetExtrusion( vtExtr) ; // 3) ricavo il punto iniziale e il punto finale, assieme ai vettori tangenti Point3d ptS1 ; pCrvCurrPartIn->GetStartPoint( ptS1) ; Point3d ptE1 ; pCrvCurrPartIn->GetEndPoint( ptE1) ; Vector3d vtS1 ; pCrvCurrPartIn->GetStartDir( vtS1) ; Vector3d vtE1 ; pCrvCurrPartIn->GetEndDir( vtE1) ; // 4) effettuo l'Offset della curva del diametro del tool OffsetCurve OffsCrv ; if ( ! OffsCrv.Make( pCrvCurrPartIn, - dDiam, ICurve::OFF_FILLET)) { m_pMchMgr->SetLastError( 2412, "Error in Pocketing : Offset not computable") ; return false ; } // 5) scorro tutte le curve di Offset che si sono formate, prendendo sempre la più lunga tra le rimanenti PtrOwner pOffLongestCrv( OffsCrv.GetLongerCurve()) ; while ( ! IsNull( pOffLongestCrv)) { // 6) escludo le curve che si chiudono su se stesse dopo l'Offset if ( ! pOffLongestCrv->IsClosed()) { // 7) trasformo la curva in composita PtrOwner pCompoPartInOffs( CreateCurveComposite()) ; pCompoPartInOffs->AddCurve( pOffLongestCrv->Clone()) ; // 8) creo due archi che collegano i punti iniziali e finali della curva originale e di quella con offset PtrOwner pArcS( CreateCurveArc()) ; PtrOwner pArcE( CreateCurveArc()) ; if ( IsNull( pArcS) || IsNull( pArcE)) return false ; Point3d ptS2 ; pCompoPartInOffs->GetStartPoint( ptS2) ; Point3d ptE2 ; pCompoPartInOffs->GetEndPoint( ptE2) ; Vector3d vtS2 ; pCompoPartInOffs->GetStartDir( vtS2) ; Vector3d vtE2 ; pCompoPartInOffs->GetEndDir( vtE2) ; pArcS->Set2PVN( ptS1, ptS2, - vtS1, - vtExtr) ; pArcE->Set2PVN( ptE2, ptE1, vtE2, - vtExtr) ; // 9) creo il loop esterno della regione da aggiungere PtrOwner pCrvExtBorder( CreateCurveComposite()) ; if ( IsNull( pCrvExtBorder)) return false ; pCrvExtBorder->AddCurve( Release( pArcS)) ; // primo tratto lineare pCrvExtBorder->AddCurve( Release( pCompoPartInOffs)) ; // tratto di offset pCrvExtBorder->AddCurve( Release( pArcE)) ; // secondo tratto lineare pCrvCurrPartIn->Invert() ; // inversione del tratto interno pCrvExtBorder->AddCurve( Release( pCrvCurrPartIn)) ; // aggiunta del tratto interno //int rrr = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCrvExtBorder->Clone()) ; //m_pGeomDB->SetMaterial( rrr, RED) ; if ( pCrvExtBorder->IsClosed()) { // 9) Creo la nuova regione da aggiungere a quella di influenza PtrOwner pSfrExpan( CreateSurfFlatRegion()) ; if ( IsNull( pSfrExpan)) return false ; pSfrExpan->AddExtLoop( Release( pCrvExtBorder)) ; //int green = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSfrExpan->Clone()) ; // //m_pGeomDB->SetMaterial( green, GREEN) ; // if ( pSfrExpan->IsValid()) { if ( AreOppositeVectorApprox( pSfrExpan->GetNormVersor(), vtExtr)) pSfrExpan->Invert() ; pSfrInc->Add( *pSfrExpan) ; } } } pOffLongestCrv.Set( OffsCrv.GetLongerCurve()) ; } } } } else return false ; } PtrOwner pSrfInc_toDraw( CloneSurfFlatRegion( pSfrInc)) ; pSrfInc_toDraw->Translate( vtTrasl) ; if ( ! bOk) { //int brown1 = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSrfInc_toDraw->Clone()) ; // //m_pGeomDB->SetMaterial( brown1, BROWN) ; } // recupero il Grezzo e sottraggo tutto ciò che sta nella regione if ( pStmRaw != nullptr) { bool bIsChanged ; if ( m_bIntersRaw) IntersSurfWithRaw( pSfrInc, pStmRaw, 1.01 * vtTrasl, bIsChanged, 1500 * EPS_SMALL, bInVsOut, false, false) ; } if ( bInVsOut) { //int P = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pStmRaw->Clone()) ; // //m_pGeomDB->SetMaterial( P, LIME) ; } PtrOwner pSrfInc_toDraw1( CloneSurfFlatRegion( pSfrInc)) ; pSrfInc_toDraw1->Translate( vtTrasl) ; if ( ! bOk) { //int P = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pStmRaw->Clone()) ; // //m_pGeomDB->SetMaterial( P, LIME) ; //int brown = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSrfInc_toDraw1->Clone()) ; // //m_pGeomDB->SetMaterial( brown, YELLOW) ; } // RECUPERO DELLA CURVA DI BORDO ESTERNA DA AGGIUNGERE ALLA SVUOTATURA PtrOwner pCrvNewBorder( GetCurveComposite( pSfrInc->GetLoop( 0, 0))) ; if ( IsNull( pCrvNewBorder)) return false ; double dUSTART ; if ( ! pCrvNewBorder->GetParamAtPoint( ptSTART, dUSTART, 5000 * EPS_SMALL)) { int nFlag ; if ( ! DistPointCurve( ptSTART, *pCrvNewBorder).GetParamAtMinDistPoint( 0, dUSTART, nFlag)) return false ; } pCrvNewBorder->ChangeStartPoint( dUSTART) ; double dUEND ; if ( ! pCrvNewBorder->GetParamAtPoint( ptEND, dUEND, 5000 * EPS_SMALL)) { int nFlag ; if ( ! DistPointCurve( ptEND, *pCrvNewBorder).GetParamAtMinDistPoint( 0, dUEND, nFlag)) return false ; } pCrvNewBorder->TrimEndAtParam( dUEND) ; pNewCrv->Clear() ; pNewCrv->AddCurve( Release( pCrvNewBorder)) ; for ( int u = 0 ; u < pNewCrv->GetCurveCount() ; ++ u) pNewCrv->SetCurveTempProp( u, 1, 0) ; //int P = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pNewCrv->Clone()) ; // //m_pGeomDB->SetMaterial( P, LIME) ; return true ; } //---------------------------------------------------------------------------- bool Pocketing::AdjustContourStart( ICurveComposite* pCompo, const ICRVCOMPOPOVECTOR& vCrvIsl, bool bOrder) { // se cerco semplicemente il tratto lineare chiuso più lungo ... if ( ! bOrder) { // cerco il tratto lineare più lungo che non sia aperto int i = 0 ; int nMax = - 1 ; double dLenMax = 0 ; const ICurve* pCrv = pCompo->GetFirstCurve() ; while ( pCrv != nullptr) { double dLen ; if ( pCrv->GetType() == CRV_LINE && pCrv->GetTempProp() == 0 && pCrv->GetLength( dLen) && dLen > dLenMax) { dLenMax = dLen ; nMax = i ; } ++ i ; pCrv = pCompo->GetNextCurve() ; } // se non trovato o troppo corto, cerco il tratto generico più lungo if ( nMax < 0 || dLenMax < 2 * m_TParams.m_dDiam) { i = 0 ; pCrv = pCompo->GetFirstCurve() ; while ( pCrv != nullptr) { double dLen ; if ( pCrv->GetType() != CRV_LINE && pCrv->GetTempProp() == 0 && pCrv->GetLength( dLen) && dLen > dLenMax) { dLenMax = dLen ; nMax = i ; } ++ i ; pCrv = pCompo->GetNextCurve() ; } } const ICurve* pCrvClone( pCompo->GetCurve( nMax)) ; double dPar ; if ( GetParamForPtStartOnEdge( pCrvClone, pCompo, vCrvIsl, dPar)) pCompo->ChangeStartPoint( nMax + dPar) ; else // sposto inizio a metà if ( nMax >= 0) pCompo->ChangeStartPoint( nMax + 0.5) ; } // se invece sto cercando di entrare da un lato chiuso per una svuotatura, allora riordino i lati // chiusi a seconda della lunghezza, e a partire dal più lungo cerco un parametro su tale curva che mi consenta // un'entrata sufficientemente distante da isole e da altre curve della curva stessa su cui cerco l'entrata ... else { // creo un vettore di indici che definisce l'ordine delle curve chiuse in base alla lunghezza INTVECTOR vInd ; vInd.reserve( pCompo->GetCurveCount()) ; // vettore di indici già utilizzati INTVECTOR vIndUsed ; vIndUsed.reserve( pCompo->GetCurveCount()) ; double dMaxLen = -INFINITO ; int nCurrInd = 0 ; bool bStop = false ; for ( int c = 0 ; c < pCompo->GetCurveCount() && ! bStop ; ++ c) { bStop = true ; for ( int i = 0 ; i < pCompo->GetCurveCount() ; ++ i) { int nProp_i ; // se la curva i-esima non è già stata considerata ed è aperta... if ( find( vIndUsed.begin(), vIndUsed.end(), i) == vIndUsed.end() && pCompo->GetCurveTempProp( i, nProp_i, 0) && nProp_i == 0) { // creo la curva i-esima const ICurve* pCrv_i( pCompo->GetCurve( i)) ; double dLen_i ; if( pCrv_i->GetLength( dLen_i) && dLen_i > dMaxLen) { // se di lunghezza maggiore alla soglia... dMaxLen = dLen_i ; nCurrInd = i ; bStop = false ; } } } vIndUsed.push_back( nCurrInd) ; vInd.push_back( nCurrInd) ; dMaxLen = -INFINITO ; } if (( int)vInd.size() == 0) { // se questa condizione fosse vera allora non sono riuscito ad entrare da nessun lato aperto in precedenza e non // ho nemmeno un lato chiuso disponibile per entrare... pCompo->ChangeStartPoint( 0.5) ; return true ; } // ora che ho riempito il vettore di indici lo scorro e cerco di entrare in questi lati chiusi secondo l'ordine bool bOk = false ; for ( int i = 0 ; i < ( int)vInd.size() && !bOk ; ++ i) { const ICurve* pCrv( pCompo->GetCurve( vInd[i])) ; double dPar ; if ( GetParamForPtStartOnEdge( pCrv, pCompo, vCrvIsl, dPar)) { pCompo->ChangeStartPoint( vInd[i] + dPar) ; bOk = true ; } } if ( ! bOk) { // se non riesco ad entrare da nessun lato chiuso, considerando che in precedenza ho già provato ad // entrare da tutti i lati aperti... pCompo->ChangeStartPoint( 0.5) ; return true ; } } return true ; } //---------------------------------------------------------------------------- bool Pocketing::VerifyLeadInHelix( ISurfFlatRegion* pSrfChunk, const Point3d& ptCen, double dRad) const { // controllo della superifice if ( pSrfChunk == nullptr) return false ; // vettore di tutte le curve della superficie ICRVCOMPOPOVECTOR vCrv ; for( int c = 0 ; c < pSrfChunk->GetChunkCount() ; c++) { for ( int l = 0 ; l < pSrfChunk->GetLoopCount( c) ; l++) { vCrv.emplace_back( GetCurveComposite( pSrfChunk->GetLoop( c, l))) ; } } if (( int)vCrv.size() == 0) return false ; // estraggo il bordo esterno PtrOwner pCompo( CloneCurveComposite( vCrv[0])) ; if ( IsNull( pCompo)) return false ; // recupero il piano della curva di contorno Point3d ptStart ; Vector3d vtN ; if ( ! pCompo->GetStartPoint( ptStart) || ! pCompo->GetExtrusion( vtN)) return false ; // porto il centro sullo stesso piano del contorno Point3d ptCenL = ptCen - ( ptCen - ptStart) * vtN * vtN ; // calcolo la distanza del centro dal contorno double dMinDist ; bool bOk = DistPointCurve( ptCenL, *pCompo).GetDist( dMinDist) && dMinDist > dRad + 0.5 * m_TParams.m_dDiam - 10 * EPS_SMALL ; // se la curva per l'attacco è valida per tale, controllo che l'elica non intersechi eventuali isole for ( int i = 1 ; bOk && i < int( vCrv.size()) ; i++) bOk = DistPointCurve( ptCenL, *vCrv[i]).GetDist( dMinDist) && dMinDist > dRad + 0.5 * m_TParams.m_dDiam - 10 * EPS_SMALL ; return bOk ; } //---------------------------------------------------------------------------- bool Pocketing::VerifyLeadInZigZag( ISurfFlatRegion* pSrfChunk, const Point3d& ptPa, const Point3d& ptPb) const { // controllo della superificie if ( pSrfChunk == nullptr) return false ; // vettore di tutte le curve della superficie ICRVCOMPOPOVECTOR vCrv ; for ( int c = 0 ; c < pSrfChunk->GetChunkCount() ; c++) { for ( int l = 0 ; l < pSrfChunk->GetLoopCount( c) ; l++) { vCrv.emplace_back( GetCurveComposite( pSrfChunk->GetLoop( c, l))) ; } } if ( vCrv.size() == 0) return false ; // estraggo il bordo esterno PtrOwner pCompo( CloneCurveComposite( vCrv[0])) ; if ( IsNull( pCompo)) return false ; // recupero il piano della curva di contorno Point3d ptStart ; Vector3d vtN ; if ( ! pCompo->GetStartPoint( ptStart) || ! pCompo->GetExtrusion( vtN)) return false ; // porto i punti sullo stesso piano del contorno Point3d ptPaL = ptPa - ( ptPa - ptStart) * vtN * vtN ; Point3d ptPbL = ptPb - ( ptPb - ptStart) * vtN * vtN ; // calcolo la distanza dei due punti dal contorno double dMinDistPa ; if ( ! DistPointCurve( ptPaL, *pCompo).GetDist( dMinDistPa)) return false ; double dMinDistPb ; if ( ! DistPointCurve( ptPbL, *pCompo).GetDist( dMinDistPb)) return false ; bool bOk = dMinDistPa > 0.5 * m_TParams.m_dDiam - 10 * EPS_SMALL && dMinDistPb > 0.5 * m_TParams.m_dDiam - 10 * EPS_SMALL ; // se la curva per l'attacco è valida per tale, controllo che lo ZigZag non intersechi eventuali isole for ( int i = 1 ; bOk && i < int( vCrv.size()) ; i++) { if ( ! DistPointCurve( ptPaL, *vCrv[i]).GetDist( dMinDistPa)) return false ; if ( ! DistPointCurve( ptPbL, *vCrv[i]).GetDist( dMinDistPb)) return false ; bOk = dMinDistPa > 0.5 * m_TParams.m_dDiam - 10 * EPS_SMALL && dMinDistPb > 0.5 * m_TParams.m_dDiam - 10 * EPS_SMALL ; } return bOk ; } //---------------------------------------------------------------------------- bool Pocketing::CalcDistanceFromRawSurface( int nPhase, const Point3d& ptP, const Vector3d& vtDir, double& dDist, Vector3d& vtNorm) { //if ( ! GetElevation( nPhase, ptP, vtDir, dDist, vtNorm)) // return false ; // se punto esterno al grezzo //if ( abs( dDist) < EPS_SMALL) { // double dDist1, dDist2 ; // if ( ! GetElevation( nPhase, ptP, -vtDir, dDist1)) // return false ; // if ( ! GetElevation( nPhase, ptP - vtDir * ( dDist1), vtDir, dDist2, vtNorm)) // return false ; // if ( abs( dDist2) > EPS_SMALL && abs( dDist1) > EPS_SMALL) // dDist = dDist2 - dDist1 ; //} //if ( ! GetElevation( nPhase, ptP, vtDir, dDist, vtNorm) // || ! GetSignedDistFromStmRaw( nPhase, ptP, vtDir, dDist, vtNorm)) // return false ; return true ; } //---------------------------------------------------------------------------- bool Pocketing::GetParamsAtEachStep( ISURFFRPOVECTOR& vSrfSliced, vector& vCrvOEWithFlags, BOOLVECTOR vbChangedPrec, const ISurfFlatRegion* pSrfChunk, const int& nStep, const Vector3d vtTool, const double& dElev, const double& dDepth, const double& dStep) { for ( int j = 1 ; j <= nStep ; ++ j) { // vettore traslazione corrente allo step j-esimo Vector3d vtTrasl = - vtTool * ( dDepth - dElev + j * dStep) ; // vettore delle curve con Flag per lati aperti ICRVCOMPOPOVECTOR vCrvOEF ; // flag se la superificie è cambiata bool bChanged = false ; // copia del chunk c-esimo della superificie attuale PtrOwner pSrfToAdapt( CloneSurfFlatRegion( pSrfChunk)) ; if ( IsNull( pSrfToAdapt)) return false ; // adatto la superficie dello step corrente con la geometria del grezzo if ( AdaptSfrWithRaw( pSrfToAdapt, vtTrasl, 5 * ( dDepth - dElev + dStep) - 50 * EPS_SMALL, vCrvOEF, bChanged)) { vSrfSliced[j-1].Set( pSrfToAdapt->Clone()) ; // la superificie potrebbe non essere valida ( ad esempio se già svuotata tutta con un Tool in precedenza...) if ( ! IsNull( vSrfSliced[j-1])) { for ( int h = 0 ; h < ( int)vCrvOEF.size() ; ++ h) vCrvOEWithFlags[j-1].emplace_back( Release( vCrvOEF[h])) ; // controllo se la superificie attuale e precedente sono diverse tra loro if ( j > 1) { double dAreaPrec = 0 ; double dAreaAct = 0 ; if ( ! IsNull( vSrfSliced[j-2])) { vSrfSliced[j-2]->GetArea( dAreaPrec) ; vSrfSliced[j-1]->GetArea( dAreaAct) ; if ( abs( dAreaAct - dAreaPrec) > 500 * EPS_SMALL) vbChangedPrec[j-1] = true ; } else vbChangedPrec[j-1] = true ; } } } else return false ; } return true ; } //---------------------------------------------------------------------------- bool Pocketing::AdaptSfrWithRaw( ISurfFlatRegion* pSrf, Vector3d vtTrasl, const double& dRawSecLen, ICRVCOMPOPOVECTOR& vCrvOEFlags, bool& bChanged, double dAreaToll) { // controllo dei parametri if ( pSrf == nullptr || dAreaToll < EPS_SMALL) return false ; // recupero la temp prop 0 ( id per gruppo del grezzo corrente) PtrOwner pCrv( pSrf->GetLoop( 0, 0)) ; if ( IsNull( pCrv)) return false ; int nProp0 = pCrv->GetTempProp( 0) ; // ricavo il grezzo attuale della lavorazione PtrOwner pStmRaw( CreateSurfTriMesh()) ; if ( ! GetStmRawPart( nProp0 , pStmRaw, GLOB_FRM)) return false ; // se il grezzo è stato trovato, allora controllo intersezioni e proiezioni per lati aperti if ( pStmRaw->IsValid() || pStmRaw->GetTriangleCount() > 0) { // tengo una copia della superificie prima dell'intersezione con il grezzo PtrOwner pSrfOrig( CloneSurfFlatRegion( pSrf)) ; if ( IsNull( pSrfOrig) || ! pSrfOrig->IsValid()) return false ; // 1) INTERSEZIONE CON GREZZO if ( m_bIntersRaw) { // proporzionale all'area ? 95 %? if ( ! IntersSurfWithRaw( pSrf, pStmRaw, vtTrasl, bChanged, 500 * EPS_SMALL, true, m_dDiam_Prec < EPS_SMALL)) return false ; if ( pSrf->GetChunkCount() == 0 || ! pSrf->IsValid()) return true ; PtrOwner pSrf_toDraw( CloneSurfFlatRegion( pSrf)) ; pSrf_toDraw->Translate( vtTrasl) ; int a = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSrf_toDraw->Clone()) ; m_pGeomDB->SetMaterial( a, AQUA) ; for ( int c = 0 ; c < pSrf_toDraw->GetChunkCount() ; ++ c) { for ( int l = 0 ; l < pSrf_toDraw->GetLoopCount( c) ; ++ l) { const ICurveComposite* pCrvCompo( GetCurveComposite( pSrf_toDraw->GetLoop( c, l))) ; for ( int u = 0 ; u < pCrvCompo->GetCurveCount() ; ++ u) { int nProp0 ; pCrvCompo->GetCurveTempProp( u, nProp0, 0) ; int nProp1 ; pCrvCompo->GetCurveTempProp( u, nProp1, 1) ; int aaa = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCrvCompo->GetCurve( u)->Clone()) ; if ( nProp1 != -99) m_pGeomDB->SetMaterial( aaa, nProp0 == 0 ? BLUE : RED) ; else m_pGeomDB->SetMaterial( aaa, Color( 1.0, 0.5, 0.0)) ; } } } } // 2) PROIEZIONE CON GREZZO if ( m_bProjectRaw) { // recupero la Trimesh di partenza if ( ! ProjectRaw( pSrf, vtTrasl, pStmRaw, nProp0, dRawSecLen, pSrfOrig, 500 * EPS_SMALL)) return false ; if ( pSrf->GetChunkCount() == 0 || ! pSrf->IsValid()) return true ; PtrOwner pSrf_toDraw( CloneSurfFlatRegion( pSrf)) ; pSrf_toDraw->Translate( vtTrasl) ; int a = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSrf_toDraw->Clone()) ; m_pGeomDB->SetMaterial( a, BLUE) ; for ( int c = 0 ; c < pSrf_toDraw->GetChunkCount() ; ++ c) { for ( int l = 0 ; l < pSrf_toDraw->GetLoopCount( c) ; ++ l) { const ICurveComposite* pCrvCompo( GetCurveComposite( pSrf_toDraw->GetLoop( c, l))) ; for ( int u = 0 ; u < pCrvCompo->GetCurveCount() ; ++ u) { int nProp0 ; pCrvCompo->GetCurveTempProp( u, nProp0, 0) ; int aaa = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCrvCompo->GetCurve( u)->Clone()) ; m_pGeomDB->SetMaterial( aaa, nProp0 == 0 ? BLUE : RED) ; } } } } } // salvo una copia della superficie attuale PtrOwner pSrf_noOpenEdge( CloneSurfFlatRegion( pSrf)) ; if ( IsNull( pSrf_noOpenEdge)) return false ; // 3) ESTENSIONE PER I LATI APERTI if ( ! ModifySurfByOpenEdge( pSrf, vCrvOEFlags, vtTrasl, pStmRaw)) return false ; /*for ( int c = 0 ; c < pSrf->GetChunkCount() ; ++ c) { for ( int l = 0 ; l < pSrf->GetLoopCount( c) ; ++ l) { const ICurveComposite* pCrvCompo( GetCurveComposite( pSrf->GetLoop( c, l))) ; for ( int u = 0 ; u < pCrvCompo->GetCurveCount() ; ++ u) { int nProp0 ; pCrvCompo->GetCurveTempProp( u, nProp0, 0) ; int aaa = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCrvCompo->GetCurve( u)->Clone()) ; m_pGeomDB->SetMaterial( aaa, nProp0 == 0 ? BLUE : RED) ; } } }*/ //PtrOwner pSrf_toDraw( CloneSurfFlatRegion( pSrf)) ; //pSrf_toDraw->Translate( vtTrasl) ; //int p = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSrf_toDraw->Clone()) ; //m_pGeomDB->SetMaterial( p, PURPLE) ; // 4) SE SUPERIFICIE PRECEDENTEMENTE GIA' LAVORATA... if ( m_dDiam_Prec > 0) return GetNewSrfByAnotherPocketing( pSrf, pSrf_noOpenEdge, vtTrasl) ; return pSrf->IsValid() && pSrf->GetChunkCount() != 0 ; } //---------------------------------------------------------------------------- bool Pocketing::AdjustFakeOpenEdges( ICurveComposite* pCrvCompo, const ISurfFlatRegion* pSfrOrig, const ISurfTriMesh* pStmRaw, const Vector3d vtTrasl) { // controllo dei parametri if ( pCrvCompo == nullptr || ! pCrvCompo->IsValid() || pCrvCompo->GetCurveCount() == 0) return false ; if ( pStmRaw == nullptr) // se non c'è grezzo... return true ; //m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCrvCompo->Clone()) ; //m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSfrOrig->Clone()) ; //m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pStmRaw->Clone()) ; // recupero le tmpProp, vettore estrusione e spessore int nTmpProp0 = pCrvCompo->GetTempProp() ; int nTmpProp1 = pCrvCompo->GetTempProp( 1) ; Vector3d vtExtr ; pCrvCompo->GetExtrusion( vtExtr) ; double dThick ; pCrvCompo->GetThickness( dThick) ; // -------------------- TAGLIO IL GREZZO CON IL PIANO DEFINITO ALLO STEP ATTUALE ------------- // 1) CREAZIONE DEL PIANO Plane3d plProj ; Point3d ptCen ; if ( ! pCrvCompo->GetCentroid( ptCen)) // punto if ( ! pCrvCompo->GetStartPoint( ptCen)) return false ; Vector3d vtNorm = pSfrOrig->GetNormVersor() ; // normale if ( vtNorm.IsSmall()) return false ; plProj.Set( ptCen + vtTrasl, -vtNorm) ; // così taglio tutto cià che sta nel semipiano negativo dello step attuale if ( ! plProj.IsValid()) return false ; // 2) TAGLIO DEL GREZZO PtrOwner pSrfRaw_clone( CloneSurfTriMesh( pStmRaw)) ; if ( IsNull( pSrfRaw_clone)) return false ; if ( ! pSrfRaw_clone->Cut( plProj, true)) return false ; if ( ! pSrfRaw_clone->IsValid() || pSrfRaw_clone->GetTriangleCount() == 0) return true ; // ------------------------------------------------------------------------------------------- // ------- PROIEZIONE DELLE CURVE DI OGNI FACCIA DEL GREZZO RICAVATO SUL PIANO DELLA SVUOTATURA -------------- // Proietto ora le curve, delle facce della superificie ottenuta, sul piano della svuotatura ICRVCOMPOPVECTOR vCrvExtProj ; PtrOwner pCrvCompo_Clone_Trasl( CloneCurveComposite( pCrvCompo)) ; if ( IsNull( pCrvCompo_Clone_Trasl) || ! pCrvCompo_Clone_Trasl->IsValid()) return false ; pCrvCompo_Clone_Trasl->Translate( vtTrasl) ; vCrvExtProj.emplace_back( CloneCurveComposite( pCrvCompo_Clone_Trasl)) ; // come indice 0 for ( int f = 0 ; f < pSrfRaw_clone->GetFacetCount() ; ++ f) { // controllo se la faccia è quasi perpendicolare, nel caso la salto Vector3d vtN_check ; pSrfRaw_clone->GetFacetNormal( f, vtN_check) ; if ( abs( vtN_check * vtNorm) < EPS_ZERO) continue ; POLYLINEVECTOR vPL ; pSrfRaw_clone->GetFacetLoops( f, vPL) ; // per ogni Loop l della faccia f for ( int l = 0 ; l < ( int) vPL.size() ; ++ l) { PtrOwner pCrvBorder( CreateCurveComposite()) ; if ( IsNull( pCrvBorder) || ! pCrvBorder->FromPolyLine( vPL[l])) return false ; PtrOwner pCrvProjFacef( ProjectCurveOnPlane( *pCrvBorder, plProj)) ; if ( IsNull( pCrvProjFacef) || ! pCrvProjFacef->IsValid()) return false ; // controllo validità della curva ( che sia chiusa e non degenere) double dArea = EPS_SMALL ; Plane3d plCheck ; if ( ! pCrvProjFacef->IsClosed() || ! pCrvProjFacef->GetArea( plCheck, dArea) || dArea <= EPS_SMALL) continue ; // creo la curva composita associata PtrOwner pCrvBorderProj_f( CreateCurveComposite()) ; pCrvBorderProj_f->AddCurve( Release( pCrvProjFacef)) ; vCrvExtProj.emplace_back( Release( pCrvBorderProj_f)) ; } } //for ( int i = 0 ; i < vCrvExtProj.size() ; ++ i) //m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, vCrvExtProj[i]->Clone()) ; //------------------------------------------------------------------------------------------------------------- // ---------------- CREAZIONE DELLA VERA A PROPRIA REGIONE DI INCIDENZA, COME SOMMA DELLE // ----------------------------- SINGOLE FLATREGIONS DI PROIEZIONE ----------------------------- PtrOwner pSrf_Proj_Ext( CreateSurfFlatRegion()) ; if ( IsNull( pSrf_Proj_Ext)) return false ; for ( int i = 1 ; i < ( int)vCrvExtProj.size() ; ++ i) { PtrOwner pSrf_H( CreateSurfFlatRegion()) ; if ( IsNull( pSrf_H)) return false ; pSrf_H->AddExtLoop( vCrvExtProj[i]->Clone()) ; // inverto se le normali risultano opposte if ( pSrf_H->IsValid()) { if ( AreOppositeVectorApprox( pSrf_H->GetNormVersor() , pSfrOrig->GetNormVersor())) pSrf_H->Invert() ; } if ( pSrf_Proj_Ext->GetChunkCount() == 0) pSrf_Proj_Ext.Set( Release( pSrf_H)) ; else pSrf_Proj_Ext->Add( *Release( pSrf_H)) ; } // creo la vera e propria regione di proiezione, sommando la proiezione esterna con la superifcie originale da svuotare PtrOwner pSrf_Proj( CloneSurfFlatRegion( pSrf_Proj_Ext)) ; PtrOwner pSrf_ind0( CreateSurfFlatRegion()) ; if ( IsNull( pSrf_Proj) || ! pSrf_Proj->IsValid() || IsNull( pSrf_ind0)) return false ; pSrf_ind0->AddExtLoop( vCrvExtProj[0]->Clone()) ; if ( AreOppositeVectorApprox( pSrf_ind0->GetNormVersor(), pSfrOrig->GetNormVersor())) pSrf_ind0->Invert() ; pSrf_Proj->Add( *pSrf_ind0) ; int ooo = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSrf_Proj->Clone()) ; m_pGeomDB->SetMaterial( ooo, Color( 0.0, 1.0, 0.0, 0.3)) ; // =============================================================================================================== // Creo la nuova curva che dovrò restiturire alla fine della proiezione ( settando le rispettive proprietà) PtrOwner pCrvCompo_Final( CreateCurveComposite()) ; if ( IsNull( pCrvCompo_Final)) return false ; pCrvCompo_Final->SetExtrusion( vtExtr) ; pCrvCompo_Final->SetThickness( dThick) ; pCrvCompo_Final->SetTempProp( nTmpProp0, 0) ; pCrvCompo_Final->SetTempProp( nTmpProp1, 1) ; // Clono la superificie originaria, portandola allo step corrente PtrOwner pSrfOrig_clone( CloneSurfFlatRegion( pSfrOrig)) ; if ( IsNull( pSrfOrig_clone) || ! pSrfOrig_clone->IsValid()) return false ; pSrfOrig_clone->Translate( vtTrasl) ; int oooo = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSrfOrig_clone->Clone()) ; m_pGeomDB->SetMaterial( oooo, Color( 0.0, 0.0, 0.0, 0.3)) ; // controllo le curve della composita bool bLoopL_isChanged = false ; for ( int u = 0 ; u < pCrvCompo_Clone_Trasl->GetCurveCount() ; ++ u) { PtrOwner pCrv_u( pCrvCompo_Clone_Trasl->GetCurve( u)->Clone()) ; if ( IsNull( pCrv_u) || ! pCrv_u->IsValid()) return false ; // ricavo la temp prop int nTmpProp = pCrv_u->GetTempProp( 0) ; if ( nTmpProp == 1) { // se si tratta di un lato aperto... // 1) clono il lato PtrOwner pCrv_uOpen_clone( pCrv_u->Clone()) ; if ( IsNull( pCrv_uOpen_clone) || ! pCrv_uOpen_clone->IsValid()) return false ; pCrv_uOpen_clone->SetExtrusion( vtExtr) ; // 2) effettuo l'Offset OffsetCurve OffsCrv ; if ( ! OffsCrv.Make( pCrv_uOpen_clone, m_dDiam_Prec > 0 ? 0.5 * m_dDiam_Prec + m_dOffsetR_Prec : 0.5 * m_TParams.m_dDiam + GetOffsR(), ICurve::OFF_FILLET) || OffsCrv.GetCurveCount() == 0) return false ; // 3) ricavo la curva di Offset PtrOwner pCrv_uOpen_Offs( OffsCrv.GetLongerCurve()) ; if ( IsNull( pCrv_uOpen_Offs) || ! pCrv_uOpen_Offs->IsValid()) return false ; // TOGLIEREEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE--- PtrOwner hhhhhh( pCrv_uOpen_Offs->Clone()) ; int aaa = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, hhhhhh->Clone()) ; m_pGeomDB->SetMaterial( aaa, YELLOW) ; // ------------------------------------------------------------------------------------------------- // 4) classifico la curva di offset ricavata con la supericie originale // NB. Tutti tratti di curva che sono esterni alla superificie originale e che si trovano all'interno della // superificie di proeizione del grezzo lo rovineranno al di fuori della superficie originale, quindi // vanno impostati come chiusi CRVCVECTOR ccClass ; if ( pSrfOrig_clone->GetCurveClassification( *pCrv_uOpen_Offs, 10 * EPS_SMALL, ccClass)) { for ( int j = 0 ; j < ( int)ccClass.size() ; ++ j) { // 5) scorro tutti i tratti di curva della classificazione // NB. I parametri sulla curva di Offset e sulla curva originale sono in proporizione ( la curva // è singola, quindi non ci sono raccordi). Posso quindi sfruttare i parametri della classificazione // della curva Offsettata e utilizzarli per spezzare in sottocurve la curva originaria PtrOwner pCrv_j_Offs( pCrv_uOpen_Offs->CopyParamRange( ccClass[j].dParS, ccClass[j].dParE)) ; PtrOwner pCrv_uj( pCrv_u->CopyParamRange( ccClass[j].dParS, ccClass[j].dParE)) ; if ( IsNull( pCrv_j_Offs) || ! pCrv_j_Offs->IsValid() || IsNull( pCrv_uj) || ! pCrv_uj->IsValid()) continue ; if ( ccClass[j].nClass == CRVC_OUT) { CRVCVECTOR ccClass1 ; bool bSetClose = false ; if ( pSrf_Proj->GetCurveClassification( *pCrv_j_Offs, EPS_SMALL, ccClass1)) { for ( int jj = 0 ; jj < ( int)ccClass1.size() && !bSetClose ; ++ jj) { if ( ccClass1[jj].nClass == CRVC_IN) { bLoopL_isChanged = true ; bSetClose = true ; //int ff = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCrv_uj->Clone()) ; //m_pGeomDB->SetMaterial( ff, Color( 0.95, 0.0, 0.63)) ; } } } pCrv_uj->SetTempProp( !bSetClose, 0) ; pCrv_uj->SetTempProp( bSetClose ? -99 : 0, 1) ; } pCrvCompo_Final->AddCurve( pCrv_uj->Clone()) ; } // chiusura ciclo for sui tratti di classificazione... } else // se classificazione errata -> lascio la curva invariata pCrvCompo_Final->AddCurve( pCrv_u->Clone()) ; } else // se curva chiusa, la aggiungo pCrvCompo_Final->AddCurve( pCrv_u->Clone()) ; //m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCrvCompo_Final->Clone()) ; } // se ci sono stati cambiamenti nella curva ... if ( ! bLoopL_isChanged) return true ; // altrimenti sotituisco la curva originale, traslo e miglioro... if ( pCrvCompo_Final != nullptr && pCrvCompo_Final->IsValid() && pCrvCompo_Final->IsClosed()) { pCrvCompo_Final->Translate( - vtTrasl) ; pCrvCompo_Final->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL, true, true) ; pCrvCompo->Clear() ; pCrvCompo->CopyFrom( pCrvCompo_Final) ; } return pCrvCompo != nullptr && pCrvCompo->IsValid() && pCrvCompo->GetCurveCount() > 0 ; } //---------------------------------------------------------------------------- bool Pocketing::ModifySurfByOpenEdge( ISurfFlatRegion* pSrf, ICRVCOMPOPOVECTOR& vCrvOEFlags, const Vector3d& vtTrasl, ISurfTriMesh* pStmRaw) { // controllo dei parametri if ( pSrf == nullptr || ! pSrf->IsValid() || pSrf->GetChunkCount() == 0) return false ; // creo la superifcie da restituire... PtrOwner pSrfFinal( CreateSurfFlatRegion()) ; if ( IsNull( pSrfFinal)) return false ; // per ogni Chunck della superificie ottenuta... for ( int c = 0 ; c < pSrf->GetChunkCount() ; ++ c) { // 1) salvo la curva esterna -> per casi ottimizzati PtrOwner pCrvEL( GetCurveComposite( pSrf->GetLoop( c, 0))) ; if ( IsNull( pCrvEL)) return false ; vCrvOEFlags.emplace_back( Release( pCrvEL)) ; // 2) creo un vettore con le isole del Chunk ( e uno con le isole ammissibili) ICRVCOMPOPOVECTOR vCrvIsl ; for ( int l = 1 ; l < pSrf->GetLoopCount( c) ; ++ l) { PtrOwner pCrvIL( GetCurveComposite( pSrf->GetLoop( c, l))) ; if ( IsNull( pCrvIL)) return false ; vCrvIsl.emplace_back( Release( pCrvIL)) ; } ICRVCOMPOPOVECTOR vCrvModIsland ; // 3) Allargo la superificie ( curva esterna) mediante i lati aperti bool bSomeOpen = false ; int nProp0 = -1 ; PtrOwner pCrvExt( GetCurveComposite( pSrf->GetLoop( c, 0))) ; for ( int u = 0 ; u < pCrvExt->GetCurveCount() && !bSomeOpen ; ++ u) { if ( pCrvExt->GetCurveTempProp( u, nProp0, 0) && nProp0 == 1) bSomeOpen = true ; } if ( bSomeOpen) { // se trovo dei lati aperti // 3.1) sistemo la superificie if ( ! AdjustContourWithOpenEdges( pCrvExt, vCrvIsl, m_dDiam_Prec > 0 ? m_dDiam_Prec : m_TParams.m_dDiam, m_dDiam_Prec > 0 ? m_dOffsetR_Prec : GetOffsR(), m_dDiam_Prec > 0 ? m_dSideStep_Prec : GetSideStep(), vtTrasl, pStmRaw)) { m_pMchMgr->SetLastError( 2430, "Error in Pocketing : adjust open edges failed") ; return false ; } } // 4) aggiungo le curve alla nuova superificie // NB Controllo se la curva si Autointerseca... alcuni lati aperti potrebbero mergiarsi SelfIntersCurve SiC( *pCrvExt) ; if ( SiC.GetIntersCount() > 0) { // creo la flatRegion SurfFlatRegionByContours SfrBC ; SfrBC.AddCurve( pCrvExt->Clone()) ; PtrOwner pSfrHelp( SfrBC.GetSurf()) ; if ( IsNull( pSfrHelp) || ! pSfrHelp->IsValid()) return false ; pCrvExt.Set( GetCurveComposite( pSfrHelp->GetLoop( 0, 0))) ; for ( int l = 1 ; l < pSfrHelp->GetLoopCount( 0) ; ++ l) { PtrOwner pCrvClosedIsland( GetCurveComposite( pSfrHelp->GetLoop( 0, l))) ; if ( IsNull( pCrvClosedIsland) || ! pCrvClosedIsland->IsValid()) return false ; for ( int u = 0 ; u < pCrvClosedIsland->GetCurveCount() ; ++ u) pCrvClosedIsland->SetCurveTempProp( u, 0, 0) ; vCrvIsl.emplace_back( Release( pCrvClosedIsland)) ; } } // 5) Controllo i bordi delle isole ottenute e modifico quelli in cui sono presenti lati aperti for ( int i = 0 ; i < ( int)vCrvIsl.size() ; ++ i) { bSomeOpen = false ; nProp0 = -1 ; int nCrvOpen = 0 ; PtrOwner pCrvIsl( GetCurveComposite( vCrvIsl[i]->Clone())) ; for ( int u = 0 ; u < pCrvIsl->GetCurveCount() ; ++ u) { if ( pCrvIsl->GetCurveTempProp( u, nProp0, 0) && nProp0 == 1) { bSomeOpen = true ; ++ nCrvOpen ; } } if ( bSomeOpen) { // se trovo dei lati aperti // 5.1) se l'isola è tutta aperta e trascurabile la talgo if ( nCrvOpen == pCrvIsl->GetCurveCount()) { // 5.1.1) Offsetto l'isola e controllo se sparisce OffsetCurve OffsCrv ; if ( ! OffsCrv.Make( pCrvIsl, m_dDiam_Prec > 0 ? m_dDiam_Prec + m_dOffsetR_Prec : m_TParams.m_dDiam, ICurve::OFF_FILLET)) { m_pMchMgr->SetLastError( 2412, "Error in Pocketing : Offset not computable") ; return false ; } // nel caso l'Offset sparisca, allora passo all'isola successiva if ( OffsCrv.GetCurveCount() == 0) continue ; } // 5.2) sistemo la superificie ICRVCOMPOPOVECTOR vCrvNULL ; if ( ! AdjustContourWithOpenEdges( pCrvIsl, vCrvNULL, m_dDiam_Prec > 0 ? m_dDiam_Prec : m_TParams.m_dDiam, m_dDiam_Prec > 0 ? m_dOffsetR_Prec : GetOffsR(), m_dDiam_Prec > 0 ? m_dSideStep_Prec : GetSideStep(), vtTrasl, pStmRaw)) { m_pMchMgr->SetLastError( 2430, "Error in Pocketing : adjust open edges failed") ; return false ; } } vCrvModIsland.emplace_back( pCrvIsl->Clone()) ; } // 6) Creo la nuova superificie da svuotare // NB. I vari chunk, dopo esseresi allargati nei lati aperti, potrebbero unirsi tra loro in alcuni parti... SurfFlatRegionByContours SfrBC_Def ; SfrBC_Def.AddCurve( Release( pCrvExt)) ; for ( int i = 0 ; i < ( int)vCrvModIsland.size() ; ++ i) SfrBC_Def.AddCurve( Release( vCrvModIsland[i])) ; PtrOwner pSrfHelp_( SfrBC_Def.GetSurf()) ; if ( pSrfFinal->GetChunkCount() == 0) pSrfFinal.Set( pSrfHelp_) ; else pSrfFinal->Add( *pSrfHelp_) ; } pSrf->Clear() ; pSrf->CopyFrom( pSrfFinal) ; return pSrf->IsValid() && pSrf->GetChunkCount() > 0 ; } //---------------------------------------------------------------------------- bool Pocketing::IntersSurfWithRaw( ISurfFlatRegion* pSfrPock, const ISurfTriMesh* pStmRaw, const Vector3d& vtTrasl, bool& bIsChanged, double dAreaToll, bool bInVsOut, bool bRemoveSmallRawParts, bool bComputeOpenEdge) { // se funzione non necessaria, esco subito if ( ! m_bIntersRaw) return true ; bIsChanged = false ; // trasformo in Trimesh la superificie da svuotare ( per sottrazione con il grezzo) PtrOwner pStm( CloneSurfTriMesh( pSfrPock->GetAuxSurf())) ; if ( IsNull( pStm)) return false ; // calcolo l'area della superificie da svuotare double dAreaBefore = 0 ; if ( ! pStm->GetArea( dAreaBefore)) return false ; // salvo una copia della superificie Trimesh ( nel caso in cui la sottrazione non funzioni) PtrOwner pStmCopy( CloneSurfTriMesh( pStm)) ; if ( IsNull( pStmCopy)) return false ; // traslo la superificie da svuotare a seconda dello step e la taglio con il grezzo if ( ! pStm->Translate( vtTrasl) || //! m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pStm->Clone()) || ! m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pStmRaw->Clone()) || ! pStm->CutWithOtherSurf( *pStmRaw, bInVsOut, true) || pStm->GetTriangleCount() == 0) { pStm.Set( pStmCopy) ; // nel caso il taglio non sia riuscito, allungo leggermente il vettore di traslazione e riprovo if ( ! pStm->Translate(( 1 + 20 * EPS_SMALL) * vtTrasl) || ! pStm->CutWithOtherSurf( *pStmRaw, bInVsOut, true) || pStm->GetTriangleCount() == 0) // nel caso non riesca ancora, lascio la superificie da svuotare inviariata... return true ; } //int A = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pStm->Clone()) ; //m_pGeomDB->SetMaterial( A, AQUA) ; // calcolo la nuova area e la confronto con la precedente ( capisco se la superificie è cambiata o meno) double dAreaAfter = 0 ; if ( ! pStm->GetArea( dAreaAfter) || abs( dAreaBefore - dAreaAfter) < dAreaToll) return true ; // se la superificie non è cambiata, allora lascio tutto inviariato... bIsChanged = true ; // se le Aree sono cambiate, allora la superificie da svuotare interseca il grezzo // ------------- creo la FlatRegion come sottrazione delle sue superifici ------------- // imposto i loop per la nuova FlatRegion dai loop della superificie Trimesh ottenuta per sottrazione // recupero thickness ed estrusione dalle curve della superificie originaria PtrOwner pCrvEL( pSfrPock->GetLoop( 0, 0)) ; double dThick ; pCrvEL->GetThickness( dThick) ; Vector3d vtExtr ; pCrvEL->GetExtrusion( vtExtr) ; // determino il piano su cui giace la superificie originale della svuotatura ( traslato) Plane3d plPock ; Vector3d vtN = pSfrPock->GetNormVersor() ; Point3d ptC ; pSfrPock->GetCentroid( ptC) ; plPock.Set( ptC, vtN) ; if ( ! plPock.IsValid()) return false ; plPock.Translate( vtTrasl) ; // creo la nuova superificie da svuotare come FlatRegion SurfFlatRegionByContours SrfChunkDef ; POLYLINEVECTOR vPl ; pStm->GetLoops( vPl) ; for ( int i = 0 ; i < ( int)vPl.size() ; ++ i) { // recupero la curva composita PolyLine PL = vPl[i] ; PtrOwner pCrv( CreateCurveComposite()) ; pCrv->FromPolyLine( PL) ; //int V = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCrv->Clone()) ; //m_pGeomDB->SetMaterial( V, GREEN) ; // essendo una curva derivante da un'intersezione di Trimesh ho una composita derivante da una polyLine, // devo recuperare gli archi PolyArc PA ; Frame3d frPock ; frPock.Set( ptC, vtN) ; if ( ! frPock.IsValid()) return false ; pCrv->ToLoc( frPock) ; pCrv->ApproxWithArcsEx( 5 * EPS_SMALL, ANG_TOL_STD_DEG, LIN_FEA_STD, PA) ; // 500 * EPS_SMALL pCrv->Clear() ; pCrv->FromPolyArc( PA) ; pCrv->ToGlob( frPock) ; pCrv->SetExtrusion( vtExtr) ; pCrv->SetThickness( dThick) ; //int l = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCrv->Clone()) ; //m_pGeomDB->SetMaterial( l, LIME) ; // la converto in una semplice cruva per proiettarla su piano della svuotatura // dato che le curve sono prese da una trimesh, le riproietto sul piano traslato per sicurezza e per evitare approssimazioni double dS, dE ; pCrv->GetDomain( dS, dE) ; PtrOwner pCrv_c( pCrv->CopyParamRange( dS, dE)) ; if ( IsNull( pCrv_c) || ! pCrv_c->IsValid()) return false ; PtrOwner pCrv_proj( ProjectCurveOnPlane( *pCrv_c, plPock)) ; //int yy = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCrv_proj->Clone()) ; //m_pGeomDB->SetMaterial( yy, YELLOW) ; SrfChunkDef.AddCurve( Release( pCrv_proj)) ; // aggiungo le curve proiettate } PtrOwner pSrfByCurves( SrfChunkDef.GetSurf()) ; if ( IsNull( pSrfByCurves) || pSrfByCurves->GetChunkCount() == 0) // controllo validità della FlatRegion return false ; // ------------- aggiunta delle piccole parti del grezzo ------------- // controllo se ho rimosso piccole regioni di grezzo... // queste regioni possono creare problemi nella definizione di lati aperti if ( bRemoveSmallRawParts) { PtrOwner pSrf_RawPartsRemoved( CloneSurfFlatRegion( pSrfByCurves)) ; PtrOwner pSrf_Pock_orig( CloneSurfFlatRegion( pSfrPock)) ; if ( IsNull( pSrf_RawPartsRemoved) || ! pSrf_RawPartsRemoved->IsValid() || IsNull( pSrf_Pock_orig) || ! pSrf_Pock_orig->IsValid()) return false ; pSrf_Pock_orig->Translate( vtTrasl) ; if ( pSrf_Pock_orig->Subtract( *pSrf_RawPartsRemoved)) { for ( int cc_ = 0 ; cc_ < pSrf_Pock_orig->GetChunkCount() ; ++ cc_) { // clono dil Chunk cc_ esimo PtrOwner pSrfCcc_( pSrf_Pock_orig->CloneChunk( cc_)) ; if ( IsNull( pSrfCcc_) || ! pSrfCcc_->IsValid()) return false ; if ( ! pSrfCcc_->Offset( m_dDiam_Prec > 0 ? - 0.5 * m_dDiam_Prec - m_dOffsetR_Prec : - 0.5 * m_TParams.m_dDiam + GetOffsR(), ICurve::OFF_FILLET) || pSrfCcc_->GetChunkCount() == 0) { // se Offset interno sparisce, allora aggiungo il chunk cc_ esimo alla superificie da svuotare PtrOwner pSrf_Chunck_cc_( pSrf_Pock_orig->CloneChunk( cc_)) ; if ( IsNull( pSrf_Chunck_cc_) || ! pSrf_Chunck_cc_->IsValid()) return false ; pSrfByCurves->Add( *Release( pSrf_Chunck_cc_)) ; } } } } // rincontrollo ancora le aree, nel caso siano circa uguali lascio la superificie invariata if ( pSrfByCurves->GetArea( dAreaAfter) && pSfrPock->GetArea( dAreaBefore) && abs( dAreaBefore - dAreaAfter) < dAreaBefore * 0.00125) return true ; // se la superificie non è cambiata, allora lascio tutto inviariato... // riporto la superificie tagliata alla quota originale pSrfByCurves->Translate( - vtTrasl) ; // ricalcolo i lati aperti ( se richisto) if ( bComputeOpenEdge) { PtrOwner pStmRaw_clone( CloneSurfTriMesh( pStmRaw)) ; if ( IsNull( pStmRaw_clone) || ! SetOpenOrCloseEdge( pSrfByCurves, pSfrPock, false, pStmRaw_clone, vtTrasl)) return false ; } // modifico la superficie da svuotare pSfrPock->Clear() ; pSfrPock->CopyFrom( pSrfByCurves) ; return true ; } //---------------------------------------------------------------------------- bool Pocketing::SetOpenOrCloseEdge( ISurfFlatRegion* pSrfTP, const ISurfFlatRegion* pSrfOrig, bool bFromProj, ISurfTriMesh* pStmRaw, Vector3d vtTrasl) { // controllo parametri if ( pSrfTP == nullptr || pSrfTP->GetChunkCount() == 0 || pSrfOrig == nullptr || pSrfOrig->GetChunkCount() == 0) return false ; // recupero le proprietà PtrOwner pCrvEL( pSrfOrig->GetLoop( 0, 0)) ; int nProp0 = pCrvEL->GetTempProp( 0) ; int nProp1 = pCrvEL->GetTempProp( 1) ; // creo un vettore contenente tutti i loop esterni ed Interni della superificie originaria int nExtLoop = pSrfOrig->GetChunkCount() ; ICRVCOMPOPOVECTOR vCrvAll ; for ( int c = 0 ; c < ( int)pSrfOrig->GetChunkCount() ; ++ c) vCrvAll.emplace_back( GetCurveComposite( pSrfOrig->GetLoop( c, 0))) ; for ( int c = 0 ; c < ( int)pSrfOrig->GetChunkCount() ; ++ c) for ( int l = 1 ; l < ( int)pSrfOrig->GetLoopCount( c) ; ++ l) vCrvAll.emplace_back( GetCurveComposite( pSrfOrig->GetLoop( c, l))) ; // superificie da ritornare ( aggiornata) SurfFlatRegionByContours pSrfMod ; // NB. Se sto svuotando un Chunk della superificie, quando lo interseco con il grezzo potrei ottenere più Chunks... // per ogni chunk della superificie da svuotare ... for ( int c = 0 ; c < pSrfTP->GetChunkCount() ; ++ c) { // per ogni loop ... for ( int l = 0 ; l < pSrfTP->GetLoopCount( c) ; ++ l) { // ricavo il loop come curva composita PtrOwner pCrv( GetCurveComposite( pSrfTP->GetLoop( c, l))) ; if ( IsNull( pCrv)) return false ; // sistemazioni varie pCrv->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL) ; for ( int i = 0 ; i < pCrv->GetCurveCount() ; ++ i) { if ( !bFromProj) // se non derivo da una proiezione, setto di Defualt le tmp prop della curva a -1 pCrv->SetCurveTempProp( i, -1, 0) ; // setto proprietà da definire di default for ( int j = 0 ; j < ( int)vCrvAll.size() ; ++ j) { int nStat = 0 ; if ( ! SetTmpPropByOverlap( pCrv, i, vCrvAll[j], nStat, 1500 * EPS_SMALL)) return false ; if ( nStat == 1) // se overlap Trovato, non controllo overlap su altri loops break ; } } // sistemo gli errori dovuti alle tolleranze if ( ! CheckSmallPartsForOpenEdge( pCrv)) return false ; // controllo che le isole definite sulla superificie originale siano coerenti con le nuove isole ricavate ICRVCOMPOPOVECTOR vAllCrv_Isl ; for ( int i = nExtLoop ; i < ( int)vCrvAll.size() ; ++ i) { // copio la curva corrente da analizzare PtrOwner pCrv_CurrIsland( CloneCurveComposite( vCrvAll[i])) ; if ( IsNull( pCrv_CurrIsland) || !pCrv_CurrIsland->IsValid()) return false ; bool bIsIn = false ; // scorro tutti loop della superificie originale for ( int cc_ = 0 ; cc_ < pSrfTP->GetChunkCount() && ! bIsIn ; ++ cc_) { for ( int ll_ = 1 ; ll_ < pSrfTP->GetLoopCount( cc_) && ! bIsIn ; ++ ll_) { // copio il bordo corrente PtrOwner pCrv_onOrig( GetCurveComposite( pSrfTP->GetLoop( cc_, ll_))) ; if ( IsNull( pCrv_onOrig) || !pCrv_onOrig->IsValid()) return false ; bool bIsStillIsland = true ; // controllo se l'isola fa overlap con altre isole for ( int u = 0 ; u < pCrv_CurrIsland->GetCurveCount() && bIsStillIsland; ++ u) { const ICurve* pCrv = pCrv_CurrIsland->GetCurve( u) ; if ( pCrv == nullptr || ! pCrv->IsValid()) return false ; int nStat = 0 ; if ( CheckSimpleOverlap( pCrv, pCrv_onOrig, nStat, 500 * EPS_SMALL) && nStat == 0) bIsStillIsland = false ; } if ( bIsStillIsland) { vAllCrv_Isl.emplace_back( CloneCurveComposite( vCrvAll[i])) ; bIsIn = true ; } } } } // controllo le sottocurve non definite con TmpProp = -1 ( non se sono nel caso di una proeizione) for ( int i = 0 ; i < pCrv->GetCurveCount() && !bFromProj ; ++ i) { int nProp ; if ( pCrv->GetCurveTempProp( i, nProp) && nProp == -1) { // controllo che quel lato non abbia un estremo in comune con un'isola if ( ! CheckBoundingPointForIslands( pCrv, i, vAllCrv_Isl, 0, true)) { pCrv->SetCurveTempProp( i, ( int)vAllCrv_Isl.size() == 0 ? 1 : 0) ; } } } // imposto le proprietà ... pCrv->SetTempProp( nProp0, 0) ; pCrv->SetTempProp( nProp1, 1) ; // controllo se i lati aperti impostati sono effettivamente aperti ( se non sono nella proieizone) if ( ! bFromProj) if ( ! AdjustFakeOpenEdges( pCrv, pSrfOrig, pStmRaw, vtTrasl)) return false ; // aggiungo la curva alla nuova superificie pSrfMod.AddCurve( pCrv->Clone()) ; } } pSrfTP->Clear() ; PtrOwner pSrfF( pSrfMod.GetSurf()) ; pSrfTP->CopyFrom( pSrfF) ; return pSrfTP->IsValid() && pSrfTP->GetChunkCount() != 0 ; } //---------------------------------------------------------------------------- bool Pocketing::GetCurveByOverlap( const ICurve* pCrv_, const ICurveComposite* pCrvCompo_, int& nInd, double dToll) { // controllo dei parametri if ( pCrv_ == nullptr || pCrvCompo_ == nullptr) return false ; nInd = -1 ; // porto le curve nel sistema di riferimento locale ( clonandole ) PtrOwner pCrv( pCrv_->Clone()) ; PtrOwner pCrvCompo( pCrvCompo_->Clone()) ; if ( IsNull( pCrv) || IsNull( pCrvCompo)) return false ; // creo il vettore di curve contenute in pCrvCompo ICURVEPOVECTOR vCrv ; vCrv.reserve( pCrvCompo->GetCurveCount()) ; const ICurve* pMyCrv = pCrvCompo->GetFirstCurve() ; while ( pMyCrv != nullptr) { vCrv.emplace_back( pMyCrv->Clone()) ; pMyCrv = pCrvCompo->GetNextCurve() ; } if (( int)vCrv.size() == 0) return false ; // vettore di punti sulla curva PNTVECTOR vPts ; const double nMAX = 10.0 ; for ( int i = 0 ; i <= nMAX ; ++ i) { double dPar = i / nMAX ; Point3d ptC ; pCrv->GetPointD1D2( dPar, ICurve::FROM_PLUS, ptC) ; vPts.push_back( ptC) ; } // controllo se una sottocurva della composita è abbastanza vicina a tutti i punti trovati for ( int jj = 0 ; jj < ( int)vCrv.size() ; ++ jj) { bool bOk = true ; for ( int i = 0 ; i <= nMAX && bOk ; ++ i) { if ( ! vCrv[jj]->IsPointOn( vPts[i], dToll)) { bOk = false ; } } if ( bOk) { nInd = jj ; return true ; } } return false ; } //---------------------------------------------------------------------------- bool Pocketing::CheckBoundingPointForIslands( ICurveComposite* pCrvCurr, int nInd, const ICRVCOMPOPOVECTOR& vCrvAll, int nIndFI, bool bFlag) { // controllo dei parametri if ( pCrvCurr == nullptr) return false ; const ICurve* pCrv = pCrvCurr->GetCurve( nInd) ; Point3d ptS ; pCrv->GetStartPoint( ptS) ; // punto iniziale di pCrv Point3d ptE ; pCrv->GetEndPoint( ptE) ; // punto finale di pCrv int nIS = -1 ; int nIE = -1 ; int nStat = -1 ; // scorro tutto il vettore di curve interne ( le isole) for ( int i = nIndFI ; i < ( int)vCrvAll.size() ; ++ i){ if ( vCrvAll[i]->IsPointOn( ptS, 1000 * EPS_SMALL)) { double dUS ; vCrvAll[i]->GetParamAtPoint( ptS, dUS, 1000 * EPS_SMALL) ; dUS = ceil( dUS) ; int nProp ; vCrvAll[i]->GetCurveTempProp( dUS, nProp, 0) ; if ( nProp == 0) nIS = i ; } if ( vCrvAll[i]->IsPointOn( ptE, 1000 * EPS_SMALL)) { double dUE ; vCrvAll[i]->GetParamAtPoint( ptE, dUE, 1000 * EPS_SMALL) ; dUE = ceil( dUE) ; int nProp ; vCrvAll[i]->GetCurveTempProp( dUE, nProp, 0) ; if ( nProp == 0) nIE = i ; } if ( nIS != -1 && nIE != -1) break ; } // 0 -> solo punto iniziale su Isola | 1 -> solo punto finale su Isola | 2 -> estremi su Isola/e if ( nIS != -1 && nIE == -1) nStat = 0 ; else if ( nIS == -1 && nIE != -1) nStat = 1 ; else if ( nIS != -1 && nIE != -1) nStat = 2 ; else if ( nIS == -1 && nIE == -1) { // non tocca nessun'isola pCrvCurr->SetCurveTempProp( nInd, bFlag) ; // la curva è scelta dal Flag return true ; } // se la curva è troppo corta, allora non la spezzo double dLen = 0 ; if ( ! pCrv->GetLength( dLen)) return false ; if ( nStat != 2 && dLen < 2 * m_TParams.m_dDiam + 100 * EPS_SMALL) { pCrvCurr->SetCurveTempProp( nInd, 0) ; // la curva è chiusa return true ; } if ( nStat == 2 && dLen < 3 * m_TParams.m_dDiam + 100 * EPS_SMALL) { pCrvCurr->SetCurveTempProp( nInd, 0) ; // la curva è chiusa return true ; } if ( nStat != 2) { // se ho un solo estremo su un'isola double dUCut = 0.5 ; pCrv->GetParamAtLength( nStat == 0 ? m_TParams.m_dDiam * 1.05 : dLen - m_TParams.m_dDiam * 1.05, dUCut) ; pCrvCurr->AddJoint( nInd + dUCut) ; pCrvCurr->SetCurveTempProp( nInd, nStat) ; pCrvCurr->SetCurveTempProp( nInd + 1, 1 - nStat) ; } else { // se ho entrambi gli estremi su isole double dUCutS = 0.5 ; double dUCutE = 0.5 ; pCrv->GetParamAtLength( m_TParams.m_dDiam * 1.05, dUCutS) ; pCrv->GetParamAtLength( dLen - m_TParams.m_dDiam * 1.05, dUCutE) ; pCrvCurr->AddJoint( nInd + dUCutS) ; pCrvCurr->SetCurveTempProp( nInd, 0) ; pCrvCurr->AddJoint( nInd + 1 + ( 1 - dUCutS) * dUCutE) ; pCrvCurr->SetCurveTempProp( nInd + 1, 1) ; pCrvCurr->SetCurveTempProp( nInd + 2 , 0) ; } return true ; } //---------------------------------------------------------------------------- bool Pocketing::GetStmRawPart( int nId, ISurfTriMesh* pSrfTMRaw, Frame3d frPocket) { // controllo se ho i flag abilitati if ( ! m_bIntersRaw && ! m_bProjectRaw) return true ; // controllo MachManager e database geometrico if ( m_pMchMgr == nullptr || m_pGeomDB == nullptr) return false ; // dall'indice della geometria da svuotare, recupero l'Id del gruppo Processing in cui mi trovo int nProcessingId = m_pGeomDB->GetParentId( nId) ; if ( nProcessingId != GDB_ID_NULL) { int nPartId = m_pGeomDB->GetParentId( nProcessingId) ; if ( nPartId != GDB_ID_NULL) { int nIdIter = m_pGeomDB->GetFirstNameInGroup( nPartId, BOX_NAME) ; if ( nIdIter != GDB_ID_NULL) { int nIdBox = m_pGeomDB->GetFirstInGroup( nIdIter) ; if ( nIdBox != GDB_ID_NULL) { const IGeoObj* pGObj = m_pGeomDB->GetGeoObj( nIdBox) ; Frame3d frRawPart ; m_pGeomDB->GetGlobFrame( nIdIter, frRawPart) ; if ( pGObj == nullptr) return false ; if ( pGObj->GetType() == SRF_TRIMESH) { PtrOwner pSrfRawPart( CloneSurfTriMesh( pGObj)) ; if ( IsNull( pSrfRawPart)) return false ; pSrfRawPart->LocToLoc( frRawPart, frPocket) ; pSrfTMRaw->CopyFrom( pSrfRawPart) ; } } } } } return true ; } //---------------------------------------------------------------------------- bool Pocketing::OptimizeChunkOneWay( ISurfFlatRegion* pSrfOrig, ISURFFRPOVECTOR& vSrfIdeal, INTVECTOR& vIndChunk, PNTVECTOR& vPtCheck) { // controllo parametri if ( pSrfOrig == nullptr || pSrfOrig->GetChunkCount() == 0) return false ; vSrfIdeal.clear() ; vIndChunk.clear() ; vPtCheck.clear() ; // Temp prop della superificie int nProp0 ; int nProp1 ; // clono la superificie passata alla funzione PtrOwner pSrfToPock( CloneSurfFlatRegion( pSrfOrig)) ; if ( IsNull( pSrfToPock) || pSrfToPock->GetChunkCount() == 0) return false ; // classifico i chunks in modo da creare delle regioni ideali; una regione ideale è formata da un chunk principale // con tutti gli altri contenuti in esso ( in questo modo ottimizzo i percorsi per i bordi) INTVECTOR vChunksAvailable( pSrfToPock->GetChunkCount(), 1) ; struct PtSPtC { // struttura per punti inziali int nInd ; // indice per vettori vPtStart, vbMidOpen, vPtMidOpen, vVtMidOut Point3d ptC ; // punto check sulla curva } ; typedef vector vPtSCheck ; vPtSCheck vNewPtStart ; for ( int c = 0 ; c < pSrfToPock->GetChunkCount() ; ++ c) { PtrOwner pSrfIdeal( CreateSurfFlatRegion()) ; if ( IsNull( pSrfIdeal)) return false ; if ( vChunksAvailable[c] == 1) { // se Chunk valido... PtrOwner pCrvExt( GetCurveComposite( pSrfToPock->GetLoop( c, 0))) ; if ( IsNull( pCrvExt)) return false ; nProp0 = pCrvExt->GetTempProp( 0) ; nProp1 = pCrvExt->GetTempProp( 1) ; pSrfIdeal.Set( pSrfToPock->CloneChunk( c)) ; // inserisco curva esterna vChunksAvailable[c] = -1 ; PtSPtC newPtSPtC ; newPtSPtC.nInd = c ; pCrvExt->GetStartPoint( newPtSPtC.ptC) ; for ( int i = 0 ; i < int( vChunksAvailable.size()) ; ++ i) { if ( vChunksAvailable[i] == 1) { // se chunk valido... PtrOwner pCrvExtC( GetCurveComposite( pSrfToPock->GetLoop( i, 0))) ; if ( IsNull( pCrvExtC)) return false ; IntersCurveCurve intCC( *pCrvExtC, *pCrvExt) ; CRVCVECTOR ccClass, ccClass1 ; intCC.GetCurveClassification( 0, EPS_SMALL, ccClass) ; intCC.GetCurveClassification( 1, EPS_SMALL, ccClass1) ; if (( ccClass.size() == 1 && ccClass[0].nClass == CRVC_IN) || ( ccClass1.size() == 1 && ccClass1[0].nClass == CRVC_IN)) { pSrfIdeal->Add( *pSrfToPock->CloneChunk( i)) ; // ... inserisco loop interno vChunksAvailable[i] = -1 ; if (( int)ccClass1.size() == 1 && ccClass1[0].nClass == CRVC_IN) { pCrvExt.Set( pCrvExtC->Clone()) ; newPtSPtC.nInd = i ; pCrvExtC->GetStartPoint( newPtSPtC.ptC) ; i = 0 ; } } } } vNewPtStart.push_back( newPtSPtC) ; } if ( pSrfIdeal->GetChunkCount() > 0) { vSrfIdeal.emplace_back( Release( pSrfIdeal)) ; } } // imposto vettore dei punti iniziali e vettore degli indici dei chunks for ( int i = 0 ; i < ( int)vNewPtStart.size() ; ++ i){ vIndChunk.emplace_back( vNewPtStart[i].nInd) ; vPtCheck.emplace_back( vNewPtStart[i].ptC) ; } // reimposto tutte le temp prop alle curve delle nuove superifici for ( int i = 0 ; i < ( int)vSrfIdeal.size() ; ++ i) { PtrOwner pSrfIdeal_TmpProp( CreateSurfFlatRegion()) ; if ( IsNull( pSrfIdeal_TmpProp)) return false ; for ( int c = 0 ; c < vSrfIdeal[i]->GetChunkCount() ; ++ c) { for ( int l = 0 ; l < vSrfIdeal[i]->GetLoopCount( c) ; ++ l) { PtrOwner pCrvCurr( vSrfIdeal[i]->GetLoop( c, l)) ; if ( IsNull( pCrvCurr) || ! pCrvCurr->IsValid()) return false ; pCrvCurr->SetTempProp( nProp0, 0) ; pCrvCurr->SetTempProp( nProp1, 1) ; if ( l == 0) pSrfIdeal_TmpProp->AddExtLoop( Release( pCrvCurr)) ; else pSrfIdeal_TmpProp->AddIntLoop( Release( pCrvCurr)) ; } } vSrfIdeal[i].Set( Release( pSrfIdeal_TmpProp)) ; } return ( vSrfIdeal.size() != 0) ; } //---------------------------------------------------------------------------- bool Pocketing::AssignContourToPath( const ICRVCOMPOPOVECTOR& vpCrvs, const Frame3d frPocket, const ISurfFlatRegion* pSrfOffs, ICRVCOMPOPOVECTOR& vAllCrv) { // controllo dei parametri if (( int) vpCrvs.size() == 0 || pSrfOffs == nullptr || pSrfOffs->GetChunkCount() == 0) return false ; vAllCrv.clear() ; // estraggo i bordi esterni dei chunk della superificie for ( int c = 0 ; c < ( int)pSrfOffs->GetChunkCount() ; ++ c) { PtrOwner pCrvExtChunkC( CloneCurveComposite( pSrfOffs->GetLoop( c, 0))) ; IntersCurveCurve intCC( *vpCrvs[0], *pCrvExtChunkC) ; CRVCVECTOR ccClass ; intCC.GetCurveClassification( 0, EPS_SMALL, ccClass) ; if ( ccClass.size() == 1 && ccClass[0].nClass == CRVC_IN) { for( int l = 0 ; l < pSrfOffs->GetLoopCount( c) ; ++ l) { PtrOwner pCrv( CloneCurveComposite( pSrfOffs->GetLoop( c, l))) ; pCrv->ToGlob( frPocket) ; vAllCrv.emplace_back( Release( pCrv)) ; } return true ; } } return false ; } //---------------------------------------------------------------------------- bool Pocketing::OrderCurvesByLastPntOfPath( ICRVCOMPOPOVECTOR& vCrv, Point3d ptEnd, PNTVECTOR& vPtStart, VCT3DVECTOR& vVtOut, BOOLVECTOR& vbMidOut, BOOLVECTOR& vbForcedOutStart) { if (( int)vCrv.size() == 0) return false ; Point3d ptRef = ptEnd ; double dMinDist = INFINITO ; int nIndexSwitch = -1 ; for ( int i = -1 ; i < int( vCrv.size()) - 1 ; ++ i) { for ( int j = i + 1 ; j < int( vCrv.size()) ; ++ j) { Point3d ptS ; vCrv[j]->GetStartPoint( ptS) ; if ( Dist( ptS, ptRef) < dMinDist) { dMinDist = Dist( ptS, ptRef) ; nIndexSwitch = j ; } } if ( nIndexSwitch != i + 1) { // scambio le curve PtrOwner pCrvClosest( vCrv[nIndexSwitch]->Clone()) ; vCrv[nIndexSwitch].Set( vCrv[i+1]) ; vCrv[i+1].Set( pCrvClosest) ; // scambio i punti Point3d ptStart = vPtStart[nIndexSwitch] ; vPtStart[nIndexSwitch] = vPtStart[i+1] ; vPtStart[i+1] = ptStart ; // scambio i vettori Vector3d vtOut = vVtOut[nIndexSwitch] ; vVtOut[nIndexSwitch] = vVtOut[i+1] ; vVtOut[i+1] = vtOut ; // scambio i booleani bool bOut = vbMidOut[nIndexSwitch] ; vbMidOut[nIndexSwitch] = vbMidOut[i+1] ; vbMidOut[i+1] = bOut ; // scambio uscite forzate bool bForcedOut = vbForcedOutStart[nIndexSwitch] ; vbForcedOutStart[nIndexSwitch] = vbForcedOutStart[i+1] ; vbForcedOutStart[i+1] = bForcedOut ; } vCrv[i+1]->GetEndPoint( ptRef) ; dMinDist = INFINITO ; } return true ; } //---------------------------------------------------------------------------- bool Pocketing::ProjectEdgesOnSelFace( const ISurfFlatRegion* pSfrFacet, const ISurfTriMesh* pStmOrig, INTVECTOR& vId , int nFacet, ISurfFlatRegion* pSfrProj) { // controllo parametri if ( pSfrFacet == nullptr || pSfrFacet->GetChunkCount() == 0 || nFacet < 0) return false ; pSfrProj->Clear() ; // creo il piano contenente la superifice FlatRegion Point3d ptC ; pSfrFacet->GetCentroid( ptC) ; Vector3d vtN = pSfrFacet->GetNormVersor() ; Plane3d plPock ; plPock.Set( ptC, vtN) ; // scorro tutti gli indici bannati for ( int id = 0 ; id < ( int)vId.size() ; ++ id) { if ( vId[id] != -1 && vId[id] != nFacet && find( vId.begin(), vId.end(), nFacet) != vId.end()) { // se ho un id presente nel vettore degli id ... estraggo il bordo della faccia con questo id POLYLINEVECTOR vPL ; pStmOrig->GetFacetLoops( vId[id], vPL) ; PtrOwner pCrvBorder( CreateCurveComposite()) ; if ( IsNull( pCrvBorder)) return false ; pCrvBorder->FromPolyLine( vPL[0]) ; // non considero le isole nelle facce laterali pCrvBorder->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL) ; // proietto questa curva nel piano della faccia selezionata PtrOwner pCrvProj( ProjectCurveOnPlane( *pCrvBorder, plPock)) ; if ( IsNull( pCrvProj) || ! pCrvProj->IsValid()) return false ; PtrOwner pSfrTemp( CreateSurfFlatRegion()) ; if ( IsNull( pSfrTemp)) return false ; pSfrTemp->AddExtLoop( Release( pCrvProj)) ; if ( pSfrTemp->IsValid()) { if ( AreOppositeVectorApprox( pSfrTemp->GetNormVersor(), vtN)) pSfrTemp->Invert() ; if ( pSfrProj->GetChunkCount() == 0) pSfrProj->CopyFrom( pSfrTemp) ; else pSfrProj->Add( *pSfrTemp) ; } } } return pSfrProj->IsValid() && pSfrProj->GetChunkCount() > 0 ; } //---------------------------------------------------------------------------- bool Pocketing::GetNewBorderByProjectionOfFaces( ISurfFlatRegion* pSrfpCompo, ICurveComposite* pCrvProj, const Point3d ptStart) { // controllo dei parametri if ( pSrfpCompo == nullptr || pSrfpCompo->GetChunkCount() == 0 || pCrvProj == nullptr || pCrvProj->GetCurveCount() == 0) return false ; // creo una superificie definita dalla curva di proiezione PtrOwner pSrfProj( CreateSurfFlatRegion()) ; pSrfProj->AddExtLoop( pCrvProj->Clone()) ; if ( IsNull( pSrfProj)) return false ; if ( AreOppositeVectorApprox( pSrfpCompo->GetNormVersor(), pSrfProj->GetNormVersor())) pSrfProj->Invert() ; PtrOwner pSrfpCompoClone( CloneSurfFlatRegion( pSrfpCompo)) ; if ( IsNull( pSrfpCompoClone) || pSrfpCompoClone->GetChunkCount() == 0) return false ; // sottraggo le due superifici if ( ! pSrfpCompoClone->Subtract( *pSrfProj)) return false ; pSrfpCompo->Clear() ; pSrfpCompo->CopyFrom( pSrfpCompoClone) ; return true ; } //---------------------------------------------------------------------------- bool Pocketing::GetSurfByAdj( const ISurfTriMesh* pSrfOri, INTVECTOR& vBannedId, int idCurrFace) { vBannedId.push_back( idCurrFace) ; INTMATRIX M ; if ( ! pSrfOri->GetFacetAdjacencies( idCurrFace, M)) return false ; for ( int i = 0 ; i < ( int)M[0].size() ; ++ i) { if ( find( vBannedId.begin(), vBannedId.end(), M[0][i]) == vBannedId.end()) { GetSurfByAdj( pSrfOri, vBannedId, M[0][i]) ; } } return true ; } //---------------------------------------------------------------------------- bool Pocketing::GetProjStmOnSfr( const ISurfFlatRegion* pSfr, const ISurfTriMesh* pStmRaw, const ISurfFlatRegion* pSrfOrig, ISurfFlatRegion* pSfrRawBoxProj) { // controllo dei parametri if ( pSfr == nullptr || ! pSfr->IsValid() || pSfr->GetChunkCount() == 0 || pStmRaw == nullptr || ! pStmRaw->IsValid() || pStmRaw->GetTriangleCount() == 0) return false ; // ---------- CREAZIONE DI UN VETTORE CONTENENTI TUTTI I TRATTI APERTI APERTE -------------------- ICRVCOMPOPOVECTOR vCrvOpen ; ICRVCOMPOPOVECTOR vCrvNULL ; PtrOwner pCrvCompo( GetCurveComposite( pSfr->GetLoop( 0, 0))) ; // controllo se la curva ha tutti i lati aperti bool bIsAllOpen = true ; int nCurrTempProp_ ; for ( int u = 0 ; u < pCrvCompo->GetCurveCount() && bIsAllOpen ; ++ u) { pCrvCompo->GetCurveTempProp( u, nCurrTempProp_, 0) ; bIsAllOpen = nCurrTempProp_ == 1 ; } if ( bIsAllOpen) // se tutti lati aperti... vCrvOpen.emplace_back( pCrvCompo->Clone()) ; else { // ... altrimenti sposto l'inizio a metà del tratto più lungo AdjustContourStart( pCrvCompo, vCrvNULL) ; // estraggo parti con proprietà uniforme in un vettore int nCurrTempProp ; int nParStart = 0 ; for ( int i = 0 ; i < pCrvCompo->GetCurveCount() ; ++ i) { int nTempProp ; pCrvCompo->GetCurveTempProp( i, nTempProp) ; if ( i == 0) { nCurrTempProp = nTempProp ; nParStart = i ; } else if ( nCurrTempProp != nTempProp) { PtrOwner pCrv( pCrvCompo->CopyParamRange( nParStart, i)) ; if ( IsNull( pCrv)) return false ; pCrv->SetTempProp( nCurrTempProp) ; PtrOwner pCrvSameTmpProp( CreateCurveComposite()) ; pCrvSameTmpProp->AddCurve( Release( pCrv)) ; if ( nCurrTempProp == 1) { pCrvSameTmpProp->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL) ; vCrvOpen.emplace_back( Release( pCrvSameTmpProp)) ; // se aperta } nCurrTempProp = nTempProp ; nParStart = i ; } } } // copio la superficie in globale PtrOwner pSfrPock( CloneSurfFlatRegion( pSfr)) ; if( IsNull( pSfrPock)) return false ; // ------------------------- CREAZIONE DEL PIANO DI TAGLIO -------------------------------------- // recupero il piano di proiezione ( piano che contiene la flatRegion) PtrOwner pCrv( GetCurveComposite( pSfrPock->GetLoop( 0, 0))) ; if ( IsNull( pCrv)) return false ; Plane3d plProj ; Point3d ptCen ; if ( ! pCrv->GetCentroid( ptCen)) // punto if ( ! pCrv->GetStartPoint( ptCen)) return false ; Vector3d vtNorm = pSfrPock->GetNormVersor() ; // normale if ( vtNorm.IsSmall()) return false ; plProj.Set( ptCen, -vtNorm) ; // così taglio tutto cià che sta nel semipiano negativo if ( ! plProj.IsValid()) return false ; // ---------------------- RICERCA DELLA REGIONE DI INCIDENZA DI PROIEZIONE -------------------------- // offsetto la regione della quantità richiesta PtrOwner pSrf_Pock_Clone(CloneSurfFlatRegion( pSfrPock)) ; if ( ! pSrf_Pock_Clone->Offset( m_dMaxLenRawProj, ICurve::OFF_CHAMFER)) return false ; CICURVEPVECTOR vCrv ; for ( int c = 0 ; c < pSrf_Pock_Clone->GetChunkCount() ; ++ c) for ( int l = 0 ; l < pSrf_Pock_Clone->GetLoopCount( c) ; ++ l) vCrv.emplace_back( pSrf_Pock_Clone->GetLoop( c, l)) ; PtrOwner pSrf_ForCuttingRaw( GetSurfTriMeshByRegionExtrusion( vCrv, vtNorm * 1000)) ; // --------------------- CREAZIONE PARTE DI GREZZO AL DI SOPRA DELLA REGIONE SI SVUOTATURA // -----------------------------------NELLA REGIONE DI INCIDENZA ----------------------------- // creo la Trimesh del grezzo e la taglio con il piano PtrOwner pSrfRaw_clone( CloneSurfTriMesh( pStmRaw)) ; if ( IsNull( pSrfRaw_clone)) return false ; if ( ! pSrfRaw_clone->CutWithOtherSurf( *pSrf_ForCuttingRaw, true, true)) return false ; if ( ! pSrfRaw_clone->IsValid() || pSrfRaw_clone->GetTriangleCount() == 0) { pSfrRawBoxProj->Clear() ; return true ; } // --------------------- RIMOZIONE DELLE PARTI NON ESSENZIALI --------------------------------- // ( Serve ancora questo controllo ? ) // Recupero solo la parte di TriMesh contente la superificie da svuotare // Tagliando il grezzo posso ottenere diverse Parts, tengo solo quelle che influenzano la mia regione di svuotatura PtrOwner pStr_real( CreateSurfTriMesh()) ; for ( int p = 0 ; p < pSrfRaw_clone->GetPartCount() ; ++ p) { // per ogni part della TriMesh PtrOwner pStm_raw_part( pSrfRaw_clone->ClonePart( p)) ; POLYLINEVECTOR vPl ; pStm_raw_part->GetLoops( vPl) ; // ricavo i Loops for ( int l = 0 ; l < ( int)vPl.size() ; ++ l) { PtrOwner pCompo( CreateCurveComposite()) ; pCompo->FromPolyLine( vPl[l]) ; // converto in curva composita PtrOwner pSfr_H( CreateSurfFlatRegion()) ; pSfr_H->AddExtLoop( Release( pCompo)) ; // creo una regione per ogni Loop if ( ! AreSameVectorApprox( pSfr_H->GetNormVersor(), pSfrPock->GetNormVersor())) pSfr_H->Invert() ; // se necessario inverto for ( int c = 0 ; c < pSfrPock->GetChunkCount() ; ++ c) { // per ogni chunk della regione di svuotatura if ( pSfr_H->GetChunkSimpleClassification( 0, *pSfrPock, c) != CCREGC_OUT) { if ( pStr_real->GetTriangleCount() != 0) pStr_real->Add( *Release( pStm_raw_part)) ; else pStr_real.Set( Release( pStm_raw_part)) ; l = ( int)vPl.size() ; break ; } } } } // ------- PROIEZIONE DI OGNI FACCIA DEL GREZZO RICAVATO SUL PIANO DELLA SVUOTATURA -------------- // creo un vettore con le curve esterne // in posizione 0 metto la curva esterna della superificie da svuoatre originale // nelle posizioni successive inserisco le curve esterne dei chunk creati ( aperti per definizione) ICRVCOMPOPOVECTOR vCrvExtProj ; // <---- questo vettore contiene il bordo della superificie ricavata dall'interzione // quindi in posizione 0 ho una curva con i lati aperti/chiusi già settati vCrvExtProj.emplace_back( GetCurveComposite( pSfr->GetLoop( 0, 0))) ; // Proietto ora le curve, delle facce della superificie ottenuta, sul piano della svuotatura for ( int f = 0 ; f < pStr_real->GetFacetCount() ; ++ f) { // controllo se la faccia è quasi perpendicolare, nel caso la salto Vector3d vtN_check ; pStr_real->GetFacetNormal( f, vtN_check) ; if ( abs( vtN_check * vtNorm) < EPS_ZERO) continue ; POLYLINEVECTOR vPL ; pStr_real->GetFacetLoops( f, vPL) ; // per ogni Loop l della faccia f for ( int l = 0 ; l < ( int) vPL.size() ; ++ l) { PtrOwner pCrvBorder( CreateCurveComposite()) ; if ( IsNull( pCrvBorder) || ! pCrvBorder->FromPolyLine( vPL[l])) return false ; PtrOwner pCrvProjFacef( ProjectCurveOnPlane( *pCrvBorder, plProj)) ; if ( IsNull( pCrvProjFacef) || ! pCrvProjFacef->IsValid()) return false ; // controllo validità della curva ( che sia chiusa e non degenere) double dArea = EPS_SMALL ; Plane3d plCheck ; if ( ! pCrvProjFacef->IsClosed() || ! pCrvProjFacef->GetArea( plCheck, dArea) || dArea <= EPS_SMALL) continue ; // creo la curva composita associata PtrOwner pCrvBorderProj_f( CreateCurveComposite()) ; pCrvBorderProj_f->AddCurve( Release( pCrvProjFacef)) ; // 1) controllo se una sottocurva della curva composita del bordo è sufficientemente vicina ad una curva aperta // della curva originale di bordo della superificie esterna bool bNeedProj = false ; for ( int i = 0 ; i < pCrvBorderProj_f->GetCurveCount() && !bNeedProj; ++ i) { const ICurve* pCrv_i = pCrvBorderProj_f->GetCurve( i) ; if ( pCrv_i == nullptr) return false ; for ( int j = 0 ; j < ( int)vCrvOpen.size() && !bNeedProj ; ++ j) { int nStat = -1 ; const double nMAX = 10.0 ; for ( int i = 0 ; i <= nMAX && !bNeedProj ; ++i) { double dPar = i / nMAX ; Point3d ptC ; pCrv_i->GetPointD1D2( dPar, ICurve::FROM_PLUS, ptC) ; if ( vCrvOpen[j]->IsPointOn( ptC, 150 * EPS_SMALL)) bNeedProj = true ; } } } if ( ! bNeedProj) { // 2) controllo se un tratto aperto è sufficientemente vicino ad una sottocurva della curva composita del bordo // della proiezione for ( int j = 0 ; j < ( int)vCrvOpen.size() && !bNeedProj ; ++ j) { for ( int u = 0 ; u < ( int)vCrvOpen[j]->GetCurveCount() && !bNeedProj ; ++ u) { const ICurve* pCrv_j_u = vCrvOpen[j]->GetCurve( u) ; if ( pCrv_j_u == nullptr) return false ; int nStat = -1 ; if ( CheckSimpleOverlap( pCrv_j_u, pCrvBorderProj_f, nStat, 150 * EPS_SMALL) && nStat == 1) bNeedProj = true ; } } } if ( ! bNeedProj) // se non devo proiettare passo alla prossima continue ; // 3) Setto tutte le sottocurve aperte for ( int uu = 0 ; uu < pCrvBorderProj_f->GetCurveCount() ; ++ uu) pCrvBorderProj_f->SetCurveTempProp( uu, 1, 0) ; // inserisco nel vettore delle curve di bordo vCrvExtProj.emplace_back( Release( pCrvBorderProj_f)) ; // <---- dall'indice 1 in poi ho solo curve aperte e // sono le curve di bordo delle proeizioni } } // Clono la superificie di partenza ( per sicurezza lascio invariata quella passata alla funzione) PtrOwner pSrf_Clone( CloneSurfFlatRegion( pSfr)) ; if ( IsNull( pSrf_Clone) || ! pSrf_Clone->IsValid()) return false ; // Creo la superficie che dovrò restiturire alla fine della proiezione PtrOwner pSrf_Proj_Ext( CreateSurfFlatRegion()) ; if ( IsNull( pSrf_Proj_Ext)) return false ; //for ( int p = 1 ; p < ( int)vCrvExtProj.size() ; ++ p) { //int g = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, vCrvExtProj[p]->Clone()) ; //m_pGeomDB->SetMaterial( g, BLACK) ; //} // ---------------- CREAZIONE DELLA VERA A PROPRIA REGIONE DI INCIDENZA, COME SOMMA DELLE // ----------------------------- SINGOLE FLATREGIONS DI PROIEZIONE ----------------------------- for ( int i = 1 ; i < ( int)vCrvExtProj.size() ; ++ i) { CRVCVECTOR ccClass ; if ( pSrf_Clone->GetCurveClassification( *vCrvExtProj[i], 150 * EPS_SMALL, ccClass)) { bool bAdd = false ; for ( int j = 0 ; j < ( int)ccClass.size() && !bAdd ; ++ j) bAdd = ccClass[j].nClass == CRVC_OUT || ccClass[j].nClass == CRVC_ON_M || ccClass[j].nClass == CRVC_ON_P ; if ( bAdd) { PtrOwner pSrf_H( CreateSurfFlatRegion()) ; if ( IsNull( pSrf_H)) return false ; pSrf_H->AddExtLoop( vCrvExtProj[i]->Clone()) ; // inverto se le normali risultano opposte if ( pSrf_H->IsValid()) { if ( AreOppositeVectorApprox( pSrf_H->GetNormVersor() , pSrf_Clone->GetNormVersor())) pSrf_H->Invert() ; } if ( pSrf_Proj_Ext->GetChunkCount() == 0) pSrf_Proj_Ext.Set( Release( pSrf_H)) ; else pSrf_Proj_Ext->Add( *Release( pSrf_H)) ; } } } // creo la vera e propria regione di proiezione, sommando la proiezione esterna con la superifcie originale da svuotare PtrOwner pSrf_Proj( CloneSurfFlatRegion( pSrf_Proj_Ext)) ; if ( IsNull( pSrf_Proj) || ! pSrf_Proj->IsValid()) return false ; pSrf_Proj->Add( *pSfr) ; // --------- LA PROIEZIONE DEL GREZZO DEVE ESTENDERE LA MIA SUPERIFCIE ORIGINARIA ( DERIVANTE DALL'INTERSEZIONE) PRESSO // I LATI APERTI DI ESSA. USO LA FUNZIONE AdjustContourWithOpenEdges FORZADO COME COLLEGAMENTI DELLE RETTE CHIUSE ------ PtrOwner pCrvExt( CloneCurveComposite( vCrvExtProj[0])) ; if ( IsNull( pCrvExt) || ! pCrvExt->IsValid()) return false ; ICRVCOMPOPOVECTOR vCrvNull ; // allargo la copia della superificie iniziale estendendola presso i lati aperti // ( semplice AdjustContourWithOpenEdges, senza grezzo e senza isole, verrà tutto fatto in seguito) if ( AdjustContourWithOpenEdges( pCrvExt, vCrvNull, m_dMaxLenRawProj, 0.0, 0.0, V_NULL, nullptr, true)) { // la curva restitutita presenta i lati aperti/chiusi impostati ( all'originale si lasciano invariati i chiusi, // gli aperrti vengono Offsettati e i raccordi sono lineari mediante rette chiuse // ( NB. Se le rette di raccordo fossero settate aperte, rischierei di rovinare parti di grezzo al // di fuori di lati chiusi ( tutto dipende dell'angolo di inclinazione della superificie originale rispetto // ad ogni singola faccia del grezzo ). PtrOwner pSrfWithOEModified( CreateSurfFlatRegion()) ; if ( IsNull( pSrfWithOEModified)) return false ; pSrfWithOEModified->AddExtLoop( Release( pCrvExt)) ; // la modifico con la curva appena restituita // ( allargata dai lati aperti) if ( pSrfWithOEModified->IsValid()) { // se la superificie ottenuta è valida... // ... la clono... PtrOwner pSfrProj_Clone( CloneSurfFlatRegion( pSrf_Proj)) ; if ( IsNull( pSfrProj_Clone) || ! pSfrProj_Clone->IsValid()) return false ; // controllo che le normali siano compatibili if ( AreOppositeVectorApprox( pSfrProj_Clone->GetNormVersor(), pSrfWithOEModified->GetNormVersor())) pSfrProj_Clone->Invert() ; //int ga = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSfrProj_Clone->Clone()) ; //m_pGeomDB->SetMaterial( ga, RED) ; //int gaa = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSrfWithOEModified->Clone()) ; //m_pGeomDB->SetMaterial( gaa, PURPLE) ; // ... e Interseco la superificie di proiezione con questa nuova superificie // NB. L'intersezione mi permette di tenere solo le parti che sono sia nella regione di incidenza che nella // estensione della superificie originali presso i lati aperti if ( pSfrProj_Clone->Intersect( *pSrfWithOEModified) && ! IsNull( pSfrProj_Clone) && pSfrProj_Clone->IsValid()) { //int g = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSfrProj_Clone->Clone()) ; //m_pGeomDB->SetMaterial( g, GREEN) ; // adatto la FlatRegion con la superificie iniziale per non sbordare dai chiusi // La superficie che ottengo rischia comunque di essere esterna a dei lati chiusi originali ( questo // accade quando si generano dei lati aperti mediante l'intersezione con il grezzo e la regione di incidenza // ha un raggio di ricerca molto grande... oppure quando semplicemente il grezzo contiene un'isola in cui // una faccia è diretta verso un pezzo di chiuso della curva esterna ( infatti le rette di raccordo chiuse // seguono la tangenza dei lati chiusi adiancenti ai tratti aperti PtrOwner pSrfProj_Clone_Clone( CloneSurfFlatRegion( pSfrProj_Clone)) ; if ( ! CutProjectionToFitShape( pSfrProj_Clone, pSrfOrig)) return false ; // Recupero le TmpProp e creo la nuova superificie mediante questo loop esterno PtrOwner pCrv_NewExt( pSfrProj_Clone->GetLoop( 0, 0)) ; if ( IsNull( pCrv_NewExt) || ! pCrv_NewExt->IsValid()) return false ; PtrOwner pCrvCompo_NewExt( CreateCurveComposite()) ; // trasformo in composita if ( IsNull( pCrvCompo_NewExt)) return false ; pCrvCompo_NewExt->AddCurve( Release( pCrv_NewExt)) ; // Imposto le temp prop if ( pCrvCompo_NewExt->IsValid()) { if ( ! SetTmpPropWithRawProjectedFaces( pCrvCompo_NewExt, vCrvExtProj, pSfr->GetNormVersor()) || ! CheckSmallPartsForOpenEdge( pCrvCompo)) return false ; // creo la superificie finale PtrOwner pSrfProj_Final( CreateSurfFlatRegion()) ; if ( IsNull( pSrfProj_Final)) return false ; pSrfProj_Final->AddExtLoop( Release( pCrvCompo_NewExt)) ; // aggiusto la normale se necessario if ( pSrfProj_Final->IsValid()) { if ( AreOppositeVectorApprox( pSrfProj_Final->GetNormVersor(), pSfr->GetNormVersor())) pSrfProj_Final->Invert() ; } // sostituisco questa superficie a quella passata dalla funzione ed esco pSfrRawBoxProj->Clear() ; pSfrRawBoxProj->CopyFrom( pSrfProj_Final) ; return pSfrRawBoxProj->IsValid() ; } } } } return true ; } //---------------------------------------------------------------------------- bool Pocketing::CutProjectionToFitShape( ISurfFlatRegion* pSrfProjected, const ISurfFlatRegion* pSrfOrig) { // controllo validità dei parametri if ( pSrfProjected == nullptr || ! pSrfProjected->IsValid() || pSrfProjected->GetChunkCount() == 0 || pSrfOrig == nullptr || ! pSrfOrig->IsValid() || pSrfOrig->GetChunkCount() == 0) return false ; ICRVCOMPOPOVECTOR vCrvNULL ; ICRVCOMPOPOVECTOR vCrvClose ; for ( int c = 0 ; c < pSrfOrig->GetChunkCount() ; ++ c) { // per ogni Chunk c for ( int l = 0 ; l < pSrfOrig->GetLoopCount( c) ; ++ l) { // per ogni Loop l // estraggo la curva di bordo PtrOwner pCrvCompo( GetCurveComposite( pSrfOrig->GetLoop( c, l ))) ; if ( IsNull( pCrvCompo) || ! pCrvCompo->IsValid() || pCrvCompo->GetCurveCount() == 0) return false ; // controllo se la curva ha tutti i lati aperti bool bIsAllOpen = true ; int nCurrTempProp_ ; for ( int u = 0 ; u < pCrvCompo->GetCurveCount() && bIsAllOpen ; ++ u) { pCrvCompo->GetCurveTempProp( u, nCurrTempProp_, 0) ; bIsAllOpen = nCurrTempProp_ == 1 ; } if ( bIsAllOpen) // se tutti lati aperti... continue ; else { AdjustContourStart( pCrvCompo, vCrvNULL) ; for ( int u = 1 ; u < pCrvCompo->GetCurveCount() ; ++ u) { int nTmpProp0 ; pCrvCompo->GetCurveTempProp( u, nTmpProp0, 0) ; if ( nTmpProp0 == 1) { pCrvCompo->ChangeStartPoint( u + 1) ; break ; } } PtrOwner pCrvClosed( CreateCurveComposite()) ; if ( IsNull( pCrvClosed)) return false ; int nCrv = 0 ; for ( int u = 0 ; u < pCrvCompo->GetCurveCount() ; ++ u) { int nCurrTmpProp ; pCrvCompo->GetCurveTempProp( u, nCurrTmpProp, 0) ; if ( nCurrTmpProp == 0) { // se chiusa if ( nCrv == 0) pCrvClosed->Clear() ; pCrvClosed->AddCurve( pCrvCompo->GetCurve( u)->Clone()) ; ++ nCrv ; } else { // se aperta if ( nCrv != 0) vCrvClose.emplace_back( pCrvClosed->Clone()) ; nCrv = 0 ; } } // l'ultima curva è sempre chiusa... vCrvClose.emplace_back( Release( pCrvClosed)) ; } } } // se nessun lato aperto, esco if (( int)vCrvClose.size() == 0) return true ; // trasformo la superificie di proiezione in Trimesh PtrOwner pStmProj( CloneSurfTriMesh( pSrfProjected->GetAuxSurf())) ; if ( IsNull( pStmProj) || ! pStmProj->IsValid() || pStmProj->GetTriangleCount() == 0) return false ; // recupero il centroide della superificie ( o un punto generico sulla superificie) Point3d ptC ; pSrfProjected->GetCentroid( ptC) ; // creo una Frame con questo vettore Frame3d frPock ; frPock.Set( ptC, pSrfOrig->GetNormVersor()) ; if ( ! frPock.IsValid()) return true ; // porto tutto in questo frame ICRVCOMPOPOVECTOR vCrvClose_c ; for ( int i = 0 ; i < ( int)vCrvClose.size() ; ++ i) { PtrOwner pCrvClose_i( CloneCurveComposite( vCrvClose[i])) ; if ( IsNull( pCrvClose_i) || ! pCrvClose_i->IsValid() || pCrvClose_i->GetCurveCount() == 0) return false ; pCrvClose_i->ToLoc( frPock) ; vCrvClose_c.emplace_back( Release( pCrvClose_i)) ; } pStmProj->ToLoc( frPock) ; // abbasso leggermente ls superificie di proiezione per evitatare triangoli sovrapposti pStmProj->Translate( Z_AX * 10 * EPS_SMALL) ; // per ogni curva chiusa di bordo for ( int i = 0 ; i < ( int)vCrvClose_c.size() ; ++ i) { // creo la sua estrusione PtrOwner pStmClosedEdge( GetSurfTriMeshByExtrusion( vCrvClose_c[i], Z_AX * 1000, false)) ; // controllo la validità dell'estrusione if ( IsNull( pStmClosedEdge) || ! pStmClosedEdge->IsValid() || pStmClosedEdge->GetTriangleCount() == 0) continue ; //int OOOOOOOOOOO = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pStmClosedEdge->Clone()) ; // --- //m_pGeomDB->SetMaterial( OOOOOOOOOOO, RED) ; // --- // tengo una copia della trimesh della proiezione per sicurezza, nel caso il taglio non funzioni PtrOwner pStmProj_clone( CloneSurfTriMesh( pStmProj)) ; if ( IsNull( pStmProj_clone) || ! pStmProj_clone->IsValid() || pStmProj_clone->GetTriangleCount() == 0) return false ; // taglio la supericie con questo lato if ( pStmProj_clone->CutWithOtherSurf( *pStmClosedEdge, true, true) && ! IsNull( pStmProj_clone) && pStmProj_clone->IsValid() && pStmProj_clone->GetTriangleCount() != 0) // se il taglio funziona, sostituisco la superificie pStmProj.Set( Release( pStmProj_clone)) ; //int OOOOOOOOOOOt = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pStmProj->Clone()) ; // --- //m_pGeomDB->SetMaterial( OOOOOOOOOOOt, PURPLE) ; // --- } // se la superificie finale è valida... if ( IsNull( pStmProj) || ! pStmProj->IsValid()) return true ; // ... ricoverto La Trimesh in FlatRegione SurfFlatRegionByContours SrfProj_H ; POLYLINEVECTOR vPl ; pStmProj->GetLoops( vPl) ; Plane3d plPlane ; plPlane.Set( ORIG, Z_AX) ; for ( int i = 0 ; i < ( int)vPl.size() ; ++ i) { // recupero la curva composita PolyLine PL = vPl[i] ; PtrOwner pCrv( CreateCurveComposite()) ; pCrv->FromPolyLine( PL) ; PolyArc PA ; pCrv->ApproxWithArcsEx( 5 * EPS_SMALL, ANG_TOL_STD_DEG, LIN_FEA_STD, PA) ; pCrv->Clear() ; pCrv->FromPolyArc( PA) ; // la converto in una semplice cruva per proiettarla su piano XY // dato che le curve sono prese da una trimesh, le riproietto per sicurezza e per evitare approssimazioni double dS, dE ; pCrv->GetDomain( dS, dE) ; PtrOwner pCrv_c( pCrv->CopyParamRange( dS, dE)) ; if ( IsNull( pCrv_c) || ! pCrv_c->IsValid()) return false ; PtrOwner pCrv_proj( ProjectCurveOnPlane( *pCrv_c, plPlane)) ; if ( IsNull( pCrv_proj) || ! pCrv_proj->IsValid()) return false ; SrfProj_H.AddCurve( Release( pCrv_proj)) ; // aggiungo le curve proiettate } // recupero la Flat region di prozione e controllo la validità PtrOwner pStmProj_HH( SrfProj_H.GetSurf()) ; if ( IsNull( pStmProj_HH) || ! pStmProj_HH->IsValid() || pStmProj_HH->GetChunkCount() == 0) return true ; // la risporto in globale e sostituisco pStmProj_HH->ToGlob( frPock) ; pSrfProjected->Clear() ; pSrfProjected->CopyFrom( pStmProj_HH) ; return pSrfProjected != nullptr && pSrfProjected->IsValid() && pSrfProjected->GetChunkCount() > 0 ; } //---------------------------------------------------------------------------- bool Pocketing::ProjectRaw( ISurfFlatRegion* pSrf, const Vector3d& vtTrasl, const ISurfTriMesh* pStmRaw, int nId, const double& dRawSecLen, const ISurfFlatRegion* pSrfOrig, double dAreaToll) { // controllo se funzione necessaria if ( ! m_bProjectRaw) return true ; // controllo dei parametri if ( pSrf == nullptr || ! pSrf->IsValid() || pSrf->GetChunkCount() == 0 || pStmRaw == nullptr || ! pStmRaw->IsValid() || pStmRaw->GetTriangleCount() == 0) return false ; // NB. La proiezione è fatta allargando la superificie attuale di svuotatura. // Come bordo esterno limite si utlizza la curva della FlatRegion della proiezione della parte di grezzo nel // semipiano positivo sopra allo step attuale della svuotatura. // 1) se un chunk non ha lati aperti, allora non serve proiettare nulla per tale chunk BOOLVECTOR vbSkip ; // vettore di Flag per capire se un chunk va modificato o meno bool bAllChunk_Closed = true ; int nProp = -1 ; for ( int c = 0 ; c < pSrf->GetChunkCount() ; ++ c) { bool bAllClosed = true ; PtrOwner pCrvFC( GetCurveComposite( pSrf->GetLoop( c, 0))) ; if ( IsNull( pCrvFC) || ! pCrvFC->IsValid()) return false ; pCrvFC->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL, true, true) ; for ( int u = 0 ; u < pCrvFC->GetCurveCount() && bAllClosed ; ++ u) { if ( pCrvFC->GetCurveTempProp( u, nProp, 0) && nProp == 1) { bAllClosed = false ; bAllChunk_Closed = false ; } } vbSkip.push_back( bAllClosed) ; } // se tutti i chunk sono chiusi, esco if ( bAllChunk_Closed) return true ; // copio la superficie da modificare PtrOwner pSrf_clone( CloneSurfFlatRegion( pSrf)) ; if ( IsNull( pSrf_clone)) return false ; // traslo la superificie allo step corrente pSrf_clone->Translate( vtTrasl) ; // superificie finale della proizione ( per tutti i chunk) PtrOwner pSrf_Final( CreateSurfFlatRegion()) ; if ( IsNull( pSrf_Final)) return false ; // vettore delle superificie ricavate da ogni chunk ISURFFRPOVECTOR vSfr_gained ; // vettore delle isole in ogni Chunk per lo step corrente ICRVCOMPOPOVECTOR vCrvIsl ; // per ogni chunk della superificie originaria da svuotare for ( int c = 0 ; c < pSrf_clone->GetChunkCount() ; ++ c) { // inserisco l'isola nel vettore for ( int l = 1 ; l < pSrf_clone->GetLoopCount( c) ; ++ l) vCrvIsl.emplace_back( GetCurveComposite( pSrf_clone->GetLoop( c, l))) ; // prendo il Loop esterno PtrOwner pCrvExt_Loop( GetCurveComposite( pSrf_clone->GetLoop( c, 0))) ; // clono il chunk c-esimo e aggiungo le regioni proiettate PtrOwner pSrf_clone_ChunkC( pSrf_clone->CloneChunk( c)) ; // ricavo la FlatRegion della proiezione di ogni faccia del grezzo tagliato dal // semipiano positivo definito dal chunk c allo step attuale ( vtTrasl) PtrOwner pSrfOnPlPlus( CreateSurfFlatRegion()) ; if ( IsNull( pSrfOnPlPlus) || ! GetProjStmOnSfr( pSrf_clone_ChunkC, pStmRaw, pSrfOrig, pSrfOnPlPlus)) return false ; if ( IsNull( pSrfOnPlPlus) || ! pSrfOnPlPlus->IsValid() || pSrfOnPlPlus->GetChunkCount() == 0) pSrfOnPlPlus.Set( pSrf_clone_ChunkC) ; // inseirsco nel vettore vSfr_gained.emplace_back( pSrfOnPlPlus->Clone()) ; // sommo il nuovo chunk ottenuto alla regione finale di proiezione if ( pSrf_Final->GetChunkCount() == 0) pSrf_Final.Set( Release( pSrfOnPlPlus)) ; else { if ( ! pSrf_Final->Add( *pSrfOnPlPlus->Clone())) { // ricavo il piano di svuotatura, estrusione e spessore Plane3d plPock ; PtrOwner pCrvH( pSrf->GetLoop( 0, 0)) ; if ( IsNull( pCrvH) || ! pCrvH->IsValid()) return false ; Point3d ptC ; if ( ! pCrvH->GetCentroid( ptC)) if ( ! pCrvH->GetStartPoint( ptC)) return false ; Vector3d vtN = pSrf->GetNormVersor() ; plPock.Set( ptC, vtN) ; if ( ! plPock.IsValid()) return false ; plPock.Translate( vtTrasl) ; Vector3d vtExtr ; pCrvH->GetExtrusion( vtExtr) ; double dThick ; pCrvH->GetThickness( dThick) ; // converto le due regioni in Trimesh PtrOwner pStm1( CloneSurfTriMesh( pSrf_Final->GetAuxSurf())) ; PtrOwner pStm2( CloneSurfTriMesh( pSrfOnPlPlus->GetAuxSurf())) ; int rr = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pStm1->Clone()) ; int rrr = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pStm2->Clone()) ; m_pGeomDB->SetMaterial( rr, RED) ; m_pGeomDB->SetMaterial( rrr, ORANGE) ; if ( ! IsNull( pStm1) && ! IsNull( pStm2) && pStm1->IsValid() && pStm2->IsValid()) { // controllo validità delle normali Vector3d vtN1, vtN2 ; if ( pStm1->GetFacetNormal( 0, vtN1) && pStm2->GetFacetNormal( 0, vtN2) && AreOppositeVectorApprox( vtN1, vtN2)) pStm2->Invert() ; // creo la Zuppa di triangoli StmFromTriangleSoup sTM_TSoup ; sTM_TSoup.Start() ; sTM_TSoup.AddSurfTriMesh( *Release( pStm1)) ; sTM_TSoup.AddSurfTriMesh( *Release( pStm2)) ; sTM_TSoup.End() ; // ricavo la Trimesh della zuppa di triangoli PtrOwner pStmResult( sTM_TSoup.GetSurf()) ; //pStm1->Add( *Release( pStm2)) ; m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pStmResult->Clone()) ; if ( ! IsNull( pStmResult) && pStmResult->IsValid()) { // dalla TriMesh ricavata ne estraggo la FlatRegion PtrOwner pSfrResult( CreateSurfFlatRegion()) ; if ( IsNull( pSfrResult)) return false ; if ( GetSfrByStm( pStmResult, pSfrResult, plPock, vtExtr, dThick)) pSrf_Final.Set( Release( pSfrResult)) ; } return false ; } } } } // può capitare che da due Chunk distinti, mediante la proeizione questi si uniscano formandone uno solo... // Imposto nuovamente le Temp Prop PtrOwner pSrf_Final_WithOCEdge( CreateSurfFlatRegion()) ; if ( IsNull( pSrf_Final_WithOCEdge)) return false ; if ( ( int)vSfr_gained.size() != pSrf_Final->GetChunkCount()) { for ( int c = 0 ; c < pSrf_Final->GetChunkCount() ; ++ c) { PtrOwner pSrfChunk_c( pSrf_Final->CloneChunk( c)) ; if ( IsNull( pSrfChunk_c) || ! pSrfChunk_c->IsValid()) return false ; for ( int i = 0 ; i < ( int)vSfr_gained.size() ; ++ i) SetOpenOrCloseEdge( pSrfChunk_c, vSfr_gained[i], true) ; if ( pSrf_Final_WithOCEdge->GetChunkCount() == 0) pSrf_Final.Set( Release( pSrfChunk_c)) ; else pSrf_Final->Add( *Release( pSrfChunk_c)) ; } } // aggiungo tutte le isole... for ( int is = 0 ; is < ( int)vCrvIsl.size() ; ++ is) pSrf_Final->AddIntLoop( Release( vCrvIsl[is])) ; if ( ! IsNull( pSrf_Final) && pSrf_Final->IsValid()) { // Controllo delle aree, se alla fine di tutto sono ancora uguali, allora esco double dArea_orig = 0 ; double dArea_finale = 0 ; if ( pSrf_Final->GetArea( dArea_finale) && pSrf->GetArea( dArea_orig) && abs( dArea_orig - dArea_finale) < dAreaToll) return true ; // esco, alla fine non ho modificato la superificie originale mediante la proiezione con il grezzo pSrf->Clear() ; pSrf->CopyFrom( Release( pSrf_Final)) ; pSrf->Translate( - vtTrasl) ; // ritraslo la superificie come in origine } return true ; } //---------------------------------------------------------------------------- bool Pocketing::AjustCurveForProjRawOnFace( const ICurveLine* pL1, ICurveLine* pL2, const ICurveComposite* pCrvBorder, ICurveComposite* pCompo, int nStat, PNTVECTOR vPtTan, ISurfFlatRegion* pSrfProjRaw) { Point3d ptS, ptJ1A, ptJ1B, ptJ2A, ptJ2B ; // controllo parametri if ( pCrvBorder == nullptr || pCrvBorder->GetCurveCount() == 0 || ! pCrvBorder->IsValid() || pCompo == nullptr || pCompo->GetCurveCount() == 0 || ! pCompo->IsValid() || pSrfProjRaw == nullptr || ! pSrfProjRaw->IsValid() || pSrfProjRaw->GetChunkCount() == 0 || ! pCompo->GetStartPoint( ptS)) return false ; // controllo nel caso di rette valide che la loro intersezione non sia dentro alla proiezione del grezzo bool bIntersInside = false ; Point3d ptInt ; if ( nStat == 0) { IntersCurveCurve intCC( *pL1, *pL2) ; if ( intCC.GetIntersCount() > 0) { IntCrvCrvInfo aInfo ; if ( intCC.GetIntCrvCrvInfo( 0, aInfo)) { DistPointSurfTm dPStm( aInfo.IciA[0].ptI, *pSrfProjRaw->GetAuxSurf()) ; double dDist ; if ( dPStm.GetDist( dDist) && dDist < 50 * EPS_SMALL) { bIntersInside = true ; ptInt = aInfo.IciA[0].ptI ; } } } } // paramentro per gestione casi degeneri switch ( nStat) { case 0 : // le rette sono entrambe valide if ( ! pL1->GetStartPoint( ptJ1A) || ! pL1->GetEndPoint( ptJ1B) || ! pL2->GetStartPoint( ptJ2A) || ! pL2->GetEndPoint( ptJ2B)) return false ; break ; case 1 : // solo la prima retta è degenere ad un punto ptJ1A = vPtTan[0] ; ptJ1B = vPtTan[0] ; if( ! pL2->GetStartPoint( ptJ2A) || ! pL2->GetEndPoint( ptJ2B)) return false ; break ; case 2 : // solo la seconda retta è degenere ad un punto ptJ2A = vPtTan[1] ; ptJ2B = vPtTan[1] ; if( ! pL1->GetStartPoint( ptJ1A) || ! pL1->GetEndPoint( ptJ1B)) return false ; break ; case 3 : // entrambe le rette sone degeneri ad un punto if( AreSamePointApprox( vPtTan[0], vPtTan[1])) // tutti punti coicidenti, non cambio nulla della pCompo return true ; ptJ1A = vPtTan[0] ; ptJ1B = vPtTan[0] ; ptJ2A = vPtTan[1] ; ptJ2B = vPtTan[1] ; break ; default: break ; } if ( bIntersInside ) { // caso C) double dU ; pL1->GetParamAtPoint( ptInt, dU, EPS_SMALL) ; PtrOwner pL1New( GetCurveLine( pL1->CopyParamRange( 0, dU))) ; // segmento retta 1 pL2->GetParamAtPoint( ptInt, dU, EPS_SMALL) ; PtrOwner pL2New( GetCurveLine( pL2->CopyParamRange( 0, dU))) ; // segmento retta 2 pCompo->GetParamAtPoint( ptJ1A, dU) ; PtrOwner pCrvA( GetCurveComposite( pCompo->CopyParamRange( 0, dU))) ; // tratto curva interna iniziale pCompo->GetParamAtPoint( ptJ2A, dU) ; // tratto curva interna finale PtrOwner pCrvB( GetCurveComposite( pCompo->CopyParamRange( dU, dU < EPS_SMALL ? .0 : pCompo->GetCurveCount()))) ; if( dU < EPS_SMALL) pCrvB.Set( CreateCurveComposite()) ; pCompo->Clear() ; pCompo->AddCurve( Release( pCrvA)) ; pCompo->AddCurve( Release( pL1New)) ; pL2New->Invert() ; pCompo->AddCurve( Release( pL2New)) ; pCompo->AddCurve( Release( pCrvB)) ; return pCompo->IsValid() && pCompo->IsClosed() ; } // controllo validità dei punti sul contorno esterno ( se le rette non toccano, allora non modifico nulla ed esco) if ( ! pCompo->IsPointOn( ptJ1A, EPS_SMALL) || ! pCompo->IsPointOn( ptJ2A, EPS_SMALL) || ! pCrvBorder->IsPointOn( ptJ1B, EPS_SMALL) || ! pCrvBorder->IsPointOn( ptJ2B, EPS_SMALL)) return true ; // copio il bordo esterno PtrOwner pCrvExt( CloneCurveComposite( pCrvBorder)) ; if ( IsNull( pCrvExt)) return false ; // ricavo il tratto da aggiungere alla curva interna double dUS = 0 ; double dUE = 0 ; pCrvExt->GetParamAtPoint( ptJ1B, dUS) ; pCrvExt->ChangeStartPoint( dUS) ; pCrvExt->GetParamAtPoint( ptJ2B, dUE, EPS_SMALL) ; PtrOwner pCrvBorderPart( GetCurveComposite( pCrvExt->CopyParamRange( 0, dUE))) ; if ( IsNull( pCrvBorderPart) || ! pCrvBorderPart->IsValid() || pCrvBorderPart->GetCurveCount() == 0) return false ; // setto aperte tutte le curve del bordo sulla curva esterna for ( int i = 0 ; i < ( int)pCrvBorderPart->GetCurveCount() ; ++ i) pCrvBorderPart->SetCurveTempProp( i, 1) ; // ricompongo la curva interna pCompo->GetParamAtPoint( ptJ1A, dUE) ; PtrOwner pCrvA( GetCurveComposite( pCompo->CopyParamRange( 0, dUE))) ; pCompo->GetParamAtPoint( ptJ2A, dUS) ; PtrOwner pCrvB( GetCurveComposite( pCompo->CopyParamRange( dUS, dUS < EPS_SMALL ? .0 : pCompo->GetCurveCount()))) ; if ( dUS < EPS_SMALL) pCrvB.Set( CreateCurveComposite()) ; PtrOwner pCrvInt( CreateCurveComposite()) ; if ( IsNull( pCrvInt)) return false ; pCrvInt->AddCurve( Release( pCrvA)) ; // aggiungo il primo tratto di curva interna if ( nStat == 0 || nStat == 2) pCrvInt->AddCurve( pL1->Clone()) ; // aggiungo il primo segmento ( se valido ) pCrvInt->AddCurve( Release( pCrvBorderPart)) ; // aggiungo il tratto di curva esterno if ( nStat == 0 || nStat == 1) { pL2->Invert() ; pCrvInt->AddCurve( pL2->Clone()) ; // aggiungo il secondo segmento ( se valido ) } pCrvInt->AddCurve( Release( pCrvB)) ; // aggiungo il secondo tratto di curva interna // torno al punto iniziale originale pCrvInt->GetParamAtPoint( ptS, dUS, EPS_SMALL) ; pCrvInt->ChangeStartPoint( dUS) ; // ritorno la nuova curva pCompo pCompo->Clear() ; pCompo->AddCurve( Release( pCrvInt)) ; return pCompo->IsValid() && pCompo->IsClosed() ; } //---------------------------------------------------------------------------- bool Pocketing::GetParamForPtStartOnEdge( const ICurve* pCrvCheck, const ICurveComposite* pCrvCompo, const ICRVCOMPOPOVECTOR& vOtherCrv, double& dPar) { // ==================== INFO ================================================================ // pCrvCheck -> sottocurva di pCrvCompo su cui cercare il parametro ideale per ingresso // vOtherCrv -> tutte le altre curve che non devono essere intersecate durante l'ingresso // ( questo vettore è stato riempito con tutti loop della superificie da // lavorare, i quali Offset non hanno generato alcuna curva di pCrvCheck ) // ========================================================================================== // controllo dei parametri if ( pCrvCheck == nullptr || ! pCrvCheck->IsValid() || pCrvCompo == nullptr || ! pCrvCompo->IsValid() || pCrvCompo->GetCurveCount() == 0) return false ; // clono le curve PtrOwner pCrv( pCrvCheck->Clone()) ; PtrOwner pCompo( CloneCurveComposite( pCrvCompo)) ; if ( IsNull( pCrv) || IsNull( pCompo)) return false ; ICRVCOMPOPOVECTOR vCrvNoInters ; vCrvNoInters.reserve(( int)vOtherCrv.size()) ; for ( int i = 0 ; i < ( int)vCrvNoInters.size() ; ++ i) vCrvNoInters.emplace_back( CloneCurveComposite( vOtherCrv[i])) ; // ricavo l'estrusione della curva composita Vector3d vtExtr ; if ( ! pCompo->GetExtrusion( vtExtr)) vtExtr = Z_AX ; // ricavo il centroide o il punto centrale della curva composita Point3d ptCen ; if ( ! pCompo->GetCentroid( ptCen)) if ( ! pCompo->GetStartPoint( ptCen)) return false ; // creo un frame locale per creare l'ombra del tool e intersecarla con la curva Frame3d frLoc ; frLoc.Set( ptCen, vtExtr) ; // porto le curve in questo sistema di riferimento pCrv->ToLoc( frLoc) ; pCompo->ToLoc( frLoc) ; for ( int i = 0 ; i < ( int)vCrvNoInters.size() ; ++i) vCrvNoInters[i]->ToLoc( frLoc) ; // fisso il diametro del tool ( più grande per sicurezza ) double dDiam = m_TParams.m_dDiam * 1.15 + 2 * GetOffsR() + 5 * EPS_SMALL ; double dLen ; if ( ! pCrv->GetLength( dLen)) return false ; double dSubArc = -1 ; if ( pCrv->GetType() == CRV_ARC) { PtrOwner pCrvArc( GetCurveArc( pCrv->Clone())) ; if ( IsNull( pCrvArc) || ! GetCoeffLinArc( pCrvArc, dDiam, dSubArc)) return false ; } double dDiv = dSubArc < 0 ? dDiam : dSubArc; double dMaxInt = floor( dLen / dDiv) ; if ( dMaxInt < EPS_SMALL) return false ; int nDen = 2 ; // intervalli in cui suddivido la curva dMaxInt = max( 2.0, dMaxInt) ; // così se entra una volta controllo sempre dParT = 0.5 while ( nDen < dMaxInt + EPS_SMALL) { // EPS_SMALL per comprendere l'uguaglianza for ( int i = 1 ; i < nDen ; ++i) { if ( int( i % nDen) == 0) continue ; double dNum = 1.0 * i ; double dParT = dNum / nDen ; Point3d ptTest ; Vector3d vtPerpIn ; if ( pCrv->GetPointD1D2( dParT, ICurve::FROM_PLUS, ptTest, &vtPerpIn)) { if ( pCrv->GetTempProp() == 0) { // se la curva è chiusa sposto il centro verso l'interno. // Devo essere sicuro di essere su una curva di Offset interno, altrimenti potrebbe essere valido // il punto trovato, però facendo poi il primo offeset tale punto potrebbe diventare un punto // di convergenza tra più chunks... //Vector3d vtPerpIn ; PtrOwner pCompoClone( CloneCurveComposite( pCompo)) ; if ( IsNull( pCompoClone)) return false ; double dU ; pCompoClone->GetParamAtPoint( ptTest, dU) ; pCompoClone->ChangeStartPoint( dU) ; vtPerpIn.Normalize() ; //pCompoClone->GetStartDir( vtPerpIn) ; vtPerpIn.Rotate( Z_AX, 0, 1) ; // cos( pi/2) = 0, sin( pi/2) = 1 vtPerpIn *= (( 0.5 * m_TParams.m_dDiam + GetOffsR() + 5 * EPS_SMALL)) ; ptTest = ptTest + vtPerpIn ; } // creo una circonferenza ( ombra del tool ) centrata su ptTest PtrOwner pCrvToolShape( CreateCurveArc()) ; pCrvToolShape->Set( ptTest, Z_AX, 0.5 * dDiam) ; if ( ! pCrvToolShape->IsValid()) return false ; // interseco la curva composita con l'ombra del tool CRVCVECTOR ccClass ; IntersCurveCurve intCC( *pCompo, *pCrvToolShape) ; //int v = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCompo->Clone()) ; //m_pGeomDB->SetMaterial( v, GREEN) ; //int p = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCrvToolShape->Clone()) ; //m_pGeomDB->SetMaterial( p, PURPLE) ; if ( intCC.GetCurveClassification( 0, EPS_SMALL, ccClass)) { //if (( int)ccClass.size() == 3 && ccClass[1].nClass == CRVC_IN) { // se ho solo due intersezioni, controllo di non intersecare isole bool bOk = true ; for ( int j = 0 ; j < ( int)vCrvNoInters.size() && bOk ; ++ j) { IntersCurveCurve intCCI( *vCrvNoInters[j], *pCrvToolShape) ; if ( intCCI.GetCurveClassification( 0, EPS_SMALL, ccClass)) { if (( int)ccClass.size() > 1) bOk = false ; } else return false ; } if ( bOk) { dPar = dParT ; return true ; } //} } else return false ; } } ++nDen ; } return false ; } //---------------------------------------------------------------------------- bool Pocketing::GetCoeffLinArc( const ICurveArc* pArc, double dDiam, double& dSubArc) { // controllo parametri if ( pArc == nullptr || ! pArc->IsValid()) return false ; Point3d ptMid ; if ( ! pArc->GetMidPoint( ptMid)) return false ; // creo l'ombra del tool nel punto medio PtrOwner pCrvTool( CreateCurveArc()) ; pCrvTool->Set( ptMid, Z_AX, dDiam) ; if ( ! pCrvTool->IsValid()) return false ; IntersCurveCurve intCC( *pArc, *pCrvTool) ; CRVCVECTOR ccClass ; if( intCC.GetCurveClassification( 0, EPS_SMALL, ccClass) && ( int)ccClass.size() == 3 && ccClass[1].nClass == CRVC_IN) { Point3d ptS, ptE ; pCrvTool->GetPointD1D2( ccClass[1].dParS, ICurve::FROM_MINUS, ptS) ; pCrvTool->GetPointD1D2( ccClass[1].dParE, ICurve::FROM_PLUS, ptE) ; Vector3d vtS = ptS - pArc->GetCenter() ; Vector3d vtE = ptE - pArc->GetCenter() ; double dTheta ; vtS.GetAngle( vtE, dTheta) ; dTheta = abs( dTheta) ; dSubArc = pArc->GetRadius() * DEGTORAD * dTheta ; } else return false ; return true ; } //---------------------------------------------------------------------------- bool Pocketing::SetBetterPtStartForSubChunks( ICurveComposite* pCrvOffsAct, const ISurfFlatRegion* pSrfToWork, Point3d& ptStart, Vector3d& vtMidOut, bool& bMidOut, double dOffs) { // ============================= INFO ============================================================== // pCrvOffsAct -> Curva di Offset su cui cercare ptStart, vtMidOut, bMidOpen // pSrfToWork -> Superificie originaria da lavorare // ( questa superificie ha i flag di lati aperti/chiusi settati nei loops) // ================================================================================================= // controllo dei parametri if ( pCrvOffsAct == nullptr || ! pCrvOffsAct->IsValid() || pCrvOffsAct->GetCurveCount() == 0 || pSrfToWork == nullptr || ! pSrfToWork->IsValid() || pSrfToWork->GetChunkCount() != 1) return false ; // clono le curva su cui devo entrares PtrOwner pCrv( CloneCurveComposite( pCrvOffsAct)) ; if ( IsNull( pCrv)) return false ; bool bSomeOpen = false ; // flag per presenza di lati aperti // creo un vettore di Loops della superificie, ordinati ICRVCOMPOPOVECTOR vCrvLoops ; for ( int l = 0 ; l < pSrfToWork->GetLoopCount( 0) ; ++ l) vCrvLoops.emplace_back( GetCurveComposite( pSrfToWork->GetLoop( 0, l))) ; // creo un vettore di indici. Questi indici si riferiscono alle posizioni di vCrvLoops i quali offset // hanno generato delle curve sulla pCrv ( curva da cui devo entrare ) INTVECTOR vIndex ; // scorro tutte le curve presenti in pCrv ( curva da cui devo entrare ) for ( int i = 0 ; i < ( int)pCrv->GetCurveCount() ; ++ i) { // nProp0 -> #curva il cui Offset ha generato la curva i-esima di pCrv int nProp0 ; pCrv->GetCurveTempProp( i, nProp0, 0) ; // nProp1 -> #loop che contiene la curva espressa in nProp0 int nProp1 ; pCrv->GetCurveTempProp( i, nProp1, 1) ; if ( nProp0 > 0) { // se questa curva non è un "raccordo" di Offset // controllo per maggiore sicurezza che effettivamente nProp1 sia un indice valido per il vettore dei Loops e // che nProp0 non sia maggiore del numero di curve del loop nProp1-esimo del vettore dei Loops della pSrfToWork if ( nProp1 >= 0 && nProp1 < ( int)vCrvLoops.size() && nProp0 < vCrvLoops[nProp1]->GetCurveCount()) { // aggiorno il vettore di indici ... if ( find( vIndex.begin(), vIndex.end(), nProp1) == vIndex.end()) vIndex.push_back( nProp1) ; // aggiorno la proprietà della curva da cui devo entrare int nTempProp ; vCrvLoops[nProp1]->GetCurveTempProp( nProp0 - 1, nTempProp, 0) ; pCrv->SetCurveTempProp( i, nTempProp, 0) ; // se la curva è aperta, aggiorno il Flag if ( nTempProp == 1 && ! bSomeOpen) bSomeOpen = true ; } else pCrv->SetCurveTempProp( i, 0, 0) ; } else pCrv->SetCurveTempProp( i, 0, 0) ; } // creo un vettore con tutti i Loops della pSwfToWork per i quali, mediante l'Offset, non hanno // generato alcuna curva presente nella pCrv ( quella da cui devo entrare ) ICRVCOMPOPOVECTOR vOtherCrv ; for ( int i = 0 ; i < ( int)vCrvLoops.size() ; ++ i) { bool bOk = true ; for ( int j = 0 ; j < ( int)vIndex.size() && bOk ; ++ j) { if ( i == vIndex[j]) bOk = false ; } if ( bOk) vOtherCrv.emplace_back( CloneCurveComposite( vCrvLoops[i])) ; } // cerchiamo un punto valido per l'entrata ... bMidOut = false ; if ( bSomeOpen) // se ho dei lati aperti, cerco il più lungo bMidOut = GetParamOnOpenSide( pCrv, vOtherCrv, ptStart, vtMidOut) ; if ( bMidOut) { // se ho trovato e valido, allora imposto il punto inziale trovato const double LEN_OUT = 5 ; double dPar ; int nFlag ; bMidOut = ( DistPointCurve( ptStart + LEN_OUT * vtMidOut, *pCrv).GetParamAtMinDistPoint( 0, dPar, nFlag) && pCrv->ChangeStartPoint( dPar)) ; } if ( ! bMidOut) // alla peggio, ordino i lati lunghi per lunghezza e cerco un'entrata valida AdjustContourStart( pCrv, vOtherCrv, true) ; // ora che ho deciso quale sia il punto iniziale, lo imposto effettivamente sulla curva di Offset passata alla funzione double dUS ; pCrv->GetStartPoint( ptStart) ; pCrvOffsAct->GetParamAtPoint( ptStart, dUS) ; pCrvOffsAct->ChangeStartPoint( dUS) ; return true ; } //---------------------------------------------------------------------------- bool Pocketing::AdjustAngleForProjectedFace( const ISurfFlatRegion* pSrfFaceT, ICurveComposite* pCrvEdgeBorder, double dAngle) { // W.I.P return true ; } //---------------------------------------------------------------------------- bool Pocketing::CheckSimpleOverlap( const ICurve* pCrv, const ICurveComposite* pCrvOri, int& nStat, double dToll) { // controllo dei parametri if (( pCrv == nullptr || pCrvOri == nullptr || dToll < EPS_SMALL)) return false ; nStat = 1 ; // 0 -> no overlap | 1 -> overlap // controllo se una sottocurva della composita è abbastanza vicina a tutti i punti trovati const double nMAX = 10.0 ; for ( int i = 0 ; i <= nMAX ; ++i) { double dPar = i / nMAX ; Point3d ptC ; pCrv->GetPointD1D2( dPar, ICurve::FROM_PLUS, ptC) ; if ( ! pCrvOri->IsPointOn( ptC, dToll)) { nStat = 0 ; return true ; } } return true ; } //---------------------------------------------------------------------------- bool Pocketing::SetTmpPropByOverlap( ICurveComposite* pCrv_, int nInd, const ICurveComposite* pCrvOri, int& nStat, double dToll) { // controllo dei parametri if (( pCrv_ == nullptr || pCrvOri == nullptr || nInd < 0 || nInd > pCrv_->GetCurveCount() || dToll < EPS_SMALL)) return false ; nStat = 1 ; // 0 -> no overlap | 1 -> overlap | 2 -> undefinded // ricavo la curva da controllare PtrOwner pCrv( GetCurveComposite( pCrv_->CopyParamRange( nInd, nInd + 1))) ; if ( IsNull( pCrv)) return false ; // controllo se la curva fa overlap if ( ! CheckSimpleOverlap( pCrv, pCrvOri, nStat, dToll)) return false ; if ( nStat == 0) return true ; // ricavo i parametri sulla curva originale di vicinanza double dUS = 0 ; double dUE = 0 ; Point3d ptS ; pCrv->GetStartPoint( ptS) ; Point3d ptE ; pCrv->GetEndPoint( ptE) ; pCrvOri->GetParamAtPoint( ptS, dUS, dToll) ; pCrvOri->GetParamAtPoint( ptE, dUE, dToll) ; // controllare questa funzione, con 50 funziona la C, ma non la passata con il tool a 75 ! int nRealDUS = ( int)floor( dUS) ; int nRealDUE = ( int)ceil( dUE) ; if ( ceil( dUS) - dUS < EPS_SMALL) nRealDUS = ( int)ceil( dUS) ; if ( dUE - floor( dUE) < EPS_SMALL) nRealDUE = ( int)floor( dUE) ; // controllo subito se tocco più curve sulla originale con stesse temp prop bool bHasAllSameProp = true ; int nProp_prec ; pCrvOri->GetCurveTempProp( nRealDUS, nProp_prec, 0) ; for ( int u = nRealDUS + 1 ; u < nRealDUE && bHasAllSameProp ; ++ u) { int nProp_act ; pCrvOri->GetCurveTempProp( u, nProp_act, 0) ; if ( nProp_prec != nProp_act) bHasAllSameProp = false ; } if ( bHasAllSameProp) { int nCrv = nRealDUS ; int nProp0 = 0 ; pCrvOri->GetCurveTempProp( nCrv, nProp0, 0) ; int nProp1 = 0 ; pCrvOri->GetCurveTempProp( nCrv, nProp1, 1) ; pCrv_->SetCurveTempProp( nInd, nProp0, 0) ; pCrv_->SetCurveTempProp( nInd, nProp1, 1) ; return true ; } // copio le sottocurve toccate PtrOwner pCrvOriRange( CloneCurveComposite( pCrvOri)) ; pCrvOriRange->TrimStartEndAtParam( floor( dUS), ceil( dUE)) ; if ( ! pCrvOriRange->IsValid()) { nStat = 2 ; return true ; } // curva finale da resitutire PtrOwner pCrvFinal( CreateCurveComposite()) ; if ( IsNull( pCrvFinal)) return false ; // per ogni sottocurva... double dUProjS = 0 ; double dUProjE = 0 ; for ( int u = 0 ; u < pCrvOriRange->GetCurveCount() ; ++ u) { Point3d ptCrvOriE ; pCrvOriRange->GetPointD1D2( u + 1, ICurve::FROM_MINUS, ptCrvOriE) ; if ( u == 0) dUProjS = 0 ; else dUProjS = dUProjE ; if ( u == pCrvOriRange->GetCurveCount() - 1) dUProjE = 1 ; else pCrv->GetParamAtPoint( ptCrvOriE, dUProjE, dToll) ; PtrOwner pCrvRange( GetCurveComposite( pCrv->CopyParamRange( dUProjS, dUProjE))) ; if ( ! IsNull( pCrvRange) && pCrvRange->IsValid()) { int nProp0 = 0 ; pCrvOriRange->GetCurveTempProp( u, nProp0, 0) ; int nProp1 = -1 ; pCrvOriRange->GetCurveTempProp( u, nProp1, 1) ; pCrvRange->SetCurveTempProp( 0, nProp0, 0) ; pCrvRange->SetCurveTempProp( 0, nProp1, 1) ; pCrvFinal->AddCurve( Release( pCrvRange)) ; } else { nStat = 2 ; return true ; } } // controllo che la curva ottenuta sia valida ... if ( ! IsNull( pCrvFinal) && pCrvFinal->GetCurveCount() > 0 && pCrvFinal->IsValid()) { Point3d ptSCheck ; Point3d ptECheck ; pCrvFinal->GetStartPoint( ptSCheck) ; pCrvFinal->GetEndPoint( ptECheck) ; if ( ! AreSamePointApprox( ptS, ptSCheck) || ! AreSamePointApprox( ptE, ptECheck)) nStat = 2 ; } else nStat = 2 ; // ritorno la curva modificata if ( nStat != 2) { pCrvFinal->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL, true, true) ; PtrOwner pCrvToReturn( CreateCurveComposite()) ; if( IsNull( pCrvToReturn)) return false ; // PRIMO TRATTO PtrOwner pCrvA( GetCurveComposite( pCrv_->CopyParamRange( 0, nInd))) ; if ( ! IsNull( pCrvA) && pCrvA->GetCurveCount() > 0 && pCrvA->IsValid()) { if ( ! pCrvToReturn->AddCurve( Release( pCrvA))) { nStat = 2 ; return true ; } } // NUOVO TRATTO if( ! pCrvToReturn->AddCurve( Release( pCrvFinal))) { nStat = 2 ; return true ; } // ULTIMO TRATTO PtrOwner pCrvB( GetCurveComposite( pCrv_->CopyParamRange( nInd + 1, pCrv_->GetCurveCount()))) ; if ( ! IsNull( pCrvB) && pCrvB->GetCurveCount() > 0 && pCrvB->IsValid()) if( ! pCrvToReturn->AddCurve( Release( pCrvB))) { nStat = 2 ; return true ; } if ( pCrvToReturn->GetCurveCount() > 0 && pCrvToReturn->IsValid()) { double dThick ; pCrv_->GetThickness( dThick) ; Vector3d vtExtr ; pCrv_->GetExtrusion( vtExtr) ; int nProp0 = pCrv_->GetTempProp( 0) ; int nProp1 = pCrv_->GetTempProp( 1) ; pCrv_->Clear() ; pCrv_->AddCurve( Release( pCrvToReturn)) ; pCrv_->SetExtrusion( vtExtr ) ; pCrv_->SetThickness( dThick) ; pCrv_->SetTempProp( nProp0, 0) ; pCrv_->SetTempProp( nProp1, 1) ; } else nStat = 2 ; } return true ; } //---------------------------------------------------------------------------- bool Pocketing::SetTmpPropWithRawProjectedFaces( ICurveComposite* pCrvCompo_NewExt, ICRVCOMPOPOVECTOR& vCrvExtProj, const Vector3d& vtN, double dToll) { // controllo validità parametri if ( pCrvCompo_NewExt == nullptr || dToll < EPS_SMALL || vtN.IsSmall()) return false ; // creo un frame Locale alla regione di svuotatura Frame3d frLoc ; Point3d ptC ; if ( ! pCrvCompo_NewExt->GetCentroid( ptC)) if ( ! pCrvCompo_NewExt->GetStartPoint( ptC)) return false ; frLoc.Set( ptC, vtN) ; if ( ! frLoc.IsValid()) return false ; // inizialmente imposto tutte le curve come chiuse for ( int u = 0 ; u < pCrvCompo_NewExt->GetCurveCount() ; ++ u) pCrvCompo_NewExt->SetCurveTempProp( u, 0, 0) ; //int ww = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCrvCompo_NewExt->Clone()) ; //m_pGeomDB->SetMaterial( ww, WHITE) ; //for ( int i = 0 ; i < ( int)vCrvExtProj.size() ; ++ i) { // int ww2 = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, vCrvExtProj[i]->Clone()) ; // m_pGeomDB->SetMaterial( ww2, BLACK) ; //} // imposto le proprietà temporanee delle curve for ( int u = 0 ; u < pCrvCompo_NewExt->GetCurveCount() ; ++ u) { bool bFound = false ; for ( int i = 0 ; i < ( int)vCrvExtProj.size() && !bFound ; ++ i) { int nStat = -1 ; if ( SetTmpPropByOverlap( pCrvCompo_NewExt, u, vCrvExtProj[i], nStat, dToll) && nStat == 1) bFound = true ; } if ( ! bFound) { // controllo se fa overlap con più curve di proiezione ( la SetTmpPropByOverlap ritorna Falso se non c'è un // CheckSimpleOverlap => Se la curva fa Overlap con diversi bordi di proiezione devo settare le temp prop caso // per caso... PtrOwner pCrvCompoCurr( CreateCurveComposite()) ; pCrvCompoCurr->AddCurve( *pCrvCompo_NewExt->GetCurve( u)) ; if ( IsNull( pCrvCompoCurr) || ! pCrvCompoCurr->IsValid()) return false ; // scorro il vettore delle curve aperte di proiezione for ( int i = 0 ; i < ( int)vCrvExtProj.size() ; ++ i) { PtrOwner pCrvCompoH( CreateCurveComposite()) ; if ( IsNull( pCrvCompoH)) return false ; // per ogni sottocurva creata dalla singola curva originale... for ( int uu = 0 ; uu < pCrvCompoCurr->GetCurveCount() ; ++ uu) { int nProp_Check = -1 ; // se la curva non è già stata impostata aperta in un passaggio precedente... if ( pCrvCompoCurr->GetCurveTempProp( uu, nProp_Check, 0) && nProp_Check == 0) { PtrOwner pCrvCurr_Close( pCrvCompoCurr->GetCurve( uu)->Clone()) ; if ( IsNull( pCrvCurr_Close) || ! pCrvCurr_Close->IsValid()) return false ; // controllo se il pezzo chiuso fa Overlap con la curva della proiezione i-esima // porto in locale... pCrvCurr_Close->ToLoc( frLoc) ; vCrvExtProj[i]->ToLoc( frLoc) ; // intersezione... IntersCurveCurve IntCC( *pCrvCurr_Close, *vCrvExtProj[i]) ; // riporto in globale... pCrvCurr_Close->ToGlob( frLoc) ; vCrvExtProj[i]->ToGlob( frLoc) ; CRVCVECTOR ccClass ; // se riesco a classificare... if ( IntCC.GetCurveClassification( 0, dToll, ccClass)) { // se questa curva non fa overlap, ma è semplicemente o tutta interna o tutta esterna alla curva // do bordo della proiezione i-esima, allor apasso a controllare la successiva if (( int)ccClass.size() == 1 && ( ccClass[0].nClass == CRVC_IN || ccClass[0].nClass == CRVC_OUT)) continue ; // altrimenti... for ( int j = 0 ; j < ( int)ccClass.size() ; ++ j) { PtrOwner pCrv_Step( pCrvCurr_Close->CopyParamRange( ccClass[j].dParS, ccClass[j].dParE)) ; if ( IsNull( pCrv_Step) || ! pCrv_Step->IsValid()) continue ; // chiusa per default... PtrOwner pCrvCompo_Step( CreateCurveComposite()) ; pCrvCompo_Step->AddCurve( pCrv_Step->Clone()) ; int nStat1 = -1 ; // richiamo la SetTmpPropByOverlap in quanto potrebbe fare overlap con l'indice 0 di vCrvExtProj. // L'indice 0 contiene il bordo con i lati aperti/chiusi settati della intersezione con il grezzo if ( SetTmpPropByOverlap( pCrvCompo_Step, 0, vCrvExtProj[i], nStat1, dToll) && nStat1 != -1) pCrvCompo_Step->SetCurveTempProp( 0, 0, 0) ; // chiusa se non c'è Overlap pCrvCompoH->AddCurve( Release( pCrvCompo_Step)) ; } } } // se la curva è aperta la riaggiungo come sottocurva aperta alla composita pCrvCompoH->AddCurve( pCrvCompoCurr->GetCurve( uu)->Clone()) ; } // finite le sottocurve, restiruisco la composita finale con il valore delle sottocurve impostate // la curva originale u-esima è stata scomposta in sottocurve aperte/chiuse a seconda di quali e quanti // overlap ha fatto con le curve esterne delle proiezioni if ( pCrvCompoH->GetCurveCount() > 1) pCrvCompoCurr.Set( Release( pCrvCompoH)) ; } // sostituisco la CURVA COMPOSITA creata con alla CURVA SEMPLICE originaria PtrOwner pCrv_Bef( CloneCurveComposite( pCrvCompo_NewExt)) ; // tratto precente PtrOwner pCrv_Aft( CloneCurveComposite( pCrvCompo_NewExt)) ; // tratto successivo PtrOwner pCrv_New( CreateCurveComposite()) ; if ( IsNull( pCrv_Bef) || IsNull( pCrv_Aft) || IsNull( pCrv_New) || ! pCrv_Bef->IsValid() || ! pCrv_Aft->IsValid()) return false ; // ricomposizione con tagli per non perdere le proprietà appena impostate pCrv_Bef->TrimEndAtParam( u) ; pCrv_Aft->TrimStartAtParam( u + 1) ; if ( ! IsNull( pCrv_Bef) && pCrv_Bef->IsValid()) pCrv_New->AddCurve( Release( pCrv_Bef)) ; int nCrv = 0 ; if ( ! IsNull( pCrvCompoCurr) && pCrvCompoCurr->IsValid()) { nCrv = pCrvCompoCurr->GetCurveCount() ; pCrv_New->AddCurve( Release( pCrvCompoCurr)) ; } if ( ! IsNull( pCrv_Aft) && pCrv_Aft->IsValid()) pCrv_New->AddCurve( Release( pCrv_Aft)) ; // controllo validità della curva, altrimenti non modifico nulla ed esco ( Avrò un chiuso) if ( ! IsNull( pCrv_New) && pCrv_New->IsValid() && pCrv_New->IsClosed()) { pCrvCompo_NewExt->Clear() ; pCrvCompo_NewExt->AddCurve( Release( pCrv_New)) ; u += nCrv - 1 ; // " ++u " } } } return true ; } //---------------------------------------------------------------------------- bool Pocketing::CheckSmallPartsForOpenEdge( ICurveComposite* pCrvCompo, double dToll) { // controllo validità dei parametri if ( pCrvCompo == nullptr || ! pCrvCompo->IsValid() || pCrvCompo->GetCurveCount() == 0 || dToll < EPS_SMALL) return false ; // sistemo le curve piccole per le quali potrei ever commesso degli errori impostando un lato chiuso for ( int i = 0 ; i < pCrvCompo->GetCurveCount() ; ++ i) { const ICurve* pCrvCurr = pCrvCompo->GetCurve( i) ; if ( pCrvCurr == nullptr) return false ; double dLen = EPS_SMALL ; if ( pCrvCurr->GetLength( dLen) && dLen < dToll && pCrvCurr->GetTempProp( 0) == 0) { const ICurve* pCrv_Prec = pCrvCompo->GetCurve( i != 0 ? i - 1 : pCrvCompo->GetCurveCount() - 1) ; const ICurve* pCrv_Succ = pCrvCompo->GetCurve( i != pCrvCompo->GetCurveCount() -1 ? i + 1 : 0 ) ; if ( pCrv_Prec == nullptr || pCrv_Succ == nullptr) return false ; if ( pCrv_Prec->GetTempProp( 0) != pCrv_Succ->GetTempProp( 0)) { // controllo se la curva attuale è in tangenza con la parte chiusa Vector3d vtAct ; // vettore sulla curva i-esima Vector3d vtRef ; // vettore sulla curva chiusa vicina if ( pCrv_Prec->GetTempProp( 0) == 0) { // se curva precedente chiusa pCrv_Prec->GetEndDir( vtRef) ; pCrvCurr->GetStartDir( vtAct) ; } else { // se curva successiva è chiusa pCrv_Succ->GetStartDir( vtRef) ; pCrvCurr->GetEndDir( vtAct) ; } if ( AreSameOrOppositeVectorEpsilon( vtRef, vtAct, 150 * EPS_SMALL)) pCrvCompo->SetCurveTempProp( i, 0, 0) ; // proseguimento o raccordo di un chiuso else pCrvCompo->SetCurveTempProp( i, 1, 0) ; // rientra nelle tolleranze e quindi è un falso chiuso } } } return true ; } //---------------------------------------------------------------------------- bool Pocketing::CheckIfOffsetIsNecessary( const ICurveComposite* pCrvOffs, const double dOffs, const int nOffsCount, const int nIter, const Vector3d& vtN, bool& bInsert) { // controllo dei parametri if ( pCrvOffs == nullptr || ! pCrvOffs->IsValid() || pCrvOffs->GetCurveCount() == 0 || dOffs < EPS_SMALL) return false ; bInsert = true ; // di base inserisco // controllo se richiesta ottimizzazione sul numero di Offsets if ( ! m_bOptOffset) return true ; if ( nIter != 0) { // controllo se sono almeno al secondo offset... // per ogni curva controllo se il controOffset + 5 * EPS_SMALL genera una regione ... OffsetCurve OffsCrv ; // considero anche i casi in cui ho bSmallRad if ( OffsCrv.Make( pCrvOffs, - m_TParams.m_dDiam / 2 + dOffs - 5 * EPS_SMALL , ICurve::OFF_FILLET)) { // se questa curva sparisce -> non serve inserirla come offset, non svuota parti aggiuntive if ( OffsCrv.GetCurveCount() == 0) { bInsert = false ; return true ; } } else return true ; // controllo se richista ottimizzazione per Offsets mediante centroidi e medial Axis if( ! m_bOptOffsetCM || OffsCrv.GetCurveCount() > 1) return true ; PtrOwner pCrvOffLonger( OffsCrv.GetLongerCurve()) ; if( IsNull( pCrvOffLonger) || ! pCrvOffLonger->IsValid()) return true ; // Immagine del tool con centro nel centroide della zona da svuotare Point3d ptC ; pCrvOffLonger->GetCentroid( ptC) ; PtrOwner pCrvTool( CreateCurveArc()) ; if( IsNull( pCrvTool)) return false ; pCrvTool->SetXY( ptC, m_TParams.m_dDiam / 2 - 5 * EPS_SMALL) ; CRVCVECTOR ccClass ; IntersCurveCurve intCC( *pCrvOffLonger, *pCrvTool) ; intCC.GetCurveClassification( 1, EPS_SMALL, ccClass) ; if (( int)ccClass.size() == 1 && ccClass[0].nClass == CRVC_OUT) { // CENTROIDE bInsert = false ; return true ; } // <- secondo test PolyLine pl ; if ( ! pCrvOffLonger->ApproxWithLines( 100 * EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_STD, pl)) return true ; Vector3d vtX ; double dLen = 0 ; double dHeight = 0 ; if( ! pl.GetMinAreaRectangleXY( ptC, vtX, dLen, dHeight)) return true ; Frame3d frLoc ; frLoc.Set( ptC, vtN, vtX) ; if( ! frLoc.IsValid()) return true ; BBox3d bBox ; frLoc.Invert() ; pCrvOffLonger->GetBBox( frLoc, bBox) ; double dDimX = bBox.GetDimX() ; double dDimY = bBox.GetDimY() ; if( dDimX < m_TParams.m_dDiam - 100 * EPS_SMALL || dDimY < m_TParams.m_dDiam - 100 * EPS_SMALL) { bInsert = false ; return true ; } } return true ; } //---------------------------------------------------------------------------- bool Pocketing::AssignFeedSpiralOpt( const int nOptType, ICurveComposite* pCrv ) { // controllo della curva corrente if ( pCrv == nullptr || !pCrv->IsValid() || pCrv->GetCurveCount() == 0) return false ; // controllo se il Flag per assegnare la Feed è attivo if ( !m_bAssignFeed) return AssignDefaultFeed( pCrv) ; switch ( m_Params.m_nSubType ) { case POCKET_SUB_SPIRALIN : if ( nOptType == 0) { // Spirale dall'Esterno for ( int u = 0 ; u < pCrv->GetCurveCount() ; ++ u) { if ( u == 0) // prima circonferenza pCrv->SetCurveTempProp( 0, FEED_DIVISOR * GetMinFeed(), 0) ; else // semi cerchi in tangenza pCrv->SetCurveTempProp( u, FEED_DIVISOR * GetMaxFeed(), 0) ; } } else if ( nOptType == 1) { // Trapezoidi for ( int u = 0 ; u < pCrv->GetCurveCount() ; ++ u) pCrv->SetCurveTempProp( u, FEED_DIVISOR * GetMinFeed(), 0) ; } break ; /* NB. Essendo la funzione CalcSpiral richiamata sia per lo SpiralIN che per lo SpiralOUT le curve sono sempre orientate nello stesso modo, solamente alla fine viene invertita la curva finale per la svuotatura... */ case POCKET_SUB_SPIRALOUT : if ( nOptType == 0) { // Spiral verso l'esterno for ( int u = 0 ; u < pCrv->GetCurveCount() ; ++ u) { if ( u > pCrv->GetCurveCount() - 3 ) // prime semi circonferenze pCrv->SetCurveTempProp( u, FEED_DIVISOR * GetMinFeed(), 0) ; else pCrv->SetCurveTempProp( u, FEED_DIVISOR * GetMaxFeed(), 0) ; } } else if ( nOptType == 1) { // Trapezoidi for ( int u = 0 ; u < pCrv->GetCurveCount() ; ++ u) pCrv->SetCurveTempProp( u, FEED_DIVISOR * GetMinFeed(), 0) ; } break ; default : break ; } return true ; } //---------------------------------------------------------------------------- bool Pocketing::AssignFeedZigZagOneWay( ICurveComposite* pCompo, const bool bIsLink, const ICURVEPOVECTOR& vLAbove, const ICURVEPOVECTOR& vLUnder, const ICRVCOMPOPOVECTOR& vAddedLinks) { // controllo che la pCompoLine sia effettivamente una linea valida if ( pCompo == nullptr || ! pCompo->IsValid()) return false ; // controllo se il Flag per assegnare la Feed è attivo if ( !m_bAssignFeed) return AssignDefaultFeed( pCompo) ; // inzialmente setto la feed Minima alla curva for ( int u = 0 ; u < pCompo->GetCurveCount() ; ++ u) pCompo->SetCurveTempProp( u, FEED_DIVISOR * GetMinFeed(), 0) ; // se è un link tra livelli diversi, allora esco ( con Feed Minima ) if ( bIsLink) { Point3d ptS_link ; pCompo->GetStartPoint( ptS_link) ; Point3d ptE_link ; pCompo->GetEndPoint( ptE_link) ; if ( abs( ptE_link.y - ptS_link.y) > 500 * EPS_SMALL) return true ; } // se la curva è piccola, allora esco ( con Feed Minima) double dLen = EPS_SMALL ; if ( ! pCompo->GetLength( dLen) || dLen < 0.6 * m_TParams.m_dDiam) return true ; Point3d ptS, ptE ; pCompo->GetStartPoint( ptS) ; pCompo->GetEndPoint( ptE) ; // creo l'intervallo desiderato valutanto le coordinate x Intervals IntMinFeed ; IntMinFeed.Set( ptS.x, ptE.x) ; // creo un vettore contenente i tratti sopra e i tratti sotto attivi ICURVEPOVECTOR vAllInt ; vAllInt.reserve(( int)vLUnder.size() + ( int)vLAbove.size()) ; for ( int i = 0 ; i < ( int)vLUnder.size() ; ++ i) vAllInt.emplace_back( vLUnder[i]->Clone()) ; for ( int i = 0 ; i < ( int)vLAbove.size() ; ++ i) vAllInt.emplace_back( vLAbove[i]->Clone()) ; int nDim = ( int)vAllInt.size() ; // aggiungo le parti dei link interessate double dCurrY = ptS.y ; BBox3d bBoxLink ; for ( int l = 0 ; l < ( int)vAddedLinks.size() ; ++ l) { vAddedLinks[l]->GetLocalBBox( bBoxLink) ; if (( dCurrY - bBoxLink.GetMin().y) < GetSideStep() + 50 * EPS_SMALL || ( dCurrY - bBoxLink.GetMax().y) < GetSideStep() + 50 * EPS_SMALL) { // determino la direzione del Link Vector3d vtLinkDir( - 25, 0, 0) ; Point3d ptS_l ; vAddedLinks[l]->GetStartPoint( ptS_l) ; Point3d ptE_l ; vAddedLinks[l]->GetEndPoint( ptE_l) ; if ( ptE_l.x - ptS_l.x < EPS_SMALL) vtLinkDir.x -= ptS_l.x - ptE_l.x ; PtrOwner pSfrRectUp( GetSurfFlatRegionRectangle( bBoxLink.GetDimX() + 50, GetSideStep())) ; pSfrRectUp->Translate(( ptS_l - ORIG) + vtLinkDir) ; // link sopra o sotto alla curva currente ? bool bIsDown = true ; if ( dCurrY - ptS_l.y < EPS_SMALL) bIsDown = false ; CRVCVECTOR ccClass ; pSfrRectUp->GetCurveClassification( *vAddedLinks[l], EPS_SMALL, ccClass) ; for ( int i = 0 ; i < ( int)ccClass.size() ; ++ i) { if ( ccClass[i].nClass == CRVC_IN && bIsDown || ccClass[i].nClass == CRVC_OUT && ! bIsDown) vAllInt.emplace_back( GetCurveComposite( vAddedLinks[l]->CopyParamRange( ccClass[i].dParS, ccClass[i].dParE))) ; } } } // scorro tutti i tratti Attivi for ( int i = 0 ; i < ( int)vAllInt.size() ; ++ i) { // controllo che il tratto lineare sotto sia sufficientemente lungo double dLen_iU = EPS_SMALL ; if ( ! vAllInt[i]->GetLength( dLen_iU) || ( dLen_iU < 1.1 * m_TParams.m_dDiam && i < nDim)) continue ; Point3d ptS_iU, ptE_iU ; vAllInt[i]->GetStartPoint( ptS_iU) ; vAllInt[i]->GetEndPoint( ptE_iU) ; // la vtDir per Above e Under è sempre invertita rispetto alla linea corrente // sottraggo questo intervallo a quello originale IntMinFeed.Subtract( ptS_iU.x, ptE_iU.x) ; } // l'intervallo orginale ora conterrà i sottointervalli con feed Minima, tolgo quelli troppo piccoli Intervals IntMinFeed_noSmall ; double dParS = EPS_SMALL ; double dParE = EPS_SMALL ; bool bFound = IntMinFeed.GetFirst( dParS, dParE) ; while ( bFound) { if ( dParE - dParS > m_TParams.m_dDiam * 0.5 - 5 * EPS_SMALL) IntMinFeed_noSmall.Add( dParS, dParE) ; bFound = IntMinFeed.GetNext( dParS, dParE) ; } // ora che ho solo tratti abbastanza lunghi, creo l'intervallo complementare // questo intervallo contiene tutte le feed Massime Intervals IntMaxFeed ; IntMaxFeed.Set( ptS.x, ptE.x) ; IntMaxFeed.Subtract( IntMinFeed_noSmall) ; // tolgo le parti piccole Intervals IntMaxFeed_noSmall ; bFound = IntMaxFeed.GetFirst( dParS, dParE) ; while ( bFound) { if ( dParE - dParS > m_TParams.m_dDiam * 0.5 - 5 * EPS_SMALL) IntMaxFeed_noSmall.Add( dParS, dParE) ; bFound = IntMaxFeed.GetNext( dParS, dParE) ; } // recupero la direzione principale della curva corrente Vector3d vtDir = X_AX ; if ( ptE.x - ptS.x < EPS_SMALL) vtDir = - X_AX ; // trasformo questi intervalli nei parametri corrispondenti sulla linea originale bool bFMax = false ; bFound = IntMaxFeed_noSmall.GetFirst( dParS, dParE) ; if ( bFound && IntMaxFeed_noSmall.IsInside( ptS.x + vtDir.x * 20 * EPS_SMALL)) bFMax = true ; if ( ! bFound && bIsLink) // se non ho intervalli a Feed Massima, allora esco ( con Feed Minima) return true ; while ( bFound) { if ( ! bIsLink) { // se segmento di ZigZag double du_js = EPS_SMALL ; pCompo->GetParamAtPoint( Point3d( dParS, ptS.y, ptS.z), du_js) ; pCompo->AddJoint( du_js) ; double du_je = EPS_SMALL ; pCompo->GetParamAtPoint( Point3d( dParE, ptE.y, ptE.z), du_je) ; pCompo->AddJoint( du_je) ; } bFound = IntMaxFeed_noSmall.GetNext( dParS, dParE) ; } // aggiorno le proprietà temporanee con la feed if ( ! bIsLink) { for ( int u = 0 ; u < pCompo->GetCurveCount() ; ++ u) { if ( IsEven( u) == bFMax) pCompo->SetCurveTempProp( u, FEED_DIVISOR * GetMaxFeed() , 0) ; else pCompo->SetCurveTempProp( u, FEED_DIVISOR * GetMinFeed() , 0) ; } } return true ; } //---------------------------------------------------------------------------- bool Pocketing::AssignFeedOnCorners( ICurveComposite* pCrv, const ICurveComposite* pCrv_orig, const double dLenToll) { // controllo sulla curva iniziale if ( pCrv == nullptr || ! pCrv->IsValid() || pCrv->GetCurveCount() == 0 || ! pCrv->IsClosed()) return false ; // controllo se Flag per Feed è attivo if ( !m_bAssignFeed) return AssignDefaultFeed( pCrv) ; // nuova curva finale PtrOwner pCrv_new( CreateCurveComposite()) ; if ( IsNull( pCrv_new)) return false ; Intervals IntU ; IntU.Set( 0.0, 1.0 * pCrv->GetCurveCount()) ; // scorro tutte le curve cercando i punti non C' for ( int u = 0 ; u < pCrv->GetCurveCount() ; ++ u ) { // curva u-esima const ICurve* pCrv_u = pCrv->GetCurve( u) ; // curva (u+1)-esima int u_f = u + 1 ; if ( u_f == pCrv->GetCurveCount()) u_f = 0 ; const ICurve* pCrv_uu = pCrv->GetCurve( u_f) ; // calcolo l'angolo tra le due curve double dAng = EPS_ANG_ZERO ; Vector3d dTan_u = V_NULL ; pCrv_u->GetEndDir( dTan_u) ; Vector3d dTan_uu = V_NULL ; pCrv_uu->GetStartDir( dTan_uu) ; double dU_S = 0.0 ; double dU_E = 1.0 ; if ( ! dTan_u.GetAngle( dTan_uu, dAng) || abs( dAng) > EPS_ANG_SMALL) { // se spigolo... // ricavo la lunghezza delle due curve e controllo che non siano dei lati aperti int nStat_u = 0 ; if ( CheckSimpleOverlap( pCrv_u, pCrv_orig, nStat_u, 50 * EPS_SMALL) && nStat_u != 1) { double dLen_u = EPS_SMALL ; pCrv_u->GetLength( dLen_u) ; if ( dLen_u > dLenToll + 500 * EPS_SMALL) pCrv_u->GetParamAtLength( dLen_u - dLenToll, dU_S) ; } int nStat_uu = 0 ; if ( CheckSimpleOverlap( pCrv_uu, pCrv_orig, nStat_uu, 50 * EPS_SMALL) && nStat_uu != 1) { double dLen_uu = EPS_SMALL ; pCrv_uu->GetLength( dLen_uu) ; if ( dLen_uu > dLenToll + 500 * EPS_SMALL) pCrv_uu->GetParamAtLength( dLenToll, dU_E) ; } if ( u_f != 0) { IntU.Subtract( u + ( nStat_u == 0 ? dU_S : 1), u_f + ( nStat_uu == 0 ? dU_E : 0)) ; } else { if ( nStat_u == 0) IntU.Subtract( u + dU_S, pCrv->GetCurveCount()) ; if ( nStat_uu == 0) IntU.Subtract( 0.0, dU_E) ; } } } ICRVCOMPOPOVECTOR vCrvMinFeed ; double dParS = EPS_SMALL ; double dParE = EPS_SMALL ; Intervals IntMinFeed ; IntMinFeed.Set( 0.0, 1.0 * pCrv->GetCurveCount()) ; IntMinFeed.Subtract( IntU) ; bool bFound = IntMinFeed.GetFirst( dParS, dParE) ; while ( bFound) { Point3d ptS, ptE ; vCrvMinFeed.emplace_back( GetCurveComposite( pCrv->CopyParamRange( dParS, dParE))) ; for ( int u = 0 ; u < vCrvMinFeed.back()->GetCurveCount() ; ++ u) vCrvMinFeed.back()->SetCurveTempProp( u, FEED_DIVISOR * GetMinFeed(), 0) ; bFound = IntMinFeed.GetNext( dParS, dParE) ; } PtrOwner pCrv_clone( pCrv->Clone()) ; for ( int i = 0 ; i < ( int)vCrvMinFeed.size() ; ++ i) { PtrOwner pCrv_back( pCrv_clone->Clone()) ; PtrOwner pCrv_forward( pCrv_clone->Clone()) ; Point3d ptS, ptE ; vCrvMinFeed[i]->GetStartPoint( ptS) ; vCrvMinFeed[i]->GetEndPoint( ptE) ; double duS ; double duE ; pCrv_clone->GetParamAtPoint( ptS, duS) ; pCrv_clone->GetParamAtPoint( ptE, duE) ; pCrv_back->TrimEndAtParam( duS) ; pCrv_forward->TrimStartAtParam( duE) ; pCrv_clone->Clear() ; pCrv_clone->AddCurve( Release( pCrv_back)) ; pCrv_clone->AddCurve( vCrvMinFeed[i]->Clone()) ; pCrv_clone->AddCurve( Release( pCrv_forward)) ; } pCrv->Clear() ; pCrv->AddCurve( Release( pCrv_clone)) ; return false ; } //---------------------------------------------------------------------------- bool Pocketing::GetFeedForParam( double& dPar, double& dFeed) { /* feed ^ | GetFeed() + --------------\ | * \ | * \ | * \ | * \ | * \ GetFeed() * GetSideStep() / d + * * | * * 0--------------+------+---------------> Working Arc GetSideStep() d */ if ( dPar > m_TParams.m_dDiam || dPar < 0 ) // dominio... return false ; if ( m_TParams.m_dDiam - GetSideStep() < 50 * EPS_SMALL) { // se la funzione è costante... dFeed = GetMaxFeed() ; // non ho scelta ... return true ; } else { if ( GetSideStep() < dPar + 50 * EPS_SMALL) { // se sono nel tratto lineare discendente ... // d/2 su parte discendente dFeed = GetFeed() + ( GetFeed() * ( 1 - ( GetSideStep() / m_TParams.m_dDiam))) * ( dPar - GetSideStep()) / ( GetSideStep() - m_TParams.m_dDiam) ; } else dFeed = GetMaxFeed() ; // se sono nel tratto costante ... } return true ; } //---------------------------------------------------------------------------- bool Pocketing::AssignFeedForOpenEdge( ICurveComposite* pCrv, const ICurveComposite* pCrvOF_orig) { if ( !m_bAssignFeed) return AssignDefaultFeed( pCrv) ; // controllo se qualche curva passa sopra ad un lato aperto... if ( pCrvOF_orig != nullptr ) { for ( int u = 0 ; u < pCrv->GetCurveCount() ; ++ u) { const ICurve* pCrv_u = pCrv->GetCurve( u) ; if ( pCrv_u == nullptr) return false ; int nStat = -1 ; if ( CheckSimpleOverlap( pCrv_u, pCrvOF_orig, nStat, 1500 * EPS_SMALL) && nStat == 1) { double dFeed = GetMinFeed() ; double dPar = m_TParams.m_dDiam / 2 ; if ( ! GetFeedForParam( dPar, dFeed)) return false ; pCrv->SetCurveTempProp( u, FEED_DIVISOR * dFeed, 0) ; } } } return true ; } //---------------------------------------------------------------------------- bool Pocketing::AssignFeedForLineInOut( ICurveComposite* pCrv, const bool bIsIn) { // controllo parametri if ( pCrv == nullptr || pCrv->GetCurveCount() < 2) return false ; if ( !m_bAssignFeed) return AssignDefaultFeed( pCrv) ; if ( bIsIn) // Segmento in ingresso pCrv->SetCurveTempProp( 0, FEED_DIVISOR * GetMinFeed(), 0) ; else // Segmento in uscita pCrv->SetCurveTempProp( pCrv->GetCurveCount() - 1, FEED_DIVISOR * GetMaxFeed(), 0) ; return true ; } //---------------------------------------------------------------------------- bool Pocketing::AssignFeedForEdgeCleaning( ICurveComposite *pCrv, const ICRVCOMPOPOVECTOR& vCrvOF_orig, int nInd) { // controllo parametri if ( pCrv == nullptr || ! pCrv->IsValid() || pCrv->GetCurveCount() == 0) return false ; // controllo che la svuotatura sia ZigZag o OneWay if ( m_Params.m_nSubType == POCKET_SUB_SPIRALIN || m_Params.m_nSubType == POCKET_SUB_SPIRALOUT) return false ; // controllo se il Flag per assegnare la Feed è attivo if ( !m_bAssignFeed) return AssignDefaultFeed( pCrv) ; double dCurrFeed = GetMinFeed() ; if ( m_Params.m_nSubType == POCKET_SUB_ZIGZAG) // se pulitura ZigZag -> posso andare alla FeedMassima dCurrFeed = GetMaxFeed() ; // se pulitura OneWay la feed rimane le minima // assegno a tutte le sottocurve la Feed for ( int u = 0 ; u < ( int)pCrv->GetCurveCount() ; ++ u) pCrv->SetCurveTempProp( u, FEED_DIVISOR * dCurrFeed, 0) ; // controllo se le curve di Bordo passano su una curva originale -> controllo dei lati aperti if ( m_Params.m_nSubType == POCKET_SUB_ZIGZAG && nInd >= 0) AssignFeedForOpenEdge( pCrv, vCrvOF_orig[nInd]) ; else { for ( int i = 0 ; i < ( int)vCrvOF_orig.size() ; ++ i) // se sono nel caso OneWay ho una regione con più chunk... AssignFeedForOpenEdge( pCrv, vCrvOF_orig[i]) ; } // se sono in una svuotatura a ZigZag, controllo la Feed sugli Angoli if ( m_Params.m_nSubType == POCKET_SUB_ZIGZAG) AssignFeedOnCorners( pCrv, vCrvOF_orig[nInd], m_TParams.m_dTDiam) ; return true ; } //---------------------------------------------------------------------------- bool Pocketing::AssignFeedSpiral( ICurveComposite* pCrv, const ISurfFlatRegion* pSrfRemoved_offs, const bool bIsLink, const ICRVCOMPOPOVECTOR& vLinks_done, const ICurveComposite* pCrv_orig, double dToll) { // controllo la validità della curva if ( pCrv == nullptr || ! pCrv->IsValid() || pCrv->GetCurveCount() == 0) return false ; // controllo se il Flag per assegnare la Feed è attivo if ( !m_bAssignFeed) return AssignDefaultFeed( pCrv) ; // imposto di Default la Feed minima per ogni sottocurva for ( int u = 0 ; u < ( int)pCrv->GetCurveCount() ; ++ u) pCrv->SetCurveTempProp( u, FEED_DIVISOR * GetMinFeed(), 0) ; // se non ho una superificie svuotata, allora esco ( con Feed Minima) if ( pSrfRemoved_offs == nullptr || ! pSrfRemoved_offs->IsValid() || pSrfRemoved_offs->GetChunkCount() == 0) { // controllo eventuali sovrapposizioni con lati aperti AssignFeedForOpenEdge( pCrv, pCrv_orig) ; return true ; } // clono la superificie ( valida) PtrOwner pSrf_Removed_offs_clone( CloneSurfFlatRegion( pSrfRemoved_offs)) ; if ( IsNull( pSrf_Removed_offs_clone) || ! pSrf_Removed_offs_clone->IsValid() || pSrf_Removed_offs_clone->GetChunkCount() == 0) return true ; // esco ( sempre con Feed Minima) // restringo la superificie in maniera appropriata if ( bIsLink) { // se curva di Link if ( ! pSrf_Removed_offs_clone->Offset( - m_TParams.m_dDiam / 2 + 1500 * EPS_SMALL, ICurve::OFF_CHAMFER) || ! pSrf_Removed_offs_clone->IsValid() || pSrf_Removed_offs_clone->GetChunkCount() == 0) return true ; // esco ( sempre con Feed Minima) } else if ( m_TParams.m_dDiam / 2 < GetSideStep()) { // se curva di Offset e raggio utensile < Side step if ( ! pSrf_Removed_offs_clone->Offset( GetSideStep() - m_TParams.m_dDiam / 2, ICurve::OFF_CHAMFER) || ! pSrf_Removed_offs_clone->IsValid() || pSrf_Removed_offs_clone->GetChunkCount() == 0) return true ; // esco ( sempre con Feed Minima) } // classifico le parti interne alla superificie creata solo dagli Offset CRVCVECTOR ccClass ; if ( ! pSrf_Removed_offs_clone->GetCurveClassification( *pCrv, EPS_SMALL, ccClass)) return true ; // esco ( sempre con Feed Minima) // creo la nuova curva con le Feed regolate PtrOwner pCrv_new( CreateCurveComposite()) ; if ( IsNull( pCrv_new)) return false ; for ( int i = 0 ; i < ( int)ccClass.size() ; ++ i) { double dCurrFeed = GetMinFeed() ; PtrOwner PCrv_sez( GetCurveComposite( pCrv->CopyParamRange( ccClass[i].dParS, ccClass[i].dParE))) ; if ( IsNull( PCrv_sez)) continue ; if ( ccClass[i].nClass == CRVC_IN) dCurrFeed = GetMaxFeed() ; for ( int u = 0 ; u < PCrv_sez->GetCurveCount() ; ++ u) PCrv_sez->SetCurveTempProp( u, FEED_DIVISOR * dCurrFeed, 0) ; pCrv_new->AddCurve( Release( PCrv_sez)) ; } pCrv->Clear() ; pCrv->AddCurve( Release( pCrv_new)) ; // controllo eventuali suvrapposizioni tra la curva attuale e i Link in precedenza percorsi for ( int l = 0 ; l < ( int)vLinks_done.size() ; ++ l) { IntersCurveCurve intCC( *pCrv, *vLinks_done[l]) ; for ( int i = 0 ; i < intCC.GetIntersCount() ; ++ i) { IntCrvCrvInfo aInfo ; if ( ! intCC.GetIntCrvCrvInfo( i, aInfo) || ! aInfo.bOverlap || AreSamePointApprox( aInfo.IciA[0].ptI, aInfo.IciA[1].ptI)) continue ; PtrOwner pCrv_before( CloneCurveComposite( pCrv)) ; pCrv_before->TrimEndAtParam( aInfo.IciA[0].dU) ; PtrOwner pCrv_after( CloneCurveComposite( pCrv)) ; pCrv_after->TrimStartAtParam( aInfo.IciA[1].dU) ; PtrOwner pCrv_overlap( GetCurveComposite( pCrv->CopyParamRange( aInfo.IciA[0].dU, aInfo.IciA[1].dU))) ; for ( int u = 0 ; u < pCrv_overlap->GetCurveCount() ; ++ u) pCrv_overlap->SetCurveTempProp( u, FEED_DIVISOR * GetMaxFeed(), 0) ; pCrv->Clear() ; pCrv->AddCurve( Release( pCrv_before)) ; pCrv->AddCurve( Release( pCrv_overlap)) ; pCrv->AddCurve( Release( pCrv_after)) ; } } if ( ! bIsLink) { // NEL CASO DI OFFSET // creo un intervallo con tutte le Feed Minime Intervals IntMinFeed ; for ( int u = 0 ; u < pCrv->GetCurveCount() ; ++ u) { int nProp ; pCrv->GetCurveTempProp( u, nProp, 0) ; if ( abs ( nProp - int( FEED_DIVISOR * GetMinFeed()) < 5 * EPS_SMALL)) IntMinFeed.Add( u, u + 1) ; } double dParS = EPS_SMALL ; double dParE = EPS_SMALL ; // a questo intervallo tolgo tutti i sottotratti di lunghezza inferiore alla tolleranza richiesta Intervals IntMinFeed_noSmall ; bool bFound = IntMinFeed.GetFirst( dParS, dParE) ; while ( bFound) { PtrOwner pCrv_Crv( pCrv->CopyParamRange( dParS, dParE)) ; double dLen = EPS_SMALL ; pCrv_Crv->GetLength( dLen) ; if ( dLen > dToll + 5 * EPS_SMALL) IntMinFeed_noSmall.Add( dParS, dParE) ; bFound = IntMinFeed.GetNext( dParS, dParE) ; } for ( int u = 0 ; u < pCrv->GetCurveCount() ; ++ u) { if ( IntMinFeed_noSmall.IsInside( u + 0.5)) pCrv->SetCurveTempProp( u, FEED_DIVISOR * GetMinFeed(), 0) ; else pCrv->SetCurveTempProp( u, FEED_DIVISOR * GetMaxFeed(), 0) ; } } else { // NEL CASO DI LINK // le curve con lunghezza < dToll vanno modificate for ( int u = 0 ; u < pCrv->GetCurveCount() ; ++ u) { double dLen = EPS_SMALL ; pCrv->GetCurve( u)->GetLength( dLen) ; if ( dLen < dToll + 5 * EPS_SMALL) { PtrOwner pCrvCompo( CloneCurveComposite( pCrv)) ; pCrvCompo->TrimStartAtParam( u) ; pCrvCompo->TrimEndAtLen( dLen + m_TParams.m_dDiam) ; if ( pCrvCompo->IsValid()) { bool bFound = false ; for ( int uu = 1 ; uu < pCrvCompo->GetCurveCount() ; ++ uu) { double dLenH = EPS_SMALL ; pCrvCompo->GetCurve( uu)->GetLength( dLenH) ; if ( dLenH < dToll + 5 * EPS_SMALL) continue ; // cerco tra le curve successive vicine se ne trovo una con Feed Minima int nProp ; pCrvCompo->GetCurveTempProp( uu, nProp, 0) ; if ( abs ( nProp - int( FEED_DIVISOR * GetMinFeed()) < 5 * EPS_SMALL)) { pCrv->SetCurveTempProp( u, FEED_DIVISOR * GetMinFeed(), 0) ; bFound = true ; break ; } } if ( ! bFound && u != 0) { // arrivato qui, so che successivamente non ho curve con Feed Minima vicine int nProp ; pCrv->GetCurveTempProp( u - 1, nProp, 0) ; if ( abs ( nProp - int( FEED_DIVISOR * GetMaxFeed()) < 5 * EPS_SMALL)) // se anche la precedente ha Feed Massima -> la curva u-esima è piccola ed Isolata pCrv->SetCurveTempProp( u, nProp, 0) ; } } else pCrv->SetCurveTempProp( u, FEED_DIVISOR * GetMinFeed(), 0) ; } } } // controllo eventuali sovrapposizioni con lati aperti AssignFeedForOpenEdge( pCrv, pCrv_orig) ; return true ; } //---------------------------------------------------------------------------- bool Pocketing::AssignFeedForReturnPath( ICurveComposite* pCrv) { // controllo curva corrente if ( pCrv == nullptr || !pCrv->IsValid() || pCrv->GetCurveCount() == 0) return false ; // controllo se il Flag per assegnare la Feed è attivo if ( !m_bAssignFeed) return AssignDefaultFeed( pCrv) ; if ( pCrv == nullptr || ! pCrv->IsValid() || pCrv->GetCurveCount() == 0) return false ; for ( int u = 0 ; u < ( int)pCrv->GetCurveCount() ; ++ u) pCrv->SetCurveTempProp( u, FEED_DIVISOR * GetMaxFeed(), 0) ; return true ; } //---------------------------------------------------------------------------- bool Pocketing::AssignFeedCrvOnUnclearedRegions( ICurveComposite* pCrv) { // controllo validità della curva if ( pCrv == nullptr || !pCrv->IsValid() || pCrv->GetCurveCount() == 0) return false ; // controllo se il Flag per assegnare la Feed è attivo if ( !m_bAssignFeed) return AssignDefaultFeed( pCrv) ; if ( pCrv == nullptr || ! pCrv->IsValid() || pCrv->GetCurveCount() == 0) return false ; for ( int u = 0 ; u < ( int)pCrv->GetCurveCount() ; ++ u) pCrv->SetCurveTempProp( u, FEED_DIVISOR * GetMinFeed(), 0) ; return true ; } //---------------------------------------------------------------------------- bool Pocketing::AssignDefaultFeed( ICurveComposite* pCrv) { if ( pCrv == nullptr || !pCrv->IsValid() || pCrv->GetCurveCount() == 0) return false ; for ( int u = 0 ; u < pCrv->GetCurveCount() ; ++ u) pCrv->SetCurveTempProp( u, FEED_DIVISOR * GetMaxFeed(), 0) ; return true ; } bool Pocketing::DrawColoredCrvForFeedTest( ICurve* pCurve, double dFeed) { return true ; if ( abs( dFeed - GetMinFeed()) < EPS_SMALL) { int rosso = m_pGeomDB->AddGeoObj(GDB_ID_NULL, GDB_ID_ROOT, pCurve->Clone()) ; m_pGeomDB->SetMaterial( rosso, RED) ; m_pGeomDB->SetStatus( rosso, ( m_Params.m_nSubType == POCKET_SUB_SPIRALIN || m_Params.m_nSubType == POCKET_SUB_SPIRALIN) ? GDB_ST_OFF : GDB_ST_ON) ; } else if ( abs( dFeed - GetMaxFeed()) < EPS_SMALL) { int verde = m_pGeomDB->AddGeoObj(GDB_ID_NULL, GDB_ID_ROOT, pCurve->Clone()) ; m_pGeomDB->SetMaterial( verde, GREEN) ; m_pGeomDB->SetStatus( verde, ( m_Params.m_nSubType == POCKET_SUB_SPIRALIN || m_Params.m_nSubType == POCKET_SUB_SPIRALIN) ? GDB_ST_OFF : GDB_ST_ON) ; } else { int giallo = m_pGeomDB->AddGeoObj(GDB_ID_NULL, GDB_ID_ROOT, pCurve->Clone()) ; m_pGeomDB->SetMaterial( giallo, YELLOW) ; m_pGeomDB->SetStatus( giallo, ( m_Params.m_nSubType == POCKET_SUB_SPIRALIN || m_Params.m_nSubType == POCKET_SUB_SPIRALIN) ? GDB_ST_OFF : GDB_ST_ON) ; } return true ; } //---------------------------------------------------------------------------- bool Pocketing::GetNewSrfByAnotherPocketing( ISurfFlatRegion* pSrf, ISurfFlatRegion* pSrf_noOpenEdge, const Vector3d& vtTrasl) { // controllo dei parametri if ( pSrf == nullptr || ! pSrf->IsValid() || pSrf->GetChunkCount() == 0 || m_dDiam_Prec < 0) return false ; // se e i parametri ed il tool permettono la nuova lavorazione... if ( m_TParams.m_dDiam / 2 + GetOffsR() < m_dDiam_Prec / 2 + m_dOffsetR_Prec) { // clono la superificie ricavata in precedenza ( senza estensione con lati aperti) PtrOwner pSrf_Sub( CloneSurfFlatRegion( pSrf)) ; if ( IsNull( pSrf_Sub) || ! pSrf_Sub->IsValid()) return false ; int Y = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSrf_Sub->Clone()) ; m_pGeomDB->SetMaterial( Y, YELLOW) ; // effettuo un Offset verso l'interno ( curve esterne che percorre il centro del Tool) if ( pSrf_Sub->Offset( - m_dDiam_Prec / 2 - m_dOffsetR_Prec - 5 * EPS_SMALL, ICurve::OFF_FILLET)) { // se la superificie sparisce o trovo un chunk non valido, la risvuoto tutta per sicurezza... if ( ! pSrf_Sub->IsValid() || pSrf_Sub->GetChunkCount() == 0) return true ; // effettuo un Offset del raggio del tool precedente per ricavare la regione svuotata in precedenza PtrOwner pSrfHelp( CloneSurfFlatRegion( pSrf_Sub)) ; if ( ! pSrf_Sub->Offset( m_dDiam_Prec / 2 + 20 * EPS_SMALL, ICurve::OFF_FILLET)) { //int nbadOffs = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSrfHelp->Clone()) ; //m_pGeomDB->Save( nbadOffs, "C:\\Users\\riccardo.elitropi\\Desktop\\Err_offs" + ToString( nbadOffs) + "__m" + ToString( m_dDiam_Prec / 2 + 20 * EPS_SMALL) + ".nge") ; return false ; } int r = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSrf_Sub->Clone()) ; m_pGeomDB->SetMaterial( r, RED) ; int v = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSrf_noOpenEdge->Clone()) ; m_pGeomDB->SetMaterial( v, GREEN) ; PtrOwner pSrf_clone( CloneSurfFlatRegion( pSrf_noOpenEdge)) ; if ( pSrf_clone->Subtract( *pSrf_Sub)) { if ( ! pSrf_clone->IsValid() || pSrf_clone->GetChunkCount() == 0) { pSrf->Clear() ; return true ; } int l = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pSrf_clone->Clone()) ; m_pGeomDB->SetMaterial( l, LIME) ; // ricavo la curva esterna originale PtrOwner pCrvExt_orig( GetCurveComposite( pSrf->GetLoop( 0, 0))) ; // superificie finale da restituire ... PtrOwner pSrf_Final( CreateSurfFlatRegion()) ; if ( IsNull( pSrf_Final)) return false ; // tolgo dalla superificie le parti al di fuori del grezzo bool bIsChanged ; // per ogni chunk della superificie ricavata.... for ( int c = 0 ; c < pSrf_clone->GetChunkCount() ; ++ c) { // singolo chunk della superificie modificato per i lati aperti... PtrOwner pChunk_WithOpenEdges( CreateSurfFlatRegion()) ; if ( IsNull( pChunk_WithOpenEdges)) return false ; int nStat = 0 ; PtrOwner pCrvExt( GetCurveComposite( pSrf_clone->GetLoop( c, 0))) ; // setto tutte le sottocurve aperte for ( int u = 0 ; u < pCrvExt->GetCurveCount() ; ++ u) { pCrvExt->SetCurveTempProp( u, 1, 0) ; const ICurve* pCrv_u = pCrvExt->GetCurve( u) ; for ( int cu = 0 ; cu < pSrf->GetChunkCount() ; ++ cu) { for ( int l = 1 ; l < pSrf->GetLoopCount( cu) ; ++ l) { PtrOwner pCrvCompo_isl( GetCurveComposite( pSrf->GetLoop( cu, l))) ; // se overlap con un' isola -> curva chiusa if ( CheckSimpleOverlap( pCrv_u, pCrvCompo_isl, nStat) && nStat == 1) pCrvExt->SetCurveTempProp( u, 0, 0) ; } } for ( int cu = 0 ; cu < pSrf_noOpenEdge->GetChunkCount() ; ++ cu) { for ( int l = 0 ; l < pSrf_noOpenEdge->GetLoopCount( cu) ; ++ l) { // se overlap con curva della superficie originale -> copio la rispettiva temp prop PtrOwner pCrvCompo( GetCurveComposite( pSrf_noOpenEdge->GetLoop( cu, l))) ; SetTmpPropByOverlap( pCrvExt, u, pCrvCompo, nStat) ; } } } bool bSomeOpen = false ; int nProp0 = -1 ; for ( int u = 0 ; u < pCrvExt->GetCurveCount() && !bSomeOpen ; ++ u) { if ( pCrvExt->GetCurveTempProp( u, nProp0, 0) && nProp0 == 1) bSomeOpen = true ; } ICRVCOMPOPOVECTOR vCrvIsl ; for ( int l = 1 ; l < pSrf_clone->GetLoopCount( c) ; ++ l) vCrvIsl.emplace_back( GetCurveComposite( pSrf_clone->GetLoop( c, l))) ; if ( bSomeOpen) { // se trovo dei lati aperti if ( ! AdjustContourWithOpenEdges( pCrvExt, vCrvIsl, m_TParams.m_dDiam, GetOffsR(), GetSideStep(), vtTrasl)) { m_pMchMgr->SetLastError( 2430, "Error in Pocketing : adjust open edges failed") ; return false ; } } // Chunk modificato con i lati aperti pChunk_WithOpenEdges->AddExtLoop( Release( pCrvExt)) ; // aggiungo la curva esterna for ( int i = 1 ; i < int( vCrvIsl.size()) ; ++ i) pChunk_WithOpenEdges->AddIntLoop( Release( vCrvIsl[i])) ; // aggiungo le eventuali isole // aggiungo questo Chunk alla superificie finale ( potrebbero essere sovrapposti per alcune parti...) if ( pSrf_Final->GetChunkCount() == 0) pSrf_Final.Set( pChunk_WithOpenEdges) ; else pSrf_Final->Add( *pChunk_WithOpenEdges) ; } pSrf->Clear() ; pSrf->CopyFrom( pSrf_Final) ; } } } return true ; } //---------------------------------------------------------------------------- bool Pocketing::GetDynamicClearedRegion( ISurfFlatRegion* pSrfPrec, const ICurveComposite* pCrv) { for ( int i = 0 ; i < pCrv->GetCurveCount() ; ++ i) { const ICurve* pCrvPath = pCrv->GetCurve( i) ; if ( pCrvPath != nullptr) { PtrOwner pCrv_i( pCrvPath->Clone()) ; if ( IsNull( pCrv_i)) return false ; PtrOwner PSrfRemoved( GetSurfFlatRegionFromFatCurve( Release( pCrv_i), m_TParams.m_dDiam / 2, false, false)) ; if ( pSrfPrec->GetChunkCount() == 0) pSrfPrec->CopyFrom( PSrfRemoved) ; else pSrfPrec->Add( *PSrfRemoved) ; } } return true ; } //---------------------------------------------------------------------------- bool Pocketing::GetSfrByStm( const ISurfTriMesh* pStm, ISurfFlatRegion* pSfr, const Plane3d plPock, const Vector3d& vtExtr, const double dThick, double dToll) { // controllo validità dei parametri if ( pStm == nullptr || ! pStm->IsValid() || ! plPock.IsValid()) return false ; // creo un Frame per il sistema di Riferimento Locale Frame3d frPock ; frPock.Set( plPock.GetPoint(), plPock.GetVersN()) ; if ( ! frPock.IsValid()) return false ; // creo la FlatRegion da resitutiure SurfFlatRegionByContours SrfChunkDef ; // recupero i Loop della TriMesh salvandoli in un vettore di PolyLine POLYLINEVECTOR vPl ; pStm->GetLoops( vPl) ; // per ogni PolyLine... for ( int i = 0 ; i < ( int)vPl.size() ; ++ i) { // recupero la curva composita PolyLine PL = vPl[i] ; PtrOwner pCrv( CreateCurveComposite()) ; pCrv->FromPolyLine( PL) ; int yy = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCrv->Clone()) ; m_pGeomDB->SetMaterial( yy, GREEN) ; // essendo una curva derivante da un'intersezione di Trimesh ho una composita derivante da una polyLine, // devo recuperare gli archi PolyArc PA ; pCrv->ToLoc( frPock) ; pCrv->ApproxWithArcsEx( 5 * EPS_SMALL, ANG_TOL_STD_DEG, LIN_FEA_STD, PA) ; // 500 * EPS_SMALL pCrv->Clear() ; pCrv->FromPolyArc( PA) ; pCrv->ToGlob( frPock) ; pCrv->SetExtrusion( vtExtr) ; pCrv->SetThickness( dThick) ; int yyy = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCrv->Clone()) ; m_pGeomDB->SetMaterial( yyy, BLACK) ; // la converto in una semplice cruva per proiettarla su piano della svuotatura // dato che le curve sono prese da una trimesh, le proietto sul piano per sicurezza e per evitare approssimazioni double dS, dE ; pCrv->GetDomain( dS, dE) ; PtrOwner pCrv_c( pCrv->CopyParamRange( dS, dE)) ; if ( IsNull( pCrv_c) || ! pCrv_c->IsValid()) return false ; PtrOwner pCrv_proj( ProjectCurveOnPlane( *pCrv_c, plPock)) ; int y = m_pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, pCrv_proj->Clone()) ; m_pGeomDB->SetMaterial( y, YELLOW) ; SrfChunkDef.AddCurve( Release( pCrv_proj)) ; // aggiungo le curve proiettate } // recupero la FlatRegion PtrOwner pSrfByCurves( SrfChunkDef.GetSurf()) ; if ( IsNull( pSrfByCurves) || pSrfByCurves->GetChunkCount() == 0) // controllo validità della FlatRegion return false ; // restituisco la FlatRegion pSfr->Clear() ; pSfr->CopyFrom( pSrfByCurves) ; return pSfr != nullptr && pSfr->IsValid() ; }