ac45a259b6
- In PocketingNT aggiunta gestione lavorazioni in Doppio in Parallelo.
3894 lines
154 KiB
C++
3894 lines
154 KiB
C++
//----------------------------------------------------------------------------
|
|
// EgalTech 2015-2023
|
|
//----------------------------------------------------------------------------
|
|
// File : Drilling.cpp Data : 20.12.23 Versione : 2.5l47
|
|
// Contenuto : Implementazione gestione forature.
|
|
//
|
|
// Note : Questa lavorazione è sempre espressa nel riferimento globale.
|
|
//
|
|
// Modifiche : 21.05.15 DS Creazione modulo.
|
|
// 20.12.23 RE Forature multiple con aggregati.
|
|
//
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
//--------------------------- Include ----------------------------------------
|
|
#include "stdafx.h"
|
|
#include "MachMgr.h"
|
|
#include "DllMain.h"
|
|
#include "Drilling.h"
|
|
#include "OperationConst.h"
|
|
#include "OperUserNotesConst.h"
|
|
#include "/EgtDev/Include/EXeCmdLogOff.h"
|
|
#include "/EgtDev/Include/EGkGeoPoint3d.h"
|
|
#include "/EgtDev/Include/EGkGeoVector3d.h"
|
|
#include "/EgtDev/Include/EGkCurveLine.h"
|
|
#include "/EgtDev/Include/EGkCurveArc.h"
|
|
#include "/EgtDev/Include/EGkCurveComposite.h"
|
|
#include "/EgtDev/Include/EGkChainCurves.h"
|
|
#include "/EgtDev/Include/EGkSfrCreate.h"
|
|
#include "/EgtDev/Include/EGkStringUtils3d.h"
|
|
#include "/EgtDev/Include/EGkUserObjFactory.h"
|
|
#include "/EgtDev/Include/EGnStringKeyVal.h"
|
|
#include "/EgtDev/Include/EgtPointerOwner.h"
|
|
#include "/EgtDev/Include/EGkGeoFrame3d.h"
|
|
#include "/EgtDev/Include/EgtIniFile.h"
|
|
|
|
using namespace std ;
|
|
|
|
//------------------------------ Errors --------------------------------------
|
|
// 2101 = "Error in Drilling : UpdateToolData failed"
|
|
// 2102 = "Error in Drilling : Offset not computable"
|
|
// 2103 = "Error in Drilling : Overlap not computable"
|
|
// 2104 = "Error in Drilling : Depth not computable"
|
|
// 2105 = "Error in Drilling : Drill with zero depth"
|
|
// 2106 = "Error in Drilling : Entity xx skipped because missing aggregate from bottom"
|
|
// 2107 = "Error in Drilling : Entity xx skipped because too far from part sides"
|
|
// 2108 = "Error in Drilling : Chaining failed"
|
|
// 2109 = "Error in Drilling : axes values not calculable"
|
|
// 2110 = "Error in Drilling : outstroke xx"
|
|
// 2111 = "Error in Drilling : link movements not calculable"
|
|
// 2112 = "Error in Drilling : link outstroke xx"
|
|
// 2113 = "Error in Drilling : post apply not calculable"
|
|
// 2114 = "Error in Drilling : blind hole not reversible"
|
|
// 2115 = "Error in Drilling : Mirror for Double calculation failed"
|
|
// 2116 = "Error in Drilling : multi drilling head without valid tools"
|
|
// 2117 = "Error in Drilling : incorrect multi drilling head"
|
|
// 2118 = "Error in Drilling : Tool loading failed"
|
|
// 2119 = "Error in Drilling : special apply not calculable"
|
|
// 2151 = "Warning in Drilling : Skipped entity (xx)"
|
|
// 2152 = "Warning in Drilling : No machinable path"
|
|
// 2153 = "Warning in Drilling : Tool name changed (xx)"
|
|
// 2154 = "Warning in Drilling : Tool data changed (xx)"
|
|
// 2155 = "Warning in Drilling : Drill bit too short for Hole "
|
|
// 2156 = "Warning in Drilling : Skipped by Standard Drilling "
|
|
// 2157 = "Warning in Drilling : Skipped by Peck Drilling "
|
|
// 2158 = "Warning in Drilling : Skipped & PartialDrilled (xx) | (xx, L:yy)
|
|
|
|
//----------------------------------------------------------------------------
|
|
// debug
|
|
#define ENABLE_DEBUG_MULTIHEAD_HOLES 0
|
|
|
|
//----------------------------------------------------------------------------
|
|
// definizione delle costanti
|
|
const int IND_TOOL_INVALID = -1 ;
|
|
const int IND_HOLE_INVALID = -1 ;
|
|
|
|
//----------------------------------------------------------------------------
|
|
// struttura semplificata del foro
|
|
struct Hole {
|
|
int nOriId ; // identificativo della geometria di origine
|
|
Point3d ptIni ; // punto iniziale
|
|
Vector3d vtDir ; // direzione di riferimento (dal fondo verso l'inizio)
|
|
double dDiam ; // diametro
|
|
double dThick ; // lunghezza della geometria originale
|
|
double dLen ; // lunghezza dell'asse
|
|
bool bBlind ; // flag per cieco/passante
|
|
// eventuale tipo ( standard, ribassato, svasato) ?
|
|
Hole( void)
|
|
: nOriId( GDB_ID_NULL), ptIni(), vtDir(), dDiam( 0), dThick( 0), dLen( 0), bBlind( true) {}
|
|
} ;
|
|
|
|
// struttura avanzata per fori nel caso di MultiHeadDrills
|
|
struct HoleInfo {
|
|
Hole hole ; // foro
|
|
bool bDrill = false ; // flag per indicare se il foro alla fine verrà lavorato
|
|
bool bTempDrill = false ; // [per test maschera ( se durante un test viene lavorato o no)]
|
|
int nTempTool = IND_TOOL_INVALID ; // [per test maschera ( indice utensile che lo lavora durante un test)]
|
|
bool bForToolM = false ; // flag per indicare se il tool main lavorerà questo foro
|
|
int nIndHoleToolM = IND_HOLE_INVALID ; // se il foro verrà lavorato, contiene l'indice del foro del tool principale
|
|
|
|
// --- vettori ordinati ---
|
|
INTVECTOR vToolHole ; // []-> indice del foro di inserimento del tool principale
|
|
INTVECTOR vIndTools ; // []-> indice del tool che lavorerà il foro corrente
|
|
VCT3DVECTOR vVtAux ; // []-> vettore ausiliario per tale condifgurazione
|
|
INTVECTOR vIndMainTool ; // []-> solo nel caso di utensili selezionabili, contiene l'indice del tool considerato come principale
|
|
|
|
int nIndTool = IND_TOOL_INVALID ; // indice del tool che alla fine lavorerà il foro
|
|
Vector3d vtAux ; // vettore ausiliario del tool principale per lavorare il foro corrente
|
|
Point3d ptBtn ; // punto interno alla base del foro
|
|
int nIndInSelVector = 0 ; // indice nel vettore m_vId ( id fori selezionati)
|
|
} ;
|
|
|
|
// struttura avanzata per il tool, per MultiHeadDrills
|
|
struct ToolInfo {
|
|
const ToolData* pTool ; // puntatore per utensile ( nullo se utensile non presente)
|
|
Point3d ptToolTip ; // punto finale del tool ( per ptBtn del foro)
|
|
ToolInfo( void)
|
|
: pTool( nullptr) {}
|
|
ToolInfo( const ToolData* pT)
|
|
: pTool( pT) {}
|
|
} ;
|
|
|
|
// struttura per foratura con MultiHeadDrills
|
|
struct MHDrill {
|
|
int nHoleInd ; // indice del foro
|
|
Vector3d vtAux ; // vettore ausiliario per tale foratura
|
|
INTVECTOR vActiveExit ; // nel caso di più utensili selezionabili, contiene gli indici delle uscite attive
|
|
ToolInfo currTool ; // utensile da inserire nel foro di indice nHoleInd ( per utensili selezionabili)
|
|
INTINTVECTOR vMatMask ; // vettore per indicare corrispondenze utensili e fori <Hole, Tool>
|
|
MHDrill( int nHInd, Vector3d vtA)
|
|
: nHoleInd( nHInd), vtAux( vtA) {} ;
|
|
MHDrill( int nHInd, Vector3d vtA, INTVECTOR vAE, ToolInfo cT)
|
|
: nHoleInd( nHInd), vtAux( vtA), vActiveExit( vAE), currTool( cT) {} ;
|
|
MHDrill( int nHInd, Vector3d vtA, INTVECTOR vAE, ToolInfo cT, INTINTVECTOR mSK)
|
|
: nHoleInd( nHInd), vtAux( vtA), vActiveExit( vAE), currTool( cT), vMatMask( mSK) {} ;
|
|
} ;
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
USEROBJ_REGISTER( GetOperationClass( OPER_DRILLING), Drilling) ;
|
|
|
|
//----------------------------------------------------------------------------
|
|
const string&
|
|
Drilling::GetClassName( void) const
|
|
{
|
|
return USEROBJ_GETNAME( Drilling) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
Drilling*
|
|
Drilling::Clone( void) const
|
|
{
|
|
// alloco oggetto
|
|
Drilling* pDri = new(nothrow) Drilling ;
|
|
// eseguo copia dei dati
|
|
if ( pDri != nullptr) {
|
|
try {
|
|
pDri->m_vId = m_vId ;
|
|
pDri->m_pMchMgr = m_pMchMgr ;
|
|
pDri->m_nPhase = m_nPhase ;
|
|
pDri->m_Params = m_Params ;
|
|
pDri->m_TParams = m_TParams ;
|
|
pDri->m_nStatus = m_nStatus ;
|
|
pDri->m_nDrillings = m_nDrillings ;
|
|
pDri->m_bTiltingTab = m_bTiltingTab ;
|
|
pDri->m_vtTiltingAx = m_vtTiltingAx ;
|
|
pDri->m_bAboveHead = m_bAboveHead ;
|
|
pDri->m_bAggrBottom = m_bAggrBottom ;
|
|
pDri->m_vUndrilledId = m_vUndrilledId ;
|
|
}
|
|
catch( ...) {
|
|
delete pDri ;
|
|
return nullptr ;
|
|
}
|
|
}
|
|
// ritorno l'oggetto
|
|
return pDri ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Drilling::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_nDrillings) + szNewLine ;
|
|
sOut += KEY_STAT + EQUAL + ToString( m_nStatus) + szNewLine ;
|
|
sOut += KEY_SKIPS + EQUAL + ToString( m_vUndrilledId) + szNewLine ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Drilling::Save( int nBaseId, STRVECTOR& vString) const
|
|
{
|
|
try {
|
|
int nSize = 1 + m_Params.GetSize() + m_TParams.GetSize() + 3 + ( m_vUndrilledId.empty() ? 0 : 1) ;
|
|
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_nDrillings, vString[++k]))
|
|
return false ;
|
|
if ( ! SetVal( KEY_STAT, m_nStatus, vString[++k]))
|
|
return false ;
|
|
if ( ! m_vUndrilledId.empty() && ! SetVal( KEY_SKIPS, m_vUndrilledId, vString[++k]))
|
|
return false ;
|
|
}
|
|
catch( ...) {
|
|
return false ;
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Drilling::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_nDrillings))
|
|
return false ;
|
|
}
|
|
else if ( sKey == KEY_STAT) {
|
|
if ( ! FromString( sVal, m_nStatus))
|
|
return false ;
|
|
}
|
|
else if ( sKey == KEY_SKIPS) {
|
|
if ( ! FromString( sVal, m_vUndrilledId))
|
|
return false ;
|
|
}
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//----------------------------------------------------------------------------
|
|
Drilling::Drilling( void)
|
|
{
|
|
m_Params.m_sName = "*" ;
|
|
m_Params.m_sToolName = "*" ;
|
|
m_Params.m_sDepth = "TH" ;
|
|
m_TParams.m_sName = "*" ;
|
|
m_TParams.m_sHead = "*" ;
|
|
m_nStatus = MCH_ST_TO_VERIFY ;
|
|
m_nDrillings = 0 ;
|
|
m_bTiltingTab = false ;
|
|
m_bAboveHead = true ;
|
|
m_bAggrBottom = false ;
|
|
m_dDistBottom = 0 ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Drilling::Prepare( const string& sDriName)
|
|
{
|
|
// 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 DrillingData* pDdata = GetDrillingData( pMMgr->GetMachining( sDriName)) ;
|
|
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
|
|
Drilling::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
|
|
Drilling::SetParam( int nType, int nVal)
|
|
{
|
|
switch ( nType) {
|
|
case MPA_SUBTYPE :
|
|
if ( nVal != m_Params.m_nSubType)
|
|
m_nStatus |= MCH_ST_PARAM_MODIF ;
|
|
m_Params.m_nSubType = 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
|
|
Drilling::SetParam( int nType, double dVal)
|
|
{
|
|
switch ( nType) {
|
|
case MPA_SPEED :
|
|
if ( ! m_TParams.VerifySpeed( dVal))
|
|
return false ;
|
|
if ( abs( m_TParams.m_dSpeed - dVal) < EPS_MACH_ANG_PAR)
|
|
dVal = 0 ;
|
|
if ( abs( dVal - m_Params.m_dSpeed) > EPS_MACH_ANG_PAR)
|
|
m_nStatus |= MCH_ST_PARAM_MODIF ;
|
|
m_Params.m_dSpeed = dVal ;
|
|
return true ;
|
|
case MPA_FEED :
|
|
if ( abs( m_TParams.m_dFeed - dVal) < EPS_MACH_LEN_PAR)
|
|
dVal = 0 ;
|
|
if ( abs( dVal - m_Params.m_dFeed) > EPS_MACH_LEN_PAR)
|
|
m_nStatus |= MCH_ST_PARAM_MODIF ;
|
|
m_Params.m_dFeed = dVal ;
|
|
return true ;
|
|
case MPA_STARTFEED :
|
|
if ( abs( m_TParams.m_dStartFeed - dVal) < EPS_MACH_LEN_PAR)
|
|
dVal = 0 ;
|
|
if ( abs( dVal - m_Params.m_dStartFeed) > EPS_MACH_LEN_PAR)
|
|
m_nStatus |= MCH_ST_PARAM_MODIF ;
|
|
m_Params.m_dStartFeed = dVal ;
|
|
return true ;
|
|
case MPA_ENDFEED :
|
|
if ( abs( m_TParams.m_dEndFeed - dVal) < EPS_MACH_LEN_PAR)
|
|
dVal = 0 ;
|
|
if ( abs( dVal - m_Params.m_dEndFeed) > EPS_MACH_LEN_PAR)
|
|
m_nStatus |= MCH_ST_PARAM_MODIF ;
|
|
m_Params.m_dEndFeed = dVal ;
|
|
return true ;
|
|
case MPA_TIPFEED :
|
|
if ( abs( m_TParams.m_dTipFeed - dVal) < EPS_MACH_LEN_PAR)
|
|
dVal = 0 ;
|
|
if ( abs( dVal - m_Params.m_dTipFeed) > EPS_MACH_LEN_PAR)
|
|
m_nStatus |= MCH_ST_PARAM_MODIF ;
|
|
m_Params.m_dTipFeed = dVal ;
|
|
return true ;
|
|
case MPA_DEPTH : {
|
|
string sVal = ToString( dVal) ;
|
|
if ( sVal != m_Params.m_sDepth)
|
|
m_nStatus |= MCH_ST_PARAM_MODIF ;
|
|
m_Params.m_sDepth = sVal ;
|
|
} return true ;
|
|
case MPA_STARTPOS :
|
|
if ( abs( dVal - m_Params.m_dStartPos) > EPS_MACH_LEN_PAR)
|
|
m_nStatus |= MCH_ST_PARAM_MODIF ;
|
|
m_Params.m_dStartPos = dVal ;
|
|
return true ;
|
|
case MPA_STARTSLOWLEN :
|
|
if ( abs( dVal - m_Params.m_dStartSlowLen) > EPS_MACH_LEN_PAR)
|
|
m_nStatus |= MCH_ST_PARAM_MODIF ;
|
|
m_Params.m_dStartSlowLen = dVal ;
|
|
return true ;
|
|
case MPA_ENDSLOWLEN :
|
|
if ( abs( dVal - m_Params.m_dEndSlowLen) > EPS_MACH_LEN_PAR)
|
|
m_nStatus |= MCH_ST_PARAM_MODIF ;
|
|
m_Params.m_dEndSlowLen = dVal ;
|
|
return true ;
|
|
case MPA_THROUADDLEN :
|
|
if ( abs( dVal - m_Params.m_dThroughAddLen) > EPS_MACH_LEN_PAR)
|
|
m_nStatus |= MCH_ST_PARAM_MODIF ;
|
|
m_Params.m_dThroughAddLen = dVal ;
|
|
return true ;
|
|
case MPA_STEP :
|
|
if ( abs( dVal - m_Params.m_dStep) > EPS_MACH_LEN_PAR)
|
|
m_nStatus |= MCH_ST_PARAM_MODIF ;
|
|
m_Params.m_dStep = dVal ;
|
|
return true ;
|
|
case MPA_RETURNPOS :
|
|
if ( abs( dVal - m_Params.m_dReturnPos) > EPS_MACH_LEN_PAR)
|
|
m_nStatus |= MCH_ST_PARAM_MODIF ;
|
|
m_Params.m_dReturnPos = dVal ;
|
|
return true ;
|
|
case MPA_OVERLAP : {
|
|
string sVal = ToString( dVal) ;
|
|
if ( sVal != m_Params.m_sOverlap)
|
|
m_nStatus |= MCH_ST_PARAM_MODIF ;
|
|
m_Params.m_sOverlap = sVal ;
|
|
} return true ;
|
|
case MPA_STARTADDLEN :
|
|
if ( abs( dVal - m_Params.m_dStartAddLen) > EPS_MACH_LEN_PAR)
|
|
m_nStatus |= MCH_ST_PARAM_MODIF ;
|
|
m_Params.m_dStartAddLen = dVal ;
|
|
return true ;
|
|
case MPA_ENDADDLEN :
|
|
if ( abs( dVal - m_Params.m_dEndAddLen) > EPS_MACH_LEN_PAR)
|
|
m_nStatus |= MCH_ST_PARAM_MODIF ;
|
|
m_Params.m_dEndAddLen = dVal ;
|
|
return true ;
|
|
case MPA_OFFSET : {
|
|
string sVal = ToString( dVal) ;
|
|
if ( sVal != m_Params.m_sOverlap)
|
|
m_nStatus |= MCH_ST_PARAM_MODIF ;
|
|
m_Params.m_sOffset = sVal ;
|
|
} return true ;
|
|
}
|
|
return false ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Drilling::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_OVERLAP_STR :
|
|
if ( sVal != m_Params.m_sOverlap)
|
|
m_nStatus |= MCH_ST_PARAM_MODIF ;
|
|
m_Params.m_sOverlap = sVal ;
|
|
return true ;
|
|
case MPA_OFFSET_STR :
|
|
if ( sVal != m_Params.m_sOffset)
|
|
m_nStatus |= MCH_ST_PARAM_MODIF ;
|
|
m_Params.m_sOffset = 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
|
|
Drilling::SetGeometry( const SELVECTOR& vIds)
|
|
{
|
|
// verifico validità gestore generale e gestore DB geometrico
|
|
if ( m_pMchMgr == nullptr || m_pGeomDB == nullptr)
|
|
return false ;
|
|
// copia temporanea e reset della geometria corrente
|
|
SELVECTOR vOldId = m_vId ;
|
|
m_vId.clear() ;
|
|
// se lavorazione standard
|
|
if ( m_Params.m_nSubType == DRI_SUB_STD) {
|
|
// verifico che gli identificativi rappresentino dei fori (il corretto diametro è verificato dopo)
|
|
for ( int i = 0 ; i < int( vIds.size()) ; ++ i) {
|
|
// recupero i dati del foro
|
|
Hole hole ;
|
|
if ( ! GetHoleData( vIds[i], hole)) {
|
|
string sInfo = "Warning in Drilling : Skipped entity " + ToString( vIds[i].nId) ;
|
|
m_pMchMgr->SetWarning( 2151, sInfo) ;
|
|
continue ;
|
|
}
|
|
// posso aggiungere alla lista
|
|
m_vId.push_back( vIds[i]) ;
|
|
}
|
|
}
|
|
// altrimenti se lavorazione lungo curve
|
|
else if ( m_Params.m_nSubType == DRI_SUB_ALONG_CURVE) {
|
|
// verifico che gli identificativi rappresentino delle curve
|
|
for ( int i = 0 ; i < int( vIds.size()) ; ++ i) {
|
|
if ( ( m_pGeomDB->GetGeoType( vIds[i].nId) & GEO_CURVE) == 0) {
|
|
string sInfo = "Warning in Drilling : Skipped entity " + ToString( vIds[i].nId) ;
|
|
m_pMchMgr->SetWarning( 2151, sInfo) ;
|
|
continue ;
|
|
}
|
|
// posso aggiungere alla lista
|
|
m_vId.push_back( vIds[i]) ;
|
|
}
|
|
}
|
|
// aggiorno lo stato
|
|
if ( m_vId != vOldId)
|
|
m_nStatus |= MCH_ST_GEO_MODIF ;
|
|
// restituisco presenza geometria da lavorare
|
|
return ( ! m_vId.empty()) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Drilling::Preview( bool bRecalc)
|
|
{
|
|
// reset numero forature nella lavorazione
|
|
m_nDrillings = 0 ;
|
|
// reset fori non lavorati
|
|
m_vUndrilledId.clear() ;
|
|
// verifico validità gestore DB geometrico e Id del gruppo
|
|
if ( m_pGeomDB == nullptr || ! m_pGeomDB->ExistsObj( m_nOwnerId))
|
|
return false ;
|
|
// recupero gruppo per geometria di Preview
|
|
int nPvId = m_pGeomDB->GetFirstNameInGroup( m_nOwnerId, MCH_PV) ;
|
|
// se non c'è, lo aggiungo
|
|
if ( nPvId == GDB_ID_NULL) {
|
|
nPvId = m_pGeomDB->AddGroup( GDB_ID_NULL, m_nOwnerId, Frame3d()) ;
|
|
if ( nPvId == GDB_ID_NULL)
|
|
return false ;
|
|
m_pGeomDB->SetName( nPvId, MCH_PV) ;
|
|
}
|
|
// altrimenti lo lavoro
|
|
else
|
|
m_pGeomDB->EmptyGroup( nPvId) ;
|
|
|
|
// aggiorno dati geometrici dell'utensile
|
|
if ( ! UpdateToolData()) {
|
|
m_pMchMgr->SetLastError( 2101, "Error in Drilling : UpdateToolData failed") ;
|
|
return false ;
|
|
}
|
|
|
|
// se lavorazione standard
|
|
if ( m_Params.m_nSubType == DRI_SUB_STD)
|
|
return StandardProcess( bRecalc, nPvId, GDB_ID_NULL) ;
|
|
// se altrimenti lavorazione lungo curve
|
|
else if ( m_Params.m_nSubType == DRI_SUB_ALONG_CURVE)
|
|
return AlongCurveProcess( bRecalc, nPvId, GDB_ID_NULL) ;
|
|
// altrimenti errore
|
|
else
|
|
return false ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Drilling::Apply( bool bRecalc, bool bPostApply)
|
|
{
|
|
// reset numero forature nella lavorazione
|
|
int nCurrDrillings = m_nDrillings ;
|
|
m_nDrillings = 0 ;
|
|
// reset fori non lavorati
|
|
INTVECTOR vCurrUndrilledId = m_vUndrilledId ;
|
|
m_vUndrilledId.clear() ;
|
|
|
|
// verifico validità gestore DB geometrico e Id del gruppo
|
|
if ( m_pGeomDB == nullptr || ! m_pGeomDB->ExistsObj( m_nOwnerId))
|
|
return false ;
|
|
|
|
// aggiorno dati geometrici dell'utensile
|
|
if ( ! UpdateToolData()) {
|
|
m_pMchMgr->SetLastError( 2101, "Error in Drilling : UpdateToolData failed") ;
|
|
return false ;
|
|
}
|
|
|
|
// se modificata geometria, necessario ricalcolo
|
|
if ( ( m_nStatus & MCH_ST_GEO_MODIF) != 0)
|
|
bRecalc = true ;
|
|
|
|
// verifico se necessario continuare nell'aggiornamento
|
|
if ( ! bRecalc && ( m_nStatus == MCH_ST_OK || m_nStatus == MCH_ST_NO_POSTAPPL)) {
|
|
// confermo i percorsi di lavorazione e i fori non lavorati
|
|
m_nDrillings = nCurrDrillings ;
|
|
m_vUndrilledId = vCurrUndrilledId ;
|
|
string sLog = string( "Drilling apply skipped : status ") + ( m_nStatus == MCH_ST_OK ? "already ok" : "no postapply") ;
|
|
LOG_DBG_INFO( GetEMkLogger(), sLog.c_str()) ;
|
|
// eseguo aggiornamento assi macchina e collegamento con operazione precedente
|
|
if ( ! Update( bPostApply))
|
|
return false ;
|
|
m_nStatus = ( bPostApply ? MCH_ST_OK : MCH_ST_NO_POSTAPPL) ;
|
|
LOG_DBG_INFO( GetEMkLogger(), "Update done") ;
|
|
// esco con successo
|
|
return true ;
|
|
}
|
|
m_nStatus = MCH_ST_TO_VERIFY ;
|
|
|
|
// recupero gruppo per geometria 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 lavoro
|
|
else
|
|
m_pGeomDB->EmptyGroup( nClId) ;
|
|
|
|
// elimino eventuale gruppo geometria simmetrica per lavorazione in doppio
|
|
int nDblId = m_pGeomDB->GetFirstNameInGroup( m_nOwnerId, MCH_DBL) ;
|
|
if ( nDblId != GDB_ID_NULL) {
|
|
m_pGeomDB->Erase( nDblId) ;
|
|
nDblId = GDB_ID_NULL ;
|
|
}
|
|
|
|
// 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( 2118, "Error in Drilling : Tool loading failed") ;
|
|
return false ;
|
|
}
|
|
|
|
// verifico se tavola basculante
|
|
bool bTiltTab = false ;
|
|
m_bTiltingTab = ( m_pMchMgr->GetCurrMachine()->GetCurrTableIsTilting( bTiltTab, m_vtTiltingAx) && bTiltTab) ;
|
|
// verifico se testa da sopra (Z+)
|
|
m_bAboveHead = m_pMchMgr->GetHeadAbove( m_TParams.m_sHead) ;
|
|
|
|
// se lavorazione standard
|
|
if ( m_Params.m_nSubType == DRI_SUB_STD) {
|
|
if ( ! StandardProcess( bRecalc, GDB_ID_NULL, nClId))
|
|
return false ;
|
|
}
|
|
// se altrimenti lavorazione lungo curve
|
|
else if ( m_Params.m_nSubType == DRI_SUB_ALONG_CURVE) {
|
|
if ( ! AlongCurveProcess( bRecalc, GDB_ID_NULL, nClId))
|
|
return false ;
|
|
}
|
|
// altrimenti errore
|
|
else
|
|
return false ;
|
|
|
|
// assegno ingombri dei vari percorsi di lavorazione e della lavorazione nel suo complesso
|
|
CalcAndSetBBox( nClId) ;
|
|
|
|
// se lavorazione in doppio, aggiungo geometria della parte simmetrica
|
|
if ( ! CalcMirrorByDouble( nClId, m_Params.m_sUserNotes)) {
|
|
m_pMchMgr->SetLastError( 2115, "Error in Drilling : Mirror for Double calculation failed") ;
|
|
return false ;
|
|
}
|
|
|
|
// 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(), "Drilling apply done") ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Drilling::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_nDrillings == 0) {
|
|
m_pMchMgr->SetWarning( 2152, "Warning in Drilling : No machinable hole") ;
|
|
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( 2109, "Error in Drilling : axes values not calculable") ;
|
|
else
|
|
m_pMchMgr->SetLastError( 2110, "Error in Drilling : outstroke ") ;
|
|
return false ;
|
|
}
|
|
|
|
// assegno estremi degli assi dei vari percorsi di lavorazione e della lavorazione nel suo complesso
|
|
CalcAndSetAxesBBox() ;
|
|
|
|
// se lavorazione in doppio, calcolo assi e movimenti di approccio e retrazione relativi
|
|
if ( GetDoubleType( m_Params.m_sUserNotes) != 0) {
|
|
// elimino le entità CLIMB, RISE e HOME della lavorazione in doppio
|
|
RemoveClimbRiseHome( false) ;
|
|
// recupero i dati della testa in doppio e la imposto
|
|
string sDblTool ; string sDblTcPos ; string sDblHead ; int nDblExit ;
|
|
bool bOk = GetDoubleToolData( sDblTool, sDblTcPos, sDblHead, nDblExit) &&
|
|
m_pMchMgr->SetCalcTool( sDblTool, sDblHead, nDblExit) ;
|
|
// imposto eventuale asse bloccato da lavorazione
|
|
SetBlockedRotAxis( m_Params.m_sBlockedAxis, true) ;
|
|
// eseguo il calcolo
|
|
if ( bOk) {
|
|
if ( ! CalculateDoubleAxesValues( sHint)) {
|
|
string sInfo = m_pMchMgr->GetOutstrokeInfo() ;
|
|
if ( sInfo.empty())
|
|
m_pMchMgr->SetLastError( 2109, "Error in Drilling : axes values not calculable for double") ;
|
|
else
|
|
m_pMchMgr->SetLastError( 2110, "Error in Drilling : double outstroke ") ;
|
|
bOk = false ;
|
|
}
|
|
}
|
|
// ripristino testa principale
|
|
m_pMchMgr->SetCalcTool( GetToolName(), GetHeadName(), GetExitNbr()) ;
|
|
// in caso di errore, esco
|
|
if ( ! bOk)
|
|
return false ;
|
|
}
|
|
|
|
// esecuzione eventuali personalizzazioni speciali
|
|
string sSpecErr ;
|
|
if ( bPostApply && ! SpecialApply( sSpecErr)) {
|
|
if ( ! IsEmptyOrSpaces( sSpecErr))
|
|
m_pMchMgr->SetLastError( 2119, sSpecErr) ;
|
|
else
|
|
m_pMchMgr->SetLastError( 2119, "Error in Drilling : special apply not calculable") ;
|
|
return false ;
|
|
}
|
|
|
|
// gestione movimenti all'inizio di ogni singolo percorso di lavorazione e alla fine della lavorazione
|
|
if ( ! AdjustStartEndMovements()) {
|
|
string sInfo = m_pMchMgr->GetOutstrokeInfo() ;
|
|
if ( sInfo.empty())
|
|
m_pMchMgr->SetLastError( 2111, "Error in Drilling : link movements not calculable") ;
|
|
else
|
|
m_pMchMgr->SetLastError( 2112, "Error in Drilling : link outstroke ") ;
|
|
return false ;
|
|
}
|
|
|
|
// esecuzione eventuali personalizzazioni
|
|
string sPostErr ;
|
|
if ( bPostApply && ! PostApply( sPostErr)) {
|
|
if ( ! IsEmptyOrSpaces( sPostErr))
|
|
m_pMchMgr->SetLastError( 2113, sPostErr) ;
|
|
else
|
|
m_pMchMgr->SetLastError( 2113, "Error in Drilling : post apply not calculable") ;
|
|
return false ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int
|
|
Drilling::VerifyMultiParallelDrills( void)
|
|
{
|
|
// se aggregato da sotto, sicuramente con una sola punta
|
|
bool bAggrBottom = IsAggrBottom( m_TParams.m_sHead) ;
|
|
if ( bAggrBottom)
|
|
return DRILL_TYPE_STD ;
|
|
// se una sola uscita, inutile continuare
|
|
int nExitCnt = m_pMchMgr->GetCurrMachine()->GetHeadExitCount( m_TParams.m_sHead) ;
|
|
if ( nExitCnt == 1)
|
|
return DRILL_TYPE_STD ;
|
|
// verifico che le uscite siano fisse
|
|
int nSelectType = m_pMchMgr->GetCurrMachine()->GetHeadSelectType( m_TParams.m_sHead) ;
|
|
if ( nSelectType != MCH_SLT_FIXEDEXITS && nSelectType != MCH_SLT_MULTIEXITS)
|
|
return DRILL_TYPE_STD ;
|
|
// recupero la direzione dell'utensile principale
|
|
Point3d ptMainExit ; Vector3d vtMainTool, vtMainAux ;
|
|
m_pMchMgr->GetCurrMachine()->GetHeadExitPosDirAux( m_TParams.m_sHead, m_TParams.m_nExit, ptMainExit, vtMainTool, vtMainAux) ;
|
|
// verifico ci sia almeno un'altra uscita attrezzata parallela a quella principale
|
|
for ( int nT = 0 ; nT < nExitCnt ; ++ nT) {
|
|
if ( nT + 1 == m_TParams.m_nExit)
|
|
continue ;
|
|
string sToolName ;
|
|
if ( m_pMchMgr->GetLoadedTool( m_TParams.m_sHead, nT + 1, sToolName) && ! sToolName.empty()) {
|
|
// recupero la tipologia di utensile
|
|
int nType = TT_NONE ;
|
|
string sCurrTool ; m_pMchMgr->TdbGetCurrToolParam( TPA_NAME, sCurrTool) ;
|
|
if ( m_pMchMgr->TdbSetCurrTool( sToolName)) {
|
|
m_pMchMgr->TdbGetCurrToolParam( TPA_TYPE, nType) ;
|
|
if ( ! IsEmptyOrSpaces( sCurrTool))
|
|
m_pMchMgr->TdbSetCurrTool( sCurrTool) ;
|
|
}
|
|
// verifico punta o fresa con direzione corretta
|
|
Point3d ptExit ; Vector3d vtTool, vtAux ;
|
|
if ( ( ( nType & TF_DRILLBIT) != 0 || nType == TT_MILL_STD) &&
|
|
m_pMchMgr->GetCurrMachine()->GetHeadExitPosDirAux( m_TParams.m_sHead, nT + 1, ptExit, vtTool, vtAux) &&
|
|
AreSameVectorApprox( vtTool, vtMainTool)) {
|
|
if ( nSelectType == MCH_SLT_FIXEDEXITS)
|
|
return DRILL_TYPE_MULTI_FIXED ;
|
|
else
|
|
return DRILL_TYPE_MULTI_SEL ;
|
|
}
|
|
}
|
|
}
|
|
// non è stato trovato niente
|
|
return ( nSelectType == MCH_SLT_MULTIEXITS ? DRILL_TYPE_MULTI_SEL : DRILL_TYPE_STD) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Drilling::StandardProcess( bool bRecalc, int nPvId, int nClId)
|
|
{
|
|
// recupero il tipo di lavorazione
|
|
int nDrillType = VerifyMultiParallelDrills() ;
|
|
// eseguo la lavorazione richiesta
|
|
switch ( nDrillType) {
|
|
case DRILL_TYPE_STD :
|
|
{ // se vtAux impostato come parametro di lavorazione nelle UserNotes
|
|
Vector3d vtAux ;
|
|
if ( GetValInNotes( m_Params.m_sUserNotes, UN_VTAUXDIR, vtAux))
|
|
vtAux.Normalize() ;
|
|
// elaboro i singoli fori
|
|
for ( int i = 0 ; i < int( m_vId.size()) ; ++ i) {
|
|
const auto& vId = m_vId[i] ;
|
|
// se richiesto preview
|
|
if ( nPvId != GDB_ID_NULL) {
|
|
if ( ! GenerateHolePv( i, vId, MCH_PATH, nPvId))
|
|
return false ;
|
|
// creo la regione di ingombro del foro
|
|
int nDriId = m_pGeomDB->GetFirstInGroup( m_pGeomDB->GetLastGroupInGroup( nPvId)) ;
|
|
GenerateHoleRegionPv( nDriId, 1, nPvId) ;
|
|
}
|
|
// se richiesta lavorazione
|
|
if ( nClId != GDB_ID_NULL) {
|
|
if ( ! GenerateHoleCl( i, vId, MCH_PATH, nClId, 0, vtAux))
|
|
return false ;
|
|
}
|
|
}
|
|
}
|
|
break ;
|
|
case DRILL_TYPE_MULTI_FIXED :
|
|
{ TABMHDRILL tabDrills ;
|
|
double dMHOff = 0 ;
|
|
if ( ! MultiHeadDrilling( m_vId, nClId, true, tabDrills, dMHOff))
|
|
return false ;
|
|
if ( tabDrills.empty())
|
|
return true ;
|
|
for ( int i = 0 ; i < int( tabDrills.size()) ; ++ i) {
|
|
// se richiesto preview
|
|
if ( nPvId != GDB_ID_NULL) {
|
|
if ( ! GenerateHolePv( i, m_vId[tabDrills[i].nHoleInd], MCH_PATH, nPvId))
|
|
return false ;
|
|
// creo la regione di ingombro del foro
|
|
int nDriId = m_pGeomDB->GetFirstInGroup( m_pGeomDB->GetLastGroupInGroup( nPvId)) ;
|
|
GenerateHoleRegionPv( nDriId, 1, nPvId) ;
|
|
}
|
|
// se richiesta lavorazione
|
|
if ( nClId != GDB_ID_NULL) {
|
|
if ( ! GenerateHoleCl( i, m_vId[tabDrills[i].nHoleInd], MCH_PATH, nClId, dMHOff,
|
|
tabDrills[i].vtAux, DRILL_TYPE_MULTI_FIXED))
|
|
return false ;
|
|
}
|
|
}
|
|
}
|
|
break ;
|
|
case DRILL_TYPE_MULTI_SEL :
|
|
{ // eseguo il MultiHead drilling per gruppo a forare
|
|
TABMHDRILL tabDrills ;
|
|
double dMHOff = 0 ;
|
|
if ( ! MultiHeadDrilling( m_vId, nClId, false, tabDrills, dMHOff))
|
|
return false ;
|
|
if ( tabDrills.empty())
|
|
return true ;
|
|
for ( int i = 0 ; i < int( tabDrills.size()) ; ++ i) {
|
|
// se richiesto preview
|
|
if ( nPvId != GDB_ID_NULL) {
|
|
if ( ! GenerateHolePv( i, m_vId[tabDrills[i].nHoleInd], MCH_PATH, nPvId))
|
|
return false ;
|
|
// creo la regione di ingombro del foro
|
|
int nDriId = m_pGeomDB->GetFirstInGroup( m_pGeomDB->GetLastGroupInGroup( nPvId)) ;
|
|
GenerateHoleRegionPv( nDriId, 1, nPvId) ;
|
|
}
|
|
// se richiesta lavorazione
|
|
if ( nClId != GDB_ID_NULL) {
|
|
#if ENABLE_DEBUG_MULTIHEAD_HOLES
|
|
PrintDescent( tabDrills[i]) ;
|
|
#endif
|
|
if ( ! GenerateHoleCl( i, m_vId[tabDrills[i].nHoleInd], MCH_PATH, nClId, dMHOff, tabDrills[i].vtAux,
|
|
DRILL_TYPE_MULTI_SEL, &( tabDrills[i].vActiveExit), &( tabDrills[i].currTool)))
|
|
return false ;
|
|
}
|
|
}
|
|
}
|
|
break ;
|
|
case DRILL_TYPE_ERR :
|
|
default :
|
|
return false ;
|
|
break ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Drilling::CalcDrilledHolesByConfig( VECTORHOLE& vHoles, int nMyInd, int nIndConfig, INTVECTOR& vIndDrilled)
|
|
{
|
|
/*
|
|
restituisce quali fori non ancora lavorati vengono lavorati con la configurazione di indice nIndConfig
|
|
per il foro nMyInd-esimo
|
|
*/
|
|
|
|
// controllo dei parametri
|
|
if ( nMyInd < 0 || nMyInd >= int( vHoles.size()) ||
|
|
nIndConfig < 0 || nIndConfig >= int( vHoles[nMyInd].vIndTools.size()))
|
|
return false ;
|
|
vIndDrilled.clear() ;
|
|
if ( vHoles.empty())
|
|
return true ;
|
|
|
|
// dichiarazione variabili di supporto
|
|
int nMainHole = vHoles[nMyInd].vToolHole[nIndConfig] ;
|
|
Vector3d vtMainAux = vHoles[nMyInd].vVtAux[nIndConfig] ;
|
|
// scorro tutti i fori
|
|
for ( int i = 0 ; i < int( vHoles.size()) ; ++ i) {
|
|
// se foro i-esimo già lavorato, passo al successivo
|
|
if ( vHoles[i].bDrill)
|
|
continue ;
|
|
// se il foro i-esimo è il corrente, lo inserisco ( è lavorato in quanto nella configurazione)
|
|
if ( i == nMyInd) {
|
|
vIndDrilled.emplace_back( i) ;
|
|
continue ;
|
|
}
|
|
// se il foro i-esimo è quello in cui il tool è posizionato, lo inserisco ( idem)
|
|
else if ( i == nMainHole) {
|
|
vIndDrilled.emplace_back( i) ;
|
|
continue ;
|
|
}
|
|
else {
|
|
// se foro i-esimo viene lavorato mettendo il tool principale nel foro nMainHole-esimo e con lo
|
|
// stesso orientamento della configurazione corrente, inserisco il foro
|
|
for ( int j = 0 ; j < int( vHoles[i].vToolHole.size()) ; ++ j) {
|
|
if ( vHoles[i].vToolHole[j] == nMainHole && AreSameVectorApprox( vHoles[i].vVtAux[j], vtMainAux))
|
|
vIndDrilled.emplace_back( i) ;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Drilling::GetClosestHolesToHole( const VECTORHOLE& vHoles, int nMyInd, bool bDrilled, INTVECTOR& vInds)
|
|
{
|
|
/*
|
|
funzione che restutisce gli indici dei fori Drilled/nonDrilled più vicini al foro nMyInd-esimo
|
|
*/
|
|
|
|
// controllo dei parametri
|
|
if ( nMyInd < 0 || nMyInd >= int( vHoles.size()))
|
|
return false ;
|
|
vInds.clear() ;
|
|
if ( vHoles.empty())
|
|
return true ;
|
|
|
|
// scorro i fori
|
|
double dMinDist = INFINITO ;
|
|
for ( int i = 0 ; i < int( vHoles.size()) ; ++ i) {
|
|
// escludo il foro nInd-esimo
|
|
if ( i == nMyInd)
|
|
continue ;
|
|
// se foro di tipologia opposta, passo al successivo
|
|
if ( vHoles[i].bDrill != bDrilled)
|
|
continue ;
|
|
// se il foro non è lavorabile, non lo conto
|
|
bool bUndrillable = true ;
|
|
for ( int j = 0 ; j < int( vHoles[i].vIndTools.size()) && bUndrillable ; ++ j) {
|
|
bUndrillable = ( vHoles[i].vToolHole[j] == IND_TOOL_INVALID &&
|
|
vHoles[i].vIndTools[j] == IND_TOOL_INVALID &&
|
|
! vHoles[i].vVtAux[j].IsValid()) ;
|
|
}
|
|
if ( bUndrillable)
|
|
continue ;
|
|
// calcolo la distanza tra i due fori
|
|
double dSqDist = SqDist( vHoles[nMyInd].hole.ptIni, vHoles[i].hole.ptIni) ;
|
|
if ( dSqDist < dMinDist) {
|
|
dMinDist = dSqDist ;
|
|
vInds.clear() ;
|
|
vInds.emplace_back( i) ;
|
|
}
|
|
else if ( abs( dSqDist - dMinDist) < 100 * SQ_EPS_SMALL)
|
|
vInds.emplace_back( i) ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Drilling::OrderConfigsForSelectableTools( VECTORHOLE& vHoles, const VECTORTOOL& vTools, int nIndToolMain, TABMHDRILL& vDrills)
|
|
{
|
|
// se non ho fori, allora non faccio nulla
|
|
vDrills.clear() ;
|
|
if ( vHoles.empty())
|
|
return true ;
|
|
|
|
// recupero gli indici dei fori non lavorabili
|
|
INTVECTOR vIndUndrilledHoles ;
|
|
for ( int i = 0 ; i < int( vHoles.size()) ; ++ i) {
|
|
// scorro sulle configurazioni trovate
|
|
bool bIsUndrilled = true ;
|
|
for ( int j = 0 ; j < int( vHoles[i].vIndTools.size()) && bIsUndrilled ; ++ j)
|
|
bIsUndrilled = ( vHoles[i].vIndTools[j] == IND_TOOL_INVALID &&
|
|
vHoles[i].vToolHole[j] == IND_TOOL_INVALID &&
|
|
! vHoles[i].vVtAux[j].IsValid()) ;
|
|
// se foro non lavorabile, lo inserisco nel vettore
|
|
if ( bIsUndrilled)
|
|
vIndUndrilledHoles.emplace_back( i) ;
|
|
}
|
|
|
|
// recupero il numero di fori totali
|
|
int nHoles = int( vHoles.size()) ;
|
|
// recupero il numero di fori non lavorabili
|
|
int nUndrilledHoles = int( vIndUndrilledHoles.size()) ;
|
|
// se i due valori coincidono, allora ho finito
|
|
if ( nHoles == nUndrilledHoles)
|
|
return true ;
|
|
|
|
// considero tutti i fori come non lavorati
|
|
for ( int i = 0 ; i < nHoles ; ++ i)
|
|
vHoles[i].bTempDrill = false ;
|
|
|
|
// inizializzo contatore di fori lavorati
|
|
int nDrilledHoles = 0 ;
|
|
|
|
#if ENABLE_DEBUG_MULTIHEAD_HOLES
|
|
LOG_ERROR( GetEMkLogger(), "--- Configurazioni scelte : ") ;
|
|
#endif
|
|
|
|
// finchè non lavoro tutti i fori ammissibili
|
|
const int MAXTRY = 5000 ;
|
|
int nCont = 0 ;
|
|
while ( nDrilledHoles < nHoles - nUndrilledHoles && nCont < MAXTRY) {
|
|
// cerco la(e) configurazione(i) che lavora(no) più fori
|
|
INTVECTOR vIndBestConfigs ;
|
|
GetConfigsWithMoreDrilledHoles( vHoles, vIndBestConfigs) ;
|
|
// se non ho trovato nessuna configurazione, allora non faccio nulla
|
|
if ( vIndBestConfigs.empty())
|
|
break ;
|
|
int nBestConfig = vIndBestConfigs[0] ;
|
|
ChooseBestConfigForSelectableTools( vHoles, nIndToolMain, vIndBestConfigs, nBestConfig) ;
|
|
// imposto bTempDrill per i fori in esame
|
|
INTVECTOR vIndActiveExits ;
|
|
int nRefHole = 0 ;
|
|
for ( int i = 0 ; i < int( vHoles.size()) ; ++ i) {
|
|
if ( ! vHoles[i].bTempDrill &&
|
|
vHoles[i].vIndTools[nBestConfig] != IND_TOOL_INVALID &&
|
|
vHoles[i].vToolHole[nBestConfig] != IND_TOOL_INVALID &&
|
|
vHoles[i].vVtAux[nBestConfig].IsValid()) {
|
|
// flag per lavorazione temporanea
|
|
vHoles[i].bTempDrill = true ;
|
|
// aumento contatore fori lavorati
|
|
++ nDrilledHoles ;
|
|
// ricavo la testa su cui è montato l'utensile
|
|
vIndActiveExits.emplace_back( vTools[vHoles[i].vIndTools[nBestConfig]].pTool->m_nExit) ;
|
|
// memorizzo un foro di riferimento
|
|
nRefHole = i ;
|
|
}
|
|
}
|
|
// calcolo la maschera per la configurazione attuale
|
|
INTINTVECTOR vMyMask ;
|
|
if ( ! MultiHeadHoleToolsConfig( vHoles, nBestConfig, vMyMask))
|
|
return false ;
|
|
// inserisco la configurazione per la lavorazione
|
|
vDrills.emplace_back( vHoles[nRefHole].vToolHole[nBestConfig],
|
|
vHoles[nRefHole].vVtAux[nBestConfig],
|
|
vIndActiveExits, vTools[vHoles[nRefHole].vIndMainTool[nBestConfig]], vMyMask) ;
|
|
#if ENABLE_DEBUG_MULTIHEAD_HOLES
|
|
string sRow = " (" ;
|
|
sRow.append( ToString( nBestConfig)) ;
|
|
sRow.append( ") --> uscite attive : ") ;
|
|
for ( int _a = 0 ; _a < int( vIndActiveExits.size()) ; ++ _a) {
|
|
sRow.append( ToString( vIndActiveExits[_a])) ;
|
|
if ( _a != int( vIndActiveExits.size()) - 1)
|
|
sRow.append( ",") ;
|
|
}
|
|
sRow.append( " [#") ;
|
|
sRow.append( ToString( int( vIndActiveExits.size()))) ;
|
|
sRow.append( "]. -> Corrispondenze :") ;
|
|
for ( int _a = 0 ; _a < int( vMyMask.size()) ; ++ _a)
|
|
sRow.append( " H:" + ToString( vMyMask[_a].first) + "|T:" + ToString( vMyMask[_a].second)) ;
|
|
LOG_ERROR( GetEMkLogger(), sRow.c_str()) ;
|
|
#endif
|
|
// incremento contatore tentativi massimi
|
|
++ nCont ;
|
|
}
|
|
// se ho superato i tentativi massimi, errore
|
|
if ( nCont == MAXTRY) {
|
|
vDrills.clear() ;
|
|
return false ;
|
|
}
|
|
|
|
// Riordino le configurazioni trovate
|
|
if ( vDrills.empty() || int( vDrills.size()) == 1)
|
|
return true ;
|
|
Point3d ptRef = ORIG ;
|
|
INTVECTOR vIndToOrder ; vIndToOrder.reserve( vDrills.size()) ;
|
|
vector<pair<int, int>> vIntervals ;
|
|
int nIndS = 0 ; int nCurrSize = -1 ;
|
|
for ( int i = 0 ; i < int( vDrills.size()) ; ++ i) {
|
|
if ( i == 0) {
|
|
nCurrSize = int( vDrills[i].vActiveExit.size()) ;
|
|
continue ;
|
|
}
|
|
if ( int( vDrills[i].vActiveExit.size()) == nCurrSize) {
|
|
if ( i == ( vDrills.size() - 1))
|
|
vIntervals.emplace_back( make_pair( nIndS, i + 1)) ;
|
|
continue ;
|
|
}
|
|
else {
|
|
vIntervals.emplace_back( make_pair( nIndS, i)) ;
|
|
nIndS = i ;
|
|
nCurrSize = int( vDrills[i].vActiveExit.size()) ;
|
|
-- i ;
|
|
}
|
|
}
|
|
#if ENABLE_DEBUG_MULTIHEAD_HOLES
|
|
string sRow = "---- Raggruppamento #uscite --- " ;
|
|
for ( int _a = 0 ; _a < int( vIntervals.size()) ; ++ _a) {
|
|
sRow.append( "(") ;
|
|
sRow.append( ToString( vIntervals[_a].first)) ;
|
|
sRow.append( ",") ;
|
|
sRow.append( ToString( vIntervals[_a].second)) ;
|
|
sRow.append( ")") ;
|
|
if ( _a != int( vIntervals.size()) - 1)
|
|
sRow.append( " | ") ;
|
|
}
|
|
LOG_ERROR( GetEMkLogger(), sRow.c_str()) ;
|
|
#endif
|
|
for ( int i = 0 ; i < int( vIntervals.size()) ; ++ i) {
|
|
for ( int j = vIntervals[i].first ; j < vIntervals[i].second ; ++ j) {
|
|
vector<pair<int, double>> my_vOrder ;
|
|
for ( int k = vIntervals[i].first ; k < vIntervals[i].second ; ++ k) {
|
|
if ( find( vIndToOrder.begin(), vIndToOrder.end(), k) != vIndToOrder.end())
|
|
continue ;
|
|
my_vOrder.push_back( make_pair( k, SqDist( vHoles[vDrills[k].nHoleInd].hole.ptIni, ptRef))) ;
|
|
}
|
|
double dMinDist = INFINITO ;
|
|
int nMyIndex = 0 ;
|
|
for ( auto& _order : my_vOrder) {
|
|
if ( _order.second < dMinDist) {
|
|
nMyIndex = _order.first ;
|
|
ptRef = vHoles[vDrills[nMyIndex].nHoleInd].hole.ptIni ;
|
|
dMinDist = _order.second ;
|
|
}
|
|
}
|
|
vIndToOrder.push_back( nMyIndex) ;
|
|
}
|
|
}
|
|
#if ENABLE_DEBUG_MULTIHEAD_HOLES
|
|
string sRow1 = "---- Ordine Indici condifugrazioni --- " ;
|
|
for ( int _a = 0 ; _a < int( vIndToOrder.size()) ; ++ _a) {
|
|
sRow1.append( ToString( vIndToOrder[_a])) ;
|
|
if ( _a != int( vIndToOrder.size()) - 1)
|
|
sRow1.append( " | ") ;
|
|
}
|
|
LOG_ERROR( GetEMkLogger(), sRow1.c_str()) ;
|
|
#endif
|
|
TABMHDRILL vOrderedDrill ;
|
|
for ( size_t i = 0 ; i < vIndToOrder.size() ; ++ i)
|
|
vOrderedDrill.emplace_back( vDrills[vIndToOrder[i]]) ;
|
|
swap( vDrills, vOrderedDrill) ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Drilling::ChooseBestConfigForSelectableTools( const VECTORHOLE& vHoles, int nIndToolMain,
|
|
INTVECTOR& vConfInds, int& nBestConf)
|
|
{
|
|
/*
|
|
algoritmo Greedy per la scelta della miglior configurazione per tool selezionabili
|
|
*/
|
|
|
|
// se non ho fori, allora ho finito
|
|
if ( vHoles.empty())
|
|
return true ;
|
|
// se non ho configurazioni, allora ho finito
|
|
if ( vConfInds.empty())
|
|
return true ;
|
|
// per sicurezza la prima configurazione è la migliore ( decisione temporanea )
|
|
nBestConf = vConfInds[0] ;
|
|
// se ho una sola configurazione, allora è quella ottimale
|
|
if ( int( vConfInds.size()) == 1)
|
|
return true ;
|
|
|
|
// euristicamente considero accettabili solo le configurazioni dove compare il tool principale
|
|
// ( se non la trovo scelgo semplicemente la prima )
|
|
INTVECTOR vConfInds_Greedy0 ;
|
|
for ( int nC = 0 ; nC < int( vConfInds.size()) ; ++ nC) {
|
|
int nMyConfig = vConfInds[nC] ;
|
|
for ( int i = 0 ; i < int( vHoles.size()) ; ++ i) {
|
|
if ( ! vHoles[i].bTempDrill &&
|
|
vHoles[i].vIndMainTool[nMyConfig] == nIndToolMain &&
|
|
vHoles[i].vToolHole[nMyConfig] != IND_TOOL_INVALID &&
|
|
vHoles[i].vVtAux[nMyConfig].IsValid()) {
|
|
vConfInds_Greedy0.emplace_back( vConfInds[nC]) ;
|
|
break ;
|
|
}
|
|
}
|
|
}
|
|
// se ho meno di due configurazioni, ho trovato quella "ottimale"
|
|
if ( int( vConfInds_Greedy0.size()) < 2) {
|
|
if ( ! vConfInds_Greedy0.empty())
|
|
nBestConf = vConfInds_Greedy0[0] ;
|
|
return true ;
|
|
}
|
|
|
|
// cerco tra le configurazioni trovate, quella che inserisce il tool main in un foro non lavorato
|
|
INTVECTOR vConfInds_Greedy1 ;
|
|
for ( int nC = 0 ; nC < int( vConfInds_Greedy0.size()) ; ++ nC) {
|
|
int nMyConfig = vConfInds_Greedy0[nC] ;
|
|
for ( int i = 0 ; i < int( vHoles.size()) ; ++ i) {
|
|
if ( ! vHoles[i].bTempDrill &&
|
|
vHoles[i].vIndMainTool[nMyConfig] == nIndToolMain &&
|
|
vHoles[i].vToolHole[nMyConfig] == i &&
|
|
vHoles[i].vVtAux[nMyConfig].IsValid()) {
|
|
vConfInds_Greedy1.emplace_back( vConfInds_Greedy0[nC]) ;
|
|
break ;
|
|
}
|
|
}
|
|
}
|
|
// se ho meno di due configurazioni, ho trovato quella "ottimale"
|
|
if ( int( vConfInds_Greedy1.size()) < 2) {
|
|
if ( ! vConfInds_Greedy1.empty())
|
|
nBestConf = vConfInds_Greedy1[0] ;
|
|
return true ;
|
|
}
|
|
|
|
// ... servono altri test di ottimizzazione ? ...
|
|
nBestConf = vConfInds_Greedy1[0] ;
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Drilling::GetConfigsWithMoreDrilledHoles( const VECTORHOLE& vHoles, INTVECTOR& vInds)
|
|
{
|
|
/*
|
|
controllando il parambetro bTempDrilled, la funzione restituisce la configurazione
|
|
( le configurazioni ) che svuotano il maggior numero di fori
|
|
*/
|
|
|
|
// se non ho fori, allora non faccio nulla
|
|
vInds.clear() ;
|
|
if ( vHoles.empty())
|
|
return true ;
|
|
|
|
// scrorro le configurazioni presenti
|
|
int nMaxDrilled = 0 ;
|
|
for ( int nC = 0 ; nC < int( vHoles[0].vToolHole.size()) ; ++ nC) {
|
|
// scorro i fori
|
|
int nCurrDrilled = 0 ;
|
|
for ( int nH = 0 ; nH < int( vHoles.size()) ; ++ nH) {
|
|
// se il foro è già lavorato, passo al successivo
|
|
if ( vHoles[nH].bTempDrill)
|
|
continue ;
|
|
// controllo se il foro non lavorato ha una configurazione valida
|
|
if ( vHoles[nH].vToolHole[nC] != IND_TOOL_INVALID &&
|
|
vHoles[nH].vIndTools[nC] != IND_TOOL_INVALID &&
|
|
vHoles[nH].vVtAux[nC].IsValid())
|
|
++ nCurrDrilled ;
|
|
}
|
|
if ( nCurrDrilled > nMaxDrilled)
|
|
nMaxDrilled = nCurrDrilled ;
|
|
}
|
|
// se non ho trovato configurazioni, vuol dire che tutti i fori sono lavorati o che non
|
|
// esiste una configurazione ammissibile
|
|
if ( nMaxDrilled == 0)
|
|
return true ;
|
|
|
|
// cerco tutte le configurazioni che svuotano nMaxDrilled fori
|
|
for ( int nC = 0 ; nC < int( vHoles[0].vToolHole.size()) ; ++ nC) {
|
|
// scorro i fori
|
|
int nCurrDrilled = 0 ;
|
|
for ( int nH = 0 ; nH < int( vHoles.size()) ; ++ nH) {
|
|
// se il foro è già lavorato, passo al successivo
|
|
if ( vHoles[nH].bTempDrill)
|
|
continue ;
|
|
// controllo se il foro non lavorato ha una configurazione valida
|
|
if ( vHoles[nH].vToolHole[nC] != IND_TOOL_INVALID &&
|
|
vHoles[nH].vIndTools[nC] != IND_TOOL_INVALID &&
|
|
vHoles[nH].vVtAux[nC].IsValid())
|
|
++ nCurrDrilled ;
|
|
}
|
|
if ( nCurrDrilled == nMaxDrilled)
|
|
vInds.emplace_back( nC) ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Drilling::EraseDuplicatedConfigs( VECTORHOLE& vHoles)
|
|
{
|
|
/* funzione per rimuovere le configurazioni tra loro equivalenti */
|
|
|
|
// scorro il vettore dei fori
|
|
if ( vHoles.empty())
|
|
return true ;
|
|
|
|
// analizzo il primo foro selezionato e scorro le configurazioni
|
|
for ( int nC = 0 ; nC < int( vHoles[0].vIndTools.size()) - 1 ; ++ nC) {
|
|
for ( int nC1 = nC + 1 ; nC1 < int( vHoles[0].vToolHole.size()) ; ++ nC1) {
|
|
if ( vHoles[0].vToolHole[nC] == vHoles[0].vToolHole[nC1] &&
|
|
vHoles[0].vIndTools[nC] == vHoles[0].vIndTools[nC1] &&
|
|
( AreSameVectorApprox( vHoles[0].vVtAux[nC], vHoles[0].vVtAux[nC1]) ||
|
|
( ! vHoles[0].vVtAux[nC].IsValid() && ! vHoles[0].vVtAux[nC1].IsValid()))) {
|
|
// controllo se vale anche per gli altri fori
|
|
bool bSame = true ;
|
|
for ( int i = 1 ; i < int( vHoles.size()) && bSame ; ++ i) {
|
|
bSame = ( vHoles[i].vToolHole[nC] == vHoles[i].vToolHole[nC1] &&
|
|
vHoles[i].vIndTools[nC] == vHoles[i].vIndTools[nC1] &&
|
|
( AreSameVectorApprox( vHoles[i].vVtAux[nC], vHoles[i].vVtAux[nC1]) ||
|
|
( ! vHoles[i].vVtAux[nC].IsValid() && ! vHoles[i].vVtAux[nC1].IsValid()))) ;
|
|
}
|
|
if ( bSame) {
|
|
for ( int k = 0 ; k < int( vHoles.size()) ; ++ k) {
|
|
vHoles[k].vToolHole.erase( vHoles[k].vToolHole.begin() + nC1) ;
|
|
vHoles[k].vIndTools.erase( vHoles[k].vIndTools.begin() + nC1) ;
|
|
vHoles[k].vVtAux.erase( vHoles[k].vVtAux.begin() + nC1) ;
|
|
}
|
|
-- nC1 ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return true ;
|
|
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Drilling::KeepMinRotatedConfigs( VECTORHOLE& vHoles, const Vector3d& vtAux, const Vector3d& vtTool)
|
|
{
|
|
/* riduco il numero di cobinazioni in base a vtAux */
|
|
|
|
// se non ho fori, allora esco
|
|
if ( vHoles.empty())
|
|
return true ;
|
|
|
|
// scorro il vettore dei fori
|
|
for ( int i = 0 ; i < int( vHoles.size()) ; ++ i) {
|
|
Vector3d vtMinAndDegAux ;
|
|
double dMinAngDeg = ANG_FULL ;
|
|
for ( int j = 0 ; j < int( vHoles[i].vVtAux.size()) ; ++ j) {
|
|
// se non valido, passo al successivo
|
|
if ( ! vHoles[i].vVtAux[j].IsValid())
|
|
continue ;
|
|
// calcolo l'angolo con segno della configurazione rispetto a vtAux
|
|
double dAngDeg ;
|
|
bool bDet ;
|
|
if ( ! vHoles[i].vVtAux[j].GetRotation( vtAux, vtTool, dAngDeg, bDet))
|
|
return false ;
|
|
// conservo l'angolo minimo
|
|
if ( abs( dAngDeg) < dMinAngDeg) {
|
|
dMinAngDeg = abs( dAngDeg) ;
|
|
vtMinAndDegAux = vHoles[i].vVtAux[j] ;
|
|
}
|
|
}
|
|
for ( int j = 0 ; j < int( vHoles[i].vVtAux.size()) ; ++ j) {
|
|
// se vettore ausiliario corrente diverso da quello minimo e non presente tra le configurazioni
|
|
// valide, allora rendo invalida la configurazione
|
|
if ( vHoles[i].vVtAux[j].IsValid() && ! AreSameOrOppositeVectorApprox( vHoles[i].vVtAux[j], vtMinAndDegAux)) {
|
|
vHoles[i].vToolHole[j] = IND_TOOL_INVALID ;
|
|
vHoles[i].vIndTools[j] = IND_TOOL_INVALID ;
|
|
vHoles[i].vVtAux[j] = V_INVALID ;
|
|
}
|
|
}
|
|
}
|
|
|
|
// cancello tutte le configurazioni invalide
|
|
int nSize = int( vHoles[0].vIndTools.size()) ;
|
|
for ( int j = 0 ; j < nSize ; ++ j) {
|
|
bool bInvalid = true ;
|
|
for ( int i = 0 ; i < int( vHoles.size()) && bInvalid ; ++ i)
|
|
bInvalid = ( vHoles[i].vIndTools[j] == IND_TOOL_INVALID &&
|
|
vHoles[i].vToolHole[j] == IND_TOOL_INVALID &&
|
|
! vHoles[i].vVtAux[j].IsValid()) ;
|
|
if ( bInvalid) {
|
|
for ( int k = 0 ; k < int( vHoles.size()) ; ++ k) {
|
|
vHoles[k].vToolHole.erase( vHoles[k].vToolHole.begin() + j) ;
|
|
vHoles[k].vIndTools.erase( vHoles[k].vIndTools.begin() + j) ;
|
|
vHoles[k].vVtAux.erase( vHoles[k].vVtAux.begin() + j) ;
|
|
} ;
|
|
-- nSize ;
|
|
-- j ;
|
|
}
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Drilling::CalcMultiHeadUndrilledHoles( const VECTORHOLE& vHoles, INTVECTOR& vIdUndrilledHoles)
|
|
{
|
|
/* funzione per calcolare gli Id dei fori fori non lavorati */
|
|
|
|
// se non ho fori, ho finito
|
|
if ( vHoles.empty())
|
|
return true ;
|
|
|
|
// scorro sui fori
|
|
for ( int i = 0 ; i < int( vHoles.size()) ; ++ i) {
|
|
// scorro sulle configurazioni trovate
|
|
bool bIsUndrilled = true ;
|
|
for ( int j = 0 ; j < int( vHoles[i].vIndTools.size()) && bIsUndrilled ; ++ j)
|
|
bIsUndrilled = ( vHoles[i].vIndTools[j] == IND_TOOL_INVALID &&
|
|
vHoles[i].vToolHole[j] == IND_TOOL_INVALID &&
|
|
! vHoles[i].vVtAux[j].IsValid()) ;
|
|
// se foro non lavorabile, lo inserisco nel vettore
|
|
if ( bIsUndrilled)
|
|
vIdUndrilledHoles.emplace_back( vHoles[i].hole.nOriId) ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Drilling::CalcMultiHeadPartialDrilledHoles( const TABMHDRILL& vDrills, const VECTORHOLE& vHoles, const VECTORTOOL& vTools,
|
|
const INTVECTOR& vIdUndrilledHoles, INTDBLVECTOR& vIdPartialdrilledHoles)
|
|
{
|
|
// se non ho configurazioni, allora non devo fare nulla
|
|
vIdPartialdrilledHoles.clear() ;
|
|
if ( vDrills.empty())
|
|
return true ;
|
|
|
|
// tutti i fori non lavorabili non sono parzialmente lavorati
|
|
vector<pair<bool, double>> vbPartDrill( vHoles.size(), make_pair( true, INFINITO)) ;
|
|
for ( int nH = 0 ; nH < int( vHoles.size()) && ! vIdUndrilledHoles.empty() ; ++ nH) {
|
|
if ( find( vIdUndrilledHoles.begin(), vIdUndrilledHoles.end(), vHoles[nH].hole.nOriId) != vIdUndrilledHoles.end())
|
|
vbPartDrill[nH].first = false ; // non potrà essere lavorato parzialmente...
|
|
}
|
|
|
|
// scorro le configurazioni
|
|
for ( int nC = 0 ; nC < int( vDrills.size()) ; ++ nC) {
|
|
// scorro i fori che compaiono nella configurazione nC-esima
|
|
for ( int nH = 0 ; nH < int( vDrills[nC].vMatMask.size()) ; ++ nH) {
|
|
int nIndH = vDrills[nC].vMatMask[nH].first ;
|
|
int nIndT = vDrills[nC].vMatMask[nH].second ;
|
|
// controllo per estrema sicurezza che gli indici siano corretti (_controllo_per_sicurezza_(debug))
|
|
if ( nIndH < 0 || nIndH >= int( vHoles.size()) ||
|
|
nIndT < 0 || nIndT >= int( vTools.size()))
|
|
return false ; // non dovrei capitare qui...
|
|
// se foro già lavorato completamente, non lo controllo, passo al foro successivo
|
|
if ( ! vbPartDrill[nIndH].first)
|
|
continue ;
|
|
// se il foro ha una lunghezza inferiore al MaxMaterial dell'utensile, allora è lavorato completamente
|
|
double dAddLen = ( vHoles[nIndH].hole.bBlind ? 0 : m_Params.m_dThroughAddLen) ;
|
|
if ( ( vHoles[nIndH].hole.dLen + dAddLen) < vTools[nIndT].pTool->m_dMaxMat + EPS_SMALL) {
|
|
vbPartDrill[nIndH].first = false ;
|
|
vbPartDrill[nIndH].second = 0. ;
|
|
}
|
|
else {
|
|
vbPartDrill[nIndH].second = min( vbPartDrill[nIndH].second,
|
|
( vHoles[nIndH].hole.dLen + dAddLen) - vTools[nIndT].pTool->m_dMaxMat) ;
|
|
}
|
|
}
|
|
}
|
|
|
|
// tutti i fori non lavorati completamente, quindi per i quali sono inseriti SOLO tools di MaxMaterial
|
|
// inferiore alla lunghezza stessa, sono lavorati parzialmente ( una maschera di compatibilità è
|
|
// comunque stata trovata )
|
|
for ( int i = 0 ; i < int( vbPartDrill.size()) ; ++ i) {
|
|
if ( vbPartDrill[i].first)
|
|
vIdPartialdrilledHoles.emplace_back( make_pair( vHoles[i].hole.nOriId, vbPartDrill[i].second)) ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Drilling::CheckBasedConfig( const VECTORHOLE& vHoles, int nHoleInd, int& nValidConfig, bool& bBaseCase)
|
|
{
|
|
// controllo dei parametri
|
|
if ( nHoleInd < 0 || nHoleInd >= int( vHoles.size()))
|
|
return false ;
|
|
if ( vHoles.empty())
|
|
return false ;
|
|
|
|
bBaseCase = false ;
|
|
nValidConfig = 0 ;
|
|
Vector3d vtAuxRef ;
|
|
for ( int i = 0 ; i < int( vHoles[nHoleInd].vIndTools.size()) ; ++ i) {
|
|
if ( vHoles[nHoleInd].vIndTools[i] != IND_TOOL_INVALID) {
|
|
++ nValidConfig ;
|
|
if ( nValidConfig == 1)
|
|
vtAuxRef = vHoles[nHoleInd].vVtAux[i] ;
|
|
else {
|
|
// controllo se i versori ausiliari sono opposti
|
|
if ( ! AreOppositeVectorApprox( vtAuxRef, vHoles[nHoleInd].vVtAux[i]))
|
|
return true ;
|
|
}
|
|
}
|
|
}
|
|
bBaseCase = ( nValidConfig == 1 || nValidConfig == 2) ;
|
|
return true ;
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Drilling::MultiHeadOrderConfig( TABMHDRILL& tabDrills, const VECTORHOLE& vHoles,
|
|
const Vector3d& vtTool, const Vector3d& vtAux)
|
|
{
|
|
/* funzione per riordinare le calate; viene creato un frame mediante vtTool e vtAux e si ordinano
|
|
i punti in locale a tale frame in base alla vicinanza che hanno dal punto minimo del boxXY */
|
|
|
|
// se non ho calate, non faccio nulla
|
|
if ( tabDrills.empty())
|
|
return true ;
|
|
|
|
// creo il sistema di riferimento locale
|
|
Frame3d frOrder ;
|
|
if ( ! frOrder.Set( ORIG, vtTool, vtAux))
|
|
return false ;
|
|
// creo un vettore con i punti sulla base superiore dei fori in locale a tale frame
|
|
// li inserisco anche nel Box
|
|
PNTVECTOR vPtLoc ;
|
|
BBox3d BBoxOrder ;
|
|
for ( int i = 0 ; i < int( tabDrills.size()) ; ++ i) {
|
|
vPtLoc.emplace_back( GetToLoc( vHoles[tabDrills[i].nHoleInd].hole.ptIni, frOrder)) ;
|
|
BBoxOrder.Add( vPtLoc.back()) ;
|
|
}
|
|
// recupero il punto minimo del Box
|
|
Point3d ptMinBoxOrder = BBoxOrder.GetMin() ;
|
|
// cerco l'indice della tabDrills il cui foro è più vicino al punto di minimo del box trovato
|
|
int nIndClosestHole = 0 ;
|
|
double dSqMinDist = INFINITO ;
|
|
for ( int i = 0 ; i < int( vPtLoc.size()) ; ++ i) {
|
|
double dCurrSqDist = SqDist( vPtLoc[i], ptMinBoxOrder) ;
|
|
if ( dCurrSqDist < dSqMinDist) {
|
|
dSqMinDist = dCurrSqDist ;
|
|
nIndClosestHole = i ;
|
|
}
|
|
}
|
|
// metto l'indice trovato in prima posizione
|
|
swap( tabDrills[nIndClosestHole], tabDrills[0]) ;
|
|
|
|
// una volta determinato il primo foro
|
|
struct OrderTabDrill {
|
|
int nHoleInd ;
|
|
Point3d ptIni ;
|
|
OrderTabDrill( int nHInd, Point3d ptI)
|
|
: nHoleInd( nHInd), ptIni( ptI) {} ;
|
|
} ;
|
|
vector<OrderTabDrill> vOrderedTab ;
|
|
for ( int i = 0 ; i < int( tabDrills.size()) ; ++ i)
|
|
vOrderedTab.emplace_back( tabDrills[i].nHoleInd, vHoles[tabDrills[i].nHoleInd].hole.ptIni) ;
|
|
// per sicurezza ...
|
|
if ( vOrderedTab.empty())
|
|
return false ;
|
|
|
|
// prendo come riferimento il primo punto
|
|
Point3d ptRef = vOrderedTab[0].ptIni ;
|
|
double dMinSqDist = INFINITO ;
|
|
int nIndexSwitch = -1 ;
|
|
// ordino le successioni di calate
|
|
for ( int i = 0 ; i < int( vOrderedTab.size()) - 1 ; ++ i) {
|
|
for ( int j = i + 1 ; j < int( vOrderedTab.size()) ; ++ j) {
|
|
Point3d ptS = vOrderedTab[j].ptIni ;
|
|
double dSqCurrDist = SqDist( ptS, ptRef) ;
|
|
if ( dSqCurrDist < dMinSqDist) {
|
|
dMinSqDist = dSqCurrDist ;
|
|
nIndexSwitch = j ;
|
|
}
|
|
}
|
|
if ( nIndexSwitch != i + 1) {
|
|
swap( vOrderedTab[nIndexSwitch], vOrderedTab[i + 1]) ;
|
|
swap( tabDrills[nIndexSwitch], tabDrills[i + 1]) ;
|
|
}
|
|
|
|
ptRef = vOrderedTab[i + 1].ptIni ;
|
|
dMinSqDist = INFINITO ;
|
|
}
|
|
|
|
return true ;
|
|
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Drilling::GetHoleBestConfig( VECTORHOLE& vHoles, const VECTORTOOL& vTools, int nInd, TABMHDRILL& tabDrills, const Vector3d& vtAux,
|
|
const Vector3d& vtTool, int& nOkHole)
|
|
{
|
|
// salvo gli indici dei fori ( non ancora lavorati) che vengono lavorati con la sola consifugrazione presente
|
|
int nMaxDrilledHoles = - 1 ;
|
|
INTVECTOR vInds ;
|
|
int nRefConfig = -1 ;
|
|
// scorro le configurazioni presenti
|
|
for ( int i = 0 ; i < int( vHoles[nInd].vToolHole.size()) ; ++ i) {
|
|
// se configurazione non valida passo alla successiva
|
|
if ( vHoles[nInd].vToolHole[i] == IND_TOOL_INVALID || /*&&*/
|
|
vHoles[nInd].vIndTools[i] == IND_TOOL_INVALID || /*&&*/
|
|
! vHoles[nInd].vVtAux[i].IsValid())
|
|
continue ;
|
|
// determino se esiste la prima configurazione ammissibile per tale foro
|
|
INTVECTOR vIndsTemp ;
|
|
if ( ! CalcDrilledHolesByConfig( vHoles, nInd, i, vIndsTemp))
|
|
return false ;
|
|
if ( int( vIndsTemp.size()) > nMaxDrilledHoles) {
|
|
nMaxDrilledHoles = int( vIndsTemp.size()) ;
|
|
nRefConfig = i ;
|
|
vInds = vIndsTemp ;
|
|
}
|
|
else if ( int( vIndsTemp.size()) == nMaxDrilledHoles) {
|
|
double dAngDeg0, dAngDeg1 ;
|
|
bool bDet0, bDet1 ;
|
|
if ( ! vHoles[nInd].vVtAux[nRefConfig].GetRotation( vtAux, vtTool, dAngDeg0, bDet0) ||
|
|
! vHoles[nInd].vVtAux[i].GetRotation( vtAux, vtTool, dAngDeg1, bDet1))
|
|
return false ;
|
|
if ( abs( dAngDeg0) > abs( dAngDeg1) + EPS_ANG_SMALL) {
|
|
nRefConfig = i ;
|
|
vInds = vIndsTemp ;
|
|
}
|
|
}
|
|
}
|
|
// assegno flag per fori lavorati
|
|
for ( int i = 0 ; i < int( vInds.size()) ; ++ i)
|
|
vHoles[vInds[i]].bDrill = true ;
|
|
// assegno posizioni di ToolMain
|
|
if ( nRefConfig != -1) {
|
|
// creazione matrice di Maschera
|
|
INTINTVECTOR vMyMask ;
|
|
if ( ! MultiHeadHoleToolsConfig( vHoles, nRefConfig, vMyMask))
|
|
return false ;
|
|
// per forza tutte le uscite sono attive
|
|
INTVECTOR vIndActiveExist ;
|
|
for ( int nT = 0 ; nT < int( vTools.size()) ; ++ nT)
|
|
vIndActiveExist.emplace_back( vTools[nT].pTool->m_nExit) ;
|
|
tabDrills.emplace_back( vHoles[nInd].vToolHole[nRefConfig], vHoles[nInd].vVtAux[nRefConfig],
|
|
vIndActiveExist, vTools[vHoles[nInd].vIndMainTool[nRefConfig]], vMyMask) ;
|
|
nOkHole += int( vInds.size()) ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Drilling::MultiHeadHoleToolsConfig( const VECTORHOLE& vHoles, int nConfig, INTINTVECTOR& vConfMask)
|
|
{
|
|
// controllo dei parametri
|
|
vConfMask.clear() ;
|
|
if ( vHoles.empty())
|
|
return true ;
|
|
if ( nConfig < 0 || nConfig >= int( vHoles[0].vIndMainTool.size()))
|
|
return false ;
|
|
|
|
// scorro i fori
|
|
for ( int nH = 0 ; nH < int( vHoles.size()) ; ++ nH) {
|
|
// recupero la configurazione attuale se valida
|
|
if ( vHoles[nH].vIndTools[nConfig] != IND_TOOL_INVALID &&
|
|
vHoles[nH].vIndMainTool[nConfig] != IND_TOOL_INVALID &&
|
|
vHoles[nH].vVtAux[nConfig].IsValid())
|
|
vConfMask.emplace_back( make_pair( nH, vHoles[nH].vIndTools[nConfig])) ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Drilling::MultiHeadDrilling( const SELVECTOR& vId, int nClId, bool bFixed, TABMHDRILL& tabDrills, double& dMHOff)
|
|
{
|
|
// controllo parametri
|
|
tabDrills.clear() ;
|
|
if ( vId.empty())
|
|
return true ;
|
|
|
|
// gestore degli utensili
|
|
ToolsMgr* pTMgr = m_pMchMgr->GetCurrToolsMgr() ;
|
|
if ( pTMgr == nullptr)
|
|
return false ;
|
|
|
|
// recupero il nome della testa e il numero di uscite
|
|
string sHead ;
|
|
m_pMchMgr->GetCurrMachine()->GetCurrHead( sHead) ;
|
|
int nExitCnt = m_pMchMgr->GetCurrMachine()->GetHeadExitCount( sHead) ;
|
|
|
|
// Recupero i dati degli utensili montati sulla testa
|
|
int nMainToolInd = -1 ;
|
|
VECTORTOOL vTools ; vTools.reserve( nExitCnt) ;
|
|
// ricavo gli utensili presenti sulle uscite
|
|
for ( int nT = 0 ; nT < nExitCnt ; ++ nT) {
|
|
string sToolName ;
|
|
if ( ! m_pMchMgr->GetLoadedTool( sHead, nT + 1, sToolName) || sToolName.empty()) {
|
|
// non c'è utensile
|
|
vTools.emplace_back( nullptr) ;
|
|
continue ;
|
|
}
|
|
// se presente e valido
|
|
const ToolData* pTdata = pTMgr->GetTool( sToolName) ;
|
|
vTools.emplace_back( pTdata) ;
|
|
// imposto il tool di riferimento come il tool m_TParams
|
|
if ( pTdata->m_Uuid == m_TParams.m_Uuid)
|
|
nMainToolInd = nT ;
|
|
}
|
|
// se non ho utensili attivi o validi, errore
|
|
if ( nMainToolInd == -1 || vTools.empty()) {
|
|
m_pMchMgr->SetLastError( 2116, "Error in Drilling : multi drilling head without valid tools") ;
|
|
return false ;
|
|
}
|
|
|
|
// recupero i dati dell'uscita dell'utensile principale
|
|
Vector3d vtTool, vtAux ;
|
|
Point3d ptExit ;
|
|
m_pMchMgr->GetCurrMachine()->GetHeadExitPosDirAux( sHead, nMainToolInd + 1, ptExit, vtTool, vtAux) ;
|
|
vTools[nMainToolInd].ptToolTip = ptExit - vtTool * vTools[nMainToolInd].pTool->m_dLen ;
|
|
if ( vtAux.IsSmall() && m_pMchMgr->GetCurrMachine()->GetCurrRotAxes() == 0)
|
|
vtAux = FromUprightOrtho( vtTool) ;
|
|
if ( vtTool.IsSmall() || vtAux.IsSmall()) {
|
|
m_pMchMgr->SetLastError( 2117, "Error in Drilling : incorrect multi drilling head") ;
|
|
return false ;
|
|
}
|
|
|
|
// carico gli altri dati della testa con le sue uscite
|
|
for ( int nT = 0 ; nT < nExitCnt ; ++ nT) {
|
|
// se utensile principale, salto al successivo
|
|
if ( nT == nMainToolInd)
|
|
continue ;
|
|
// se non attrezzato, salto al successivo
|
|
if ( vTools[nT].pTool == nullptr)
|
|
continue ;
|
|
// recupero i dati dell'uscita
|
|
Point3d ptExit ;
|
|
Vector3d vtCurrDir, vtCurrAux ;
|
|
m_pMchMgr->GetCurrMachine()->GetHeadExitPosDirAux( sHead, nT + 1, ptExit, vtCurrDir, vtCurrAux) ;
|
|
// controllo abbia la stessa direzione del principale, altrimenti disattrezzo
|
|
if ( ! AreSameVectorApprox( vtCurrDir, vtTool)) {
|
|
vTools[nT].pTool = nullptr ;
|
|
continue ;
|
|
}
|
|
// assegno tip utensile
|
|
vTools[nT].ptToolTip = ptExit - vtCurrDir * vTools[nT].pTool->m_dLen ;
|
|
}
|
|
|
|
// Recupero le geometrie dei fori
|
|
bool bSomeHoleOk = false ;
|
|
VECTORHOLE vHoles( vId.size()) ;
|
|
for ( int nH = 0 ; nH < int( vId.size()) ; ++ nH) {
|
|
Hole hole ;
|
|
if ( ! GetHoleData( m_vId[nH], hole)) {
|
|
string sInfo = "Warning in Drilling : Skipped entity " + ToString( m_vId[nH]) ;
|
|
m_pMchMgr->SetWarning( 2151, sInfo) ;
|
|
m_vUndrilledId.emplace_back( m_vId[nH].nId) ;
|
|
continue ;
|
|
}
|
|
// se richiesta inversione e foro passante, provvedo
|
|
if ( m_Params.m_bInvert) {
|
|
if ( hole.bBlind) {
|
|
m_pMchMgr->SetLastError( 2114, "Error in Drilling : blind hole not reversible") ;
|
|
return false ;
|
|
}
|
|
else {
|
|
hole.ptIni -= hole.vtDir * hole.dThick ;
|
|
hole.vtDir.Invert() ;
|
|
}
|
|
}
|
|
// se lavorazione del foro non arriva al suo fondo, lo considero cieco
|
|
if ( hole.dLen < hole.dThick - 10 * EPS_SMALL)
|
|
hole.bBlind = true ;
|
|
|
|
vHoles[nH].hole = hole ;
|
|
vHoles[nH].nIndInSelVector = nH ;
|
|
bSomeHoleOk = true ;
|
|
}
|
|
if ( ! bSomeHoleOk)
|
|
return true ;
|
|
|
|
// imposto eventuale asse bloccato da lavorazione
|
|
SetBlockedRotAxis( m_Params.m_sBlockedAxis) ;
|
|
// applico eventuali blocchi di assi rotanti
|
|
m_pMchMgr->ApplyRotAxisBlock() ;
|
|
|
|
// se utensili non selezionabili
|
|
// NB. Queste due funzioni possono essere accorpate in una unica... dipende da quanto voglio essere
|
|
// selettivo nei criteri di scelta della maschera
|
|
if ( bFixed) {
|
|
// calcolo la maschera di corrispondenza tra utensili e fori
|
|
if ( ! CalcMask( vHoles, vTools, nMainToolInd, vtTool, vtAux))
|
|
return false ;
|
|
}
|
|
// se utensili selezionabili
|
|
else {
|
|
// calcolo la maschera di corrispondenza tra utensili e fori
|
|
if ( ! CalcMaskSel( vHoles, vTools, vtTool, vtAux))
|
|
return false ;
|
|
}
|
|
|
|
#if ENABLE_DEBUG_MULTIHEAD_HOLES
|
|
PrintConfigs( vHoles) ;
|
|
#endif
|
|
|
|
// riduco il numero di configurazioni in base a vtAux
|
|
if ( ! KeepMinRotatedConfigs( vHoles, vtAux, vtTool))
|
|
return false ;
|
|
|
|
// calcolo i fori non lavorati
|
|
if ( ! CalcMultiHeadUndrilledHoles( vHoles, m_vUndrilledId))
|
|
return false ;
|
|
// se non posso lavorare nessun foro, esco
|
|
int nUndrilleds = int( m_vUndrilledId.size()) ;
|
|
if ( nUndrilleds == int( vHoles.size()))
|
|
return true ;
|
|
|
|
// numero di fori lavorati
|
|
int nOkHole = 0 ;
|
|
// se c'è un solo foro va sicuramente bene
|
|
if ( int( vHoles.size()) == 1 && ! vHoles[0].vVtAux.empty()) {
|
|
vHoles[0].bForToolM = true ;
|
|
vHoles[0].nIndTool = nMainToolInd ;
|
|
vHoles[0].nIndHoleToolM = 0 ;
|
|
vHoles[0].vtAux = vHoles[0].vVtAux[0] ;
|
|
}
|
|
|
|
// calcolo la massima differenza di lunghezza tra il primo tool e gli altri ( così l'elevazione finale rimane compatibile)
|
|
double dRefLen = vTools[nMainToolInd].pTool->m_dTLen ;
|
|
double dOffMax = 0 ;
|
|
for ( int nT = 0 ; nT < int( vTools.size()) && nUndrilleds != int( vHoles.size()) ; ++ nT) {
|
|
if ( vTools[nT].pTool == nullptr || nT == nMainToolInd)
|
|
continue ;
|
|
if ( vTools[nT].pTool->m_dTLen > dRefLen + dOffMax)
|
|
dOffMax = vTools[nT].pTool->m_dTLen - dRefLen ;
|
|
}
|
|
dMHOff = dOffMax ;
|
|
|
|
// se testa fissa
|
|
if ( bFixed) {
|
|
// Inizio a considerare i fori che presentano meno configurazioni per essere lavorati.
|
|
// Essi sono i più critici, quindi vengono gestiti per primi, scremando quindi le configurazioni degli altri.
|
|
// Parto ad analizzare i fori lavorabili con una sola possibile configurazione
|
|
|
|
// cerco le configurazioni di base ( quelle con 1 o due configurazioni opposte)
|
|
for ( int i = 0 ; i < int( vHoles.size()) ; ++ i) {
|
|
// se foro già lavorato passo al successivo
|
|
if ( vHoles[i].bDrill)
|
|
continue ;
|
|
// se il foro i-esimo non è base, passo al successivo
|
|
int nValidConfig ;
|
|
bool bBaseCase ;
|
|
if ( ! CheckBasedConfig( vHoles, i, nValidConfig, bBaseCase))
|
|
return false ;
|
|
if ( ! bBaseCase)
|
|
continue ;
|
|
// salvo gli indici dei fori ( non ancora lavorati) che vengono lavorati con la sola configurazione presente
|
|
if ( ! GetHoleBestConfig( vHoles, vTools, i, tabDrills, vtAux, vtTool, nOkHole))
|
|
return false ;
|
|
}
|
|
// se nessun foro lavorabile, esco ( fino a prova contraria non esco mai...)
|
|
if ( tabDrills.empty())
|
|
return false ;
|
|
|
|
// Una volta scremate le configurazioni critiche, cerco i fori non lavorati più vicini ad essi.
|
|
// L'idea è che avendo lavorato i fori a signola configurazione, ottengo meno combinazioni
|
|
// per i fori ad esso adiacenti... l'idea si ripete per tutti i fori successivi
|
|
|
|
// per vicinanza cerco gli altri fori oltre ai casi base
|
|
while ( nOkHole < int( vHoles.size()) - nUndrilleds) {
|
|
INTVECTOR vNextInds ;
|
|
if ( ! GetClosestHolesToHole( vHoles, tabDrills.back().nHoleInd, false, vNextInds) ||
|
|
vNextInds.empty() ||
|
|
! GetHoleBestConfig( vHoles, vTools, vNextInds[0], tabDrills, vtAux, vtTool, nOkHole))
|
|
return false ;
|
|
}
|
|
// per sicurezza ...
|
|
if ( tabDrills.empty())
|
|
return false ;
|
|
|
|
// Analizzando i fori in base alle possibili combinazioni, ho riempito la tabella delle forature
|
|
// multiple con lavorazioni sparse tra loro, riordino quindi le discese degli utensili in base
|
|
// alla vicinanza dei fori lavorati dal Tool principale
|
|
if ( ! MultiHeadOrderConfig( tabDrills, vHoles, vtTool, vtAux))
|
|
return false ;
|
|
}
|
|
// se utensili selezionabili
|
|
else {
|
|
// Inizio a considerare le configurazioni che presentano più utensili attivi, decrementando
|
|
// con il numero di passsate gli utensili selezionati
|
|
if ( ! OrderConfigsForSelectableTools( vHoles, vTools, nMainToolInd, tabDrills))
|
|
return false ;
|
|
}
|
|
|
|
// controllo i fori lavorati parzialmente dalle configurazioni trovate
|
|
if ( ! CalcMultiHeadPartialDrilledHoles( tabDrills, vHoles, vTools, m_vUndrilledId, m_vPartialDrilledId))
|
|
return false ;
|
|
|
|
#if ENABLE_DEBUG_MULTIHEAD_HOLES
|
|
string sRow = "Undrilled Holes : " ;
|
|
for ( int _a = 0 ; _a < int( m_vUndrilledId.size()) ; ++ _a)
|
|
sRow.append( ( _a == 0 ? "" : ",") + ToString( m_vUndrilledId[_a])) ;
|
|
LOG_ERROR( GetEMkLogger(), sRow.c_str()) ;
|
|
string sRow1 = "Partial Drilled Holes : " ;
|
|
for ( int _a = 0 ; _a < int( m_vPartialDrilledId.size()) ; ++ _a) {
|
|
sRow1.append( ( _a == 0 ? "" : ",") + ToString( m_vPartialDrilledId[_a].first)) ;
|
|
sRow1.append( " Missing Len : " + ToString( m_vPartialDrilledId[_a].second)) ;
|
|
}
|
|
LOG_ERROR( GetEMkLogger(), sRow1.c_str()) ;
|
|
#endif
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Drilling::CalcMask( VECTORHOLE& vHoles, const VECTORTOOL& vTools, int nIndMT,
|
|
const Vector3d& vtTool, const Vector3d& vtAux)
|
|
{
|
|
/*
|
|
funzione per il calcolo della maschera di compatibilità tra un insieme di utensili e
|
|
un insieme di fori.
|
|
Funzione chiamata per utensili non selezionabili
|
|
*/
|
|
|
|
// controllo dei parametri
|
|
if ( vHoles.empty() || vTools.empty())
|
|
return false ;
|
|
|
|
// recupero il valore di tolleranza sul diametro
|
|
double dDiamToler = GetHoleDiamToler() ;
|
|
|
|
int nExitCnt = int( vTools.size()) ;
|
|
int nNullTools = 0 ;
|
|
for ( int i = 0 ; i < int( vTools.size()) ; ++ i) {
|
|
if ( vTools[i].pTool == nullptr)
|
|
++ nNullTools ;
|
|
}
|
|
|
|
// in ogni foro i-esimo inserisco il Tool principale
|
|
for ( int i = 0 ; i < int( vHoles.size()) ; ++ i) {
|
|
// resetto le variabili di controllo di lavorazione temporanea per tutti i fori
|
|
for ( int j = 0 ; j < int( vHoles.size()) ; ++ j) {
|
|
vHoles[j].bTempDrill = false ;
|
|
vHoles[j].nTempTool = -1 ;
|
|
}
|
|
// verifica validità del foro i-esimo per il Tool principale
|
|
Hole Hole_i = vHoles[i].hole ;
|
|
if ( ! MultiHeadVerifyHole( Hole_i, vTools[nIndMT].pTool, dDiamToler, m_vId[vHoles[i].nIndInSelVector]))
|
|
continue ;
|
|
|
|
// angoli per allineare versore T del tool principale con vtDir del foro i-esimo
|
|
int nStat ;
|
|
DBLVECTOR vAng1, vAng2 ;
|
|
if ( ! m_pMchMgr->GetCalcAngles( Hole_i.vtDir, V_NULL, nStat, vAng1, vAng2))
|
|
continue ;
|
|
Vector3d vtTnew ;
|
|
// check che versore T sia allineato con vtDir
|
|
if ( ! m_pMchMgr->GetCalcToolDirFromAngles( vAng1, vtTnew) || ! AreSameVectorApprox( vtTnew, Hole_i.vtDir))
|
|
continue ;
|
|
Vector3d vtAnew ;
|
|
// nuova configurazione del versore A ottenuta
|
|
if ( ! m_pMchMgr->GetCalcAuxDirFromAngles( vAng1, vtAnew))
|
|
continue ;
|
|
if ( vtAnew.IsSmall() && m_pMchMgr->GetCurrMachine()->GetCurrRotAxes() == 0)
|
|
vtAnew = vtAux ;
|
|
|
|
// creo un nuovo sistema di riferimento centrato nel Tool principale
|
|
Frame3d frMT ;
|
|
frMT.Set( vTools[nIndMT].ptToolTip, vtTool, vtAux) ;
|
|
if ( ! frMT.IsValid())
|
|
return false ;
|
|
// creo un frame nel foro i-esimo orientato come il frame sul tool principale ( origine nella base interna del foro)
|
|
Frame3d frHMT ;
|
|
frHMT.Set( Hole_i.ptIni - Hole_i.vtDir * Hole_i.dLen, vtTnew, vtAnew) ;
|
|
if ( ! frHMT.IsValid())
|
|
return false ;
|
|
// numero di forature inserendo il Tool principale nel foro i-esimo
|
|
int nDrills = 1 ;
|
|
// setto le variabili temporanee per il foro i-esimo
|
|
vHoles[i].bTempDrill = true ;
|
|
vHoles[i].nTempTool = nIndMT ;
|
|
|
|
// controllo la compatibilità tra le geometrie dei Tool e dei fori
|
|
CheckOtherHolesWithTools( vHoles, vTools, nIndMT, i, Hole_i, frMT, frHMT, dDiamToler, nDrills) ;
|
|
|
|
// controllo quanti fori sono riuscito a lavorare e setto i loro parametri di foratura
|
|
if ( nDrills == nExitCnt - nNullTools) { // se ho lavorato il numero corretto di fori ...
|
|
for ( int nD = 0 ; nD < int( vHoles.size()) ; ++ nD) {
|
|
if ( vHoles[nD].bTempDrill) {
|
|
vHoles[nD].vToolHole.push_back( i) ; // indice del foro per il tool principale
|
|
vHoles[nD].vIndTools.push_back( vHoles[nD].nTempTool) ; // indice del tool che lavora questo foro
|
|
vHoles[nD].vVtAux.push_back( frHMT.VersX()) ; // versore ausiliario A del tool principale
|
|
vHoles[nD].vIndMainTool.push_back( nIndMT) ; // indice del tool considerato come principale
|
|
}
|
|
else {
|
|
// rendo tutto non valido
|
|
vHoles[nD].vToolHole.push_back( IND_TOOL_INVALID) ;
|
|
vHoles[nD].vIndTools.push_back( IND_TOOL_INVALID) ;
|
|
vHoles[nD].vVtAux.push_back( V_INVALID) ;
|
|
vHoles[nD].vIndMainTool.push_back( nIndMT) ;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
for ( int nD = 0 ; nD < int( vHoles.size()) ; ++ nD)
|
|
vHoles[nD].bTempDrill = false ;
|
|
}
|
|
|
|
// se la testa può ruotare
|
|
if ( nStat < 0) {
|
|
// inizio a scorrere tutti i tools
|
|
for ( int nT = 0 ; nT < int( vTools.size()) ; ++ nT) {
|
|
if ( vTools[nT].pTool == nullptr || nT == nIndMT)
|
|
continue ;
|
|
// cerco se ho un foro j-esimo adatto per quella punta
|
|
for ( int j = 0 ; j < int( vHoles.size()) ; ++ j) {
|
|
Hole Hole_j = vHoles[j].hole ;
|
|
if ( i == j ||
|
|
! AreSameVectorApprox( Hole_j.vtDir, Hole_i.vtDir) ||
|
|
! MultiHeadVerifyHole( Hole_j, vTools[nT].pTool, dDiamToler, m_vId[vHoles[j].nIndInSelVector]))
|
|
continue ;
|
|
// resetto le variabili di controllo di foratura temporanea per tutti i fori
|
|
for ( int k = 0 ; k < int( vHoles.size()) ; ++ k) {
|
|
vHoles[k].bTempDrill = false ;
|
|
vHoles[k].nTempTool = IND_TOOL_INVALID ;
|
|
}
|
|
|
|
// calcolo il vettore uscente dal tool Main e diretto al tool nT-esimo
|
|
Vector3d vtRefT = vTools[nT].ptToolTip - vTools[nIndMT].ptToolTip ;
|
|
// calcolo il vettore uscente dal foro i-esimo e diretto al foro j-esimo
|
|
Vector3d vtRefH = Hole_j.ptIni - Hole_j.vtDir * Hole_j.dLen -
|
|
( Hole_i.ptIni - Hole_i.vtDir * Hole_i.dLen) ;
|
|
|
|
// se le distanze sono compatibili
|
|
if ( abs( vtRefH.Len() - vtRefT.Len()) < EPS_SMALL) {
|
|
// rioriento il frame sul foro i-esimo
|
|
Point3d ptHj = Hole_j.ptIni - Hole_j.vtDir * Hole_j.dLen ;
|
|
ptHj.ToLoc( frHMT) ;
|
|
Vector3d vtProjB( ptHj.x, ptHj.y, 0) ;
|
|
|
|
Point3d ptTt = vTools[nT].ptToolTip ;
|
|
ptTt.ToLoc( frMT) ;
|
|
Vector3d vtProjA( ptTt.x, ptTt.y, 0) ;
|
|
|
|
double dAngle ; vtProjA.GetAngleXY( vtProjB, dAngle) ;
|
|
frHMT.Rotate( frHMT.Orig(), frHMT.VersZ(), dAngle) ;
|
|
|
|
nDrills = 1 ; // foratura nel foro i-esimo e j-esimo
|
|
CheckOtherHolesWithTools( vHoles, vTools, nIndMT, i, Hole_i, frMT, frHMT, dDiamToler, nDrills) ;
|
|
|
|
// setto le variabili temporanee per il foro i-esimo
|
|
vHoles[i].bTempDrill = true ;
|
|
vHoles[i].nTempTool = nIndMT ;
|
|
|
|
// controllo quanti fori sono riuscito a lavorare in questo nuovo sistema di riferimento
|
|
if ( nDrills == nExitCnt - nNullTools) {
|
|
for ( int nD = 0 ; nD < int( vHoles.size()) ; ++ nD) {
|
|
if ( vHoles[nD].bTempDrill) {
|
|
vHoles[nD].vToolHole.push_back( i) ; // indice del foro per il tool principale
|
|
vHoles[nD].vIndTools.push_back( vHoles[nD].nTempTool) ; // indice del tool che lavora questo foro
|
|
vHoles[nD].vVtAux.push_back( frHMT.VersX()) ; // versore ausiliario del tool principale
|
|
vHoles[nD].vIndMainTool.push_back( nIndMT) ;
|
|
}
|
|
else {
|
|
// rendo tutto non valido
|
|
vHoles[nD].vToolHole.push_back( IND_TOOL_INVALID) ;
|
|
vHoles[nD].vIndTools.push_back( IND_TOOL_INVALID) ;
|
|
vHoles[nD].vVtAux.push_back( V_INVALID) ;
|
|
vHoles[nD].vIndMainTool.push_back( nIndMT) ;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
for ( int nD = 0 ; nD < int( vHoles.size()) ; ++ nD)
|
|
vHoles[nD].bTempDrill = false ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// cancello le configurazioni identiche tra loro ( possono capitare quando i tools sono già
|
|
// allineati con i fori)
|
|
EraseDuplicatedConfigs( vHoles) ;
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Drilling::CalcMaskSel( VECTORHOLE& vHoles, const VECTORTOOL& vTools,
|
|
const Vector3d& vtTool, const Vector3d& vtAux)
|
|
{
|
|
/*
|
|
funzione per il calcolo della maschera di compatibilità tra un insieme di utensili e
|
|
un insieme di fori.
|
|
Funzione chiamata per utensili non selezionabili
|
|
*/
|
|
|
|
// controllo dei parametri
|
|
if ( vHoles.empty() || vTools.empty())
|
|
return false ;
|
|
|
|
// recupero il valore di tolleranza sul diametro
|
|
double dDiamToler = GetHoleDiamToler() ;
|
|
|
|
// per ogni foro i-esimo inserisco un utensile selezionabile
|
|
for ( int i = 0 ; i < int( vHoles.size()) ; ++ i) {
|
|
// resetto le variabili di controllo di lavorazione temporanea per tutti i fori
|
|
for ( int k = 0 ; k < int( vHoles.size()) ; ++ k) {
|
|
vHoles[k].bTempDrill = false ;
|
|
vHoles[k].nTempTool = -1 ;
|
|
}
|
|
// ciclo sugli utensili selezionabili
|
|
for ( int j = 0 ; j < int( vTools.size()) ; ++ j) {
|
|
// se utensile non valido, passo al successivo
|
|
if ( vTools[j].pTool == nullptr)
|
|
continue ;
|
|
for ( int k = 0 ; k < int( vHoles.size()) ; ++ k) {
|
|
vHoles[k].bTempDrill = false ;
|
|
vHoles[k].nTempTool = -1 ;
|
|
}
|
|
// verifica validità del foro i-esimo per il Tool principale
|
|
Hole Hole_i = vHoles[i].hole ;
|
|
if ( ! MultiHeadVerifyHole( Hole_i, vTools[j].pTool, dDiamToler, m_vId[vHoles[i].nIndInSelVector]))
|
|
continue ;
|
|
|
|
// angoli per allineare versore T del tool principale con vtDir del foro i-esimo
|
|
int nStat ;
|
|
DBLVECTOR vAng1, vAng2 ;
|
|
if ( ! m_pMchMgr->GetCalcAngles( Hole_i.vtDir, V_NULL, nStat, vAng1, vAng2))
|
|
continue ;
|
|
Vector3d vtTnew ;
|
|
// check che versore T sia allineato con vtDir
|
|
if ( ! m_pMchMgr->GetCalcToolDirFromAngles( vAng1, vtTnew) || ! AreSameVectorApprox( vtTnew, Hole_i.vtDir))
|
|
continue ;
|
|
Vector3d vtAnew ;
|
|
// nuova configurazione del versore A ottenuta
|
|
if ( ! m_pMchMgr->GetCalcAuxDirFromAngles( vAng1, vtAnew))
|
|
continue ;
|
|
if ( vtAnew.IsSmall() && m_pMchMgr->GetCurrMachine()->GetCurrRotAxes() == 0)
|
|
vtAnew = vtAux ;
|
|
|
|
// creo un nuovo sistema di riferimento centrato nel Tool j-esimo
|
|
Frame3d frMT ;
|
|
frMT.Set( vTools[j].ptToolTip, vtTool, vtAux) ;
|
|
if ( ! frMT.IsValid())
|
|
return false ;
|
|
// creo un frame nel foro i-esimo orientato come il frame sul tool principale ( origine nella base interna del foro)
|
|
Frame3d frHMT ;
|
|
frHMT.Set( Hole_i.ptIni - Hole_i.vtDir * Hole_i.dLen, vtTnew, vtAnew) ;
|
|
if ( ! frHMT.IsValid())
|
|
return false ;
|
|
// numero di forature inserendo il Tool j-esimo nel foro i-esimo
|
|
int nDrills = 1 ;
|
|
// setto le variabili temporanee per il foro i-esimo
|
|
vHoles[i].bTempDrill = true ;
|
|
vHoles[i].nTempTool = j ;
|
|
|
|
// controllo la compatibilità tra le geometrie dei Tool e dei fori
|
|
CheckOtherHolesWithTools( vHoles, vTools, j, i, Hole_i, frMT, frHMT, dDiamToler, nDrills) ;
|
|
|
|
// memorizzo la configurazione attuale
|
|
for ( int nD = 0 ; nD < int( vHoles.size()) ; ++ nD) {
|
|
// se il foro è lavorabile, memorizzo la configurazione
|
|
if ( vHoles[nD].bTempDrill) {
|
|
vHoles[nD].vToolHole.push_back( i) ; // indice del foro per il tool principale
|
|
vHoles[nD].vIndTools.push_back( vHoles[nD].nTempTool) ; // indice del tool che lavora questo foro
|
|
vHoles[nD].vVtAux.push_back( frHMT.VersX()) ; // versore ausiliario A del tool principale
|
|
vHoles[nD].vIndMainTool.push_back( j) ; // indice del tool considerato come principale
|
|
}
|
|
else {
|
|
// rendo tutto non valido
|
|
vHoles[nD].vToolHole.push_back( IND_TOOL_INVALID) ;
|
|
vHoles[nD].vIndTools.push_back( IND_TOOL_INVALID) ;
|
|
vHoles[nD].vVtAux.push_back( V_INVALID) ;
|
|
vHoles[nD].vIndMainTool.push_back( j) ;
|
|
}
|
|
}
|
|
|
|
// se la testa può ruotare
|
|
if ( nStat < 0) {
|
|
// resetto le variabili di controllo di lavorazione temporanea per tutti i fori
|
|
for ( int k = 0 ; k < int( vHoles.size()) ; ++ k) {
|
|
vHoles[k].bTempDrill = false ;
|
|
vHoles[k].nTempTool = -1 ;
|
|
}
|
|
// inizio a scorrere tutti i tools ( ad eccezione del tool j-esimo)
|
|
for ( int nT = 0 ; nT < int( vTools.size()) ; ++ nT) {
|
|
if ( vTools[nT].pTool == nullptr || nT == j)
|
|
continue ;
|
|
// cerco se ho un foro nH-esimo adatto per quella punta
|
|
for ( int nH = 0 ; nH < int( vHoles.size()) ; ++ nH) {
|
|
Hole Hole_nH = vHoles[nH].hole ;
|
|
if ( i == nH ||
|
|
! AreSameVectorApprox( Hole_nH.vtDir, Hole_i.vtDir) ||
|
|
! MultiHeadVerifyHole( Hole_nH, vTools[nT].pTool, dDiamToler, m_vId[vHoles[nH].nIndInSelVector]))
|
|
continue ;
|
|
// resetto le variabili di controllo di foratura temporanea per tutti i fori
|
|
for ( int k = 0 ; k < int( vHoles.size()) ; ++ k) {
|
|
vHoles[k].bTempDrill = false ;
|
|
vHoles[k].nTempTool = IND_TOOL_INVALID ;
|
|
}
|
|
|
|
// calcolo il vettore uscente dal tool j-esimo e diretto al tool nT-esimo
|
|
Vector3d vtRefT = vTools[nT].ptToolTip - vTools[j].ptToolTip ;
|
|
// calcolo il vettore uscente dal foro i-esimo e diretto al foro nH-esimo
|
|
Vector3d vtRefH = Hole_nH.ptIni - Hole_nH.vtDir * Hole_nH.dLen -
|
|
( Hole_i.ptIni - Hole_i.vtDir * Hole_i.dLen) ;
|
|
|
|
// se le distanze sono compatibili
|
|
if ( abs( vtRefH.Len() - vtRefT.Len()) < EPS_SMALL) {
|
|
// rioriento il frame sul foro i-esimo
|
|
Point3d ptHj = Hole_nH.ptIni - Hole_nH.vtDir * Hole_nH.dLen ;
|
|
ptHj.ToLoc( frHMT) ;
|
|
Vector3d vtProjB( ptHj.x, ptHj.y, 0) ;
|
|
|
|
Point3d ptTt = vTools[nT].ptToolTip ;
|
|
ptTt.ToLoc( frMT) ;
|
|
Vector3d vtProjA( ptTt.x, ptTt.y, 0) ;
|
|
|
|
double dAngle ; vtProjA.GetAngleXY( vtProjB, dAngle) ;
|
|
frHMT.Rotate( frHMT.Orig(), frHMT.VersZ(), dAngle) ;
|
|
|
|
nDrills = 1 ; // foratura nel foro i-esimo e jj-esimo
|
|
CheckOtherHolesWithTools( vHoles, vTools, j, i, Hole_i, frMT, frHMT, dDiamToler, nDrills) ;
|
|
|
|
// setto le variabili temporanee per il foro i-esimo
|
|
vHoles[i].bTempDrill = true ;
|
|
vHoles[i].nTempTool = j ;
|
|
|
|
// memorizzo la configurazione attuale
|
|
for ( int nD = 0 ; nD < int( vHoles.size()) ; ++ nD) {
|
|
if ( vHoles[nD].bTempDrill) {
|
|
vHoles[nD].vToolHole.push_back( i) ; // indice del foro per il tool principale
|
|
vHoles[nD].vIndTools.push_back( vHoles[nD].nTempTool) ; // indice del tool che lavora questo foro
|
|
vHoles[nD].vVtAux.push_back( frHMT.VersX()) ; // versore ausiliario del tool principale
|
|
vHoles[nD].vIndMainTool.push_back( j) ; // indice del tool considerato come principale
|
|
}
|
|
else {
|
|
// rendo tutto non valido
|
|
vHoles[nD].vToolHole.push_back( IND_TOOL_INVALID) ;
|
|
vHoles[nD].vIndTools.push_back( IND_TOOL_INVALID) ;
|
|
vHoles[nD].vVtAux.push_back( V_INVALID) ;
|
|
vHoles[nD].vIndMainTool.push_back( j) ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// cancello le configurazioni identiche tra loro ( possono capitare quando i tools sono già
|
|
// allineati con i fori)
|
|
EraseDuplicatedConfigs( vHoles) ;
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Drilling::CheckOtherHolesWithTools( VECTORHOLE& vHoles, const VECTORTOOL& vTools, int nIndTM, int nIndHTM, Hole holeICP,
|
|
const Frame3d& frMT, const Frame3d& frHMT, double dDiamToler, int& nDrills)
|
|
{
|
|
/*
|
|
supponendo di inserire il tool principale nel foro nIndTM-esimo vengono controllate
|
|
le compatibilità tra gli altri utensili e gli altri fori
|
|
*/
|
|
|
|
// controllo parametri
|
|
if ( vHoles.empty() || vTools.empty())
|
|
return true ;
|
|
if ( nIndTM < 0 || nIndTM >= int( vTools.size()) ||
|
|
nIndHTM < 0 || nIndHTM >= int( vHoles.size()) ||
|
|
! frMT.IsValid() || ! frHMT.IsValid() ||
|
|
nDrills < 0 || nDrills > max( int( vHoles.size()), int( vTools.size())))
|
|
return false ;
|
|
|
|
// definisco il punto dove cade il tool principale
|
|
Hole holeTM = holeICP ; // copia del foro i-esimo
|
|
|
|
// ciclo su tutti i tools
|
|
for ( int nT = 0 ; nT < int( vTools.size()) ; ++ nT) {
|
|
if ( vTools[nT].pTool == nullptr || nT == nIndTM)
|
|
continue ;
|
|
// esprimo il punto finale del tool t-esimo nel sistema di riferimento del Tool principale
|
|
Point3d ptETt = vTools[nT].ptToolTip ;
|
|
ptETt.ToLoc( frMT) ;
|
|
// cerco se ho un foro j-esimo adatto per quella punta
|
|
for ( int j = 0 ; j < int( vHoles.size()) ; ++ j) {
|
|
Hole Hole_j = vHoles[j].hole ; // copia del foro j-esimo
|
|
// controllo che il foro j-esimo non sia l'i-esimo, che non sia stato già precedentemente lavorato
|
|
// da un altro tool t'-esimo e che vtDir del foro i-esimo coincida con vtDir del foro j-esimo
|
|
// e che il tool t-esimo sia compatibile con il foro j-esimo
|
|
if ( nIndHTM == j ||
|
|
vHoles[j].bTempDrill ||
|
|
! AreSameVectorApprox( Hole_j.vtDir, holeTM.vtDir) ||
|
|
! MultiHeadVerifyHole( Hole_j, vTools[nT].pTool, dDiamToler, m_vId[vHoles[j].nIndInSelVector]))
|
|
continue ;
|
|
// esprimo il foro j-esimo nel sistema di riferimento del Tool principale centrato nel foro i-esimo
|
|
Point3d ptHj = Hole_j.ptIni - Hole_j.vtDir * Hole_j.dLen ;
|
|
ptHj.ToLoc( frHMT) ;
|
|
// controllo la compatibilità
|
|
if ( AreSamePointApprox( ptHj, ptETt)) {
|
|
// aggiorno il numero di fori lavorati
|
|
++ nDrills ;
|
|
// aggiorno le variabili temporanee
|
|
vHoles[j].bTempDrill = true ;
|
|
vHoles[j].nTempTool = nT ;
|
|
// non controllo gli altri vertici per la punta t-esima
|
|
break ;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Drilling::MultiHeadVerifyHole( Hole& hole, const ToolData* Tool, double dDiamToler, SelData Id)
|
|
{
|
|
/*
|
|
funzione per verificare la compatibilità tra un utensile e un foro, vengono controllati
|
|
i diametri, le profondità e i percorsi dal basso
|
|
*/
|
|
|
|
// verifico che il diamtro del tool sia compatibile con quello del foro
|
|
if ( ! VerifyDiameter( hole.dDiam, Tool->m_dDiam, dDiamToler))
|
|
return false ;
|
|
// imposto elevazione da lunghezza foro con possibilità di sovrascrittura da info
|
|
double dElev = hole.dLen ;
|
|
double dMaxElev ;
|
|
if ( GetValInNotes( m_Params.m_sUserNotes, UN_MAXELEV, dMaxElev) && dElev > dMaxElev) {
|
|
dElev = dMaxElev ;
|
|
hole.ptIni += hole.vtDir * ( dElev - hole.dLen) ;
|
|
hole.dLen = dElev ;
|
|
}
|
|
if ( ! VerifyHoleFromBottom( hole, Id))
|
|
return false ;
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Drilling::AlongCurveProcess( bool bRecalc, int nPvId, int nClId)
|
|
{
|
|
// 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 lavoro
|
|
else if ( bRecalc) {
|
|
m_pGeomDB->EmptyGroup( nAuxId) ;
|
|
bChain = true ;
|
|
}
|
|
|
|
// se necessario, eseguo concatenamento ed inserisco i percorsi sotto la geometria ausiliaria
|
|
if ( bChain && ! Chain( nAuxId)) {
|
|
m_pMchMgr->SetLastError( 2108, "Error in Drilling : Chaining failed") ;
|
|
return false ;
|
|
}
|
|
|
|
// calcolo ogni singola catena
|
|
int nPathId = m_pGeomDB->GetFirstGroupInGroup( nAuxId) ;
|
|
while ( nPathId != GDB_ID_NULL) {
|
|
if ( ! ProcessPath( nPathId, nPvId, nClId))
|
|
return false ;
|
|
nPathId = m_pGeomDB->GetNextGroup( nPathId) ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Drilling::Chain( int nGrpDestId)
|
|
{
|
|
// vettore puntatori alle curve
|
|
ICURVEPOVECTOR vpCrvs ;
|
|
vpCrvs.reserve( m_vId.size()) ;
|
|
// recupero tutte le curve e le porto in globale
|
|
for ( const auto& Id : m_vId) {
|
|
// prendo curva
|
|
vpCrvs.emplace_back( GetCurve( Id)) ;
|
|
// ne verifico la validità
|
|
if ( IsNull( vpCrvs.back())) {
|
|
string sInfo = "Warning in Drilling : Skipped entity " + ToString( Id) ;
|
|
m_pMchMgr->SetWarning( 2151, sInfo) ;
|
|
vpCrvs.back().Reset() ;
|
|
}
|
|
}
|
|
// 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( m_vId[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) ;
|
|
// 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 ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
ICurve*
|
|
Drilling::GetCurve( SelData Id)
|
|
{
|
|
// accetto solo curve
|
|
PtrOwner<ICurve> pCurve ;
|
|
// se direttamente curva
|
|
if ( Id.nSub == SEL_SUB_ALL) {
|
|
// recupero e duplico la curva
|
|
const ICurve* pOriCurve = ::GetCurve( m_pGeomDB->GetGeoObj( Id.nId)) ;
|
|
if ( pOriCurve != nullptr)
|
|
pCurve.Set( pOriCurve->Clone()) ;
|
|
}
|
|
// altrimenti sottocurva di composita
|
|
else {
|
|
// recupero la composita
|
|
const ICurveComposite* pCompo = GetCurveComposite( m_pGeomDB->GetGeoObj( Id.nId)) ;
|
|
if ( pCompo != nullptr) {
|
|
// duplico la curva semplice
|
|
const ICurve* pOriCurve = ::GetCurve( pCompo->GetCurve( Id.nSub)) ;
|
|
if ( pOriCurve != nullptr) {
|
|
pCurve.Set( pOriCurve->Clone()) ;
|
|
// recupero estrusione e spessore
|
|
Vector3d vtExtr ;
|
|
if ( pCompo->GetExtrusion( vtExtr))
|
|
pCurve->SetExtrusion( vtExtr) ;
|
|
double dThick ;
|
|
if ( pCompo->GetThickness( dThick))
|
|
pCurve->SetThickness( dThick) ;
|
|
}
|
|
}
|
|
}
|
|
if ( IsNull( pCurve))
|
|
return nullptr ;
|
|
// ne recupero il riferimento globale
|
|
Frame3d frGlob ;
|
|
if ( ! m_pGeomDB->GetGlobFrame( Id.nId, frGlob))
|
|
return nullptr ;
|
|
// la porto in globale
|
|
pCurve->ToGlob( frGlob) ;
|
|
// la restituisco
|
|
return Release( pCurve) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Drilling::ProcessPath( int nPathId, int nPvId, int nClId)
|
|
{
|
|
// recupero gruppo per geometria temporanea
|
|
const string GRP_TEMP = "Temp" ;
|
|
int nTempId = m_pGeomDB->GetFirstNameInGroup( m_nOwnerId, GRP_TEMP) ;
|
|
// se non c'è, lo aggiungo
|
|
if ( nTempId == GDB_ID_NULL) {
|
|
nTempId = m_pGeomDB->AddGroup( GDB_ID_NULL, m_nOwnerId, Frame3d()) ;
|
|
if ( nTempId == GDB_ID_NULL)
|
|
return false ;
|
|
m_pGeomDB->SetName( nTempId, GRP_TEMP) ;
|
|
}
|
|
// altrimenti lo lavoro
|
|
else
|
|
m_pGeomDB->EmptyGroup( nTempId) ;
|
|
// in ogni caso lo dichiaro temporaneo e non visibile
|
|
m_pGeomDB->SetLevel( nTempId, GDB_LV_TEMP) ;
|
|
m_pGeomDB->SetStatus( nTempId, GDB_ST_OFF) ;
|
|
|
|
// recupero la curva composita
|
|
int nCrvId = m_pGeomDB->GetFirstInGroup( nPathId) ;
|
|
// recupero nome del path
|
|
string sPName ;
|
|
m_pGeomDB->GetName( nPathId, sPName) ;
|
|
|
|
// valuto l'espressione dell'offset e della sovrapposizione
|
|
ExeLuaSetGlobNumVar( "D", m_TParams.m_dDiam) ;
|
|
double dOffset ;
|
|
if ( ! ExeLuaEvalNumExpr( m_Params.m_sOffset, &dOffset)) {
|
|
m_pMchMgr->SetLastError( 2102, "Error in Drilling : Offset not computable") ;
|
|
return false ;
|
|
}
|
|
double dOverlap ;
|
|
if ( ! ExeLuaEvalNumExpr( m_Params.m_sOverlap, &dOverlap)) {
|
|
m_pMchMgr->SetLastError( 2103, "Error in Drilling : Overlap not computable") ;
|
|
return false ;
|
|
}
|
|
|
|
// disabilito eventuale registrazione comandi EXE (riabilitazione automatica)
|
|
CmdLogOff cmdLogOff ;
|
|
|
|
// genero le circonferenze
|
|
int nCount = 0 ;
|
|
int nFirstId = ExeCreateCirclesAlongCurve( nTempId, nCrvId, dOffset, dOverlap, m_Params.m_dStartAddLen,
|
|
m_Params.m_dEndAddLen, m_TParams.m_dDiam, &nCount) ;
|
|
|
|
// se richiesta anteprima
|
|
if ( nPvId != GDB_ID_NULL) {
|
|
// creo l'anteprima dei fori
|
|
for ( int i = 0 ; i < nCount ; ++ i) {
|
|
// identificativo circonferenza
|
|
int nId = nFirstId + i ;
|
|
// calcolo il preview del foro
|
|
if ( ! GenerateHolePv( i, nId, sPName + "_", nPvId))
|
|
return false ;
|
|
}
|
|
// creo la regione di ingombro dei fori
|
|
GenerateHoleRegionPv( nFirstId, nCount, nPvId) ;
|
|
}
|
|
|
|
// se richiesta lavorazione
|
|
if ( nClId != GDB_ID_NULL) {
|
|
// creo lavorazione dei fori
|
|
for ( int i = 0 ; i < nCount ; ++ i) {
|
|
// identificativo circonferenza
|
|
int nId = nFirstId + i ;
|
|
// calcolo la lavorazione del foro
|
|
if ( ! GenerateHoleCl( i, nId, sPName + "_", nClId))
|
|
return false ;
|
|
}
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Drilling::GenerateHolePv( int nInd, const SelData& nCircId, const string& sPName, int nPvId)
|
|
{
|
|
// creo gruppo per geometria di lavorazione del foro
|
|
int nPathId = m_pGeomDB->AddGroup( GDB_ID_NULL, nPvId, Frame3d()) ;
|
|
if ( nPathId == GDB_ID_NULL)
|
|
return false ;
|
|
m_pGeomDB->SetName( nPathId, sPName + ToString( nInd + 1)) ;
|
|
m_pGeomDB->SetInfo( nPathId, KEY_IDS, ToString( nCircId)) ;
|
|
m_pGeomDB->SetMaterial( nPathId, GREEN) ;
|
|
// recupero il valore di tolleranza sul diametro
|
|
double dDiamTol = GetHoleDiamToler() ;
|
|
// recupero i dati del foro
|
|
Hole hole ;
|
|
if ( ! GetHoleData( nCircId, hole) || ! VerifyDiameter( hole.dDiam, m_TParams.m_dDiam, dDiamTol)) {
|
|
m_pGeomDB->Erase( nPathId) ;
|
|
string sInfo = "Warning in Drilling : Skipped entity " + ToString( nCircId) ;
|
|
m_pMchMgr->SetWarning( 2151, sInfo) ;
|
|
return true ;
|
|
}
|
|
// limito lunghezza foro a massima lavorazione della punta
|
|
if ( hole.dLen > m_TParams.m_dMaxMat + EPS_SMALL) {
|
|
hole.dLen = m_TParams.m_dMaxMat ;
|
|
string sInfo = "Warning in Drilling : Drill bit too short for Hole " + ToString( nCircId) ;
|
|
m_pMchMgr->SetWarning( 2155, sInfo) ;
|
|
}
|
|
// inserisco circonferenza che rappresenta il foro
|
|
PtrOwner<ICurveArc> pCrvArc( CreateCurveArc()) ;
|
|
if ( IsNull( pCrvArc) || ! pCrvArc->Set( hole.ptIni, hole.vtDir, 0.5 * m_TParams.m_dDiam))
|
|
return false ;
|
|
// assegno il versore estrusione e lo spessore
|
|
pCrvArc->SetExtrusion( hole.vtDir) ;
|
|
pCrvArc->SetThickness( - hole.dLen) ;
|
|
// inserisco nel DB
|
|
int nDriId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nPathId, Release( pCrvArc)) ;
|
|
// assegno nome e colore
|
|
m_pGeomDB->SetName( nDriId, MCH_PV_CUT) ;
|
|
m_pGeomDB->SetMaterial( nDriId, LIME) ;
|
|
// aggiorno numero forature
|
|
++ m_nDrillings ;
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Drilling::GenerateHoleCl( int nInd, const SelData& nCircId, const string& sPName, int nClId,
|
|
double dMHOff, const Vector3d& vtA, int nDrillType,
|
|
INTVECTOR* pvActiveExit, ToolInfo* currTool)
|
|
{
|
|
// creo gruppo per geometria di lavorazione del foro
|
|
int nPathId = m_pGeomDB->AddGroup( GDB_ID_NULL, nClId, Frame3d()) ;
|
|
if ( nPathId == GDB_ID_NULL)
|
|
return false ;
|
|
m_pGeomDB->SetName( nPathId, sPName + ToString( nInd + 1)) ;
|
|
m_pGeomDB->SetInfo( nPathId, KEY_IDS, ToString( nCircId)) ;
|
|
if ( nDrillType == DRILL_TYPE_MULTI_SEL && pvActiveExit != nullptr)
|
|
m_pGeomDB->SetInfo( nPathId, KEY_DRACEX, ToString( *pvActiveExit)) ;
|
|
m_pGeomDB->SetMaterial( nPathId, GREEN) ;
|
|
// recupero il valore di tolleranza sul diametro
|
|
double dDiamTol = GetHoleDiamToler() ;
|
|
// recupero parametri dell'utensile principale
|
|
ToolData currToolData = m_TParams ;
|
|
if ( nDrillType == DRILL_TYPE_MULTI_SEL) {
|
|
if ( currTool == nullptr)
|
|
return false ;
|
|
currToolData = *currTool->pTool ;
|
|
}
|
|
// recupero i dati del foro
|
|
Hole hole ;
|
|
if ( ! GetHoleData( nCircId, hole) || ! VerifyDiameter( hole.dDiam, currToolData.m_dDiam, dDiamTol)) {
|
|
if ( nDrillType == DRILL_TYPE_STD) {
|
|
m_pGeomDB->Erase( nPathId) ;
|
|
string sInfo = "Warning in Drilling : Skipped entity " + ToString( nCircId) ;
|
|
m_pMchMgr->SetWarning( 2151, sInfo) ;
|
|
}
|
|
return true ;
|
|
}
|
|
// se richiesta inversione e foro passante, provvedo
|
|
if ( m_Params.m_bInvert) {
|
|
if ( hole.bBlind) {
|
|
m_pMchMgr->SetLastError( 2114, "Error in Drilling : blind hole not reversible") ;
|
|
return false ;
|
|
}
|
|
else {
|
|
hole.ptIni -= hole.vtDir * hole.dThick ;
|
|
hole.vtDir.Invert() ;
|
|
}
|
|
}
|
|
// se lavorazione del foro non arriva al suo fondo, lo considero cieco
|
|
if ( hole.dLen < hole.dThick - 10 * EPS_SMALL)
|
|
hole.bBlind = true ;
|
|
// imposto elevazione da lunghezza foro con possibilità di sovrascrittura da info
|
|
double dElev = hole.dLen ;
|
|
double dMaxElev ;
|
|
if ( GetValInNotes( m_Params.m_sUserNotes, UN_MAXELEV, dMaxElev) && dElev > dMaxElev) {
|
|
dElev = dMaxElev ;
|
|
hole.ptIni += hole.vtDir * ( dElev - hole.dLen) ;
|
|
hole.dLen = ( hole.dLen > 10 * EPS_SMALL ? max( dElev, 10 * EPS_SMALL) : dElev) ;
|
|
}
|
|
// limito lunghezza foro a massima lavorazione della punta ( per utensile corrente )
|
|
double dAddLen = ( hole.bBlind ? 0 : m_Params.m_dThroughAddLen) ;
|
|
if ( ( dElev + dAddLen) > currToolData.m_dMaxMat + EPS_SMALL) {
|
|
hole.dLen = currToolData.m_dMaxMat + max( hole.dLen - dElev, 0.) ;
|
|
hole.bBlind = true ;
|
|
if ( nDrillType == DRILL_TYPE_STD) {
|
|
string sInfo = "Warning in Drilling : Drill bit too short for Hole " + ToString( nCircId) ;
|
|
m_pMchMgr->SetWarning( 2155, sInfo) ;
|
|
}
|
|
}
|
|
// verifiche per foro verso il basso
|
|
m_bAggrBottom = false ;
|
|
if ( ! VerifyHoleFromBottom( hole, nCircId))
|
|
return false ;
|
|
// assegno il vettore estrazione al gruppo del percorso
|
|
m_pGeomDB->SetInfo( nPathId, KEY_EXTR, hole.vtDir) ;
|
|
// assegno i punti di inizio e fine al gruppo del percorso
|
|
m_pGeomDB->SetInfo( nPathId, KEY_START, hole.ptIni) ;
|
|
m_pGeomDB->SetInfo( nPathId, KEY_END, hole.ptIni) ;
|
|
// assegno l'elevazione massima
|
|
m_pGeomDB->SetInfo( nPathId, KEY_ELEV, hole.dLen) ;
|
|
// foro normale
|
|
if ( ( m_Params.m_dStep < EPS_SMALL || m_Params.m_dStep > hole.dLen - 10 * EPS_SMALL) &&
|
|
GetDoubleLastStep() > hole.dLen - 10 * EPS_SMALL) {
|
|
if ( DoStandardDrilling( hole, nCircId, nPathId, dMHOff, vtA, currToolData)) {
|
|
// aggiorno numero forature
|
|
++ m_nDrillings ;
|
|
}
|
|
else {
|
|
m_pGeomDB->Erase( nPathId) ;
|
|
string sInfo = "Warning in Drilling : Skipped by Standard Drilling " + ToString( nCircId) ;
|
|
m_pMchMgr->SetWarning( 2156, sInfo) ;
|
|
}
|
|
}
|
|
else {
|
|
if ( DoPeckDrilling( hole, nCircId, nPathId, dMHOff, vtA, currToolData)) {
|
|
// aggiorno numero forature
|
|
++ m_nDrillings ;
|
|
}
|
|
else {
|
|
m_pGeomDB->Erase( nPathId) ;
|
|
string sInfo = "Warning in Drilling : Skipped by Peck Drilling " + ToString( nCircId) ;
|
|
m_pMchMgr->SetWarning( 2157, sInfo) ;
|
|
}
|
|
}
|
|
|
|
// aggiusto i percorsi nel caso di utensili selezionabili con utensile principale non attivo
|
|
if ( nDrillType == DRILL_TYPE_MULTI_SEL && ! SameTool( currToolData, m_TParams)) {
|
|
if ( ! AdapthPathToMainTool( nPathId, nCircId, sPName, nClId, dMHOff, vtA, nDrillType, pvActiveExit, &( currToolData)))
|
|
return false ;
|
|
}
|
|
|
|
// aggiungo eventuali Warning per fori non lavorati o lavorati parzialmente
|
|
int nUndrilleds = int( m_vUndrilledId.size()) ;
|
|
int nPartialDrilled = int( m_vPartialDrilledId.size()) ;
|
|
if ( nUndrilleds + nPartialDrilled > 0) {
|
|
string sWarning = "" ;
|
|
if ( nUndrilleds > 0) {
|
|
sWarning += "Warning in Drilling : Skipped entities " ;
|
|
for ( int i = 0 ; i < nUndrilleds ; ++ i)
|
|
sWarning += ToString( m_vUndrilledId[i]) + ( i != nUndrilleds - 1 ? ", " : "") ;
|
|
}
|
|
if ( nPartialDrilled > 0) {
|
|
if ( nUndrilleds > 0)
|
|
sWarning += " | " ;
|
|
sWarning += "Warning in Drilling : Partial Holes " ;
|
|
for ( int i = 0 ; i < nPartialDrilled ; ++ i)
|
|
sWarning += "(" + ToString( m_vPartialDrilledId[i].first) + ", Len : " +
|
|
ToString( m_vPartialDrilledId[i].second) + ")" +
|
|
( i != nPartialDrilled - 1 ? ", " : "") ;
|
|
}
|
|
m_pMchMgr->SetWarning( 2158, sWarning) ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
bool
|
|
Drilling::AdapthPathToMainTool( int nPathId, const SelData& nCircId, const std::string& sPName, int nClId,
|
|
double dMHOff, const Vector3d& vtAux, int nDrillType,
|
|
INTVECTOR* pvActiveExit, ToolData* currToolData)
|
|
{
|
|
// controllo di avere delle uscite attive
|
|
if ( pvActiveExit == nullptr)
|
|
return false ;
|
|
// se tool corrente non valido, errore
|
|
if ( currToolData == nullptr)
|
|
return false ;
|
|
// se utensile corrente identico all'utensile principale della lavorazione, non faccio nulla
|
|
if ( SameTool( *currToolData, m_TParams))
|
|
return true ;
|
|
|
|
// inizializzo punti finali degli utensili
|
|
Point3d ptEndCurrTool = P_INVALID ;
|
|
Point3d ptEndTParams = P_INVALID ;
|
|
|
|
// vettore direzione utensili
|
|
Vector3d vtDir ;
|
|
|
|
// gestore degli utensili
|
|
ToolsMgr* pTMgr = m_pMchMgr->GetCurrToolsMgr() ;
|
|
if ( pTMgr == nullptr)
|
|
return false ;
|
|
|
|
// recupero il nome della testa e il numero di uscite
|
|
string sHead ;
|
|
m_pMchMgr->GetCurrMachine()->GetCurrHead( sHead) ;
|
|
int nExitCnt = m_pMchMgr->GetCurrMachine()->GetHeadExitCount( sHead) ;
|
|
|
|
// ricavo gli utensili presenti sulle uscite
|
|
for ( int nT = 0 ; nT < nExitCnt ; ++ nT) {
|
|
string sToolName ;
|
|
if ( ! m_pMchMgr->GetLoadedTool( sHead, nT + 1, sToolName) || sToolName.empty())
|
|
continue ;
|
|
// se presente e valido
|
|
const ToolData* pTdata = pTMgr->GetTool( sToolName) ;
|
|
// imposto il tool di riferimento come il tool m_TParams
|
|
bool bIsTParams = ( pTdata->m_Uuid == m_TParams.m_Uuid) ;
|
|
bool bIsCurrTool = ( pTdata->m_Uuid == currToolData->m_Uuid) ;
|
|
if ( bIsTParams || bIsCurrTool) {
|
|
// recupero i dati dell'uscita
|
|
Point3d ptExit ;
|
|
Vector3d vtCurrDir, vtCurrAux ;
|
|
m_pMchMgr->GetCurrMachine()->GetHeadExitPosDirAux( sHead, nT + 1, ptExit, vtCurrDir, vtCurrAux) ;
|
|
vtDir = vtCurrDir ; // ho già controllato prima che siano compatibili
|
|
if ( bIsTParams)
|
|
ptEndTParams = ptExit - vtCurrDir * pTdata->m_dLen ;
|
|
else
|
|
ptEndCurrTool = ptExit - vtCurrDir * pTdata->m_dLen ;
|
|
}
|
|
if ( ptEndCurrTool.IsValid() && ptEndTParams.IsValid())
|
|
break ;
|
|
}
|
|
// se non trovati allora errore
|
|
if ( ! ptEndCurrTool.IsValid() || ! ptEndTParams.IsValid())
|
|
return false ;
|
|
|
|
// creo un sistema di riferimento centrato sul tool corrente
|
|
Frame3d frCurr ;
|
|
if ( ! frCurr.Set( ptEndCurrTool, vtDir, vtAux))
|
|
return false ;
|
|
// porto l'altro punto nel riferimento corrente
|
|
ptEndTParams.ToLoc( frCurr) ;
|
|
// ricavo il vettore traslazione
|
|
Vector3d vtTrasl = ( ptEndTParams - ORIG) ;
|
|
vtTrasl.ToGlob( frCurr) ;
|
|
// scorro le entità nel gruppo di lavorazione corrente
|
|
Hole myHole ;
|
|
if ( ! GetHoleData( nCircId, myHole))
|
|
return false ;
|
|
int nId = m_pGeomDB->GetFirstInGroup( nPathId) ;
|
|
while ( nId != GDB_ID_NULL) {
|
|
// recupero l'oggetto CamData
|
|
auto* myCamDataObj = GetCamData( m_pGeomDB->GetUserObj( nId)) ;
|
|
myCamDataObj->Translate( vtTrasl) ;
|
|
// recupero l'oggetto geometrico
|
|
auto* myGeoObj = m_pGeomDB->GetGeoObj( nId) ;
|
|
myGeoObj->Translate( vtTrasl) ;
|
|
// passo all'indice successivo
|
|
nId = m_pGeomDB->GetNext( nId) ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Drilling::GenerateHoleRegionPv( int nFirstId, int nCount, int nPvId)
|
|
{
|
|
// raggio dei fori
|
|
double dRad = m_TParams.m_dDiam / 2 ;
|
|
// extra raggio
|
|
double dExtraR = GetExtraROnDrillRegion() ;
|
|
|
|
// gruppo di inserimento
|
|
int nGroupId = m_pGeomDB->GetLastGroupInGroup( nPvId) ;
|
|
|
|
// creo polyline che unisce i centri
|
|
PolyLine PL ;
|
|
for ( int i = 0 ; i < nCount ; ++ i) {
|
|
int nId = nFirstId + i ;
|
|
const ICurveArc* pArc = GetCurveArc( m_pGeomDB->GetGeoObj( nId)) ;
|
|
if ( pArc == nullptr)
|
|
return false ;
|
|
PL.AddUPoint( i, pArc->GetCenter()) ;
|
|
}
|
|
|
|
// calcolo la regione
|
|
ISurfFlatRegion* pSfr = nullptr ;
|
|
|
|
// se polilinea con almeno due punti
|
|
if ( PL.GetPointNbr() > 1) {
|
|
// ne derivo una curva composita
|
|
PtrOwner<ICurveComposite> pCompo1( CreateCurveComposite()) ;
|
|
if ( IsNull( pCompo1) || ! pCompo1->FromPolyLine( PL))
|
|
return false ;
|
|
// calcolo la regione
|
|
pSfr = GetSurfFlatRegionFromFatCurve( Release( pCompo1), dRad + dExtraR, false, true) ;
|
|
if ( pSfr == nullptr)
|
|
return false ;
|
|
}
|
|
// altrimenti
|
|
else {
|
|
// approssimo l'unico foro
|
|
pSfr = GetSurfFlatRegionDisk( dRad + dExtraR) ;
|
|
if ( pSfr == nullptr)
|
|
return false ;
|
|
Point3d ptCen ;
|
|
PL.GetFirstPoint( ptCen) ;
|
|
pSfr->Translate( ptCen - ORIG) ;
|
|
}
|
|
|
|
// inserisco la regione nel DB
|
|
int nRId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nGroupId, pSfr) ;
|
|
if ( nRId == GDB_ID_NULL)
|
|
return false ;
|
|
m_pGeomDB->SetName( nRId, MCH_PV_RCUT) ;
|
|
m_pGeomDB->SetMaterial( nRId, INVISIBLE) ;
|
|
// la copio anche come regione ridotta
|
|
int nRrId = m_pGeomDB->Copy( nRId, GDB_ID_NULL, nGroupId) ;
|
|
if ( nRrId == GDB_ID_NULL)
|
|
return false ;
|
|
m_pGeomDB->SetName( nRrId, MCH_PV_RRCUT) ;
|
|
m_pGeomDB->SetMaterial( nRrId, INVISIBLE) ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Drilling::VerifyDiameter( double dHdiam, double dTdiam, double dDiamTol)
|
|
{
|
|
// imposto minima tolleranza
|
|
if ( abs( dDiamTol) < 10 * EPS_SMALL)
|
|
dDiamTol = 10 * EPS_SMALL ;
|
|
// se tolleranza in più o in meno
|
|
if ( dDiamTol > 0)
|
|
return ( abs( dHdiam - dTdiam) < dDiamTol) ;
|
|
// altrimenti tolleranza solo in meno
|
|
return ( dTdiam < dHdiam + 10 * EPS_SMALL && dTdiam > dHdiam + dDiamTol - 10 * EPS_SMALL) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Drilling::GetParam( int nType, bool& bVal) const
|
|
{
|
|
switch ( nType) {
|
|
case MPA_INVERT :
|
|
bVal = m_Params.m_bInvert ;
|
|
return true ;
|
|
}
|
|
bVal = false ;
|
|
return false ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Drilling::GetParam( int nType, int& nVal) const
|
|
{
|
|
switch ( nType) {
|
|
case MPA_TYPE :
|
|
nVal = MT_DRILLING ;
|
|
return true ;
|
|
case MPA_SUBTYPE :
|
|
nVal = m_Params.m_nSubType ;
|
|
return true ;
|
|
case MPA_SCC :
|
|
nVal = m_Params.m_nSolCh ;
|
|
return true ;
|
|
}
|
|
nVal = 0 ;
|
|
return false ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Drilling::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_STARTPOS :
|
|
dVal = m_Params.m_dStartPos ;
|
|
return true ;
|
|
case MPA_STARTSLOWLEN :
|
|
dVal = m_Params.m_dStartSlowLen ;
|
|
return true ;
|
|
case MPA_ENDSLOWLEN :
|
|
dVal = m_Params.m_dEndSlowLen ;
|
|
return true ;
|
|
case MPA_THROUADDLEN :
|
|
dVal = m_Params.m_dThroughAddLen ;
|
|
return true ;
|
|
case MPA_STEP :
|
|
dVal = m_Params.m_dStep ;
|
|
return true ;
|
|
case MPA_RETURNPOS :
|
|
dVal = m_Params.m_dReturnPos ;
|
|
return true ;
|
|
case MPA_STARTADDLEN :
|
|
dVal = m_Params.m_dStartAddLen ;
|
|
return true ;
|
|
case MPA_ENDADDLEN :
|
|
dVal = m_Params.m_dEndAddLen ;
|
|
return true ;
|
|
}
|
|
dVal = 0 ;
|
|
return false ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Drilling::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_OVERLAP_STR :
|
|
sVal = m_Params.m_sOverlap ;
|
|
return true ;
|
|
case MPA_OFFSET_STR :
|
|
sVal = m_Params.m_sOffset ;
|
|
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&
|
|
Drilling::GetToolData( void) const
|
|
{
|
|
return m_TParams ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Drilling::UpdateToolData( void)
|
|
{
|
|
// recupero il gestore DB utensili della macchina corrente
|
|
ToolsMgr* pTMgr = m_pMchMgr->GetCurrToolsMgr() ;
|
|
if ( pTMgr == nullptr)
|
|
return false ;
|
|
// recupero l'utensile nel DB utensili (se fallisce con UUID provo con il nome)
|
|
const ToolData* pTdata = pTMgr->GetTool( m_Params.m_ToolUuid) ;
|
|
if ( pTdata == nullptr) {
|
|
pTdata = pTMgr->GetTool( m_Params.m_sToolName) ;
|
|
if ( pTdata == nullptr)
|
|
return false ;
|
|
m_Params.m_ToolUuid = m_TParams.m_Uuid ;
|
|
}
|
|
// salvo posizione TC, testa e uscita originali
|
|
string sOrigTcPos = m_TParams.m_sTcPos ;
|
|
string sOrigHead = m_TParams.m_sHead ;
|
|
int nOrigExit = m_TParams.m_nExit ;
|
|
// verifico se sono diversi (ad esclusione di nome, posizione TC, testa e uscita)
|
|
bool bChanged = ( ! SameTool( m_TParams, *pTdata, false)) ;
|
|
// aggiorno comunque i parametri
|
|
m_TParams = *pTdata ;
|
|
// se definito attrezzaggio, aggiorno i parametri che ne possono derivare
|
|
string sTcPos ; string sHead ; int nExit ;
|
|
if ( m_pMchMgr->GetCurrSetupMgr().GetToolData( m_TParams.m_sName, sTcPos, sHead, nExit)) {
|
|
if ( sOrigTcPos != sTcPos ||
|
|
sOrigHead != sHead ||
|
|
nOrigExit != nExit)
|
|
bChanged = true ;
|
|
m_TParams.m_sTcPos = sTcPos ;
|
|
m_TParams.m_sHead = sHead ;
|
|
m_TParams.m_nExit = nExit ;
|
|
}
|
|
else {
|
|
if ( sOrigTcPos != pTdata->m_sTcPos ||
|
|
sOrigHead != pTdata->m_sHead ||
|
|
nOrigExit != pTdata->m_nExit)
|
|
bChanged = true ;
|
|
}
|
|
// eventuali segnalazioni
|
|
if ( ! EqualNoCase( m_Params.m_sToolName, m_TParams.m_sName)) {
|
|
string sInfo = "Warning in Drilling : tool name changed (" +
|
|
m_Params.m_sToolName + "->" + m_TParams.m_sName + ")" ;
|
|
m_pMchMgr->SetWarning( 2153, sInfo) ;
|
|
m_Params.m_sToolName = m_TParams.m_sName ;
|
|
}
|
|
if ( bChanged) {
|
|
string sInfo = "Warning in Drilling : tool data changed (" +
|
|
m_Params.m_sToolName + ")" ;
|
|
m_pMchMgr->SetWarning( 2154, sInfo) ;
|
|
}
|
|
// se modificato, aggiusto lo stato
|
|
if ( bChanged)
|
|
m_nStatus = MCH_ST_TO_VERIFY ;
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Drilling::GetGeometry( SELVECTOR& vIds) const
|
|
{
|
|
// restituisco l'elenco delle entità
|
|
vIds = m_vId ;
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Drilling::GetSkippedGeometry( SELVECTOR& vIds) const
|
|
{
|
|
// pulisco elenco entità non lavorate
|
|
vIds.clear() ;
|
|
// inserisco le entità non lavorate
|
|
for ( const auto& nId : m_vUndrilledId)
|
|
vIds.emplace_back( nId, SEL_SUB_ALL) ;
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Drilling::GetHoleData( SelData Id, Hole& hole)
|
|
{
|
|
PtrOwner<ICurveArc> pMyArc ;
|
|
// deve essere un arco o una composita formata da un arco
|
|
const ICurveArc* pArc = GetCurveArc( m_pGeomDB->GetGeoObj( Id.nId)) ;
|
|
if ( pArc == nullptr) {
|
|
const ICurveComposite* pCompo = GetCurveComposite( m_pGeomDB->GetGeoObj( Id.nId)) ;
|
|
Point3d ptCen ;
|
|
Vector3d vtN ;
|
|
double dRad ;
|
|
bool bCCW ;
|
|
if ( pCompo == nullptr || ! pCompo->IsACircle( 100 * EPS_SMALL, ptCen, vtN, dRad, bCCW))
|
|
return false ;
|
|
pMyArc.Set( CreateCurveArc()) ;
|
|
if ( IsNull( pMyArc) || ! pMyArc->Set( ptCen, vtN, dRad))
|
|
return false ;
|
|
Vector3d vtExtr ; pCompo->GetExtrusion( vtExtr) ;
|
|
pMyArc->SetExtrusion( vtExtr) ;
|
|
double dThick = 0 ; pCompo->GetThickness( dThick) ;
|
|
pMyArc->SetThickness( dThick) ;
|
|
pArc = pMyArc ;
|
|
}
|
|
// ne recupero il riferimento globale
|
|
Frame3d frGlob ;
|
|
if ( ! m_pGeomDB->GetGlobFrame( Id.nId, frGlob))
|
|
return false ;
|
|
// deve avere estrusione
|
|
Vector3d vtExtr ;
|
|
if ( ! pArc->GetExtrusion( vtExtr))
|
|
return false ;
|
|
if ( vtExtr.IsSmall())
|
|
vtExtr = pArc->GetNormVersor() ;
|
|
// recupero spessore
|
|
double dThick = 0 ;
|
|
pArc->GetThickness( dThick) ;
|
|
// se diretto come asse Z, recupero distanza da fondo dei grezzi interessati dal foro
|
|
double dRbDist = 0 ;
|
|
Vector3d vtExtrG = vtExtr ;
|
|
vtExtrG.ToGlob( frGlob) ;
|
|
if ( vtExtrG.IsZplus())
|
|
GetDistanceFromRawBottom( m_nPhase, Id.nId, EPS_SMALL, dRbDist) ;
|
|
// valuto l'espressione dell'affondamento
|
|
ExeLuaSetGlobNumVar( "TH", abs( dThick)) ;
|
|
ExeLuaSetGlobNumVar( "RB", dRbDist) ;
|
|
double dDepth ;
|
|
string sMyDepth = m_Params.m_sDepth ;
|
|
if ( ! ExeLuaEvalNumExpr( ToUpper( sMyDepth), &dDepth)) {
|
|
m_pMchMgr->SetLastError( 2104, "Error in Drilling : Depth not computable") ;
|
|
return false ;
|
|
}
|
|
if ( abs( dDepth) < EPS_SMALL) {
|
|
m_pMchMgr->SetLastError( 2105, "Error in Drilling : Drill with zero depth") ;
|
|
return false ;
|
|
}
|
|
// assegno Id
|
|
hole.nOriId = Id.nId ;
|
|
// ne recupero il diametro
|
|
hole.dDiam = 2 * pArc->GetRadius() ;
|
|
// ne recupero il centro
|
|
hole.ptIni = pArc->GetCenter() + ( dThick > 0 ? vtExtr * dThick : V_NULL) ;
|
|
hole.ptIni.ToGlob( frGlob) ;
|
|
// ne recupero versore direzione e lunghezze
|
|
hole.vtDir = vtExtr ;
|
|
hole.vtDir.ToGlob( frGlob) ;
|
|
hole.vtDir.Normalize() ;
|
|
hole.dThick = abs( dThick) ;
|
|
hole.dLen = abs( dDepth) ;
|
|
// per default è cieco
|
|
hole.bBlind = true ;
|
|
// se dichiarato passante o no (1/0)
|
|
int nOpen ;
|
|
if ( GetValInNotes( m_Params.m_sUserNotes, UN_OPEN, nOpen))
|
|
hole.bBlind = ( nOpen == 0) ;
|
|
// se verticale ed arriva fino al fondo grezzo, allora passante
|
|
else if ( hole.vtDir.IsZplus() && hole.dThick > dRbDist - EPS_SMALL)
|
|
hole.bBlind = false ;
|
|
// altrimenti determino la distanza del fondo del foro dal bordo opposto del grezzo
|
|
else {
|
|
const double BLIND_TOL = 10 ;
|
|
double dBackElev ;
|
|
if ( GetElevation( m_nPhase, hole.ptIni, - hole.vtDir, dBackElev) && ( dBackElev - hole.dThick) <= BLIND_TOL)
|
|
hole.bBlind = false ;
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Drilling::VerifyHoleFromBottom( const Hole& hole, SelData Id)
|
|
{
|
|
// se non è foro dal basso in alto, esco
|
|
if ( hole.vtDir.z > MIN_ZDIR_TOP_TOOL)
|
|
return true ;
|
|
// se c'è testa non dall'alto o tavola basculante, esco
|
|
if ( ! m_bAboveHead || m_bTiltingTab)
|
|
return true ;
|
|
// recupero dati di eventuale rinvio da sotto
|
|
if ( ! GetAggrBottomData( m_TParams.m_sHead, m_AggrBottom) || m_AggrBottom.nType == 0) {
|
|
string sOut = "Error in Drilling : Entity " + ToString( Id) + " skipped because missing aggregate from bottom" ;
|
|
m_pMchMgr->SetLastError( 2106, sOut) ;
|
|
return false ;
|
|
}
|
|
// calcolo la distanza minima del punto dal contorno del grezzo
|
|
double dDist ;
|
|
Vector3d vtDir ;
|
|
if ( ! GetMinDistanceFromRawSide( m_nPhase, hole.ptIni, 0, m_AggrBottom.vtMDir, MCH_AGB_DELTAMAX_MDIR, dDist, vtDir) || dDist > m_AggrBottom.dDMax) {
|
|
string sOut = "Error in Drilling : Entity " + ToString( Id) + " skipped because too far from part sides" ;
|
|
m_pMchMgr->SetLastError( 2107, sOut) ;
|
|
return false ;
|
|
}
|
|
// assegno direzione di accesso e segnalazione di utilizzo aggregato da sotto
|
|
m_vtAggrBottom = vtDir ;
|
|
m_bAggrBottom = true ;
|
|
m_dDistBottom = dDist ;
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Drilling::VerifyParallelDrilling( int nDouble, const Hole& hole)
|
|
{
|
|
// verifico se lavorazione in doppio valida
|
|
if ( nDouble != 1 && nDouble != 2 && nDouble != 3)
|
|
return false ;
|
|
|
|
// se la macchina non presenta nel file .ini la possibilità di lavorazione in doppio parallela, esco
|
|
Machine* pMch = m_pMchMgr->GetCurrMachine() ;
|
|
if ( pMch == nullptr)
|
|
return false ;
|
|
string sMachIni = pMch->GetMachineDir() + "\\" + pMch->GetMachineName() + ".ini" ;
|
|
int nDrillingDouble = GetPrivateProfileInt( MACHININGS_SEC.c_str(), DRILLING_PARALLEL_KEY.c_str(), 0, sMachIni.c_str()) ;
|
|
if ( nDrillingDouble != 1)
|
|
return false ;
|
|
|
|
// recupero il piano di Mirror
|
|
Point3d ptOn ; Vector3d vtNorm ;
|
|
if ( ! CalcMirrorPlaneByDouble( nDouble, m_Params.m_sUserNotes, ptOn, vtNorm))
|
|
return false ;
|
|
Plane3d plMirror ;
|
|
if ( ! plMirror.Set( ptOn, vtNorm))
|
|
return false ;
|
|
|
|
// verifico subito che la normale del piano si trovi entro un grado rispetto alla direzione del foro ( tolleranza da .BTL)
|
|
if ( abs( hole.vtDir * vtNorm) < cos( ( 1. - EPS_ANG_SMALL) * DEGTORAD))
|
|
return false ;
|
|
|
|
// se il punto finale del foro si trova nel semipiano positivo di Mirroring e sufficientemente distante da esso, non eseguo
|
|
// lavorazione in parallelo
|
|
Point3d ptHoleEnd = hole.ptIni - hole.dLen * hole.vtDir ;
|
|
const double SAFE_DIST_TOL = 5. ;
|
|
double dDist = ( ptHoleEnd - ptOn) * vtNorm ;
|
|
if ( dDist < EPS_SMALL)
|
|
return true ;
|
|
double dSafeTipDist = m_TParams.m_dTLen - m_TParams.m_dLen ;
|
|
if ( dDist < dSafeTipDist + SAFE_DIST_TOL)
|
|
return true ;
|
|
|
|
return false ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Drilling::DoStandardDrilling( const Hole& hole, SelData Id, int nPathId, double dMHOff, const Vector3d& vtA, const ToolData& currToolData)
|
|
{
|
|
// aggiusto alcuni parametri del ciclo di foratura
|
|
double dStartSlowLen = abs( m_Params.m_dStartSlowLen) ;
|
|
if ( abs( currToolData.m_dStartFeed - currToolData.m_dFeed) < EPS_SMALL)
|
|
dStartSlowLen = 0 ;
|
|
double dEndSlowLen = ( hole.bBlind ? 0 : abs( m_Params.m_dEndSlowLen)) ;
|
|
if ( abs( currToolData.m_dTipFeed - currToolData.m_dFeed) < EPS_SMALL)
|
|
dEndSlowLen = 0 ;
|
|
if ( ( dStartSlowLen + dEndSlowLen) > hole.dLen) {
|
|
dStartSlowLen = dStartSlowLen / ( dStartSlowLen + dEndSlowLen) * hole.dLen ;
|
|
dEndSlowLen = hole.dLen - dStartSlowLen ;
|
|
}
|
|
double dAddLen = ( hole.bBlind ? 0 : m_Params.m_dThroughAddLen) ;
|
|
bool bStartSlow = ( dStartSlowLen > EPS_SMALL) ;
|
|
bool bStd = ( ( hole.dLen - dStartSlowLen - dEndSlowLen) > EPS_SMALL) ;
|
|
bool bEndSlow = ( dEndSlowLen > EPS_SMALL) ;
|
|
// determino l'elevazione
|
|
double dElev = 0 ;
|
|
GetElevation( m_nPhase, hole.ptIni, hole.vtDir, currToolData.m_dDiam / 2, hole.vtDir, dElev) ;
|
|
// determino alcune caratteristiche dell'utensile
|
|
double dTExtrLen = max( 0.0, currToolData.m_dTLen - currToolData.m_dLen) ;
|
|
// necessità di spezzatura per robot
|
|
bool bSplitArcs = GetSplitArcs( V_NULL) ;
|
|
// imposto dati comuni
|
|
SetPathId( nPathId) ;
|
|
SetToolDir( hole.vtDir) ;
|
|
// 1 -> punto approccio (se con aggregato da sotto è una sequenza di approccio)
|
|
SetFlag( 1) ;
|
|
double dSafeZ = GetSafeZ() ;
|
|
double dSafeAggrBottZ = GetSafeAggrBottZ() ;
|
|
double dAppr = ( m_bAggrBottom ? dSafeAggrBottZ : dSafeZ) ;
|
|
Point3d ptP1 = hole.ptIni + hole.vtDir * ( dAppr + dElev + dTExtrLen + dMHOff) ;
|
|
if ( m_bAggrBottom) {
|
|
Point3d ptP0 = ptP1 + m_vtAggrBottom * ( m_dDistBottom + m_AggrBottom.dEncH + dSafeZ) ;
|
|
// se rinvio da sotto che richiede speciale rotazione
|
|
if ( m_AggrBottom.nType == 1) {
|
|
// punto ruotato
|
|
Point3d ptP00 = ptP0 + Z_AX * ( m_AggrBottom.dEncV + currToolData.m_dLen + dAppr + dTExtrLen) ;
|
|
Vector3d vtAux = m_vtAggrBottom ;
|
|
vtAux.Rotate( Z_AX, 0, 1) ;
|
|
SetAuxDir( vtAux) ;
|
|
if ( AddRapidStart( ptP00, MCH_CL_AGB_DWN) == GDB_ID_NULL)
|
|
return false ;
|
|
// vado al punto standard
|
|
SetAuxDir( m_vtAggrBottom) ;
|
|
SetFlag( 0) ;
|
|
if ( AddRapidMove( ptP0, bSplitArcs, MCH_CL_AGB_IN) == GDB_ID_NULL)
|
|
return false ;
|
|
}
|
|
// se altrimenti con rotazione per minimizzare la sporgenza
|
|
else if ( m_AggrBottom.nType == 3) {
|
|
// punto standard ruotato
|
|
Vector3d vtAux = m_vtAggrBottom ;
|
|
vtAux.Rotate( Z_AX, 0, 1) ;
|
|
SetAuxDir( vtAux) ;
|
|
if ( AddRapidStart( ptP0, MCH_CL_AGB_IN) == GDB_ID_NULL)
|
|
return false ;
|
|
// la rotazione viene eseguita nel movimento successivo al punto sopra l'inizio lavorazione
|
|
SetAuxDir( m_vtAggrBottom) ;
|
|
SetFlag( 0) ;
|
|
}
|
|
// altrimenti rinvio normale
|
|
else {
|
|
SetAuxDir( m_vtAggrBottom) ;
|
|
if ( AddRapidStart( ptP0, MCH_CL_AGB_IN) == GDB_ID_NULL)
|
|
return false ;
|
|
SetFlag( 0) ;
|
|
}
|
|
if ( AddRapidMove( ptP1, bSplitArcs) == GDB_ID_NULL)
|
|
return false ;
|
|
}
|
|
else {
|
|
if ( ! vtA.IsSmall())
|
|
SetAuxDir( vtA) ;
|
|
if ( AddRapidStart( ptP1) == GDB_ID_NULL)
|
|
return false ;
|
|
}
|
|
SetFlag( 0) ;
|
|
// 2 -> punto fuori (se diverso dal precedente)
|
|
if ( m_Params.m_dStartPos < dAppr) {
|
|
Point3d ptP2 = hole.ptIni + hole.vtDir * ( m_Params.m_dStartPos + dTExtrLen) ;
|
|
if ( AddRapidMove( ptP2, bSplitArcs) == GDB_ID_NULL)
|
|
return false ;
|
|
}
|
|
// 3 -> punto termine velocità ridotta iniziale (se previsto)
|
|
if ( bStartSlow) {
|
|
SetFeed( GetStartFeed()) ;
|
|
if ( ! bStd && ! bEndSlow)
|
|
SetFlag( 101) ; // fondo del foro
|
|
Point3d ptP3 = hole.ptIni - hole.vtDir * dStartSlowLen ;
|
|
if ( ! bStd && ! bEndSlow)
|
|
ptP3 -= hole.vtDir * dAddLen ;
|
|
if ( AddLinearMove( ptP3, bSplitArcs) == GDB_ID_NULL)
|
|
return false ;
|
|
}
|
|
// 4 -> punto termine velocità standard (se risulta)
|
|
if ( bStd) {
|
|
SetFeed( GetFeed()) ;
|
|
if ( ! bEndSlow)
|
|
SetFlag( 101) ; // fondo del foro
|
|
Point3d ptP4 = hole.ptIni - hole.vtDir * ( hole.dLen - dEndSlowLen) ;
|
|
if ( ! bEndSlow)
|
|
ptP4 -= hole.vtDir * dAddLen ;
|
|
if ( AddLinearMove( ptP4, bSplitArcs) == GDB_ID_NULL)
|
|
return false ;
|
|
}
|
|
// 5 -> punto termine velocità finale ridotta (se previsto)
|
|
if ( bEndSlow) {
|
|
SetFeed( GetTipFeed()) ;
|
|
SetFlag( 101) ; // fondo del foro
|
|
Point3d ptP5 = hole.ptIni - hole.vtDir * ( hole.dLen + dAddLen) ;
|
|
if ( AddLinearMove( ptP5, bSplitArcs) == GDB_ID_NULL)
|
|
return false ;
|
|
}
|
|
// 6 -> ritorno all'approccio del foro
|
|
SetFeed( GetEndFeed()) ;
|
|
SetFlag( 104) ; // risalita sopra il foro
|
|
if ( AddLinearMove( ptP1, bSplitArcs) == GDB_ID_NULL)
|
|
return false ;
|
|
// 7 -> punto fuori (se uso aggregato da sotto)
|
|
if ( m_bAggrBottom) {
|
|
// se con rotazione per minimizzare la sporgenza
|
|
if ( m_AggrBottom.nType == 3) {
|
|
// imposto rotazione su punto standard
|
|
Vector3d vtAux = m_vtAggrBottom ;
|
|
vtAux.Rotate( Z_AX, 0, 1) ;
|
|
SetAuxDir( vtAux) ;
|
|
}
|
|
SetFlag( 0) ;
|
|
// vado al punto
|
|
Point3d ptP0 = ptP1 + m_vtAggrBottom * ( m_dDistBottom + m_AggrBottom.dEncH + dSafeZ) ;
|
|
if ( AddRapidMove( ptP0, bSplitArcs, MCH_CL_AGB_OUT) == GDB_ID_NULL)
|
|
return false ;
|
|
// se rinvio da sotto che richiede speciale rotazione
|
|
if ( m_AggrBottom.nType == 1) {
|
|
Point3d ptP00 = ptP0 + Z_AX * ( m_AggrBottom.dEncV + currToolData.m_dLen + dAppr + dTExtrLen) ;
|
|
Vector3d vtAux = m_vtAggrBottom ;
|
|
vtAux.Rotate( Z_AX, 0, 1) ;
|
|
SetAuxDir( vtAux) ;
|
|
if ( AddRapidMove( ptP00, bSplitArcs, MCH_CL_AGB_UP) == GDB_ID_NULL)
|
|
return false ;
|
|
}
|
|
}
|
|
|
|
// reset dati di movimento
|
|
ResetMoveData() ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Drilling::DoPeckDrilling( const Hole& hole, SelData Id, int nPathId, double dMHOff, const Vector3d& vtA, const ToolData& currToolData)
|
|
{
|
|
// aggiusto alcuni parametri del ciclo di foratura
|
|
double dStartSlowLen = abs( m_Params.m_dStartSlowLen) ;
|
|
if ( abs( currToolData.m_dStartFeed - currToolData.m_dFeed) < EPS_SMALL)
|
|
dStartSlowLen = 0 ;
|
|
double dEndSlowLen = ( hole.bBlind ? 0 : abs( m_Params.m_dEndSlowLen)) ;
|
|
if ( abs( currToolData.m_dTipFeed - currToolData.m_dFeed) < EPS_SMALL)
|
|
dEndSlowLen = 0 ;
|
|
if ( ( dStartSlowLen + dEndSlowLen) > hole.dLen) {
|
|
dStartSlowLen = dStartSlowLen / ( dStartSlowLen + dEndSlowLen) * hole.dLen ;
|
|
dEndSlowLen = hole.dLen - dStartSlowLen ;
|
|
}
|
|
double dStdLen = hole.dLen - dStartSlowLen - dEndSlowLen ;
|
|
double dAddLen = ( hole.bBlind ? 0 : m_Params.m_dThroughAddLen) ;
|
|
double dReturnPos = m_Params.m_dReturnPos ;
|
|
bool bStartSlow = ( dStartSlowLen > EPS_SMALL) ;
|
|
bool bStd = ( dStdLen > EPS_SMALL) ;
|
|
bool bEndSlow = ( dEndSlowLen > EPS_SMALL) ;
|
|
// determino l'elevazione
|
|
double dElev = 0 ;
|
|
GetElevation( m_nPhase, hole.ptIni, hole.vtDir, currToolData.m_dDiam / 2, hole.vtDir, dElev) ;
|
|
// determino alcune caratteristiche dell'utensile
|
|
double dTExtrLen = max( 0.0, currToolData.m_dTLen - currToolData.m_dLen) ;
|
|
// necessità di spezzatura per robot
|
|
bool bSplitArcs = GetSplitArcs( V_NULL) ;
|
|
// imposto dati comuni
|
|
SetPathId( nPathId) ;
|
|
SetToolDir( hole.vtDir) ;
|
|
// 1 -> punto approccio
|
|
SetFlag( 1) ;
|
|
double dSafeZ = GetSafeZ() ;
|
|
double dSafeAggrBottZ = GetSafeAggrBottZ() ;
|
|
double dAppr = ( m_bAggrBottom ? dSafeAggrBottZ : dSafeZ) ;
|
|
Point3d ptP1 = hole.ptIni + hole.vtDir * ( dAppr + dElev + dTExtrLen + dMHOff) ;
|
|
if ( m_bAggrBottom) {
|
|
Point3d ptP0 = ptP1 + m_vtAggrBottom * ( m_dDistBottom + m_AggrBottom.dEncH + dSafeZ) ;
|
|
// se rinvio da sotto che richiede speciale rotazione
|
|
if ( m_AggrBottom.nType == 1) {
|
|
// punto ruotato
|
|
Point3d ptP00 = ptP0 + Z_AX * ( m_AggrBottom.dEncV + currToolData.m_dLen + dAppr + dTExtrLen) ;
|
|
Vector3d vtAux = m_vtAggrBottom ;
|
|
vtAux.Rotate( Z_AX, 0, 1) ;
|
|
SetAuxDir( vtAux) ;
|
|
if ( AddRapidStart( ptP00, MCH_CL_AGB_DWN) == GDB_ID_NULL)
|
|
return false ;
|
|
// vado al punto standard
|
|
SetFlag( 0) ;
|
|
SetAuxDir( m_vtAggrBottom) ;
|
|
if ( AddRapidMove( ptP0, bSplitArcs, MCH_CL_AGB_IN) == GDB_ID_NULL)
|
|
return false ;
|
|
}
|
|
// se altrimenti con rotazione per minimizzare la sporgenza
|
|
else if ( m_AggrBottom.nType == 3) {
|
|
// punto standard ruotato
|
|
Vector3d vtAux = m_vtAggrBottom ;
|
|
vtAux.Rotate( Z_AX, 0, 1) ;
|
|
SetAuxDir( vtAux) ;
|
|
if ( AddRapidStart( ptP0, MCH_CL_AGB_IN) == GDB_ID_NULL)
|
|
return false ;
|
|
// la rotazione viene eseguita nel movimento successivo al punto sopra l'inizio lavorazione
|
|
SetAuxDir( m_vtAggrBottom) ;
|
|
SetFlag( 0) ;
|
|
}
|
|
// altrimenti rinvio normale
|
|
else {
|
|
SetAuxDir( m_vtAggrBottom) ;
|
|
if ( AddRapidStart( ptP0, MCH_CL_AGB_IN) == GDB_ID_NULL)
|
|
return false ;
|
|
SetFlag( 0) ;
|
|
}
|
|
if ( AddRapidMove( ptP1, bSplitArcs) == GDB_ID_NULL)
|
|
return false ;
|
|
}
|
|
else {
|
|
if ( ! vtA.IsSmall())
|
|
SetAuxDir( vtA) ;
|
|
if ( AddRapidStart( ptP1) == GDB_ID_NULL)
|
|
return false ;
|
|
}
|
|
SetFlag( 0) ;
|
|
// 2 -> punto fuori (se diverso dal precedente)
|
|
if ( m_Params.m_dStartPos < dAppr) {
|
|
Point3d ptP2 = hole.ptIni + hole.vtDir * ( m_Params.m_dStartPos + dTExtrLen) ;
|
|
if ( AddRapidMove( ptP2, bSplitArcs) == GDB_ID_NULL)
|
|
return false ;
|
|
}
|
|
// parametri per foro in doppio
|
|
int nDouble = GetDoubleType( m_Params.m_sUserNotes) ;
|
|
bool bDouble = ( nDouble != 0) ;
|
|
bool bDoubleParallel = false ;
|
|
if ( bDouble)
|
|
bDoubleParallel = VerifyParallelDrilling( nDouble, hole) ;
|
|
double dDoubleLastStep = GetDoubleLastStep() ;
|
|
// ciclo di affondamento a step
|
|
const double MIN_STEP = 1 ;
|
|
const double APPR_STEP = 1 ;
|
|
const double MIN_MOVE = 1 ;
|
|
double dOrigStep = max( m_Params.m_dStep, MIN_STEP) ;
|
|
double dSteppedLen = ( bDouble ? hole.dLen - dDoubleLastStep : hole.dLen) ;
|
|
int nStep = int( ceil( dSteppedLen / dOrigStep)) ;
|
|
double dStep = dSteppedLen / nStep ;
|
|
if ( bDouble)
|
|
++ nStep ;
|
|
double dLastStep = ( bDouble ? dDoubleLastStep : dStep) ;
|
|
if ( dReturnPos < - dStep + APPR_STEP + MIN_MOVE)
|
|
dReturnPos = - dStep + APPR_STEP + MIN_MOVE ;
|
|
double dCurrLen = 0 ;
|
|
for ( int i = 1 ; i <= nStep ; ++ i) {
|
|
// se non è primo step faccio retrazione e riaffondo
|
|
if ( i != 1) {
|
|
// retrazione
|
|
SetFeed( GetEndFeed()) ;
|
|
SetFlag( 103) ; // punto di scarico truciolo
|
|
Point3d ptPr = hole.ptIni + hole.vtDir * dReturnPos ;
|
|
if ( AddLinearMove( ptPr, bSplitArcs) == GDB_ID_NULL)
|
|
return false ;
|
|
// riaffondo
|
|
SetFeed( GetEndFeed()) ;
|
|
SetFlag( 0) ;
|
|
Point3d ptPa = hole.ptIni - hole.vtDir * ( dCurrLen - APPR_STEP) ;
|
|
if ( AddLinearMove( ptPa, bSplitArcs) == GDB_ID_NULL)
|
|
return false ;
|
|
}
|
|
// lunghezza di fine step
|
|
double dEndLen = dCurrLen + ( i == nStep ? dLastStep : dStep) ;
|
|
// 3 -> punto termine velocità ridotta iniziale (se previsto)
|
|
if ( bStartSlow && ( i == 1 || dCurrLen < dStartSlowLen + EPS_SMALL)) {
|
|
// lunghezza di esecuzione
|
|
double dLen = min( dStartSlowLen, dEndLen) ;
|
|
// determino se arrivo in fondo al foro
|
|
bool bHoleEnd = ( ! bStd && ! bEndSlow && dLen > hole.dLen - EPS_SMALL) ;
|
|
// determino se arrivo in fondo allo step
|
|
bool bStepEnd = ( dLen > dEndLen - EPS_SMALL) ;
|
|
// assegno parametri
|
|
SetFeed( GetStartFeed()) ;
|
|
if ( bHoleEnd)
|
|
SetFlag( 101) ; // fondo del foro
|
|
else if ( bStepEnd)
|
|
SetFlag( 102) ; // fondo dello step
|
|
// movimento
|
|
Point3d ptP3 = hole.ptIni - hole.vtDir * dLen ;
|
|
if ( bHoleEnd)
|
|
ptP3 -= hole.vtDir * dAddLen ;
|
|
if ( bDoubleParallel && i == nStep) {
|
|
SetFlag( 105) ; // movimento in doppio parallelo
|
|
if ( AddLinearMove( ptP3, bSplitArcs, MCH_CL_PARALLEL_DBL) == GDB_ID_NULL)
|
|
return false ;
|
|
}
|
|
else {
|
|
if ( AddLinearMove( ptP3, bSplitArcs) == GDB_ID_NULL)
|
|
return false ;
|
|
}
|
|
// aggiorno posizione e verifico se step completato
|
|
dCurrLen = dLen ;
|
|
if ( bHoleEnd || bStepEnd)
|
|
continue ;
|
|
}
|
|
// 4 -> punto termine velocità standard (se risulta)
|
|
if ( bStd && dCurrLen < dStartSlowLen + dStdLen + EPS_SMALL) {
|
|
// lunghezza di esecuzione
|
|
double dLen = min( hole.dLen - dEndSlowLen, dEndLen) ;
|
|
// determino se arrivo in fondo al foro
|
|
bool bHoleEnd = ( ! bEndSlow && dLen > hole.dLen - EPS_SMALL) ;
|
|
// determino se arrivo in fondo allo step
|
|
bool bStepEnd = ( dLen > dEndLen - EPS_SMALL) ;
|
|
// assegno parametri
|
|
SetFeed( GetFeed()) ;
|
|
if ( bHoleEnd)
|
|
SetFlag( 101) ; // fondo del foro
|
|
else if ( bStepEnd)
|
|
SetFlag( 102) ; // fondo dello step
|
|
// movimento
|
|
Point3d ptP4 = hole.ptIni - hole.vtDir * dLen ;
|
|
if ( bHoleEnd)
|
|
ptP4 -= hole.vtDir * dAddLen ;
|
|
if ( bDoubleParallel && i == nStep) {
|
|
SetFlag( 105) ; // movimento in doppio parallelo
|
|
if ( AddLinearMove( ptP4, bSplitArcs, MCH_CL_PARALLEL_DBL) == GDB_ID_NULL)
|
|
return false ;
|
|
}
|
|
else {
|
|
if ( AddLinearMove( ptP4, bSplitArcs) == GDB_ID_NULL)
|
|
return false ;
|
|
}
|
|
// aggiorno posizione e verifico se step completato
|
|
dCurrLen = dLen ;
|
|
if ( bHoleEnd || bStepEnd)
|
|
continue ;
|
|
}
|
|
// 5 -> punto termine velocità finale ridotta (se previsto)
|
|
if ( bEndSlow) {
|
|
// lunghezza di esecuzione
|
|
double dLen = dEndLen ;
|
|
// determino se arrivo in fondo al foro
|
|
bool bHoleEnd = ( dLen > hole.dLen - EPS_SMALL) ;
|
|
// sono sempre in fondo allo step
|
|
// assegno parametri
|
|
SetFeed( GetTipFeed()) ;
|
|
if ( bHoleEnd)
|
|
SetFlag( 101) ; // fondo del foro
|
|
else
|
|
SetFlag( 102) ; // fondo dello step
|
|
// movimento
|
|
Point3d ptP5 = hole.ptIni - hole.vtDir * dLen ;
|
|
if ( bHoleEnd)
|
|
ptP5 -= hole.vtDir * dAddLen ;
|
|
if ( bDoubleParallel && i == nStep) {
|
|
SetFlag( 105) ; // movimento in doppio parallelo
|
|
if ( AddLinearMove( ptP5, bSplitArcs, MCH_CL_PARALLEL_DBL) == GDB_ID_NULL)
|
|
return false ;
|
|
}
|
|
else {
|
|
if ( AddLinearMove( ptP5, bSplitArcs) == GDB_ID_NULL)
|
|
return false ;
|
|
}
|
|
// aggiorno posizione
|
|
dCurrLen = dLen ;
|
|
}
|
|
}
|
|
|
|
// 6 -> ritorno all'approccio del foro
|
|
SetFeed( GetEndFeed()) ;
|
|
if ( bDoubleParallel) {
|
|
SetFlag( 105) ; // movimento in doppio parallelo
|
|
// aggiungo risalita aggiuntiva per lavorazione in doppio pari a due volte il LastStep
|
|
Point3d ptEnd ; GetCurrPos( ptEnd) ;
|
|
if ( AddLinearMove( ptEnd + min( dLastStep, dCurrLen) * hole.vtDir, bSplitArcs, MCH_CL_PARALLEL_DBL) == GDB_ID_NULL)
|
|
return false ;
|
|
SetFeed( GetFeed()) ;
|
|
GetCurrPos( ptEnd) ;
|
|
if ( AddLinearMove( ptEnd + min( dLastStep, dCurrLen) * hole.vtDir, bSplitArcs, MCH_CL_PARALLEL_DBL) == GDB_ID_NULL)
|
|
return false ;
|
|
SetFeed( GetEndFeed()) ;
|
|
// aggiungo discensa di LastStep per simmetria con secondo utensile
|
|
GetCurrPos( ptEnd) ;
|
|
if ( AddLinearMove( ptEnd - dLastStep * hole.vtDir, bSplitArcs, MCH_CL_PARALLEL_DBL) == GDB_ID_NULL)
|
|
return false ;
|
|
}
|
|
SetFlag( 104) ; // risalita sopra il foro
|
|
if ( AddLinearMove( ptP1, bSplitArcs) == GDB_ID_NULL)
|
|
return false ;
|
|
|
|
// 7 -> punto fuori (se uso aggregato da sotto)
|
|
if ( m_bAggrBottom) {
|
|
// se con rotazione per minimizzare la sporgenza
|
|
if ( m_AggrBottom.nType == 3) {
|
|
// imposto rotazione su punto standard
|
|
Vector3d vtAux = m_vtAggrBottom ;
|
|
vtAux.Rotate( Z_AX, 0, 1) ;
|
|
SetAuxDir( vtAux) ;
|
|
}
|
|
// vado al punto
|
|
SetFlag( 0) ;
|
|
Point3d ptP0 = ptP1 + m_vtAggrBottom * ( m_dDistBottom + m_AggrBottom.dEncH + dSafeZ) ;
|
|
if ( AddRapidMove( ptP0, bSplitArcs, MCH_CL_AGB_OUT) == GDB_ID_NULL)
|
|
return false ;
|
|
// se rinvio da sotto che richiede speciale rotazione
|
|
if ( m_AggrBottom.nType == 1) {
|
|
Point3d ptP00 = ptP0 + Z_AX * ( m_AggrBottom.dEncV + currToolData.m_dLen + dAppr + dTExtrLen) ;
|
|
Vector3d vtAux = m_vtAggrBottom ;
|
|
vtAux.Rotate( Z_AX, 0, 1) ;
|
|
SetAuxDir( vtAux) ;
|
|
if ( AddRapidMove( ptP00, bSplitArcs, MCH_CL_AGB_UP) == GDB_ID_NULL)
|
|
return false ;
|
|
}
|
|
}
|
|
|
|
// reset dati di movimento
|
|
ResetMoveData() ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
double
|
|
Drilling::GetDoubleLastStep( void)
|
|
{
|
|
// se non è foratura in doppio, restituisco valore molto grande
|
|
const double FALSE_LASTSTEP = 10000 ;
|
|
if ( GetDoubleType( m_Params.m_sUserNotes) == 0)
|
|
return FALSE_LASTSTEP ;
|
|
// recupero valore
|
|
const double MIN_LASTSTEP = 15 ;
|
|
double dDoubleLastStep = m_Params.m_dStep ;
|
|
if ( GetValInNotes( m_Params.m_sUserNotes, UN_LASTSTEP, dDoubleLastStep))
|
|
dDoubleLastStep = max( dDoubleLastStep, MIN_LASTSTEP) ;
|
|
return dDoubleLastStep ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Debug Functions
|
|
//----------------------------------------------------------------------------
|
|
void
|
|
Drilling::PrintConfigs( const VECTORHOLE& vHoles)
|
|
{
|
|
// Matrice ( #Configurazioni, #Fori )
|
|
// Ogni cella contiene ( Indice Foro in cui inserire il tool Main, Indice del Tool che lavoro il foro corrente, vtAux )
|
|
// Esempio ( Cella )_ij = ( A, B, vtAux)_ij :
|
|
// Nella configurazione i-esima il foro j esimo è lavorato dal tool B inserendo il tool principale nel foro A
|
|
// mantenendo un vettore ausiliario pari a vtAux
|
|
|
|
int nSpace = 25 ;
|
|
// riga dei fori
|
|
string sHoleRow = " " ; // 12 spazi
|
|
for ( int i = 0 ; i < int( vHoles.size()) ; ++ i) {
|
|
sHoleRow.append( "(" + ToString( i) + ")") ;
|
|
for ( int j = sHoleRow.length() ; j < ( i + 1) * nSpace + 12 ; ++ j)
|
|
sHoleRow.append( " ") ;
|
|
}
|
|
LOG_ERROR( GetEMkLogger(), sHoleRow.c_str()) ;
|
|
// scorro le configurazioni
|
|
for ( int nC = 0 ; ! vHoles.empty() && nC < int( vHoles[0].vIndTools.size()) ; ++ nC) {
|
|
string sRow = "(" + ToString( nC) + ")" ;
|
|
if ( vHoles[0].vIndMainTool.empty())
|
|
sRow.append( " ->") ;
|
|
else
|
|
sRow.append( "[" + ToString( vHoles[0].vIndMainTool[nC]) + "]->") ;
|
|
for ( int j = sRow.length() ; j < 12 ; ++ j)
|
|
sRow.append( " ") ;
|
|
for ( int nH = 0 ; nH < int( vHoles.size()) ; ++ nH) {
|
|
string sCell = "(" ;
|
|
if ( vHoles[nH].vIndTools[nC] != IND_TOOL_INVALID &&
|
|
vHoles[nH].vToolHole[nC] != IND_TOOL_INVALID &&
|
|
vHoles[nH].vVtAux[nC].IsValid()) {
|
|
sCell.append( ( ToString( vHoles[nH].vToolHole[nC]) + ", " +
|
|
ToString( vHoles[nH].vIndTools[nC]) + ", {" +
|
|
ToString( vHoles[nH].vVtAux[nC].x, 3) + ", " +
|
|
ToString( vHoles[nH].vVtAux[nC].y, 3) + ", " +
|
|
ToString( vHoles[nH].vVtAux[nC].z, 3) + "})").c_str()) ;
|
|
}
|
|
else
|
|
sCell.append( "-, -, {-, -, -})") ;
|
|
|
|
for ( int j = sCell.length() ; j < nSpace ; ++ j)
|
|
sCell.append( " ") ;
|
|
sRow.append( sCell) ;
|
|
}
|
|
LOG_ERROR( GetEMkLogger(), sRow.c_str()) ;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void
|
|
Drilling::PrintDescent( const MHDrill& myMHDescent)
|
|
{
|
|
LOG_ERROR( GetEMkLogger(), ( " --- Tool main sull'uscita " + ToString( myMHDescent.currTool.pTool->m_nExit) + " per il foro " + ToString( m_vId[myMHDescent.nHoleInd].nId)).c_str()) ;
|
|
string sActiveTool = "" ;
|
|
for ( int _a = 0 ; _a < int( myMHDescent.vActiveExit.size()) ; ++ _a)
|
|
sActiveTool.append( "->" + ToString( myMHDescent.vActiveExit[_a])) ;
|
|
LOG_ERROR( GetEMkLogger(), ( " Uscite attive : " + sActiveTool).c_str()) ;
|
|
string s_vtAux = "{" ;
|
|
s_vtAux.append( ToString( myMHDescent.vtAux.x) + ", ") ;
|
|
s_vtAux.append( ToString( myMHDescent.vtAux.y) + ", ") ;
|
|
s_vtAux.append( ToString( myMHDescent.vtAux.z) + "}") ;
|
|
LOG_ERROR( GetEMkLogger(), ( " vtAux : " + s_vtAux).c_str()) ;
|
|
}
|