Files
EgtMachKernel/SurfRoughing.cpp
T
Riccardo Elitropi f6afb6ac9c EgtMachKernel :
- LeadIn/LeadOut mediante SafeZ.
2024-08-29 10:41:17 +02:00

3225 lines
126 KiB
C++

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