Files
EgtMachKernel/Pocketing.cpp
T
SaraP 34ef5388e1 EgtMachKernel :
- in Pocketing adattamenti per modifiche a GeomKernel ( funzione GetCurveClassification).
2021-11-18 10:13:14 +01:00

4911 lines
194 KiB
C++

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