From 363ada252849d2633a671e411e1f80da9b784b24 Mon Sep 17 00:00:00 2001 From: Dario Sassi Date: Sat, 4 Feb 2017 15:31:52 +0000 Subject: [PATCH] EgtMachKernel : - aggiunte lavorazioni Scalpellatura e Svuotatura. --- Chiseling.h | 97 ++ ChiselingData.cpp | 28 + ChiselingData.h | 4 +- Chseling.cpp | 1534 ++++++++++++++++++++++++++++ EgtMachKernel.vcxproj | 4 + EgtMachKernel.vcxproj.filters | 12 + MachMgrOperations.cpp | 6 + MachiningCreate.h | 5 + Pocketing.cpp | 1816 +++++++++++++++++++++++++++++++++ Pocketing.h | 107 ++ 10 files changed, 3612 insertions(+), 1 deletion(-) create mode 100644 Chiseling.h create mode 100644 Chseling.cpp create mode 100644 Pocketing.cpp create mode 100644 Pocketing.h diff --git a/Chiseling.h b/Chiseling.h new file mode 100644 index 0000000..4251d88 --- /dev/null +++ b/Chiseling.h @@ -0,0 +1,97 @@ +//---------------------------------------------------------------------------- +// EgalTech 2017-2017 +//---------------------------------------------------------------------------- +// File : Chiseling.h Data : 04.02.17 Versione : 1.8b1 +// Contenuto : Dichiarazione della classe Chiseling. +// +// +// +// Modifiche : 04.02.17 DS Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +#pragma once + +#include "Machining.h" +#include "ChiselingData.h" +#include "ToolData.h" + +class ICurve ; +class ICurveComposite ; + +//---------------------------------------------------------------------------- +class Chiseling : public Machining +{ + public : // IUserObj + Chiseling* Clone( void) const override ; + const std::string& GetClassName( void) const override ; + bool Dump( std::string& sOut, bool bMM = true, const char* szNewLine = "\n") const override ; + bool ToSave( void) const override + { return true ; } + bool Save( STRVECTOR& vString) const override ; + bool Load( const STRVECTOR& vString, int nBaseGdbId) override ; + + public : // Operation + bool IsEmpty( void) const override + { return ( m_nMills == 0) ; } + + protected : // Operation + int GetSolCh( void) const override + { return m_Params.m_nSolCh ; } + bool AdjustEndPointForAxesCalc( const CamData* pCamData, Point3d& ptP) const override ; + + public : // Machining + bool Prepare( const std::string& sMillName) override ; + bool SetParam( int nType, bool bVal) override ; + bool SetParam( int nType, int nVal) override ; + bool SetParam( int nType, double dVal) override ; + bool SetParam( int nType, const std::string& sVal) override ; + bool SetGeometry( const SELVECTOR& vIds) override ; + bool Preview( bool bRecalc) override ; + bool Apply( bool bRecalc) override ; + bool GetParam( int nType, bool& bVal) const override ; + bool GetParam( int nType, int& nVal) const override ; + bool GetParam( int nType, double& dVal) const override ; + bool GetParam( int nType, std::string& sVal) const override ; + const ToolData& GetToolData( void) const ; + bool GetGeometry( SELVECTOR& vIds) const override ; + + public : + Chiseling( void) ; + + private : + bool UpdateToolData( void) ; + bool VerifyGeometry( SelData Id, int& nSubs, int& nType) ; + ICurve* GetCurve( SelData Id) ; + bool AdjustCurveFromSurf( ICurveComposite* pCrvCompo) ; + bool Chain( int nGrpDestId) ; + bool ProcessPath( int nPathId, int nPvId, int nClId) ; + bool CalcPathElevation( const ICurveComposite* pCompo, const Vector3d& vtTool, double dDepth, double dRad, double& dElev) ; + bool VerifyPathFromBottom( const ICurveComposite* pCompo, const Vector3d& vtTool) ; + bool GenerateMillingPv( int nPathId, const ICurveComposite* pCompo) ; + bool AddStandardMilling( const ICurveComposite* pCompo, const Vector3d& vtTool, const Vector3d& vtExtr, + double dDepth, double dElev, bool bSplitArcs) ; + bool AddApproach( const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dElev, double dAppr) ; + bool AddRetract( const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dElev, double dAppr) ; + double GetRadiusForStartEndElevation( void) ; + + private : + double GetFeed() const + { return ( abs( m_Params.m_dFeed) < EPS_MACH_LEN_PAR ? m_TParams.m_dFeed : m_Params.m_dFeed) ; } + double GetEndFeed() const + { return ( abs( m_Params.m_dEndFeed) < EPS_MACH_LEN_PAR ? m_TParams.m_dEndFeed : m_Params.m_dEndFeed) ; } + double GetTipFeed() const + { return ( abs( m_Params.m_dTipFeed) < EPS_MACH_LEN_PAR ? m_TParams.m_dTipFeed : m_Params.m_dTipFeed) ; } + double GetOffsL() const + { return ( abs( m_Params.m_dOffsL - UNKNOWN_PAR) < EPS_MACH_LEN_PAR ? m_TParams.m_dOffsL : m_Params.m_dOffsL) ; } + double GetOffsR() const + { return ( abs( m_Params.m_dOffsR - UNKNOWN_PAR) < EPS_MACH_LEN_PAR ? m_TParams.m_dOffsR : m_Params.m_dOffsR) ; } + + private : + SELVECTOR m_vId ; // identificativi entità geometriche da lavorare + ChiselingData m_Params ; // parametri lavorazione + ToolData m_TParams ; // parametri utensile + int m_nMills ; // numero di percorsi di lavoro generati + bool m_bAggrBottom ; // flag di utilizzo dell'aggregato da sotto +} ; \ No newline at end of file diff --git a/ChiselingData.cpp b/ChiselingData.cpp index 1451858..ca77c7f 100644 --- a/ChiselingData.cpp +++ b/ChiselingData.cpp @@ -35,6 +35,8 @@ enum nChiselingKey { KEY_NAME, KEY_NNS, KEY_NNU, + KEY_OL, + KEY_OR, KEY_PR, KEY_PS, KEY_SCC, @@ -55,6 +57,8 @@ static const std::array sChiselingKey = { "NAME", "NNS", "NNU", + "OL", + "OR", "PR", "PS", "SCC", @@ -103,6 +107,8 @@ ChiselingData::CopyFrom( const MachiningData* pMdata) m_dFeed = pDdata->m_dFeed ; m_dEndFeed = pDdata->m_dEndFeed ; m_dTipFeed = pDdata->m_dTipFeed ; + m_dOffsL = pDdata->m_dOffsL ; + m_dOffsR = pDdata->m_dOffsR ; m_nWorkSide = pDdata->m_nWorkSide ; m_bInvert = pDdata->m_bInvert ; m_sDepth = pDdata->m_sDepth ; @@ -135,6 +141,8 @@ ChiselingData::SameAs(const MachiningData* pMdata) const abs( m_dFeed - pDdata->m_dFeed) < EPS_MACH_LEN_PAR && abs( m_dEndFeed - pDdata->m_dEndFeed) < EPS_MACH_LEN_PAR && abs( m_dTipFeed - pDdata->m_dTipFeed) < EPS_MACH_LEN_PAR && + abs( m_dOffsL - pDdata->m_dOffsL) < EPS_MACH_LEN_PAR && + abs( m_dOffsR - pDdata->m_dOffsR) < EPS_MACH_LEN_PAR && m_nWorkSide == pDdata->m_nWorkSide && m_bInvert == pDdata->m_bInvert && m_sDepth == pDdata->m_sDepth && @@ -212,6 +220,12 @@ ChiselingData::FromString( const string& sString, int& nKey) case KEY_NNU : m_sUserNotes = sVal ; break ; + case KEY_OL : + bOk = ::FromString( sVal, m_dOffsL) ; + break ; + case KEY_OR : + bOk = ::FromString( sVal, m_dOffsR) ; + break ; case KEY_PR : bOk = ::FromString( sVal, m_dReturnPos) ; break ; @@ -257,6 +271,8 @@ ChiselingData::ToString( int nKey) const case KEY_NAME : return ( sChiselingKey[KEY_NAME] + "=" + m_sName) ; case KEY_NNS : return ( sChiselingKey[KEY_NNS] + "=" + m_sSysNotes) ; case KEY_NNU : return ( sChiselingKey[KEY_NNU] + "=" + m_sUserNotes) ; + case KEY_OL : return ( sChiselingKey[KEY_OL] + "=" + ::ToString( m_dOffsL)) ; + case KEY_OR : return ( sChiselingKey[KEY_OR] + "=" + ::ToString( m_dOffsR)) ; case KEY_PR : return ( sChiselingKey[KEY_PR] + "=" + ::ToString( m_dReturnPos)) ; case KEY_PS : return ( sChiselingKey[KEY_PS] + "=" + ::ToString( m_dStartPos)) ; case KEY_SCC : return ( sChiselingKey[KEY_SCC] + "=" + ::ToString( m_nSolCh)) ; @@ -359,6 +375,12 @@ ChiselingData::SetParam( int nType, double dVal) case MPA_TIPFEED : m_dTipFeed = dVal ; return true ; + case MPA_OFFSL : + m_dOffsL = dVal ; + return true ; + case MPA_OFFSR : + m_dOffsR = dVal ; + return true ; case MPA_DEPTH : m_sDepth = ::ToString( dVal) ; return true ; @@ -461,6 +483,12 @@ ChiselingData::GetParam( int nType, double& dVal) const case MPA_TIPFEED : dVal = m_dTipFeed ; return true ; + case MPA_OFFSL : + dVal = m_dOffsL ; + return true ; + case MPA_OFFSR : + dVal = m_dOffsR ; + return true ; case MPA_STARTPOS : dVal = m_dStartPos ; return true ; diff --git a/ChiselingData.h b/ChiselingData.h index 12a333a..ba9ee04 100644 --- a/ChiselingData.h +++ b/ChiselingData.h @@ -24,6 +24,8 @@ struct ChiselingData : public MachiningData double m_dFeed ; // velocità di lavorazione normale ( se 0 da utensile) double m_dEndFeed ; // velocità di lavorazione finale ( se 0 da utensile) double m_dTipFeed ; // velocità di lavorazione di sfondamento ( se 0 da utensile) + double m_dOffsR ; // offset radiale ( se UNKNOWN_PAR da utensile) + double m_dOffsL ; // offset longitudinale ( se UNKNOWN_PAR da utensile) bool m_bInvert ; // flag di inversione direzione lavorazione per casi passanti int m_nWorkSide ; // lato di lavoro (destra, sinistra) std::string m_sDepth ; // affondamento (espressione numerica) @@ -36,7 +38,7 @@ struct ChiselingData : public MachiningData ChiselingData( void) : m_ToolUuid(), m_nSolCh( 0), m_dFeed( 0), m_dEndFeed( 0), m_dTipFeed( 0), - m_bInvert( false), m_nWorkSide( 2), m_dStartPos( 0), + m_dOffsR( UNKNOWN_PAR), m_dOffsL( UNKNOWN_PAR), m_bInvert( false), m_nWorkSide( 2), m_dStartPos( 0), m_dStep( 0), m_dReturnPos( 0), m_dEndAddLen( 0) {} ChiselingData* Clone( void) const override ; bool CopyFrom( const MachiningData* pMdata) override ; diff --git a/Chseling.cpp b/Chseling.cpp new file mode 100644 index 0000000..84fc05d --- /dev/null +++ b/Chseling.cpp @@ -0,0 +1,1534 @@ +//---------------------------------------------------------------------------- +// EgalTech 2017-2017 +//---------------------------------------------------------------------------- +// File : Chiseling.cpp Data : 04.02.17 Versione : 1.8b1 +// Contenuto : Implementazione gestione scalpellature. +// +// +// +// Modifiche : 04.02.17 DS Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +//--------------------------- Include ---------------------------------------- +#include "stdafx.h" +#include "MachMgr.h" +#include "DllMain.h" +#include "Chiseling.h" +#include "MachiningConst.h" +#include "/EgtDev/Include/EGkCurveLine.h" +#include "/EgtDev/Include/EGkCurveArc.h" +#include "/EgtDev/Include/EGkCurveComposite.h" +#include "/EgtDev/Include/EGkArcSpecial.h" +#include "/EgtDev/Include/EGkChainCurves.h" +#include "/EgtDev/Include/EGkOffsetCurve.h" +#include "/EgtDev/Include/EGkSfrCreate.h" +#include "/EgtDev/Include/EGkSurfTriMesh.h" +#include "/EgtDev/Include/EGkUserObjFactory.h" +#include "/EgtDev/Include/EGnStringKeyVal.h" +#include "/EgtDev/Include/EgtPointerOwner.h" + +using namespace std ; + +//---------------------------------------------------------------------------- +USEROBJ_REGISTER( "EMkChiseling", Chiseling) ; + +//---------------------------------------------------------------------------- +const string& +Chiseling::GetClassName( void) const +{ + return USEROBJ_GETNAME( Chiseling) ; +} + +//---------------------------------------------------------------------------- +Chiseling* +Chiseling::Clone( void) const +{ + // alloco oggetto + Chiseling* pChisel = new(nothrow) Chiseling ; + // eseguo copia dei dati + if ( pChisel != nullptr) { + try { + pChisel->m_Params = m_Params ; + pChisel->m_TParams = m_TParams ; + } + catch( ...) { + delete pChisel ; + return nullptr ; + } + } + // ritorno l'oggetto + return pChisel ; +} + +//---------------------------------------------------------------------------- +bool +Chiseling::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_nMills) + szNewLine ; + + return true ; +} + +//---------------------------------------------------------------------------- +bool +Chiseling::Save( STRVECTOR& vString) const +{ + try { + int nSize = 1 + m_Params.GetSize() + m_TParams.GetSize() + 2 ; + 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_nMills, vString[++k])) + return false ; + } + catch( ...) { + return false ; + } + return true ; +} + +//---------------------------------------------------------------------------- +bool +Chiseling::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_nMills)) + return false ; + } + } + return true ; +} + +//---------------------------------------------------------------------------- +//---------------------------------------------------------------------------- +Chiseling::Chiseling( void) +{ + m_Params.m_sName = "*" ; + m_Params.m_sToolName = "*" ; + m_TParams.m_sName = "*" ; + m_TParams.m_sHead = "*" ; + m_nMills = 0 ; +} + +//---------------------------------------------------------------------------- +bool +Chiseling::Prepare( const string& sMillName) +{ + // verifico il gestore lavorazioni + if ( m_pMchMgr == nullptr) + return false ; + // recupero il gestore DB utensili della macchina corrente + ToolsMgr* pTMgr = m_pMchMgr->GetCurrToolsMgr() ; + if ( pTMgr == nullptr) + return false ; + // recupero il gestore DB lavorazioni della macchina corrente + MachiningsMgr* pMMgr = m_pMchMgr->GetCurrMachiningsMgr() ; + if ( pMMgr == nullptr) + return false ; + // ricerca della lavorazione di libreria con il nome indicato + const ChiselingData* pDdata = GetChiselingData( pMMgr->GetMachining( sMillName)) ; + if ( pDdata == nullptr) + return false ; + m_Params = *pDdata ; + // ricerca dell'utensile usato dalla lavorazione + const ToolData* pTdata = pTMgr->GetTool( m_Params.m_ToolUuid) ; + if ( pTdata == nullptr) + return false ; + m_TParams = *pTdata ; + m_Params.m_sToolName = m_TParams.m_sName ; + return true ; +} + +//---------------------------------------------------------------------------- +bool +Chiseling::SetParam( int nType, bool bVal) +{ + switch ( nType) { + case MPA_INVERT : + m_Params.m_bInvert = bVal ; + return true ; + } + return false ; +} + +//---------------------------------------------------------------------------- +bool +Chiseling::SetParam( int nType, int nVal) +{ + switch ( nType) { + case MPA_WORKSIDE : + if ( ! m_Params.VerifyWorkSide( nVal)) + return false ; + m_Params.m_nWorkSide = nVal ; + return true ; + case MPA_SCC : + if ( ! m_Params.VerifySolCh( nVal)) + return false ; + m_Params.m_nSolCh = nVal ; + return true ; + } + return false ; +} + +//---------------------------------------------------------------------------- +bool +Chiseling::SetParam( int nType, double dVal) +{ + switch ( nType) { + case MPA_FEED : + if ( abs( m_TParams.m_dFeed - dVal) < EPS_MACH_LEN_PAR) + m_Params.m_dFeed = 0 ; + else + m_Params.m_dFeed = dVal ; + return true ; + case MPA_ENDFEED : + if ( abs( m_TParams.m_dEndFeed - dVal) < EPS_MACH_LEN_PAR) + m_Params.m_dEndFeed = 0 ; + else + m_Params.m_dEndFeed = dVal ; + return true ; + case MPA_TIPFEED : + if ( abs( m_TParams.m_dTipFeed - dVal) < EPS_MACH_LEN_PAR) + m_Params.m_dTipFeed = 0 ; + else + m_Params.m_dTipFeed = dVal ; + return true ; + case MPA_OFFSR : + if ( abs( m_TParams.m_dOffsR - dVal) < EPS_MACH_LEN_PAR) + m_Params.m_dOffsR = UNKNOWN_PAR ; + else + m_Params.m_dOffsR = dVal ; + return true ; + case MPA_OFFSL : + if ( abs( m_TParams.m_dOffsL - dVal) < EPS_MACH_LEN_PAR) + m_Params.m_dOffsL = UNKNOWN_PAR ; + else + m_Params.m_dOffsL = dVal ; + return true ; + case MPA_DEPTH : + m_Params.m_sDepth = ToString( dVal) ; + return true ; + case MPA_STARTPOS : + m_Params.m_dStartPos = dVal ; + return true ; + case MPA_STEP : + m_Params.m_dStep = dVal ; + return true ; + case MPA_ENDADDLEN : + m_Params.m_dEndAddLen = dVal ; + return true ; + } + return false ; +} + +//---------------------------------------------------------------------------- +bool +Chiseling::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 ; + m_Params.m_sToolName = sVal ; + m_Params.m_ToolUuid = pTdata->m_Uuid ; + m_TParams = *pTdata ; + } break ; + case MPA_DEPTH_STR : + m_Params.m_sDepth = sVal ; + return true ; + case MPA_SYSNOTES : + m_Params.m_sSysNotes = sVal ; + break ; + case MPA_USERNOTES : + m_Params.m_sUserNotes = sVal ; + break ; + default : + return false ; + } + return true ; +} + +//---------------------------------------------------------------------------- +bool +Chiseling::SetGeometry( const SELVECTOR& vIds) +{ + // verifico validità gestore DB geometrico + if ( m_pGeomDB == nullptr) + return false ; + // reset della geometria corrente + m_vId.clear() ; + // verifico che gli identificativi rappresentino delle entità ammissibili (tutte curve o tutte facce) + int nType = GEO_NONE ; + for ( const auto& Id : vIds) { + // test sull'entità + int nSubs ; + if ( ! VerifyGeometry( Id, nSubs, nType)) { + string sOut = "Entity " + ToString( Id) + " skipped by Milling" ; + LOG_INFO( GetEMkLogger(), sOut.c_str()) ; + continue ; + } + // posso aggiungere alla lista + m_vId.emplace_back( Id) ; + } + return ( ! m_vId.empty() || vIds.empty()) ; +} + +//---------------------------------------------------------------------------- +bool +Chiseling::Preview( bool bRecalc) +{ + // reset numero percorsi di lavoro generati + m_nMills = 0 ; + + // verifico validità gestore DB geometrico e Id del gruppo + if ( m_pGeomDB == nullptr || ! m_pGeomDB->ExistsObj( m_nOwnerId)) + return false ; + + // recupero gruppo per geometria ausiliaria + int nAuxId = m_pGeomDB->GetFirstNameInGroup( m_nOwnerId, MCH_AUX) ; + bool bChain = false ; + // se non c'è, lo aggiungo + if ( nAuxId == GDB_ID_NULL) { + nAuxId = m_pGeomDB->AddGroup( GDB_ID_NULL, m_nOwnerId, Frame3d()) ; + if ( nAuxId == GDB_ID_NULL) + return false ; + m_pGeomDB->SetName( nAuxId, MCH_AUX) ; + m_pGeomDB->SetStatus( nAuxId, GDB_ST_OFF) ; + bChain = true ; + } + // altrimenti, se chiesto ricalcolo, lo svuoto + else if ( bRecalc) { + m_pGeomDB->EmptyGroup( nAuxId) ; + bChain = true ; + } + + // aggiorno dati geometrici dell'utensile + if ( ! UpdateToolData()) { + LOG_INFO( GetEMkLogger(), "Error in Milling : UpdateToolData failed") ; + return false ; + } + + // se necessario, eseguo concatenamento ed inserisco i percorsi sotto la geometria ausiliaria + if ( bChain && ! Chain( nAuxId)) + return false ; + + // recupero gruppo per geometria di Preview + int nPvId = m_pGeomDB->GetFirstNameInGroup( m_nOwnerId, MCH_PV) ; + // se non c'è, lo aggiungo + if ( nPvId == GDB_ID_NULL) { + nPvId = m_pGeomDB->AddGroup( GDB_ID_NULL, m_nOwnerId, Frame3d()) ; + if ( nPvId == GDB_ID_NULL) + return false ; + m_pGeomDB->SetName( nPvId, MCH_PV) ; + } + // altrimenti lo svuoto + else + m_pGeomDB->EmptyGroup( nPvId) ; + + // lavoro ogni singola catena + int nPathId = m_pGeomDB->GetFirstGroupInGroup( nAuxId) ; + while ( nPathId != GDB_ID_NULL) { + if ( ! ProcessPath( nPathId, nPvId, GDB_ID_NULL)) + return false ; + nPathId = m_pGeomDB->GetNextGroup( nPathId) ; + } + + return true ; +} + +//---------------------------------------------------------------------------- +bool +Chiseling::Apply( bool bRecalc) +{ + // reset numero percorsi di lavoro generati + m_nMills = 0 ; + + // verifico validità gestore DB geometrico e Id del gruppo + if ( m_pGeomDB == nullptr || ! m_pGeomDB->ExistsObj( m_nOwnerId)) + return false ; + + // recupero gruppo per geometria ausiliaria + int nAuxId = m_pGeomDB->GetFirstNameInGroup( m_nOwnerId, MCH_AUX) ; + bool bChain = false ; + // se non c'è, lo aggiungo + if ( nAuxId == GDB_ID_NULL) { + nAuxId = m_pGeomDB->AddGroup( GDB_ID_NULL, m_nOwnerId, Frame3d()) ; + if ( nAuxId == GDB_ID_NULL) + return false ; + m_pGeomDB->SetName( nAuxId, MCH_AUX) ; + m_pGeomDB->SetStatus( nAuxId, GDB_ST_OFF) ; + bChain = true ; + } + // altrimenti, se chiesto ricalcolo, lo svuoto + else if ( bRecalc) { + m_pGeomDB->EmptyGroup( nAuxId) ; + bChain = true ; + } + + // aggiorno dati geometrici dell'utensile + if ( ! UpdateToolData()) { + LOG_INFO( GetEMkLogger(), "Error in Milling : UpdateToolData failed") ; + return false ; + } + + // se necessario, eseguo concatenamento ed inserisco i percorsi sotto la geometria ausiliaria + if ( bChain && ! Chain( nAuxId)) + return false ; + + // recupero gruppo per geometria di lavorazione (Cutter Location) + int nClId = m_pGeomDB->GetFirstNameInGroup( m_nOwnerId, MCH_CL) ; + // se non c'è, lo aggiungo + if ( nClId == GDB_ID_NULL) { + nClId = m_pGeomDB->AddGroup( GDB_ID_NULL, m_nOwnerId, Frame3d()) ; + if ( nClId == GDB_ID_NULL) + return false ; + m_pGeomDB->SetName( nClId, MCH_CL) ; + } + // altrimenti lo svuoto + else + m_pGeomDB->EmptyGroup( nClId) ; + + // lavoro ogni singola catena + int nPathId = m_pGeomDB->GetFirstGroupInGroup( nAuxId) ; + while ( nPathId != GDB_ID_NULL) { + if ( ! ProcessPath( nPathId, GDB_ID_NULL, nClId)) + return false ; + nPathId = m_pGeomDB->GetNextGroup( nPathId) ; + } + + // se lavorazione vuota, esco + if ( m_nMills == 0) + return true ; + + // calcolo gli assi macchina + string sHint = ExtractHint( m_Params.m_sUserNotes) ; + if ( ! CalculateAxesValues( sHint)) + return false ; + + // gestione movimenti all'inizio di ogni singolo percorso di lavorazione e alla fine della lavorazione + if ( ! AdjustStartEndMovements()) + return false ; + + // esecuzione eventuali personalizzazioni + if ( ! PostApply()) + return false ; + + return true ; +} + +//---------------------------------------------------------------------------- +bool +Chiseling::GetParam( int nType, bool& bVal) const +{ + switch ( nType) { + case MPA_INVERT : + bVal = m_Params.m_bInvert ; + return true ; + } + bVal = false ; + return false ; +} + +//---------------------------------------------------------------------------- +bool +Chiseling::GetParam( int nType, int& nVal) const +{ + switch ( nType) { + case MPA_TYPE : + nVal = MT_CHISELING ; + return true ; + case MPA_WORKSIDE : + nVal = m_Params.m_nWorkSide ; + return true ; + case MPA_SCC : + nVal = m_Params.m_nSolCh ; + return true ; + } + nVal = 0 ; + return false ; +} + +//---------------------------------------------------------------------------- +bool +Chiseling::GetParam( int nType, double& dVal) const +{ + switch ( nType) { + case MPA_FEED : + dVal = GetFeed() ; + return true ; + case MPA_ENDFEED : + dVal = GetEndFeed() ; + return true ; + case MPA_TIPFEED : + dVal = GetTipFeed() ; + return true ; + case MPA_OFFSR : + dVal = GetOffsR() ; + return true ; + case MPA_OFFSL : + dVal = GetOffsL() ; + return true ; + case MPA_STARTPOS : + dVal = m_Params.m_dStartPos ; + return true ; + case MPA_STEP : + dVal = m_Params.m_dStep ; + return true ; + case MPA_ENDADDLEN : + dVal = m_Params.m_dEndAddLen ; + return true ; + } + dVal = 0 ; + return false ; +} + +//---------------------------------------------------------------------------- +bool +Chiseling::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 ; + } + sVal = "" ; + return false ; +} + +//---------------------------------------------------------------------------- +const ToolData& +Chiseling::GetToolData( void) const +{ + return m_TParams ; +} + +//---------------------------------------------------------------------------- +bool +Chiseling::UpdateToolData( void) +{ + // recupero il gestore DB utensili della macchina corrente + ToolsMgr* pTMgr = m_pMchMgr->GetCurrToolsMgr() ; + if ( pTMgr == nullptr) + return false ; + // recupero l'utensile nel DB utensili + const ToolData* pTdata = pTMgr->GetTool( m_Params.m_ToolUuid) ; + if ( pTdata == nullptr) + return false ; + // aggiorno i parametri + m_TParams = *pTdata ; + if ( ! EqualNoCase( m_Params.m_sToolName, m_TParams.m_sName)) { + string sLog = "Warning in Milling : tool name changed (" + + m_Params.m_sToolName + "->" + m_TParams.m_sName +")" ; + LOG_INFO( GetEMkLogger(), sLog.c_str()) ; + } + return true ; +} + +//---------------------------------------------------------------------------- +bool +Chiseling::GetGeometry( SELVECTOR& vIds) const +{ + // restituisco l'elenco delle entità + vIds = m_vId ; + return true ; +} + +//---------------------------------------------------------------------------- +bool +Chiseling::VerifyGeometry( SelData Id, int& nSubs, int& nType) +{ + // ammessi : tutte curve o tutte facce di trimesh + const IGeoObj* pGObj = m_pGeomDB->GetGeoObj( Id.nId) ; + if ( pGObj == nullptr) + return false ; + // se ammesse curve ed è tale + if ( nType != GEO_SURF && ( pGObj->GetType() & GEO_CURVE) != 0) { + const ICurve* pCurve = nullptr ; + // se direttamente la curva + if ( Id.nSub == SEL_SUB_ALL) { + pCurve = ::GetCurve( pGObj) ; + if ( pCurve != nullptr) { + if ( pCurve->GetType() == CRV_COMPO) + nSubs = ::GetCurveComposite( pCurve)->GetCurveCount() ; + else + nSubs = 0 ; + } + } + // altrimenti sottocurva di composita + else { + const ICurveComposite* pCompo = GetCurveComposite( pGObj) ; + if ( pCompo != nullptr) + pCurve = pCompo->GetCurve( Id.nSub) ; + nSubs = 0 ; + } + return ( pCurve != nullptr) ; + } + // se altrimenti ammesse superfici trimesh ed è tale + else if ( nType != GEO_CURVE && ( pGObj->GetType() & GEO_SURF) != 0) { + const ISurfTriMesh* pSurf = ::GetSurfTriMesh( pGObj) ; + if ( pSurf == nullptr) + return false ; + // se direttamente la superficie + if ( Id.nSub == SEL_SUB_ALL) { + nSubs = pSurf->GetFacetCount() ; + return true ; + } + // altrimenti faccia di superficie trimesh + else { + // se faccia non esistente + if ( Id.nSub > pSurf->GetFacetCount()) + return false ; + // tutto bene + nSubs = 0 ; + return true ; + } + } + // altrimenti errore + else + return false ; +} + +//---------------------------------------------------------------------------- +ICurve* +Chiseling::GetCurve( SelData Id) +{ + // ammessi : curve o facce di polymesh + const IGeoObj* pGObj = m_pGeomDB->GetGeoObj( Id.nId) ; + if ( pGObj == nullptr) + return nullptr ; + // ne recupero il riferimento globale + Frame3d frGlob ; + if ( ! m_pGeomDB->GetGlobFrame( Id.nId, frGlob)) + return nullptr ; + // se curva + if ( ( pGObj->GetType() & GEO_CURVE) != 0) { + PtrOwner pCurve ; + // se direttamente curva + if ( Id.nSub == SEL_SUB_ALL) { + // recupero e duplico la curva + const ICurve* pOriCurve = ::GetCurve( pGObj) ; + if ( pOriCurve != nullptr) + pCurve.Set( pOriCurve->Clone()) ; + // se estrusione mancante, imposto default + Vector3d vtExtr ; + if ( ! pCurve->GetExtrusion( vtExtr) || vtExtr.IsSmall()) + pCurve->SetExtrusion( Z_AX) ; + } + // altrimenti sottocurva di composita + else { + // recupero la composita + const ICurveComposite* pCompo = GetCurveComposite( pGObj) ; + if ( pCompo != nullptr) { + // 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) || vtExtr.IsSmall()) + vtExtr = Z_AX ; + pCurve->SetExtrusion( vtExtr) ; + double dThick ; + if ( pCompo->GetThickness( dThick)) + pCurve->SetThickness( dThick) ; + } + } + } + if ( IsNull( pCurve)) + return nullptr ; + // la porto in globale + pCurve->ToGlob( frGlob) ; + // la restituisco + return Release( pCurve) ; + } + // se altrimenti superficie + else if ( ( pGObj->GetType() & GEO_SURF) != 0) { + // recupero la trimesh + const ISurfTriMesh* pSurf = ::GetSurfTriMesh( pGObj) ; + if ( pSurf == nullptr) + return nullptr ; + // recupero l'indice della faccia + int nFacet = ( ( Id.nSub == SEL_SUB_ALL) ? 0 : Id.nSub) ; + // recupero i contorni della faccia + POLYLINEVECTOR vPL ; + pSurf->GetFacetLoops( nFacet, vPL) ; + if ( vPL.empty()) + return nullptr ; + // recupero la normale esterna della faccia + Vector3d vtN ; + if ( ! pSurf->GetFacetNormal( nFacet, vtN)) + return nullptr ; + // creo la curva a partire da quello esterno + PtrOwner pCrvCompo( CreateCurveComposite()) ; + pCrvCompo->FromPolyLine( vPL[0]) ; + if ( ! pCrvCompo->IsValid()) + return nullptr ; + // assegno l'estrusione dalla normale alla faccia + pCrvCompo->SetExtrusion( vtN) ; + // la porto in globale + pCrvCompo->ToGlob( frGlob) ; + // sistemazioni varie + AdjustCurveFromSurf( pCrvCompo) ; + // la restituisco + return Release( pCrvCompo) ; + } + // altrimenti errore + else + return nullptr ; +} + +//---------------------------------------------------------------------------- +bool +Chiseling::AdjustCurveFromSurf( ICurveComposite* pCrvCompo) +{ + // prendo il contorno + if ( ( m_TParams.m_nType & TF_SAWBLADE) == 0) { + // cerco l'estremo più alto e lo imposto come inizio + double dU = 0 ; + double dUmax = 0 ; + double dZmax = - INFINITO ; + Point3d ptP ; + while ( pCrvCompo->GetPointD1D2( dU, ICurve::FROM_MINUS, ptP)) { + if ( ptP.z > dZmax + EPS_SMALL) { + dZmax = ptP.z ; + dUmax = dU ; + } + dU += 1 ; + } + if ( dU != 0) + pCrvCompo->ChangeStartPoint( dUmax) ; + } + return true ; +} + +//---------------------------------------------------------------------------- +bool +Chiseling::Chain( int nGrpDestId) +{ + // vettore puntatori alle curve + typedef PtrOwner POWNCURVE ; + typedef std::vector POCRVVECTOR ; + POCRVVECTOR 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 sOut = "Entity " + ToString( Id) + " skipped by Milling" ; + LOG_INFO( GetEMkLogger(), sOut.c_str()) ; + 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 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) && fabs( dTemp) > fabs( 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 ; +} + +//---------------------------------------------------------------------------- +bool +Chiseling::AdjustEndPointForAxesCalc( const CamData* pCamData, Point3d& ptP) const +{ + // non devo fare alcunché + return true ; +} + +//---------------------------------------------------------------------------- +bool +Chiseling::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) ; + + // copio la curva composita da elaborare + int nCrvId = m_pGeomDB->GetFirstInGroup( nPathId) ; + if ( m_pGeomDB->GetGeoType( nCrvId) != CRV_COMPO) + return false ; + int nCopyId = m_pGeomDB->CopyGlob( nCrvId, GDB_ID_NULL, nTempId) ; + if ( nCopyId == GDB_ID_NULL) + return false ; + ICurveComposite* pCompo = GetCurveComposite( m_pGeomDB->GetGeoObj( nCopyId)) ; + + // eventuale inversione percorso + if ( m_Params.m_bInvert) + pCompo->Invert() ; + + // recupero estrusione e spessore + Vector3d vtExtr ; + pCompo->GetExtrusion( vtExtr) ; + double dThick ; + pCompo->GetThickness( dThick) ; + + // se utensile non centrato, eseguo correzione raggio utensile ed eventuale offset + double dOffs = 0.5 * m_TParams.m_dDiam + GetOffsR() ; + if ( m_Params.m_nWorkSide != MILL_WS_CENTER && abs( dOffs) > EPS_SMALL) { + // valore offset + double dSignOffs = ( m_Params.m_nWorkSide == MILL_WS_RIGHT) ? dOffs : - dOffs ; + // flag offset + int nFlag = ICurve::OFF_EXTEND ; + // se percorso chiuso senza overlap ed inizio/fine è un angolo esterno + if ( pCompo->IsClosed()) { + Vector3d vtStart, vtEnd ; + if ( pCompo->GetStartDir( vtStart) && pCompo->GetEndDir( vtEnd) && + ( vtEnd ^ vtStart) * vtExtr * dSignOffs > 0) + nFlag += ICurve::OFF_FORCE_OPEN ; + } + // esecuzione offset + if ( ! pCompo->SimpleOffset( dSignOffs, nFlag)) { + // se curva piatta, provo con offset avanzato + bool bOk = false ; + Plane3d plPlane ; + if ( pCompo->IsFlat( plPlane, 100 * EPS_SMALL) && + AreSameOrOppositeVectorApprox( vtExtr, plPlane.vtN)) { + OffsetCurve OffsCrv ; + if ( OffsCrv.Make( pCompo, dSignOffs, nFlag)) { + ICurve* pOffs = OffsCrv.GetLongerCurve() ; + if ( pOffs != nullptr) { + pCompo->Clear() ; + pCompo->AddCurve( pOffs) ; + bOk = true ; + } + } + } + if ( ! bOk) { + LOG_INFO( GetEMkLogger(), "Error in Milling : Offset not computable") ; + return false ; + } + } + } + + // unisco le parti allineate (tranne inizio-fine se chiusa) + if ( ! pCompo->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL, false)) + return false ; + + // recupero il punto di inizio (per poi salvarlo nelle info di CL path) + Point3d ptStart ; + pCompo->GetStartPoint( ptStart) ; + + // recupero il box del grezzo in globale + BBox3d b3Raw ; + if ( ! GetRawGlobBox( m_nPhase, nPathId, 0.5 * m_TParams.m_dDiam, b3Raw) || b3Raw.IsEmpty()) { + LOG_INFO( GetEMkLogger(), "Error in Milling : Empty RawBox") ; + return false ; + } + + // recupero distanza da fondo dei grezzi interessati dal percorso + double dRbDist = 0 ; + if ( AreSameVectorApprox( vtExtr, Z_AX)) { + if ( ! GetDistanceFromRawBottom( m_nPhase, nCopyId, m_TParams.m_dDiam, dRbDist)) + return false ; + } + + // 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)) { + LOG_INFO( GetEMkLogger(), "Error in Milling : Depth not computable") ; + return false ; + } + // se spessore positivo, lo sottraggo dal risultato + if ( dThick > 0) + dDepth -= dThick ; + // sottraggo eventuale offset longitudinale + dDepth -= GetOffsL() ; + + // recupero nome del path + string sPathName ; + m_pGeomDB->GetName( nPathId, sPathName) ; + + // eventuale approssimazione con segmenti di retta + int nSplitArcs = m_pMchMgr->GetCurrMachiningsMgr()->GetSplitArcs() ; + bool bSplitArcs = ( nSplitArcs == SPLAR_ALWAYS || + ( nSplitArcs == SPLAR_NO_XY_PLANE && ! vtExtr.IsZplus()) || + ( nSplitArcs == SPLAR_GEN_PLANE && vtExtr.IsGeneric())) ; + if ( bSplitArcs) { + const double ANG_TOL_MAX_DEG = 90 ; + PolyLine PL ; + if ( pCompo->ApproxWithLines( 50 * EPS_SMALL, ANG_TOL_MAX_DEG, ICurve::APL_SPECIAL, PL)) { + // sostituisco le linee alle curve originali + pCompo->Clear() ; + pCompo->FromPolyLine( PL) ; + // riassegno estrusione e spessore + pCompo->SetExtrusion( vtExtr) ; + pCompo->SetThickness( dThick) ; + } + } + + // 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 ; ++ i) { + // 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) ; + ++ i ; + ++ nMaxInd ; + } + } + + // calcolo il versore fresa + Vector3d vtTool = Z_AX ; + if ( ! vtExtr.IsSmall()) + vtTool = vtExtr ; + + // calcolo l'elevazione massima + double dElev ; + if ( CalcPathElevation( pCompo, vtTool, dDepth, 0.5 * m_TParams.m_dDiam, dElev)) { + if ( dElev < EPS_SMALL && AreSameVectorApprox( vtExtr, Z_AX)) { + BBox3d b3Crv ; + pCompo->GetLocalBBox( b3Crv) ; + dElev = max( 0., b3Raw.GetMax().z - b3Crv.GetMin().z + dDepth) ; + } + } + else + return false ; + + // per frese normali, verifico di non superare il massimo materiale + if ( ( m_TParams.m_nType & TF_SAWBLADE) == 0) { + const double MAXMAT_TOL = EPS_SMALL ; + if ( ( m_Params.m_dStep < EPS_SMALL && dElev > m_TParams.m_dMaxMat + MAXMAT_TOL) || + ( m_Params.m_dStep > EPS_SMALL && m_Params.m_dStep > m_TParams.m_dMaxMat + EPS_SMALL)) { + if ( dDepth + max( dThick, 0.0) > m_TParams.m_dMaxMat) { + dDepth = m_TParams.m_dMaxMat - max( dThick, 0.0) ; + string sInfo = "Warning in Milling : machining depth (" + ToString( dElev, 1) + + ") bigger than MaxMaterial (" + ToString( m_TParams.m_dMaxMat, 1) + ")" ; + LOG_INFO( GetEMkLogger(), sInfo.c_str()) ; + } + else { + string sInfo = "Error in Milling : machining depth (" + ToString( dElev, 1) + + ") bigger than MaxMaterial (" + ToString( m_TParams.m_dMaxMat, 1) + ")" ; + LOG_INFO( GetEMkLogger(), sInfo.c_str()) ; + return false ; + } + } + } + + // verifiche per fresatura dal basso + m_bAggrBottom = false ; + if ( ! VerifyPathFromBottom( pCompo, vtTool)) { + return false ; + } + + // se richiesta anteprima + if ( nPvId != GDB_ID_NULL) { + // creo gruppo per geometria di lavorazione del percorso + int nPxId = m_pGeomDB->AddGroup( GDB_ID_NULL, nPvId, Frame3d()) ; + if ( nPxId == GDB_ID_NULL) + return false ; + m_pGeomDB->SetName( nPxId, sPathName) ; + m_pGeomDB->SetMaterial( nPxId, GREEN) ; + // creo l'anteprima del percorso + if ( ! GenerateMillingPv( nPxId, pCompo)) + return false ; + } + + // se richiesta lavorazione + if ( nClId != GDB_ID_NULL) { + // creo gruppo per geometria di lavorazione del percorso + int nPxId = m_pGeomDB->AddGroup( GDB_ID_NULL, nClId, Frame3d()) ; + if ( nPxId == GDB_ID_NULL) + return false ; + m_pGeomDB->SetName( nPxId, sPathName) ; + m_pGeomDB->SetMaterial( nPxId, BLUE) ; + + // assegno il vettore estrazione al gruppo del percorso + m_pGeomDB->SetInfo( nPxId, KEY_EXTR, vtTool) ; + // assegno il punto di inizio al gruppo del percorso + m_pGeomDB->SetInfo( nPxId, KEY_START, ptStart) ; + + // Imposto dati comuni + SetPathId( nPxId) ; + SetToolDir( vtTool) ; + + // Una sola passata + if ( ! AddStandardMilling( pCompo, vtTool, vtExtr, dDepth, dElev, bSplitArcs)) + return false ; + + // assegno al gruppo l'ingombro del percorso di lavoro + BBox3d b3Grp ; + m_pGeomDB->GetGlobalBBox( nPxId, b3Grp) ; + m_pGeomDB->SetInfo( nPxId, KEY_PMIN, b3Grp.GetMin()) ; + m_pGeomDB->SetInfo( nPxId, KEY_PMAX, b3Grp.GetMax()) ; + } + + // incremento numero di fresate + ++ m_nMills ; + + return true ; +} + +//---------------------------------------------------------------------------- +bool +Chiseling::CalcPathElevation( const ICurveComposite* pCompo, const Vector3d& vtTool, double dDepth, double dRad, + double& dElev) +{ + dElev = 0 ; + int nMaxInd = pCompo->GetCurveCount() - 1 ; + for ( int i = 0 ; i <= nMaxInd ; ++ i) { + // curva corrente + const ICurve* pCrvC = pCompo->GetCurve( i) ; + // calcolo elevazione + double dCurrElev ; + Point3d ptStart, ptMid, ptEnd ; + pCrvC->GetStartPoint( ptStart) ; + pCrvC->GetMidPoint( ptMid) ; + pCrvC->GetEndPoint( ptEnd) ; + Vector3d vtStartPerp, vtMidPerp, vtEndPerp, vtTg ; + pCrvC->GetStartDir( vtTg) ; + vtStartPerp = vtTg ^ vtTool ; + vtStartPerp.Normalize() ; + vtStartPerp *= dRad ; + pCrvC->GetMidDir( vtTg) ; + vtMidPerp = vtTg ^ vtTool ; + vtMidPerp.Normalize() ; + vtMidPerp *= dRad ; + pCrvC->GetEndDir( vtTg) ; + vtEndPerp = vtTg ^ vtTool ; + vtEndPerp.Normalize() ; + vtEndPerp *= dRad ; + Vector3d vtDepth = vtTool * dDepth ; + // linea centro utensile + if ( GetElevation( m_nPhase, ptStart - vtDepth, ptMid - vtDepth, ptEnd - vtDepth, vtTool, dCurrElev)) { + if ( dCurrElev > dElev) + dElev = dCurrElev ; + } + else { + LOG_INFO( GetEMkLogger(), "Error in Milling : Entity GetElevation") ; + return false ; + } + // da una parte + if ( GetElevation( m_nPhase, ptStart + vtStartPerp - vtDepth, ptMid + vtMidPerp - vtDepth, + ptEnd + vtEndPerp - vtDepth, vtTool, dCurrElev)) { + if ( dCurrElev > dElev) + dElev = dCurrElev ; + } + else { + LOG_INFO( GetEMkLogger(), "Error in Milling : Entity GetElevation") ; + return false ; + } + // dall'altra parte + if ( GetElevation( m_nPhase, ptStart - vtStartPerp - vtDepth, ptMid - vtMidPerp - vtDepth, + ptEnd - vtEndPerp - vtDepth, vtTool, dCurrElev)) { + if ( dCurrElev > dElev) + dElev = dCurrElev ; + } + else { + LOG_INFO( GetEMkLogger(), "Error in Milling : Entity GetElevation") ; + return false ; + } + } + return true ; +} + +//---------------------------------------------------------------------------- +bool +Chiseling::VerifyPathFromBottom( const ICurveComposite* pCompo, const Vector3d& vtTool) +{ + // se non è fresatura dal basso in alto, esco + if ( vtTool.z > - 0.5) + return true ; + // se c'è tavola basculante, esco + bool bTabTilting = false ; + if ( m_pMchMgr->GetCurrMachine()->GetCurrTableIsTilting( bTabTilting) && bTabTilting) + return true ; + // verifico se c'è rinvio da sotto + int nHeadId = m_pMchMgr->GetHeadId( m_TParams.m_sHead) ; + int nAgbType ; + if ( ! m_pGeomDB->GetInfo( nHeadId, "AGB_TYPE", nAgbType) || nAgbType == 0) { + string sOut = "Milling error : missing aggregate from bottom" ; + LOG_INFO( GetEMkLogger(), sOut.c_str()) ; + return false ; + } + // recupero la massima distanza consentita dal rinvio + double dAgbDmax = 0 ; + m_pGeomDB->GetInfo( nHeadId, "AGB_DMAX", dAgbDmax) ; + // calcolo la massima distanza minima del percorso dal contorno del grezzo + double dDist = 0 ; + Vector3d vtDir ; + int nMaxInd = pCompo->GetCurveCount() - 1 ; + for ( int i = 0 ; i <= nMaxInd ; ++ i) { + // curva corrente + const ICurve* pCrvC = pCompo->GetCurve( i) ; + // considero inizio della prima curva, punto medio e fine di tutte + Point3d ptP ; + double dCurrDist = 0 ; + Vector3d vtCurrDir ; + if ( i == 0) { + pCrvC->GetStartPoint( ptP) ; + GetMinDistanceFromRawSide( m_nPhase, ptP, dCurrDist, vtCurrDir) ; + if ( dCurrDist > dDist) { + dDist = dCurrDist ; + vtDir = vtCurrDir ; + } + } + pCrvC->GetMidPoint( ptP) ; + GetMinDistanceFromRawSide( m_nPhase, ptP, dCurrDist, vtCurrDir) ; + if ( dCurrDist > dDist) { + dDist = dCurrDist ; + vtDir = vtCurrDir ; + } + pCrvC->GetEndPoint( ptP) ; + GetMinDistanceFromRawSide( m_nPhase, ptP, dCurrDist, vtCurrDir) ; + if ( dCurrDist > dDist) { + dDist = dCurrDist ; + vtDir = vtCurrDir ; + } + } + // se supera il limite, errore + if ( dDist > dAgbDmax) { + string sOut = "Milling error : path too far from part sides" ; + LOG_INFO( GetEMkLogger(), sOut.c_str()) ; + return false ; + } + // assegno direzione di accesso e segnalo utilizzo aggregato da sotto + SetAuxDir( vtDir) ; + m_bAggrBottom = true ; + return true ; +} + +//---------------------------------------------------------------------------- +bool +Chiseling::GenerateMillingPv( int nPathId, const ICurveComposite* pCompo) +{ + // creo copia della curva composita + PtrOwner< ICurve> pCrv( pCompo->Clone()) ; + if ( IsNull( pCrv)) + return false ; + // calcolo la regione + PtrOwner pSfr ; + pSfr.Set( GetSurfFlatRegionFromFatCurve( Release( pCrv), 0.5 * m_TParams.m_dDiam, false, false)) ; + if ( IsNull( pSfr)) + return false ; + // ne recupero il contorno + PtrOwner< ICurve> pCrv2 ; + pCrv2.Set( pSfr->GetLoop( 0, 0)) ; + if ( IsNull( pCrv2)) + return false ; + // inserisco la curva nel DB + int nC2Id = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nPathId, Release( pCrv2)) ; + if ( nC2Id == GDB_ID_NULL) + return false ; + // assegno nome e colore + m_pGeomDB->SetName( nC2Id, MCH_PV_CUT) ; + m_pGeomDB->SetMaterial( nC2Id, LIME) ; + // eventuali altri contorni ( interni di contornatura chiusa) + const int MAX_INT_LOOP = 1000 ; + for ( int i = 1 ; i <= MAX_INT_LOOP ; ++i) { + PtrOwner< ICurve> pCrv3 ; + pCrv3.Set( pSfr->GetLoop( 0, i)) ; + if ( IsNull( pCrv3)) + break ; + // inserisco la curva nel DB + int nC3Id = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nPathId, Release( pCrv3)) ; + if ( nC3Id == GDB_ID_NULL) + return false ; + // assegno nome e colore + m_pGeomDB->SetName( nC3Id, MCH_PV_CUT) ; + m_pGeomDB->SetMaterial( nC3Id, LIME) ; + } + // inserisco la regione nel DB + int nRId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nPathId, Release( pSfr)) ; + if ( nRId == GDB_ID_NULL) + return false ; + m_pGeomDB->SetName( nRId, MCH_PV_RCUT) ; + m_pGeomDB->SetMaterial( nRId, INVISIBLE) ; + // la copio anche come regione ridotta + int nRrId = m_pGeomDB->Copy( nRId, GDB_ID_NULL, nPathId) ; + if ( nRrId == GDB_ID_NULL) + return false ; + m_pGeomDB->SetName( nRrId, MCH_PV_RRCUT) ; + m_pGeomDB->SetMaterial( nRrId, INVISIBLE) ; + return true ; +} + +//---------------------------------------------------------------------------- +bool +Chiseling::AddStandardMilling( const ICurveComposite* pCompo, const Vector3d& vtTool, const Vector3d& vtExtr, + double dDepth, double dElev, bool bSplitArcs) +{ + // recupero distanza di sicurezza + double dSafeZ = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeZ() ; + // lunghezza di approccio/retrazione + double dAppr = m_Params.m_dStartPos ; + + // ciclo sulle curve elementari + bool bClosed = pCompo->IsClosed() ; + int nMaxInd = pCompo->GetCurveCount() - 1 ; + for ( int i = 0 ; i <= nMaxInd ; ++ i) { + // curva corrente + const ICurve* pCrvC = pCompo->GetCurve( i) ; + // copio la curva + PtrOwner pCurve( ::GetCurve( pCrvC->Clone())) ; + if ( IsNull( pCurve)) + return false ; + // aggiungo affondamento + pCurve->Translate( - vtTool * dDepth) ; + // se prima entità, approccio e affondo + if ( i == 0) { + // dati inizio entità + Point3d ptStart ; + pCurve->GetStartPoint( ptStart) ; + Vector3d vtStart ; + pCurve->GetStartDir( vtStart) ; + // determino inizio attacco + Point3d ptP1 ; + // aggiungo approccio per frese normali con spazio sopra attacco + if ( ( m_TParams.m_nType & TF_SAWBLADE) == 0) { + // determino elevazione su inizio attacco + double dStElev ; + if ( ! GetElevation( m_nPhase, ptStart - 10 * EPS_SMALL * vtTool, vtTool, GetRadiusForStartEndElevation(), dStElev)) + dStElev = dElev ; + dStElev -= ( ptP1 - ptStart) * vtExtr ; + // approccio al punto iniziale + if ( ! AddApproach( ptP1, vtTool, dSafeZ, dStElev, dAppr)) + return false ; + } + // altrimenti, approccio per lame o diretto + else { + // affondo al punto iniziale + SetFlag( 0) ; + if ( AddRapidStart( ptP1) == GDB_ID_NULL) + return false ; + } + // aggiungo attacco + } + // elaborazioni sulla curva corrente + if ( pCurve->GetType() == CRV_LINE) { + ICurveLine* pLine = GetCurveLine( pCurve) ; + Point3d ptP3 = pLine->GetEnd() ; + SetFeed( GetFeed()) ; + if ( AddLinearMove( ptP3) == GDB_ID_NULL) + return false ; + } + else if ( pCurve->GetType() == CRV_ARC) { + ICurveArc* pArc = GetCurveArc( pCurve) ; + Point3d ptCen = pArc->GetCenter() ; + double dAngCen = pArc->GetAngCenter() ; + Vector3d vtN = pArc->GetNormVersor() ; + Point3d ptP3 ; + pArc->GetEndPoint( ptP3) ; + SetFeed( GetFeed()) ; + if ( AddArcMove( ptP3, ptCen, dAngCen, vtN) == GDB_ID_NULL) + return false ; + } + // se ultima entità, uscita e retrazione + if ( i == nMaxInd) { + // dati fine entità + Point3d ptEnd ; + pCurve->GetEndPoint( ptEnd) ; + Vector3d vtEnd ; + pCurve->GetEndDir( vtEnd) ; + // aggiungo uscita + Point3d ptP1 ; + // aggiungo retrazione per frese normali + if ( ( m_TParams.m_nType & TF_SAWBLADE) == 0) { + double dEndElev ; + if ( ! GetElevation( m_nPhase, ptEnd - 10 * EPS_SMALL * vtTool, vtTool, GetRadiusForStartEndElevation(), dEndElev)) + dEndElev = dElev ; + dEndElev -= ( ptP1 - ptEnd) * vtExtr ; + // aggiungo retrazione + if ( ! AddRetract( ptP1, vtTool, dSafeZ, dEndElev, dAppr)) + return false ; + } + // per lame non è necessario + } + } + return true ; +} + +//---------------------------------------------------------------------------- +bool +Chiseling::AddApproach( const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dElev, double dAppr) +{ + SetFlag( 1) ; + // se con aggregato da sotto + if ( m_bAggrBottom) { + // ne recupero alcuni dati + double dAgbEncH = 0 ; + double dAgbEncV = 0 ; + m_pGeomDB->GetInfo( m_pMchMgr->GetHeadId( m_TParams.m_sHead), "AGB_ENCH", dAgbEncH) ; + m_pGeomDB->GetInfo( m_pMchMgr->GetHeadId( m_TParams.m_sHead), "AGB_ENCV", dAgbEncV) ; + // aggiuntivo in Z + double dAggZ = max( dElev + max( dSafeZ, dAppr), 0.) ; + // distanza dal bordo del pezzo + double dDistBottom ; + if ( ! GetDistanceFromRawSide( m_nPhase, ptP, m_vtAux, dDistBottom)) + dDistBottom = 0 ; + // pre-approccio + Point3d ptP0 = ptP - Z_AX * dAggZ + m_vtAux * ( dDistBottom + dAgbEncH + dAppr) ; + Point3d ptP00 = ptP0 + Z_AX * ( dAgbEncV + m_TParams.m_dLen + dAggZ) ; + Vector3d vtAux = m_vtAux ; + vtAux.Rotate( Z_AX, 90) ; + SetAuxDir( vtAux) ; + if ( AddRapidStart( ptP00, MCH_CL_AGB_DWN) == GDB_ID_NULL) + return false ; + vtAux.Rotate( Z_AX, - 90) ; + SetAuxDir( vtAux) ; + SetFlag( 0) ; + if ( AddRapidMove( ptP0, MCH_CL_AGB_IN) == GDB_ID_NULL) + return false ; + } + // se sopra attacco c'è spazio per sicurezza o approccio + if ( dElev + max( dSafeZ, dAppr) > 10 * EPS_SMALL) { + // se distanza di sicurezza minore di distanza di inizio + if ( dSafeZ < dAppr + 10 * EPS_SMALL) { + // 1 -> punto sopra inizio + Point3d ptP1 = ptP + vtTool * ( dElev + dAppr) ; + if ( ( ! m_bAggrBottom && AddRapidStart( ptP1) == GDB_ID_NULL) || + ( m_bAggrBottom && AddRapidMove( ptP1) == GDB_ID_NULL)) + return false ; + } + else { + // 1a -> punto sopra inizio + Point3d ptP1b = ptP + vtTool * ( dElev + dAppr) ; + Point3d ptP1a = ptP1b + vtTool * ( dSafeZ - dAppr) ; + if ( ( ! m_bAggrBottom && AddRapidStart( ptP1a) == GDB_ID_NULL) || + ( m_bAggrBottom && AddRapidMove( ptP1a) == GDB_ID_NULL)) + // 1b -> punto appena sopra inizio + if ( ( dElev + dAppr) > EPS_SMALL) { + SetFlag( 0) ; + if ( AddRapidMove( ptP1b) == GDB_ID_NULL) + return false ; + } + } + // affondo al punto iniziale + SetFlag( 0) ; + SetFeed( GetTipFeed()) ; + if ( AddLinearMove( ptP) == GDB_ID_NULL) + return false ; + } + else { + // affondo diretto al punto iniziale + SetFlag( 0) ; + if ( ( ! m_bAggrBottom && AddRapidStart( ptP) == GDB_ID_NULL) || + ( m_bAggrBottom && AddRapidMove( ptP) == GDB_ID_NULL)) + return false ; + } + return true ; +} + +//---------------------------------------------------------------------------- +bool +Chiseling::AddRetract( const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dElev, double dAppr) +{ + // se sopra uscita c'è spazio per sicurezza o approccio + if ( dElev + max( dSafeZ, dAppr) > 10 * EPS_SMALL) { + if ( dSafeZ < dAppr + 10 * EPS_SMALL) { + // 4 -> movimento di risalita sopra il punto finale + SetFeed( GetEndFeed()) ; + Point3d ptP4 = ptP + vtTool * ( dElev + dAppr) ; + if ( AddLinearMove( ptP4) == GDB_ID_NULL) + return false ; + } + else { + // 4a -> movimento di risalita appena sopra il punto finale + Point3d ptP4a = ptP + vtTool * ( dElev + dAppr) ; + if ( dElev + dAppr > EPS_SMALL) { + SetFeed( GetEndFeed()) ; + if ( AddLinearMove( ptP4a) == GDB_ID_NULL) + return false ; + } + // 4b -> movimento di risalita sopra il punto finale + Point3d ptP4b = ptP4a + vtTool * ( dSafeZ - dAppr) ; + if ( AddRapidMove( ptP4b) == GDB_ID_NULL) + return false ; + } + } + // se con aggregato da sotto + if ( m_bAggrBottom) { + // ne recupero alcuni dati + double dAgbEncH = 0 ; + double dAgbEncV = 0 ; + m_pGeomDB->GetInfo( m_pMchMgr->GetHeadId( m_TParams.m_sHead), "AGB_ENCH", dAgbEncH) ; + m_pGeomDB->GetInfo( m_pMchMgr->GetHeadId( m_TParams.m_sHead), "AGB_ENCV", dAgbEncV) ; + // aggiuntivo in Z + double dAggZ = max( dElev + max( dSafeZ, dAppr), 0.) ; + // distanza dal bordo del pezzo + double dDistBottom ; + if ( ! GetDistanceFromRawSide( m_nPhase, ptP, m_vtAux, dDistBottom)) + dDistBottom = 0 ; + // post-retract + Point3d ptP0 = ptP - Z_AX * dAggZ + m_vtAux * ( dDistBottom + dAgbEncH + dAppr) ; + Point3d ptP00 = ptP0 + Z_AX * ( dAgbEncV + m_TParams.m_dLen + dAggZ) ; + if ( AddRapidMove( ptP0, MCH_CL_AGB_OUT) == GDB_ID_NULL) + return false ; + Vector3d vtAux = m_vtAux ; + vtAux.Rotate( Z_AX, 90) ; + SetAuxDir( vtAux) ; + if ( AddRapidMove( ptP00, MCH_CL_AGB_UP) == GDB_ID_NULL) + return false ; + } + return true ; +} + +//---------------------------------------------------------------------------- +double +Chiseling::GetRadiusForStartEndElevation( void) +{ + const double DELTA_ELEV_RAD = 20.0 ; + return ( 0.5 * m_TParams.m_dTDiam + DELTA_ELEV_RAD) ; +} diff --git a/EgtMachKernel.vcxproj b/EgtMachKernel.vcxproj index 8169c16..2e4c38e 100644 --- a/EgtMachKernel.vcxproj +++ b/EgtMachKernel.vcxproj @@ -211,6 +211,7 @@ copy $(TargetPath) \EgtProg\Dll64 + false false @@ -251,6 +252,7 @@ copy $(TargetPath) \EgtProg\Dll64 + @@ -279,6 +281,7 @@ copy $(TargetPath) \EgtProg\Dll64 + @@ -303,6 +306,7 @@ copy $(TargetPath) \EgtProg\Dll64 + diff --git a/EgtMachKernel.vcxproj.filters b/EgtMachKernel.vcxproj.filters index 4d65e60..8a26ab0 100644 --- a/EgtMachKernel.vcxproj.filters +++ b/EgtMachKernel.vcxproj.filters @@ -195,6 +195,12 @@ Source Files\Machinings + + Source Files\Operations + + + Source Files\Operations + @@ -338,6 +344,12 @@ Header Files + + Header Files + + + Header Files + diff --git a/MachMgrOperations.cpp b/MachMgrOperations.cpp index 3d1f745..46c339c 100644 --- a/MachMgrOperations.cpp +++ b/MachMgrOperations.cpp @@ -171,12 +171,18 @@ MachMgr::GetOperationType( int nId) const return OPER_SAWING ; else if ( sUserObj == USEROBJ_GETNAME( Milling)) return OPER_MILLING ; + else if ( sUserObj == USEROBJ_GETNAME( Pocketing)) + return OPER_POCKETING ; + //else if ( sUserObj == USEROBJ_GETNAME( Mortising)) + // return OPER_MORTISING ; else if ( sUserObj == USEROBJ_GETNAME( SawRoughing)) return OPER_SAWROUGHING ; else if ( sUserObj == USEROBJ_GETNAME( SawFinishing)) return OPER_SAWFINISHING ; else if ( sUserObj == USEROBJ_GETNAME( GenMachining)) return OPER_GENMACHINING ; + else if ( sUserObj == USEROBJ_GETNAME( Chiseling)) + return OPER_CHISELING ; else return OPER_NULL ; } diff --git a/MachiningCreate.h b/MachiningCreate.h index e096637..8c69d43 100644 --- a/MachiningCreate.h +++ b/MachiningCreate.h @@ -16,9 +16,11 @@ #include "Drilling.h" #include "Sawing.h" #include "Milling.h" +#include "Pocketing.h" #include "SawRoughing.h" #include "SawFinishing.h" #include "GenMachining.h" +#include "Chiseling.h" //---------------------------------------------------------------------------- // Dal tipo numerico crea una istanza della classe @@ -29,9 +31,12 @@ CreateMachining( int nMchType) case MT_DRILLING : return new( std::nothrow) Drilling ; case MT_SAWING : return new( std::nothrow) Sawing ; case MT_MILLING : return new( std::nothrow) Milling ; + case MT_POCKETING : return new( std::nothrow) Pocketing ; + // case MT_MORTISING : return new( std::nothrow) Mortising ; case MT_SAWROUGHING : return new( std::nothrow) SawRoughing ; case MT_SAWFINISHING : return new( std::nothrow) SawFinishing ; case MT_GENMACHINING : return new( std::nothrow) GenMachining ; + case MT_CHISELING : return new( std::nothrow) Chiseling ; } return nullptr ; } diff --git a/Pocketing.cpp b/Pocketing.cpp new file mode 100644 index 0000000..2cfe14b --- /dev/null +++ b/Pocketing.cpp @@ -0,0 +1,1816 @@ +//---------------------------------------------------------------------------- +// EgalTech 2017-2017 +//---------------------------------------------------------------------------- +// File : Pocketing.cpp Data : 04.02.17 Versione : 1.8b1 +// Contenuto : Implementazione gestione svuotature. +// +// +// +// Modifiche : 04.02.17 DS Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +//--------------------------- Include ---------------------------------------- +#include "stdafx.h" +#include "MachMgr.h" +#include "DllMain.h" +#include "Pocketing.h" +#include "MachiningConst.h" +#include "/EgtDev/Include/EGkCurveLine.h" +#include "/EgtDev/Include/EGkCurveArc.h" +#include "/EgtDev/Include/EGkCurveComposite.h" +#include "/EgtDev/Include/EGkArcSpecial.h" +#include "/EgtDev/Include/EGkChainCurves.h" +#include "/EgtDev/Include/EGkOffsetCurve.h" +#include "/EgtDev/Include/EGkSfrCreate.h" +#include "/EgtDev/Include/EGkSurfTriMesh.h" +#include "/EgtDev/Include/EGkUserObjFactory.h" +#include "/EgtDev/Include/EGnStringKeyVal.h" +#include "/EgtDev/Include/EgtPointerOwner.h" + +using namespace std ; + +//---------------------------------------------------------------------------- +USEROBJ_REGISTER( "EMkPocketing", Pocketing) ; + +//---------------------------------------------------------------------------- +const string& +Pocketing::GetClassName( void) const +{ + return USEROBJ_GETNAME( Pocketing) ; +} + +//---------------------------------------------------------------------------- +Pocketing* +Pocketing::Clone( void) const +{ + // alloco oggetto + Pocketing* pPock = new(nothrow) Pocketing ; + // eseguo copia dei dati + if ( pPock != nullptr) { + try { + pPock->m_Params = m_Params ; + pPock->m_TParams = m_TParams ; + } + catch( ...) { + delete pPock ; + return nullptr ; + } + } + // ritorno l'oggetto + return pPock ; +} + +//---------------------------------------------------------------------------- +bool +Pocketing::Dump( string& sOut, bool bMM, const char* szNewLine) const +{ + sOut += GetClassName() + "[mm]" + szNewLine ; + sOut += KEY_PHASE + EQUAL + ToString( m_nPhase) + szNewLine ; + sOut += KEY_IDS + EQUAL + ToString( m_vId) + szNewLine ; + for ( int i = 0 ; i < m_Params.GetSize() ; ++ i) + sOut += m_Params.ToString( i) + szNewLine ; + for ( int i = 0 ; i < m_TParams.GetSize() ; ++ i) + sOut += m_TParams.ToString( i) + szNewLine ; + sOut += KEY_NUM + EQUAL + ToString( m_nMills) + szNewLine ; + + return true ; +} + +//---------------------------------------------------------------------------- +bool +Pocketing::Save( STRVECTOR& vString) const +{ + try { + int nSize = 1 + m_Params.GetSize() + m_TParams.GetSize() + 2 ; + 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_nMills, vString[++k])) + return false ; + } + catch( ...) { + return false ; + } + return true ; +} + +//---------------------------------------------------------------------------- +bool +Pocketing::Load( const STRVECTOR& vString, int nBaseGdbId) +{ + int nSize = int( vString.size()) ; + // lista identificativi geometrie da lavorare + int k = - 1 ; + if ( k >= nSize - 1 || ! GetVal( vString[++k], KEY_IDS, m_vId)) + return false ; + for ( auto& Sel : m_vId) + Sel.nId += nBaseGdbId ; + // parametri lavorazione + for ( int i = 0 ; i < m_Params.GetSize() ; ++ i) { + int nKey ; + if ( k >= nSize - 1 || ! m_Params.FromString( vString[++k], nKey) || nKey != i) { + if ( m_Params.IsOptional( i)) + -- k ; + else + return false ; + } + } + // parametri utensile + for ( int i = 0 ; i < m_TParams.GetSize() ; ++ i) { + int nKey ; + if ( k >= nSize - 1 || ! m_TParams.FromString( vString[++k], nKey) || nKey != i) + return false ; + } + // parametri di stato + while ( k < nSize - 1) { + // separo chiave da valore + string sKey, sVal ; + SplitFirst( vString[++k], "=", sKey, sVal) ; + // leggo + if ( sKey == KEY_PHASE){ + if ( ! FromString( sVal, m_nPhase)) + return false ; + } + else if ( sKey == KEY_NUM) { + if ( ! FromString( sVal, m_nMills)) + return false ; + } + } + return true ; +} + +//---------------------------------------------------------------------------- +//---------------------------------------------------------------------------- +Pocketing::Pocketing( void) +{ + m_Params.m_sName = "*" ; + m_Params.m_sToolName = "*" ; + m_TParams.m_sName = "*" ; + m_TParams.m_sHead = "*" ; + m_nMills = 0 ; +} + +//---------------------------------------------------------------------------- +bool +Pocketing::Prepare( const string& sMillName) +{ + // verifico il gestore lavorazioni + if ( m_pMchMgr == nullptr) + return false ; + // recupero il gestore DB utensili della macchina corrente + ToolsMgr* pTMgr = m_pMchMgr->GetCurrToolsMgr() ; + if ( pTMgr == nullptr) + return false ; + // recupero il gestore DB lavorazioni della macchina corrente + MachiningsMgr* pMMgr = m_pMchMgr->GetCurrMachiningsMgr() ; + if ( pMMgr == nullptr) + return false ; + // ricerca della lavorazione di libreria con il nome indicato + const PocketingData* pDdata = GetPocketingData( pMMgr->GetMachining( sMillName)) ; + if ( pDdata == nullptr) + return false ; + m_Params = *pDdata ; + // ricerca dell'utensile usato dalla lavorazione + const ToolData* pTdata = pTMgr->GetTool( m_Params.m_ToolUuid) ; + if ( pTdata == nullptr) + return false ; + m_TParams = *pTdata ; + m_Params.m_sToolName = m_TParams.m_sName ; + return true ; +} + +//---------------------------------------------------------------------------- +bool +Pocketing::SetParam( int nType, bool bVal) +{ + switch ( nType) { + case MPA_INVERT : + m_Params.m_bInvert = bVal ; + return true ; + } + return false ; +} + +//---------------------------------------------------------------------------- +bool +Pocketing::SetParam( int nType, int nVal) +{ + switch ( nType) { + case MPA_LEADINTYPE : + if ( ! m_Params.VerifyLeadInType( nVal)) + return false ; + m_Params.m_nLeadInType = nVal ; + return true ; + case MPA_LEADOUTTYPE : + if ( ! m_Params.VerifyLeadOutType( nVal)) + return false ; + m_Params.m_nLeadOutType = nVal ; + return true ; + case MPA_SCC : + if ( ! m_Params.VerifySolCh( nVal)) + return false ; + m_Params.m_nSolCh = nVal ; + return true ; + case MPA_SUBTYPE : + if ( ! m_Params.VerifySubType( nVal)) + return false ; + m_Params.m_nSubType = nVal ; + return true ; + } + return false ; +} + +//---------------------------------------------------------------------------- +bool +Pocketing::SetParam( int nType, double dVal) +{ + switch ( nType) { + case MPA_SPEED : + if ( ! m_TParams.VerifySpeed( dVal)) + return false ; + if ( abs( m_TParams.m_dSpeed - dVal) < EPS_MACH_ANG_PAR) + m_Params.m_dSpeed = 0 ; + else + m_Params.m_dSpeed = dVal ; + return true ; + case MPA_FEED : + if ( abs( m_TParams.m_dFeed - dVal) < EPS_MACH_LEN_PAR) + m_Params.m_dFeed = 0 ; + else + m_Params.m_dFeed = dVal ; + return true ; + case MPA_STARTFEED : + if ( abs( m_TParams.m_dStartFeed - dVal) < EPS_MACH_LEN_PAR) + m_Params.m_dStartFeed = 0 ; + else + m_Params.m_dStartFeed = dVal ; + return true ; + case MPA_ENDFEED : + if ( abs( m_TParams.m_dEndFeed - dVal) < EPS_MACH_LEN_PAR) + m_Params.m_dEndFeed = 0 ; + else + m_Params.m_dEndFeed = dVal ; + return true ; + case MPA_TIPFEED : + if ( abs( m_TParams.m_dTipFeed - dVal) < EPS_MACH_LEN_PAR) + m_Params.m_dTipFeed = 0 ; + else + m_Params.m_dTipFeed = dVal ; + return true ; + case MPA_OFFSR : + if ( abs( m_TParams.m_dOffsR - dVal) < EPS_MACH_LEN_PAR) + m_Params.m_dOffsR = UNKNOWN_PAR ; + else + m_Params.m_dOffsR = dVal ; + return true ; + case MPA_OFFSL : + if ( abs( m_TParams.m_dOffsL - dVal) < EPS_MACH_LEN_PAR) + m_Params.m_dOffsL = UNKNOWN_PAR ; + else + m_Params.m_dOffsL = dVal ; + return true ; + case MPA_DEPTH : + m_Params.m_sDepth = ToString( dVal) ; + return true ; + case MPA_STARTPOS : + m_Params.m_dStartPos = dVal ; + return true ; + case MPA_STEP : + m_Params.m_dStep = dVal ; + return true ; + case MPA_LITANG : + m_Params.m_dLiTang = dVal ; + return true ; + case MPA_LOTANG : + m_Params.m_dLoTang = dVal ; + return true ; + } + return false ; +} + +//---------------------------------------------------------------------------- +bool +Pocketing::SetParam( int nType, const string& sVal) +{ + switch ( nType) { + case MPA_TOOL : { + const ToolData* pTdata ; + if ( ! m_Params.VerifyTool( m_pMchMgr->GetCurrToolsMgr(), sVal, pTdata)) + return false ; + m_Params.m_sToolName = sVal ; + m_Params.m_ToolUuid = pTdata->m_Uuid ; + m_TParams = *pTdata ; + } break ; + case MPA_DEPTH_STR : + m_Params.m_sDepth = sVal ; + return true ; + case MPA_SYSNOTES : + m_Params.m_sSysNotes = sVal ; + break ; + case MPA_USERNOTES : + m_Params.m_sUserNotes = sVal ; + break ; + default : + return false ; + } + return true ; +} + +//---------------------------------------------------------------------------- +bool +Pocketing::SetGeometry( const SELVECTOR& vIds) +{ + // verifico validità gestore DB geometrico + if ( m_pGeomDB == nullptr) + return false ; + // reset della geometria corrente + m_vId.clear() ; + // verifico che gli identificativi rappresentino delle entità ammissibili (tutte curve o tutte facce) + int nType = GEO_NONE ; + for ( const auto& Id : vIds) { + // test sull'entità + int nSubs ; + if ( ! VerifyGeometry( Id, nSubs, nType)) { + string sOut = "Entity " + ToString( Id) + " skipped by Milling" ; + LOG_INFO( GetEMkLogger(), sOut.c_str()) ; + continue ; + } + // posso aggiungere alla lista + m_vId.emplace_back( Id) ; + } + return ( ! m_vId.empty() || vIds.empty()) ; +} + +//---------------------------------------------------------------------------- +bool +Pocketing::Preview( bool bRecalc) +{ + // reset numero percorsi di lavoro generati + m_nMills = 0 ; + + // verifico validità gestore DB geometrico e Id del gruppo + if ( m_pGeomDB == nullptr || ! m_pGeomDB->ExistsObj( m_nOwnerId)) + return false ; + + // recupero gruppo per geometria ausiliaria + int nAuxId = m_pGeomDB->GetFirstNameInGroup( m_nOwnerId, MCH_AUX) ; + bool bChain = false ; + // se non c'è, lo aggiungo + if ( nAuxId == GDB_ID_NULL) { + nAuxId = m_pGeomDB->AddGroup( GDB_ID_NULL, m_nOwnerId, Frame3d()) ; + if ( nAuxId == GDB_ID_NULL) + return false ; + m_pGeomDB->SetName( nAuxId, MCH_AUX) ; + m_pGeomDB->SetStatus( nAuxId, GDB_ST_OFF) ; + bChain = true ; + } + // altrimenti, se chiesto ricalcolo, lo svuoto + else if ( bRecalc) { + m_pGeomDB->EmptyGroup( nAuxId) ; + bChain = true ; + } + + // aggiorno dati geometrici dell'utensile + if ( ! UpdateToolData()) { + LOG_INFO( GetEMkLogger(), "Error in Milling : UpdateToolData failed") ; + return false ; + } + + // se necessario, eseguo concatenamento ed inserisco i percorsi sotto la geometria ausiliaria + if ( bChain && ! Chain( nAuxId)) + return false ; + + // recupero gruppo per geometria di Preview + int nPvId = m_pGeomDB->GetFirstNameInGroup( m_nOwnerId, MCH_PV) ; + // se non c'è, lo aggiungo + if ( nPvId == GDB_ID_NULL) { + nPvId = m_pGeomDB->AddGroup( GDB_ID_NULL, m_nOwnerId, Frame3d()) ; + if ( nPvId == GDB_ID_NULL) + return false ; + m_pGeomDB->SetName( nPvId, MCH_PV) ; + } + // altrimenti lo svuoto + else + m_pGeomDB->EmptyGroup( nPvId) ; + + // lavoro ogni singola catena + int nPathId = m_pGeomDB->GetFirstGroupInGroup( nAuxId) ; + while ( nPathId != GDB_ID_NULL) { + if ( ! ProcessPath( nPathId, nPvId, GDB_ID_NULL)) + return false ; + nPathId = m_pGeomDB->GetNextGroup( nPathId) ; + } + + return true ; +} + +//---------------------------------------------------------------------------- +bool +Pocketing::Apply( bool bRecalc) +{ + // reset numero percorsi di lavoro generati + m_nMills = 0 ; + + // verifico validità gestore DB geometrico e Id del gruppo + if ( m_pGeomDB == nullptr || ! m_pGeomDB->ExistsObj( m_nOwnerId)) + return false ; + + // recupero gruppo per geometria ausiliaria + int nAuxId = m_pGeomDB->GetFirstNameInGroup( m_nOwnerId, MCH_AUX) ; + bool bChain = false ; + // se non c'è, lo aggiungo + if ( nAuxId == GDB_ID_NULL) { + nAuxId = m_pGeomDB->AddGroup( GDB_ID_NULL, m_nOwnerId, Frame3d()) ; + if ( nAuxId == GDB_ID_NULL) + return false ; + m_pGeomDB->SetName( nAuxId, MCH_AUX) ; + m_pGeomDB->SetStatus( nAuxId, GDB_ST_OFF) ; + bChain = true ; + } + // altrimenti, se chiesto ricalcolo, lo svuoto + else if ( bRecalc) { + m_pGeomDB->EmptyGroup( nAuxId) ; + bChain = true ; + } + + // aggiorno dati geometrici dell'utensile + if ( ! UpdateToolData()) { + LOG_INFO( GetEMkLogger(), "Error in Milling : UpdateToolData failed") ; + return false ; + } + + // se necessario, eseguo concatenamento ed inserisco i percorsi sotto la geometria ausiliaria + if ( bChain && ! Chain( nAuxId)) + return false ; + + // recupero gruppo per geometria di lavorazione (Cutter Location) + int nClId = m_pGeomDB->GetFirstNameInGroup( m_nOwnerId, MCH_CL) ; + // se non c'è, lo aggiungo + if ( nClId == GDB_ID_NULL) { + nClId = m_pGeomDB->AddGroup( GDB_ID_NULL, m_nOwnerId, Frame3d()) ; + if ( nClId == GDB_ID_NULL) + return false ; + m_pGeomDB->SetName( nClId, MCH_CL) ; + } + // altrimenti lo svuoto + else + m_pGeomDB->EmptyGroup( nClId) ; + + // lavoro ogni singola catena + int nPathId = m_pGeomDB->GetFirstGroupInGroup( nAuxId) ; + while ( nPathId != GDB_ID_NULL) { + if ( ! ProcessPath( nPathId, GDB_ID_NULL, nClId)) + return false ; + nPathId = m_pGeomDB->GetNextGroup( nPathId) ; + } + + // se lavorazione vuota, esco + if ( m_nMills == 0) + return true ; + + // calcolo gli assi macchina + string sHint = ExtractHint( m_Params.m_sUserNotes) ; + if ( ! CalculateAxesValues( sHint)) + return false ; + + // gestione movimenti all'inizio di ogni singolo percorso di lavorazione e alla fine della lavorazione + if ( ! AdjustStartEndMovements()) + return false ; + + // esecuzione eventuali personalizzazioni + if ( ! PostApply()) + return false ; + + return true ; +} + +//---------------------------------------------------------------------------- +bool +Pocketing::GetParam( int nType, bool& bVal) const +{ + switch ( nType) { + case MPA_INVERT : + bVal = m_Params.m_bInvert ; + return true ; + } + bVal = false ; + return false ; +} + +//---------------------------------------------------------------------------- +bool +Pocketing::GetParam( int nType, int& nVal) const +{ + switch ( nType) { + case MPA_TYPE : + nVal = MT_POCKETING ; + return true ; + case MPA_LEADINTYPE : + nVal = m_Params.m_nLeadInType ; + return true ; + case MPA_LEADOUTTYPE : + nVal = m_Params.m_nLeadOutType ; + return true ; + case MPA_SCC : + nVal = m_Params.m_nSolCh ; + return true ; + case MPA_SUBTYPE : + nVal = m_Params.m_nSubType ; + return true ; + } + nVal = 0 ; + return false ; +} + +//---------------------------------------------------------------------------- +bool +Pocketing::GetParam( int nType, double& dVal) const +{ + switch ( nType) { + case MPA_SPEED : + dVal = GetSpeed() ; + return true ; + case MPA_FEED : + dVal = GetFeed() ; + return true ; + case MPA_STARTFEED : + dVal = GetStartFeed() ; + return true ; + case MPA_ENDFEED : + dVal = GetEndFeed() ; + return true ; + case MPA_TIPFEED : + dVal = GetTipFeed() ; + return true ; + case MPA_OFFSR : + dVal = GetOffsR() ; + return true ; + case MPA_OFFSL : + dVal = GetOffsL() ; + return true ; + case MPA_STARTPOS : + dVal = m_Params.m_dStartPos ; + return true ; + case MPA_STEP : + dVal = m_Params.m_dStep ; + return true ; + case MPA_LITANG : + dVal = m_Params.m_dLiTang ; + return true ; + case MPA_LOTANG : + dVal = m_Params.m_dLoTang ; + return true ; + } + dVal = 0 ; + return false ; +} + +//---------------------------------------------------------------------------- +bool +Pocketing::GetParam( int nType, string& sVal) const +{ + switch ( nType) { + case MPA_NAME : + sVal = m_Params.m_sName ; + return true ; + case MPA_TOOL : + sVal = m_Params.m_sToolName ; + return true ; + case MPA_DEPTH_STR : + sVal = m_Params.m_sDepth ; + return true ; + case MPA_TUUID : + sVal = ToString( m_Params.m_ToolUuid) ; + return true ; + case MPA_UUID : + sVal = ToString( m_Params.m_Uuid) ; + return true ; + case MPA_SYSNOTES : + sVal = m_Params.m_sSysNotes ; + return true ; + case MPA_USERNOTES : + sVal = m_Params.m_sUserNotes ; + return true ; + } + sVal = "" ; + return false ; +} + +//---------------------------------------------------------------------------- +const ToolData& +Pocketing::GetToolData( void) const +{ + return m_TParams ; +} + +//---------------------------------------------------------------------------- +bool +Pocketing::UpdateToolData( void) +{ + // recupero il gestore DB utensili della macchina corrente + ToolsMgr* pTMgr = m_pMchMgr->GetCurrToolsMgr() ; + if ( pTMgr == nullptr) + return false ; + // recupero l'utensile nel DB utensili + const ToolData* pTdata = pTMgr->GetTool( m_Params.m_ToolUuid) ; + if ( pTdata == nullptr) + return false ; + // aggiorno i parametri + m_TParams = *pTdata ; + if ( ! EqualNoCase( m_Params.m_sToolName, m_TParams.m_sName)) { + string sLog = "Warning in Milling : tool name changed (" + + m_Params.m_sToolName + "->" + m_TParams.m_sName +")" ; + LOG_INFO( GetEMkLogger(), sLog.c_str()) ; + } + return true ; +} + +//---------------------------------------------------------------------------- +bool +Pocketing::GetGeometry( SELVECTOR& vIds) const +{ + // restituisco l'elenco delle entità + vIds = m_vId ; + return true ; +} + +//---------------------------------------------------------------------------- +bool +Pocketing::VerifyGeometry( SelData Id, int& nSubs, int& nType) +{ + // ammessi : tutte curve o tutte facce di trimesh + const IGeoObj* pGObj = m_pGeomDB->GetGeoObj( Id.nId) ; + if ( pGObj == nullptr) + return false ; + // se ammesse curve ed è tale + if ( nType != GEO_SURF && ( pGObj->GetType() & GEO_CURVE) != 0) { + const ICurve* pCurve = nullptr ; + // se direttamente la curva + if ( Id.nSub == SEL_SUB_ALL) { + pCurve = ::GetCurve( pGObj) ; + if ( pCurve != nullptr) { + if ( pCurve->GetType() == CRV_COMPO) + nSubs = ::GetCurveComposite( pCurve)->GetCurveCount() ; + else + nSubs = 0 ; + } + } + // altrimenti sottocurva di composita + else { + const ICurveComposite* pCompo = GetCurveComposite( pGObj) ; + if ( pCompo != nullptr) + pCurve = pCompo->GetCurve( Id.nSub) ; + nSubs = 0 ; + } + return ( pCurve != nullptr) ; + } + // se altrimenti ammesse superfici trimesh ed è tale + else if ( nType != GEO_CURVE && ( pGObj->GetType() & GEO_SURF) != 0) { + const ISurfTriMesh* pSurf = ::GetSurfTriMesh( pGObj) ; + if ( pSurf == nullptr) + return false ; + // se direttamente la superficie + if ( Id.nSub == SEL_SUB_ALL) { + nSubs = pSurf->GetFacetCount() ; + return true ; + } + // altrimenti faccia di superficie trimesh + else { + // se faccia non esistente + if ( Id.nSub > pSurf->GetFacetCount()) + return false ; + // tutto bene + nSubs = 0 ; + return true ; + } + } + // altrimenti errore + else + return false ; +} + +//---------------------------------------------------------------------------- +ICurve* +Pocketing::GetCurve( SelData Id) +{ + // ammessi : curve o facce di polymesh + const IGeoObj* pGObj = m_pGeomDB->GetGeoObj( Id.nId) ; + if ( pGObj == nullptr) + return nullptr ; + // ne recupero il riferimento globale + Frame3d frGlob ; + if ( ! m_pGeomDB->GetGlobFrame( Id.nId, frGlob)) + return nullptr ; + // se curva + if ( ( pGObj->GetType() & GEO_CURVE) != 0) { + PtrOwner pCurve ; + // se direttamente curva + if ( Id.nSub == SEL_SUB_ALL) { + // recupero e duplico la curva + const ICurve* pOriCurve = ::GetCurve( pGObj) ; + if ( pOriCurve != nullptr) + pCurve.Set( pOriCurve->Clone()) ; + // se estrusione mancante, imposto default + Vector3d vtExtr ; + if ( ! pCurve->GetExtrusion( vtExtr) || vtExtr.IsSmall()) + pCurve->SetExtrusion( Z_AX) ; + } + // altrimenti sottocurva di composita + else { + // recupero la composita + const ICurveComposite* pCompo = GetCurveComposite( pGObj) ; + if ( pCompo != nullptr) { + // 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) || vtExtr.IsSmall()) + vtExtr = Z_AX ; + pCurve->SetExtrusion( vtExtr) ; + double dThick ; + if ( pCompo->GetThickness( dThick)) + pCurve->SetThickness( dThick) ; + } + } + } + if ( IsNull( pCurve)) + return nullptr ; + // la porto in globale + pCurve->ToGlob( frGlob) ; + // la restituisco + return Release( pCurve) ; + } + // se altrimenti superficie + else if ( ( pGObj->GetType() & GEO_SURF) != 0) { + // recupero la trimesh + const ISurfTriMesh* pSurf = ::GetSurfTriMesh( pGObj) ; + if ( pSurf == nullptr) + return nullptr ; + // recupero l'indice della faccia + int nFacet = ( ( Id.nSub == SEL_SUB_ALL) ? 0 : Id.nSub) ; + // recupero i contorni della faccia + POLYLINEVECTOR vPL ; + pSurf->GetFacetLoops( nFacet, vPL) ; + if ( vPL.empty()) + return nullptr ; + // recupero la normale esterna della faccia + Vector3d vtN ; + if ( ! pSurf->GetFacetNormal( nFacet, vtN)) + return nullptr ; + // creo la curva a partire da quello esterno + PtrOwner pCrvCompo( CreateCurveComposite()) ; + pCrvCompo->FromPolyLine( vPL[0]) ; + if ( ! pCrvCompo->IsValid()) + return nullptr ; + // assegno l'estrusione dalla normale alla faccia + pCrvCompo->SetExtrusion( vtN) ; + // la porto in globale + pCrvCompo->ToGlob( frGlob) ; + // sistemazioni varie + AdjustCurveFromSurf( pCrvCompo) ; + // la restituisco + return Release( pCrvCompo) ; + } + // altrimenti errore + else + return nullptr ; +} + +//---------------------------------------------------------------------------- +bool +Pocketing::AdjustCurveFromSurf( ICurveComposite* pCrvCompo) +{ + // con utensile fresa fa il contorno + if ( ( m_TParams.m_nType & TF_SAWBLADE) == 0) { + // cerco l'estremo più alto e lo imposto come inizio + double dU = 0 ; + double dUmax = 0 ; + double dZmax = - INFINITO ; + Point3d ptP ; + while ( pCrvCompo->GetPointD1D2( dU, ICurve::FROM_MINUS, ptP)) { + if ( ptP.z > dZmax + EPS_SMALL) { + dZmax = ptP.z ; + dUmax = dU ; + } + dU += 1 ; + } + if ( dU != 0) + pCrvCompo->ChangeStartPoint( dUmax) ; + } + return true ; +} + +//---------------------------------------------------------------------------- +bool +Pocketing::Chain( int nGrpDestId) +{ + // vettore puntatori alle curve + typedef PtrOwner POWNCURVE ; + typedef std::vector POCRVVECTOR ; + POCRVVECTOR 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 sOut = "Entity " + ToString( Id) + " skipped by Milling" ; + LOG_INFO( GetEMkLogger(), sOut.c_str()) ; + 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 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) && fabs( dTemp) > fabs( 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 ; +} + +//---------------------------------------------------------------------------- +bool +Pocketing::AdjustEndPointForAxesCalc( const CamData* pCamData, Point3d& ptP) const +{ + // non devo fare alcunché + return true ; +} + +//---------------------------------------------------------------------------- +bool +Pocketing::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) ; + + // copio la curva composita da elaborare + int nCrvId = m_pGeomDB->GetFirstInGroup( nPathId) ; + if ( m_pGeomDB->GetGeoType( nCrvId) != CRV_COMPO) + return false ; + int nCopyId = m_pGeomDB->CopyGlob( nCrvId, GDB_ID_NULL, nTempId) ; + if ( nCopyId == GDB_ID_NULL) + return false ; + ICurveComposite* pCompo = GetCurveComposite( m_pGeomDB->GetGeoObj( nCopyId)) ; + + // eventuale inversione percorso + if ( m_Params.m_bInvert) + pCompo->Invert() ; + + // recupero estrusione e spessore + Vector3d vtExtr ; + pCompo->GetExtrusion( vtExtr) ; + double dThick ; + pCompo->GetThickness( dThick) ; + + // unisco le parti allineate (tranne inizio-fine se chiusa) + if ( ! pCompo->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL, false)) + return false ; + + // recupero il punto di inizio (per poi salvarlo nelle info di CL path) + Point3d ptStart ; + pCompo->GetStartPoint( ptStart) ; + + // recupero il box del grezzo in globale + BBox3d b3Raw ; + if ( ! GetRawGlobBox( m_nPhase, nPathId, 0.5 * m_TParams.m_dDiam, b3Raw) || b3Raw.IsEmpty()) { + LOG_INFO( GetEMkLogger(), "Error in Milling : Empty RawBox") ; + return false ; + } + + // recupero distanza da fondo dei grezzi interessati dal percorso + double dRbDist = 0 ; + if ( AreSameVectorApprox( vtExtr, Z_AX)) { + if ( ! GetDistanceFromRawBottom( m_nPhase, nCopyId, m_TParams.m_dDiam, dRbDist)) + return false ; + } + + // 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)) { + LOG_INFO( GetEMkLogger(), "Error in Milling : Depth not computable") ; + return false ; + } + // se spessore positivo, lo sottraggo dal risultato + if ( dThick > 0) + dDepth -= dThick ; + // sottraggo eventuale offset longitudinale + dDepth -= GetOffsL() ; + + // recupero nome del path + string sPathName ; + m_pGeomDB->GetName( nPathId, sPathName) ; + + // eventuale approssimazione con segmenti di retta + int nSplitArcs = m_pMchMgr->GetCurrMachiningsMgr()->GetSplitArcs() ; + bool bSplitArcs = ( nSplitArcs == SPLAR_ALWAYS || + ( nSplitArcs == SPLAR_NO_XY_PLANE && ! vtExtr.IsZplus()) || + ( nSplitArcs == SPLAR_GEN_PLANE && vtExtr.IsGeneric())) ; + if ( bSplitArcs) { + const double ANG_TOL_MAX_DEG = 90 ; + PolyLine PL ; + if ( pCompo->ApproxWithLines( 50 * EPS_SMALL, ANG_TOL_MAX_DEG, ICurve::APL_SPECIAL, PL)) { + // sostituisco le linee alle curve originali + pCompo->Clear() ; + pCompo->FromPolyLine( PL) ; + // riassegno estrusione e spessore + pCompo->SetExtrusion( vtExtr) ; + pCompo->SetThickness( dThick) ; + } + } + + // 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 ; ++ i) { + // 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) ; + ++ i ; + ++ nMaxInd ; + } + } + + // calcolo il versore fresa + Vector3d vtTool = Z_AX ; + if ( ! vtExtr.IsSmall()) + vtTool = vtExtr ; + + // calcolo l'elevazione massima + double dElev ; + if ( CalcPathElevation( pCompo, vtTool, dDepth, 0.5 * m_TParams.m_dDiam, dElev)) { + if ( dElev < EPS_SMALL && AreSameVectorApprox( vtExtr, Z_AX)) { + BBox3d b3Crv ; + pCompo->GetLocalBBox( b3Crv) ; + dElev = max( 0., b3Raw.GetMax().z - b3Crv.GetMin().z + dDepth) ; + } + } + else + return false ; + + // per frese normali, verifico di non superare il massimo materiale + if ( ( m_TParams.m_nType & TF_SAWBLADE) == 0) { + const double MAXMAT_TOL = EPS_SMALL ; + if ( ( m_Params.m_dStep < EPS_SMALL && dElev > m_TParams.m_dMaxMat + MAXMAT_TOL) || + ( m_Params.m_dStep > EPS_SMALL && m_Params.m_dStep > m_TParams.m_dMaxMat + EPS_SMALL)) { + if ( dDepth + max( dThick, 0.0) > m_TParams.m_dMaxMat) { + dDepth = m_TParams.m_dMaxMat - max( dThick, 0.0) ; + string sInfo = "Warning in Milling : machining depth (" + ToString( dElev, 1) + + ") bigger than MaxMaterial (" + ToString( m_TParams.m_dMaxMat, 1) + ")" ; + LOG_INFO( GetEMkLogger(), sInfo.c_str()) ; + } + else { + string sInfo = "Error in Milling : machining depth (" + ToString( dElev, 1) + + ") bigger than MaxMaterial (" + ToString( m_TParams.m_dMaxMat, 1) + ")" ; + LOG_INFO( GetEMkLogger(), sInfo.c_str()) ; + return false ; + } + } + } + + // verifiche per fresatura dal basso + m_bAggrBottom = false ; + if ( ! VerifyPathFromBottom( pCompo, vtTool)) { + return false ; + } + + // se richiesta anteprima + if ( nPvId != GDB_ID_NULL) { + // creo gruppo per geometria di lavorazione del percorso + int nPxId = m_pGeomDB->AddGroup( GDB_ID_NULL, nPvId, Frame3d()) ; + if ( nPxId == GDB_ID_NULL) + return false ; + m_pGeomDB->SetName( nPxId, sPathName) ; + m_pGeomDB->SetMaterial( nPxId, GREEN) ; + // creo l'anteprima del percorso + if ( ! GenerateMillingPv( nPxId, pCompo)) + return false ; + } + + // se richiesta lavorazione + if ( nClId != GDB_ID_NULL) { + // creo gruppo per geometria di lavorazione del percorso + int nPxId = m_pGeomDB->AddGroup( GDB_ID_NULL, nClId, Frame3d()) ; + if ( nPxId == GDB_ID_NULL) + return false ; + m_pGeomDB->SetName( nPxId, sPathName) ; + m_pGeomDB->SetMaterial( nPxId, BLUE) ; + + // assegno il vettore estrazione al gruppo del percorso + m_pGeomDB->SetInfo( nPxId, KEY_EXTR, vtTool) ; + // assegno il punto di inizio al gruppo del percorso + m_pGeomDB->SetInfo( nPxId, KEY_START, ptStart) ; + + // Imposto dati comuni + SetPathId( nPxId) ; + SetToolDir( vtTool) ; + + // Se una sola passata + if ( ! AddStandardMilling( pCompo, vtTool, vtExtr, dDepth, dElev, bSplitArcs)) + return false ; + + // assegno al gruppo l'ingombro del percorso di lavoro + BBox3d b3Grp ; + m_pGeomDB->GetGlobalBBox( nPxId, b3Grp) ; + m_pGeomDB->SetInfo( nPxId, KEY_PMIN, b3Grp.GetMin()) ; + m_pGeomDB->SetInfo( nPxId, KEY_PMAX, b3Grp.GetMax()) ; + } + + // incremento numero di fresate + ++ m_nMills ; + + return true ; +} + +//---------------------------------------------------------------------------- +bool +Pocketing::CalcPathElevation( const ICurveComposite* pCompo, const Vector3d& vtTool, double dDepth, double dRad, + double& dElev) +{ + dElev = 0 ; + int nMaxInd = pCompo->GetCurveCount() - 1 ; + for ( int i = 0 ; i <= nMaxInd ; ++ i) { + // curva corrente + const ICurve* pCrvC = pCompo->GetCurve( i) ; + // calcolo elevazione + double dCurrElev ; + Point3d ptStart, ptMid, ptEnd ; + pCrvC->GetStartPoint( ptStart) ; + pCrvC->GetMidPoint( ptMid) ; + pCrvC->GetEndPoint( ptEnd) ; + Vector3d vtStartPerp, vtMidPerp, vtEndPerp, vtTg ; + pCrvC->GetStartDir( vtTg) ; + vtStartPerp = vtTg ^ vtTool ; + vtStartPerp.Normalize() ; + vtStartPerp *= dRad ; + pCrvC->GetMidDir( vtTg) ; + vtMidPerp = vtTg ^ vtTool ; + vtMidPerp.Normalize() ; + vtMidPerp *= dRad ; + pCrvC->GetEndDir( vtTg) ; + vtEndPerp = vtTg ^ vtTool ; + vtEndPerp.Normalize() ; + vtEndPerp *= dRad ; + Vector3d vtDepth = vtTool * dDepth ; + // linea centro utensile + if ( GetElevation( m_nPhase, ptStart - vtDepth, ptMid - vtDepth, ptEnd - vtDepth, vtTool, dCurrElev)) { + if ( dCurrElev > dElev) + dElev = dCurrElev ; + } + else { + LOG_INFO( GetEMkLogger(), "Error in Milling : Entity GetElevation") ; + return false ; + } + // da una parte + if ( GetElevation( m_nPhase, ptStart + vtStartPerp - vtDepth, ptMid + vtMidPerp - vtDepth, + ptEnd + vtEndPerp - vtDepth, vtTool, dCurrElev)) { + if ( dCurrElev > dElev) + dElev = dCurrElev ; + } + else { + LOG_INFO( GetEMkLogger(), "Error in Milling : Entity GetElevation") ; + return false ; + } + // dall'altra parte + if ( GetElevation( m_nPhase, ptStart - vtStartPerp - vtDepth, ptMid - vtMidPerp - vtDepth, + ptEnd - vtEndPerp - vtDepth, vtTool, dCurrElev)) { + if ( dCurrElev > dElev) + dElev = dCurrElev ; + } + else { + LOG_INFO( GetEMkLogger(), "Error in Milling : Entity GetElevation") ; + return false ; + } + } + return true ; +} + +//---------------------------------------------------------------------------- +bool +Pocketing::VerifyPathFromBottom( const ICurveComposite* pCompo, const Vector3d& vtTool) +{ + // se non è fresatura dal basso in alto, esco + if ( vtTool.z > - 0.5) + return true ; + // se c'è tavola basculante, esco + bool bTabTilting = false ; + if ( m_pMchMgr->GetCurrMachine()->GetCurrTableIsTilting( bTabTilting) && bTabTilting) + return true ; + // verifico se c'è rinvio da sotto + int nHeadId = m_pMchMgr->GetHeadId( m_TParams.m_sHead) ; + int nAgbType ; + if ( ! m_pGeomDB->GetInfo( nHeadId, "AGB_TYPE", nAgbType) || nAgbType == 0) { + string sOut = "Milling error : missing aggregate from bottom" ; + LOG_INFO( GetEMkLogger(), sOut.c_str()) ; + return false ; + } + // recupero la massima distanza consentita dal rinvio + double dAgbDmax = 0 ; + m_pGeomDB->GetInfo( nHeadId, "AGB_DMAX", dAgbDmax) ; + // calcolo la massima distanza minima del percorso dal contorno del grezzo + double dDist = 0 ; + Vector3d vtDir ; + int nMaxInd = pCompo->GetCurveCount() - 1 ; + for ( int i = 0 ; i <= nMaxInd ; ++ i) { + // curva corrente + const ICurve* pCrvC = pCompo->GetCurve( i) ; + // considero inizio della prima curva, punto medio e fine di tutte + Point3d ptP ; + double dCurrDist = 0 ; + Vector3d vtCurrDir ; + if ( i == 0) { + pCrvC->GetStartPoint( ptP) ; + GetMinDistanceFromRawSide( m_nPhase, ptP, dCurrDist, vtCurrDir) ; + if ( dCurrDist > dDist) { + dDist = dCurrDist ; + vtDir = vtCurrDir ; + } + } + pCrvC->GetMidPoint( ptP) ; + GetMinDistanceFromRawSide( m_nPhase, ptP, dCurrDist, vtCurrDir) ; + if ( dCurrDist > dDist) { + dDist = dCurrDist ; + vtDir = vtCurrDir ; + } + pCrvC->GetEndPoint( ptP) ; + GetMinDistanceFromRawSide( m_nPhase, ptP, dCurrDist, vtCurrDir) ; + if ( dCurrDist > dDist) { + dDist = dCurrDist ; + vtDir = vtCurrDir ; + } + } + // se supera il limite, errore + if ( dDist > dAgbDmax) { + string sOut = "Milling error : path too far from part sides" ; + LOG_INFO( GetEMkLogger(), sOut.c_str()) ; + return false ; + } + // assegno direzione di accesso e segnalo utilizzo aggregato da sotto + SetAuxDir( vtDir) ; + m_bAggrBottom = true ; + return true ; +} + +//---------------------------------------------------------------------------- +bool +Pocketing::GenerateMillingPv( int nPathId, const ICurveComposite* pCompo) +{ + // creo copia della curva composita + PtrOwner< ICurve> pCrv( pCompo->Clone()) ; + if ( IsNull( pCrv)) + return false ; + // calcolo la regione + PtrOwner pSfr ; + pSfr.Set( GetSurfFlatRegionFromFatCurve( Release( pCrv), 0.5 * m_TParams.m_dDiam, false, false)) ; + if ( IsNull( pSfr)) + return false ; + // ne recupero il contorno + PtrOwner< ICurve> pCrv2 ; + pCrv2.Set( pSfr->GetLoop( 0, 0)) ; + if ( IsNull( pCrv2)) + return false ; + // inserisco la curva nel DB + int nC2Id = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nPathId, Release( pCrv2)) ; + if ( nC2Id == GDB_ID_NULL) + return false ; + // assegno nome e colore + m_pGeomDB->SetName( nC2Id, MCH_PV_CUT) ; + m_pGeomDB->SetMaterial( nC2Id, LIME) ; + // eventuali altri contorni ( interni di contornatura chiusa) + const int MAX_INT_LOOP = 1000 ; + for ( int i = 1 ; i <= MAX_INT_LOOP ; ++i) { + PtrOwner< ICurve> pCrv3 ; + pCrv3.Set( pSfr->GetLoop( 0, i)) ; + if ( IsNull( pCrv3)) + break ; + // inserisco la curva nel DB + int nC3Id = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nPathId, Release( pCrv3)) ; + if ( nC3Id == GDB_ID_NULL) + return false ; + // assegno nome e colore + m_pGeomDB->SetName( nC3Id, MCH_PV_CUT) ; + m_pGeomDB->SetMaterial( nC3Id, LIME) ; + } + // inserisco la regione nel DB + int nRId = m_pGeomDB->AddGeoObj( GDB_ID_NULL, nPathId, Release( pSfr)) ; + if ( nRId == GDB_ID_NULL) + return false ; + m_pGeomDB->SetName( nRId, MCH_PV_RCUT) ; + m_pGeomDB->SetMaterial( nRId, INVISIBLE) ; + // la copio anche come regione ridotta + int nRrId = m_pGeomDB->Copy( nRId, GDB_ID_NULL, nPathId) ; + if ( nRrId == GDB_ID_NULL) + return false ; + m_pGeomDB->SetName( nRrId, MCH_PV_RRCUT) ; + m_pGeomDB->SetMaterial( nRrId, INVISIBLE) ; + return true ; +} + +//---------------------------------------------------------------------------- +bool +Pocketing::AddStandardMilling( const ICurveComposite* pCompo, const Vector3d& vtTool, const Vector3d& vtExtr, + double dDepth, double dElev, bool bSplitArcs) +{ + // recupero distanza di sicurezza + double dSafeZ = m_pMchMgr->GetCurrMachiningsMgr()->GetSafeZ() ; + // lunghezza di approccio/retrazione + double dAppr = m_Params.m_dStartPos ; + + // ciclo sulle curve elementari + bool bClosed = pCompo->IsClosed() ; + int nMaxInd = pCompo->GetCurveCount() - 1 ; + for ( int i = 0 ; i <= nMaxInd ; ++ i) { + // curva corrente + const ICurve* pCrvC = pCompo->GetCurve( i) ; + // copio la curva + PtrOwner pCurve( ::GetCurve( pCrvC->Clone())) ; + if ( IsNull( pCurve)) + return false ; + // aggiungo affondamento + pCurve->Translate( - vtTool * dDepth) ; + // se prima entità, approccio e affondo + if ( i == 0) { + // dati inizio entità + Point3d ptStart ; + pCurve->GetStartPoint( ptStart) ; + Vector3d vtStart ; + pCurve->GetStartDir( vtStart) ; + // determino inizio attacco + Point3d ptP1 ; + if ( ! CalcLeadInStart( ptStart, vtStart, vtExtr, false, ptP1)) + return false ; + // aggiungo approccio per frese normali con spazio sopra attacco + if ( ( m_TParams.m_nType & TF_SAWBLADE) == 0) { + // determino elevazione su inizio attacco + double dStElev ; + if ( ! GetElevation( m_nPhase, ptStart - 10 * EPS_SMALL * vtTool, vtTool, GetRadiusForStartEndElevation(), dStElev)) + dStElev = dElev ; + dStElev -= ( ptP1 - ptStart) * vtExtr ; + // approccio al punto iniziale + if ( ! AddApproach( ptP1, vtTool, dSafeZ, dStElev, dAppr)) + return false ; + } + // altrimenti, approccio per lame o diretto + else { + // affondo al punto iniziale + SetFlag( 0) ; + if ( AddRapidStart( ptP1) == GDB_ID_NULL) + return false ; + } + // aggiungo attacco + SetFeed( GetStartFeed()) ; + if ( ! AddLeadIn( ptP1, ptStart, vtStart, vtExtr, false, bSplitArcs)) { + LOG_INFO( GetEMkLogger(), "Error in Milling : LeadIn not computable") ; + return false ; + } + } + // elaborazioni sulla curva corrente + if ( pCurve->GetType() == CRV_LINE) { + ICurveLine* pLine = GetCurveLine( pCurve) ; + Point3d ptP3 = pLine->GetEnd() ; + SetFeed( GetFeed()) ; + if ( AddLinearMove( ptP3) == GDB_ID_NULL) + return false ; + } + else if ( pCurve->GetType() == CRV_ARC) { + ICurveArc* pArc = GetCurveArc( pCurve) ; + Point3d ptCen = pArc->GetCenter() ; + double dAngCen = pArc->GetAngCenter() ; + Vector3d vtN = pArc->GetNormVersor() ; + Point3d ptP3 ; + pArc->GetEndPoint( ptP3) ; + SetFeed( GetFeed()) ; + if ( AddArcMove( ptP3, ptCen, dAngCen, vtN) == GDB_ID_NULL) + return false ; + } + // se ultima entità, uscita e retrazione + if ( i == nMaxInd) { + // dati fine entità + Point3d ptEnd ; + pCurve->GetEndPoint( ptEnd) ; + Vector3d vtEnd ; + pCurve->GetEndDir( vtEnd) ; + // aggiungo uscita + Point3d ptP1 ; + SetFeed( GetStartFeed()) ; + if ( ! AddLeadOut( ptEnd, vtEnd, vtExtr, false, bSplitArcs, ptP1)) { + LOG_INFO( GetEMkLogger(), "Error in Milling : LeadOut not computable") ; + return false ; + } + // aggiungo retrazione per frese normali + if ( ( m_TParams.m_nType & TF_SAWBLADE) == 0) { + double dEndElev ; + if ( ! GetElevation( m_nPhase, ptEnd - 10 * EPS_SMALL * vtTool, vtTool, GetRadiusForStartEndElevation(), dEndElev)) + dEndElev = dElev ; + dEndElev -= ( ptP1 - ptEnd) * vtExtr ; + // aggiungo retrazione + if ( ! AddRetract( ptP1, vtTool, dSafeZ, dEndElev, dAppr)) + return false ; + } + // per lame non è necessario + } + } + return true ; +} + +//---------------------------------------------------------------------------- +bool +Pocketing::AddApproach( const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dElev, double dAppr) +{ + SetFlag( 1) ; + // se con aggregato da sotto + if ( m_bAggrBottom) { + // ne recupero alcuni dati + double dAgbEncH = 0 ; + double dAgbEncV = 0 ; + m_pGeomDB->GetInfo( m_pMchMgr->GetHeadId( m_TParams.m_sHead), "AGB_ENCH", dAgbEncH) ; + m_pGeomDB->GetInfo( m_pMchMgr->GetHeadId( m_TParams.m_sHead), "AGB_ENCV", dAgbEncV) ; + // aggiuntivo in Z + double dAggZ = max( dElev + max( dSafeZ, dAppr), 0.) ; + // distanza dal bordo del pezzo + double dDistBottom ; + if ( ! GetDistanceFromRawSide( m_nPhase, ptP, m_vtAux, dDistBottom)) + dDistBottom = 0 ; + // pre-approccio + Point3d ptP0 = ptP - Z_AX * dAggZ + m_vtAux * ( dDistBottom + dAgbEncH + dAppr) ; + Point3d ptP00 = ptP0 + Z_AX * ( dAgbEncV + m_TParams.m_dLen + dAggZ) ; + Vector3d vtAux = m_vtAux ; + vtAux.Rotate( Z_AX, 90) ; + SetAuxDir( vtAux) ; + if ( AddRapidStart( ptP00, MCH_CL_AGB_DWN) == GDB_ID_NULL) + return false ; + vtAux.Rotate( Z_AX, - 90) ; + SetAuxDir( vtAux) ; + SetFlag( 0) ; + if ( AddRapidMove( ptP0, MCH_CL_AGB_IN) == GDB_ID_NULL) + return false ; + } + // se sopra attacco c'è spazio per sicurezza o approccio + if ( dElev + max( dSafeZ, dAppr) > 10 * EPS_SMALL) { + // se distanza di sicurezza minore di distanza di inizio + if ( dSafeZ < dAppr + 10 * EPS_SMALL) { + // 1 -> punto sopra inizio + Point3d ptP1 = ptP + vtTool * ( dElev + dAppr) ; + if ( ( ! m_bAggrBottom && AddRapidStart( ptP1) == GDB_ID_NULL) || + ( m_bAggrBottom && AddRapidMove( ptP1) == GDB_ID_NULL)) + return false ; + } + else { + // 1a -> punto sopra inizio + Point3d ptP1b = ptP + vtTool * ( dElev + dAppr) ; + Point3d ptP1a = ptP1b + vtTool * ( dSafeZ - dAppr) ; + if ( ( ! m_bAggrBottom && AddRapidStart( ptP1a) == GDB_ID_NULL) || + ( m_bAggrBottom && AddRapidMove( ptP1a) == GDB_ID_NULL)) + // 1b -> punto appena sopra inizio + if ( ( dElev + dAppr) > EPS_SMALL) { + SetFlag( 0) ; + if ( AddRapidMove( ptP1b) == GDB_ID_NULL) + return false ; + } + } + // affondo al punto iniziale + SetFlag( 0) ; + SetFeed( GetTipFeed()) ; + if ( AddLinearMove( ptP) == GDB_ID_NULL) + return false ; + } + else { + // affondo diretto al punto iniziale + SetFlag( 0) ; + if ( ( ! m_bAggrBottom && AddRapidStart( ptP) == GDB_ID_NULL) || + ( m_bAggrBottom && AddRapidMove( ptP) == GDB_ID_NULL)) + return false ; + } + return true ; +} + +//---------------------------------------------------------------------------- +bool +Pocketing::AddRetract( const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dElev, double dAppr) +{ + // se sopra uscita c'è spazio per sicurezza o approccio + if ( dElev + max( dSafeZ, dAppr) > 10 * EPS_SMALL) { + if ( dSafeZ < dAppr + 10 * EPS_SMALL) { + // 4 -> movimento di risalita sopra il punto finale + SetFeed( GetEndFeed()) ; + Point3d ptP4 = ptP + vtTool * ( dElev + dAppr) ; + if ( AddLinearMove( ptP4) == GDB_ID_NULL) + return false ; + } + else { + // 4a -> movimento di risalita appena sopra il punto finale + Point3d ptP4a = ptP + vtTool * ( dElev + dAppr) ; + if ( dElev + dAppr > EPS_SMALL) { + SetFeed( GetEndFeed()) ; + if ( AddLinearMove( ptP4a) == GDB_ID_NULL) + return false ; + } + // 4b -> movimento di risalita sopra il punto finale + Point3d ptP4b = ptP4a + vtTool * ( dSafeZ - dAppr) ; + if ( AddRapidMove( ptP4b) == GDB_ID_NULL) + return false ; + } + } + // se con aggregato da sotto + if ( m_bAggrBottom) { + // ne recupero alcuni dati + double dAgbEncH = 0 ; + double dAgbEncV = 0 ; + m_pGeomDB->GetInfo( m_pMchMgr->GetHeadId( m_TParams.m_sHead), "AGB_ENCH", dAgbEncH) ; + m_pGeomDB->GetInfo( m_pMchMgr->GetHeadId( m_TParams.m_sHead), "AGB_ENCV", dAgbEncV) ; + // aggiuntivo in Z + double dAggZ = max( dElev + max( dSafeZ, dAppr), 0.) ; + // distanza dal bordo del pezzo + double dDistBottom ; + if ( ! GetDistanceFromRawSide( m_nPhase, ptP, m_vtAux, dDistBottom)) + dDistBottom = 0 ; + // post-retract + Point3d ptP0 = ptP - Z_AX * dAggZ + m_vtAux * ( dDistBottom + dAgbEncH + dAppr) ; + Point3d ptP00 = ptP0 + Z_AX * ( dAgbEncV + m_TParams.m_dLen + dAggZ) ; + if ( AddRapidMove( ptP0, MCH_CL_AGB_OUT) == GDB_ID_NULL) + return false ; + Vector3d vtAux = m_vtAux ; + vtAux.Rotate( Z_AX, 90) ; + SetAuxDir( vtAux) ; + if ( AddRapidMove( ptP00, MCH_CL_AGB_UP) == GDB_ID_NULL) + return false ; + } + return true ; +} + +//---------------------------------------------------------------------------- +bool +Pocketing::CalcLeadInStart( const Point3d& ptStart, const Vector3d& vtStart, const Vector3d& vtN, bool bInvert, + Point3d& ptP1) +{ + // Assegno tipo e parametri + int nType = m_Params.m_nLeadInType ; + double dTang = m_Params.m_dLiTang ; + double dPerp = 0 ; + double dElev = 0 ; + // se step invertito + if ( bInvert) { + switch ( m_Params.m_nLeadOutType) { + case MILL_LO_LINEAR : nType = MILL_LI_LINEAR ; break ; + case MILL_LO_TANGENT : nType = MILL_LI_TANGENT ; break ; + case MILL_LO_GLIDE : nType = MILL_LI_GLIDE ; break ; + case MILL_LO_AS_LI : /* resta inalterato */ ; break ; + default : nType = MILL_LI_NONE ; break ; + } + if ( m_Params.m_nLeadOutType != MILL_LO_AS_LI) { + dTang = m_Params.m_dLoTang ; + dPerp = 0 ; + dElev = 0 ; + } + } + // senso di rotazione da dir tg a dir esterna + bool bCcwRot = true ; + // Calcolo punto iniziale + switch ( nType) { + case MILL_LI_NONE : + ptP1 = ptStart ; + return true ; + case MILL_LI_LINEAR : + case MILL_LI_TANGENT : { + Vector3d vtPerp = vtStart ; + vtPerp.Rotate( vtN, ( bCcwRot ? 90 : - 90)) ; + ptP1 = ptStart - vtStart * dTang + vtPerp * dPerp + vtN * dElev ; + return true ; + } + case MILL_LI_GLIDE : + // !!! DA FARE !!! + return false ; + default : + return false ; + } +} + +//---------------------------------------------------------------------------- +bool +Pocketing::AddLeadIn( const Point3d& ptP1, const Point3d& ptStart, const Vector3d& vtStart, + const Vector3d& vtN, bool bInvert, bool bSplitArcs) +{ + // Assegno il tipo + int nType = m_Params.m_nLeadInType ; + // se step invertito + if ( bInvert) { + switch ( m_Params.m_nLeadOutType) { + case MILL_LO_LINEAR : nType = MILL_LI_LINEAR ; break ; + case MILL_LO_TANGENT : nType = MILL_LI_TANGENT ; break ; + case MILL_LO_GLIDE : nType = MILL_LI_GLIDE ; break ; + case MILL_LO_AS_LI : /* resta inalterato */ ; break ; + default : nType = MILL_LI_NONE ; break ; + } + } + // se archi da spezzare + if ( bSplitArcs) { + if ( nType == MILL_LI_TANGENT) + nType = MILL_LI_LINEAR ; + if ( nType == MILL_LI_HELIX) + nType = MILL_LI_ZIGZAG ; + } + // se parametri tg e perp entrambi nulli, allora nessun attacco + if ( (( ptStart - ptP1) ^ vtN).IsSmall()) + nType = MILL_LI_NONE ; + // Eseguo a seconda del tipo + switch ( nType) { + case MILL_LI_NONE : + return true ; + case MILL_LI_LINEAR : + return ( AddLinearMove( ptStart, MCH_CL_LEADIN) != GDB_ID_NULL) ; + case MILL_LI_TANGENT : + { + PtrOwner pCrv( GetArc2PVN( ptStart, ptP1, - vtStart, vtN)) ; + if ( IsNull( pCrv)) + return false ; + pCrv->Invert() ; + if ( pCrv->GetType() == CRV_LINE) { + ICurveLine* pLine = GetCurveLine( pCrv) ; + Point3d ptP3 = pLine->GetEnd() ; + return ( AddLinearMove( ptP3, MCH_CL_LEADIN) != GDB_ID_NULL) ; + } + else if ( pCrv->GetType() == CRV_ARC) { + ICurveArc* pArc = GetCurveArc( pCrv) ; + Point3d ptCen = pArc->GetCenter() ; + double dAngCen = pArc->GetAngCenter() ; + Vector3d vtN = pArc->GetNormVersor() ; + Point3d ptP3 ; + pArc->GetEndPoint( ptP3) ; + // se angolo al centro minore del limite, un solo arco + const double MAX_ANG_CEN = 150 + EPS_ANG_SMALL ; + if ( abs( dAngCen) < MAX_ANG_CEN) { + if ( AddArcMove( ptP3, ptCen, dAngCen, vtN, MCH_CL_LEADIN) == GDB_ID_NULL) + return false ; + } + // altrimenti due archi + else if ( abs( dAngCen) < 2 * MAX_ANG_CEN){ + Point3d ptMid ; + pArc->GetMidPoint( ptMid) ; + // prima metà arco + if ( AddArcMove( ptMid, ptCen, dAngCen / 2, vtN, MCH_CL_LEADIN) == GDB_ID_NULL) + return false ; + // seconda metà arco + if ( AddArcMove( ptP3, ptCen, dAngCen / 2, vtN, MCH_CL_LEADIN) == GDB_ID_NULL) + return false ; + } + // oppure tre archi + else { + Point3d ptTmp ; + // primo terzo + pArc->GetPointD1D2( 1. / 3, ICurve::FROM_MINUS, ptTmp) ; + if ( AddArcMove( ptTmp, ptCen, dAngCen / 3, vtN, MCH_CL_LEADIN) == GDB_ID_NULL) + return false ; + // secondo terzo + ptCen.z = ptTmp.z ; + pArc->GetPointD1D2( 2. / 3, ICurve::FROM_MINUS, ptTmp) ; + if ( AddArcMove( ptTmp, ptCen, dAngCen / 3, vtN, MCH_CL_LEADIN) == GDB_ID_NULL) + return false ; + // ultimo terzo + ptCen.z = ptTmp.z ; + if ( AddArcMove( ptP3, ptCen, dAngCen / 3, vtN, MCH_CL_LEADIN) == GDB_ID_NULL) + return false ; + } + return true ; + } + } + case MILL_LI_GLIDE : + // !!! DA FARE !!! + return false ; + case MILL_LI_ZIGZAG : + // !!! DA FARE !!! + return false ; + case MILL_LI_HELIX : + // !!! DA FARE !!! + return false ; + default : + return false ; + } +} + +//---------------------------------------------------------------------------- +bool +Pocketing::AddLeadOut( const Point3d& ptEnd, const Vector3d& vtEnd, const Vector3d& vtN, + bool bInvert, bool bSplitArcs, Point3d& ptP1) +{ + // assegno i parametri + int nType = m_Params.m_nLeadOutType ; + double dTang = m_Params.m_dLoTang ; + double dPerp = 0 ; + double dElev = 0 ; + // se uscita come ingresso o step invertito + if ( nType == MILL_LO_AS_LI || bInvert) { + switch ( m_Params.m_nLeadInType) { + case MILL_LI_LINEAR : nType = MILL_LO_LINEAR ; break ; + case MILL_LI_TANGENT : nType = MILL_LO_TANGENT ; break ; + case MILL_LI_GLIDE : nType = MILL_LO_GLIDE ; break ; + case MILL_LI_ZIGZAG : nType = MILL_LO_LINEAR ; break ; + case MILL_LI_HELIX : nType = MILL_LO_TANGENT ; break ; + default : nType = MILL_LO_NONE ; break ; + } + dTang = m_Params.m_dLiTang ; + dPerp = 0 ; + dElev = 0 ; + } + if ( bSplitArcs) { + if ( nType == MILL_LO_TANGENT) + nType = MILL_LO_LINEAR ; + } + // se parametri nulli, allora nessuna uscita + if ( abs( dTang) < EPS_SMALL && abs( dPerp) < EPS_SMALL ) + nType = MILL_LO_NONE ; + // senso di rotazione da dir tg a dir esterna + bool bCcwRot = true ; + // eseguo a seconda del tipo + switch ( nType) { + case MILL_LO_NONE : + ptP1 = ptEnd ; + return true ; + case MILL_LO_LINEAR : + { + if ( dTang < 10 * EPS_SMALL && abs( dPerp) < EPS_SMALL) + return false ; + Vector3d vtPerp = vtEnd ; + vtPerp.Rotate( vtN, ( bCcwRot ? 90 : - 90)) ; + ptP1 = ptEnd + vtEnd * dTang + vtPerp * dPerp + vtN * dElev ; + return ( AddLinearMove( ptP1, MCH_CL_LEADOUT) != GDB_ID_NULL) ; + } + case MILL_LO_TANGENT : + { + // calcolo punto finale dell'uscita + if ( dTang < 10 * EPS_SMALL && abs( dPerp) < EPS_SMALL) + return false ; + Vector3d vtPerp = vtEnd ; + vtPerp.Rotate( vtN, ( bCcwRot ? 90 : - 90)) ; + ptP1 = ptEnd + vtEnd * dTang + vtPerp * dPerp + vtN * dElev ; + // inserisco uscita + PtrOwner pCrv( GetArc2PVN( ptEnd, ptP1, vtEnd, vtN)) ; + if ( IsNull( pCrv)) + return false ; + if ( pCrv->GetType() == CRV_LINE) { + ICurveLine* pLine = GetCurveLine( pCrv) ; + Point3d ptP3 = pLine->GetEnd() ; + return ( AddLinearMove( ptP3, MCH_CL_LEADOUT) != GDB_ID_NULL) ; + } + else if ( pCrv->GetType() == CRV_ARC) { + ICurveArc* pArc = GetCurveArc( pCrv) ; + Point3d ptCen = pArc->GetCenter() ; + double dAngCen = pArc->GetAngCenter() ; + Vector3d vtN = pArc->GetNormVersor() ; + Point3d ptP3 ; + pArc->GetEndPoint( ptP3) ; + // se angolo al centro minore del limite, un solo arco + const double MAX_ANG_CEN = 150 + EPS_ANG_SMALL ; + if ( abs( dAngCen) < MAX_ANG_CEN) { + if ( AddArcMove( ptP3, ptCen, dAngCen, vtN, MCH_CL_LEADOUT) == GDB_ID_NULL) + return false ; + } + // altrimenti due archi + else if ( abs( dAngCen) < 2 * MAX_ANG_CEN){ + Point3d ptMid ; + pArc->GetMidPoint( ptMid) ; + // prima metà arco + if ( AddArcMove( ptMid, ptCen, dAngCen / 2, vtN, MCH_CL_LEADOUT) == GDB_ID_NULL) + return false ; + // seconda metà arco + ptCen.z = ptMid.z ; + if ( AddArcMove( ptP3, ptCen, dAngCen / 2, vtN, MCH_CL_LEADOUT) == GDB_ID_NULL) + return false ; + } + // oppure tre archi + else { + Point3d ptTmp ; + // primo terzo + pArc->GetPointD1D2( 1. / 3, ICurve::FROM_MINUS, ptTmp) ; + if ( AddArcMove( ptTmp, ptCen, dAngCen / 3, vtN, MCH_CL_LEADOUT) == GDB_ID_NULL) + return false ; + // secondo terzo + ptCen.z = ptTmp.z ; + pArc->GetPointD1D2( 2. / 3, ICurve::FROM_MINUS, ptTmp) ; + if ( AddArcMove( ptTmp, ptCen, dAngCen / 3, vtN, MCH_CL_LEADOUT) == GDB_ID_NULL) + return false ; + // ultimo terzo + ptCen.z = ptTmp.z ; + if ( AddArcMove( ptP3, ptCen, dAngCen / 3, vtN, MCH_CL_LEADOUT) == GDB_ID_NULL) + return false ; + } + return true ; + } + } + case MILL_LO_GLIDE : + // !!! DA FARE !!! + return false ; + default : + return false ; + } +} + +//---------------------------------------------------------------------------- +double +Pocketing::GetRadiusForStartEndElevation( void) +{ + const double DELTA_ELEV_RAD = 20.0 ; + return ( 0.5 * m_TParams.m_dTDiam + DELTA_ELEV_RAD) ; +} diff --git a/Pocketing.h b/Pocketing.h new file mode 100644 index 0000000..1bcdc81 --- /dev/null +++ b/Pocketing.h @@ -0,0 +1,107 @@ +//---------------------------------------------------------------------------- +// EgalTech 2017-2017 +//---------------------------------------------------------------------------- +// File :Pocketing.h Data : 04.02.17 Versione : 1.8b1 +// Contenuto : Dichiarazione della classe Pocketing. +// +// +// +// Modifiche : 04.02.17 DS Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +#pragma once + +#include "Machining.h" +#include "PocketingData.h" +#include "ToolData.h" + +class ICurve ; +class ICurveComposite ; + +//---------------------------------------------------------------------------- +class Pocketing : public Machining +{ + public : // IUserObj + Pocketing* Clone( void) const override ; + const std::string& GetClassName( void) const override ; + bool Dump( std::string& sOut, bool bMM = true, const char* szNewLine = "\n") const override ; + bool ToSave( void) const override + { return true ; } + bool Save( STRVECTOR& vString) const override ; + bool Load( const STRVECTOR& vString, int nBaseGdbId) override ; + + public : // Operation + bool IsEmpty( void) const override + { return ( m_nMills == 0) ; } + + protected : // Operation + int GetSolCh( void) const override + { return m_Params.m_nSolCh ; } + bool AdjustEndPointForAxesCalc( const CamData* pCamData, Point3d& ptP) const override ; + + public : // Machining + bool Prepare( const std::string& sMillName) override ; + bool SetParam( int nType, bool bVal) override ; + bool SetParam( int nType, int nVal) override ; + bool SetParam( int nType, double dVal) override ; + bool SetParam( int nType, const std::string& sVal) override ; + bool SetGeometry( const SELVECTOR& vIds) override ; + bool Preview( bool bRecalc) override ; + bool Apply( bool bRecalc) override ; + bool GetParam( int nType, bool& bVal) const override ; + bool GetParam( int nType, int& nVal) const override ; + bool GetParam( int nType, double& dVal) const override ; + bool GetParam( int nType, std::string& sVal) const override ; + const ToolData& GetToolData( void) const ; + bool GetGeometry( SELVECTOR& vIds) const override ; + + public : + Pocketing( void) ; + + private : + bool UpdateToolData( void) ; + bool VerifyGeometry( SelData Id, int& nSubs, int& nType) ; + ICurve* GetCurve( SelData Id) ; + bool AdjustCurveFromSurf( ICurveComposite* pCrvCompo) ; + bool Chain( int nGrpDestId) ; + bool ProcessPath( int nPathId, int nPvId, int nClId) ; + bool CalcPathElevation( const ICurveComposite* pCompo, const Vector3d& vtTool, double dDepth, double dRad, double& dElev) ; + bool VerifyPathFromBottom( const ICurveComposite* pCompo, const Vector3d& vtTool) ; + bool GenerateMillingPv( int nPathId, const ICurveComposite* pCompo) ; + bool AddStandardMilling( const ICurveComposite* pCompo, const Vector3d& vtTool, const Vector3d& vtExtr, + double dDepth, double dElev, bool bSplitArcs) ; + bool AddApproach( const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dElev, double dAppr) ; + bool AddRetract( const Point3d& ptP, const Vector3d& vtTool, double dSafeZ, double dElev, double dAppr) ; + bool CalcLeadInStart( const Point3d& ptStart, const Vector3d& vtStart, const Vector3d& vtN, bool bInvert, + Point3d& ptP1) ; + bool AddLeadIn( const Point3d& ptP1, const Point3d& ptStart, const Vector3d& vtStart, + const Vector3d& vtN, bool bInvert, bool bSplitArcs) ; + bool AddLeadOut( const Point3d& ptEnd, const Vector3d& vtEnd, const Vector3d& vtN, + bool bInvert, bool bSplitArcs, Point3d& ptP1) ; + double GetRadiusForStartEndElevation( void) ; + + private : + double GetSpeed() const + { return ( abs( m_Params.m_dSpeed) < EPS_MACH_ANG_PAR ? m_TParams.m_dSpeed : m_Params.m_dSpeed) ; } + double GetFeed() const + { return ( abs( m_Params.m_dFeed) < EPS_MACH_LEN_PAR ? m_TParams.m_dFeed : m_Params.m_dFeed) ; } + double GetStartFeed() const + { return ( abs( m_Params.m_dStartFeed) < EPS_MACH_LEN_PAR ? m_TParams.m_dStartFeed : m_Params.m_dStartFeed) ; } + double GetEndFeed() const + { return ( abs( m_Params.m_dEndFeed) < EPS_MACH_LEN_PAR ? m_TParams.m_dEndFeed : m_Params.m_dEndFeed) ; } + double GetTipFeed() const + { return ( abs( m_Params.m_dTipFeed) < EPS_MACH_LEN_PAR ? m_TParams.m_dTipFeed : m_Params.m_dTipFeed) ; } + double GetOffsL() const + { return ( abs( m_Params.m_dOffsL - UNKNOWN_PAR) < EPS_MACH_LEN_PAR ? m_TParams.m_dOffsL : m_Params.m_dOffsL) ; } + double GetOffsR() const + { return ( abs( m_Params.m_dOffsR - UNKNOWN_PAR) < EPS_MACH_LEN_PAR ? m_TParams.m_dOffsR : m_Params.m_dOffsR) ; } + + private : + SELVECTOR m_vId ; // identificativi entità geometriche da lavorare + PocketingData m_Params ; // parametri lavorazione + ToolData m_TParams ; // parametri utensile + int m_nMills ; // numero di percorsi di lavoro generati + bool m_bAggrBottom ; // flag di utilizzo dell'aggregato da sotto +} ; \ No newline at end of file