Files
EgtMachKernel/Drilling.cpp
T
Riccardo Elitropi 271db23717 EgtMachKernel :
- migliorate le forature multiple.
2024-11-15 17:06:25 +01:00

2845 lines
108 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 "/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/EGkUserObjFactory.h"
#include "/EgtDev/Include/EGnStringKeyVal.h"
#include "/EgtDev/Include/EgtPointerOwner.h"
#include "/EgtDev/Include/EGkGeoFrame3d.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"
// 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 "
//----------------------------------------------------------------------------
// 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à svuotato, 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 svuoterà il foro corrente
VCT3DVECTOR vVtAux ; // []-> vettore ausiliario per tale condifgurazione
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 nInd_id_hole ; // indice foro
Vector3d vtAux ; // vettore ausiliario per tale foratura
MHDrill( int nIndH, Vector3d vtA)
: nInd_id_hole( nIndH), vtAux( vtA) {} ;
} ;
//----------------------------------------------------------------------------
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_vIdUndrilledHoles = m_vIdUndrilledHoles ;
}
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 ;
return true ;
}
//----------------------------------------------------------------------------
bool
Drilling::Save( int nBaseId, STRVECTOR& vString) const
{
try {
int nSize = 1 + m_Params.GetSize() + m_TParams.GetSize() + 3 ;
vString.insert( vString.begin(), nSize, "") ;
int k = - 1 ;
if ( ! SetVal( KEY_IDS, m_vId, vString[++k]))
return false ;
for ( int i = 0 ; i < m_Params.GetSize() ; ++ i)
vString[++k] = m_Params.ToString( i) ;
for ( int i = 0 ; i < m_TParams.GetSize() ; ++ i)
vString[++k] = m_TParams.ToString( i) ;
if ( ! SetVal( KEY_PHASE, m_nPhase, vString[++k]))
return false ;
if ( ! SetVal( KEY_NUM, m_nDrillings, vString[++k]))
return false ;
if ( ! SetVal( KEY_STAT, m_nStatus, 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 ;
}
}
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 ;
m_vIdUndrilledHoles = {} ;
}
//----------------------------------------------------------------------------
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 ;
// reset della geometria corrente
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
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 ;
// 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 svuoto
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 ;
// verifico validità gestore DB geometrico e Id del gruppo
if ( m_pGeomDB == nullptr || ! m_pGeomDB->ExistsObj( m_nOwnerId))
return false ;
// aggiorno dati geometrici dell'utensile
bool bToolChanged = true ;
if ( ! UpdateToolData( &bToolChanged)) {
m_pMchMgr->SetLastError( 2101, "Error in Drilling : UpdateToolData failed") ;
return false ;
}
// verifico se necessario continuare nell'aggiornamento
if ( ! bRecalc && ! bToolChanged &&
( m_nStatus == MCH_ST_OK || m_nStatus == MCH_ST_NO_POSTAPPL)) {
// confermo i percorsi di lavorazione
m_nDrillings = nCurrDrillings ;
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 svuoto
else
m_pGeomDB->EmptyGroup( nClId) ;
// elimino eventuale gruppo geometria simmetrica per lavorazione in doppio
int nDblId = m_pGeomDB->GetFirstNameInGroup( m_nOwnerId, MCH_DBL) ;
if ( nDblId != GDB_ID_NULL) {
m_pGeomDB->Erase( nDblId) ;
nDblId = GDB_ID_NULL ;
}
// 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 ;
}
// 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) ;
// eseguo aggiornamento assi macchina e collegamento con operazione precedente
if ( ! Update( bPostApply))
return false ;
// se lavorazione in doppio, aggiungo geometria della parte simmetrica
if ( ! CalcMirrorByDouble( nClId, m_Params.m_sUserNotes)) {
m_pMchMgr->SetLastError( 2115, "Error in Drilling : Mirror for Double calculation failed") ;
return false ;
}
// aggiorno stato della lavorazione
m_nStatus = ( bPostApply ? MCH_ST_OK : MCH_ST_NO_POSTAPPL) ;
// dichiaro successiva da aggiornare
UpdateFollowingOperationsStatus( MCH_ST_OTH_MODIF) ;
LOG_DBG_INFO( GetEMkLogger(), "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 ;
}
// 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 ;
}
// assegno estremi degli assi dei vari percorsi di lavorazione e della lavorazione nel suo complesso
CalcAndSetAxesBBox() ;
// esecuzione eventuali personalizzazioni
string sErr ;
if ( bPostApply && ! PostApply( sErr)) {
if ( ! IsEmptyOrSpaces( sErr))
m_pMchMgr->SetLastError( 2113, sErr) ;
else
m_pMchMgr->SetLastError( 2113, "Error in Drilling : post apply not calculable") ;
return false ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
Drilling::VerifyMultiParallelFixedDrills( void)
{
// se aggregato da sotto, sicuramente con una sola punta
bool bAggrBottom = IsAggrBottom( m_TParams.m_sHead) ;
if ( bAggrBottom)
return false ;
// se una sola uscita, inutile continuare
int nExitCnt = m_pMchMgr->GetCurrMachine()->GetHeadExitCount( m_TParams.m_sHead) ;
if ( nExitCnt == 1)
return false ;
// verifico che le uscite siano fisse
int nSelectType = m_pMchMgr->GetCurrMachine()->GetHeadSelectType( m_TParams.m_sHead) ;
if ( nSelectType != MCH_SLT_FIXEDEXITS)
return false ;
// 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))
return true ;
}
}
// non è stato trovato niente
return false ;
}
//----------------------------------------------------------------------------
bool
Drilling::StandardProcess( bool bRecalc, int nPvId, int nClId)
{
// se ho almeno un'altra punta fissa parallela alla principale ...
if ( VerifyMultiParallelFixedDrills()) {
TABMHDRILL tabDrills ;
double dMHOff = 0 ;
if ( ! MultiHeadDrilling( m_vId, nClId, 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].nInd_id_hole], 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].nInd_id_hole], MCH_PATH, nClId, dMHOff, tabDrills[i].vtAux))
return false ;
}
}
return true ;
}
// ... altrimenti 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))
return false ;
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
Drilling::CalcDrilledHolesByConfig( VECTORHOLE& vHoles, int nMyInd, int nIndConfig, INTVECTOR& vIndDrilled)
{
/*
restituisce quali fori non ancora svuotati vengono svuotati 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 ( è svuotato 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 svuotato 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 ;
// 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::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::CalcMultyHeadUndrilledHoles( const VECTORHOLE& vHoles, INTVECTOR& vIdUndrilledHoles)
{
/* funzione per calcolare gli Id dei fori fori non svuotati */
// se non ho fori, ho finito
vIdUndrilledHoles.clear() ;
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 svuotabile, lo inserisco nel vettore
if ( bIsUndrilled)
vIdUndrilledHoles.emplace_back( vHoles[i].hole.nOriId) ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
Drilling::CheckBasedConfig( const VECTORHOLE& vHoles, int nIndHole, int& nValidConfig, bool& bBaseCase)
{
// controllo dei parametri
if ( nIndHole < 0 || nIndHole >= int( vHoles.size()))
return false ;
if ( vHoles.empty())
return false ;
bBaseCase = false ;
nValidConfig = 0 ;
Vector3d vtAuxRef ;
for ( int i = 0 ; i < int( vHoles[nIndHole].vIndTools.size()) ; ++ i) {
if ( vHoles[nIndHole].vIndTools[i] != IND_TOOL_INVALID) {
++ nValidConfig ;
if ( nValidConfig == 1)
vtAuxRef = vHoles[nIndHole].vVtAux[i] ;
else {
// controllo se i versori ausiliari sono opposti
if ( ! AreOppositeVectorApprox( vtAuxRef, vHoles[nIndHole].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].nInd_id_hole].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 nInd_id_hole ;
Point3d ptIni ;
OrderTabDrill( int nInH, Point3d ptI)
: nInd_id_hole( nInH), ptIni( ptI) {} ;
} ;
vector<OrderTabDrill> vOrderedTab ;
for ( int i = 0 ; i < int( tabDrills.size()) ; ++ i)
vOrderedTab.emplace_back( tabDrills[i].nInd_id_hole, vHoles[tabDrills[i].nInd_id_hole].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, int nInd, TABMHDRILL& tabDrills, const Vector3d& vtAux,
const Vector3d& vtTool, int& nOkHole)
{
// salvo gli indici dei fori ( non ancora svuotati) che vengono svuotati 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 svuotati
for ( int i = 0 ; i < int( vInds.size()) ; ++ i)
vHoles[vInds[i]].bDrill = true ;
// assegno posizioni di ToolMain
if ( nRefConfig != -1) {
tabDrills.emplace_back( vHoles[nInd].vToolHole[nRefConfig], vHoles[nInd].vVtAux[nRefConfig]) ;
nOkHole += int( vInds.size()) ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
Drilling::MultiHeadDrilling( const SELVECTOR& vId, int nClId, 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) ;
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() ;
// calcolo la maschera di corrispondenza tra utensili e fori
if ( ! CalcMask( vHoles, vTools, nMainToolInd, vtTool, vtAux))
return false ;
// riduco il numeor di configurazioni in base a vtAux
if ( ! KeepMinRotatedConfigs( vHoles, vtAux, vtTool))
return false ;
// calcolo i fori non svuotati
if ( ! CalcMultyHeadUndrilledHoles( vHoles, m_vIdUndrilledHoles))
return false ;
// per ogni foro non svuotato, segnalo il Warning
int nNoDrillHoles = int( m_vIdUndrilledHoles.size()) ;
if ( ! m_vIdUndrilledHoles.empty()) {
string sIndHoles = "" ;
for ( int i = 0 ; i < nNoDrillHoles ; ++ i)
sIndHoles.append( ToString( m_vIdUndrilledHoles[i]) + ( i != nNoDrillHoles - 1 ? ", " : "")) ;
string sInfo = "Warning in Drilling : Skipped entities " + sIndHoles ;
m_pMchMgr->SetWarning( 2151, sInfo) ;
}
// se non posso svuotare nessun foro, esco
if ( nNoDrillHoles == 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()) && nNoDrillHoles != 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 ;
/* Inizio a considerare i fori che presentano meno configurazioni per essere svuotati.
Esso sono i più critici, quindi vengono gestiti per primi, scremando quindi le configurazioni
degli altri fori.
Parto ad analizzare i fori svuotabili 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 svuotati) che vengono svuotati con la sola configurazione presente
if ( ! GetHoleBestConfig( vHoles, i, tabDrills, vtAux, vtTool, nOkHole))
return false ;
}
// se nessun foro svuotabile, esco ( fino a prova contraria non esco mai...)
if ( tabDrills.empty())
return false ;
/* Una volta scremate le configurazioni critiche, cerco i fori non svuotati più vicini ad essi.
L'idea è che avendo svuotato 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()) - nNoDrillHoles) {
INTVECTOR vNextInds ;
if ( ! GetClosestHolesToHole( vHoles, tabDrills.back().nInd_id_hole, false, vNextInds) ||
vNextInds.empty() ||
! GetHoleBestConfig( vHoles, 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 svuotati dal Tool principale */
if ( ! MultiHeadOrderConfig( tabDrills, vHoles, vtTool, vtAux))
return false ;
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
*/
// 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 svuotatura 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 ;
int nStat ;
DBLVECTOR vAng1, vAng2 ;
// angoli per allineare versore T del tool principale con vtDir del foro i-esimo
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 svuotare e setto i loro parametri di foratura
if ( nDrills == nExitCnt - nNullTools) { // se ho svuotato 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 svuota questo foro
vHoles[nD].vVtAux.push_back( frHMT.VersX()) ; // versore ausiliario A del tool 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) ;
}
}
}
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
}
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) ;
}
}
}
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::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 ( FromString( ExtractInfo( m_Params.m_sUserNotes, "MaxElev="), dMaxElev) && dElev > dMaxElev) {
dElev = dMaxElev ;
hole.ptIni += hole.vtDir * ( dElev - hole.dLen) ;
hole.dLen = dElev ;
}
// limito lunghezza foro a massima lavorazione della punta
double dAddLen = ( hole.bBlind ? 0. : m_Params.m_dThroughAddLen) ;
if ( ( dElev + dAddLen) > Tool->m_dMaxMat + EPS_SMALL) {
hole.dLen = Tool->m_dMaxMat + max( hole.dLen - dElev, 0.) ;
hole.bBlind = true ;
}
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 svuoto
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 svuoto
else
m_pGeomDB->EmptyGroup( nTempId) ;
// in ogni caso lo dichiaro temporaneo e non visibile
m_pGeomDB->SetLevel( nTempId, GDB_LV_TEMP) ;
m_pGeomDB->SetStatus( nTempId, GDB_ST_OFF) ;
// recupero 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, Vector3d vtA)
{
// 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)) ;
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 ;
}
// 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 ( FromString( ExtractInfo( m_Params.m_sUserNotes, "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
double dAddLen = ( hole.bBlind ? 0 : m_Params.m_dThroughAddLen) ;
if ( ( dElev + dAddLen) > m_TParams.m_dMaxMat + EPS_SMALL) {
hole.dLen = m_TParams.m_dMaxMat + max( hole.dLen - dElev, 0.) ;
hole.bBlind = true ;
string sInfo = "Warning in Drilling : Drill bit too short for Hole " + ToString( nCircId) ;
m_pMchMgr->SetWarning( 2155, sInfo) ;
}
// verifico se tavola basculante
bool bTiltTab = false ;
m_bTiltingTab = ( m_pMchMgr->GetCurrMachine()->GetCurrTableIsTilting( bTiltTab, m_vtTiltingAx) && bTiltTab) ;
// verifico se testa da sopra (Z+)
m_bAboveHead = m_pMchMgr->GetHeadAbove( m_TParams.m_sHead) ;
// verifiche per 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 - EPS_SMALL) {
if ( DoStandardDrilling( hole, nCircId, nPathId, dMHOff, vtA)) {
// 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)) {
// 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) ;
}
}
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( bool* pbChanged)
{
// recupero il gestore DB utensili della macchina corrente
ToolsMgr* pTMgr = m_pMchMgr->GetCurrToolsMgr() ;
if ( pTMgr == nullptr)
return false ;
// recupero l'utensile nel DB utensili
const ToolData* pTdata = pTMgr->GetTool( m_Params.m_ToolUuid) ;
if ( pTdata == nullptr)
return false ;
// salvo posizione TC, testa e uscita originali
string sOrigTcPos = m_TParams.m_sTcPos ;
string sOrigHead = m_TParams.m_sHead ;
int nOrigExit = m_TParams.m_nExit ;
// verifico se sono diversi (ad esclusione di nome, posizione TC, testa e uscita)
bool bChanged = ( ! SameTool( m_TParams, *pTdata, false)) ;
// aggiorno comunque i parametri
m_TParams = *pTdata ;
// se definito attrezzaggio, aggiorno i parametri che ne possono derivare
string sTcPos ; string sHead ; int nExit ;
if ( m_pMchMgr->GetCurrSetupMgr().GetToolData( m_TParams.m_sName, sTcPos, sHead, nExit)) {
if ( sOrigTcPos != sTcPos ||
sOrigHead != sHead ||
nOrigExit != nExit)
bChanged = true ;
m_TParams.m_sTcPos = sTcPos ;
m_TParams.m_sHead = sHead ;
m_TParams.m_nExit = nExit ;
}
else {
if ( sOrigTcPos != pTdata->m_sTcPos ||
sOrigHead != pTdata->m_sHead ||
nOrigExit != pTdata->m_nExit)
bChanged = true ;
}
// eventuali segnalazioni
if ( ! EqualNoCase( m_Params.m_sToolName, m_TParams.m_sName)) {
string sInfo = "Warning in 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 definito parametro di ritorno, lo assegno
if ( pbChanged != nullptr)
*pbChanged = bChanged ;
return true ;
}
//----------------------------------------------------------------------------
bool
Drilling::GetGeometry( SELVECTOR& vIds) const
{
// restituisco l'elenco delle entità
vIds = m_vId ;
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 ( FromString( ExtractInfo( m_Params.m_sUserNotes, "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::DoStandardDrilling( const Hole& hole, SelData Id, int nPathId, double dMHOff, const Vector3d& vtA)
{
// aggiusto alcuni parametri del ciclo di foratura
double dStartSlowLen = abs( m_Params.m_dStartSlowLen) ;
if ( abs( m_TParams.m_dStartFeed - m_TParams.m_dFeed) < EPS_SMALL)
dStartSlowLen = 0 ;
double dEndSlowLen = ( hole.bBlind ? 0 : abs( m_Params.m_dEndSlowLen)) ;
if ( abs( m_TParams.m_dTipFeed - m_TParams.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, m_TParams.m_dDiam / 2, hole.vtDir, dElev) ;
// determino alcune caratteristiche dell'utensile
double dTExtrLen = max( 0.0, m_TParams.m_dTLen - m_TParams.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 + m_TParams.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 + m_TParams.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)
{
// aggiusto alcuni parametri del ciclo di foratura
double dStartSlowLen = abs( m_Params.m_dStartSlowLen) ;
if ( abs( m_TParams.m_dStartFeed - m_TParams.m_dFeed) < EPS_SMALL)
dStartSlowLen = 0 ;
double dEndSlowLen = ( hole.bBlind ? 0 : abs( m_Params.m_dEndSlowLen)) ;
if ( abs( m_TParams.m_dTipFeed - m_TParams.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, m_TParams.m_dDiam / 2, hole.vtDir, dElev) ;
// determino alcune caratteristiche dell'utensile
double dTExtrLen = max( 0.0, m_TParams.m_dTLen - m_TParams.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 + m_TParams.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 ;
}
// ciclo di affondamento a step
const double MIN_STEP = 1 ;
const double APPR_STEP = 1 ;
const double MIN_MOVE = 1 ;
double dStep = max( m_Params.m_dStep, MIN_STEP) ;
int nStep = int( ceil( hole.dLen / dStep)) ;
dStep = hole.dLen / nStep ;
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 + 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 ( 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 ( 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 ( AddLinearMove( ptP5, bSplitArcs) == GDB_ID_NULL)
return false ;
// aggiorno posizione
dCurrLen = dLen ;
}
}
// 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) ;
}
// 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 + m_TParams.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 ;
}