From f258acefd0adac38e78f7a17c28924dd8cb19b17 Mon Sep 17 00:00:00 2001 From: Riccardo Elitropi Date: Tue, 16 Dec 2025 15:44:29 +0100 Subject: [PATCH] EgtNumKernel 2.7l1 : - in Machining Optimization aggiunta ottimizzazione mirata ai singoli gruppi. --- EgtNumKernel.rc | Bin 11670 -> 11670 bytes MachOptimization.cpp | 314 ++++++++++++++++++++++++++++++++++--------- MachOptimization.h | 7 + 3 files changed, 259 insertions(+), 62 deletions(-) diff --git a/EgtNumKernel.rc b/EgtNumKernel.rc index 66e1368af869e1afb9f10aaca489b399ef383acd..48ef265a7d24a2df063f4c51f87627b2d7d8e1f3 100644 GIT binary patch delta 281 zcmbOhJuP~}I%aiGhCGIJh8%`ehGHOAV9;O)W+-7u1ma8}FBB-731UxPs3kr5pIX-D zIF?yVj7FOeik)YgEWo2P*+G$G@&id3<{SpY$&4bpn{}j|7&muuyD)J{Rj3l`A;N*2W^Clls6A{b@`^gjRryQVP5Hq)$ delta 241 zcmbOhJuP~}I%aKGhCGIJh8%`WhGK>c1_cHUhESkLCPN8BDnkm89}HwAf_cT07ivjw z{=m$_%xJiIy_`HVWA^6rip7kZJGh-7Lg$$#_ekb|g$o%sR|vac6V8%`3PTM@CDjcF qC$H0)H+h$u2rtOBo?!RoFjRtEH~9l|*5(v-9cEOi%?q`@G64XfwL=R4 diff --git a/MachOptimization.cpp b/MachOptimization.cpp index 3afad5d..77c16e4 100644 --- a/MachOptimization.cpp +++ b/MachOptimization.cpp @@ -59,6 +59,7 @@ MachOptimization::MachOptimization( void) m_dFeedL = 1. ; m_dFeedA = 1. ; m_bAllMandatory = false ; + m_bOptInGroup = false ; } //---------------------------------------------------------------------------- @@ -233,6 +234,14 @@ MachOptimization::SetAllGroupsAsMandatory( bool bAllMandatory) return true ; } +//---------------------------------------------------------------------------- +bool +MachOptimization::SetOptimizationForGroups( bool bOptForGroups) +{ + m_bOptInGroup = bOptForGroups ; + return true ; +} + //---------------------------------------------------------------------------- /* Funzione che assegna le dipendenze suggerite in base ai Gruppi */ bool @@ -469,6 +478,14 @@ MachOptimization::CalcMachTime( int nInd1, int nInd2, int& nTime) MachOptm& Lav1 = m_vMachOptm[nInd1] ; MachOptm& Lav2 = m_vMachOptm[nInd2] ; + return ( CalcMachTime( Lav1, Lav2, nTime)) ; +} + +//---------------------------------------------------------------------------- +/* Funzione per calcolare il tempo nel passare da una lavorazione all'altra */ +bool +MachOptimization::CalcMachTime( const MachOptm& Lav1, const MachOptm& Lav2, int& nTime) +{ // Se l'utensile è lo stesso if ( Lav1.nIdTool == Lav2.nIdTool) nTime = int( max( CalcTimeLavLav( Lav1, Lav2, true), CalcTimeLavLav( Lav1, Lav2, false))) ; @@ -494,8 +511,6 @@ bool MachOptimization::ComputeTimeMatrix( INTMATRIX& mTimes) { // Creo una copia dei vettori delle dipendenze ( le cancello di volta in volta che le assegno) - INTINTVECTOR vDep = m_vDependences ; - INTINTVECTOR vSuggDep = m_vSuggDependences ; const int N = int( m_vMachOptm.size()) ; // Matrice NxN ( con Flag per cella già calcolata) mTimes.clear() ; @@ -573,6 +588,70 @@ MachOptimization::GetIndById( int nId) return -1 ; } +//---------------------------------------------------------------------------- +/* Funzione per separare le lavorazioni e le dipendenze a seconda dei gruppi */ +bool +MachOptimization::SplitMachOptsInGroups( MACHOPTMMATRIX& matMachOpt, vector& matDep, + vector& matSuggDep) +{ + // Se non ho lavorazioni, non faccio nulla + if ( m_vMachOptm.empty()) + return true ; + // Se non devo ottimizzare per gruppi, errore + if ( ! m_bOptInGroup) + return false ; + + // Ordino le lavorazioni in base al gruppo + sort( m_vMachOptm.begin(), m_vMachOptm.end(), []( const MachOptm& MachA, const MachOptm& MachB) { + return ( MachA.nGroup > MachB.nGroup) ; + }) ; + + // Separo le lavorazioni + int nHighestPriority = m_vMachOptm[0].nGroup ; + matMachOpt.emplace_back( MACHOPTMVECTOR{}) ; + matMachOpt.back().emplace_back( m_vMachOptm[0]) ; + for ( int i = 1 ; i < int( m_vMachOptm.size()) ; ++ i) { + if ( m_vMachOptm[i].nGroup < nHighestPriority) { + matMachOpt.emplace_back( MACHOPTMVECTOR{}) ; + nHighestPriority = m_vMachOptm[i].nGroup ; + } + matMachOpt.back().emplace_back( m_vMachOptm[i]) ; + } + + // Recupero le Dipendeze Obbligatorie e Suggerite tra i vari gruppi + BOOLVECTOR vbDep( m_vDependences.size(), false) ; + BOOLVECTOR vbSuggDep( m_vSuggDependences.size(), false) ; + for ( const MACHOPTMVECTOR& vMachOpt : matMachOpt) { + // Recupero gli Id delle lavorazioni correnti + INTVECTOR vId ; vId.reserve( vMachOpt.size()) ; + for ( const MachOptm& Lav : vMachOpt) + vId.push_back( Lav.nId) ; + // Inizializzo i vettori delle dipendenze + matDep.emplace_back( INTINTVECTOR{}) ; + matSuggDep.emplace_back( INTINTVECTOR{}) ; + // Recupero le dipendenze associate a questo gruppo + // NB. Devono essere solamente dipendenze interne al gruppo ( le altre vengono scartate a priori) + for ( int i = 0 ; i < int( m_vDependences.size()) ; ++ i) { + if ( ! vbDep[i] && + find( vId.begin(), vId.end(), m_vDependences[i].first) != vId.end() && + find( vId.begin(), vId.end(), m_vDependences[i].second) != vId.end()) { + matDep.back().emplace_back( m_vDependences[i]) ; + vbDep[i] = true ; + } + } + for ( int i = 0 ; i < int( m_vSuggDependences.size()) ; ++ i) { + if ( ! vbSuggDep[i] && + find( vId.begin(), vId.end(), m_vSuggDependences[i].first) != vId.end() && + find( vId.begin(), vId.end(), m_vSuggDependences[i].second) != vId.end()){ + matSuggDep.back().emplace_back( m_vSuggDependences[i]) ; + vbSuggDep[i] = true ; + } + } + } + + return true ; +} + //---------------------------------------------------------------------------- bool MachOptimization::GetResult( INTVECTOR& vIds) @@ -586,73 +665,184 @@ MachOptimization::GetResult( INTVECTOR& vIds) vIds.push_back( m_vMachOptm[0].nId) ; return true ; } - // Inserisco le lavorazioni per ordine di inserimento - for ( const MachOptm& myLav : m_vMachOptm) - vIds.push_back( myLav.nId) ; - // Inizializzo le dipendenze suggerite dai gruppi di lavorazione - if ( ! SetGroupDependences()) { - LOG_ERROR( GetENkLogger(), "Error in defining Group depedences") ; - return false ; - } - // Calcolo la matrice dei tempi - INTMATRIX mTimes ; - if ( ! ComputeTimeMatrix( mTimes)) { - LOG_ERROR( GetENkLogger(), "Error in Computing Time Matrix") ; - return false ; - } - // Istanzio il Problema ShortesPath con vincoli - PtrOwner mySP( CreateShortestPath()) ; - if ( IsNull( mySP)) - return false ; - // Per ogni lavorazione inserisco gli estremi - for ( const MachOptm& Lav : m_vMachOptm) { - if ( ! mySP->AddPoint( Lav.dX_Start, Lav.dY_Start, Lav.dZ_End, 0., 0., - Lav.dX_End, Lav.dY_End, Lav.dZ_End, 0., 0.)) { - LOG_ERROR( GetENkLogger(), "Error adding Machining Bounds") ; + + // --- Se richiesta ottimizzazione solo interna per i gruppi + if ( m_bOptInGroup) { + // Recupero tutti i gruppi e le dipendenze separatamente ed ordinate per priorità di gruppo + MACHOPTMMATRIX matMachOpt ; + vector matDep, matSuggDep ; + if ( ! SplitMachOptsInGroups( matMachOpt, matDep, matSuggDep)) return false ; + // Per ognuna di esse eseguo l'algoritmo di ShortestPath + MachOptm LastMach ; + for ( int i = 0 ; i < int( matMachOpt.size()) ; ++ i) { + m_vMachOptm.clear() ; + m_vDependences.clear() ; + m_vSuggDependences.clear() ; + if ( matMachOpt.empty()) + continue ; + m_vMachOptm = matMachOpt[i] ; + m_vDependences = matDep[i] ; + m_vSuggDependences = matSuggDep[i] ; + // Calcolo la matrice dei tempi + INTMATRIX mTimes ; + if ( ! ComputeTimeMatrix( mTimes)) { + LOG_ERROR( GetENkLogger(), "Error in Computing Time Matrix") ; + return false ; + } + // Istanzio il Problema ShortesPath con vincoli + PtrOwner mySP( CreateShortestPath()) ; + if ( IsNull( mySP)) + return false ; + // Per ogni lavorazione inserisco gli estremi + for ( const MachOptm& Lav : m_vMachOptm) { + if ( ! mySP->AddPoint( Lav.dX_Start, Lav.dY_Start, Lav.dZ_End, 0., 0., + Lav.dX_End, Lav.dY_End, Lav.dZ_End, 0., 0.)) { + LOG_ERROR( GetENkLogger(), "Error adding Machining Bounds") ; + return false ; + } + } + // Assegno la matrice delle distanze calcolata in precedenza + if ( ! mySP->SetDistMatrix( mTimes)) { + LOG_ERROR( GetENkLogger(), "Error setting distances matrix") ; + return false ; + } + // Se ho una lavorazione impostata in precedenza + if ( LastMach.nId != -1) { + // Cerco le lavorazioni che non presentano precedenze + MACHOPTMVECTOR vLav ; vLav.reserve( m_vMachOptm.size()) ; + if ( m_vDependences.empty()) + vLav = m_vMachOptm ; + else { + INTSET setSecondDep ; + for ( const INTINT& Dep : m_vDependences) + setSecondDep.insert( Dep.second) ; + for ( int i = 0 ; i < int( m_vMachOptm.size()) ; ++ i) { + if ( setSecondDep.find( m_vMachOptm[i].nId) == setSecondDep.end()) + vLav.emplace_back( m_vMachOptm[i]) ; + } + } + // Tra quelle valide cerco la migliore da cui partire + int nBestLavId = 0 ; + int nBestTime = MAXTIME ; + for ( int i = 0 ; i < int( vLav.size()) ; ++ i) { + int nCurrTime = MAXTIME ; + CalcMachTime( LastMach, vLav[i], nCurrTime) ; + if ( nCurrTime < nBestTime) { + nBestTime = nCurrTime ; + nBestLavId = vLav[i].nId ; + } + } + // Imposto la prima lavorazione + if ( ! SetFirstMachining( nBestLavId)) + return false ; + } + // Per ogni dipendeza obbligatoria assegno un vincolo + for ( const INTINT& nnDep : m_vDependences) { + if ( ! mySP->SetConstraintOrder( GetIndById( nnDep.first), GetIndById( nnDep.second))) { + LOG_ERROR( GetENkLogger(), "Error in adding Constraints") ; + return false ; + } + } + // Aggiungo le dipendenza suggerite + for ( const INTINT& nnSuggDep : m_vSuggDependences) { + if ( ! mySP->SetSuggestedOrder( GetIndById( nnSuggDep.first), GetIndById( nnSuggDep.second))) { + LOG_ERROR( GetENkLogger(), "Error in adding Suggested Dependence") ; + return false ; + } + } + // Calcolo la soluzione + #if _TIME_DEBUG + PerformanceCounter PC ; PC.Start() ; + #endif + if ( ! mySP->Calculate( IShortestPath::SP_OPEN)) { + LOG_ERROR( GetENkLogger(), "Error in computing solution") ; + return false ; + } + // Recupero l'ordine + INTVECTOR U ; + if ( ! mySP->GetOrder( U)) { + LOG_ERROR( GetENkLogger(), "Error in ordering") ; + return false ; + } + // Restituisco gli Id ordinati + for ( int nInd = 0 ; nInd < int( U.size()) ; ++ nInd) + vIds.emplace_back( m_vMachOptm[U[nInd]].nId) ; + // Memorizzo l'ultima lavorazione per il gruppo successivo + LastMach = ( U.empty() ? MachOptm() : m_vMachOptm[U.back()]) ; } } - // Assegno la matrice delle distanze calcolata in precedenza - if ( ! mySP->SetDistMatrix( mTimes)) { - LOG_ERROR( GetENkLogger(), "Error setting distances matrix") ; - return false ; - } - // Per ogni dipendeza obbligatoria assegno un vincolo - for ( const INTINT& nnDep : m_vDependences) { - if ( ! mySP->SetConstraintOrder( GetIndById( nnDep.first), GetIndById( nnDep.second))) { - LOG_ERROR( GetENkLogger(), "Error in adding Constraints") ; + + //--- Se invece ottimizzazione globale + else { + // Inserisco le lavorazioni per ordine di inserimento + for ( const MachOptm& myLav : m_vMachOptm) + vIds.push_back( myLav.nId) ; + // Inizializzo le dipendenze suggerite dai gruppi di lavorazione + if ( ! SetGroupDependences()) { + LOG_ERROR( GetENkLogger(), "Error in defining Group depedences") ; return false ; } - } - // Aggiungo le dipendenza suggerite - for ( const INTINT& nnSuggDep : m_vSuggDependences) { - if ( ! mySP->SetSuggestedOrder( GetIndById( nnSuggDep.first), GetIndById( nnSuggDep.second))) { - LOG_ERROR( GetENkLogger(), "Error in adding Suggested Dependence") ; + // Calcolo la matrice dei tempi + INTMATRIX mTimes ; + if ( ! ComputeTimeMatrix( mTimes)) { + LOG_ERROR( GetENkLogger(), "Error in Computing Time Matrix") ; return false ; } + // Istanzio il Problema ShortesPath con vincoli + PtrOwner mySP( CreateShortestPath()) ; + if ( IsNull( mySP)) + return false ; + // Per ogni lavorazione inserisco gli estremi + for ( const MachOptm& Lav : m_vMachOptm) { + if ( ! mySP->AddPoint( Lav.dX_Start, Lav.dY_Start, Lav.dZ_End, 0., 0., + Lav.dX_End, Lav.dY_End, Lav.dZ_End, 0., 0.)) { + LOG_ERROR( GetENkLogger(), "Error adding Machining Bounds") ; + return false ; + } + } + // Assegno la matrice delle distanze calcolata in precedenza + if ( ! mySP->SetDistMatrix( mTimes)) { + LOG_ERROR( GetENkLogger(), "Error setting distances matrix") ; + return false ; + } + // Per ogni dipendeza obbligatoria assegno un vincolo + for ( const INTINT& nnDep : m_vDependences) { + if ( ! mySP->SetConstraintOrder( GetIndById( nnDep.first), GetIndById( nnDep.second))) { + LOG_ERROR( GetENkLogger(), "Error in adding Constraints") ; + return false ; + } + } + // Aggiungo le dipendenza suggerite + for ( const INTINT& nnSuggDep : m_vSuggDependences) { + if ( ! mySP->SetSuggestedOrder( GetIndById( nnSuggDep.first), GetIndById( nnSuggDep.second))) { + LOG_ERROR( GetENkLogger(), "Error in adding Suggested Dependence") ; + return false ; + } + } + // Calcolo la soluzione + #if _TIME_DEBUG + PerformanceCounter PC ; PC.Start() ; + #endif + if ( ! mySP->Calculate( IShortestPath::SP_OPEN)) { + LOG_ERROR( GetENkLogger(), "Error in computing solution") ; + return false ; + } + #if _TIME_DEBUG + string sTime = string( to_string( m_vDependences.size()) + string( "Time : ") + ToString( PC.Stop())) ; + LOG_INFO( GetENkLogger(), sTime.c_str()) ; + #endif + // Recupero l'ordine + INTVECTOR U ; + if ( ! mySP->GetOrder( U)) { + LOG_ERROR( GetENkLogger(), "Error in ordering") ; + return false ; + } + // Restituisco gli Id ordinati + vIds.resize( m_vMachOptm.size()) ; + for ( int nInd = 0 ; nInd < int( U.size()) ; ++ nInd) + vIds[nInd] = m_vMachOptm[U[nInd]].nId ; } - // Calcolo la soluzione - #if _TIME_DEBUG - PerformanceCounter PC ; PC.Start() ; - #endif - if ( ! mySP->Calculate( IShortestPath::SP_OPEN)) { - LOG_ERROR( GetENkLogger(), "Error in computing solution") ; - return false ; - } - #if _TIME_DEBUG - string sTime = string( to_string( m_vDependences.size()) + string( "Time : ") + ToString( PC.Stop())) ; - LOG_INFO( GetENkLogger(), sTime.c_str()) ; - #endif - // Recupero l'ordine - INTVECTOR U ; - if ( ! mySP->GetOrder( U)) { - LOG_ERROR( GetENkLogger(), "Error in ordering") ; - return false ; - } - // Restituisco gli Id ordinati - vIds.resize( m_vMachOptm.size()) ; - for ( int nInd = 0 ; nInd < int( U.size()) ; ++ nInd) - vIds[nInd] = m_vMachOptm[U[nInd]].nId ; + return true ; } - diff --git a/MachOptimization.h b/MachOptimization.h index 947ac1b..ff8dc8b 100644 --- a/MachOptimization.h +++ b/MachOptimization.h @@ -14,6 +14,8 @@ #include "/EgtDev/Include/ENkMachOptimization.h" +using namespace std ; + //---------------------------------------------------------------------------- class MachOptimization : public IMachOptimization { @@ -36,6 +38,7 @@ class MachOptimization : public IMachOptimization bool SetLastMachining( int nId) override ; bool SetFeeds( double dFeedL, double dFeedA) override ; bool SetAllGroupsAsMandatory( bool bAllMandatory) override ; + bool SetOptimizationForGroups( bool bOptForGroups) override ; // Risultati bool GetResult( INTVECTOR& vIds) override ; @@ -50,6 +53,7 @@ class MachOptimization : public IMachOptimization double& dTimeLav1TC1, double& dTimeTC1TC2, double& dTimeTC2Lav2, double& dTUnload1, double& dTLoad2) ; bool CalcMachTime( int nInd1, int nInd2, int& nTime) ; + bool CalcMachTime( const MachOptm& Lav1, const MachOptm& Lav2, int& nTime) ; // Controllo Conflitti tra dipendenze e Gestione Dipendenze bool CheckDependences( int nIdPrev, int nIdNext, const INTINTVECTOR& vDep, @@ -61,6 +65,8 @@ class MachOptimization : public IMachOptimization // Utility int GetIndById( int nId) ; + bool SplitMachOptsInGroups( MACHOPTMMATRIX& matMachOpt, vector& matDep, + vector& matSuggDep) ; private : MACHOPTMVECTOR m_vMachOptm ; // Vettore delle lavorazioni @@ -70,4 +76,5 @@ class MachOptimization : public IMachOptimization double m_dFeedL ; // Feed Lineare double m_dFeedA ; // Feed Angolare bool m_bAllMandatory ; // Flag per impostare ogni dipendenza da Gruppo come vincolo + bool m_bOptInGroup ; // Flag per ottimizzazione solo interna ai gruppi } ;