Files
EgtMachKernel/Operation.cpp
T
Dario Sassi 2d0ea787fa EgtMachKernel :
- in svuotature gestione SpiralIn e SpiralOut ottimizzate per cerchi
- in svuotatura aggiunti attacchi zigzag e elica e uscita Glide
- in contornatura miglioramenti vari.
2017-02-20 18:28:57 +00:00

1674 lines
66 KiB
C++

//----------------------------------------------------------------------------
// EgalTech 2016-2016
//----------------------------------------------------------------------------
// File : Operation.cpp Data : 29.04.16 Versione : 1.6p4
// Contenuto : Implementazione gestione base operazioni.
//
//
//
// Modifiche : 29.04.16 DS Creazione modulo.
//
//
//----------------------------------------------------------------------------
//--------------------------- Include ----------------------------------------
#include "stdafx.h"
#include "DllMain.h"
#include "Operation.h"
#include "MachMgr.h"
#include "OutputConst.h"
#include "/EgtDev/Include/EGkAngle.h"
#include "/EgtDev/Include/EGkGeoPoint3d.h"
#include "/EgtDev/Include/EGkCurveLine.h"
#include "/EgtDev/Include/EGkCurveArc.h"
#include "/EgtDev/Include/EgkArcSpecial.h"
#include "/EgtDev/Include/EGkCurveComposite.h"
#include "/EgtDev/Include/EgkDistPointCurve.h"
#include "/EgtDev/Include/EgkIntersCurves.h"
#include "/EgtDev/Include/EGkIntersLineSurfTm.h"
#include "/EgtDev/Include/EGkGeomDB.h"
#include "/EgtDev/Include/EGkCDBoxPolyhedron.h"
#include "/EgtDev/Include/EXeConst.h"
#include "/EgtDev/Include/EgtPointerOwner.h"
using namespace std ;
//----------------------------------------------------------------------------
bool
Operation::SetOwner( int nId, IGeomDB* pGDB)
{
m_nOwnerId = nId ;
m_pGeomDB = pGDB ;
return ( m_nOwnerId != GDB_ID_NULL && m_pGeomDB != nullptr) ;
}
//----------------------------------------------------------------------------
int
Operation::GetOwner( void) const
{
return m_nOwnerId ;
}
//----------------------------------------------------------------------------
IGeomDB*
Operation::GetGeomDB( void) const
{
return m_pGeomDB ;
}
//----------------------------------------------------------------------------
bool
Operation::Init( MachMgr* pMchMgr)
{
m_pMchMgr = pMchMgr ;
if ( m_pMchMgr == nullptr)
return false ;
if ( m_pMchMgr->GetGeomDB() != m_pGeomDB)
return false ;
return true ;
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
Operation::Operation( void)
: m_nOwnerId( GDB_ID_NULL), m_pGeomDB( nullptr), m_pMchMgr( nullptr), m_nPhase( 1),
m_nPathId( GDB_ID_NULL), m_bCurr( false), m_ptCurr(),
m_vtTool(), m_vtCorr(), m_vtAux(), m_dFeed( 0), m_nFlag( 0)
{
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
bool
Operation::GetElevation( int nPhase, const Point3d& ptP,
const Vector3d& vtDir, double& dElev)
{
if ( m_pMchMgr == nullptr || m_pGeomDB == nullptr)
return false ;
// inizializzo elevazione
dElev = INFINITO ;
// ciclo sui grezzi
bool bFound = false ;
int nRawId = m_pMchMgr->GetFirstRawPart() ;
while ( nRawId != GDB_ID_NULL) {
// verifico che il grezzo compaia nella fase
if ( m_pMchMgr->VerifyRawPartPhase( nRawId, nPhase)) {
// intersezione del raggio dal punto alla trimesh del grezzo
const double RAY_LEN = 10000 ;
int nStmId = m_pGeomDB->GetFirstNameInGroup( nRawId, MACH_RAW_SOLID) ;
ISurfTriMesh* pStm = GetSurfTriMesh( m_pGeomDB->GetGeoObj( nStmId)) ;
if ( pStm != nullptr) {
bFound = true ;
// recupero il riferimento della trimesh
Frame3d frStm ;
m_pGeomDB->GetGlobFrame( nStmId, frStm) ;
// porto il raggio in questo riferimento
Point3d ptPL = ptP ;
ptPL.ToLoc( frStm) ;
Vector3d vtDirL = vtDir ;
vtDirL.ToLoc( frStm) ;
ILSIVECTOR vInfo ;
if ( IntersLineSurfTm( ptPL, vtDirL, RAY_LEN, *pStm, vInfo)) {
for ( const auto& Info : vInfo) {
// se tratto di intersezione coincidente, considero la posizione più lontana, ovvero 2
if ( Info.nILTT == ILTT_SEGM || Info.nILTT == ILTT_SEGM_ON_EDGE) {
// se prosegue un tratto precedente, non devo controllare sia minimo
if ( fabs( dElev - Info.dU) < EPS_SMALL)
dElev = Info.dU2 ;
else
dElev = min( dElev, Info.dU2) ;
}
// altrimenti intersezione puntuale, verifico che esca (coseno >= 0)
else if ( Info.dCosDN > - COS_ORTO_ANG_ZERO) {
dElev = min( dElev, Info.dU) ;
}
}
}
}
}
// passo al grezzo successivo
nRawId = m_pMchMgr->GetNextRawPart( nRawId) ;
}
// se non trovate intersezioni, elevazione nulla
if ( dElev > INFINITO - 1)
dElev = 0 ;
return bFound ;
}
//----------------------------------------------------------------------------
bool
Operation::GetElevation( int nPhase, const Point3d& ptP1, const Point3d& ptP2,
const Vector3d& vtDir, double& dElev)
{
if ( m_pMchMgr == nullptr || m_pGeomDB == nullptr)
return false ;
// inizializzo elevazione
dElev = INFINITO ;
// ciclo sui grezzi
bool bFound = false ;
int nRawId = m_pMchMgr->GetFirstRawPart() ;
while ( nRawId != GDB_ID_NULL) {
// verifico che il grezzo compaia nella fase
if ( m_pMchMgr->VerifyRawPartPhase( nRawId, nPhase)) {
// intersezione del raggio dal punto alla trimesh del grezzo
const double RAY_LEN = 10000 ;
int nStmId = m_pGeomDB->GetFirstNameInGroup( nRawId, MACH_RAW_SOLID) ;
ISurfTriMesh* pStm = GetSurfTriMesh( m_pGeomDB->GetGeoObj( nStmId)) ;
if ( pStm != nullptr) {
bFound = true ;
// recupero il riferimento della trimesh
Frame3d frStm ;
m_pGeomDB->GetGlobFrame( nStmId, frStm) ;
// porto il segmento e la direzione in questo riferimento
Point3d ptP1L = ptP1 ;
ptP1L.ToLoc( frStm) ;
Point3d ptP2L = ptP2 ;
ptP2L.ToLoc( frStm) ;
Vector3d vtDirL = vtDir ;
vtDirL.ToLoc( frStm) ;
ILSIVECTOR vInfo ;
// inizializzo elevazione della superficie
double dElevS = 0 ;
// faccio test con un insieme di punti ( !!! sostituire con intersezione tra rettangolo e trimesh !!!)
const double STEP = 50 ;
int nStep = max( (int) ceil( ApproxDist( ptP1L, ptP2L) / STEP), 3) ;
for ( int i = 0 ; i <= nStep ; ++ i) {
// calcolo punto di test
double dFraz = i / (double) nStep ;
Point3d ptPL = Media( ptP1L, ptP2L, dFraz) ;
// inizializzo elevazione del punto
double dElevP = INFINITO ;
// calcolo elevazione sul punto
if ( IntersLineSurfTm( ptPL, vtDirL, RAY_LEN, *pStm, vInfo)) {
for ( const auto& Info : vInfo) {
// se tratto di intersezione coincidente, considero la posizione più lontana, ovvero 2
if ( Info.nILTT == ILTT_SEGM || Info.nILTT == ILTT_SEGM_ON_EDGE) {
// se prosegue un tratto precedente, non devo controllare sia minimo
if ( fabs( dElevP - Info.dU) < EPS_SMALL)
dElevP = Info.dU2 ;
else
dElevP = min( dElevP, Info.dU2) ;
}
// altrimenti intersezione puntuale, verifico che esca (coseno >= 0)
else if ( Info.dCosDN > - COS_ORTO_ANG_ZERO) {
dElevP = min( dElevP, Info.dU) ;
}
}
}
// se elevazione calcolata, aggiorno quella della superficie
if ( dElevP < INFINITO - 1)
dElevS = max( dElevS, dElevP) ;
}
// aggiorno elevazione complessiva
if ( dElevS > 0)
dElev = min( dElev, dElevS) ;
}
}
// passo al grezzo successivo
nRawId = m_pMchMgr->GetNextRawPart( nRawId) ;
}
// se non trovate intersezioni, elevazione nulla
if ( dElev > INFINITO - 1)
dElev = 0 ;
return bFound ;
}
//----------------------------------------------------------------------------
bool
Operation::GetElevation( int nPhase, const Point3d& ptP1, const Point3d& ptP2, const Point3d& ptP3,
const Vector3d& vtDir, double& dElev)
{
if ( m_pMchMgr == nullptr || m_pGeomDB == nullptr)
return false ;
// approssimo l'arco con due linee
double dElev1, dElev2 ;
if ( ! GetElevation( nPhase, ptP1, ptP2, vtDir, dElev1))
return false ;
if ( ! GetElevation( nPhase, ptP2, ptP3, vtDir, dElev2))
return false ;
dElev = max( dElev1, dElev2) ;
return true ;
}
//----------------------------------------------------------------------------
bool
Operation::GetElevation( int nPhase, const Point3d& ptP,
const Vector3d& vtDir, double dRad, double& dElev)
{
if ( m_pMchMgr == nullptr || m_pGeomDB == nullptr)
return false ;
// considero il punto
if ( ! GetElevation( nPhase, ptP, vtDir, dElev))
return false ;
// considero 8 punti sulla circonferenza
const int N_STEP = 8 ;
Vector3d vtRad = FromUprightOrtho( vtDir) * dRad ;
for ( int i = 0 ; i < N_STEP ; ++ i) {
double dElevT ;
vtRad.Rotate( vtDir, ANG_FULL / N_STEP) ;
if ( ! GetElevation( nPhase, ptP + vtRad, vtDir, dElevT))
return false ;
dElev = max( dElev, dElevT) ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
Operation::GetDistanceFromRawSide( int nPhase, const Point3d& ptP, const Vector3d& vtDir, double& dDist)
{
if ( m_pMchMgr == nullptr || m_pGeomDB == nullptr)
return false ;
// recupero il grezzo in cui è incluso il punto
BBox3d b3Pnt( ptP) ;
b3Pnt.Expand( 10, 10, 0) ;
int nRawId = m_pMchMgr->GetFirstRawPart() ;
while ( nRawId != GDB_ID_NULL) {
// verifico che il grezzo compaia nella fase
if ( m_pMchMgr->VerifyRawPartPhase( nRawId, nPhase)) {
// pre-filtro con il box
BBox3d b3Raw ;
int nRawSolidId = m_pGeomDB->GetFirstNameInGroup( nRawId, MACH_RAW_SOLID) ;
if ( m_pGeomDB->GetGlobalBBox( nRawSolidId, b3Raw) && b3Pnt.OverlapsXY( b3Raw)) {
// porto il punto nel riferimento del grezzo
Frame3d frRaw ;
m_pGeomDB->GetGroupGlobFrame( nRawId, frRaw) ;
Point3d ptPL = ptP ;
ptPL.ToLoc( frRaw) ;
// verifica con il contorno
int nOutCrvId = m_pGeomDB->GetFirstNameInGroup( nRawId, MACH_RAW_OUTLINE) ;
const ICurve* pCurve = GetCurve( m_pGeomDB->GetGeoObj( nOutCrvId)) ;
if ( pCurve != nullptr) {
int nSide ;
double dDist ;
DistPointCurve distPC( ptPL, *pCurve) ;
if ( distPC.GetDist( dDist) && dDist < 100 * EPS_SMALL ||
(distPC.GetSideAtMinDistPoint( 0, Z_AX, nSide) && nSide != MDS_RIGHT))
break ;
}
}
}
// passo al grezzo successivo
nRawId = m_pMchMgr->GetNextRawPart( nRawId) ;
}
// se il punto non è interno ad alcun grezzo, distanza nulla
if ( nRawId == GDB_ID_NULL) {
dDist = 0 ;
return true ;
}
// recupero il contorno del grezzo
int nOutId = m_pGeomDB->GetFirstNameInGroup( nRawId, MACH_RAW_OUTLINE) ;
ICurve* pOut = ::GetCurve( m_pGeomDB->GetGeoObj( nOutId)) ;
if ( pOut == nullptr)
return false ;
// recupero il riferimento del contorno e verifico che abbia Z verticale
Frame3d frStm ;
if ( ! m_pGeomDB->GetGlobFrame( nOutId, frStm) ||
( frStm.GetZType() != Frame3d::TOP && frStm.GetZType() != Frame3d::BOTTOM))
return false ;
// interseco il raggio di test (portato nel riferimento del contorno) con il contorno del grezzo
const double RAY_LEN = 10000 ;
PtrOwner<ICurveLine> pRay( CreateCurveLine()) ;
if ( IsNull( pRay) || ! pRay->SetPVL( ptP, vtDir, RAY_LEN))
return false ;
pRay->ToLoc( frStm) ;
IntersCurveCurve intCC( *pRay, *pOut) ;
IntCrvCrvInfo aInfo ;
if ( intCC.GetIntCrvCrvInfo( 0, aInfo))
dDist = aInfo.IciA[0].dU * RAY_LEN ;
else
dDist = 0 ;
return true ;
}
//----------------------------------------------------------------------------
bool
Operation::GetMinDistanceFromRawSide( int nPhase, const Point3d& ptP, double& dDist, Vector3d& vtDir)
{
if ( m_pMchMgr == nullptr || m_pGeomDB == nullptr)
return false ;
// recupero il grezzo in cui è incluso il punto
BBox3d b3Pnt( ptP) ;
b3Pnt.Expand( 10, 10, 0) ;
int nRawId = m_pMchMgr->GetFirstRawPart() ;
while ( nRawId != GDB_ID_NULL) {
// verifico che il grezzo compaia nella fase
if ( m_pMchMgr->VerifyRawPartPhase( nRawId, nPhase)) {
// pre-filtro con il box
BBox3d b3Raw ;
int nRawSolidId = m_pGeomDB->GetFirstNameInGroup( nRawId, MACH_RAW_SOLID) ;
if ( m_pGeomDB->GetGlobalBBox( nRawSolidId, b3Raw) && b3Pnt.OverlapsXY( b3Raw)) {
// porto il punto nel riferimento del grezzo
Frame3d frRaw ;
m_pGeomDB->GetGroupGlobFrame( nRawId, frRaw) ;
Point3d ptPL = ptP ;
ptPL.ToLoc( frRaw) ;
// verifica con il contorno
int nOutCrvId = m_pGeomDB->GetFirstNameInGroup( nRawId, MACH_RAW_OUTLINE) ;
const ICurve* pCurve = GetCurve( m_pGeomDB->GetGeoObj( nOutCrvId)) ;
if ( pCurve != nullptr) {
int nSide ;
DistPointCurve distPC( ptPL, *pCurve) ;
// se punto praticamente sul bordo del grezzo, prendo la normale esterna a questo bordo
if ( distPC.GetDist( dDist) && dDist < 100 * EPS_SMALL) {
double dU ;
int nFlag ;
Point3d ptML ;
Vector3d vtTgL ;
if ( distPC.GetParamAtMinDistPoint( 0, dU, nFlag) &&
pCurve->GetPointTang( dU, ICurve::FROM_MINUS, ptML, vtTgL)) {
vtDir = vtTgL ;
vtDir.Rotate( Z_AX, - ANG_RIGHT) ;
vtDir.ToGlob( frRaw) ;
vtDir.Normalize() ;
break ;
}
}
// altrimenti se punto interno, prendo la direzione dal punto al bordo
else if (distPC.GetSideAtMinDistPoint( 0, Z_AX, nSide) && nSide != MDS_RIGHT) {
int nFlag ;
Point3d ptML ;
if ( distPC.GetMinDistPoint( 0, ptML, nFlag)) {
vtDir = ptML - ptPL ;
vtDir.ToGlob( frRaw) ;
vtDir.z = 0 ;
vtDir.Normalize() ;
break ;
}
}
}
}
}
// passo al grezzo successivo
nRawId = m_pMchMgr->GetNextRawPart( nRawId) ;
}
// se il punto non è interno ad alcun grezzo, distanza nulla
if ( nRawId == GDB_ID_NULL)
dDist = 0 ;
return true ;
}
//----------------------------------------------------------------------------
bool
Operation::GetDistanceFromRawBottom( int nPhase, int nPathId, double dToler, double& dRbDist)
{
if ( m_pMchMgr == nullptr || m_pGeomDB == nullptr)
return false ;
// recupero distanza da fondo dei grezzi interessati dal percorso
dRbDist = 0 ;
BBox3d b3Compo ;
if ( ! m_pGeomDB->GetGlobalBBox( nPathId, b3Compo))
return false ;
b3Compo.Expand( dToler, dToler, 0) ;
int nRawId = m_pMchMgr->GetFirstRawPart() ;
while ( nRawId != GDB_ID_NULL) {
// verifico che il grezzo compaia nella fase
if ( m_pMchMgr->VerifyRawPartPhase( nRawId, nPhase)) {
BBox3d b3Raw ;
int nRawSolidId = m_pGeomDB->GetFirstNameInGroup( nRawId, MACH_RAW_SOLID) ;
if ( m_pGeomDB->GetGlobalBBox( nRawSolidId, b3Raw) && b3Compo.OverlapsXY( b3Raw)) {
double dDist = b3Compo.GetMax().z - b3Raw.GetMin().z ;
if ( dDist > dRbDist)
dRbDist = dDist ;
}
}
// passo al grezzo successivo
nRawId = m_pMchMgr->GetNextRawPart( nRawId) ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
Operation::GetRawGlobBox( int nPhase, int nPathId, double dToler, BBox3d& b3Raw)
{
if ( m_pMchMgr == nullptr || m_pGeomDB == nullptr)
return false ;
// inizializzo box
b3Raw.Reset() ;
// ricerco grezzi interessati dal percorso
BBox3d b3Compo ;
if ( ! m_pGeomDB->GetGlobalBBox( nPathId, b3Compo))
return false ;
b3Compo.Expand( dToler, dToler, 0) ;
int nRawId = m_pMchMgr->GetFirstRawPart() ;
while ( nRawId != GDB_ID_NULL) {
// verifico che il grezzo compaia nella fase
if ( m_pMchMgr->VerifyRawPartPhase( nRawId, nPhase)) {
BBox3d b3OneRaw ;
int nRawSolidId = m_pGeomDB->GetFirstNameInGroup( nRawId, MACH_RAW_SOLID) ;
if ( m_pGeomDB->GetGlobalBBox( nRawSolidId, b3OneRaw) && b3Compo.OverlapsXY( b3OneRaw)) {
b3Raw.Add( b3OneRaw) ;
}
}
// passo al grezzo successivo
nRawId = m_pMchMgr->GetNextRawPart( nRawId) ;
}
return true ;
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
bool
Operation::ApproxWithArcsIfUseful( ICurveComposite* pCompo)
{
// costanti di approssimazione
const double LIN_TOL_MID = 0.05 ;
const double ANG_TOL_STD_DEG = 15 ;
const double LIN_FEA_STD = 20 ;
// recupero estrusione e spessore
Vector3d vtExtr = Z_AX ;
pCompo->GetExtrusion( vtExtr) ;
double dThick = 0 ;
pCompo->GetThickness( dThick) ;
// verifico se sono tante linee
double dLen = 0 ;
pCompo->GetLength( dLen) ;
int nCrvs = pCompo->GetCurveCount() ;
if ( nCrvs < 5 || dLen > nCrvs * LIN_FEA_STD)
return true ;
// calcolo approssimazione con archi
PolyArc PA ;
if ( ! pCompo->ApproxWithArcsEx( LIN_TOL_MID, ANG_TOL_STD_DEG, LIN_FEA_STD, PA))
return false ;
// sostituisco gli archi alle curve originali
pCompo->Clear() ;
if ( ! pCompo->FromPolyArc( PA))
return false ;
// riassegno estrusione e spessore
pCompo->SetExtrusion( vtExtr) ;
pCompo->SetThickness( dThick) ;
return true ;
}
//----------------------------------------------------------------------------
bool
Operation::ApproxWithLines( ICurveComposite* pCompo)
{
// recupero estrusione e spessore
Vector3d vtExtr = Z_AX ;
pCompo->GetExtrusion( vtExtr) ;
double dThick = 0 ;
pCompo->GetThickness( dThick) ;
// calcolo approssimazione lineare
const double ANG_TOL_MAX_DEG = 90 ;
PolyLine PL ;
if ( ! pCompo->ApproxWithLines( 50 * EPS_SMALL, ANG_TOL_MAX_DEG, ICurve::APL_SPECIAL, PL))
return false ;
// sostituisco le linee alle curve originali
pCompo->Clear() ;
pCompo->FromPolyLine( PL) ;
// riassegno estrusione e spessore
pCompo->SetExtrusion( vtExtr) ;
pCompo->SetThickness( dThick) ;
return true ;
}
//----------------------------------------------------------------------------
bool
Operation::VerifyArcs( ICurveComposite* pCompo)
{
// verifiche sull'ampiezza dell'angolo al centro degli eventuali archi
const double MAX_ANG_CEN = 150 + EPS_ANG_SMALL ;
int nMaxInd = pCompo->GetCurveCount() - 1 ;
for ( int i = 0 ; i <= nMaxInd ; ) {
// se arco con angolo al centro oltre il limite, lo divido a metà
const ICurveArc* pArc = GetCurveArc( pCompo->GetCurve( i)) ;
if ( pArc != nullptr && abs( pArc->GetAngCenter()) > MAX_ANG_CEN) {
pCompo->AddJoint( i + 0.5) ;
++ nMaxInd ;
}
else
++ i ;
}
return true ;
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
bool
Operation::GetInitialAxesValues( DBLVECTOR& vAxVal)
{
if ( m_pMchMgr == nullptr || m_pGeomDB == nullptr)
return false ;
// recupero gruppo per geometria di lavorazione (Cutter Location)
int nClId = m_pGeomDB->GetFirstNameInGroup( GetOwner(), MCH_CL) ;
if ( nClId == GDB_ID_NULL)
return false ;
// recupero il primo percorso CL
int nClPathId = m_pGeomDB->GetFirstGroupInGroup( nClId) ;
// restituisco i valori iniziali degli assi di questo percorso di lavorazione
return GetClPathInitialAxesValues( nClPathId, vAxVal) ;
}
//----------------------------------------------------------------------------
bool
Operation::GetClPathInitialAxesValues( int nClPathId, DBLVECTOR& vAxVal)
{
if ( m_pMchMgr == nullptr || m_pGeomDB == nullptr)
return false ;
// recupero la prima entità di questo percorso
int nEntId = m_pGeomDB->GetFirstInGroup( nClPathId) ;
// recupero i dati Cam dell'entità
CamData* pCamData = GetCamData( m_pGeomDB->GetUserObj( nEntId)) ;
if ( pCamData == nullptr)
return false ;
// assegno i valori degli assi
vAxVal = pCamData->GetAxesVal() ;
return ( vAxVal.size() > 0) ;
}
//----------------------------------------------------------------------------
bool
Operation::GetFinalAxesValues( DBLVECTOR& vAxVal)
{
if ( m_pMchMgr == nullptr || m_pGeomDB == nullptr)
return false ;
// recupero gruppo per geometria di lavorazione (Cutter Location)
int nClId = m_pGeomDB->GetFirstNameInGroup( GetOwner(), MCH_CL) ;
if ( nClId == GDB_ID_NULL)
return false ;
// recupero l'ultimo percorso CL
int nClPathId = m_pGeomDB->GetLastGroupInGroup( nClId) ;
// restituisco i valori finali degli assi di questo percorso di lavorazione
return GetClPathFinalAxesValues( nClPathId, vAxVal) ;
}
//----------------------------------------------------------------------------
bool
Operation::GetClPathFinalAxesValues( int nClPathId, DBLVECTOR& vAxVal)
{
if ( m_pMchMgr == nullptr || m_pGeomDB == nullptr)
return false ;
// recupero l'ultima entità di questo percorso
int nEntId = m_pGeomDB->GetLastInGroup( nClPathId) ;
// recupero i dati Cam dell'entità
CamData* pCamData = GetCamData( m_pGeomDB->GetUserObj( nEntId)) ;
if ( pCamData == nullptr)
return false ;
// assegno i valori degli assi
vAxVal = pCamData->GetAxesVal() ;
return ( vAxVal.size() > 0) ;
}
//----------------------------------------------------------------------------
std::string
Operation::ExtractHint( const std::string& sNotes)
{
const string KEY_HINT = "Hint:" ;
string sHint ;
STRVECTOR vsCmd ;
Tokenize( sNotes, ";", vsCmd) ;
for each (const auto& sCmd in vsCmd) {
// se per assi rotanti
if ( sCmd.find( KEY_HINT) != string::npos) {
sHint = sCmd ;
ReplaceString( sHint, KEY_HINT, "") ;
break ;
}
}
return sHint ;
}
//----------------------------------------------------------------------------
bool
Operation::CalculateAxesValues( const string& sHint)
{
if ( m_pMchMgr == nullptr || m_pGeomDB == nullptr)
return false ;
// recupero l'operazione precedente non vuota o che richiede home precedente
int nPrevOpId = m_pMchMgr->GetPrevActiveOperation( m_nOwnerId) ;
Operation* pPrevOp = GetOperation( m_pGeomDB->GetUserObj( nPrevOpId)) ;
while ( pPrevOp != nullptr) {
if ( ! pPrevOp->IsEmpty() || pPrevOp->NeedPrevHome())
break ;
else {
nPrevOpId = m_pMchMgr->GetPrevActiveOperation( nPrevOpId) ;
pPrevOp = GetOperation( m_pGeomDB->GetUserObj( nPrevOpId)) ;
}
}
// recupero l'utensile precedente
string sPrevTool ;
if ( pPrevOp != nullptr && ! pPrevOp->IsEmpty())
sPrevTool = pPrevOp->GetToolName() ;
// imposto l'utensile per i calcoli macchina
if ( ! m_pMchMgr->SetCalcTool( GetToolName(), GetHeadName(), GetExitNbr()))
return false ;
// rimuovo posizionamento home da lavorazione precedente se non richiesto (non può più essere l'ultima)
if ( pPrevOp != nullptr && ! NeedPrevHome())
pPrevOp->RemoveHome() ;
// recupero il numero di assi lineari e rotanti attivi
int nLinAxes = m_pMchMgr->GetCurrLinAxes() ;
int nRotAxes = m_pMchMgr->GetCurrRotAxes() ;
// Assegno gli angoli iniziali
DBLVECTOR vAxRotPrec( nRotAxes, 0.) ;
DBLVECTOR vAxVal ;
// se utensile non cambiato, uso gli angoli finali della lavorazione precedente
if ( ! sPrevTool.empty() && ! ToolChangeNeeded( *pPrevOp, *this) &&
pPrevOp->GetFinalAxesValues( vAxVal)) {
for ( int i = 0 ; i < nRotAxes ; ++ i)
vAxRotPrec[i] = vAxVal[nLinAxes + i] ;
}
// altrimenti uso gli angoli home
else {
m_pMchMgr->GetAllCalcAxesHomePos( vAxVal) ;
for ( int i = 0 ; i < nRotAxes ; ++ i)
vAxRotPrec[i] = vAxVal[nLinAxes + i] ;
}
// se ci sono suggerimenti validi per gli assi rotanti, li applico
if ( ! sHint.empty()) {
STRVECTOR vsTok ;
Tokenize( sHint, ",", vsTok) ;
for each (const auto& sTok in vsTok) {
string szKey, szVal ;
Split( sTok, "=", true, szKey, szVal) ;
for ( int i = 0 ; i < nRotAxes ; ++ i) {
string sAxToken ;
if ( m_pMchMgr->GetCurrMachine()->GetCurrAxisToken(nLinAxes + i, sAxToken) &&
szKey == sAxToken) {
double dVal ;
if ( FromString( szVal, dVal))
vAxRotPrec[i] = dVal ;
break ;
}
}
}
}
// recupero peso primo asse rotante di testa
double dRot1W = m_pMchMgr->GetCalcRot1W() ;
// applico eventuali blocchi di assi rotanti
m_pMchMgr->ApplyRotAxisBlock() ;
// applico il criterio di scelta della soluzione quando molteplici
m_pMchMgr->SetCalcSolCh( GetSolCh()) ;
// recupero gruppo della geometria di lavorazione (Cutter Location)
int nClId = m_pGeomDB->GetFirstNameInGroup( GetOwner(), MCH_CL) ;
if ( nClId == GDB_ID_NULL)
return false ;
// calcolo il valore degli assi macchina di tutti i movimenti
bool bOk = true ;
int nClPathId = m_pGeomDB->GetFirstGroupInGroup( nClId) ;
while ( nClPathId != GDB_ID_NULL) {
DBLVECTOR vAxRotPrecOri = vAxRotPrec ;
int nOutStrC = 0 ;
if ( ! CalculateClPathAxesValues( nClPathId, nLinAxes, nRotAxes, dRot1W, vAxRotPrec, nOutStrC)) {
// se extracorsa dell'asse C, provo a precaricarlo al contrario
if ( nOutStrC != 0) {
vAxRotPrec[0] = vAxRotPrecOri[0] + ( nOutStrC > 0 ? - ANG_FULL : ANG_FULL) ;
vAxRotPrec[1] = vAxRotPrecOri[1] ;
if ( ! CalculateClPathAxesValues( nClPathId, nLinAxes, nRotAxes, dRot1W, vAxRotPrec, nOutStrC))
bOk = false ;
}
else
bOk = false ;
}
nClPathId = m_pGeomDB->GetNextGroup( nClPathId) ;
}
return bOk ;
}
//----------------------------------------------------------------------------
bool
Operation::CalculateClPathAxesValues( int nClPathId, int nLinAxes, int nRotAxes, double dRot1W,
DBLVECTOR& vAxRotPrec, int& nOutStrC)
{
if ( m_pMchMgr == nullptr || m_pGeomDB == nullptr)
return false ;
// recupero il numero degli assi lineari e rotanti
// predispongo variabile per valori assi
DBLVECTOR vAxVal ;
vAxVal.reserve( 8) ;
// variabili per coordinate lineari precedenti
double dXprec, dYprec, dZprec ;
// ciclo su tutte le entità del percorso CL
nOutStrC = 0 ;
bool bOk = true ;
bool bFirst = true ;
for ( int nEntId = m_pGeomDB->GetFirstInGroup( nClPathId) ;
nEntId != GDB_ID_NULL ;
nEntId = m_pGeomDB->GetNext( nEntId)) {
// recupero i dati Cam dell'entità
CamData* pCamData = GetCamData( m_pGeomDB->GetUserObj( nEntId)) ;
if ( pCamData == nullptr)
continue ;
// verifico che il primo movimento non sia un arco
if ( bFirst && pCamData->IsArc()) {
pCamData->ResetAxes() ;
LOG_INFO( GetEMkLogger(), "Error : first move in ClPath is an arc")
return false ;
}
// calcolo degli assi rotanti della macchina
int nRStat ;
DBLVECTOR vAng1, vAng2 ;
bool bROk = m_pMchMgr->GetCalcAngles( pCamData->GetToolDir(), pCamData->GetAuxDir(), nRStat, vAng1, vAng2) ;
if ( ! bROk || nRStat == 0) {
pCamData->SetAxes( CamData::AS_DIR_ERR, vAxVal) ;
LOG_INFO( GetEMkLogger(), "Error : tool direction unreachable")
return false ;
}
if ( abs( nRStat) == 1) {
// se primo movimento
if ( bFirst) {
// porto gli angoli ai valori più vicini ai precedenti con offset di uno o più giri
for ( size_t i = 0 ; i < vAng1.size() ; ++ i)
m_pMchMgr->GetNearestAngleInStroke( int( i), vAxRotPrec[i], vAng1[i]) ;
// se sol.ne indeterminata (sempre il primo asse), assegno il precedente, limitandolo alla corsa
if ( nRStat < 0 && vAng1.size() >= 1) {
vAng1[0] = vAxRotPrec[0] ;
m_pMchMgr->LimitAngleToStroke( 0, vAng1[0]) ;
}
}
// per movimenti successivi
else {
// scelgo gli angoli più vicini, per continuità non applico offset per stare nelle corse
for ( size_t i = 0 ; i < vAng1.size() ; ++ i)
vAng1[i] = AngleNearAngle( vAng1[i], vAxRotPrec[i]) ;
// se sol.ne indeterminata (sempre il primo asse), assegno il precedente
if ( nRStat < 0 && vAng1.size() >= 1) {
vAng1[0] = vAxRotPrec[0] ;
}
}
}
if ( abs( nRStat) == 2) {
// se primo movimento
if ( bFirst) {
// porto gli angoli ai valori più vicini ai precedenti con offset di uno o più giri
for ( size_t i = 0 ; i < vAng1.size() ; ++ i) {
m_pMchMgr->GetNearestAngleInStroke( int( i), vAxRotPrec[i], vAng1[i]) ;
m_pMchMgr->GetNearestAngleInStroke( int( i), vAxRotPrec[i], vAng2[i]) ;
}
// se sol.ne indeterminata (sempre il primo asse), assegno il precedente, limitandolo alla corsa
if ( nRStat < 0 && vAng1.size() >= 1) {
vAng1[0] = vAxRotPrec[0] ;
m_pMchMgr->LimitAngleToStroke( 0, vAng1[0]) ;
vAng2[0] = vAng1[0] ;
}
}
else {
// scelgo gli angoli più vicini, per continuità non applico offset per stare nelle corse
for ( size_t i = 0 ; i < vAng1.size() ; ++ i) {
vAng1[i] = AngleNearAngle( vAng1[i], vAxRotPrec[i]) ;
vAng2[i] = AngleNearAngle( vAng2[i], vAxRotPrec[i]) ;
// se sol.ne indeterminata (sempre il primo asse), assegno il precedente
if ( nRStat < 0 && vAng1.size() >= 1) {
vAng1[0] = vAxRotPrec[0] ;
vAng2[0] = vAng1[0] ;
}
}
}
// scelgo la soluzione più vicina ai precedenti
double dDelta1 = 0 ;
double dDelta2 = 0 ;
for ( size_t i = 0 ; i < vAng1.size() ; ++ i) {
// ignoro gli assi bloccati
if ( m_pMchMgr->IsKinematicRotAxisBlocked( int( i)))
continue ;
// calcolo i delta asse con eventuale peso
bool bFirst = ( i == 0) ;
dDelta1 += fabs( vAng1[i] - vAxRotPrec[i]) * ( bFirst ? dRot1W : 1) ;
dDelta2 += fabs( vAng2[i] - vAxRotPrec[i]) * ( bFirst ? dRot1W : 1) ;
}
if ( dDelta2 < dDelta1 - EPS_ANG_SMALL)
vAng1 = vAng2 ;
}
// ricavo posizione con eventuali modifiche dipendenti dalla lavorazione
Point3d ptP = pCamData->GetEndPoint() ;
AdjustEndPointForAxesCalc( pCamData, ptP) ;
// calcolo gli assi lineari della macchina
int nLStat ;
double dX, dY, dZ ;
bool bLOk = m_pMchMgr->GetCalcPositions( ptP, vAng1, nLStat, dX, dY, dZ) ;
if ( ! bLOk || nLStat != 0) {
bOk = false ;
pCamData->SetAxes( CamData::AS_ERR, vAxVal) ;
continue ;
}
// assegno valori assi
vAxVal.clear() ;
vAxVal.emplace_back( dX) ;
vAxVal.emplace_back( dY) ;
vAxVal.emplace_back( dZ) ;
for ( auto dAng : vAng1)
vAxVal.emplace_back( dAng) ;
// verifico i limiti di corsa degli assi
int nStat ;
bool bOsOk = m_pMchMgr->VerifyOutstroke( dX, dY, dZ, vAng1, nStat) ;
if ( ! bOsOk || nStat != 0) {
bOk = false ;
pCamData->SetAxes( CamData::AS_OUTSTROKE, vAxVal) ;
if ( nOutStrC == 0) {
if ( (nStat & 64) != 0)
nOutStrC = - 1 ;
else if ( (nStat & 128) != 0)
nOutStrC = 1 ;
}
string sInfo = "Outstroke : " + m_pMchMgr->GetOutstrokeInfo() ;
LOG_INFO( GetEMkLogger(), sInfo.c_str())
// imposto stato
bFirst = false ;
// memorizzo i valori degli assi lineari come nuovi precedenti
dXprec = dX ;
dYprec = dY ;
dZprec = dZ ;
// memorizzo i valori degli angoli come nuovi precedenti
vAxRotPrec = vAng1 ;
continue ;
}
// salvo i valori degli assi
pCamData->SetAxes( CamData::AS_OK, vAxVal) ;
// se arco devo calcolarne il centro in assi macchina
if ( pCamData->IsArc()) {
// devo lavorare con arco schiacciato nel suo piano
Point3d ptCen = pCamData->GetCenter() ;
double dAngCen = pCamData->GetAngCen() ;
Vector3d vtN = pCamData->GetNormDir() ;
double dDeltaN = pCamData->GetDeltaN() ;
// ricavo punto medio nel piano dell'arco
Point3d ptMid = ptP - dDeltaN * vtN ;
ptMid.Rotate( ptCen, vtN, - dAngCen / 2) ;
// determino i valori degli assi al punto medio
DBLVECTOR vAngMid( vAng1.size()) ;
for ( size_t i = 0 ; i < vAng1.size() ; ++ i)
vAngMid[i] = ( vAxRotPrec[i] + vAng1[i]) / 2 ;
int nLmidStat ;
double dXmid, dYmid, dZmid ;
bool bLmidOk = m_pMchMgr->GetCalcPositions( ptMid, vAngMid, nLmidStat, dXmid, dYmid, dZmid) ;
if ( ! bLmidOk || nLmidStat != 0) {
bOk = false ;
pCamData->SetAxes( CamData::AS_ERR, vAxVal) ;
continue ;
}
// ricavo punto finale nel piano dell'arco
Point3d ptEnd = ptP - dDeltaN * vtN ;
// determino i valori degli assi al punto finale
DBLVECTOR vAngEnd( vAng1.size()) ;
for ( size_t i = 0 ; i < vAng1.size() ; ++ i)
vAngEnd[i] = vAng1[i] ;
int nLendStat ;
double dXend, dYend, dZend ;
bool bLendOk = m_pMchMgr->GetCalcPositions( ptEnd, vAngEnd, nLendStat, dXend, dYend, dZend) ;
if ( ! bLendOk || nLendStat != 0) {
bOk = false ;
pCamData->SetAxes( CamData::AS_ERR, vAxVal) ;
continue ;
}
// punti espressi in assi macchina
Point3d ptP1M( dXprec, dYprec, dZprec) ;
Point3d ptP2M( dXmid, dYmid, dZmid) ;
Point3d ptP3M( dXend, dYend, dZend) ;
// se coincidono
if ( AreSamePointApprox( ptP1M, ptP2M) && AreSamePointApprox( ptP1M, ptP3M)) {
// lo considero un arco di raggio nullo
pCamData->SetAxesCen( ptP2M) ;
pCamData->SetAxesRad( 0) ;
pCamData->SetAxesAngCen( 0) ;
pCamData->SetAxesNormDir( V_NULL) ;
// il movimento diventa lineare
pCamData->SetMoveType( 1) ;
// non è necessario verificare i limiti di corsa degli assi
}
// altrimenti calcolo l'arco cui appartengono
else {
// calcolo arco per i tre punti espressi in assi macchina
PtrOwner<ICurve> pCurve( GetArc3P( ptP1M, ptP2M, ptP3M, false)) ;
if ( IsNull( pCurve)) {
LOG_INFO( GetEMkLogger(), "Error : arc on machine not calculable")
return false ;
}
// se realmente arco
if ( pCurve->GetType() == CRV_ARC) {
ICurveArc* pArc = GetCurveArc( pCurve) ;
// verifico il piano
if ( pArc->GetNormVersor() * pCamData->GetNormDir() < 0)
pArc->InvertN() ;
// assegno il centro e il raggio di questo arco ai dati cam
pCamData->SetAxesCen( pArc->GetCenter()) ;
pCamData->SetAxesRad( pArc->GetRadius()) ;
pCamData->SetAxesAngCen( pArc->GetAngCenter()) ;
pCamData->SetAxesNormDir( pArc->GetNormVersor()) ;
// aggiorno il tipo di arco
pCamData->SetMoveType( pArc->GetAngCenter() > 0 ? 3 : 2) ;
// verifico i limiti di corsa dei punti lungo l'arco
const int NUM_VERIF_STEP = 16 ;
Point3d ptCen = pCamData->GetAxesCen() ;
double dAngCenStep = pCamData->GetAxesAngCen() / NUM_VERIF_STEP ;
Vector3d vtN = pCamData->GetAxesNormDir() ;
Vector3d vtCurr = Point3d( dXprec, dYprec, dZprec) - ptCen ;
for ( int i = 1 ; i < NUM_VERIF_STEP ; ++ i) {
vtCurr.Rotate( vtN, dAngCenStep) ;
double dCoeff = double( i) / NUM_VERIF_STEP ;
Point3d ptCurr = ptCen + vtCurr + vtN * dDeltaN * dCoeff ;
DBLVECTOR vAng( vAng1.size()) ;
for ( size_t i = 0 ; i < vAng1.size() ; ++ i)
vAng[i] = vAxRotPrec[i] * ( 1 - dCoeff) + vAng1[i] * dCoeff ;
int nStat ;
bool bOsOk = m_pMchMgr->VerifyOutstroke( ptCurr.x, ptCurr.y, ptCurr.z, vAng, nStat) ;
if ( ! bOsOk || nStat != 0) {
bOk = false ;
pCamData->SetAxes( CamData::AS_OUTSTROKE, vAxVal) ;
string sInfo = "Outstroke : " + m_pMchMgr->GetOutstrokeInfo() ;
LOG_INFO( GetEMkLogger(), sInfo.c_str())
continue ;
}
}
}
// altrimenti linea
else {
ICurveLine* pLine = GetCurveLine( pCurve) ;
// lo considero un arco di raggio infinito
pCamData->SetAxesCen( ORIG) ;
pCamData->SetAxesRad( 0) ;
pCamData->SetAxesAngCen( 0) ;
pCamData->SetAxesNormDir( V_NULL) ;
// il movimento diventa lineare
pCamData->SetMoveType( 1) ;
// non è necessario verificare i limiti di corsa degli assi
}
}
}
bFirst = false ;
// memorizzo i valori degli assi lineari come nuovi precedenti
dXprec = dX ;
dYprec = dY ;
dZprec = dZ ;
// memorizzo i valori degli angoli come nuovi precedenti
vAxRotPrec = vAng1 ;
}
return bOk ;
}
//----------------------------------------------------------------------------
bool
Operation::AdjustStartEndMovements( void)
{
if ( m_pMchMgr == nullptr || m_pGeomDB == nullptr)
return false ;
// recupero gruppo della geometria di lavorazione (Cutter Location)
int nClId = m_pGeomDB->GetFirstNameInGroup( m_nOwnerId, MCH_CL) ;
if ( nClId == GDB_ID_NULL)
return false ;
// recupero ultima operazione precedente non vuota o che richiede home precedente
int nPrevOpId = m_pMchMgr->GetPrevActiveOperation( m_nOwnerId) ;
Operation* pPrevOp = GetOperation( m_pGeomDB->GetUserObj( nPrevOpId)) ;
while ( pPrevOp != nullptr) {
if ( ! pPrevOp->IsEmpty() || pPrevOp->NeedPrevHome())
break ;
else {
nPrevOpId = m_pMchMgr->GetPrevActiveOperation( nPrevOpId) ;
pPrevOp = GetOperation( m_pGeomDB->GetUserObj( nPrevOpId)) ;
}
}
// recupero l'utensile precedente e i dati della sua testa
string sPrevTool ;
if ( pPrevOp != nullptr && ! pPrevOp->IsEmpty())
sPrevTool = pPrevOp->GetToolName() ;
// determino posizione precedente assi
DBLVECTOR vAxVal ;
bool bHomeZ = false ;
// se primo utensile o richiesto, uso la posizione home
if ( sPrevTool.empty() || NeedPrevHome()) {
// imposto l'utensile per i calcoli macchina
if ( ! m_pMchMgr->SetCalcTool( GetToolName(), GetHeadName(), GetExitNbr()))
return false ;
// recupero posizione home
if ( ! m_pMchMgr->GetAllCalcAxesHomePos( vAxVal))
return false ;
// si parte da HomeZ
bHomeZ = true ;
}
// se utensile non cambiato o su diversa uscita della stessa testa, uso posizione finale della lavorazione precedente
else if ( ! ToolChangeNeeded( *pPrevOp, *this)) {
// imposto l'utensile per i calcoli macchina
if ( ! m_pMchMgr->SetCalcTool( GetToolName(), GetHeadName(), GetExitNbr()))
return false ;
// cancello risalita lavorazione precedente
pPrevOp->RemoveRise() ;
// recupero posizioni
DBLVECTOR vAxIni ;
if ( ! pPrevOp->GetFinalAxesValues( vAxVal) || ! GetInitialAxesValues( vAxIni))
return false ;
// determino delta Z rispetto a posizione finale
if ( vAxVal.size() >= 4 && vAxIni.size() >= 4) {
// verifico se movimento assi rotanti richiede una risalita parziale
double dDelta = 0 ;
if ( ! CalcDeltaZForHeadRotation( vAxVal, vAxIni, dDelta))
return false ;
// se necessaria, aggiungo risalita parziale
if ( dDelta > EPS_SMALL) {
if ( ! pPrevOp->AddRise( vAxVal, dDelta))
return false ;
// aggiorno quota in Z della posizione iniziale ( anche se verrà aggiornata solo in seguito)
vAxIni[2] = vAxVal[2] ;
}
}
// verifico se la testa interferisce con i pezzi o i bloccaggi sulla tavola
if ( ! TestCollisionAvoid( vAxVal, vAxIni)) {
// cancello eventuale risalita parziale della lavorazione precedente
pPrevOp->RemoveRise() ;
// aggiungo risalita a Zmax
if ( ! pPrevOp->AddRise( vAxVal))
return false ;
// si parte da HomeZ
bHomeZ = true ;
}
}
// altrimenti aggiungo uscita per cambio utensile alla lavorazione precedente e parto da questa
else {
// imposto l'utensile precedente per i calcoli macchina
if ( ! m_pMchMgr->SetCalcTool( pPrevOp->GetToolName(), pPrevOp->GetHeadName(), pPrevOp->GetExitNbr()))
return false ;
// ricalcolo risalita di lavorazione precedente
pPrevOp->RemoveRise() ;
if ( ! pPrevOp->AddRise( vAxVal))
return false ;
// imposto l'utensile per i calcoli macchina
if ( ! m_pMchMgr->SetCalcTool( GetToolName(), GetHeadName(), GetExitNbr()))
return false ;
// si parte da HomeZ
bHomeZ = true ;
}
// aggiusto l'inizio di ogni percorso di lavoro
bool bOk = true ;
int nClPathId = m_pGeomDB->GetFirstGroupInGroup( nClId) ;
while ( bOk && nClPathId != GDB_ID_NULL) {
// sistemo inizio
if ( ! AdjustOneStartMovement( nClPathId, vAxVal, bHomeZ))
bOk = false ;
bHomeZ = false ;
// recupero nuovi finali
if ( ! GetClPathFinalAxesValues( nClPathId, vAxVal))
bOk = false ;
// passo al successivo
nClPathId = m_pGeomDB->GetNextGroup( nClPathId) ;
}
// aggiungo risalita finale
bOk = bOk && AddRise( vAxVal) ;
// vado in home
bOk = bOk && AddHome() ;
return bOk ;
}
//----------------------------------------------------------------------------
bool
Operation::AdjustOneStartMovement( int nClPathId, const DBLVECTOR& vAxPrev, bool bHomeZ)
{
if ( m_pMchMgr == nullptr || m_pGeomDB == nullptr)
return false ;
// recupero la prima entità di questo percorso
int nEntId = m_pGeomDB->GetFirstInGroup( nClPathId) ;
// recupero i dati Cam dell'entità
CamData* pCamData = GetCamData( m_pGeomDB->GetUserObj( nEntId)) ;
if ( pCamData == nullptr)
return false ;
// recupero i valori degli assi
DBLVECTOR vAxCurr ;
vAxCurr = pCamData->GetAxesVal() ;
// se provengo da HomeZ (ovvero Z massima)
if ( bHomeZ) {
// copio l'entità
if ( m_pGeomDB->Copy( nEntId, GDB_ID_NULL, nEntId, GDB_AFTER) == GDB_ID_NULL)
return false ;
// modifico quella originale (è la prima del percorso)
m_pGeomDB->RemoveName( nEntId) ;
DBLVECTOR vAxNew = vAxCurr ;
vAxNew[2] = vAxPrev[2] ;
// eventuale aggiustamenti speciali dipendenti dalla macchina
Vector3d vtTool = pCamData->GetToolDir() ;
DBLVECTOR vAxTmp = vAxNew ;
bool bModif ;
if ( ! SpecialMoveZup( vtTool, vAxTmp, bModif))
return false ;
if ( bModif) {
pCamData->SetToolDir( vtTool) ;
vAxNew = vAxTmp ;
}
// applico le modifiche
pCamData->SetAxes( CamData::AS_OK, vAxNew) ;
pCamData->ChangeAxesMask( CamData::MSK_L1 | CamData::MSK_L2 | CamData::MSK_R1 | CamData::MSK_R2 | CamData::MSK_R3) ;
pCamData->SetFlag( 2) ;
}
// verifico se la testa interferisce con i pezzi o i bloccaggi sulla tavola
else {
// determino la Z più alta tra le due posizioni
double dZtop = max( vAxPrev[2], vAxCurr[2]) ;
// per il test uso posizioni temporanee con questa Z
DBLVECTOR vAxPrevZtop = vAxPrev ; vAxPrevZtop[2] = dZtop ;
DBLVECTOR vAxCurrZtop = vAxCurr ; vAxCurrZtop[2] = dZtop ;
// se interferisce
if ( ! TestCollisionAvoid( vAxPrevZtop, vAxCurrZtop)) {
// recupero HomeZ
Machine* pMch = m_pMchMgr->GetCurrMachine() ;
double dHomeZ ;
if ( pMch == nullptr || ! pMch->GetCurrAxisHomePos( 2, dHomeZ))
return false ;
// risalita sopra fine percorso precedente
// copio l'entità
int nNew1Id = m_pGeomDB->Copy( nEntId, GDB_ID_NULL, nEntId, GDB_BEFORE) ;
CamData* pNew1CamData = GetCamData( m_pGeomDB->GetUserObj( nNew1Id)) ;
if ( pNew1CamData == nullptr)
return false ;
// modifico questa entità
m_pGeomDB->RemoveName( nNew1Id) ;
DBLVECTOR vAxNew1 = vAxPrev ;
vAxNew1[2] = dHomeZ ;
int nMask = CamData::MSK_L3 ;
// eventuali aggiustamenti speciali dipendenti dalla macchina
Vector3d vtTool = pCamData->GetToolDir() ;
DBLVECTOR vAxTmp = vAxNew1 ;
bool bModif ;
if ( ! SpecialMoveZup( vtTool, vAxTmp, bModif))
return false ;
if ( bModif) {
pCamData->SetToolDir( vtTool) ;
if ( vAxNew1.size() >= 4 && abs( vAxTmp[3] - vAxNew1[3]) > EPS_ANG_SMALL) {
vAxCurr[3] = vAxNew1[3] ;
nMask |= CamData::MSK_R1 ;
}
if ( vAxNew1.size() >= 5 && abs( vAxTmp[4] - vAxNew1[4]) > EPS_ANG_SMALL) {
vAxCurr[4] = vAxNew1[4] ;
nMask |= CamData::MSK_R2 ;
}
if ( vAxNew1.size() >= 6 && abs( vAxTmp[5] - vAxNew1[5]) > EPS_ANG_SMALL) {
vAxCurr[5] = vAxNew1[5] ;
nMask |= CamData::MSK_R3 ;
}
vAxNew1 = vAxTmp ;
}
// applico le modifiche
pNew1CamData->SetAxes( CamData::AS_OK, vAxNew1) ;
pNew1CamData->ChangeAxesMask( nMask) ;
pNew1CamData->SetFlag( 0) ;
// spostamento sopra inizio percorso corrente
// copio l'entità
int nNew2Id = m_pGeomDB->Copy( nEntId, GDB_ID_NULL, nEntId, GDB_BEFORE) ;
CamData* pNew2CamData = GetCamData( m_pGeomDB->GetUserObj( nNew2Id)) ;
if ( pNew2CamData == nullptr)
return false ;
// modifico quella originale (è la prima del percorso)
m_pGeomDB->RemoveName( nNew2Id) ;
DBLVECTOR vAxNew2 = vAxCurr ;
vAxNew2[2] = dHomeZ ;
pNew2CamData->SetAxes( CamData::AS_OK, vAxNew2) ;
pNew2CamData->ChangeAxesMask( CamData::MSK_L1 | CamData::MSK_L2 | CamData::MSK_R1 | CamData::MSK_R2 | CamData::MSK_R3) ;
pNew2CamData->SetFlag( 2) ;
}
// altrimenti
else {
// se Z pressochè uguali non devo fare alcunché
if ( fabs( vAxCurr[2] - vAxPrev[2]) < 10 * EPS_SMALL)
return true ;
// se Z corrente maggiore della precedente
else if ( vAxCurr[2] > vAxPrev[2]) {
// copio l'entità
if ( m_pGeomDB->Copy( nEntId, GDB_ID_NULL, nEntId, GDB_AFTER) == GDB_ID_NULL)
return false ;
// modifico quella originale (è la prima del percorso)
m_pGeomDB->RemoveName( nEntId) ;
DBLVECTOR vAxNew = vAxPrev ;
vAxNew[2] = vAxCurr[2] ;
pCamData->SetAxes( CamData::AS_OK, vAxNew) ;
pCamData->ChangeAxesMask( CamData::MSK_L3) ;
pCamData->SetFlag( 0) ;
}
// altrimenti Z corrente minore della precedente
else {
// copio l'entità
if ( m_pGeomDB->Copy( nEntId, GDB_ID_NULL, nEntId, GDB_AFTER) == GDB_ID_NULL)
return false ;
// modifico quella originale (è la prima del percorso)
m_pGeomDB->RemoveName( nEntId) ;
DBLVECTOR vAxNew = vAxCurr ;
vAxNew[2] = vAxPrev[2] ;
// eventuali aggiustamenti speciali dipendenti dalla macchina
Vector3d vtTool = pCamData->GetToolDir() ;
DBLVECTOR vAxTmp = vAxNew ;
bool bModif ;
if ( ! SpecialMoveZup( vtTool, vAxTmp, bModif))
return false ;
if ( bModif) {
pCamData->SetToolDir( vtTool) ;
vAxNew = vAxTmp ;
}
// applico le modifiche
pCamData->SetAxes( CamData::AS_OK, vAxNew) ;
pCamData->ChangeAxesMask( CamData::MSK_L1 | CamData::MSK_L2 | CamData::MSK_R1 | CamData::MSK_R2 | CamData::MSK_R3) ;
pCamData->SetFlag( 2) ;
}
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
Operation::ToolChangeNeeded( const Operation& Op1, const Operation& Op2)
{
// se non cambia l'utensile, non cambia la testa fisica
if ( EqualNoCase( Op1.GetToolName(), Op2.GetToolName()))
return false ;
// se non hanno TcPos e stanno sulla stessa testa con uscita diversa, non cambia la testa fisica
if ( Op1.GetToolTcPos().empty() && Op2.GetToolTcPos().empty() &&
EqualNoCase( Op1.GetHeadName(), Op2.GetHeadName()) && Op1.GetExitNbr() != Op2.GetExitNbr())
return false ;
// se hanno lo stesso TcPos e stanno sulla stessa testa con uscita diversa, non cambia la testa fisica
if ( EqualNoCase( Op1.GetToolTcPos(), Op2.GetToolTcPos()) &&
EqualNoCase( Op1.GetHeadName(), Op2.GetHeadName()) && Op1.GetExitNbr() != Op2.GetExitNbr())
return false ;
// altrimenti necessario un cambio
return true ;
}
//----------------------------------------------------------------------------
bool
Operation::AddRise( DBLVECTOR& vAxVal, double dDelta)
{
if ( m_pMchMgr == nullptr || m_pGeomDB == nullptr)
return false ;
// recupero gruppo per geometria di lavorazione (Cutter Location)
int nClId = m_pGeomDB->GetFirstNameInGroup( GetOwner(), MCH_CL) ;
if ( nClId == GDB_ID_NULL)
return false ;
// recupero l'ultimo percorso
int nLastPxClId = m_pGeomDB->GetLastGroupInGroup( nClId) ;
// recupero l'ultima entità del percorso
int nEntId = m_pGeomDB->GetLastInGroup( nLastPxClId) ;
if ( nEntId == GDB_ID_NULL)
return false ;
// ne recupero i dati Cam
CamData* pCamData = GetCamData( m_pGeomDB->GetUserObj( nEntId)) ;
if ( pCamData == nullptr)
return false ;
// creo oggetto punto per DB geometrico
PtrOwner<IGeoPoint3d> pGP( CreateGeoPoint3d()) ;
if ( IsNull( pGP))
return false ;
// assegno le coordinate del punto
pGP->Set( pCamData->GetEndPoint()) ;
// inserisco l'oggetto nel DB geometrico
int nId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLastPxClId, Release( pGP)) ;
if ( nId == GDB_ID_NULL)
return false ;
m_pGeomDB->SetName( nId, MCH_CL_RISE) ;
// creo oggetto dati Cam
PtrOwner<CamData> pCam( pCamData->Clone()) ;
if ( IsNull( pCam))
return false ;
// recupero i valori degli assi
vAxVal = pCam->GetAxesVal() ;
if ( vAxVal.size() < 3)
return false ;
// flag per tipo di movimento in rapido
int nFlag = 0 ;
// se delta positivo lo uso come incremento di Z
if ( dDelta > 0) {
vAxVal[2] += dDelta ;
nFlag = 0 ; // movimento standard
}
// altrimenti uso la Z home
else {
// recupero posizione home
DBLVECTOR vAxHome ;
m_pMchMgr->GetAllCalcAxesHomePos( vAxHome) ;
vAxVal[2] = vAxHome[2] ;
nFlag = 3 ; // movimento a Zmax
}
// eventuale aggiustamenti speciali dipendenti dalla macchina
Vector3d vtTool = pCamData->GetToolDir() ;
DBLVECTOR vAxTmp = vAxVal ;
bool bModif ;
if ( ! SpecialMoveZup( vtTool, vAxTmp, bModif))
return false ;
if ( bModif) {
pCamData->SetToolDir( vtTool) ;
vAxVal = vAxTmp ;
}
// verifico extra-corsa dell'asse Z
double dL1 = vAxVal[0] ;
double dL2 = vAxVal[1] ;
double dL3 = vAxVal[2] ;
DBLVECTOR vAng ;
for ( int i = 0 ; i < int( vAxVal.size()) - 3 ; ++ i)
vAng.emplace_back( vAxVal[i+3]) ;
int nStat ;
bool bOk = ( m_pMchMgr->VerifyOutstroke( dL1, dL2, dL3, vAng, nStat) && nStat == 0) ;
// assegno i dati
pCam->SetAxes( (bOk ? CamData::AS_OK : CamData::AS_OUTSTROKE), vAxVal) ;
pCam->SetMoveType( 0) ;
pCam->SetFeed( 0) ;
pCam->SetFlag( nFlag) ;
// associo questo oggetto a quello geometrico
m_pGeomDB->SetUserObj( nId, Release( pCam)) ;
return bOk ;
}
//----------------------------------------------------------------------------
bool
Operation::RemoveRise( void)
{
if ( m_pMchMgr == nullptr || m_pGeomDB == nullptr)
return false ;
// recupero gruppo per geometria di lavorazione (Cutter Location)
int nClId = m_pGeomDB->GetFirstNameInGroup( GetOwner(), MCH_CL) ;
if ( nClId == GDB_ID_NULL)
return false ;
// recupero l'ultimo percorso CL
int nClPathId = m_pGeomDB->GetLastGroupInGroup( nClId) ;
// elimino tutte le entità RISE alla fine del percorso
int nId = m_pGeomDB->GetFirstNameInGroup( nClPathId, MCH_CL_RISE) ;
while ( nId != GDB_ID_NULL) {
m_pGeomDB->Erase( nId) ;
nId = m_pGeomDB->GetFirstNameInGroup( nClPathId, MCH_CL_RISE) ;
}
// elimino a maggior ragione le entità HOME
nId = m_pGeomDB->GetFirstNameInGroup( nClPathId, MCH_CL_HOME) ;
while ( nId != GDB_ID_NULL) {
m_pGeomDB->Erase( nId) ;
nId = m_pGeomDB->GetFirstNameInGroup( nClPathId, MCH_CL_HOME) ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
Operation::AddHome( void)
{
if ( m_pMchMgr == nullptr || m_pGeomDB == nullptr)
return false ;
// recupero gruppo per geometria di lavorazione (Cutter Location)
int nClId = m_pGeomDB->GetFirstNameInGroup( GetOwner(), MCH_CL) ;
if ( nClId == GDB_ID_NULL)
return false ;
// recupero l'ultimo percorso
int nLastPxClId = m_pGeomDB->GetLastGroupInGroup( nClId) ;
// recupero l'ultima entità del percorso di nome RISE
int nEntId = m_pGeomDB->GetLastNameInGroup( nLastPxClId, MCH_CL_RISE) ;
if ( nEntId == GDB_ID_NULL)
return false ;
// ne recupero i dati Cam
CamData* pCamData = GetCamData( m_pGeomDB->GetUserObj( nEntId)) ;
if ( pCamData == nullptr)
return false ;
// creo oggetto punto per DB geometrico
PtrOwner<IGeoPoint3d> pGP( CreateGeoPoint3d()) ;
if ( IsNull( pGP))
return false ;
// assegno le coordinate del punto
pGP->Set( pCamData->GetEndPoint()) ;
// inserisco l'oggetto nel DB geometrico
int nId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nLastPxClId, Release( pGP)) ;
if ( nId == GDB_ID_NULL)
return false ;
m_pGeomDB->SetName( nId, MCH_CL_HOME) ;
// creo oggetto dati Cam
PtrOwner<CamData> pCam( pCamData->Clone()) ;
if ( IsNull( pCam))
return false ;
// flag per tipo di movimento in rapido (rapido a Home)
int nFlag = 4 ;
// recupero coordinate home
DBLVECTOR vAxHome ;
m_pMchMgr->GetAllCalcAxesHomePos( vAxHome) ;
// assegno i dati
pCam->SetAxes( CamData::AS_OK, vAxHome) ;
pCam->SetMoveType( 0) ;
pCam->SetFeed( 0) ;
pCam->SetFlag( nFlag) ;
// associo questo oggetto a quello geometrico
m_pGeomDB->SetUserObj( nId, Release( pCam)) ;
return true ;
}
//----------------------------------------------------------------------------
bool
Operation::RemoveHome( void)
{
if ( m_pMchMgr == nullptr || m_pGeomDB == nullptr)
return false ;
// recupero gruppo per geometria di lavorazione (Cutter Location)
int nClId = m_pGeomDB->GetFirstNameInGroup( GetOwner(), MCH_CL) ;
if ( nClId == GDB_ID_NULL)
return false ;
// recupero l'ultimo percorso CL
int nClPathId = m_pGeomDB->GetLastGroupInGroup( nClId) ;
// elimino tutte le entità HOME alla fine del percorso
int nId = m_pGeomDB->GetFirstNameInGroup( nClPathId, MCH_CL_HOME) ;
while ( nId != GDB_ID_NULL) {
m_pGeomDB->Erase( nId) ;
nId = m_pGeomDB->GetFirstNameInGroup( nClPathId, MCH_CL_HOME) ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
Operation::CalcDeltaZForHeadRotation( const DBLVECTOR& vAxStart, const DBLVECTOR& vAxEnd, double& dDeltaZ)
{
// il numero di assi deve essere costante
if ( vAxStart.size() != vAxEnd.size())
return false ;
// se ci sono solo assi lineari, pongo delta Z nullo
if ( vAxStart.size() <= 3) {
dDeltaZ = 0 ;
return true ;
}
// determino gli estremi del movimento rotatorio
double dR1Start = ( vAxStart.size() >= 4 ? vAxStart[3] : 0) ;
double dR2Start = ( vAxStart.size() >= 5 ? vAxStart[4] : 0) ;
double dR3Start = ( vAxStart.size() >= 6 ? vAxStart[5] : 0) ;
double dR1End = ( vAxEnd.size() >= 4 ? vAxEnd[3] : 0) ;
double dR2End = ( vAxEnd.size() >= 5 ? vAxEnd[4] : 0) ;
double dR3End = ( vAxEnd.size() >= 6 ? vAxEnd[5] : 0) ;
// determino le variazioni di ciascun asse
double dR1Delta = dR1End - dR1Start ;
double dR2Delta = dR2End - dR2Start ;
double dR3Delta = dR3End - dR3Start ;
// divido il movimento in step di massimo 5 gradi
int nStep = int( max( abs( dR1Delta), max( abs( dR2Delta), abs( dR3Delta))) / 5.0) + 1 ;
double dR1Step = dR1Delta / nStep ;
double dR2Step = dR2Delta / nStep ;
double dR3Step = dR3Delta / nStep ;
// calcolo
double dL1 = vAxStart[0] ;
double dL2 = vAxStart[1] ;
double dL3 = vAxStart[2] ;
double dZStart, dZmin ;
DBLVECTOR vAng( 3) ;
for ( int i = 0 ; i <= nStep ; ++ i) {
vAng[0] = dR1Start + i * dR1Step ;
vAng[1] = dR2Start + i * dR2Step ;
vAng[2] = dR3Start + i * dR2Step ;
Point3d ptTip ;
if ( ! m_pMchMgr->GetCalcTipFromPositions( dL1, dL2, dL3, vAng, true, true, ptTip))
return false ;
if ( i == 0) {
dZStart = ptTip.z ;
dZmin = dZStart ;
}
else if ( ptTip.z < dZmin)
dZmin = ptTip.z ;
}
dDeltaZ = dZStart - dZmin ;
return true ;
}
//----------------------------------------------------------------------------
bool
Operation::TestCollisionAvoid( const DBLVECTOR& vAxStart, const DBLVECTOR& vAxEnd)
{
// Recupero macchina corrente
Machine* pMch = ( m_pMchMgr != nullptr ? m_pMchMgr->GetCurrMachine() : nullptr) ;
if ( pMch == nullptr)
return false ;
// Recupero tavola corrente
string sTable ;
if ( ! pMch->GetCurrTable( sTable))
return false ;
// Recupero assi correnti
STRVECTOR vAxName ;
pMch->GetAllCurrAxesName( vAxName) ;
// il numero di assi deve essere costante
if ( vAxName.size() != vAxStart.size() || vAxName.size() != vAxEnd.size())
return false ;
// !!! Temporaneo in attesa di gestione attrezzaggio !!!
// Se testa con Info ZMAXONROT != 0 e movimento assi rotanti -> collisione
int nHeadId = pMch->GetCurrHead() ;
int nVal = 0 ;
if ( m_pGeomDB->GetInfo( nHeadId, "ZMAXONROT", nVal) && nVal != 0) {
int nLinAxes = m_pMchMgr->GetCurrLinAxes() ;
int nRotAxes = m_pMchMgr->GetCurrRotAxes() ;
for ( int i = nLinAxes ; i < nLinAxes + nRotAxes ; ++ i) {
if ( int( vAxName.size()) > i && abs( vAxEnd[i] - vAxStart[i]) > 100 * EPS_ANG_SMALL)
return false ;
}
}
// Porto la macchina in home
pMch->ResetAllAxesPos() ;
// Elenco grezzi attivi
INTVECTOR vRawId ;
int nRawId = m_pMchMgr->GetFirstRawPart() ;
while ( nRawId != GDB_ID_NULL) {
if ( m_pMchMgr->VerifyRawPartPhase( nRawId, m_nPhase))
vRawId.emplace_back( nRawId) ;
nRawId = m_pMchMgr->GetNextRawPart( nRawId) ;
}
// Aggancio pezzi attivi alla tavola corrente
for ( const auto nRawId : vRawId)
pMch->LinkRawPartToGroup( nRawId, sTable) ;
// Elenco bloccaggi attivi
INTVECTOR vFxtId ;
int nFxtId = m_pMchMgr->GetFirstFixture() ;
while ( nFxtId != GDB_ID_NULL) {
vFxtId.emplace_back( nFxtId) ;
nFxtId = m_pMchMgr->GetNextFixture( nFxtId) ;
}
// Aggancio bloccaggi alla tavola corrente
for ( const auto nFxtId : vFxtId)
pMch->LinkFixtureToGroup( nFxtId, sTable) ;
// Vado nelle posizioni da controllare
bool bCollide = false ;
for ( int i = 1 ; i <= 15 && ! bCollide ; ++ i) {
double dCoeff = double( i) / 16 ;
for ( size_t j = 0 ; j < vAxStart.size() ; ++ j) {
double dPos = ( 1 - dCoeff) * vAxStart[j] + dCoeff * vAxEnd[j] ;
pMch->SetAxisPos( vAxName[j], dPos) ;
}
// Eseguo controllo
BBox3d b3Head ;
m_pGeomDB->GetGlobalBBox( pMch->GetCurrHead(), b3Head) ;
for ( const auto nRawId : vRawId) {
BBox3d b3Raw ;
int nRawSolidId = m_pGeomDB->GetFirstNameInGroup( nRawId, MACH_RAW_SOLID) ;
if ( m_pGeomDB->GetGlobalBBox( nRawSolidId, b3Raw) && b3Head.Overlaps( b3Raw)) {
// box testa nel riferimento del solido
Frame3d frSolid ;
m_pGeomDB->GetGlobFrame( nRawSolidId, frSolid) ;
BBox3d b3Hsol ;
m_pGeomDB->GetRefBBox( pMch->GetCurrHead(), frSolid, b3Hsol) ;
// solido
const ISurfTriMesh* pStm = GetSurfTriMesh( m_pGeomDB->GetGeoObj( nRawSolidId)) ;
// verifica di collisione tra box e solido
if ( pStm == nullptr || CDBoxPolyhedron( b3Hsol, *pStm))
bCollide = true ;
break ;
}
}
for ( const auto nFxtId : vFxtId) {
BBox3d b3Fxt ;
int nFlag = BBF_ONLY_VISIBLE | BBF_IGNORE_TEXT | BBF_IGNORE_TEXT ;
if ( m_pGeomDB->GetGlobalBBox( nFxtId, b3Fxt, nFlag) && b3Head.Overlaps( b3Fxt)) {
bCollide = true ;
break ;
}
}
}
// Riporto la macchina in home
pMch->ResetAllAxesPos() ;
// Sgancio grezzi e sottopezzi dalla tavola corrente
pMch->UnlinkAllRawPartsFromGroups() ;
pMch->UnlinkAllFixturesFromGroups() ;
return ( ! bCollide) ;
}
//----------------------------------------------------------------------------
bool
Operation::SpecialMoveZup( Vector3d& vtTool, DBLVECTOR& vAx, bool& bModif)
{
// recupero la macchina corrente
Machine* pMch = m_pMchMgr->GetCurrMachine() ;
if ( pMch == nullptr)
return false ;
// costanti
static const string EMC_VAR = "EMC" ; // tabella variabili locali per calcolo
static const string EVAR_ERROR = ".ERR" ; // OUT (int) codice di errore ( 0 = ok)
static const string EVAR_MODIF = ".MODIF" ; // OUT (bool) flag di modifica effettuata
static const string ON_SPECIAL_MOVEZUP = "OnSpecialMoveZup" ;
// eseguo l'azione
if ( pMch->LuaExistsFunction( ON_SPECIAL_MOVEZUP)) {
bool bOk = true ;
int nErr = 99 ;
// imposto valori parametri
bOk = bOk && pMch->LuaCreateGlobTable( EMC_VAR) ;
bOk = bOk && pMch->LuaSetGlobVar( EMC_VAR + GVAR_TOOL, GetToolName()) ;
bOk = bOk && pMch->LuaSetGlobVar( EMC_VAR + GVAR_HEAD, GetHeadName()) ;
bOk = bOk && pMch->LuaSetGlobVar( EMC_VAR + GVAR_EXIT, GetExitNbr()) ;
bOk = bOk && pMch->LuaSetGlobVar( EMC_VAR + GVAR_TCPOS, GetToolTcPos()) ;
// direzione utensile
bOk = bOk && pMch->LuaSetGlobVar( EMC_VAR + GVAR_TDIR, vtTool) ;
// valore degli assi
int nNumAxes = int( vAx.size()) ;
for ( int i = 1 ; i <= MAX_AXES ; ++ i) {
if ( i <= nNumAxes)
bOk = bOk && pMch->LuaSetGlobVar( GetGlobVarAxisValue( i, EMC_VAR), vAx[i-1]) ;
else
bOk = bOk && pMch->LuaResetGlobVar( GetGlobVarAxisValue( i, EMC_VAR)) ;
}
// eseguo
bOk = bOk && pMch->LuaCallFunction( ON_SPECIAL_MOVEZUP, false) ;
// recupero valori parametri obbligatori
bOk = bOk && pMch->LuaGetGlobVar( EMC_VAR + EVAR_ERROR, nErr) ;
bOk = bOk && pMch->LuaGetGlobVar( EMC_VAR + EVAR_MODIF, bModif) ;
bOk = bOk && pMch->LuaGetGlobVar( EMC_VAR + GVAR_TDIR, vtTool) ;
for ( int i = 1 ; i <= nNumAxes ; ++ i)
bOk = bOk && pMch->LuaGetGlobVar( GetGlobVarAxisValue( i, EMC_VAR), vAx[i-1]) ;
// reset
bOk = bOk && pMch->LuaResetGlobVar( EMC_VAR) ;
// segnalo errori
if ( nErr != 0) {
bOk = false ;
string sOut = " Error in " + ON_SPECIAL_MOVEZUP + " (" + ToString( nErr) + ")" ;
LOG_INFO( GetEMkLogger(), sOut.c_str())
}
return bOk ;
}
else {
bModif = false ;
return true ;
}
}