//---------------------------------------------------------------------------- // EgalTech 2015-2015 //---------------------------------------------------------------------------- // File : Sawing.cpp Data : 24.10.15 Versione : 1.6j3 // Contenuto : Implementazione gestione tagli con lama. // // Note : Questa lavorazione è sempre espressa nel riferimento globale. // // Modifiche : 07.06.15 DS Creazione modulo. // // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "MachMgr.h" #include "DllMain.h" #include "Sawing.h" #include "MachiningConst.h" #include "CamData.h" #include "/EgtDev/Include/EXeExecutor.h" #include "/EgtDev/Include/EGkCurveLine.h" #include "/EgtDev/Include/EGkCurveComposite.h" #include "/EgtDev/Include/EgkChainCurves.h" #include "/EgtDev/Include/EGkUserObjFactory.h" #include "/EgtDev/Include/EGnStringKeyVal.h" #include "/EgtDev/Include/EgtPointerOwner.h" // per far dimenticare macro di WinUser.h #undef GetClassName using namespace std ; //---------------------------------------------------------------------------- USEROBJ_REGISTER( "EMkSawing", Sawing) ; //---------------------------------------------------------------------------- const string& Sawing::GetClassName( void) const { return USEROBJ_GETNAME( Sawing) ; } //---------------------------------------------------------------------------- Sawing* Sawing::Clone( void) const { // alloco oggetto Sawing* pSaw = new(nothrow) Sawing ; // eseguo copia dei dati if ( pSaw != nullptr) { try { pSaw->m_nOwnerId = GDB_ID_NULL ; pSaw->m_pGeomDB = nullptr ; pSaw->m_Params = m_Params ; pSaw->m_TParams = m_TParams ; } catch( ...) { delete pSaw ; return nullptr ; } } // ritorno l'oggetto return pSaw ; } //---------------------------------------------------------------------------- bool Sawing::Dump( string& sOut, bool bMM, const char* szNewLine) const { sOut += GetClassName() + "[mm]" + 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 ; return true ; } //---------------------------------------------------------------------------- bool Sawing::Save( STRVECTOR& vString) const { try { int nSize = 1 + m_Params.GetSize() + m_TParams.GetSize() ; 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) ; } catch( ...) { return false ; } return true ; } //---------------------------------------------------------------------------- bool Sawing::Load( const STRVECTOR& vString) { int nSize = 1 + m_Params.GetSize() + m_TParams.GetSize() ; if ( int( vString.size()) < nSize) return false ; int k = - 1 ; if ( ! GetVal( vString[++k], KEY_IDS, m_vId)) return false ; for ( int i = 0 ; i < m_Params.GetSize() ; ++ i) { int nKey ; if ( ! m_Params.FromString( vString[++k], nKey) || nKey != i) return false ; } for ( int i = 0 ; i < m_TParams.GetSize() ; ++ i) { int nKey ; if ( ! m_TParams.FromString( vString[++k], nKey) || nKey != i) return false ; } return true ; } //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- Sawing::Sawing( void) { m_nOwnerId = GDB_ID_NULL ; m_pGeomDB = nullptr ; m_Params.m_sName = "*" ; m_Params.m_sToolName = "*" ; m_TParams.m_sName = "*" ; m_TParams.m_sHead = "*" ; } //---------------------------------------------------------------------------- bool Sawing::Prepare( const string& sSawName) { // verifico il gestore lavorazioni if ( m_pMchMgr == nullptr) return false ; // recupero il gestore DB utensili della macchina corrente ToolsMgr* pTMgr = m_pMchMgr->GetCurrToolsMgr() ; if ( pTMgr == nullptr) return false ; // recupero il gestore DB lavorazioni della macchina corrente MachiningsMgr* pMMgr = m_pMchMgr->GetCurrMachiningsMgr() ; if ( pMMgr == nullptr) return false ; // ricerca della lavorazione di libreria con il nome indicato const SawingData* pDdata = GetSawingData( pMMgr->GetMachining( sSawName)) ; if ( pDdata == nullptr) return false ; m_Params = *pDdata ; // ricerca dell'utensile usato dalla lavorazione const ToolData* pTdata = pTMgr->GetTool( m_Params.m_ToolUuid) ; if ( pTdata == nullptr) return false ; m_TParams = *pTdata ; m_Params.m_sToolName = m_TParams.m_sName ; return true ; } //---------------------------------------------------------------------------- bool Sawing::SetParam( int nType, bool bVal) { switch ( nType) { case MPA_INVERT : m_Params.m_bInvert = bVal ; return true ; case MPA_TOANDFROM : m_Params.m_bToAndFrom = bVal ; return true ; } return false ; } //---------------------------------------------------------------------------- bool Sawing::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_HEADSIDE : if ( ! m_Params.VerifyHeadSide( nVal)) return false ; m_Params.m_nHeadSide = nVal ; return true ; case MPA_LEADINTYPE : if ( ! m_Params.VerifyLeadInType( nVal)) return false ; m_Params.m_nLeadInType = nVal ; return true ; case MPA_EXTLINKTYPE : if ( ! m_Params.VerifyExtLinkType( nVal)) return false ; m_Params.m_nExtLinkType = nVal ; return true ; case MPA_LEADOUTTYPE : if ( ! m_Params.VerifyLeadOutType( nVal)) return false ; m_Params.m_nLeadOutType = nVal ; return true ; case MPA_CURVEUSE : if ( ! m_Params.VerifyCurveUse( nVal)) return false ; m_Params.m_nCurveUse = nVal ; return true ; } return false ; } //---------------------------------------------------------------------------- bool Sawing::SetParam( int nType, double dVal) { switch ( nType) { case MPA_TOOLSPEED : if ( ! m_TParams.VerifySpeed( dVal)) return false ; m_TParams.m_dSpeed = dVal ; return true ; case MPA_TOOLFEED : m_TParams.m_dFeed = dVal ; return true ; case MPA_TOOLSTARTFEED : m_TParams.m_dStartFeed = dVal ; return true ; case MPA_TOOLENDFEED : m_TParams.m_dEndFeed = dVal ; return true ; case MPA_TOOLTIPFEED : m_TParams.m_dTipFeed = dVal ; return true ; case MPA_TOOLOFFSR : m_TParams.m_dOffsR = dVal ; return true ; case MPA_TOOLOFFSL : m_TParams.m_dOffsL = dVal ; return true ; case MPA_DEPTH : m_Params.m_sDepth = ToString( dVal) ; return true ; case MPA_SIDEANGLE : if ( ! m_Params.VerifySideAngle( dVal)) return false ; m_Params.m_dSideAngle = dVal ; return true ; case MPA_APPROX : m_Params.m_dApprox = dVal ; return true ; } return false ; } //---------------------------------------------------------------------------- bool Sawing::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 ; } return true ; case MPA_DEPTH_STR : m_Params.m_sDepth = sVal ; return true ; } return false ; } //---------------------------------------------------------------------------- bool Sawing::SetGeometry( const SELVECTOR& vIds) { // verifico validità gestore DB geometrico if ( m_pGeomDB == nullptr) return false ; // reset della geometria corrente m_vId.clear() ; // verifico che gli identificativi rappresentino delle entità ammissibili for ( const auto& Id : vIds) { // test sull'entità int nSubs ; if ( ! VerifyGeometry( Id, nSubs)) { string sOut = "Entity " + ToString( Id) + " skipped by Sawing" ; LOG_INFO( GetEMkLogger(), sOut.c_str()) ; continue ; } // posso aggiungere alla lista if ( nSubs == 0) m_vId.emplace_back( Id) ; else { for ( int i = 0 ; i < nSubs ; ++ i) m_vId.emplace_back( Id.nId, i) ; } } return ( ! m_vId.empty()) ; } //---------------------------------------------------------------------------- bool Sawing::Apply( void) { // 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) ; // 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) ; } // altrimenti lo svuoto else m_pGeomDB->EmptyGroup( nAuxId) ; // verifiche per angolo di sbandamento if ( ! VerifySideAngle()) return false ; // eseguo concatenamento, inserisco i percorsi sotto la geometria ausiliaria if ( ! 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) { PathApply( nPathId, nClId) ; nPathId = m_pGeomDB->GetNextGroup( nPathId) ; } // calcolo gli assi macchina return CalculateAxesValues() ; } //---------------------------------------------------------------------------- bool Sawing::GetParam( int nType, bool& bVal) const { switch ( nType) { case MPA_INVERT : bVal = m_Params.m_bInvert ; return true ; case MPA_TOANDFROM : bVal = m_Params.m_bToAndFrom ; return true ; } return false ; } //---------------------------------------------------------------------------- bool Sawing::GetParam( int nType, int& nVal) const { switch ( nType) { case MPA_WORKSIDE : nVal = m_Params.m_nWorkSide ; return true ; case MPA_HEADSIDE : nVal = m_Params.m_nHeadSide ; return true ; case MPA_LEADINTYPE : nVal = m_Params.m_nLeadInType ; return true ; case MPA_EXTLINKTYPE : nVal = m_Params.m_nExtLinkType ; return true ; case MPA_LEADOUTTYPE : nVal = m_Params.m_nLeadOutType ; return true ; case MPA_CURVEUSE : nVal = m_Params.m_nCurveUse ; return true ; } return false ; } //---------------------------------------------------------------------------- bool Sawing::GetParam( int nType, double& dVal) const { switch ( nType) { case MPA_TOOLSPEED : dVal = m_TParams.m_dSpeed ; return true ; case MPA_TOOLFEED : dVal = m_TParams.m_dFeed ; return true ; case MPA_TOOLSTARTFEED : dVal = m_TParams.m_dStartFeed ; return true ; case MPA_TOOLENDFEED : dVal = m_TParams.m_dEndFeed ; return true ; case MPA_TOOLTIPFEED : dVal = m_TParams.m_dTipFeed ; return true ; case MPA_TOOLOFFSR : dVal = m_TParams.m_dOffsR ; return true ; case MPA_TOOLOFFSL : dVal = m_TParams.m_dOffsL ; return true ; case MPA_SIDEANGLE : dVal = m_Params.m_dSideAngle ; return true ; case MPA_APPROX : dVal = m_Params.m_dApprox ; return true ; } return false ; } //---------------------------------------------------------------------------- bool Sawing::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 ; } return false ; } //---------------------------------------------------------------------------- const ToolData& Sawing::GetToolData( void) const { return m_TParams ; } //---------------------------------------------------------------------------- bool Sawing::VerifyGeometry( SelData Id, int& nSubs) { // ammessi : curve o facce di polymesh // per ora accetto solo curve const ICurve* pCurve = nullptr ; const IGeoObj* pGObj = m_pGeomDB->GetGeoObj( Id.nId) ; // se direttamente la curva if ( Id.nSub == SEL_SUB_ALL) { pCurve = ::GetCurve( m_pGeomDB->GetGeoObj( Id.nId)) ; if ( pCurve != nullptr) { if ( pCurve->GetType() == CRV_COMPO) nSubs = ::GetCurveComposite( pCurve)->GetCurveCount() ; else nSubs = 0 ; } } // altrimenti sottocurva di composita else { const ICurveComposite* pCompo = GetCurveComposite( m_pGeomDB->GetGeoObj( Id.nId)) ; if ( pCompo != nullptr) pCurve = pCompo->GetCurve( Id.nSub) ; nSubs = 0 ; } return ( pCurve != nullptr) ; } //---------------------------------------------------------------------------- ICurve* Sawing::GetCurve( SelData Id) { // ammessi : curve o facce di polymesh // nel caso di facce si deve recuperare la linea di base // per ora accetto solo curve PtrOwner pCurve ; // se direttamente curva if ( Id.nSub == SEL_SUB_ALL) { // recupero e duplico la curva const ICurve* pOriCurve = ::GetCurve( m_pGeomDB->GetGeoObj( Id.nId)) ; if ( pOriCurve != nullptr) pCurve.Set( pOriCurve->Clone()) ; } // altrimenti sottocurva di composita else { // recupero la composita const ICurveComposite* pCompo = GetCurveComposite( m_pGeomDB->GetGeoObj( Id.nId)) ; if ( pCompo != nullptr) { // duplico la curva semplice const ICurve* pOriCurve = ::GetCurve( pCompo->GetCurve( Id.nSub)) ; if ( pOriCurve != nullptr) { pCurve.Set( pOriCurve->Clone()) ; // recupero estrusione e spessore Vector3d vtExtr ; if ( pCompo->GetExtrusion( vtExtr)) pCurve->SetExtrusion( vtExtr) ; double dThick ; if ( pCompo->GetThickness( dThick)) pCurve->SetThickness( dThick) ; } } } if ( IsNull( pCurve)) return nullptr ; // ne recupero il riferimento globale Frame3d frGlob ; if ( ! m_pGeomDB->GetGlobFrame( Id.nId, frGlob)) return nullptr ; // la porto in globale pCurve->ToGlob( frGlob) ; // la restituisco return Release( pCurve) ; } //---------------------------------------------------------------------------- bool Sawing::VerifySideAngle( void) { // verifiche per angolo di sbandamento if ( fabs( m_Params.m_dSideAngle) > EPS_ANG_SMALL) { // non ammesso lato di lavoro in centro if ( m_Params.m_nWorkSide == SAW_WS_CENTER) { LOG_INFO( GetEMkLogger(), "Center work not allowed with side angle") ; return false ; } // se angolo esterno lato mandrino deve uguagliare lato di lavoro if ( m_Params.m_dSideAngle > 0) { if ( m_Params.m_nWorkSide == SAW_WS_RIGHT) { if ( m_Params.m_nHeadSide == SAW_HS_LEFT) { LOG_INFO( GetEMkLogger(), "External side angle HeadSide must equal WorkSide") ; m_Params.m_nHeadSide = SAW_HS_RIGHT ; } } if ( m_Params.m_nWorkSide == SAW_WS_LEFT) { if ( m_Params.m_nHeadSide == SAW_HS_RIGHT) { LOG_INFO( GetEMkLogger(), "External side angle HeadSide must equal WorkSide") ; m_Params.m_nHeadSide = SAW_HS_LEFT ; } } } // altrimenti angolo interno, lato mandrino deve essere opposto a lato di lavoro else { if ( m_Params.m_nWorkSide == SAW_WS_RIGHT) { if ( m_Params.m_nHeadSide == SAW_HS_RIGHT) { LOG_INFO( GetEMkLogger(), "Internal side angle HeadSide must opposite WorkSide") ; m_Params.m_nHeadSide = SAW_HS_LEFT ; } } if ( m_Params.m_nWorkSide == SAW_WS_LEFT) { if ( m_Params.m_nHeadSide == SAW_HS_LEFT) { LOG_INFO( GetEMkLogger(), "Internal side angle HeadSide must opposite WorkSide") ; m_Params.m_nHeadSide = SAW_HS_RIGHT ; } } } } return true ; } //---------------------------------------------------------------------------- bool Sawing::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 Sawing" ; LOG_INFO( GetEMkLogger(), sOut.c_str()) ; vpCrvs.back().Reset() ; } } // preparo i dati per il concatenamento 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 = Get( 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 ; } // recupero i percorsi concatenati int nCount = 0 ; Point3d ptNear = ORIG ; 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 = Get( 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 Sawing::PathApply( int nPathId, 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)) ; // elaboro la curva composita e la esplodo nelle curve componenti if ( m_Params.m_nCurveUse == SAW_CRV_APPROX || m_Params.m_nCurveUse == SAW_CRV_CONVEX) { // calcolo l'approssimazione lineare con eventuale convessità PolyLine PL ; int nType = ICurve::APL_STD ; if ( m_Params.m_nWorkSide == SAW_WS_LEFT) nType = (( m_Params.m_nCurveUse == SAW_CRV_APPROX) ? ICurve::APL_LEFT : ICurve::APL_LEFT_CONVEX) ; else if ( m_Params.m_nWorkSide == SAW_WS_RIGHT) nType = (( m_Params.m_nCurveUse == SAW_CRV_APPROX) ? ICurve::APL_RIGHT : ICurve::APL_RIGHT_CONVEX) ; if ( ! pCompo->ApproxWithLines( m_Params.m_dApprox, ANG_RIGHT, nType, PL)) return false ; // salvo estrusione e spessore Vector3d vtExtr ; pCompo->GetExtrusion( vtExtr) ; double dThick ; pCompo->GetThickness( dThick) ; // sostituisco la curva composita con la sua approssimazione if ( ! pCompo->Clear() || ! pCompo->FromPolyLine( PL)) return false ; // assegno estrusione e spessore originali pCompo->SetExtrusion( vtExtr) ; pCompo->SetThickness( dThick) ; } // se lama non centrata e richiesto, eseguo offset if ( m_Params.m_nWorkSide != SAW_WS_CENTER && fabs( m_TParams.m_dOffsL) > EPS_SMALL) { double dOffs = ( m_Params.m_nWorkSide == SAW_WS_RIGHT) ? m_TParams.m_dOffsL : - m_TParams.m_dOffsL ; if ( ! pCompo->SimpleOffset( dOffs, ICurve::OFF_EXTEND)) return false ; } // unisco le parti allineate if ( ! pCompo->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL)) return false ; // eventuale inversione percorso if ( m_Params.m_bInvert) pCompo->Invert() ; // recupero estrusione e spessore Vector3d vtExtr ; pCompo->GetExtrusion( vtExtr) ; double dThick ; pCompo->GetThickness( dThick) ; // valuto l'espressione dell'affondamento string sExec = "TH=" + (( dThick * vtExtr.z < 0) ? ToString( fabs( dThick)) : ToString( 0)) ; ExeLuaExecLine( sExec) ; double dDepth ; if ( ! ExeLuaEvalNumExpr( m_Params.m_sDepth, &dDepth)) { string sOut = "Depth not computable by Sawing" ; LOG_INFO( GetEMkLogger(), sOut.c_str()) ; return false ; } // correzione per angolo di fianco if ( fabs( m_Params.m_dSideAngle) > EPS_ANG_SMALL) { // generale dDepth /= cos( m_Params.m_dSideAngle * DEGTORAD) ; // se sottosquadra (controllo il lato opposto della lama, quindi ...) if ( m_Params.m_dSideAngle < 0) dDepth += m_TParams.m_dThick * tan( abs( m_Params.m_dSideAngle) * DEGTORAD) ; } // verifico di non superare il massimo materiale if ( dDepth > m_TParams.m_dMaxMat) { string sOut = "Depth bigger than MaxMaterial" ; LOG_INFO( GetEMkLogger(), sOut.c_str()) ; return false ; } // recupero nome del path string sPathName ; m_pGeomDB->GetName( nPathId, sPathName) ; // ciclo sulle curve elementari bool bClosed = pCompo->IsClosed() ; int nMaxInd = pCompo->GetCurveCount() - 1 ; for ( int i = 0 ; i <= nMaxInd ; ++ i) { // curva precedente int j = (( i == 0 && bClosed) ? nMaxInd : i - 1) ; const ICurve* pCrvP = pCompo->GetCurve( j) ; ; // curva corrente const ICurve* pCrvC = pCompo->GetCurve( i) ; // curva successiva int k = (( i == nMaxInd && bClosed) ? 0 : i + 1) ; const ICurve* pCrvN = pCompo->GetCurve( k) ; // elaborazioni sulla curva corrente string sName = sPathName + "_" + ToString( i) ; if ( ! EntityApply( pCrvP, pCrvC, pCrvN, dDepth, i == 0, i == nMaxInd, sName, nClId)) return false ; } return true ; } //---------------------------------------------------------------------------- bool Sawing::EntityApply( const ICurve* pCrvP, const ICurve* pCrvC, const ICurve* pCrvN, double dDepth, bool bIsFirst, bool bIsLast, const string& sName, int nClId) { // se non è una linea, la salto if ( pCrvC->GetType() != CRV_LINE) return true ; // creo gruppo per geometria di lavorazione della linea int nPxId = m_pGeomDB->AddGroup( GDB_ID_NULL, nClId, Frame3d()) ; if ( nPxId == GDB_ID_NULL) return false ; m_pGeomDB->SetName( nPxId, sName) ; m_pGeomDB->SetMaterial( nPxId, BLUE) ; // copio la curva PtrOwner pLine( GetCurveLine( pCrvC->Clone())) ; // calcolo i versori fresa e correzione Vector3d vtTool, vtCorr ; if ( ! CalculateToolAndCorrVersors( Get( pLine), vtTool, vtCorr)) { string sOut = "Entity not versorable by Sawing" ; LOG_INFO( GetEMkLogger(), sOut.c_str()) ; return false ; } // correzioni per lato lama, lato mandrino if ( ! AdjustForSide( Get( pLine))) { string sOut = "Entity not offsetable by Sawing" ; LOG_INFO( GetEMkLogger(), sOut.c_str()) ; return false ; } // aggiungo affondamento pLine->Translate( - vtCorr * dDepth) ; // calcolo elevazione double dElev ; if ( ! GetElevation( pLine->GetStart(), pLine->GetEnd(), vtCorr, dElev)) { string sOut = "Entity not elevation-enabled by Sawing" ; LOG_INFO( GetEMkLogger(), sOut.c_str()) ; return false ; } // direzione linea corrente Vector3d vtDirC ; pLine->GetStartDir( vtDirC) ; // calcolo tipo angolo con precedente bool bExtAngPC = true ; if ( pCrvP != nullptr) { Vector3d vtDirP ; pCrvP->GetEndDir( vtDirP) ; double dAngPC ; vtDirP.GetAngleXY( vtDirC, dAngPC) ; if ( ( m_Params.m_nWorkSide == SAW_WS_LEFT && dAngPC > EPS_ANG_SMALL) || ( m_Params.m_nWorkSide == SAW_WS_RIGHT && dAngPC < - EPS_ANG_SMALL)) bExtAngPC = false ; } // calcolo tipo angolo con successivo bool bExtAngCN = true ; if ( pCrvN != nullptr) { Vector3d vtDirN ; pCrvN->GetStartDir( vtDirN) ; double dAngCN ; vtDirC.GetAngleXY( vtDirN, dAngCN) ; if ( ( m_Params.m_nWorkSide == SAW_WS_LEFT && dAngCN > EPS_ANG_SMALL) || ( m_Params.m_nWorkSide == SAW_WS_RIGHT && dAngCN < - EPS_ANG_SMALL)) bExtAngCN = false ; } // aggiusto per tipo estremi AdjustForEdges( Get( pLine), dElev, bIsFirst, bIsLast, bExtAngPC, bExtAngCN) ; // recupero distanza di approccio double dAppr = GetApproachDist() ; // correzione per angolo di fianco if ( fabs( m_Params.m_dSideAngle) > EPS_ANG_SMALL) dAppr /= cos( m_Params.m_dSideAngle * DEGTORAD) ; // imposto dati comuni SetPathId( nPxId) ; SetToolDir( vtTool) ; SetCorrDir( vtCorr) ; // 1 -> punto sopra inizio Point3d ptP1 = pLine->GetStart() + vtCorr * ( dElev + dAppr) ; if ( AddStart( ptP1) == GDB_ID_NULL) return false ; // 2 -> movimento al punto iniziale SetFeed( m_TParams.m_dTipFeed) ; Point3d ptP2 = pLine->GetStart() ; if ( AddLinearMove( ptP2) == GDB_ID_NULL) return false ; // 3 -> movimento al punto finale SetFeed( m_TParams.m_dFeed) ; Point3d ptP3 = pLine->GetEnd() ; if ( AddLinearMove( ptP3) == GDB_ID_NULL) return false ; // 4 -> movimento di risalita sopra il punto finale SetFeed( m_TParams.m_dFeed) ; Point3d ptP4 = pLine->GetEnd() + vtCorr * ( dElev + dAppr) ; if ( AddLinearMove( ptP4) == GDB_ID_NULL) return false ; return true ; } //---------------------------------------------------------------------------- bool Sawing::CalculateToolAndCorrVersors( const ICurve* pCurve, Vector3d& vtTool, Vector3d& vtCorr) { // Recupero la direzione della linea e la proietto nel piano XY Vector3d vtTang ; pCurve->GetStartDir( vtTang) ; vtTang.z = 0 ; if ( ! vtTang.Normalize()) return false ; // Versore fresa : annullo la componente in Z e normalizzo vtTool = vtTang ; // ruoto attorno a Zglob+ a seconda del lato mandrino if ( m_Params.m_nHeadSide == SAW_HS_LEFT) vtTool.Rotate( Z_AX, 90) ; else vtTool.Rotate( Z_AX, -90) ; // Versore correzione vtCorr = Z_AX ; // Se lama sbandata if ( fabs( m_Params.m_dSideAngle) > EPS_ANG_SMALL) { if ( m_Params.m_nWorkSide == SAW_WS_RIGHT) { vtTool.Rotate( vtTang, - m_Params.m_dSideAngle) ; vtCorr.Rotate( vtTang, - m_Params.m_dSideAngle) ; } else { vtTool.Rotate( vtTang, m_Params.m_dSideAngle) ; vtCorr.Rotate( vtTang, m_Params.m_dSideAngle) ; } } return true ; } //---------------------------------------------------------------------------- bool Sawing::AdjustForSide( ICurve* pCurve) { // se lato lavoro e lato mandrino coincidono, non devo fare alcunché if ( ( m_Params.m_nWorkSide == SAW_WS_LEFT && m_Params.m_nHeadSide == SAW_HS_LEFT) || ( m_Params.m_nWorkSide == SAW_WS_RIGHT && m_Params.m_nHeadSide == SAW_HS_RIGHT)) return true ; // calcolo offset curva double dOffs = 0 ; if ( m_Params.m_nWorkSide == SAW_WS_LEFT) dOffs = - m_TParams.m_dThick ; else if ( m_Params.m_nWorkSide == SAW_WS_RIGHT) dOffs = m_TParams.m_dThick ; else if ( m_Params.m_nHeadSide == SAW_HS_LEFT) // lama in centro dOffs = 0.5 * m_TParams.m_dThick ; else // testa a destra e lama in centro dOffs = - 0.5 * m_TParams.m_dThick ; // correzione per angolo di fianco if ( fabs( m_Params.m_dSideAngle) > EPS_ANG_SMALL) dOffs /= cos( m_Params.m_dSideAngle * DEGTORAD) ; // eseguo offset curva ( nel piano XY globale) return pCurve->SimpleOffset( dOffs) ; } //---------------------------------------------------------------------------- bool Sawing::AdjustForEdges( ICurveLine* pLine, double dElev, bool bIsFirst, bool bIsLast, bool bExtAngPC, bool bExtAngCN) { // distanza XY tra centro e bordo taglio double dDeltaT = (( dElev < 0.5 * m_TParams.m_dDiam) ? sqrt( dElev * m_TParams.m_dDiam - dElev * dElev) : 0) ; // verifiche e aggiustamenti sull'inizio double dDeltaI = 0 ; if ( ! bExtAngPC) dDeltaI = - dDeltaT ; else if ( bIsFirst) { if ( m_Params.m_nLeadInType == SAW_LI_STRICT) dDeltaI = - dDeltaT ; else if ( m_Params.m_nLeadInType == SAW_LI_OUT) dDeltaI = dDeltaT ; else if ( m_Params.m_nLeadInType == SAW_LI_EXT_CENT) ; // estendere al bordo del grezzo else if ( m_Params.m_nLeadInType == SAW_LI_EXT_OUT) ; // estendere al bordo del grezzo e aggiungere dDeltaT } else { if ( m_Params.m_nExtLinkType == SAW_EL_EXT_NEXT || m_Params.m_nExtLinkType == SAW_EL_EXT_BOTH) { ; // estendere al bordo del grezzo se LeadIn EXT_OUT aggiungere dDeltaT } } // verifiche e aggiustamenti sulla fine double dDeltaF = 0 ; if ( ! bExtAngCN) dDeltaF = - dDeltaT ; else if ( bIsLast) { if ( m_Params.m_nLeadOutType == SAW_LI_STRICT) dDeltaF = - dDeltaT ; else if ( m_Params.m_nLeadInType == SAW_LO_EXT) ; // estendere al bordo del grezzo } else { if ( m_Params.m_nExtLinkType == SAW_EL_EXT_PREV || m_Params.m_nExtLinkType == SAW_EL_EXT_BOTH) { ; // estendere al bordo del grezzo } } // controllo se lunghezza entità accettabile const double MIN_LEN = 10 ; double dLenXY = DistXY( pLine->GetStart(), pLine->GetEnd()) ; if ( dDeltaI + dLenXY + dDeltaF < MIN_LEN) return false ; // modifico gli estremi if ( dDeltaF > EPS_SMALL) pLine->ExtendEndByLen( dDeltaF) ; else if ( dDeltaF < - EPS_SMALL) pLine->TrimEndAtLen( dLenXY + dDeltaF) ; if ( dDeltaI > EPS_SMALL) pLine->ExtendStartByLen( dDeltaI) ; else if ( dDeltaI < - EPS_SMALL) pLine->TrimStartAtLen( fabs( dDeltaI)) ; return true ; } //---------------------------------------------------------------------------- bool Sawing::AdjustPositionForAxesCalc( const CamData* pCamData, Point3d& ptP) { // compenso il raggio dell'utensile ptP += pCamData->GetCorrDir() * ( m_TParams.m_dDiam / 2) ; return true ; }