From e2e246f3f4b4077626ea0695eadf5077f67ac896 Mon Sep 17 00:00:00 2001 From: Riccardo Elitropi Date: Mon, 23 Sep 2024 11:16:08 +0200 Subject: [PATCH] EgtMachKernel : - definizione di PocketingNT. --- EgtMachKernel.vcxproj | 2 + OperationConst.h | 1 + Pocketing.cpp | 4 +- PocketingNT.cpp | 5860 +++++++++++++++++++++++++++++++++++++++++ PocketingNT.h | 197 ++ 5 files changed, 6063 insertions(+), 1 deletion(-) create mode 100644 PocketingNT.cpp create mode 100644 PocketingNT.h diff --git a/EgtMachKernel.vcxproj b/EgtMachKernel.vcxproj index 921d8b3..d087a05 100644 --- a/EgtMachKernel.vcxproj +++ b/EgtMachKernel.vcxproj @@ -275,6 +275,7 @@ copy $(TargetPath) \EgtProg\Dll64 + @@ -448,6 +449,7 @@ copy $(TargetPath) \EgtProg\Dll64 + diff --git a/OperationConst.h b/OperationConst.h index 845bdf1..d7d2d06 100644 --- a/OperationConst.h +++ b/OperationConst.h @@ -18,6 +18,7 @@ #include "/EgtDev/Include/EMkOperationConst.h" #include +#define POCKETING_NT 1 //---------------------------------------------------------------------------- static const std::string s_OpeClass[] = {"", diff --git a/Pocketing.cpp b/Pocketing.cpp index 8213114..2a1f3ef 100644 --- a/Pocketing.cpp +++ b/Pocketing.cpp @@ -89,7 +89,9 @@ static string KEY_OPEN = "OPEN" ; static int LINK_CURVE_PROP = -3 ; //---------------------------------------------------------------------------- -USEROBJ_REGISTER( GetOperationClass( OPER_POCKETING), Pocketing) ; +#if POCKETING_NT != 1 + USEROBJ_REGISTER( GetOperationClass( OPER_POCKETING), Pocketing) ; +#endif //---------------------------------------------------------------------------- const string& diff --git a/PocketingNT.cpp b/PocketingNT.cpp new file mode 100644 index 0000000..4e9659b --- /dev/null +++ b/PocketingNT.cpp @@ -0,0 +1,5860 @@ +//---------------------------------------------------------------------------- +// EgalTech 2017-2023 +//---------------------------------------------------------------------------- +// File : PocketingNT.cpp Data : 17.12.23 Versione : 2.5l3 +// 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 "PocketingNT.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/EGkPolygonElevation.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 + +using namespace std ; + +//------------------------------ Errors -------------------------------------- +// 2401 = "Error in PocketingNT : UpdateToolData failed" +// 2402 = "Error in PocketingNT : Open Contour" +// 2403 = "Error in PocketingNT : Contour Not Flat" +// 2404 = "Error in PocketingNT : Tool Not Perpendicular to Flat Area" +// 2405 = "Error in PocketingNT : Empty RawBox" +// 2406 = "Error in PocketingNT : Depth not computable" +// 2408 = "Error in PocketingNT : Entity GetElevation" +// 2409 = "Error in PocketingNT : missing aggregate from bottom" +// 2410 = "Error in PocketingNT : path too far from part sides" +// 2411 = "Error in PocketingNT : toolpath allocation failed" +// 2412 = "Error in PocketingNT : Offset not computable" +// 2413 = "Error in PocketingNT : Toolpath not computable" +// 2414 = "Error in PocketingNT : Approach not computable" +// 2415 = "Error in PocketingNT : LeadIn not computable" +// 2416 = "Error in PocketingNT : LeadOut not computable" +// 2417 = "Error in PocketingNT : Retract not computable" +// 2418 = "Error in PocketingNT : Link not computable" +// 2419 = "Error in PocketingNT : Linear Approx not computable" +// 2420 = "Error in PocketingNT : Return toolpath not computable" +// 2421 = "Error in PocketingNT : Chaining failed" +// 2422 = "Error in PocketingNT : Tool MaxMaterial too small (xxx)" +// 2423 = "Error in PocketingNT : axes values not calculable" +// 2424 = "Error in PocketingNT : outstroke xxx" +// 2425 = "Error in PocketingNT : link movements not calculable" +// 2426 = "Error in PocketingNT : link outstroke xxx" +// 2427 = "Error in PocketingNT : post apply not calculable" +// 2428 = "Error in PocketingNT : Tool loading failed" +// 2429 = "Error in PocketingNT : machining depth (xxx) bigger than MaxDepth (yyy)" +// 2430 = "Error in PocketingNT : adjust open edges failed" +// 2431 = "Error in PocketingNT : LeadIn with Mill NoTip in material" +// 2432 = "Error in PocketingNT : Mirror for Double calculation failed" +// 2451 = "Warning in PocketingNT : Skipped entity (xx)" +// 2452 = "Warning in PocketingNT : No machinable pocket" +// 2453 = "Warning in PocketingNT : Tool name changed (xx)" +// 2454 = "Warning in PocketingNT : Tool data changed (xx)" +// 2455 = "Warning in PocketingNT : skipped Path too short" +// 2456 = "Warning in PocketingNT : machining step too small (xx)" +// 2457 = "Warning in PocketingNT : machining step (xxx) bigger than MaxMaterial (yyy)" +// 2458 = "Warning in PocketingNT : machining depth (xxx) bigger than MaxMaterial (yyy)" + +//---------------------------------------------------------------------------- +static string KEY_OPEN = "OPEN" ; +static int LINK_CURVE_PROP = -3 ; + +//---------------------------------------------------------------------------- +#if POCKETING_NT == 1 + USEROBJ_REGISTER( GetOperationClass( OPER_POCKETING), PocketingNT) ; +#endif + +//---------------------------------------------------------------------------- +const string& +PocketingNT::GetClassName( void) const +{ + return USEROBJ_GETNAME( PocketingNT) ; +} + +//---------------------------------------------------------------------------- +PocketingNT* +PocketingNT::Clone( void) const +{ + // alloco oggetto + PocketingNT* pPock = new(nothrow) PocketingNT ; + // 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 +PocketingNT::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) { + string sTmp = m_Params.ToString( i) ; + if ( ! IsEmptyOrSpaces( sTmp)) + sOut += sTmp + szNewLine ; + } + for ( int i = 0 ; i < m_TParams.GetSize() ; ++ i) { + string sTmp = m_TParams.ToString( i) ; + if ( ! IsEmptyOrSpaces( sTmp)) + sOut += sTmp + szNewLine ; + } + sOut += KEY_NUM + EQUAL + ToString( m_nPockets) + szNewLine ; + sOut += KEY_STAT + EQUAL + ToString( m_nStatus) + szNewLine ; + + return true ; +} + +//---------------------------------------------------------------------------- +bool +PocketingNT::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 +PocketingNT::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 ; +} + +//---------------------------------------------------------------------------- +//---------------------------------------------------------------------------- +PocketingNT::PocketingNT( 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 +PocketingNT::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 +PocketingNT::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 +PocketingNT::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 +PocketingNT::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 +PocketingNT::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 +PocketingNT::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 PocketingNT : 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 +PocketingNT::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 PocketingNT : 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 PocketingNT : 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 PocketingNT : 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 +PocketingNT::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 PocketingNT : 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(), "PocketingNT 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 PocketingNT : Tool loading failed") ; + return false ; + } + // recupero i dati del portautensile + int nToolId = m_pMchMgr->GetCalcTool() ; + m_dTHoldBase = 0 ; + m_pGeomDB->GetInfo( nToolId, TTH_BASE, m_dTHoldBase) ; + m_dTHoldLen = 0 ; + m_pGeomDB->GetInfo( nToolId, TTH_LEN, m_dTHoldLen) ; + m_dTHoldDiam = 0 ; + m_pGeomDB->GetInfo( nToolId, TTH_DIAM, m_dTHoldDiam) ; + + // recupero gruppo per geometria di lavorazione (Cutter Location) + int nClId = m_pGeomDB->GetFirstNameInGroup( m_nOwnerId, MCH_CL) ; + // se non c'è, lo aggiungo + if ( nClId == GDB_ID_NULL) { + nClId = m_pGeomDB->AddGroup( GDB_ID_NULL, m_nOwnerId, Frame3d()) ; + if ( nClId == GDB_ID_NULL) + return false ; + m_pGeomDB->SetName( nClId, MCH_CL) ; + } + // altrimenti lo svuoto + else + m_pGeomDB->EmptyGroup( nClId) ; + + // elimino eventuale gruppo geometria simmetrica per lavorazione in doppio + int nDblId = m_pGeomDB->GetFirstNameInGroup( m_nOwnerId, MCH_DBL) ; + if ( nDblId != GDB_ID_NULL) { + m_pGeomDB->Erase( nDblId) ; + nDblId = GDB_ID_NULL ; + } + + // se necessario, eseguo concatenamento ed inserisco i percorsi sotto la geometria ausiliaria + if ( bChain && ! Chain( nAuxId)) { + m_pMchMgr->SetLastError( 2421, "Error in PocketingNT : Chaining failed") ; + return false ; + } + + // lavoro ogni singola catena + bool bOk = true ; + int nPathId = m_pGeomDB->GetFirstGroupInGroup( nAuxId) ; + while ( nPathId != GDB_ID_NULL) { + if ( ! ProcessPath( nPathId, GDB_ID_NULL, nClId)) + bOk = false ; + nPathId = m_pGeomDB->GetNextGroup( nPathId) ; + } + if ( ! bOk) + return false ; + + // assegno ingombri dei vari percorsi di lavorazione e della lavorazione nel suo complesso + CalcAndSetBBox( nClId) ; + + // eseguo aggiornamento assi macchina e collegamento con operazione precedente + if ( ! Update( bPostApply)) + return false ; + + // se lavorazione in doppio, aggiungo geometria della parte simmetrica + if ( ! CalcMirrorByDouble( nClId, m_Params.m_sUserNotes)) { + m_pMchMgr->SetLastError( 2432, "Error in PocketingNT : Mirror for Double calculation failed") ; + 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(), "PocketingNT apply done") ; + + return true ; +} + +//---------------------------------------------------------------------------- +bool +PocketingNT::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 PocketingNT : No machinable pocket") ; + return true ; + } + + // elimino le entità CLIMB, RISE e HOME della lavorazione, potrebbero falsare i calcoli degli assi (in ogni casi vengono riaggiunte dopo) + RemoveClimbRiseHome() ; + + // imposto eventuale asse bloccato da lavorazione + SetBlockedRotAxis( m_Params.m_sBlockedAxis) ; + + // calcolo gli assi macchina + string sHint = ExtractHint( m_Params.m_sUserNotes) ; + if ( ! m_Params.m_sInitAngs.empty()) + sHint = m_Params.m_sInitAngs ; + if ( ! CalculateAxesValues( sHint)) { + string sInfo = m_pMchMgr->GetOutstrokeInfo() ; + if ( sInfo.empty()) + m_pMchMgr->SetLastError( 2423, "Error in PocketingNT : axes values not calculable") ; + else + m_pMchMgr->SetLastError( 2424, "Error in PocketingNT : 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 PocketingNT : link movements not calculable") ; + else + m_pMchMgr->SetLastError( 2426, "Error in PocketingNT : 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 PocketingNT : post apply not calculable") ; + return false ; + } + + return true ; +} + +//---------------------------------------------------------------------------- +bool +PocketingNT::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 +PocketingNT::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 +PocketingNT::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 +PocketingNT::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& +PocketingNT::GetToolData( void) const +{ + return m_TParams ; +} + +//---------------------------------------------------------------------------- +bool +PocketingNT::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 PocketingNT : 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 PocketingNT : 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 +PocketingNT::GetGeometry( SELVECTOR& vIds) const +{ + // restituisco l'elenco delle entità + vIds = m_vId ; + return true ; +} + +//---------------------------------------------------------------------------- +bool +PocketingNT::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 +PocketingNT::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 ; + // la duplico + pCurve.Set( pOriCurve->Clone()) ; + // recupero eventuali informazioni per lati aperti + SetCurveAllTempProp( Id.nId, false, pCurve) ; + // se estrusione mancante, imposto default + Vector3d vtExtr ; + if ( ! pCurve->GetExtrusion( vtExtr) || vtExtr.IsSmall()) + pCurve->SetExtrusion( Z_AX) ; + } + // altrimenti sottocurva di composita + else { + // recupero la composita + const ICurveComposite* pCompo = GetCurveComposite( pGObj) ; + if ( pCompo == nullptr) + return false ; + // recupero la curva semplice + const ICurve* pOriCurve = ::GetCurve( pCompo->GetCurve( Id.nSub)) ; + if ( pOriCurve == nullptr) + return false ; + // la duplico + pCurve.Set( pOriCurve->Clone()) ; + // reset proprietà temporanee + ResetCurveAllTempProp( pCurve) ; + // recupero estrusione e spessore + Vector3d vtExtr ; + if ( ! pCompo->GetExtrusion( vtExtr) || vtExtr.IsSmall()) + vtExtr = Z_AX ; + pCurve->SetExtrusion( vtExtr) ; + double dThick ; + if ( pCompo->GetThickness( dThick)) + pCurve->SetThickness( dThick) ; + } + if ( IsNull( pCurve)) + return false ; + // la porto in globale + pCurve->ToGlob( frGlob) ; + // la restituisco + lstPC.emplace_back( Release( pCurve)) ; + return true ; + } + // se altrimenti testo + else if ( pGObj->GetType() == EXT_TEXT) { + // recupero il testo + const IExtText* pText = ::GetExtText( pGObj) ; + if ( pText == nullptr) + return false ; + // recupero l'outline del testo + if ( ! pText->GetOutline( lstPC)) + return false ; + // reset proprietà temporanee + for ( auto pCrv : lstPC) + ResetCurveAllTempProp( pCrv) ; + // porto le curve in globale + for ( auto pCrv : lstPC) + pCrv->ToGlob( frGlob) ; + // ritorno + return true ; + } + // se altrimenti superficie + else if ( pGObj->GetType() == SRF_TRIMESH) { + // recupero la trimesh + const ISurfTriMesh* pSurf = ::GetSurfTriMesh( pGObj) ; + if ( pSurf == nullptr) + return false ; + // recupero l'indice della faccia + int nFacet = ( ( Id.nSub == SEL_SUB_ALL) ? 0 : Id.nSub) ; + // recupero i contorni della faccia + POLYLINEVECTOR vPL ; + pSurf->GetFacetLoops( nFacet, vPL) ; + if ( vPL.empty()) + return false ; + // creo la curva a partire da quello esterno + PtrOwner pCrvCompo( CreateCurveComposite()) ; + pCrvCompo->FromPolyLine( vPL[0]) ; + if ( ! pCrvCompo->IsValid()) + return false ; + // reset proprietà temporanee + ResetCurveAllTempProp( pCrvCompo) ; + // determino eventuali lati aperti e aggiorno proprietà del contorno + int nInd = 0 ; + double dPar ; + bool bFound = vPL[0].GetFirstU( dPar, true) ; + while ( bFound) { + // recupero il flag + int nFlag = int( dPar) ; + // se non c'è nulla di adiacente, lato aperto + if ( nFlag == SVT_NULL) + pCrvCompo->SetCurveTempProp( nInd, 1) ; + // altrimenti verifico se la faccia adiacente forma diedro convesso o concavo + else { + bool bAdjac ; + Point3d ptP1, ptP2 ; + double dAng ; + if ( ! pSurf->GetFacetsContact( nFacet, nFlag, bAdjac, ptP1, ptP2, dAng)) + dAng = - ANG_RIGHT ; + if ( dAng > - EPS_ANG_SMALL) + pCrvCompo->SetCurveTempProp( nInd, 1) ; + } + // passo al successivo + ++ nInd ; + bFound = vPL[0].GetNextU( dPar, true) ; + } + // recupero la normale esterna della faccia + Vector3d vtN ; + if ( ! pSurf->GetFacetNormal( nFacet, vtN)) + return false ; + // assegno l'estrusione dalla normale alla faccia + pCrvCompo->SetExtrusion( vtN) ; + // unisco le eventuali parti allineate + pCrvCompo->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL) ; + // la porto in globale + pCrvCompo->ToGlob( frGlob) ; + // sistemazioni varie + AdjustCurveFromSurf( pCrvCompo, TOOL_ORTHO, FACE_CONT, V_NULL, 0) ; + // 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 ; + if ( ! pCrvCompo.Set( ConvertCurveToComposite( pReg->GetLoop( nC, nL)))) + return false ; + // reset proprietà temporanee + ResetCurveAllTempProp( pCrvCompo) ; + // assegno l'estrusione dalla normale alla regione + pCrvCompo->SetExtrusion( vtN) ; + // unisco le eventuali parti allineate + pCrvCompo->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL) ; + // la porto in globale + pCrvCompo->ToGlob( frGlob) ; + // sistemazioni varie + AdjustCurveFromSurf( pCrvCompo, TOOL_ORTHO, FACE_CONT, V_NULL, 0) ; + // la restituisco + lstPC.emplace_back( Release( pCrvCompo)) ; + } + } + return true ; + } + // altrimenti errore + else + return false ; +} + +//---------------------------------------------------------------------------- +bool +PocketingNT::SetCurveAllTempProp( int nCrvId, bool bForcedClose, ICurve* pCurve, bool* pbSomeOpen) +{ + if ( pCurve == nullptr) + return false ; + if ( pbSomeOpen != nullptr) + *pbSomeOpen = false ; + // reset proprietà temporanee + ResetCurveAllTempProp( pCurve) ; + // se forzato chiuso o non presenti info per lati aperti, esco + if ( bForcedClose || ! 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) { + if ( pCC->SetCurveTempProp( j, 1)) { + if ( pbSomeOpen != nullptr) + *pbSomeOpen = true ; + } + } + } + // altrimenti + else { + if ( ! vOpen.empty() && vOpen[0] == 0) { + pCurve->SetTempProp( 1) ; + if ( pbSomeOpen != nullptr) + *pbSomeOpen = true ; + } + } + return true ; +} + +//---------------------------------------------------------------------------- +bool +PocketingNT::ResetCurveAllTempProp( ICurve* pCurve) +{ + if ( pCurve == nullptr) + return false ; + pCurve->SetTempProp( 0) ; + ICurveComposite* pCC = GetCurveComposite( pCurve) ; + if ( pCC != nullptr) { + for ( int i = 0 ; i < pCC->GetCurveCount() ; ++ i) + pCC->SetCurveTempProp( i, 0) ; + } + return true ; +} + +//---------------------------------------------------------------------------- +bool +PocketingNT::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 PocketingNT : Skipped entity " + ToString( Id) ; + m_pMchMgr->SetWarning( 2451, sInfo) ; + } + for ( auto pCrv : lstPC) { + vpCrvs.emplace_back( pCrv) ; + vInds.emplace_back( Id) ; + } + } + // preparo i dati per il concatenamento + bool bFirst = true ; + Point3d ptNear = ORIG ; + double dToler = 10 * EPS_SMALL ; + ChainCurves chainC ; + chainC.Init( true, dToler, int( vpCrvs.size())) ; + for ( size_t i = 0 ; i < vpCrvs.size() ; ++ i) { + // recupero la curva e il suo riferimento + ICurve* pCrv = vpCrvs[i] ; + if ( pCrv == nullptr) + continue ; + // recupero i dati della curva necessari al concatenamento e li assegno + Point3d ptStart, ptEnd ; + Vector3d vtStart, vtEnd ; + if ( ! pCrv->GetStartPoint( ptStart) || ! pCrv->GetStartDir( vtStart) || + ! pCrv->GetEndPoint( ptEnd) || ! pCrv->GetEndDir( vtEnd)) + return false ; + if ( ! chainC.AddCurve( int( i + 1), ptStart, vtStart, ptEnd, vtEnd)) + return false ; + // se prima curva, assegno inizio della ricerca + if ( bFirst) { + ptNear = ptStart + 10 * EPS_SMALL * vtStart ; + bFirst = false ; + } + } + // recupero i percorsi concatenati + int nCount = 0 ; + INTVECTOR vnId2 ; + while ( chainC.GetChainFromNear( ptNear, false, vnId2)) { + // creo una curva composita + PtrOwner pCrvCompo( CreateCurveComposite()) ; + if ( IsNull( pCrvCompo)) + return false ; + // estrusione e spessore + Vector3d vtExtr = Z_AX ; + double dThick = 0 ; + // vettore Id originali + SELVECTOR vId2 ; + vId2.reserve( vnId2.size()) ; + // recupero le curve semplici e le inserisco nella curva composita + for ( size_t i = 0 ; i < vnId2.size() ; ++ i) { + int nId = abs( vnId2[i]) - 1 ; + bool bInvert = ( vnId2[i] < 0) ; + vId2.emplace_back( vInds[nId]) ; + // recupero la curva + ICurve* pCrv = vpCrvs[nId] ; + // se necessario, la inverto + if ( bInvert) + pCrv->Invert() ; + // recupero eventuali estrusione e spessore + Vector3d vtTemp ; + if ( pCrv->GetExtrusion( vtTemp)) { + vtExtr = vtTemp ; + double dTemp ; + if ( pCrv->GetThickness( dTemp) && abs( dTemp) > abs( dThick)) + dThick = dTemp ; + } + // la aggiungo alla curva composta + if ( ! pCrvCompo->AddCurve( ::Release( vpCrvs[nId]), true, dToler)) + return false ; + } + // se non sono state inserite curve, vado oltre + if ( pCrvCompo->GetCurveCount() == 0) + continue ; + // imposto estrusione e spessore + pCrvCompo->SetExtrusion( vtExtr) ; + pCrvCompo->SetThickness( dThick) ; + // aggiorno il nuovo punto vicino + pCrvCompo->GetEndPoint( ptNear) ; + // se utile, approssimo con archi + if ( ! ApproxWithArcsIfUseful( pCrvCompo, true)) + return false ; + // recupero eventuali lati aperti + INTVECTOR vOpen ; + for ( int i = 0 ; i < int( pCrvCompo->GetCurveCount()) ; ++ i) { + int nProp = 0 ; + if ( pCrvCompo->GetCurveTempProp( i, nProp) && nProp == 1) + vOpen.emplace_back( i) ; + } + // creo nuovo gruppo + int nPathId = m_pGeomDB->AddGroup( GDB_ID_NULL, nGrpDestId, Frame3d()) ; + if ( nPathId == GDB_ID_NULL) + return false ; + m_pGeomDB->SetName( nPathId, MCH_PATH + ToString( ++ nCount)) ; + 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 +PocketingNT::ProcessPath( int nPathId, int nPvId, int nClId) +{ + // recupero gruppo per geometria temporanea + const string GRP_TEMP = "Temp" ; + int nTempId = m_pGeomDB->GetFirstNameInGroup( m_nOwnerId, GRP_TEMP) ; + // se non c'è, lo aggiungo + if ( nTempId == GDB_ID_NULL) { + nTempId = m_pGeomDB->AddGroup( GDB_ID_NULL, m_nOwnerId, Frame3d()) ; + if ( nTempId == GDB_ID_NULL) + return false ; + m_pGeomDB->SetName( nTempId, GRP_TEMP) ; + } + // altrimenti lo svuoto + else + m_pGeomDB->EmptyGroup( nTempId) ; + // in ogni caso lo dichiaro temporaneo e non visibile + m_pGeomDB->SetLevel( nTempId, GDB_LV_TEMP) ; + m_pGeomDB->SetStatus( nTempId, GDB_ST_OFF) ; + + // verifico sia una curva chiusa (deve delimitare l'area da svuotare) + int nCrvId = m_pGeomDB->GetFirstInGroup( nPathId) ; + if ( m_pGeomDB->GetGeoType( nCrvId) != CRV_COMPO) + return false ; + ICurve* pCrv = ::GetCurve( m_pGeomDB->GetGeoObj( nCrvId)) ; + if ( pCrv == nullptr || ! pCrv->IsClosed()) { + m_pMchMgr->SetLastError( 2402, "Error in PocketingNT : Open Contour") ; + return false ; + } + + // copio la curva composita da elaborare + int nCopyId = m_pGeomDB->CopyGlob( nCrvId, GDB_ID_NULL, nTempId) ; + if ( nCopyId == GDB_ID_NULL) + return false ; + ICurveComposite* pCompo = GetCurveComposite( m_pGeomDB->GetGeoObj( nCopyId)) ; + + // annullo i flag di tratto aperto + for ( int i = 0 ; i < int( pCompo->GetCurveCount()) ; ++ i) + pCompo->SetCurveTempProp( i, 0) ; + + // verifico se vanno gestiti i lati aperti + bool bSomeOpen ; + SetCurveAllTempProp( nCrvId, GetForcedClosed(), pCompo, &bSomeOpen) ; + + // recupero estrusione e spessore + Vector3d vtExtr = Z_AX ; + pCompo->GetExtrusion( vtExtr) ; + double dThick ; + pCompo->GetThickness( dThick) ; + + // eventuale inversione direzione utensile + if ( m_Params.m_bToolInvert) { + vtExtr.Invert() ; + pCompo->SetExtrusion( vtExtr) ; + dThick = - dThick ; + pCompo->SetThickness( dThick) ; + } + + // verifico sia piana e se necessario la appiattisco + PtrOwner pFlatCrv( FlattenCurve( *pCompo, 50 * EPS_SMALL, 50 * EPS_ANG_SMALL, FLTCRV_USE_EXTR)) ; + if ( IsNull( pFlatCrv)) { + Plane3d plPlane ; + if ( ! pCompo->IsFlat( plPlane, true, 50 * EPS_SMALL)) + m_pMchMgr->SetLastError( 2403, "Error in PocketingNT : Contour Not Flat") ; + else + m_pMchMgr->SetLastError( 2404, "Error in PocketingNT : Tool Not Perpendicular to Flat Area") ; + return false ; + } + pFlatCrv->GetExtrusion( vtExtr) ; + pCompo->Clear() ; + pCompo->AddCurve( Release( pFlatCrv)) ; + pCompo->SetExtrusion( vtExtr) ; + pCompo->SetThickness( dThick) ; + // sistemo senso antiorario visto dalla direzione di estrusione + Plane3d plPlane ; double dArea ; + pCompo->GetArea( plPlane, dArea) ; + if ( plPlane.GetVersN() * vtExtr * dArea < 0) + pCompo->Invert() ; + + // unisco le parti allineate (tranne inizio-fine se chiusa) + if ( ! pCompo->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL, false, true)) + return false ; + + // se ci sono lati aperti + bool bMidOpen = false ; + Point3d ptMidOpen ; + Vector3d vtMidOut ; + if ( bSomeOpen) { + // ricerca del punto medio del lato aperto più lungo + bMidOpen = GetMidOfLongestOpenSide( pCompo, ptMidOpen, vtMidOut) ; + // sistemazioni per eventuali lati aperti + if ( ! AdjustContourWithOpenEdges( pCompo)) { + m_pMchMgr->SetLastError( 2430, "Error in PocketingNT : adjust open edges failed") ; + return false ; + } + } + + // sposto l'inizio a metà del tratto più lungo ( o aperto più lungo) + if ( bMidOpen) { + const double LEN_OUT = 5 ; + double dPar ; int nFlag ; + bMidOpen = ( DistPointCurve( ptMidOpen + LEN_OUT * vtMidOut, *pCompo).GetParamAtMinDistPoint( 0, dPar, nFlag) && pCompo->ChangeStartPoint( dPar)) ; + } + if ( ! bMidOpen) + AdjustContourStart( pCompo) ; + + // recupero il punto di inizio (per poi salvarlo nelle info di CL path) + Point3d ptStart ; pCompo->GetStartPoint( ptStart) ; + + // recupero il box del grezzo in globale + BBox3d b3Raw ; + if ( ! GetRawGlobBox( m_nPhase, nPathId, 0.5 * m_TParams.m_dTDiam, b3Raw) || b3Raw.IsEmpty()) { + m_pMchMgr->SetLastError( 2405, "Error in PocketingNT : Empty RawBox") ; + return false ; + } + + // recupero distanza da fondo dei grezzi interessati dal percorso + double dRbDist = 0 ; + if ( AreSameVectorApprox( vtExtr, Z_AX)) { + if ( ! GetDistanceFromRawBottom( m_nPhase, nCopyId, m_TParams.m_dTDiam, dRbDist)) + return false ; + } + + // valuto l'espressione dell'affondamento + ExeLuaSetGlobNumVar( "TH", abs( dThick)) ; + ExeLuaSetGlobNumVar( "RB", dRbDist) ; + double dDepth ; + string sMyDepth = m_Params.m_sDepth ; + if ( ! ExeLuaEvalNumExpr( ToUpper( sMyDepth), &dDepth)) { + m_pMchMgr->SetLastError( 2406, "Error in PocketingNT : Depth not computable") ; + return false ; + } + // se spessore positivo, lo sottraggo dal risultato + if ( dThick > 0) + dDepth -= dThick ; + // sottraggo eventuale offset longitudinale + dDepth -= GetOffsL() ; + + // recupero nome del path + string sPathName ; + m_pGeomDB->GetName( nPathId, sPathName) ; + + // assegno il versore fresa + Vector3d vtTool = vtExtr ; + + // calcolo l'elevazione massima + double dElev ; + if ( CalcRegionElevation( pCompo, vtTool, dDepth, 0.5 * m_TParams.m_dDiam, m_TParams.m_dLen, dElev)) { + if ( dElev < EPS_SMALL && AreSameVectorApprox( vtExtr, Z_AX)) { + BBox3d b3Crv ; + pCompo->GetLocalBBox( b3Crv) ; + dElev = max( 0., b3Raw.GetMax().z - b3Crv.GetMin().z + min( 0., dThick) + dDepth) ; + } + } + else + return false ; + // eventuale imposizione massima elevazione da note utente + double dMaxElev ; + if ( FromString( ExtractInfo( m_Params.m_sUserNotes, "MaxElev="), dMaxElev) && dElev > dMaxElev) + dElev = dMaxElev ; + + // verifico che lo step dell'utensile sia sensato + double dOkStep = ( m_Params.m_dStep > EPS_SMALL ? m_Params.m_dStep + EPS_SMALL : 0) ; + const double MIN_ZSTEP = 1.0 ; + if ( dOkStep >= EPS_SMALL && dOkStep < MIN_ZSTEP) { + dOkStep = MIN_ZSTEP + EPS_SMALL ; + string sInfo = "Warning in PocketingNT : 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 PocketingNT : 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 PocketingNT : 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 PocketingNT : 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 = 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 PocketingNT : 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( pCompo, vtTool)) { + return false ; + } + + // recupero eventuale flag di lato aperto forzato fuori dal grezzo + int nOpenOutRaw ; + m_bOpenOutRaw = ( FromString( ExtractInfo( m_Params.m_sUserNotes, "OpenOutRaw="), nOpenOutRaw) && nOpenOutRaw != 0) ; + + // 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, pCompo)) + return false ; + } + + // se richiesta lavorazione + if ( nClId != GDB_ID_NULL) { + // creo gruppo per geometria di lavorazione del percorso + int nPxId = m_pGeomDB->AddGroup( GDB_ID_NULL, nClId, Frame3d()) ; + if ( nPxId == GDB_ID_NULL) + return false ; + m_pGeomDB->SetName( nPxId, sPathName) ; + m_pGeomDB->SetMaterial( nPxId, BLUE) ; + + // verifico se archi vanno approssimati con segmenti di retta + bool bSplitArcs = GetSplitArcs( vtExtr) ; + + // assegno il vettore estrazione al gruppo del percorso + m_pGeomDB->SetInfo( nPxId, KEY_EXTR, vtTool) ; + // assegno i punti di inizio e fine al gruppo del percorso + m_pGeomDB->SetInfo( nPxId, KEY_START, ptStart) ; + m_pGeomDB->SetInfo( nPxId, KEY_END, ptStart) ; + // assegno l'elevazione massima + m_pGeomDB->SetInfo( nPxId, KEY_ELEV, dElev) ; + + // Imposto dati comuni + SetPathId( nPxId) ; + SetToolDir( vtTool) ; + + // Eseguo la lavorazione a seconda del tipo + switch ( m_Params.m_nSubType) { + case POCKET_SUB_ZIGZAG : + case POCKET_SUB_CONFORMAL_ZIGZAG : + if ( ! AddZigZag( pCompo, vtTool, vtExtr, dDepth, dElev, dOkStep, bSplitArcs, nPathId)) + return false ; + break ; + case POCKET_SUB_ONEWAY : + case POCKET_SUB_CONFORMAL_ONEWAY : + if ( ! AddOneWay( pCompo, vtTool, vtExtr, dDepth, dElev, dOkStep, bSplitArcs)) + return false ; + break ; + case POCKET_SUB_SPIRALIN : + if ( ! AddSpiralIn( pCompo, vtTool, vtExtr, dDepth, dElev, dOkStep, bSplitArcs, bMidOpen, ptMidOpen, vtMidOut, nPathId)) + return false ; + break ; + case POCKET_SUB_SPIRALOUT : + if ( ! AddSpiralOut( pCompo, vtTool, vtExtr, dDepth, dElev, dOkStep, bSplitArcs, nPathId)) + return false ; + break ; + } + } + + // incremento numero di svuotature + ++ m_nPockets ; + + return true ; +} + +//---------------------------------------------------------------------------- +bool +PocketingNT::CalcRegionElevation( const ICurveComposite* pCompo, const Vector3d& vtTool, double dDepth, double dRad, double dLen, + double& dElev) const +{ + // inizializzo l'elevazione + dElev = 0 ; + + // approssimo la curva con una polilinea che uso per creare il poligono equivalente + PolyLine PL ; + if ( ! pCompo->ApproxWithLines( LIN_TOL_RAW, ANG_TOL_MAX_DEG, ICurve::APL_SPECIAL, PL)) + return false ; + Polygon3d pgFacet ; + if ( ! pgFacet.FromPolyLine( PL)) + return false ; + // aggiungo l'affondamento + pgFacet.Translate( -dDepth * vtTool) ; + + // inizializzo elevazioni per ogni grezzo + INTDBLVECTOR vRawElev ; + // ciclo sui grezzi della fase + int nRawId = m_pMchMgr->GetFirstRawPart() ; + while ( nRawId != GDB_ID_NULL) { + // verifico che il grezzo compaia nella fase + if ( m_pMchMgr->VerifyRawPartPhase( nRawId, m_nPhase)) { + // recupero la trimesh del grezzo + int nStmId = m_pGeomDB->GetFirstNameInGroup( nRawId, MACH_RAW_SOLID) ; + const ISurfTriMesh* pStm = GetSurfTriMesh( m_pGeomDB->GetGeoObj( nStmId)) ; + if ( pStm != nullptr) { + // recupero il riferimento della trimesh + Frame3d frStm ; + m_pGeomDB->GetGlobFrame( nStmId, frStm) ; + // porto il poligono in questo riferimento + Polygon3d pgFacetL = pgFacet ; + pgFacetL.ToLoc( frStm) ; + // calcolo l'elevazione + double dCurrElev ; + if ( ! PolygonElevationInClosedSurfTm( pgFacetL, *pStm, true, dCurrElev)) + return false ; + if ( dCurrElev > EPS_SMALL) + vRawElev.emplace_back( nStmId, dCurrElev) ; + } + } + // passo al grezzo successivo + nRawId = m_pMchMgr->GetNextRawPart( nRawId) ; + } + // se trovate elevazioni + if ( ! vRawElev.empty()) { + // ordino il vettore secondo l'elevazione crescente + sort( vRawElev.begin(), vRawElev.end(), []( const INTDBL& a, const INTDBL& b) + { return a.second < b.second ; }) ; + // box dell'insieme delle posizioni utensile all'inizioe + const double MAX_DIST_RAW = 200.0 ; + BBox3d b3Tool ; + pgFacet.GetLocalBBox( b3Tool) ; + b3Tool.Add( b3Tool.GetMin() + dLen * vtTool) ; + b3Tool.Add( b3Tool.GetMax() + dLen * vtTool) ; + if ( vtTool.IsX()) + b3Tool.Expand( 0, dRad, dRad) ; + else if ( vtTool.IsY()) + b3Tool.Expand( dRad, 0, dRad) ; + else if ( vtTool.IsZ()) + b3Tool.Expand( dRad, dRad, 0) ; + else { + double dExpandX = dRad * sqrt( 1 - vtTool.x * vtTool.x) ; + double dExpandY = dRad * sqrt( 1 - vtTool.y * vtTool.y) ; + double dExpandZ = dRad * sqrt( 1 - vtTool.z * vtTool.z) ; + b3Tool.Expand( dExpandX, dExpandY, dExpandZ) ; + } + b3Tool.Expand( MAX_DIST_RAW) ; + // verifico la reale interferenza dell'utensile con i diversi grezzi + for ( int i = 0 ; i < int( vRawElev.size()) ; ++ i) { + // box del grezzo + BBox3d b3Raw ; + m_pGeomDB->GetGlobalBBox( vRawElev[i].first, b3Raw) ; + // confronto con il box dell'utensile nella posizione precedente + BBox3d b3CurrTool = b3Tool ; + b3CurrTool.Translate( dElev * vtTool) ; + if ( b3Raw.Overlaps( b3CurrTool)) + dElev = vRawElev[i].second ; + } + } + + return true ; +} + +//---------------------------------------------------------------------------- +bool +PocketingNT::VerifyPathFromBottom( const ICurveComposite* pCompo, const Vector3d& vtTool) +{ + // se non è svuotatura dal basso in alto, esco + if ( vtTool.z > MIN_ZDIR_TOP_TOOL) + return true ; + // se c'è testa non dall'alto o tavola basculante, esco + if ( ! m_bAboveHead || m_bTiltingTab) + return true ; + // recupero dati di eventuale rinvio da sotto + if ( ! GetAggrBottomData( m_TParams.m_sHead, m_AggrBottom) || m_AggrBottom.nType == 0) { + m_pMchMgr->SetLastError( 2409, "Error in PocketingNT : 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 ; + 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_TParams.m_dDiam / 2 + GetOffsR()) > m_AggrBottom.dDMax) { + m_pMchMgr->SetLastError( 2410, "Error in PocketingNT : 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 +PocketingNT::GeneratePocketingPv( int nPathId, const ICurveComposite* pCompo) +{ + // creo copia della curva composita + PtrOwner pCrv( pCompo->Clone()) ; + if ( IsNull( pCrv)) + return false ; + // calcolo la regione + SurfFlatRegionByContours SfrCntrRr ; + SfrCntrRr.AddCurve( Release( pCrv)) ; + PtrOwner pSfr( SfrCntrRr.GetSurf()) ; + if ( IsNull( pSfr)) + return false ; + // ne recupero il contorno + PtrOwner< ICurve> pCrv2 ; + pCrv2.Set( pSfr->GetLoop( 0, 0)) ; + if ( IsNull( pCrv2)) + return false ; + // inserisco la curva nel DB + int nC2Id = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nPathId, Release( pCrv2)) ; + if ( nC2Id == GDB_ID_NULL) + return false ; + // assegno nome e colore + m_pGeomDB->SetName( nC2Id, MCH_PV_CUT) ; + m_pGeomDB->SetMaterial( nC2Id, RED) ; + // eventuali altri contorni ( interni di contornatura chiusa) + const int MAX_INT_LOOP = 1000 ; + for ( int i = 1 ; i <= MAX_INT_LOOP ; ++i) { + PtrOwner< ICurve> pCrv3 ; + pCrv3.Set( pSfr->GetLoop( 0, i)) ; + if ( IsNull( pCrv3)) + break ; + // inserisco la curva nel DB + int nC3Id = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nPathId, Release( pCrv3)) ; + if ( nC3Id == GDB_ID_NULL) + return false ; + // assegno nome e colore + m_pGeomDB->SetName( nC3Id, MCH_PV_CUT) ; + m_pGeomDB->SetMaterial( nC3Id, RED) ; + } + // inserisco la regione nel DB + int nRId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nPathId, Release( pSfr)) ; + if ( nRId == GDB_ID_NULL) + return false ; + m_pGeomDB->SetName( nRId, MCH_PV_RCUT) ; + m_pGeomDB->SetMaterial( nRId, Color( 255, 0, 0, 60)) ; + // la copio anche come regione ridotta + int nRrId = m_pGeomDB->Copy( nRId, GDB_ID_NULL, nPathId) ; + if ( nRrId == GDB_ID_NULL) + return false ; + m_pGeomDB->SetName( nRrId, MCH_PV_RRCUT) ; + m_pGeomDB->SetMaterial( nRrId, INVISIBLE) ; + return true ; +} + +//---------------------------------------------------------------------------- +static double +GetCurveRadius( const ICurve* pCrv) +{ + if ( pCrv == nullptr) + return 0.0 ; + BBox3d b3Loc ; + if ( ! pCrv->GetLocalBBox( b3Loc, BBF_EXACT)) + return 0.0 ; + double dRad ; + if ( ! b3Loc.GetRadius( dRad)) + return 0.0 ; + return dRad ; +} + +//---------------------------------------------------------------------------- +bool +PocketingNT::AddZigZag( const ICurveComposite* pCompo, const Vector3d& vtTool, const Vector3d& vtExtr, + double dDepth, double dElev, double dOkStep, bool bSplitArcs, int nPathId) +{ + // recupero distanze di sicurezza + double dSafeZ = GetSafeZ() ; + double dSafeAggrBottZ = 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 ; + + // determino il riferimento di base della svuotatura + Frame3d frPocket ; + Point3d ptCen ; pCompo->GetCentroid( ptCen) ; + frPocket.Set( ptCen, vtExtr) ; + frPocket.Rotate( ptCen, vtExtr, m_Params.m_dSideAngle) ; + + ICRVCOMPOPOVECTOR vpCrvs ; + int nOffsCrvNbr = 0 ; + + // verifico se si tratta di caso ottimizzato + bool bOptimizedZigZag = false ; + bool bOutRawLeadIn = false ; + double dOptZigZagOffs ; + if ( ! OptimizedZigZag( nPathId, vtTool, dDepth, dSafeZ, frPocket, bOptimizedZigZag, vpCrvs, dOptZigZagOffs)) + return false ; + if ( bOptimizedZigZag && ! vpCrvs.empty()) { + nOffsCrvNbr = 1 ; + // 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 ; + 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 ottimizzato e 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 PocketingNT : LeadIn with Mill NoTip in material") ; + return false ; + } + } + + // se caso non ottimizzato calcolo curva offsettata del raggio utensile + sovramateriale + (se non lucidatura) extra + double dTRad = m_TParams.m_dDiam / 2 ; + double dOffs = dTRad + GetOffsR() ; + double dExtra = (( m_TParams.m_nType != TT_MILL_POLISHING) ? min( 0.1 * m_TParams.m_dDiam, 2.0) : 0) ; + OffsetCurve OffsCrv ; + if ( ! bOptimizedZigZag) { + if ( ! OffsCrv.Make( pCompo, - ( dOffs + dExtra), ICurve::OFF_FILLET)) { + m_pMchMgr->SetLastError( 2412, "Error in PocketingNT : Offset not computable") ; + return false ; + } + nOffsCrvNbr = OffsCrv.GetCurveCount() ; + } + + // ciclo sulle curve risultanti + bool bStart = true ; + while ( nOffsCrvNbr > 0) { + + if ( bOptimizedZigZag) + nOffsCrvNbr = 0 ; // setto a zero per non rientrare nel while + else { + // recupero la prima curva di offset + PtrOwner pOffs ; + if ( ! pOffs.Set( ConvertCurveToComposite( OffsCrv.GetLongerCurve()))) { + m_pMchMgr->SetLastError( 2413, "Error in PocketingNT : Toolpath not computable") ; + return false ; + } + nOffsCrvNbr = OffsCrv.GetCurveCount() ; + + // porto la curva nel riferimento della svuotatura + pOffs->ToLoc( frPocket) ; + + // calcolo i percorsi di svuotatura + vpCrvs.clear() ; + if ( ! CalcZigZag( pOffs, vpCrvs)) + return false ; + } + + // 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) ; + } + } + } + + // se necessario, approssimo con rette + if ( bSplitArcs) { + for ( auto& pMCrv : vpCrvs) { + if ( ! ApproxWithLines( pMCrv)) { + m_pMchMgr->SetLastError( 2419, "Error in PocketingNT : Linear Approx not computable") ; + return false ; + } + } + } + + // inserisco i movimenti di svuotatura + for ( int j = 1 ; j <= nStep ; ++ j) { + // 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 + PtrOwner pCurve( pCrvC->Clone()) ; + if ( IsNull( pCurve)) + return false ; + pCurve->ToGlob( frPocket) ; + // aggiungo affondamento + pCurve->Translate( - vtTool * ( dDepth - dElev + j * dStep)) ; + // se prima entità + if ( i == 0 ) { + // dati inizio entità + Point3d ptStart ; + pCurve->GetStartPoint( ptStart) ; + Vector3d vtStart ; + pCurve->GetStartDir( vtStart) ; + // determino inizio attacco + Point3d ptP1 ; + if ( ! CalcLeadInStart( ptStart, vtStart, vtExtr, nullptr, ptP1)) + return false ; + // determino elevazione su inizio attacco + double dStElev ; + GetElevation( m_nPhase, ptStart - 10 * EPS_SMALL * vtTool, vtTool, GetRadiusForStartEndElevation(), vtTool, dStElev) ; + dStElev = max( 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 + LIO_ELEV_TOL) ; + dStElev = -LIO_ELEV_TOL ; + } + } + // se inizio, approccio globale al punto iniziale + if ( bStart) { + if ( ! AddApproach( ptP1, vtTool, dSafeZ, dSafeAggrBottZ, dStElev, dAppr, bSplitArcs, bOutRawLeadIn || m_bOpenOutRaw)) { + m_pMchMgr->SetLastError( 2414, "Error in PocketingNT : Approach not computable") ; + return false ; + } + bStart = false ; + } + // altrimenti, approccio di collegamento + else { + if ( ! AddLinkApproach( ptP1, vtTool, dSafeZ, dSafeAggrBottZ, dStElev, dAppr, bSplitArcs, bOutRawLeadIn || m_bOpenOutRaw)) { + m_pMchMgr->SetLastError( 2418, "Error in PocketingNT : Link not computable") ; + return false ; + } + } + // aggiungo attacco + SetFeed( GetStartFeed()) ; + if ( ! AddLeadIn( ptP1, ptStart, vtStart, vtExtr, pCompo, nullptr, ! m_Params.m_bInvert, + bSplitArcs, bOutRawLeadIn || m_bOpenOutRaw)) { + m_pMchMgr->SetLastError( 2415, "Error in PocketingNT : LeadIn not computable") ; + return false ; + } + } + // elaborazioni sulla curva corrente + if ( pCurve->GetType() == CRV_LINE) { + ICurveLine* pLine = GetCurveLine( pCurve) ; + Point3d ptP3 = pLine->GetEnd() ; + SetFeed( GetFeed()) ; + if ( AddLinearMove( ptP3, bSplitArcs) == GDB_ID_NULL) + return false ; + } + else if ( pCurve->GetType() == CRV_ARC) { + ICurveArc* pArc = GetCurveArc( pCurve) ; + Point3d ptCen = pArc->GetCenter() ; + double dAngCen = pArc->GetAngCenter() ; + Vector3d vtN = pArc->GetNormVersor() ; + Point3d ptP3 ; + pArc->GetEndPoint( ptP3) ; + SetFeed( GetFeed()) ; + if ( AddArcMove( ptP3, ptCen, dAngCen, vtN) == GDB_ID_NULL) + return false ; + } + // se ultima entità + if ( i == nMaxInd) { + // dati fine entità + Point3d ptEnd ; + pCurve->GetEndPoint( ptEnd) ; + Vector3d vtEnd ; + pCurve->GetEndDir( vtEnd) ; + // aggiungo uscita + double dEndElev = dElev ; + Point3d ptP1 ; + SetFeed( GetEndFeed()) ; + if ( ! AddLeadOut( ptEnd, vtEnd, vtExtr, nullptr, bSplitArcs, true, ptP1, dEndElev)) { + m_pMchMgr->SetLastError( 2416, "Error in PocketingNT : LeadOut not computable") ; + return false ; + } + // 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, bSplitArcs)) { + m_pMchMgr->SetLastError( 2418, "Error in PocketingNT : Retract not computable") ; + return false ; + } + } + // altrimenti, aggiungo retrazione di collegamento + else { + if ( ! AddLinkRetract( ptP1, vtTool, dSafeZ, dSafeAggrBottZ, dEndElev, dAppr, bSplitArcs)) { + m_pMchMgr->SetLastError( 2418, "Error in PocketingNT : Link not computable") ; + return false ; + } + } + } + } + } + } + } + + // se lucidatura o caso ottimizzato, non aggiungo contorno + if ( m_TParams.m_nType == TT_MILL_POLISHING || bOptimizedZigZag) + return true ; + + // calcolo seconda curva offsettata del raggio utensile + sovramateriale + OffsetCurve OffsCrv2 ; + if ( ! OffsCrv2.Make( pCompo, - dOffs, ICurve::OFF_FILLET)) { + m_pMchMgr->SetLastError( 2412, "Error in PocketingNT : Offset not computable") ; + return false ; + } + + // ciclo sulle curve risultanti + while ( OffsCrv2.GetCurveCount() > 0) { + + // recupero la prima curva di offset + PtrOwner pOffs2 ; + if ( ! pOffs2.Set( ConvertCurveToComposite( OffsCrv2.GetLongerCurve()))) { + m_pMchMgr->SetLastError( 2413, "Error in PocketingNT : Toolpath not computable") ; + return false ; + } + + // se necessario, approssimo con rette + if ( bSplitArcs) { + if ( ! ApproxWithLines( pOffs2)) { + m_pMchMgr->SetLastError( 2419, "Error in PocketingNT : Linear Approx not computable") ; + return false ; + } + } + // altrimenti verifico archi + else + VerifyArcs( pOffs2) ; + + // se richiesto, la inverto + if ( m_Params.m_bInvert) + pOffs2->Invert() ; + + // sposto l'inizio a metà del tratto più lungo + AdjustContourStart( pOffs2) ; + + // aggiungo la lavorazione di questa curva + Point3d ptP1 ; + for ( int j = 1 ; j <= nStep ; ++ j) { + // ciclo sulle curve elementari + int nMaxInd = pOffs2->GetCurveCount() - 1 ; + for ( int i = 0 ; i <= nMaxInd ; ++ i) { + // curva corrente + const ICurve* pCrvC = pOffs2->GetCurve( i) ; + // copio la curva + PtrOwner pCurve( pCrvC->Clone()) ; + if ( IsNull( pCurve)) + return false ; + // aggiungo affondamento + pCurve->Translate( - vtTool * ( dDepth - dElev + j * dStep)) ; + // se prima entità + if ( i == 0 ) { + // dati inizio entità + Point3d ptStart ; + pCurve->GetStartPoint( ptStart) ; + Vector3d vtStart ; + pCurve->GetStartDir( vtStart) ; + // se primo step, approccio e affondo + if ( j == 1) { + // determino inizio attacco + if ( ! CalcLeadInStart( ptStart, vtStart, vtExtr, nullptr, ptP1)) + return false ; + // determino elevazione su inizio attacco + double dStElev ; + if ( ! GetElevation( m_nPhase, ptStart - 10 * EPS_SMALL * vtTool, vtTool, + GetRadiusForStartEndElevation(), vtTool, dStElev)) + dStElev = 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 || m_bTiltingTab) + dStElev = max( dStElev, dStep) ; + dStElev -= ( ptP1 - ptStart) * vtExtr ; + // se attacco a zigzag o a spirale o a scivolo, l'elevazione va nell'attacco + if ( GetLeadInType() == POCKET_LI_ZIGZAG || + GetLeadInType() == POCKET_LI_HELIX || + GetLeadInType() == POCKET_LI_GLIDE) { + ptP1 += vtExtr * ( dStElev + LIO_ELEV_TOL) ; + dStElev = -LIO_ELEV_TOL ; + } + // approccio al punto iniziale + if ( ! AddLinkApproach( ptP1, vtTool, dSafeZ, dSafeAggrBottZ, dStElev, dAppr, bSplitArcs)) { + m_pMchMgr->SetLastError( 2418, "Error in PocketingNT : Link not computable") ; + return false ; + } + // aggiungo attacco + SetFeed( GetStartFeed()) ; + if ( ! AddLeadIn( ptP1, ptStart, vtStart, vtExtr, pCompo, nullptr, ! m_Params.m_bInvert, bSplitArcs)) { + m_pMchMgr->SetLastError( 2415, "Error in PocketingNT : LeadIn not computable") ; + return false ; + } + } + // altrimenti solo collegamento + else { + SetFeed( GetStartFeed()) ; + GetCurrPos( ptP1) ; + if ( ! AddLeadIn( ptP1, ptStart, vtStart, vtExtr, pCompo, nullptr, ! m_Params.m_bInvert, bSplitArcs)) { + m_pMchMgr->SetLastError( 2418, "Error in PocketingNT : Link not computable") ; + return false ; + } + } + } + // elaborazioni sulla curva corrente + if ( pCurve->GetType() == CRV_LINE) { + ICurveLine* pLine = GetCurveLine( pCurve) ; + Point3d ptP3 = pLine->GetEnd() ; + SetFeed( GetFeed()) ; + if ( AddLinearMove( ptP3, bSplitArcs) == GDB_ID_NULL) + return false ; + } + else if ( pCurve->GetType() == CRV_ARC) { + ICurveArc* pArc = GetCurveArc( pCurve) ; + Point3d ptCen = pArc->GetCenter() ; + double dAngCen = pArc->GetAngCenter() ; + Vector3d vtN = pArc->GetNormVersor() ; + Point3d ptP3 ; + pArc->GetEndPoint( ptP3) ; + SetFeed( GetFeed()) ; + if ( AddArcMove( ptP3, ptCen, dAngCen, vtN) == GDB_ID_NULL) + return false ; + } + // se ultima entità + if ( i == nMaxInd) { + // se ultimo step, uscita e retrazione di collegamento + if ( j == nStep) { + // dati fine entità + Point3d ptEnd ; + pCurve->GetEndPoint( ptEnd) ; + Vector3d vtEnd ; + pCurve->GetEndDir( vtEnd) ; + // aggiungo uscita + double dEndElev = dElev ; + SetFeed( GetEndFeed()) ; + if ( ! AddLeadOut( ptEnd, vtEnd, vtExtr, nullptr, bSplitArcs, false, ptP1, dEndElev)) { + m_pMchMgr->SetLastError( 2416, "Error in PocketingNT : LeadOut not computable") ; + return false ; + } + // se ci sono ancora curve, aggiungo retrazione di collegamento + if ( OffsCrv2.GetCurveCount() > 0) { + if ( ! AddLinkRetract( ptP1, vtTool, dSafeZ, dSafeAggrBottZ, dEndElev, dAppr, bSplitArcs)) { + m_pMchMgr->SetLastError( 2418, "Error in PocketingNT : Link not computable") ; + return false ; + } + } + // altrimenti retrazione finale + else { + if ( ! AddRetract( ptP1, vtTool, dSafeZ, dSafeAggrBottZ, dEndElev, dAppr, bSplitArcs)) { + m_pMchMgr->SetLastError( 2418, "Error in PocketingNT : Retract not computable") ; + return false ; + } + } + } + } + } + } + } + + return true ; +} + +//---------------------------------------------------------------------------- +bool +PocketingNT::CalcZigZag( const ICurveComposite* pOffs, + ICRVCOMPOPOVECTOR& vpCrvs) +{ + // ingombro del contorno offsettato + BBox3d b3Pocket ; + pOffs->GetLocalBBox( b3Pocket) ; + Point3d ptMin ; double dDimX, dDimY, dDimZ ; + b3Pocket.GetMinDim( ptMin, dDimX, dDimY, dDimZ) ; + + // lunghezza del contorno offsettato + double dLen ; pOffs->GetLength( dLen) ; + + // passi in Y + int nYStep = static_cast( 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 ; + } ; + // 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 PocketingNT : Toolpath not computable") ; + return false ; + } + // calcolo la classificazione della curva rispetto al contorno esterno offsettato + IntersCurveCurve intCC( *pLine, *pOffs) ; + CRVCVECTOR ccClass ; + if ( ! intCC.GetCurveClassification( 0, EPS_SMALL, ccClass)) { + m_pMchMgr->SetLastError( 2413, "Error in PocketingNT : Toolpath not computable") ; + return false ; + } + // determino gli intervalli di curva da conservare + Intervals inOk ; + for ( auto& ccOne : ccClass) { + if ( ccOne.nClass == CRVC_IN || ccOne.nClass == CRVC_ON_P || ccOne.nClass == CRVC_ON_M) + inOk.Add( ccOne.dParS, ccOne.dParE) ; + } + // inserisco i tratti validi (secondo X+ i pari, secondo X- i dispari) + double dParS, dParE ; + bool bFound = ( bPlus ? inOk.GetFirst( dParS, dParE) : inOk.GetLast( dParE, dParS)) ; + while ( bFound) { + // determino i dati della sezione + Section Sect ; + Sect.bActive = true ; + pLine->GetPointD1D2( dParS, ICurve::FROM_PLUS, Sect.ptS) ; + pLine->GetPointD1D2( dParE, ICurve::FROM_MINUS, Sect.ptE) ; + pOffs->GetParamAtPoint( Sect.ptS, Sect.dOs, 10 * EPS_SMALL) ; + pOffs->GetParamAtPoint( Sect.ptE, Sect.dOe, 10 * EPS_SMALL) ; + // inserisco nel contenitore + vvSec[i].emplace_back( Sect) ; + ++ nCount ; + // recupero successivo intervallo + bFound = ( bPlus ? inOk.GetNext( dParS, dParE) : inOk.GetPrev( dParE, dParS)) ; + } + } + + // dominio del contorno + double dUmin, dUmax ; + pOffs->GetDomain( dUmin, dUmax) ; + double dUspan = dUmax - dUmin ; + + // creo i percorsi di svuotatura + vpCrvs.reserve( nCount) ; + int nI = -1, nJ = -1 ; + while ( true) { + // se sezione non valida + if ( nI < 0 || nJ < 0) { + // ricerco la prima valida + for ( int k = 0 ; k < int( vvSec.size()) && nI < 0 ; ++ k) { + for ( int l = 0 ; l < int( vvSec[k].size()) && nJ < 0 ; ++ l) { + if ( vvSec[k][l].bActive) { + nI = k ; + nJ = l ; + } + } + } + // se trovata, creo nuova curva composita + if ( nI >= 0 && nJ >= 0) { + // creo la curva + vpCrvs.emplace_back( CreateCurveComposite()) ; + // aggiungo punto iniziale + vpCrvs.back()->AddPoint( vvSec[nI][nJ].ptS) ; + } + // altrimenti, esco + else + break ; + } + // determino senso + bool bPlus = (( nI % 2) == nRef) ; + // aggiungo la sezione alla curva + Section& Sec = vvSec[nI][nJ] ; + Sec.bActive = false ; + vpCrvs.back()->AddLine( vvSec[nI][nJ].ptE) ; + // cerco nella stessa fila o in quella successiva sezione successiva raccordabile tramite il contorno + double dUstart = Sec.dOe ; + double dUref = ( bPlus ? INFINITO : - INFINITO) ; + int nNextI = -1 ; + int nNextJ = -1 ; + int li = nJ + 1 ; + for ( int k = nI ; k <= nI + 1 && k < int( vvSec.size()) ; ++ k) { + for ( int l = li ; l < int( vvSec[k].size()) ; ++ l) { + if ( ! vvSec[k][l].bActive) + continue ; + 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, aggiungo il tratto di contorno e continuo + if ( nNextI != -1) { + PtrOwner pCopy ; + if ( bPlus) { + if ( dUref > dUmax) + dUref -= dUspan ; + pCopy.Set( pOffs->CopyParamRange( dUstart, dUref)) ; + if ( ! IsNull( pCopy)) { + double dCLen ; pCopy->GetLength( dCLen) ; + if ( dCLen > 0.5 * dLen) { + pCopy.Set( pOffs->CopyParamRange( dUref, dUstart)) ; + if ( ! IsNull( pCopy)) + pCopy->Invert() ; + } + } + } + else { + if ( dUref < dUmin) + dUref += dUspan ; + pCopy.Set( pOffs->CopyParamRange( dUref, dUstart)) ; + if ( ! IsNull( pCopy)) { + pCopy->Invert() ; + double dCLen ; pCopy->GetLength( dCLen) ; + if ( dCLen > 0.5 * dLen) + pCopy.Set( pOffs->CopyParamRange( dUstart, dUref)) ; + } + } + BBox3d b3Copy ; + if ( ! IsNull( pCopy)) + pCopy->GetLocalBBox( b3Copy) ; + if ( ! b3Copy.IsEmpty() && ( b3Copy.GetMax().y - b3Copy.GetMin().y) < dYStep + 10 * EPS_SMALL) { + vpCrvs.back()->AddCurve( Release( pCopy)) ; + nI = nNextI ; + nJ = nNextJ ; + } + else { + nI = -1 ; + nJ = -1 ; + } + } + else { + nI = -1 ; + nJ = -1 ; + } + } + return true ; +} + +//---------------------------------------------------------- +bool +PocketingNT::OptimizedZigZag( int nPathId, const Vector3d& vtTool, double dDepth, double dSafeZ, + Frame3d& frPocket, bool& bOptimizedZigZag, ICRVCOMPOPOVECTOR& vpCrvs, double& dOffs) +{ + // recupero la curva originale che delimita la svuotatura + int nCrvId = m_pGeomDB->GetFirstInGroup( nPathId) ; + PtrOwner pCrvPocket( CloneCurveComposite( m_pGeomDB->GetGeoObj( nCrvId))) ; + if ( IsNull( pCrvPocket)) + return false ; + pCrvPocket->ToLoc( frPocket) ; + SetCurveAllTempProp( nCrvId, GetForcedClosed(), 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 ; + switch ( nClosedSides) { + case 0 : + ZigZagOptimizedNoClosedEdges( pCrvPocket, bOptimizedZigZag, vtDir, dOffs) ; + break ; + case 1 : + ZigZagOptimizedOneClosedEdge( pCrvPocket, vnInfoClosed[0], bOptimizedZigZag, vtDir, dOffs) ; + break ; + case 2 : + ZigZagOptimizedTwoClosedEdges( pCrvPocket, vnInfoClosed, bOptimizedZigZag, bTwoOpposite, vtDir, dOffs) ; + break ; + case 3 : + ZigZagOptimizedThreeClosedEdges( pCrvPocket, vnInfoClosed, bOptimizedZigZag, bTwoOpposite, vtDir, dOffs) ; + break ; + default : + bOptimizedZigZag = false ; + break ; + } + + if ( ! bOptimizedZigZag) + return true ; + + // oriento il frame della svuotatura allineando asse X con vtDir + if ( vtDir.IsZero()) + pCrvPocket->GetStartDir( vtDir) ; + double dAng ; + vtDir.GetAngleXY( X_AX, dAng) ; + if ( nClosedSides == 0) + dAng += m_Params.m_dSideAngle ; + pCrvPocket->ToGlob( frPocket) ; + Point3d ptCen = frPocket.Orig() ; + Vector3d vtExtr = frPocket.VersZ() ; + frPocket.Rotate( ptCen, vtExtr, -dAng) ; + pCrvPocket->ToLoc( frPocket) ; + + // calcolo il percorso di svuotatura + if ( ! CalcZigZag( pCrvPocket, 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.)) ; + + return true ; +} + +//------------------------------------------------------------------ +bool +PocketingNT::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 +PocketingNT::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 +PocketingNT::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 +PocketingNT::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 || dLen3 > 1.5 * m_TParams.m_dDiam) + return true ; + pCrv2->GetStartDir( vtDir) ; + bOpposite = false ; + } + else { + if ( dLen2 > 1.5 * m_TParams.m_dDiam) + 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 + PocketingNT::ZigZagOptimizedComputeOffset( ICurveComposite* pCrvPocket, const Vector3d& vtMainDir, int nOffsettedEdgesOnY, + const INTVECTOR& vnClosedIds, double& dOffs) + { + // calcolo il side step che verrà utilizzato in CalcZigZag + Frame3d frLoc ; + if ( ! frLoc.Set( ORIG, Z_AX, vtMainDir)) + return true ; + BBox3d b3Loc ; + pCrvPocket->ToLoc( frLoc) ; + pCrvPocket->GetLocalBBox( b3Loc) ; + pCrvPocket->ToGlob( frLoc) ; + Point3d pt ; + double dDimX, dDimY, dDimZ ; + b3Loc.GetMinDim( pt, dDimX, dDimY, dDimZ) ; + // riduco la DimY della svuotatura in base al numero di lati chiusi che saranno offsettati lungo quella direzione + dDimY -= nOffsettedEdgesOnY * ( 0.5 * m_TParams.m_dDiam + GetOffsR()) ; + int nYStep = static_cast( ceil( ( dDimY - 30 * EPS_SMALL) / GetSideStep())) ; + double dYSideStep = ( nYStep > 0 ? ( dDimY - 30 * EPS_SMALL) / nYStep : 0) ; + + // individuo i lati vicini a quelli closed + for ( int i = 0 ; i < ( int)vnClosedIds.size() ; i ++) { + int nNext = vnClosedIds[i] == pCrvPocket->GetCurveCount() - 1 ? 0 : vnClosedIds[i] + 1 ; + int nPrev = vnClosedIds[i] == 0 ? pCrvPocket->GetCurveCount() - 1 : vnClosedIds[i] - 1 ; + pCrvPocket->SetCurveTempProp( nNext, 1, 1) ; + pCrvPocket->SetCurveTempProp( nPrev, 1, 1) ; + } + + // verifico se resteranno aree residue e calcolo eventuale offset per pCrvPocket + dOffs = 0 ; + for ( int i = 0 ; i < pCrvPocket->GetCurveCount() ; i ++) { + + double dOffsTmp = 0 ; + double dVal = 0 ; + + if ( pCrvPocket->GetCurve(i)->GetType() == CRV_LINE) { + Vector3d vtDir ; + if ( ! pCrvPocket->GetCurve( i)->GetStartDir( vtDir)) + return false ; + + int nProp ; + pCrvPocket->GetCurveTempProp( i, nProp, 1) ; + double dLen ; + pCrvPocket->GetCurve( i)->GetLength( dLen) ; + + if ( nProp == 1 && dLen > 1000 * EPS_SMALL) { + // gestione speciale se vicino al lato closed + double dCosAlpha = vtMainDir * vtDir ; + if ( abs( dCosAlpha) > EPS_SMALL && abs( dCosAlpha) < 1 - EPS_SMALL) + dOffsTmp = abs( 0.5 * m_TParams.m_dDiam * dCosAlpha) ; + } + else { + double dSinAlpha = ( vtMainDir ^ vtDir).Len() ; + if ( abs( dSinAlpha) > EPS_SMALL) + dVal = ( dYSideStep - 0.5 * m_TParams.m_dDiam) / dSinAlpha - 0.5 * m_TParams.m_dDiam ; + if ( dVal > EPS_SMALL) { + double dCosAlpha = vtMainDir * vtDir ; + dOffsTmp = abs( ( dYSideStep - 0.5 * m_TParams.m_dDiam) * dCosAlpha) ; + } + } + } + if ( dOffsTmp > dOffs) + dOffs = dOffsTmp ; + } + + // aggiusto offset + 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 PocketingNT : Offset not computable") ; + return false ; + } + if ( OffsCrv.GetCurveCount() > 1) + return false ; + + // aggiorno pCrvPocket + pCrvPocket->Clear() ; + pCrvPocket->AddCurve( OffsCrv.GetCurve()) ; + } + + return true ; + } + +//------------------------------------------------------------------ +bool +PocketingNT::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 +PocketingNT::AddOneWay( const ICurveComposite* pCompo, const Vector3d& vtTool, const Vector3d& vtExtr, + double dDepth, double dElev, double dOkStep, bool bSplitArcs) +{ + // recupero distanze di sicurezza + double dSafeZ = GetSafeZ() ; + double dSafeAggrBottZ = 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 PocketingNT : LeadIn with Mill NoTip in material") ; + return false ; + } + } + + // determino numero e affondamento degli step + int nStep = 1 ; + nStep = max( 1, static_cast( ceil( dElev / dOkStep))) ; + double dStep = dElev / nStep ; + + // calcolo curva offsettata del raggio utensile + sovramateriale + double dTRad = 0.5 * m_TParams.m_dDiam ; + double dOffs = dTRad + GetOffsR() ; + OffsetCurve OffsCrv ; + if ( ! OffsCrv.Make( pCompo, - dOffs, ICurve::OFF_FILLET)) { + m_pMchMgr->SetLastError( 2412, "Error in PocketingNT : Offset not computable") ; + return false ; + } + + // ciclo sulle curve risultanti + while ( OffsCrv.GetCurveCount() > 0) { + + // recupero la prima curva di offset + PtrOwner pOffs ; + if ( ! pOffs.Set( ConvertCurveToComposite( OffsCrv.GetLongerCurve()))) { + m_pMchMgr->SetLastError( 2413, "Error in PocketingNT : Toolpath not computable") ; + return false ; + } + + // se richiesto, la inverto + if ( m_Params.m_bInvert) + pOffs->Invert() ; + + // sposto l'inizio a metà del tratto più lungo + AdjustContourStart( pOffs) ; + + // se necessario, approssimo con rette + if ( bSplitArcs) { + if ( ! ApproxWithLines( pOffs)) { + m_pMchMgr->SetLastError( 2419, "Error in PocketingNT : Linear Approx not computable") ; + return false ; + } + } + // altrimenti verifico archi + else + VerifyArcs( pOffs) ; + + // coefficiente di riduzione feed di lavorazione di questa curva + double dFeedRid = min( GetSideStep() / m_TParams.m_dDiam, 1.0) ; + + // aggiungo la lavorazione di questa curva + Point3d ptP1 ; + for ( int j = 1 ; j <= nStep ; ++ j) { + // ciclo sulle curve elementari + int nMaxInd = pOffs->GetCurveCount() - 1 ; + for ( int i = 0 ; i <= nMaxInd ; ++ i) { + // curva corrente + const ICurve* pCrvC = pOffs->GetCurve( i) ; + // copio la curva + PtrOwner pCurve( pCrvC->Clone()) ; + if ( IsNull( pCurve)) + return false ; + // aggiungo affondamento + pCurve->Translate( - vtTool * ( dDepth - dElev + j * dStep)) ; + // se prima entità + if ( i == 0 ) { + // dati inizio entità + Point3d ptStart ; + pCurve->GetStartPoint( ptStart) ; + Vector3d vtStart ; + pCurve->GetStartDir( vtStart) ; + // se primo step, approccio e affondo + if ( j == 1) { + // determino inizio attacco + if ( ! CalcLeadInStart( ptStart, vtStart, vtExtr, nullptr, ptP1)) + return false ; + // determino elevazione su inizio attacco + double dStElev ; + if ( ! GetElevation( m_nPhase, ptStart - 10 * EPS_SMALL * vtTool, vtTool, GetRadiusForStartEndElevation(), vtTool, dStElev)) + dStElev = dStep ; + bool 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 || m_bTiltingTab) + dStElev = max( dStElev, dStep) ; + dStElev -= ( ptP1 - ptStart) * vtExtr ; + // se attacco a zigzag o a spirale o a scivolo, l'elevazione va nell'attacco + if ( GetLeadInType() == POCKET_LI_ZIGZAG || + GetLeadInType() == POCKET_LI_HELIX || + GetLeadInType() == POCKET_LI_GLIDE) { + ptP1 += vtExtr * ( dStElev + LIO_ELEV_TOL) ; + dStElev = -LIO_ELEV_TOL ; + } + // approccio al punto iniziale + if ( ! AddApproach( ptP1, vtTool, dSafeZ, dSafeAggrBottZ, dStElev, dAppr, bSplitArcs, false)) { + m_pMchMgr->SetLastError( 2414, "Error in PocketingNT : Approach not computable") ; + return false ; + } + // aggiungo attacco + SetFeed( GetStartFeed()) ; + if ( ! AddLeadIn( ptP1, ptStart, vtStart, vtExtr, pCompo, nullptr, ! m_Params.m_bInvert, bSplitArcs)) { + m_pMchMgr->SetLastError( 2415, "Error in PocketingNT : LeadIn not computable") ; + return false ; + } + } + // altrimenti solo collegamento + else { + SetFeed( GetStartFeed()) ; + GetCurrPos( ptP1) ; + if ( ! AddLeadIn( ptP1, ptStart, vtStart, vtExtr, pCompo, nullptr, ! m_Params.m_bInvert, bSplitArcs)) { + m_pMchMgr->SetLastError( 2418, "Error in PocketingNT : Link not computable") ; + return false ; + } + } + } + // elaborazioni sulla curva corrente + if ( pCurve->GetType() == CRV_LINE) { + ICurveLine* pLine = GetCurveLine( pCurve) ; + Point3d ptP3 = pLine->GetEnd() ; + SetFeed( dFeedRid * GetFeed()) ; + if ( AddLinearMove( ptP3, bSplitArcs) == GDB_ID_NULL) + return false ; + } + else if ( pCurve->GetType() == CRV_ARC) { + ICurveArc* pArc = GetCurveArc( pCurve) ; + Point3d ptCen = pArc->GetCenter() ; + double dAngCen = pArc->GetAngCenter() ; + Vector3d vtN = pArc->GetNormVersor() ; + Point3d ptP3 ; + pArc->GetEndPoint( ptP3) ; + SetFeed( dFeedRid * GetFeed()) ; + if ( AddArcMove( ptP3, ptCen, dAngCen, vtN) == GDB_ID_NULL) + return false ; + } + // se ultima entità + if ( i == nMaxInd) { + // se ultimo step, uscita e retrazione di collegamento + if ( j == nStep) { + // dati fine entità + Point3d ptEnd ; + pCurve->GetEndPoint( ptEnd) ; + Vector3d vtEnd ; + pCurve->GetEndDir( vtEnd) ; + // aggiungo uscita + Point3d ptP1 ; + double dEndElev = dElev ; + SetFeed( GetEndFeed()) ; + if ( ! AddLeadOut( ptEnd, vtEnd, vtExtr, nullptr, bSplitArcs, false, ptP1, dEndElev)) { + m_pMchMgr->SetLastError( 2416, "Error in PocketingNT : LeadOut not computable") ; + return false ; + } + // aggiungo retrazione + if ( ! AddLinkRetract( ptP1, vtTool, dSafeZ, dSafeAggrBottZ, dEndElev, dAppr, bSplitArcs)) { + m_pMchMgr->SetLastError( 2418, "Error in PocketingNT : Link not computable") ; + return false ; + } + } + } + } + } + } + + // calcolo seconda curva di offset + OffsetCurve OffsCrv2 ; + double dExtra = min( 0.1 * m_TParams.m_dDiam, 1.0) ; + if ( ! OffsCrv2.Make( pCompo, - ( dOffs + dExtra), ICurve::OFF_FILLET)) { + m_pMchMgr->SetLastError( 2412, "Error in PocketingNT : Offset not computable") ; + return false ; + } + + // ciclo sulle curve risultanti + while ( OffsCrv2.GetCurveCount() > 0) { + + PtrOwner pOffs2 ; + if ( ! pOffs2.Set( ConvertCurveToComposite( OffsCrv2.GetLongerCurve()))) { + m_pMchMgr->SetLastError( 2413, "Error in PocketingNT : Toolpath not computable") ; + return false ; + } + + // determino il riferimento di base e il box della svuotatura + Frame3d frPocket ; + Point3d ptCen ; pCompo->GetCentroid( ptCen) ; + frPocket.Set( ptCen, vtExtr) ; + frPocket.Rotate( ptCen, vtExtr, m_Params.m_dSideAngle) ; + pOffs2->ToLoc( frPocket) ; + BBox3d b3Pocket ; + pOffs2->GetLocalBBox( b3Pocket) ; + Point3d ptMin ; double dDimX, dDimY, dDimZ ; + b3Pocket.GetMinDim( ptMin, dDimX, dDimY, dDimZ) ; + + // passi in Y + int nYStep = static_cast( ceil( ( dDimY + 2 * dExtra) / GetSideStep())) ; + double dYStep = ( nYStep > 0 ? ( dDimY + 2 * dExtra) / nYStep : 0) ; + -- nYStep ; + + // calcolo le linee di svuotatura + const double EXP_LEN = 1.0 ; + for ( int j = 1 ; j <= nStep ; ++ j) { + for ( int i = 1 ; i <= nYStep ; ++ i) { + // definisco la linea + PtrOwner pLine( CreateCurveLine()) ; + Point3d ptStart( ptMin.x - EXP_LEN, ptMin.y + ( - dExtra + i * dYStep), ptMin.z + dDimZ) ; + if ( IsNull( pLine) || ! pLine->SetPVL( ptStart, X_AX, dDimX + 2 * EXP_LEN)) { + m_pMchMgr->SetLastError( 2413, "Error in PocketingNT : Toolpath not computable") ; + return false ; + } + // calcolo la classificazione della curva rispetto al contorno esterno offsettato + IntersCurveCurve intCC( *pLine, *pOffs2) ; + CRVCVECTOR ccClass ; + if ( ! intCC.GetCurveClassification( 0, EPS_SMALL, ccClass)) { + m_pMchMgr->SetLastError( 2413, "Error in PocketingNT : Toolpath not computable") ; + return false ; + } + // determino gli intervalli di curva da conservare + Intervals inOk ; + for ( auto& ccOne : ccClass) { + if ( ccOne.nClass == CRVC_IN || ccOne.nClass == CRVC_ON_P || ccOne.nClass == CRVC_ON_M) + inOk.Add( ccOne.dParS, ccOne.dParE) ; + } + // inserisco i tratti validi + double dParS, dParE ; + bool bFound = inOk.GetFirst( dParS, dParE) ; + while ( bFound) { + // calcolo inizio con affondamento + Point3d ptS ; pLine->GetPointD1D2( dParS, ICurve::FROM_PLUS, ptS) ; + ptS.ToGlob( frPocket) ; + ptS.Translate( - vtTool * ( dDepth - dElev + j * dStep)) ; + // determino inizio attacco + Point3d ptP ; + if ( ! CalcLeadInStart( ptS, frPocket.VersX(), vtExtr, nullptr, ptP)) + return false ; + // determino elevazione su inizio attacco + double dStElev ; + if ( ! GetElevation( m_nPhase, ptS - 10 * EPS_SMALL * vtTool, vtTool, GetRadiusForStartEndElevation(), vtTool, dStElev)) + dStElev = j * dStep ; + bool 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) + dStElev = max( dStElev, j * dStep) ; + dStElev -= ( ptP - ptS) * vtExtr ; + // sempre approccio di collegamento + if ( ! AddLinkApproach( ptP, vtTool, dSafeZ, dSafeAggrBottZ, dStElev, dAppr, bSplitArcs)) { + m_pMchMgr->SetLastError( 2418, "Error in PocketingNT : Link not computable") ; + return false ; + } + // aggiungo attacco + SetFeed( GetStartFeed()) ; + if ( ! AddLeadIn( ptP, ptS, frPocket.VersX(), vtExtr, pCompo, nullptr, ! m_Params.m_bInvert, bSplitArcs, true)) { + m_pMchMgr->SetLastError( 2415, "Error in PocketingNT : LeadIn not computable") ; + return false ; + } + // calcolo fine con affondamento + Point3d ptE ; pLine->GetPointD1D2( dParE, ICurve::FROM_MINUS, ptE) ; + ptE.ToGlob( frPocket) ; + ptE.Translate( - vtTool * ( dDepth - dElev + j * dStep)) ; + // movimento al punto finale + SetFeed( GetFeed()) ; + if ( AddLinearMove( ptE, bSplitArcs) == GDB_ID_NULL) + return false ; + // risalita + Point3d ptQ ; + double dEndElev = dElev ; + SetFeed( GetEndFeed()) ; + if ( ! AddLeadOut( ptE, frPocket.VersX(), vtExtr, nullptr, bSplitArcs, true, ptQ, dEndElev)) { + m_pMchMgr->SetLastError( 2416, "Error in PocketingNT : LeadOut not computable") ; + return false ; + } + // recupero successivo intervallo + bFound = inOk.GetNext( dParS, dParE) ; + // se ultimo movimento di ultima area, aggiungo retrazione globale + if ( j == nStep && i == nYStep && ! bFound && OffsCrv2.GetCurveCount() == 0) { + if ( ! AddRetract( ptQ, vtTool, dSafeZ, dSafeAggrBottZ, dEndElev, dAppr, bSplitArcs)) { + m_pMchMgr->SetLastError( 2417, "Error in PocketingNT : Retract not computable") ; + return false ; + } + } + // altrimenti aggiungo retrazione di collegamento + else { + if ( ! AddLinkRetract( ptQ, vtTool, dSafeZ, dSafeAggrBottZ, dEndElev, dAppr, bSplitArcs)) { + m_pMchMgr->SetLastError( 2418, "Error in PocketingNT : Link not computable") ; + return false ; + } + } + } + } + } + } + + return true ; +} + +//---------------------------------------------------------------------------- +bool +PocketingNT::AddSpiralIn( const ICurveComposite* pCompo, const Vector3d& vtTool, const Vector3d& vtExtr, + double dDepth, double dElev, double dOkStep, bool bSplitArcs, bool bMidOpen, + const Point3d& ptMidOpen, const Vector3d& vtMidOut, int nPathId) +{ + // recupero distanze di sicurezza + double dSafeZ = GetSafeZ() ; + double dSafeAggrBottZ = GetSafeAggrBottZ() ; + // lunghezza di approccio/retrazione + double dAppr = m_Params.m_dStartPos ; + + // ciclo sulle regioni + const int MAX_REGS = 50 ; + int nReg = 0 ; + while ( nReg < MAX_REGS) { + + // calcolo la spirale dall'esterno all'interno e la curva che unisce inizio e fine + PtrOwner pMCrv( CreateCurveComposite()) ; + PtrOwner pRCrv( CreateCurveComposite()) ; + if ( IsNull( pMCrv) || IsNull( pRCrv)) { + m_pMchMgr->SetLastError( 2411, "Error in PocketingNT : 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 PocketingNT : 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 ; + if ( ! CalcSpiral( pCompo, nReg, bSplitArcs, pMCrv, pRCrv, nPathId, 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 PocketingNT : Toolpath not computable") ; + return false ; + } + } + + // se prima regione e gestione lato aperto ( caso non ottimizzato) + bool bOutStart = ( nReg == 1 && bMidOpen) ; + if ( bOutStart && ! bOptimizedTrap) { + // calcolo il punto fuori + Point3d ptOut = ptMidOpen + vtMidOut * ( 0.5 * m_TParams.m_dDiam + max( dSafeZ, m_dOpenMinSafe)) ; + // verifico che il punto sia veramente fuori dal grezzo + double dStElev ; + 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) ; + } + pRCrv->AddLine( ptOut, true) ; + // premetto alla spirale la partenza da fuori + pMCrv->AddLine( ptOut, 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) ; + } + + // verifico se ingresso da considerare fuori grezzo anche se dentro + bool bForcedOutStart = ( bMidOpen && 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 ( ! LeadInRawIsOk()) { + m_pMchMgr->SetLastError( 2431, "Error in PocketingNT : LeadIn with Mill NoTip in material") ; + return false ; + } + } + + // determino numero e affondamento degli step + int nStep = 1 ; + nStep = max( 1, static_cast( ceil( dElev / dOkStep))) ; + double dStep = dElev / nStep ; + + int nMaxInd = pMCrv->GetCurveCount() - 1 ; + int nMaxRInd = pRCrv->GetCurveCount() - 1 ; + + // ciclo sugli step + Point3d ptP1 ; + for ( int j = 1 ; j <= nStep ; ++ j) { + // se sono nel caso ottimizzato e ho attacco e uscita entrambi dentro/fuori dal grezzo, ad ogni step inverto la direzione della curva + 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) { + // 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 || m_bTiltingTab) + dStElev = max( dStElev, dStep) ; + dStElev -= ( ptP1 - ptStart) * vtExtr ; + // se attacco a zigzag o a spirale o a scivolo, l'elevazione va nell'attacco + if ( GetLeadInType() == POCKET_LI_ZIGZAG || + GetLeadInType() == POCKET_LI_HELIX || + GetLeadInType() == POCKET_LI_GLIDE) { + ptP1 += vtExtr * ( dStElev + LIO_ELEV_TOL) ; + dStElev = -LIO_ELEV_TOL ; + } + // approccio al punto iniziale + if ( ! AddApproach( ptP1, vtTool, dSafeZ, dSafeAggrBottZ, dStElev, dAppr, bSplitArcs, bOutStart || bForcedOutStart)) { + m_pMchMgr->SetLastError( 2414, "Error in PocketingNT : Approach not computable") ; + return false ; + } + // aggiungo attacco + SetFeed( GetStartFeed()) ; + if ( ! AddLeadIn( ptP1, ptStart, vtStart, vtExtr, pCompo, pRCrv, ! m_Params.m_bInvert, bSplitArcs, bOutStart || bForcedOutStart)) { + m_pMchMgr->SetLastError( 2415, "Error in PocketingNT : LeadIn not computable") ; + return false ; + } + } + // altrimenti solo collegamento + else { + SetFeed( GetStartFeed()) ; + GetCurrPos( ptP1) ; + if ( ! AddLeadIn( ptP1, ptStart, vtStart, vtExtr, pCompo, pRCrv, ! m_Params.m_bInvert, bSplitArcs, bOutStart || bForcedOutStart)) { + m_pMchMgr->SetLastError( 2418, "Error in PocketingNT : Link not computable") ; + return false ; + } + } + } + // elaborazioni sulla curva corrente + if ( pCurve->GetType() == CRV_LINE) { + ICurveLine* pLine = GetCurveLine( pCurve) ; + Point3d ptP3 = pLine->GetEnd() ; + SetFeed( GetFeed()) ; + if ( AddLinearMove( ptP3, bSplitArcs) == GDB_ID_NULL) + return false ; + } + else if ( pCurve->GetType() == CRV_ARC) { + ICurveArc* pArc = GetCurveArc( pCurve) ; + Point3d ptCen = pArc->GetCenter() ; + double dAngCen = pArc->GetAngCenter() ; + Vector3d vtN = pArc->GetNormVersor() ; + Point3d ptP3 ; + pArc->GetEndPoint( ptP3) ; + SetFeed( GetFeed()) ; + if ( AddArcMove( ptP3, ptCen, dAngCen, vtN) == GDB_ID_NULL) + return false ; + } + // se ultima entità + if ( i == nMaxInd) { + // se step intermedio, ritorno all'inizio direttamente + if ( j < nStep) { + // se necessario ritorno all'inizio + if ( nMaxRInd >= 0) { + // copio la curva di ritorno + PtrOwner pRet( pRCrv->Clone()) ; + if ( IsNull( pRet)) + return false ; + // aggiungo affondamento + pRet->Translate( - vtTool * ( dDepth - dElev + j * dStep)) ; + // se attacco a scivolo, accorcio della lunghezza dell'attacco + if ( GetLeadInType() == POCKET_LI_GLIDE) { + double dLen ; pRet->GetLength( dLen) ; + if ( dLen > m_Params.m_dLiTang + 10 * EPS_SMALL) + pRet->TrimEndAtLen( dLen - m_Params.m_dLiTang) ; + else + pRet->Clear() ; + } + // emetto + SetFeed( GetFeed()) ; + if ( pRet->GetCurveCount() > 0 && AddCurveMove( pRet) == GDB_ID_NULL) + return false ; + } + } + // atrimenti ultimo step, uscita e retrazione + else { + // dati fine entità + Point3d ptEnd ; + pCurve->GetEndPoint( ptEnd) ; + Vector3d vtEnd ; + pCurve->GetEndDir( vtEnd) ; + // aggiungo uscita + Point3d ptP1 ; + double dEndElev = dElev ; + SetFeed( GetEndFeed()) ; + if ( ! AddLeadOut( ptEnd, vtEnd, vtExtr, pRCrv, bSplitArcs, false, ptP1, dEndElev)) { + m_pMchMgr->SetLastError( 2416, "Error in PocketingNT : LeadOut not computable") ; + return false ; + } + // aggiungo retrazione + if ( ! AddRetract( ptP1, vtTool, dSafeZ, dSafeAggrBottZ, dEndElev, dAppr, bSplitArcs)) { + m_pMchMgr->SetLastError( 2417, "Error in PocketingNT : Retract not computable") ; + return false ; + } + } + } + } + } + } + return true ; +} + +//---------------------------------------------------------------------------- +bool +PocketingNT::AddSpiralOut( const ICurveComposite* pCompo, const Vector3d& vtTool, const Vector3d& vtExtr, + double dDepth, double dElev, double dOkStep, bool bSplitArcs, int nPathId) +{ + // recupero distanze di sicurezza + double dSafeZ = GetSafeZ() ; + double dSafeAggrBottZ = GetSafeAggrBottZ() ; + // lunghezza di approccio/retrazione + double dAppr = m_Params.m_dStartPos ; + + // ciclo sulle regioni + const int MAX_REGS = 50 ; + int nReg = 0 ; + while ( nReg < MAX_REGS) { + + // calcolo la spirale dall'interno all'esterno + PtrOwner pMCrv( CreateCurveComposite()) ; + PtrOwner pRCrv( CreateCurveComposite()) ; + if ( IsNull( pMCrv) || IsNull( pRCrv)) { + m_pMchMgr->SetLastError( 2411, "Error in PocketingNT : 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 PocketingNT : 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 ; + if ( ! CalcSpiral( pCompo, nReg, bSplitArcs, pMCrv, pRCrv, nPathId, 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 PocketingNT : 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) ; + } + + // 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 PocketingNT : 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() ; + } + + // determino numero e affondamento degli step + int nStep = 1 ; + nStep = max( 1, static_cast( ceil( dElev / dOkStep))) ; + double dStep = dElev / nStep ; + + int nMaxInd = pMCrv->GetCurveCount() - 1 ; + int nMaxRInd = pRCrv->GetCurveCount() - 1 ; + + // ciclo sugli step + Point3d ptP1 ; + for ( int j = 1 ; j <= nStep ; ++ j) { + // se sono nel caso ottimizzato e ho attacco e uscita entrambi dentro/fuori dal grezzo, ad ogni step inverto la direzione della curva + 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) { + // determino inizio attacco + if ( ! CalcLeadInStart( ptStart, vtStart, vtExtr, pRCrv, ptP1)) { + m_pMchMgr->SetLastError( 2415, "Error in PocketingNT : 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 || m_bTiltingTab) + dStElev = max( dStElev, dStep) ; + dStElev -= ( ptP1 - ptStart) * vtExtr ; + // se attacco a zigzag o a spirale o a scivolo, l'elevazione va nell'attacco + if ( GetLeadInType() == POCKET_LI_ZIGZAG || + GetLeadInType() == POCKET_LI_HELIX || + GetLeadInType() == POCKET_LI_GLIDE) { + ptP1 += vtExtr * ( dStElev + LIO_ELEV_TOL) ; + dStElev = -LIO_ELEV_TOL ; + } + // approccio al punto iniziale + if ( ! AddApproach( ptP1, vtTool, dSafeZ, dSafeAggrBottZ, dStElev, dAppr, bSplitArcs, false)) { + m_pMchMgr->SetLastError( 2414, "Error in PocketingNT : Approach not computable") ; + return false ; + } + // aggiungo attacco + SetFeed( GetStartFeed()) ; + if ( ! AddLeadIn( ptP1, ptStart, vtStart, vtExtr, pCompo, pRCrv, m_Params.m_bInvert, bSplitArcs, bOutStart)) { + m_pMchMgr->SetLastError( 2415, "Error in PocketingNT : LeadIn not computable") ; + return false ; + } + } + // altrimenti solo collegamento + else { + SetFeed( GetStartFeed()) ; + GetCurrPos( ptP1) ; + if ( ! AddLeadIn( ptP1, ptStart, vtStart, vtExtr, pCompo, pRCrv, m_Params.m_bInvert, bSplitArcs, bOutStart)) { + m_pMchMgr->SetLastError( 2418, "Error in PocketingNT : Link not computable") ; + return false ; + } + } + } + // elaborazioni sulla curva corrente + if ( pCurve->GetType() == CRV_LINE) { + ICurveLine* pLine = GetCurveLine( pCurve) ; + Point3d ptP3 = pLine->GetEnd() ; + SetFeed( GetFeed()) ; + if ( AddLinearMove( ptP3, bSplitArcs) == GDB_ID_NULL) + return false ; + } + else if ( pCurve->GetType() == CRV_ARC) { + ICurveArc* pArc = GetCurveArc( pCurve) ; + Point3d ptCen = pArc->GetCenter() ; + double dAngCen = pArc->GetAngCenter() ; + Vector3d vtN = pArc->GetNormVersor() ; + Point3d ptP3 ; + pArc->GetEndPoint( ptP3) ; + SetFeed( GetFeed()) ; + if ( AddArcMove( ptP3, ptCen, dAngCen, vtN) == GDB_ID_NULL) + return false ; + } + // se ultima entità + if ( i == nMaxInd) { + // se step intermedio + if ( j < nStep) { + // se necessario ritorno all'inizio + if ( nMaxRInd >= 0) { + // copio la curva di ritorno + PtrOwner pRet( pRCrv->Clone()) ; + if ( IsNull( pRet)) + return false ; + // aggiungo affondamento + pRet->Translate( - vtTool * ( dDepth - dElev + j * dStep)) ; + // se attacco a scivolo, accorcio della lunghezza dell'attacco + if ( GetLeadInType() == POCKET_LI_GLIDE) { + double dLen ; pRet->GetLength( dLen) ; + if ( dLen > m_Params.m_dLiTang + 10 * EPS_SMALL) + pRet->TrimEndAtLen( dLen - m_Params.m_dLiTang) ; + else + pRet->Clear() ; + } + // emetto + SetFeed( GetFeed()) ; + if ( pRet->GetCurveCount() > 0 && AddCurveMove( pRet) == GDB_ID_NULL) + return false ; + } + } + // atrimenti ultimo step, uscita e retrazione + else { + // dati fine entità + Point3d ptEnd ; + pCurve->GetEndPoint( ptEnd) ; + Vector3d vtEnd ; + pCurve->GetEndDir( vtEnd) ; + // aggiungo uscita + Point3d ptQ ; + double dEndElev = dElev ; + SetFeed( GetEndFeed()) ; + if ( ! AddLeadOut( ptEnd, vtEnd, vtExtr, pRCrv, bSplitArcs, false, ptQ, dEndElev)) { + m_pMchMgr->SetLastError( 2416, "Error in PocketingNT : LeadOut not computable") ; + return false ; + } + // aggiungo retrazione + if ( ! AddRetract( ptQ, vtTool, dSafeZ, dSafeAggrBottZ, dEndElev, dAppr, bSplitArcs)) { + m_pMchMgr->SetLastError( 2417, "Error in PocketingNT : Retract not computable") ; + return false ; + } + } + } + } + } + } + return true ; +} + +//---------------------------------------------------------------------------- +bool +PocketingNT::CalcSpiral( const ICurveComposite* pCompo, int nReg, bool bSplitArcs, + ICurveComposite* pMCrv, ICurveComposite* pRCrv, int nPathId, 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() ; + + // se circonferenza, chiamo la funzione specializzata + Point3d ptCen ; Vector3d vtN ; double dRad ; bool bCCW ; + if ( pCompo->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) + return CalcCircleSpiral( ptCen, vtN, dRad - dOffs, dIntRad, bSplitArcs, pMCrv, pRCrv) ; + else + return true ; + } + + // recupero la curva originaria della svuotatura (non allargata per lati aperti) per verificare caso trapezoide + int nCrvId = m_pGeomDB->GetFirstInGroup( nPathId) ; + PtrOwner pCrvPocket( CloneCurveComposite( m_pGeomDB->GetGeoObj( nCrvId))) ; + if ( IsNull( pCrvPocket)) + return false ; + bool bSomeOpen ; + SetCurveAllTempProp( nCrvId, GetForcedClosed(), pCrvPocket, &bSomeOpen) ; + pCrvPocket->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL) ; + + Point3d pt ; + Vector3d vtB1, vtL1, vtB2 ; + if ( pCrvPocket->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 = m_Params.m_dSideStep ; + FromString( ExtractInfo( m_Params.m_sUserNotes, "MaxOptSize="), dMaxOptSize) ; + if ( ( ( bSomeOpen && dPocketSize < m_TParams.m_dDiam + EPS_SMALL) || abs( dPocketSize - m_TParams.m_dDiam) < EPS_SMALL) && + dPocketSize < dMaxOptSize + 10 * EPS_SMALL) { + if ( nReg == 0) { + CalcTrapezoidSpiral( pCrvPocket, vtDir, dPocketSize, pMCrv, pRCrv, bOptimizedTrap) ; + if ( bOptimizedTrap) + return true ; + } + else + return true ; + } + } + + // ciclo di offset verso l'interno + const int MAX_ITER = 1000 ; + int nIter = 0 ; + ICURVEPOVECTOR vOffs ; + ICURVEPOVECTOR vCrvStack ; + DBLVECTOR vRadStack ; + PtrOwner pOffs ; + double dCurrRad = GetCurveRadius( pCompo) ; + while ( nIter < MAX_ITER) { + // se l'offset richiesto è pari al valore limite per la curva ne modifico leggermente il valore per evitare problemi con + // le tolleranze di vroni + double dMaxOffs ; + if ( nIter == 0) + CalcCurveLimitOffset( *pCompo, dMaxOffs) ; + else + CalcCurveLimitOffset( *pOffs, dMaxOffs) ; + if ( abs( dMaxOffs - dOffs) < EPS_SMALL) + dOffs -= EPS_SMALL ; + + // calcolo + OffsetCurve OffsCrv ; + if ( ! OffsCrv.Make( ( nIter == 0 ? (ICurve*) pCompo : pOffs), - dOffs, ICurve::OFF_FILLET) || + ( nIter == 0 && nReg == 0 && OffsCrv.GetCurveCount() == 0)) { + m_pMchMgr->SetLastError( 2412, "Error in PocketingNT : Offset not computable") ; + return false ; + } + // se primo offset e richiesta regione oltre il massimo, esco + if ( nIter == 0 && nReg >= OffsCrv.GetCurveCount()) + return true ; + // recupero le curve di offset e le metto sullo stack (se primo offset solo quella voluta) + int nCount = 0 ; + ICurve* pCrv = OffsCrv.GetLongerCurve() ; + while ( pCrv != nullptr) { + if ( nIter != 0 || nReg == nCount) { + vCrvStack.emplace_back( pCrv) ; + vRadStack.emplace_back( dCurrRad) ; + if ( nIter == 0) + break ; + } + else + delete( pCrv) ; + pCrv = OffsCrv.GetCurve() ; + ++ nCount ; + } + // recupero la prossima curva di offset + PtrOwner pNextOffs ; + if ( ! vCrvStack.empty()) { + pNextOffs.Set( vCrvStack.back()) ; + vCrvStack.pop_back() ; + dCurrRad = vRadStack.back() ; + vRadStack.pop_back() ; + } + double dRad = GetCurveRadius( pNextOffs) ; + bool bNextOk = ( dRad > EPS_ZERO && dRad < dCurrRad) ; + bool bSmallRad = ( nIter == 0 ? dOffs < dTRad + GetOffsR() + EPS_ZERO : dOffs < dTRad + EPS_ZERO) ; + // se completato step di offset, accodo la curva offsettata al percorso di lavoro + if ( ! IsNull( pOffs) && ( bNextOk || bSmallRad)) { + // inserisco l'offset nel vettore + vOffs.emplace_back( Release( pOffs)) ; + } + // se offset va bene + if ( bNextOk) { + // sistemo per prossimo step + dCurrRad = dRad ; + pOffs.Set( pNextOffs) ; + // nuovo valore pari allo step + dOffs = GetSideStep() ; + } + // se altrimenti riducibile, provo con offset ridotto al raggio utensile + else if ( ! bSmallRad) { + // nuovo valore pari al raggio + dOffs = ( nIter == 0 ? dTRad + GetOffsR() : dTRad) ; + } + // altrimenti esco + else + break ; + // incremento contatore iterazioni + ++ nIter ; + } + + // calcolo i collegamenti + ICURVEPOVECTOR vLinks( vOffs.size()) ; + for ( int i = 1 ; i < int( vOffs.size()) ; ++ i) { + // punti di inizio e fine + Point3d ptStart ; + vOffs[i-1]->GetEndPoint( ptStart) ; + Point3d ptEnd ; + vOffs[i]->GetStartPoint( ptEnd) ; + // calcolo il collegamento (garantendo che non esca dalla svuotatura) + PtrOwner pCrvLink( CreateCurveComposite()) ; + if ( CalcBoundedLink( ptStart, ptEnd, vOffs[0], pCrvLink)) + vLinks[i].Set( pCrvLink) ; + else { + m_pMchMgr->SetLastError( 2413, "Error in PocketingNT : Toolpath not computable") ; + return false ; + } + } + + // calcolo il percorso di ritorno + if ( vOffs.size() >= 2) { + // punti di inizio e fine + Point3d ptStart ; + vOffs.back()->GetEndPoint( ptStart) ; + Point3d ptEnd ; + vOffs.front()->GetStartPoint( ptEnd) ; + // calcolo il ritorno (garantendo che non esca dalla svuotatura) + PtrOwner pCrvLink( CreateCurveComposite()) ; + if ( CalcBoundedLink( ptStart, ptEnd, vOffs[0], 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( 2419, "Error in PocketingNT : Linear Approx not computable") ; + return false ; + } + VerifyArcs( pRCrv) ; + } + else { + m_pMchMgr->SetLastError( 2413, "Error in PocketingNT : Toolpath not computable") ; + return false ; + } + } + + // creo il percorso di lavoro a partire dalla raccolta degli offset e dei collegamenti + for ( int i = 0 ; i < int( vOffs.size()) ; ++ i) { + // se collegamento da aggiungere + if ( ! IsNull( vLinks[i])) { + int nCrvsCount0 = pMCrv->GetCurveCount() ; + // accodo nel percorso di lavorazione + pMCrv->AddCurve( Release( vLinks[i])) ; + // 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) ; + } + } + // se richiesta percorrenza invertita + if ( m_Params.m_bInvert) + vOffs[i]->Invert() ; + // aggiungo la curva + pMCrv->AddCurve( Release( vOffs[i])) ; + } + + // verifico il percorso di lavoro + if ( pMCrv->GetCurveCount() == 0) { + m_pMchMgr->SetLastError( 2413, "Error in PocketingNT : Toolpath not computable") ; + return false ; + } + // se necessario, approssimo archi con rette + if ( bSplitArcs && ! ApproxWithLines( pMCrv)) { + m_pMchMgr->SetLastError( 2419, "Error in PocketingNT : Linear Approx not computable") ; + return false ; + } + // eventuale sistemazione archi + VerifyArcs( pMCrv) ; + + // setto estrusione + Vector3d vtExtr ; + if ( pCompo->GetExtrusion( vtExtr)) + pMCrv->SetExtrusion( vtExtr) ; + + return true ; +} + +//---------------------------------------------------------------------------- +bool +PocketingNT::CalcBoundedLink( const Point3d& ptStart, const Point3d& ptEnd, const ICurve* pCrvBound, + ICurveComposite* pCrvLink) +{ + // recupero il vettore estrusione + Vector3d vtExtr ; + pCrvBound->GetExtrusion( vtExtr) ; + // determino il riferimento naturale della svuotatura (OCS con il vettore estrusione come asse Z) + Frame3d frLoc ; + frLoc.Set( ORIG, vtExtr) ; + // porto la curva di contenimento in locale a questo riferimento + CurveLocal CrvOutLoc( pCrvBound, GLOB_FRM, frLoc) ; + + // creo la retta che li unisce + PtrOwner pLine( CreateCurveLine()) ; + if ( IsNull( pLine) || ! pLine->Set( ptStart, ptEnd)) + return false ; + pLine->SetExtrusion( vtExtr) ; + // la porto in locale al riferimento della svuotatura + CurveLocal LineLoc( pLine, GLOB_FRM, frLoc) ; + + // classifico la curva di collegamento rispetto a quella di contenimento + CRVCVECTOR ccClass ; + IntersCurveCurve intCC( *LineLoc, *CrvOutLoc) ; + intCC.GetCurveClassification( 0, EPS_SMALL, ccClass) ; + // se nessuno o un solo tratto e interno, la retta è il collegamento + if ( ccClass.empty() || ( ccClass.size() == 1 && ccClass[0].nClass == CRVC_IN)) { + pCrvLink->AddCurve( Release( pLine)) ; + return true ; + } + // altrimenti combino i tratti interni di retta con tratti opportuni della curva di contenimento + else { + PtrOwner pCompo( CreateCurveComposite()) ; + if ( IsNull( pCompo)) + return false ; + for ( int j = 0 ; j < int( ccClass.size()) ; ++ j) { + if ( ccClass[j].nClass == CRVC_IN || ccClass[j].nClass == CRVC_ON_P || ccClass[j].nClass == CRVC_ON_M) + pCompo->AddCurve( pLine->CopyParamRange( ccClass[j].dParS, ccClass[j].dParE)) ; + else if ( ccClass[j].nClass == CRVC_OUT) { + Point3d ptS ; + pLine->GetPointD1D2( ccClass[j].dParS, ICurve::FROM_PLUS, ptS) ; + double dOffS ; + pCrvBound->GetParamAtPoint( ptS, dOffS) ; + Point3d ptE ; + pLine->GetPointD1D2( ccClass[j].dParE, ICurve::FROM_MINUS, ptE) ; + double dOffE ; + pCrvBound->GetParamAtPoint( ptE, dOffE) ; + // recupero i due possibili percorsi e uso il più corto + PtrOwner pCrvA( pCrvBound->CopyParamRange( dOffS, dOffE)) ; + PtrOwner pCrvB( pCrvBound->CopyParamRange( dOffE, dOffS)) ; + if ( IsNull( pCrvA) || IsNull( pCrvB)) + return false ; + double dLenA ; pCrvA->GetLength( dLenA) ; + double dLenB ; pCrvB->GetLength( dLenB) ; + if ( dLenA < dLenB) { + pCompo->AddCurve( Release( pCrvA)) ; + } + else { + pCrvB->Invert() ; + pCompo->AddCurve( Release( pCrvB)) ; + } + } + } + pCrvLink->AddCurve( Release( pCompo)) ; + return true ; + } +} + +//------------------------------------------------------------------------------ +bool +PocketingNT::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 +PocketingNT::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 PocketingNT : 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 PocketingNT : Toolpath not computable") ; + return false ; + } + Vector3d vtDir = pArc->GetStartVersor() ; + pMCrv->AddCurve( Release( pArc)) ; + // se richiesta percorrenza invertita + if ( m_Params.m_bInvert) + pMCrv->Invert() ; + + // se raggio esterno maggiore dell'interno + if ( dOutRad > dIntRad + 10 * EPS_SMALL) { + + // aggiungo le semicirconferenze della spirale ( devono essere in numero dispari) + int nStep = int( ceil( ( dOutRad - dIntRad) / ( 0.5 * GetSideStep()))) ; + if ( IsEven( nStep)) + nStep += 1 ; + double dStep = ( dOutRad - dIntRad) / nStep ; + for ( int i = 1 ; i <= nStep ; ++ i) { + if ( ! IsEven( i)) + pMCrv->AddArcTg( ptCen - vtDir * ( dOutRad - i * dStep)) ; + else + pMCrv->AddArcTg( ptCen + vtDir * ( dOutRad - i * dStep)) ; + } + + // aggiungo la circonferenza interna + pMCrv->AddArcTg( ptCen + vtDir * dIntRad) ; + pMCrv->AddArcTg( ptCen - vtDir * dIntRad) ; + } + + // verifico il percorso di lavoro + if ( pMCrv->GetCurveCount() == 0) { + m_pMchMgr->SetLastError( 2413, "Error in PocketingNT : Toolpath not computable") ; + return false ; + } + // se necessario, approssimo con rette + if ( bSplitArcs && ! ApproxWithLines( pMCrv)) { + m_pMchMgr->SetLastError( 2419, "Error in PocketingNT : Linear Approx not computable") ; + return false ; + } + // eventuale sistemazione archi + VerifyArcs( pMCrv) ; + + // calcolo l'eventuale percorso di ritorno + Point3d ptStart ; pMCrv->GetStartPoint( ptStart) ; + Point3d ptEnd ; pMCrv->GetEndPoint( ptEnd) ; + Vector3d vtStart ; pMCrv->GetStartDir( vtStart) ; + if ( ! AreSamePointApprox( ptStart, ptEnd)) { + PtrOwner pArc2( CreateCurveArc()) ; + if ( IsNull( pArc2) || ! pArc2->Set2PVN( ptStart, ptEnd, - vtStart, vtN)) { + m_pMchMgr->SetLastError( 2420, "Error in PocketingNT : Return toolpath not computable") ; + return false ; + } + pRCrv->AddCurve( Release( pArc2)) ; + // inverto + pRCrv->Invert() ; + // se necessario, approssimo con rette + if ( bSplitArcs && ! ApproxWithLines( pRCrv)) { + m_pMchMgr->SetLastError( 2419, "Error in PocketingNT : Linear Approx not computable") ; + return false ; + } + // eventuale sistemazione archi + VerifyArcs( pRCrv) ; + } + + return true ; +} + +//---------------------------------------------------- +bool +PocketingNT::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 +PocketingNT::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 +PocketingNT::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 +PocketingNT::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 +PocketingNT::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 +PocketingNT::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 +PocketingNT::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) ; + } + 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 = 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 ( 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 && CalcDistanceFromRawSurface( m_nPhase, ptP, vtNorm, dDistMin, vtNormMin)) { + if ( abs( dDistMin) < abs( dDist) && abs( dDistMin) > EPS_SMALL) { + dDistRef = dDistMin ; + dCorr = dDist / dDistMin ; + } + } + + // se vicino al bordo del grezzo + if ( 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 ; + + // 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 +PocketingNT::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 PocketingNT : 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( 2419, "Error in PocketingNT : Linear Approx not computable") ; + return false ; + } + VerifyArcs( pRCrv) ; + } + else { + m_pMchMgr->SetLastError( 2413, "Error in PocketingNT : 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( 2419, "Error in PocketingNT : Linear Approx not computable") ; + return false ; + } + VerifyArcs( pMCrv) ; + + pMCrv->ToGlob( frLoc) ; + pRCrv->ToGlob( frLoc) ; + return true ; +} + +//---------------------------------------------------------------------------- +bool +PocketingNT::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 PocketingNT : 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 +PocketingNT::AddApproach( const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dSafeAggrBottZ, + double dElev, double dAppr, bool bSplitArcs, 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 ( ! GetAggrBottDistanceFromRawSide( m_nPhase, ptP, m_vtAggrBottom, ( m_AggrBottom.dEncH + dSafeZ), 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) ; + // se richiede speciale rotazione + if ( m_AggrBottom.nType == 1) { + // punto ruotato + Point3d ptP00 = ptP0 + Z_AX * ( m_AggrBottom.dEncV + m_TParams.m_dLen + dAggZ - dElev) ; + Vector3d vtAux = m_vtAggrBottom ; + vtAux.Rotate( Z_AX, 0, 1) ; + SetAuxDir( vtAux) ; + if ( AddRapidStart( ptP00, MCH_CL_AGB_DWN) == GDB_ID_NULL) + return false ; + // vado al punto standard + SetAuxDir( m_vtAggrBottom) ; + SetFlag( 0) ; + if ( AddRapidMove( ptP0, bSplitArcs, MCH_CL_AGB_IN) == GDB_ID_NULL) + return false ; + } + // se altrimenti con rotazione per minimizzare la sporgenza + else if ( m_AggrBottom.nType == 3) { + // punto standard ruotato + Vector3d vtAux = m_vtAggrBottom ; + vtAux.Rotate( Z_AX, 0, 1) ; + SetAuxDir( vtAux) ; + if ( AddRapidStart( ptP0, MCH_CL_AGB_IN) == GDB_ID_NULL) + return false ; + // la rotazione viene eseguita nel movimento successivo al punto sopra l'inizio lavorazione + SetAuxDir( m_vtAggrBottom) ; + SetFlag( 0) ; + } + // 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) { + Point3d ptP1 = ptP + vtTool * ( dElev + dAppr) ; + // se distanza di sicurezza minore di distanza di inizio + if ( dSafeDist < dAppr + 10 * EPS_SMALL) { + // 1 -> punto sopra inizio + if ( AddRapidStartOrMove( ptP1, ! m_bAggrBottom, bSplitArcs) == GDB_ID_NULL) + return false ; + } + else { + // 1a -> punto molto sopra inizio + Point3d ptP1a = ptP1 + vtTool * ( dSafeDist - dAppr) ; + if ( AddRapidStartOrMove( ptP1a, ! m_bAggrBottom, bSplitArcs) == GDB_ID_NULL) + return false ; + // 1 -> punto sopra inizio + if ( ( dElev + dAppr) > 10 * EPS_SMALL || (( dElev + dAppr) > -EPS_ZERO && dAppr > EPS_SMALL)) { + SetFlag( 0) ; + if ( AddRapidMove( ptP1, bSplitArcs) == GDB_ID_NULL) + return false ; + } + else + ptP1 = ptP1a ; + } + // affondo al punto iniziale + SetFlag( 0) ; + bool bStartFeed = ( bOutStart || m_TParams.m_nType == TT_MILL_NOTIP) ; + SetFeed( bStartFeed ? GetStartFeed() : GetTipFeed()) ; + if ( ! AreSamePointApprox( ptP1, ptP) && AddLinearMove( ptP, bSplitArcs) == GDB_ID_NULL) + return false ; + } + else { + // affondo diretto al punto iniziale + SetFlag( 0) ; + if ( AddRapidStartOrMove( ptP, ! m_bAggrBottom, bSplitArcs) == GDB_ID_NULL) + return false ; + } + return true ; +} + +//---------------------------------------------------------------------------- +bool +PocketingNT::AddLinkApproach( const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dSafeAggrBottZ, + double dElev, double dAppr, bool bSplitArcs, 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, bSplitArcs) == GDB_ID_NULL) + return false ; + } + // affondo al punto iniziale + SetFlag( 0) ; + SetFeed( bOutStart ? GetStartFeed() : GetTipFeed()) ; + if ( AddLinearMove( ptP, bSplitArcs) == GDB_ID_NULL) + return false ; + } + else { + // affondo diretto al punto iniziale + SetFlag( 0) ; + if ( AddRapidMove( ptP, bSplitArcs) == GDB_ID_NULL) + return false ; + } + return true ; +} + +//---------------------------------------------------------------------------- +bool +PocketingNT::AddLinkRetract( const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dSafeAggrBottZ, + double dElev, double dAppr, bool bSplitArcs) +{ + // 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, bSplitArcs) == GDB_ID_NULL) + return false ; + } + return true ; +} + +//---------------------------------------------------------------------------- +bool +PocketingNT::AddRetract( const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dSafeAggrBottZ, + double dElev, double dAppr, bool bSplitArcs) +{ + // 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 ( ! GetAggrBottDistanceFromRawSide( m_nPhase, ptP, m_vtAggrBottom, ( m_AggrBottom.dEncH + dSafeZ), 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, bSplitArcs) == 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, bSplitArcs) == GDB_ID_NULL) + return false ; + } + // 4b -> movimento di risalita sopra il punto finale + Point3d ptP4b = ptP4a + vtTool * ( dSafeDist - dAppr) ; + if ( AddRapidMove( ptP4b, bSplitArcs) == GDB_ID_NULL) + return false ; + } + } + // se con aggregato da sotto o equivalente (rinvio a 90 gradi su testa 5 assi) + if ( m_bAggrBottom) { + // se con rotazione per minimizzare la sporgenza + if ( m_AggrBottom.nType == 3) { + // imposto rotazione su punto standard + Vector3d vtAux = m_vtAggrBottom ; + vtAux.Rotate( Z_AX, 0, 1) ; + SetAuxDir( vtAux) ; + } + // 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) ; + if ( AddRapidMove( ptP0, bSplitArcs, MCH_CL_AGB_OUT) == GDB_ID_NULL) + return false ; + // se richiede speciale rotazione + if ( m_AggrBottom.nType == 1) { + Point3d ptP00 = ptP0 + Z_AX * ( m_AggrBottom.dEncV + m_TParams.m_dLen + dAggZ - dElev) ; + Vector3d vtAux = m_vtAggrBottom ; + vtAux.Rotate( Z_AX, 0, 1) ; + SetAuxDir( vtAux) ; + if ( AddRapidMove( ptP00, bSplitArcs, MCH_CL_AGB_UP) == GDB_ID_NULL) + return false ; + } + } + return true ; +} + +//---------------------------------------------------------------------------- +bool +PocketingNT::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 +PocketingNT::AddLeadIn( const Point3d& ptP1, const Point3d& ptStart, const Vector3d& vtStart, const Vector3d& vtN, + const ICurveComposite* pCompo, const ICurveComposite* pRCrv, bool bAtLeft, bool bSplitArcs, + bool bNoneForced, bool bSkipControl) +{ + // Assegno il tipo + int nType = GetLeadInType() ; + if ( bNoneForced || + AreSamePointEpsilon( ptP1, ptStart, 10 * EPS_SMALL) || + ( nType == 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( pCompo, ptCen, dRad)) { + // creo l'elica + PtrOwner pArc( CreateCurveArc()) ; + if ( IsNull( pArc) || ! pArc->Set( ptCen, vtN, dRad, - vtCen, dAngCen, dDeltaN)) + return false ; + // emetto l'elica (con eventuale spezzatura) + return ( AddCurveMove( pArc, bSplitArcs, MCH_CL_LEADIN) != GDB_ID_NULL) ; + } + // altrimenti zigzag + else + nType = 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( pCompo, ptPa, ptPb)) { + for ( int i = 1 ; i <= nStep ; ++ i) { + if ( AddLinearMove( ptPa - vtN * ( i - 0.75) * dStep, bSplitArcs, MCH_CL_LEADIN) == GDB_ID_NULL) + return false ; + if ( AddLinearMove( ptPb - vtN * ( i - 0.25) * dStep, bSplitArcs, MCH_CL_LEADIN) == GDB_ID_NULL) + return false ; + } + return ( AddLinearMove( ptStart, bSplitArcs, MCH_CL_LEADIN) != GDB_ID_NULL) ; + } + // altrimenti diretto + else { + nType = 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( ConvertCurveToComposite( pRCrv->CopyParamRange( dU, dParE)))) + return false ; + } + else { + if ( ! pCrv.Set( pRCrv->Clone())) + return false ; + } + pCrv->SetExtrusion( vtN) ; + // la porto alla giusta quota + Point3d ptFin ; pCrv->GetEndPoint( ptFin) ; + Vector3d vtMove = ptStart - ptFin ; + pCrv->Translate( vtMove) ; + // assegno la corretta pendenza + double dNini = ( ptP1 - ORIG) * vtN ; + double dNfin = ( ptStart - ORIG) * vtN ; + AdjustCurveSlope( pCrv, dNini, dNfin) ; + // emetto (con eventuale spezzatura) + return ( AddCurveMove( pCrv, bSplitArcs, MCH_CL_LEADIN) != GDB_ID_NULL) ; + } + // altrimenti diretto + else + nType = POCKET_LI_NONE ; + } + // Se diretto + if ( nType == POCKET_LI_NONE) { + Point3d ptCurr = ptP1 ; + GetCurrPos( ptCurr) ; + if ( ! AreSamePointApprox( ptCurr, ptStart)) { + if ( AddLinearMove( ptStart, bSplitArcs, MCH_CL_LEADIN) == GDB_ID_NULL) + return false ; + } + return true ; + } + // Altrimenti errore + return false ; +} + +//---------------------------------------------------------------------------- +bool +PocketingNT::AddLeadOut( const Point3d& ptEnd, const Vector3d& vtEnd, const Vector3d& vtN, + const ICurveComposite* pRCrv, bool bSplitArcs, bool bNoneForced, + Point3d& ptP1, double& dElev) +{ + bool bOppositeHome ; + return AddLeadOut( ptEnd, vtEnd, vtN, pRCrv, bSplitArcs, bNoneForced, ptP1, dElev, bOppositeHome) ; +} + +//---------------------------------------------------------------------------- +bool +PocketingNT::AddLeadOut( const Point3d& ptEnd, const Vector3d& vtEnd, const Vector3d& vtN, + const ICurveComposite* pRCrv, bool bSplitArcs, bool bNoneForced, + Point3d& ptP1, double& dElev, bool& bOppositeHome) +{ + // assegno i parametri + int nType = GetLeadOutType() ; + if ( bNoneForced || + ( nType == POCKET_LO_GLIDE && ( pRCrv == nullptr || pRCrv->GetCurveCount() == 0))) + nType = POCKET_LO_NONE ; + // eseguo a seconda del tipo + switch ( nType) { + case POCKET_LO_NONE : + { + // nessuna uscita + ptP1 = ptEnd ; + // determino elevazione su fine uscita + double dEndElev ; + if ( GetElevation( m_nPhase, ptP1 - 10 * EPS_SMALL * vtN, vtN, GetRadiusForStartEndElevation(), vtN, dEndElev)) + dElev = dEndElev ; + // correzione per punto sotto il grezzo con testa normale da sopra + double dSafeZ = 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( ConvertCurveToComposite( pRCrv->CopyParamRange( 0, dU)))) + return false ; + } + else { + if ( ! pCrv.Set( pRCrv->Clone())) + return false ; + } + // la porto alla giusta quota + Point3d ptIni ; pCrv->GetStartPoint( ptIni) ; + Vector3d vtMove = ptEnd - ptIni ; + pCrv->Translate( vtMove) ; + Point3d ptFin ; pCrv->GetEndPoint( ptFin) ; + ptFin += vtN * 1.0 ; + pCrv->ModifyEnd( ptFin) ; + // emetto (con eventuale spezzatura) + AddCurveMove( pCrv, bSplitArcs, MCH_CL_LEADOUT) ; + // determino elevazione su fine uscita + ptP1 = ptFin ; + 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 = 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 +PocketingNT::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 +PocketingNT::GetForcedClosed( void) +{ + int nOpen ; + if ( FromString( ExtractInfo( m_Params.m_sUserNotes, "Open="), nOpen) && nOpen == 0) + return true ; + else + return false ; +} + +//---------------------------------------------------------------------------- +bool +PocketingNT::GetMidOfLongestOpenSide( const ICurveComposite* pCompo, Point3d& ptMid, Vector3d& vtMidOrt) +{ + // recupero il vettore estrusione + Vector3d vtExtr = Z_AX ; + pCompo->GetExtrusion( vtExtr) ; + // verifico se tutti i lati sono aperti + bool bAllOpen = true ; + const ICurve* pMyCrv = pCompo->GetFirstCurve() ; + while ( pMyCrv != nullptr) { + if ( pMyCrv->GetTempProp() != 1) { + bAllOpen = false ; + break ; + } + pMyCrv = pCompo->GetNextCurve() ; + } + // richiedo lunghezza superiore a diametro utensile più doppio offset radiale + double 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 + else if ( dLen + dLenAgg > dMaxLen) { + dMaxLen = dLen + dLenAgg ; + pCrv->GetMidPoint( ptMid) ; + // vettore ortogonale verso l'esterno (ruotato -90deg attorno a estrusione) + pCrv->GetMidDir( vtMidOrt) ; + vtMidOrt.Rotate( vtExtr, 0, -1) ; + bFound = true ; + } + dLenPrev = dLen ; + } + } + else + dLenPrev = 0 ; + // vado alla successiva + pPrevCrv = pCrv ; + pCrv = ( bNextOk ? pNextCrv : nullptr) ; + } + + return bFound ; +} + +//---------------------------------------------------------------------------- +bool +PocketingNT::AdjustContourWithOpenEdges( ICurveComposite* pCompo) +{ + // vettore estrusione + Vector3d vtExtr ; pCompo->GetExtrusion( vtExtr) ; + // calcolo riferimento nel piano della svuotatura + Frame3d frPocket ; + Point3d ptStart ; pCompo->GetStartPoint( ptStart) ; + frPocket.Set( ptStart, vtExtr) ; + // sposto l'inizio a metà del tratto più lungo + AdjustContourStart( pCompo) ; + // raggio di riferimento per offset + double dOutEdge = 0.5 * m_TParams.m_dDiam ; + if ( m_Params.m_nSubType == POCKET_SUB_SPIRALIN || m_Params.m_nSubType == POCKET_SUB_ZIGZAG) + dOutEdge = max( dOutEdge, m_TParams.m_dDiam - m_Params.m_dSideStep) ; + double dRad = dOutEdge + GetOffsR() ; + // 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) || OffsCrv.GetCurveCount() == 0) { + m_pMchMgr->SetLastError( 2412, "Error in PocketingNT : Offset not computable") ; + return false ; + } + vpCrvs[i].Set( OffsCrv.GetLongerCurve()) ; + vpCrvs[i]->SetTempProp( 1) ; + } + } + // reinserisco le curve, chiudendo eventuali gap + pCompo->Clear() ; + pCompo->SetExtrusion( vtExtr) ; + bool bOpenCurr = false ; + double dDiam = 1.05 * m_TParams.m_dDiam + 2 * GetOffsR() ; + for ( int i = 0 ; i < int( vpCrvs.size()) ; ++ i) { + // stato curve + bool bOpenPrev = bOpenCurr ; + bOpenCurr = ( vpCrvs[i]->GetTempProp() != 0) ; + // chiudo eventuale gap + if ( i > 0) { + Point3d ptEnd ; pCompo->GetEndPoint( ptEnd) ; + Point3d ptStart ; vpCrvs[i]->GetStartPoint( ptStart) ; + if ( ! AreSamePointEpsilon( ptEnd, ptStart, 10 * EPS_SMALL)) { + // se passo da chiuso ad aperto + if ( ! bOpenPrev && bOpenCurr) { + // determino la curva ad amo + Vector3d vtTg ; pCompo->GetEndDir( vtTg) ; + Vector3d vtOrt = vtTg ; vtOrt.Rotate( vtExtr, 0, 1) ; + Point3d ptArc = ptEnd + dDiam * vtOrt ; + Point3d ptLine = ptArc - 5 * dDiam * vtTg ; + PtrOwner pJCrv( CreateCurveComposite()) ; + if ( IsNull( pJCrv)) + return false ; + pJCrv->SetExtrusion( vtExtr) ; + pJCrv->AddPoint( ptLine) ; + pJCrv->AddLine( ptArc, false) ; + pJCrv->AddArcTg( ptEnd, false) ; + // calcolo l'intersezione nel piano della svuotatura dell'amo con la curva aperta + pJCrv->ToLoc( frPocket) ; + vpCrvs[i]->ToLoc( frPocket) ; + IntersCurveCurve intCC( *pJCrv, *vpCrvs[i]) ; + pJCrv->ToGlob( frPocket) ; + vpCrvs[i]->ToGlob( frPocket) ; + // taglio opportunamente le curve + bool bFound = false ; + IntCrvCrvInfo aInfo ; + if ( intCC.GetIntersCount() > 0) { + // 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) ; + } + // se passo da aperto a chiuso + else if ( bOpenPrev && ! bOpenCurr) { + // determino la curva ad amo + Vector3d vtTg ; vpCrvs[i]->GetStartDir( vtTg) ; + Vector3d vtOrt = vtTg ; vtOrt.Rotate( vtExtr, 0, 1) ; + Point3d ptArc = ptStart + dDiam * vtOrt ; + Point3d ptLine = ptArc + 5 * dDiam * vtTg ; + PtrOwner pJCrv( CreateCurveComposite()) ; + if ( IsNull( pJCrv)) + return false ; + pJCrv->SetExtrusion( vtExtr) ; + pJCrv->AddPoint( ptLine) ; + pJCrv->AddLine( ptArc) ; + pJCrv->AddArcTg( ptStart) ; + // calcolo l'intersezione nel piano della svuotatura dell'amo con la curva aperta + PtrOwner pLCrv( CreateCurveComposite()) ; + if ( IsNull( pLCrv)) + return false ; + pLCrv->AddCurve( pCompo->GetLastCurve()->Clone()) ; + if ( pCompo->GetCurveCount() >= 2) + pLCrv->AddCurve( pCompo->GetPrevCurve()->Clone(), false) ; + double dUL = pLCrv->GetCurveCount() ; + pJCrv->ToLoc( frPocket) ; + pLCrv->ToLoc( frPocket) ; + IntersCurveCurve intCC( *pJCrv, *pLCrv) ; + pJCrv->ToGlob( frPocket) ; + pLCrv->ToGlob( frPocket) ; + // taglio opportunamente le curve + IntCrvCrvInfo aInfo ; + if ( intCC.GetIntCrvCrvInfo( 0, aInfo)) { + double dUs, dUe ; pCompo->GetDomain( dUs, dUe) ; + pCompo->TrimEndAtParam( dUe - dUL + aInfo.IciB[0].dU) ; + pJCrv->TrimStartAtParam( aInfo.IciA[0].dU) ; + pCompo->AddCurve( ::Release( pJCrv), true, 10 * EPS_SMALL) ; + } + else + pCompo->AddLine( ptStart) ; + } + else + pCompo->AddLine( ptStart) ; + } + } + // aggiungo la curva + pCompo->AddCurve( ::Release( vpCrvs[i]), true, 10 * EPS_SMALL) ; + } + // non dovrebbe esserci un gap, ma meglio prevenire problemi + pCompo->Close() ; + + return true ; +} + +//---------------------------------------------------------------------------- +bool +PocketingNT::AdjustContourStart( ICurveComposite* pCompo) +{ + // 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 < 1.25 * 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() ; + } + } + + // sposto inizio + if ( nMax >= 0) + pCompo->ChangeStartPoint( nMax + 0.5) ; + + return true ; +} + +//---------------------------------------------------------------------------- +bool +PocketingNT::VerifyLeadInHelix( const ICurveComposite* pCompo, const Point3d& ptCen, double dRad) const +{ + // recupero il piano della curva di contorno + Point3d ptStart ; + Vector3d vtN ; + if ( pCompo == nullptr || ! 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 ; + return ( DistPointCurve( ptCenL, *pCompo).GetDist( dMinDist) && dMinDist > dRad + 0.5 * m_TParams.m_dDiam - 10 * EPS_SMALL) ; +} + +//---------------------------------------------------------------------------- +bool +PocketingNT::VerifyLeadInZigZag( const ICurveComposite* pCompo, const Point3d& ptPa, const Point3d& ptPb) const +{ + // recupero il piano della curva di contorno + Point3d ptStart ; + Vector3d vtN ; + if ( pCompo == nullptr || ! 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 ; + return ( dMinDistPa > 0.5 * m_TParams.m_dDiam - 10 * EPS_SMALL && dMinDistPb > 0.5 * m_TParams.m_dDiam - 10 * EPS_SMALL) ; +} + +//---------------------------------------------------------------------------- +bool +PocketingNT::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 ; + } + + return true ; +} diff --git a/PocketingNT.h b/PocketingNT.h new file mode 100644 index 0000000..078a4dc --- /dev/null +++ b/PocketingNT.h @@ -0,0 +1,197 @@ +//---------------------------------------------------------------------------- +// EgalTech 2017-2017 +//---------------------------------------------------------------------------- +// File :Pocketing.h Data : 04.02.17 Versione : 1.8b1 +// Contenuto : Dichiarazione della classe Pocketing. +// +// +// +// Modifiche : 04.02.17 DS Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +#pragma once + +#include "Machining.h" +#include "PocketingData.h" +#include "ToolData.h" +#include "/EgtDev/Include/EGkCurveComposite.h" +#include "/EgtDev/Include/EGkCurveLine.h" +#include "/EgtDev/Include/EgtNumUtils.h" + +//---------------------------------------------------------------------------- +class PocketingNT : public Machining +{ + public : // IUserObj + PocketingNT* Clone( void) const override ; + const std::string& GetClassName( void) const override ; + bool Dump( std::string& sOut, bool bMM = true, const char* szNewLine = "\n") const override ; + bool ToSave( void) const override + { return true ; } + bool Save( int nBaseId, STRVECTOR& vString) const override ; + bool Load( const STRVECTOR& vString, int nBaseGdbId) override ; + + public : // Operation + int GetType( void) const override + { return OPER_POCKETING ; } + bool IsEmpty( void) const override + { return ( m_nPockets == 0) ; } + bool UpdateStatus( int nModif) override + { m_nStatus |= nModif ; return true ; } + + protected : // Operation + int GetSolCh( void) const override + { return m_Params.m_nSolCh ; } + + public : // Machining + bool Prepare( const std::string& sMillName) override ; + bool SetParam( int nType, bool bVal) override ; + bool SetParam( int nType, int nVal) override ; + bool SetParam( int nType, double dVal) override ; + bool SetParam( int nType, const std::string& sVal) override ; + bool SetGeometry( const SELVECTOR& vIds) override ; + bool Preview( bool bRecalc) override ; + bool Apply( bool bRecalc, bool bPostApply) override ; + bool Update( bool bPostApply) override ; + bool GetParam( int nType, bool& bVal) const override ; + bool GetParam( int nType, int& nVal) const override ; + bool GetParam( int nType, double& dVal) const override ; + bool GetParam( int nType, std::string& sVal) const override ; + bool UpdateToolData( bool* pbChanged = nullptr) override ; + const ToolData& GetToolData( void) const override ; + bool GetGeometry( SELVECTOR& vIds) const override ; + + public : + PocketingNT( void) ; + + private : + bool VerifyGeometry( SelData Id, int& nSubs, int& nType) ; + bool GetCurves( SelData Id, ICURVEPLIST& lstPC) ; + bool SetCurveAllTempProp( int nCrvId, bool bForcedClose, ICurve* pCurve, bool* pbSomeOpen = nullptr) ; + bool ResetCurveAllTempProp( ICurve* pCurve) ; + bool Chain( int nGrpDestId) ; + bool ProcessPath( int nPathId, int nPvId, int nClId) ; + bool CalcRegionElevation( const ICurveComposite* pCompo, const Vector3d& vtTool, double dDepth, double dRad, double dLen, double& dElev) const ; + bool VerifyPathFromBottom( const ICurveComposite* pCompo, const Vector3d& vtTool) ; + bool GeneratePocketingPv( int nPathId, const ICurveComposite* pCompo) ; + bool AddZigZag( const ICurveComposite* pCompo, const Vector3d& vtTool, const Vector3d& vtExtr, + double dDepth, double dElev, double dOkStep, bool bSplitArcs, int nPathId) ; + bool CalcZigZag( const ICurveComposite* pOffs, ICRVCOMPOPOVECTOR& vpCrvs) ; + bool OptimizedZigZag( int nPathId, const Vector3d& vtTool, double dDepth, double dSafeZ, + Frame3d& frPocket, bool& bOptimizedZigZag, ICRVCOMPOPOVECTOR& vpCrvs, double& dOffs) ; + bool ZigZagOptimizedNoClosedEdges( ICurveComposite* pCrvPocket, bool& bOptimizedZigZag, Vector3d& vtDir, double& dOffs) ; + bool ZigZagOptimizedOneClosedEdge( ICurveComposite* pCrvPocket, int nClosedId, bool& bOptimizedZigZag, Vector3d& vtDir, double& dOffs) ; + bool ZigZagOptimizedTwoClosedEdges( ICurveComposite* pCrvPocket, const INTVECTOR& vnClosedIds, bool& bOptimizedZigZag, + bool& bOpposite, Vector3d& vtDir, double& dOffs) ; + bool ZigZagOptimizedThreeClosedEdges( ICurveComposite* pCrvPocket, const INTVECTOR& vnClosedIds, bool& bOptimizedZigZag, + bool& bOpposite, Vector3d& vtDir, double& dOffs) ; + bool ZigZagOptimizedComputeOffset( ICurveComposite* pCrvPocket, const Vector3d& vtMainDir, int nOffsettedEdgesOnY, + const INTVECTOR& vnClosedIds, double& dOffs) ; + bool CutCurveWithLine( ICurveComposite* pCrvA, const ICurveLine* pCrvB) ; + bool AddOneWay( const ICurveComposite* pCompo, const Vector3d& vtTool, const Vector3d& vtExtr, + double dDepth, double dElev, double dOkStep, bool bSplitArcs) ; + bool AddSpiralIn( const ICurveComposite* pCompo, const Vector3d& vtTool, const Vector3d& vtExtr, + double dDepth, double dElev, double dOkStep, bool bSplitArcs, bool bMidOpen, + const Point3d& ptMidOpen, const Vector3d& vtMidOut, int nPathId) ; + bool AddSpiralOut( const ICurveComposite* pCompo, const Vector3d& vtTool, const Vector3d& vtExtr, + double dDepth, double dElev, double dOkStep, bool bSplitArcs, int nPathId) ; + bool CalcSpiral( const ICurveComposite* pCompo, int nReg, bool bSplitArcs, + ICurveComposite* pMCrv, ICurveComposite* pRCrv, int nPathId, bool& bOptimizedTrap) ; + bool CalcBoundedLink( const Point3d& ptStart, const Point3d& ptEnd, const ICurve* pCrvBound, + ICurveComposite* pCrvLink) ; + bool CalcBoundedLinkWithBiArcs( const Point3d& ptStart, const Vector3d& vtStart, const Point3d& ptEnd, const Vector3d& vtEnd, + const ICurve* pCrvBound, ICurveComposite* pCrvLink) ; + bool CalcCircleSpiral( const Point3d& ptCen, const Vector3d& vtN, double dOutRad, double dIntRad, + bool bSplitArcs, ICurveComposite* pMCrv, ICurveComposite* pRCrv) ; + bool CalcTrapezoidSpiral( ICurveComposite* pCrvPocket, const Vector3d& vtDir, double dPocketSize, + ICurveComposite* pMCrv, ICurveComposite* pRCrv, bool& bOptimizedTrap) ; + bool CalcTrapezoidSpiralLocalFrame( ICurveComposite * pCrvPocket, const Vector3d& vtDir, Frame3d& frLoc) ; + bool CalcTrapezoidSpiralXCoord( const ICurveComposite * pCrvPocket, bool bStart, double dYCoord, double& dXCoord, double dPocketSize) ; + bool AdjustTrapezoidSpiralForAngles( ICurveComposite * pMCrv, const ICurveComposite * pCrvPocket, bool bStart) ; + bool SpecialAdjustTrapezoidSpiralForAngles( ICurveComposite* pMCrv, const ICurveComposite* pCrvPocket) ; + bool AdjustTrapezoidSpiralForLeadInLeadOut( ICurveComposite * pCompo, ICurveComposite * pRCrv, const Vector3d& vtTool, + double dDepth, int& nOutsideRaw) ; + bool ComputeTrapezoidSpiralLeadInLeadOut( ICurveComposite * pCompo, const Vector3d& vtMainDir, bool bLeadIn, const Vector3d& vtTool, double dDepth, bool& bIsOutsideRaw) ; + bool ComputePolishingPath( ICurveComposite* pMCrv, ICurveComposite* pRCrv, bool bSplitArcs) ; + bool AddEpicycles( ICurveComposite * pCompo, ICurveComposite * pCrv, ICurveComposite * pCrvBound = nullptr) ; + bool AddApproach( const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dSafeAggrBottZ, + double dElev, double dAppr, bool bSplitArcs, bool bOutStart) ; + bool AddLinkApproach( const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dSafeAggrBottZ, + double dElev, double dAppr, bool bSplitArcs, bool bOutStart = false) ; + bool AddLinkRetract( const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dSafeAggrBottZ, + double dElev, double dAppr, bool bSplitArcs) ; + bool AddRetract( const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dSafeAggrBottZ, + double dElev, double dAppr, bool bSplitArcs) ; + bool CalcLeadInStart( const Point3d& ptStart, const Vector3d& vtStart, const Vector3d& vtN, + const ICurveComposite* pRCrv, Point3d& ptP1) const ; + bool AddLeadIn( const Point3d& ptP1, const Point3d& ptStart, const Vector3d& vtStart, const Vector3d& vtN, + const ICurveComposite* pCompo, const ICurveComposite* pRCrv, bool bAtLeft, bool bSplitArcs, + bool bNoneForced = false, bool bSkipControl = false) ; + bool AddLeadOut( const Point3d& ptEnd, const Vector3d& vtEnd, const Vector3d& vtN, + const ICurveComposite* pRCrv, bool bSplitArcs, bool bNoneForced, + Point3d& ptP1, double& dElev) ; + bool AddLeadOut( const Point3d& ptEnd, const Vector3d& vtEnd, const Vector3d& vtN, + const ICurveComposite* pRCrv, bool bSplitArcs, bool bNoneForced, + Point3d& ptP1, double& dElev, bool& bOppositeHome) ; + double GetRadiusForStartEndElevation( void) const ; + bool GetForcedClosed( void) ; + bool GetMidOfLongestOpenSide( const ICurveComposite* pCompo, Point3d& ptMid, Vector3d& vtMidOut) ; + bool AdjustContourWithOpenEdges( ICurveComposite* pCompo) ; + bool AdjustContourStart( ICurveComposite* pCompo) ; + bool VerifyLeadInHelix( const ICurveComposite* pCompo, const Point3d& ptCen, double dRad) const ; + bool VerifyLeadInZigZag( const ICurveComposite* pCompo, const Point3d& ptPa, const Point3d& ptPb) const ; + bool CalcDistanceFromRawSurface( int nPhase, const Point3d& ptP, const Vector3d& vtDir, double& dDist, Vector3d& vtNorm) ; + + private : + double GetSpeed( void) const + { return ( IsNullAngValue( m_Params.m_dSpeed) ? m_TParams.m_dSpeed : m_Params.m_dSpeed) ; } + double GetFeed( void) const + { return ( IsNullLenValue( m_Params.m_dFeed) ? m_TParams.m_dFeed : m_Params.m_dFeed) ; } + double GetStartFeed( void) const + { return ( IsNullLenValue( m_Params.m_dStartFeed) ? m_TParams.m_dStartFeed : m_Params.m_dStartFeed) ; } + double GetEndFeed( void) const + { return ( IsNullLenValue( m_Params.m_dEndFeed) ? m_TParams.m_dEndFeed : m_Params.m_dEndFeed) ; } + double GetTipFeed( void) const + { return ( IsNullLenValue( m_Params.m_dTipFeed) ? m_TParams.m_dTipFeed : m_Params.m_dTipFeed) ; } + double GetOffsL( void) const + { return ( IsUnknownValue( m_Params.m_dOffsL) ? m_TParams.m_dOffsL : m_Params.m_dOffsL) ; } + double GetOffsR( void) const + { return ( IsUnknownValue( m_Params.m_dOffsR) ? m_TParams.m_dOffsR : m_Params.m_dOffsR) ; } + double GetSideStep( void) const + { return Clamp( m_Params.m_dSideStep, std::min( 0.1 * m_TParams.m_dDiam, 1.0), m_TParams.m_dDiam) ; } + int GetLeadInType( void) const + { if ( m_Params.m_dLiTang < std::min( 0.1 * m_TParams.m_dDiam, 1.0)) + return POCKET_LI_NONE ; + if ( m_Params.m_nLeadInType != POCKET_LI_GLIDE && m_Params.m_dLiElev < 10 * EPS_SMALL) + return POCKET_LI_NONE ; + return m_Params.m_nLeadInType ; } + bool LeadInRawIsOk( void) const + { if ( m_TParams.m_nType != TT_MILL_NOTIP) + return true ; + return (( GetLeadInType() == POCKET_LI_ZIGZAG || GetLeadInType() == POCKET_LI_HELIX) && + m_Params.m_dLiTang >= 0.9 * m_TParams.m_dDiam && m_Params.m_dLiElev <= 2) ; } + int GetLeadOutType( void) const + { if ( m_Params.m_dLoTang < std::min( 0.1 * m_TParams.m_dDiam, 1.0)) + return POCKET_LO_NONE ; + return m_Params.m_nLeadOutType ; } + + private : + SELVECTOR m_vId ; // identificativi entità geometriche da lavorare + PocketingData m_Params ; // parametri lavorazione + ToolData m_TParams ; // parametri utensile + double m_dTHoldBase ; // posizione base del porta-utensile + double m_dTHoldLen ; // lunghezza del porta-utensile + double m_dTHoldDiam ; // diametro del porta-utensile + double m_dMaxHelixRad ; // raggio massimo attacco ad elica nel caso di cerchi + int m_nStatus ; // stato di aggiornamento della lavorazione + int m_nPockets ; // numero di percorsi di svuotatura generati + bool m_bTiltingTab ; // flag utilizzo tavola basculante + Vector3d m_vtTiltingAx ; // versore direzione eventuale asse basculante + bool m_bAboveHead ; // flag utilizzo testa da sopra + bool m_bAggrBottom ; // flag di utilizzo dell'aggregato da sotto + Vector3d m_vtAggrBottom ; // vettore direzione ausiliaria aggregato da sotto + AggrBottom m_AggrBottom ; // dati eventuale aggregato da sotto + bool m_bOpenOutRaw ; // flag forzatura lati aperti sempre fuori dal grezzo + double m_dOpenMinSafe ; // minima distanza di sicurezza di attacco su lato aperto +} ; \ No newline at end of file