17 Commits

Author SHA1 Message Date
Dario Sassi da69366833 EgtNumKernel 3.1a1 :
- ricompilazione con cambio major versione.
2026-01-02 12:33:12 +01:00
Riccardo Elitropi afe4648575 EgtNumKernel :
- modifica prototipi in Machining Optimization.
2025-12-18 09:03:57 +01:00
Riccardo Elitropi 0efb3082d0 EgtNumKernel :
- in Machining Optimization aggiunta gestione OpenBounds.
2025-12-17 15:03:14 +01:00
Riccardo Elitropi f258acefd0 EgtNumKernel 2.7l1 :
- in Machining Optimization aggiunta ottimizzazione mirata ai singoli gruppi.
2025-12-16 15:44:29 +01:00
Dario Sassi 6d34e7accb EgtNumKernel 2.7k1 :
- ricompilazione per passaggio a C++ 20
2025-11-01 17:20:33 +01:00
Dario Sassi f7d51cc5cb EgtNumKernel 2.7h1 :
- ricompilazione con cambio versione.
2025-08-22 11:39:08 +02:00
Dario Sassi a78c20ca50 EgtNumKernel 2.7g1 :
- ricompilazione con cambio versione.
2025-07-03 10:12:50 +02:00
Dario Sassi 431fefcf9d EgtNumKernel 2.7d2 :
- ricompilazione con cambio versione.
2025-04-23 12:17:07 +02:00
Riccardo Elitropi 558b590810 EgtNumKernel :
- Aggiunta classe di calcolo per ottimizzazione ordine delle lavorazioni
- Aggiunti vincoli obbligatori e dipendenze suggerite a ShortestPath.
2025-04-23 10:09:41 +02:00
Dario Sassi d9818970e7 EgtNumKernel 2.7a1 :
- cambio annuale di versione
- compilazione 32bit senza più limiti per Windows XP.
2025-01-09 17:56:30 +01:00
Dario Sassi dd87289571 EgtNumKernel 2.6l2 :
- ricompilazione con cambio versione.
2024-12-05 17:39:32 +01:00
Dario Sassi e02619caaf EgtNumKernel 2.6g5 :
- ricompilazione con cambio versione.
2024-07-18 20:36:05 +02:00
Dario Sassi 4af2386744 EgtNumKernel 2.6b1 :
- ricompilazione con cambio versione.
2024-02-13 14:33:24 +01:00
Riccardo Elitropi 510e39db1e Merge commit '897b45e54975ecce10fda28035bf00da41485e2a' 2024-02-13 12:30:39 +01:00
Riccardo Elitropi 897b45e549 EgtNumKernel :
- piccole migliorie.
2024-02-13 12:29:25 +01:00
Riccardo Elitropi 31a96af3ba EgtNumKernel :
- aggiunto algoritmo Dijkstra.
2024-02-08 13:02:09 +01:00
Dario Sassi dcf1812704 EgtNumKernel 2.6a1 :
- ricompilazione con cambio versione.
2024-01-16 11:05:58 +01:00
16 changed files with 2041 additions and 179 deletions
+279
View File
@@ -0,0 +1,279 @@
//----------------------------------------------------------------------------
// EgalTech 2025-2025
//----------------------------------------------------------------------------
// File : Dependences.cpp Data : 16.04.25 Versione : 2.7a1
// Contenuto : Scelta dei nodi in base alle dipenze per ShortestPath ;
//
//
// Modifiche : 16.04.25 RE Creazione modulo.
//
//
//----------------------------------------------------------------------------
//--------------------------- Include ----------------------------------------
#include "stdafx.h"
#include "DllMain.h"
#include "ShortestPath.h"
#include "/EgtDev/Include/EGnStringUtils.h"
#include <new>
using namespace std ;
//----------------------------------------------------------------------------
/* Funzione per impostare i vincoli di precendeza obbligatori */
bool
ShortestPath::SetConstraintOrder( int nPrev, int nNext)
{
// se ho già delle dipendenze inserite, controllo che non sia già inserita o in conflitto
for ( auto it = m_vOrderConstr.begin() ; it != m_vOrderConstr.end() ; ++ it) {
// se dipendenza già presente, non la considero
if ( ( *it).first == nPrev && ( *it).second == nNext) {
LOG_INFO( GetENkLogger(), string( "Constraint Dependence already in : " + ToString( nPrev) + ", " + ToString( nNext)).c_str()) ;
return true ;
}
// se conflitto allora ritorno errore
if ( ( *it).first == nNext && ( *it).second == nPrev) {
LOG_INFO( GetENkLogger(), string( "Constraint Dependence conflict: " + ToString( nPrev) + ", " + ToString( nNext)).c_str()) ;
return false ;
}
}
// inserisco la dipendenze
m_vOrderConstr.emplace_back( make_pair( nPrev, nNext)) ;
return true ;
}
//----------------------------------------------------------------------------
/* Funzione per impostare i vincoli di precedenza suggeriti */
bool
ShortestPath::SetSuggestedOrder( int nPrev, int nNext)
{
// se vettore dipendenze vuoto, lo alloco
if ( m_vOrderSugg.empty()) {
m_vOrderSugg.resize( m_nNumPnts * m_nNumPnts, false) ;
m_vOrderSuggRowMap.resize( m_nNumPnts, false) ;
}
// se in conflitto, allora non la inserisco e cancello quella presente
if ( m_vOrderSugg[ nNext * m_nNumPnts + nPrev]) {
m_vOrderSugg[ nNext * m_nNumPnts + nPrev] = false ;
return true ;
}
// inserisco la dipendenze
m_vOrderSugg[ nPrev * m_nNumPnts + nNext] = true ;
m_vOrderSuggRowMap[ nPrev] = true ;
return true ;
}
//----------------------------------------------------------------------------
/* Funzione per verificare se un vincolo è violato o meno */
bool
ShortestPath::IsViolatingContraints( int nPrev, int nNext)
{
// scorro i vincoli
for ( const INTINT nC : m_vOrderConstr) {
// se il vincolo è ( nNext, nPrev) allora non è violato
if ( nC.first == nNext && nC.second == nPrev)
return true ;
}
return false ;
}
//----------------------------------------------------------------------------
/* Funzione per verificare se un Path rispetta tutti i vincoli obbligatori */
bool
ShortestPath::IsPathRespectingContraints( NODE* pPath)
{
// controllo validità del percorso
if ( pPath == nullptr)
return false ;
// controllo se il percorso ricavato, viola un vincolo
for ( unsigned nC = 0 ; nC < m_vOrderConstr.size() ; ++ nC) {
// scorro il percorso
NODE* pCurr = pPath ;
for ( unsigned i = 0 ; i < m_nNumPnts ; ++ i) {
if ( pCurr->nPos == m_vOrderConstr[nC].first)
break ;
if ( pCurr->nPos == m_vOrderConstr[nC].second)
return false ;
pCurr = pCurr->pNext ;
}
}
return true ;
}
//----------------------------------------------------------------------------
/* Funzione per verificare se una rotazione ciclica di nodi viola dei vincoli */
bool
ShortestPath::IsChangingStartPathRespectingConstraints( NODE* pPath, NODE* pFirst)
{
// copio il percorso in quello per le dipendenze
CopyPath( pPath, m_pCheckDep) ;
NODE* pCurr = m_pCheckDep ;
for ( unsigned i = 0 ; i < m_nNumPnts ; ++ i) {
// mi muovo alla posizione succesisva nel percorso di test
pCurr = pCurr->pNext ;
// controllo se il nuovo percorso rispetta i vincoli
if ( IsPathRespectingContraints( pCurr)) {
pFirst = pFirst->pNext ;
return true ;
}
}
return false ;
}
//----------------------------------------------------------------------------
/* Funzione per calcolare il numero di dipendenze SUGGERITE non rispettate da un Path */
bool
ShortestPath::IsPathRespectingSuggestedDependences( NODE* pPath, int& nBreak)
{
// se non ho dipendenze suggerite, ho finito
if ( m_vOrderSugg.empty())
return true ;
// controllo validità del percorso
nBreak = 0 ;
if ( pPath == nullptr)
return false ;
// scrorro i nodi coinvolti da dipendenze
unsigned nDim = m_nNumPnts - ( m_nType == SP_OPEN ? 1 : 0) ;
for ( unsigned i = 0 ; i < nDim ; ++ i) {
// controllo se il nodo corrente è legato da dipendenze suggerite
if ( m_vOrderSuggRowMap[i]) {
// scorro il percorso
NODE* pCurr = pPath ;
for ( unsigned j = 0 ; j < m_nNumPnts ; ++ j) {
if ( pCurr->nPos != m_nNumPnts - 1) {
if ( pCurr->nPos == i)
break ;
if ( m_vOrderSugg[ i * nDim + pCurr->nPos])
++ nBreak ;
}
pCurr = pCurr->pNext ;
}
}
}
return ( nBreak == 0) ;
}
//----------------------------------------------------------------------------
/* Funzione per calcolare il coefficiente di costo per ogni dipedenza suggerita violata */
unsigned
ShortestPath::CalcMaxDist( void)
{
// scorro gli elementi della matrice delle distanze
// NB. Si può decidere di calcolarlo diversamente
if ( m_Dists == nullptr)
return false ;
unsigned nMaxDist = 0 ;
for ( unsigned i = 0 ; i < m_nNumPnts ; ++ i) {
for ( unsigned j = 0 ; j < m_nNumPnts ; ++ j) {
if ( i != j && m_Dists[ Index( i, j)] < MAXDIST - 1)
nMaxDist = max( nMaxDist, m_Dists[ Index( i, j)]) ;
}
}
return nMaxDist ;
}
/* ------------------------------------------------------------------------- */
bool
ShortestPath::ChooseFirstNode( unsigned& iFirst)
{
// definisco un vettore dei soli nodi che posso inserire
vector<unsigned> vOkNodes ; vOkNodes.reserve( m_nNumPnts) ;
// scorro i nodi i-esimi
for ( unsigned i = 0 ; i < m_nNumPnts ; ++ i) {
// non deve esistere alcun vincolo del tipo ( j, i)
bool bOk = true ;
for ( unsigned nC = 0 ; nC < m_vOrderConstr.size() && bOk ; ++ nC) {
// recupero il vincolo ( a, b)
const INTINT& nnDep = m_vOrderConstr[nC] ;
bOk = nnDep.second != i ;
}
if ( bOk)
vOkNodes.push_back( i) ;
}
// se non ho nodi, allora errore
if ( vOkNodes.empty())
return false ;
// scelgo l'ultimo ( per percorsi OPEN)
iFirst = vOkNodes.back() ;
return true ;
}
/* ------------------------------------------------------------------------- */
bool
ShortestPath::ChooseNextNode( NODE* pPath, unsigned nSize, unsigned& jNext, bool bNearVsFar)
{
// recupero i nodi non inseriti nel path
jNext = -1 ;
vector<unsigned> vUninstertedNodes ; vUninstertedNodes.reserve( m_nNumPnts) ;
for ( unsigned nInd = 0 ; nInd < m_nNumPnts ; ++ nInd) {
bool bIn = false ;
NODE* pNode = pPath ;
for ( unsigned nNode = 0 ; nNode < nSize && ! bIn ; ++ nNode) {
bIn = ( pNode->nPos == nInd) ;
pNode = pNode->pPrev ;
}
if ( ! bIn)
vUninstertedNodes.push_back( nInd) ;
}
// se tutti i nodi sono inseriti, allora non faccio nulla
if ( vUninstertedNodes.empty())
return true ;
// se un solo nodo non inserito, allora non ho altra scelta
if ( vUninstertedNodes.size() == unsigned( 1)) {
jNext = vUninstertedNodes[0] ;
return true ;
}
// definisco un vettore dei soli nodi che posso inserire
vector<unsigned> vOkNodes ; vOkNodes.reserve( m_nNumPnts) ;
// scorro i nodi che devo ancora posizionare
for ( unsigned j : vUninstertedNodes) {
/*
* l'ultimo nodo inserito è l'i-esimo, e il successivo sarà il j-esimo ( i ---> j)
* devo controllare che tra i nodi inseriti non ci sia un nodo k tale per cui viene violato
* il vincolo ( k, j)
*/
// controllo che l'arco ( i --> j) sia valido
if ( ! m_Available[ Index( pPath->nPos, j)])
continue ;
// scorro i vincoli
bool bOk = true ;
for ( unsigned nC = 0 ; nC < m_vOrderConstr.size() && bOk ; ++ nC) {
// recupero il vincolo ( a, b)
const INTINT& nnDep = m_vOrderConstr[nC] ;
// controllo se esiste un vincolo del tipo ( ?, j)
if ( nnDep.second == j) {
// in questo caso controllo se esiste un nodo k != j che viola il vincolo ( k, j)
for ( unsigned k = 0 ; k < vUninstertedNodes.size() && bOk ; ++ k) {
if ( vUninstertedNodes[k] != j)
bOk = ( vUninstertedNodes[k] != nnDep.first) ;
}
}
}
// se vincolo non violato, allora il nodo j può essere inserito
if ( bOk)
vOkNodes.push_back( j) ;
}
// se non posso inserire alcun nodo, allora errore
if ( vOkNodes.empty())
return false ;
// se un solo nodo possibile, allora è quello
if ( vOkNodes.size() == unsigned( 1)) {
jNext = vOkNodes[0] ;
return true ;
}
// altrimenti seleziono il nodo j-esimo tale per cui l'arco ( i --> j) ha costo minimo/assimo ( bNearVsFar)
int nRefDist = bNearVsFar ? MAXDIST : -1 ;
for ( unsigned j : vOkNodes) {
int nDist = int( ArcCost( pPath->nPos, j)) ;
bool bUpdate = false ;
if ( bNearVsFar)
bUpdate = ( nDist < nRefDist) ;
else
bUpdate = ( nDist > nRefDist) ;
if ( bUpdate) {
nRefDist = nDist ;
jNext = j ;
}
}
return true ;
}
+151
View File
@@ -0,0 +1,151 @@
//----------------------------------------------------------------------------
// EgalTech 2015-2015
//----------------------------------------------------------------------------
// File : Dijkstra.cpp Data : 08.02.24 Versione : 2.6b1
// Contenuto : Classe per calcolo del percorso a peso minimo su un grafo orientato.
//
//
// Modifiche : 02.02.2024 RE Creazione modulo.
//
//
//----------------------------------------------------------------------------
//--------------------------- Include ----------------------------------------
#include "stdafx.h"
#include "DllMain.h"
#include "Dijkstra.h"
#include "/EgtDev/Include/EGnStringUtils.h"
#include "/EgtDev/Include/EgtILogger.h"
#include "set"
#include <new>
using namespace std ;
//----------------------------------------------------------------------------
IDijkstra*
CreateDijkstra( void)
{
return static_cast<IDijkstra*> ( new(nothrow) Dijkstra) ;
}
//----------------------------------------------------------------------------
Dijkstra::Dijkstra( void)
{
m_AdjMatrix = { } ;
m_nDest = -1 ;
m_bValid = false ;
}
//----------------------------------------------------------------------------
Dijkstra::~Dijkstra( void)
{
}
//----------------------------------------------------------------------------
bool
Dijkstra::SetGraph( DBLMATRIX AdjMatrix, int nDestInd) {
// se vuota, errore
if ( AdjMatrix.empty())
return false ;
// controllo che la matrice sia quadrata
int nRows = static_cast<int>( AdjMatrix.size()) ;
for ( int i = 0 ; i < nRows ; ++ i)
if ( static_cast<int>( AdjMatrix[i].size()) != nRows)
return false ;
// i pesi non devono essere negativi
for ( int i = 0 ; i < nRows ; ++ i)
for ( int j = 0 ; j < int( AdjMatrix[i].size()) ; ++ j)
if ( AdjMatrix[i][j] < 0)
return false ;
// assegno la matrice delle adiancenze e la destinazione
m_AdjMatrix = AdjMatrix ;
m_nDest = nDestInd ;
// per sicurezza assegno agli elementi sulla diagonale la massima distanza
for ( int i = 0 ; i < nRows ; ++ i)
m_AdjMatrix[i][i] = WEIGHT_NO_ADJ ;
// il grafo è valido
m_bValid = true ;
return true ;
}
//----------------------------------------------------------------------------
bool
Dijkstra::GetPath( INTVECTOR& vNodePath)
{
// se il grafo non è valido, allora esco
if ( ! m_bValid)
return false ;
// dimensione dei nodi
const int DIM = static_cast<int>( m_AdjMatrix.size()) ;
// ridimensiono il percorso
vNodePath.resize( DIM) ;
// definisco il vettore delle distanze
vector<double> vDists ; vDists.resize( DIM) ;
// definisco l'insieme dei nodi visitati
set<int> sNode_toCheck ;
// inizializzo l'insieme dei nodi da visitare, le distanze ( ad infinito) e gli indici dei nodi
// precedenti ( tutti a -1)
for ( int i = 0 ; i < DIM ; ++ i) {
sNode_toCheck.insert( i) ;
vNodePath[i] = -1 ;
vDists[i] = WEIGHT_NO_ADJ ;
}
// il nodo sorgente ( in posizione zero) ha distanza nulla
vDists[0] = 0. ;
// finchè non ho controllato tutti i nodi...
while ( ! sNode_toCheck.empty()) {
// cerco il nodo ( tra quelli non ancora visitati) a cui è associata la distanza minima
// ( alla prima iterazione il nodo è lo 0)
int nMinInd = -1 ;
double dDistRef = WEIGHT_NO_ADJ - 1 ;
for ( int i = 0 ; i < DIM ; ++ i) {
// cerco un nodo i disponibile
set<int>::iterator iter = sNode_toCheck.find( i) ;
if ( iter == sNode_toCheck.end())
continue ;
// se la distanza e minore del riferimento, aggiorno
if ( vDists[i] < dDistRef) {
dDistRef = vDists[i] ;
nMinInd = i ;
}
}
// se nodo non trovato o coincidente alla destinazione ( se presente), allora il percorso è terminato
if ( nMinInd == -1 || nMinInd == m_nDest)
break ;
// escludo il nodo i-esimo trovato
sNode_toCheck.erase( nMinInd) ;
// cerco i nodi ad esso adiacenti
for ( int i = 0 ; i < DIM ; ++ i) {
if ( m_AdjMatrix[nMinInd][i] < MAXDIST) {
// la distanza per raggiungere il nodo i dal nodo nMinInd è pari alla somma dei contributi
// associati alle lunghezza trovate
double myDist = vDists[nMinInd] + m_AdjMatrix[nMinInd][i] ;
// se inferiore...
if ( myDist < vDists[i]) {
// aggiorno la distanza per raggiungere il nodo i
vDists[i] = myDist ;
// aggiorno l'indice per raggiungere il nodo i
vNodePath[i] = nMinInd ;
}
}
}
}
return true ;
}
+38
View File
@@ -0,0 +1,38 @@
//----------------------------------------------------------------------------
// EgalTech 2015-2015
//----------------------------------------------------------------------------
// File : Dijkstra.h Data : 08.02.24 Versione : 2.6b1
// Contenuto : Classe per calcolo del percorso a peso minimo su un grafo orientato.
//
//
// Modifiche : 02.02.2024 RE Creazione modulo.
//
//
//----------------------------------------------------------------------------
#pragma once
#include "/EgtDev/Include/ENkDijkstra.h"
//----------------------------------------------------------------------------
#define MAXDIST 1073741823U // 2^30 - 1 per evitare overflow
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
class Dijkstra : public IDijkstra
{
public :
~Dijkstra( void) override ;
bool SetGraph( DBLMATRIX AdjMatrix, int nDestInd = -1) override ;
bool GetPath( INTVECTOR& vNodePath) override ;
public :
Dijkstra( void) ;
private :
int m_nDest ;
DBLMATRIX m_AdjMatrix ;
bool m_bValid ;
} ;
BIN
View File
Binary file not shown.
+12 -7
View File
@@ -22,14 +22,14 @@
<ProjectGuid>{E47BBFD0-36EA-4EC1-9D6D-B05CA9C092C6}</ProjectGuid> <ProjectGuid>{E47BBFD0-36EA-4EC1-9D6D-B05CA9C092C6}</ProjectGuid>
<Keyword>Win32Proj</Keyword> <Keyword>Win32Proj</Keyword>
<RootNamespace>EgtNumKernel</RootNamespace> <RootNamespace>EgtNumKernel</RootNamespace>
<WindowsTargetPlatformVersion>10.0.20348.0</WindowsTargetPlatformVersion> <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType> <ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v141_xp</PlatformToolset> <PlatformToolset>v143</PlatformToolset>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType> <ConfigurationType>DynamicLibrary</ConfigurationType>
@@ -42,7 +42,7 @@
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v141_xp</PlatformToolset> <PlatformToolset>v143</PlatformToolset>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType> <ConfigurationType>DynamicLibrary</ConfigurationType>
@@ -103,7 +103,7 @@
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;I_AM_ENK;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;I_AM_ENK;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<OpenMPSupport>false</OpenMPSupport> <OpenMPSupport>false</OpenMPSupport>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<LanguageStandard>stdcpp17</LanguageStandard> <LanguageStandard>stdcpp20</LanguageStandard>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Windows</SubSystem> <SubSystem>Windows</SubSystem>
@@ -125,7 +125,7 @@ copy $(TargetPath) \EgtProg\DllD32</Command>
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;I_AM_ENK;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;I_AM_ENK;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<OpenMPSupport>true</OpenMPSupport> <OpenMPSupport>true</OpenMPSupport>
<LanguageStandard>stdcpp17</LanguageStandard> <LanguageStandard>stdcpp20</LanguageStandard>
<AdditionalOptions>-Wno-tautological-undefined-compare</AdditionalOptions> <AdditionalOptions>-Wno-tautological-undefined-compare</AdditionalOptions>
</ClCompile> </ClCompile>
<Link> <Link>
@@ -156,7 +156,7 @@ copy $(TargetPath) \EgtProg\DllD64</Command>
<EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations> <EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations>
<EnableParallelCodeGeneration>true</EnableParallelCodeGeneration> <EnableParallelCodeGeneration>true</EnableParallelCodeGeneration>
<OmitFramePointers>true</OmitFramePointers> <OmitFramePointers>true</OmitFramePointers>
<LanguageStandard>stdcpp17</LanguageStandard> <LanguageStandard>stdcpp20</LanguageStandard>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Windows</SubSystem> <SubSystem>Windows</SubSystem>
@@ -188,7 +188,7 @@ copy $(TargetPath) \EgtProg\Dll32</Command>
<EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet> <EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet>
<EnableFiberSafeOptimizations>false</EnableFiberSafeOptimizations> <EnableFiberSafeOptimizations>false</EnableFiberSafeOptimizations>
<EnableParallelCodeGeneration>true</EnableParallelCodeGeneration> <EnableParallelCodeGeneration>true</EnableParallelCodeGeneration>
<LanguageStandard>stdcpp17</LanguageStandard> <LanguageStandard>stdcpp20</LanguageStandard>
<AdditionalOptions>-Wno-tautological-undefined-compare</AdditionalOptions> <AdditionalOptions>-Wno-tautological-undefined-compare</AdditionalOptions>
</ClCompile> </ClCompile>
<Link> <Link>
@@ -207,12 +207,15 @@ copy $(TargetPath) \EgtProg\Dll64</Command>
</ResourceCompile> </ResourceCompile>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="Dijkstra.cpp" />
<ClCompile Include="ENkDllMain.cpp" /> <ClCompile Include="ENkDllMain.cpp" />
<ClCompile Include="Fn.cpp" /> <ClCompile Include="Fn.cpp" />
<ClCompile Include="Hybrid.cpp" /> <ClCompile Include="Hybrid.cpp" />
<ClCompile Include="JenkinsTraub.cpp" /> <ClCompile Include="JenkinsTraub.cpp" />
<ClCompile Include="MachOptimization.cpp" />
<ClCompile Include="MaximumFiller.cpp" /> <ClCompile Include="MaximumFiller.cpp" />
<ClCompile Include="Nn.cpp" /> <ClCompile Include="Nn.cpp" />
<ClCompile Include="Dependences.cpp" />
<ClCompile Include="Polynomial.cpp" /> <ClCompile Include="Polynomial.cpp" />
<ClCompile Include="PolynomialRoots.cpp" /> <ClCompile Include="PolynomialRoots.cpp" />
<ClCompile Include="PntOpt.cpp" /> <ClCompile Include="PntOpt.cpp" />
@@ -236,8 +239,10 @@ copy $(TargetPath) \EgtProg\Dll64</Command>
<ClInclude Include="..\Include\ENkDllMain.h" /> <ClInclude Include="..\Include\ENkDllMain.h" />
<ClInclude Include="..\Include\ENkPolynomial.h" /> <ClInclude Include="..\Include\ENkPolynomial.h" />
<ClInclude Include="..\Include\ENkPolynomialRoots.h" /> <ClInclude Include="..\Include\ENkPolynomialRoots.h" />
<ClInclude Include="Dijkstra.h" />
<ClInclude Include="DllMain.h" /> <ClInclude Include="DllMain.h" />
<ClInclude Include="JenkinsTraub.h" /> <ClInclude Include="JenkinsTraub.h" />
<ClInclude Include="MachOptimization.h" />
<ClInclude Include="MaximumFiller.h" /> <ClInclude Include="MaximumFiller.h" />
<ClInclude Include="resource.h" /> <ClInclude Include="resource.h" />
<ClInclude Include="ShortestPath.h" /> <ClInclude Include="ShortestPath.h" />
+21
View File
@@ -22,6 +22,12 @@
<Filter Include="File di origine\MaximumFilling"> <Filter Include="File di origine\MaximumFilling">
<UniqueIdentifier>{205f239f-c48e-4049-bac5-74708a6c530c}</UniqueIdentifier> <UniqueIdentifier>{205f239f-c48e-4049-bac5-74708a6c530c}</UniqueIdentifier>
</Filter> </Filter>
<Filter Include="File di origine\Dijkstra">
<UniqueIdentifier>{54a2fd6b-2491-42af-932a-eaa6f62f1ae2}</UniqueIdentifier>
</Filter>
<Filter Include="File di origine\MachOptimization">
<UniqueIdentifier>{4413b322-852f-4def-8339-088d4420d41d}</UniqueIdentifier>
</Filter>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="ENkDllMain.cpp"> <ClCompile Include="ENkDllMain.cpp">
@@ -66,6 +72,15 @@
<ClCompile Include="MaximumFiller.cpp"> <ClCompile Include="MaximumFiller.cpp">
<Filter>File di origine\MaximumFilling</Filter> <Filter>File di origine\MaximumFilling</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Dijkstra.cpp">
<Filter>File di origine\Dijkstra</Filter>
</ClCompile>
<ClCompile Include="MachOptimization.cpp">
<Filter>File di origine\MachOptimization</Filter>
</ClCompile>
<ClCompile Include="Dependences.cpp">
<Filter>File di origine\ShortestPath</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="stdafx.h"> <ClInclude Include="stdafx.h">
@@ -110,6 +125,12 @@
<ClInclude Include="MaximumFiller.h"> <ClInclude Include="MaximumFiller.h">
<Filter>File di intestazione</Filter> <Filter>File di intestazione</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="Dijkstra.h">
<Filter>File di intestazione</Filter>
</ClInclude>
<ClInclude Include="MachOptimization.h">
<Filter>File di intestazione</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ResourceCompile Include="EgtNumKernel.rc"> <ResourceCompile Include="EgtNumKernel.rc">
+52 -27
View File
@@ -2,7 +2,7 @@
// EgalTech 2015-2015 // EgalTech 2015-2015
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
// File : NN.cpp Data : 24.12.15 Versione : 1.6l4 // File : NN.cpp Data : 24.12.15 Versione : 1.6l4
// Contenuto : Calcolo del percorso minimo basandosi su punto più lontano ; // Contenuto : Calcolo del percorso minimo basandosi su punto più lontano ;
// pessima stima, utile come base per miglioramenti. // pessima stima, utile come base per miglioramenti.
// //
// //
@@ -15,7 +15,7 @@
#include "stdafx.h" #include "stdafx.h"
#include "ShortestPath.h" #include "ShortestPath.h"
/*-------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
long long unsigned long long unsigned
ShortestPath::FarNeighbor( void) ShortestPath::FarNeighbor( void)
{ {
@@ -26,34 +26,59 @@ ShortestPath::FarNeighbor( void)
m_Available[ Index( i, i)] = false ; m_Available[ Index( i, i)] = false ;
} }
// cerco il nodo con il più corto arco che se ne diparte // se non ho dipendenze
unsigned nCurr = 0 ; if ( ! ExistConstraints()) {
unsigned nNew = HighArc( nCurr) ; // cerco il nodo con il più corto arco che se ne diparte
for ( unsigned i = 1 ; i < m_nNumPnts ; ++ i) { unsigned nCurr = 0 ;
unsigned j = HighArc( i) ; unsigned nNew = HighArc( nCurr) ;
if ( ArcCost( i, j) > ArcCost( nCurr, nNew)) { for ( unsigned i = 1 ; i < m_nNumPnts ; ++ i) {
nCurr = i ; unsigned j = HighArc( i) ;
nNew = j ; if ( ArcCost( i, j) > ArcCost( nCurr, nNew)) {
nCurr = i ;
nNew = j ;
}
} }
// imposto il nodo corrente come base del percorso
NODE* pPath = m_pMain ;
pPath->nPos = nCurr ;
// ciclo
do {
// imposto tutti gli archi non disponibili al nodo corrente
for ( unsigned i = 0 ; i < m_nNumPnts ; ++ i)
m_Available[ Index( i, nCurr)] = false ;
// aggiungo un nuovo nodo al percorso
pPath = pPath->pNext ;
pPath->nPos = nNew ;
// imposto il nuovo nodo come nodo corrente
nCurr = nNew ;
// cerco il nuovo nodo all'estremo dell'arco più corto dal nodo corrente
nNew = HighArc( nCurr) ;
} while ( m_Available[ Index( nCurr, nNew)]) ;
} }
// se esistono dipendenze
// imposto il nodo corrente come base del percorso else {
NODE* pPath = m_pMain ; // cerco il primo nodo da cui iniziare
pPath->nPos = nCurr ; unsigned nNew = -1 ;
if ( ! ChooseFirstNode( nNew))
// ciclo return MAXDIST ;
do { // imposto il nodo corrente come base del percorso
// imposto tutti gli archi non disponibili al nodo corrente NODE* pPath = m_pMain ;
for ( unsigned i = 0 ; i < m_nNumPnts ; ++ i)
m_Available[ Index( i, nCurr)] = false ;
// aggiungo un nuovo nodo al percorso
pPath = pPath->pNext ;
pPath->nPos = nNew ; pPath->nPos = nNew ;
// imposto il nuovo nodo come nodo corrente unsigned nSize = 1 ;
nCurr = nNew ; // ciclo
// cerco il nuovo nodo all'estremo dell'arco più corto dal nodo corrente do {
nNew = HighArc( nCurr) ; // imposto tutti gli archi non disponibili al nodo corrente
} while ( m_Available[ Index( nCurr, nNew)]) ; for ( unsigned i = 0 ; i < m_nNumPnts ; ++ i)
m_Available[ Index( i, nNew)] = false ;
// cerco il nuovo nodo all'estremo dell'arco più lungo dal nodo corrente
if ( ! ChooseNextNode( pPath, nSize, nNew, false))
return MAXDIST ;
// aggiungo un nuovo nodo al percorso
pPath = pPath->pNext ;
pPath->nPos = nNew ;
++ nSize ;
} while ( nSize < m_nNumPnts) ;
}
// calcolo il costo del percorso // calcolo il costo del percorso
return TotalCost( m_pMain) ; return TotalCost( m_pMain) ;
+120 -37
View File
@@ -17,6 +17,36 @@
#include "stdafx.h" #include "stdafx.h"
#include "ShortestPath.h" #include "ShortestPath.h"
// ----------------------------------------------------------------------------
static void
SwapNodesForHybrid1( NODE* pLast, NODE* pFirst, NODE* pKth)
{
NODE* pSave = pKth->pNext ;
pKth->pNext = pKth->pNext->pNext ;
pKth->pNext->pPrev = pKth ;
pLast->pNext = pSave ;
pFirst->pPrev = pSave ;
pSave->pNext = pFirst ;
pSave->pPrev = pLast ;
}
// ----------------------------------------------------------------------------
static void
SwapNodesForHybrid2( NODE* pLast, NODE* pFirst, NODE* pKth)
{
for ( NODE* pReverse = pFirst ; pReverse != pKth ;) {
NODE* pSave = pReverse->pNext ;
pReverse->pNext = pReverse->pPrev ;
pReverse->pPrev = pSave ;
pReverse = pSave ;
}
pFirst->pNext = pKth->pNext ;
pKth->pNext->pPrev = pFirst ;
pKth->pNext = pKth->pPrev ;
pKth->pPrev = pLast ;
pLast->pNext = pKth ;
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
long long unsigned long long unsigned
ShortestPath::Hybrid( NODE* pPath) ShortestPath::Hybrid( NODE* pPath)
@@ -24,56 +54,109 @@ ShortestPath::Hybrid( NODE* pPath)
const int MAX_TRY = 2048 ; const int MAX_TRY = 2048 ;
unsigned count = 1 ; unsigned count = 1 ;
NODE* pFirst = pPath ; NODE* pFirst = pPath ;
NODE* pFirstDep = m_pCheckDep ;
unsigned nTry = 1 ; unsigned nTry = 1 ;
do { do {
NODE* pLast = pFirst->pPrev ; NODE* pLast = pFirst->pPrev ;
NODE* pKth = pFirst->pNext ; NODE* pKth = pFirst->pNext ;
NODE* pLastDep = pFirstDep->pPrev ;
NODE* pKthDep = pFirstDep->pNext ;
do { do {
// Point-Opt ( D1=new, D3=original) unsigned D1 = 0 ;
unsigned D1 = ArcCost( pKth->nPos, pKth->pNext->pNext->nPos) + unsigned D2 = 0 ;
ArcCost( pKth->pNext->nPos, pFirst->nPos) + unsigned D3 = 0 ;
ArcCost( pLast->nPos, pKth->pNext->nPos) ; unsigned D4 = 0 ;
unsigned D3 = ArcCost( pLast->nPos, pFirst->nPos) + // se non esistono dipendenze suggerite
ArcCost( pKth->nPos, pKth->pNext->nPos) + if ( ! ExistSuggDependences()) {
ArcCost( pKth->pNext->nPos, pKth->pNext->pNext->nPos) ; // Point-Opt ( D1=new, D3=original)
// Two-Opt ( D2=new, D4=original) D1 = ArcCost( pKth->nPos, pKth->pNext->pNext->nPos) +
unsigned D2 = ArcCost( pFirst->nPos, pKth->pNext->nPos) + ArcCost( pKth->pNext->nPos, pFirst->nPos) +
ArcCost( pLast->nPos, pKth->nPos) ; ArcCost( pLast->nPos, pKth->pNext->nPos) ;
unsigned D4 = ArcCost( pLast->nPos, pFirst->nPos) + D3 = ArcCost( pLast->nPos, pFirst->nPos) +
ArcCost( pKth->nPos, pKth->pNext->nPos) ; ArcCost( pKth->nPos, pKth->pNext->nPos) +
// Lunghezze originali e nuova del tratto intermedio che viene invertito ArcCost( pKth->pNext->nPos, pKth->pNext->pNext->nPos) ;
for ( NODE* pCurr = pFirst ; pCurr != pKth ; pCurr = pCurr->pNext) { // Two-Opt ( D2=new, D4=original)
D4 += ArcCost( pCurr->nPos, pCurr->pNext->nPos) ; D2 = ArcCost( pFirst->nPos, pKth->pNext->nPos) +
D2 += ArcCost( pCurr->pNext->nPos, pCurr->nPos) ; ArcCost( pLast->nPos, pKth->nPos) ;
D4 = ArcCost( pLast->nPos, pFirst->nPos) +
ArcCost( pKth->nPos, pKth->pNext->nPos) ;
// Lunghezze originali e nuova del tratto intermedio che viene invertito
for ( NODE* pCurr = pFirst ; pCurr != pKth ; pCurr = pCurr->pNext) {
D4 += ArcCost( pCurr->nPos, pCurr->pNext->nPos) ;
D2 += ArcCost( pCurr->pNext->nPos, pCurr->nPos) ;
}
} }
// se esistono dipendenze suggerite
else {
D3 = static_cast<unsigned>( TotalCost( pPath)) ;
D4 = D3 ;
D1 = MAXDIST ;
D2 = MAXDIST ;
CopyPathAdv( pPath, m_pCheckDep, pLast, pFirst, pKth, &pLastDep, &pFirstDep, &pKthDep) ;
SwapNodesForHybrid1( pLastDep, pFirstDep, pKthDep) ;
bool bOkD1 = ( IsPathRespectingContraints( m_pCheckDep)) ;
if ( bOkD1)
D1 = static_cast<unsigned>( TotalCost( m_pCheckDep)) ;
CopyPathAdv( pPath, m_pCheckDep, pLast, pFirst, pKth, &pLastDep, &pFirstDep, &pKthDep) ;
SwapNodesForHybrid2( pLastDep, pFirstDep, pKthDep) ;
bool bOkD2 = ( IsPathRespectingContraints( m_pCheckDep)) ;
if ( bOkD2)
D2 = static_cast<unsigned>( TotalCost( m_pCheckDep)) ;
}
// controllo se ci sono miglioramenti nei persorsi
if ( D1 < D3 || D2 < D4) { if ( D1 < D3 || D2 < D4) {
if ( D1 < D3 && if ( D1 < D3 &&
( D2 >= D4 || ( D3 - D1) >= ( D4 - D2))) { ( D2 >= D4 || ( D3 - D1) >= ( D4 - D2))) {
NODE* pSave = pKth->pNext ; // nel caso di assenza di dipendenze
pKth->pNext = pKth->pNext->pNext ; if ( ! ExistConstraints()) {
pKth->pNext->pPrev = pKth ; SwapNodesForHybrid1( pLast, pFirst, pKth) ;
pLast->pNext = pSave ; count = 0 ;
pFirst->pPrev = pSave ; pFirst = pLast->pNext ;
pSave->pNext = pFirst ; pKth = pFirst->pNext ;
pSave->pPrev = pLast ; }
// nel caso di dipendeze, controllo se il nuovo percorso le rispetta
else {
CopyPathAdv( pPath, m_pCheckDep, pLast, pFirst, pKth, &pLastDep, &pFirstDep, &pKthDep) ;
// effettuo i cambi dei nodi sul path di test per le dipendenze
SwapNodesForHybrid1( pLastDep, pFirstDep, pKthDep) ;
// se il path di test rispetta i vincoli, allora effettuo i cambi sul percorso vero
if ( IsPathRespectingContraints( m_pCheckDep)) {
SwapNodesForHybrid1( pLast, pFirst, pKth) ;
count = 0 ;
pFirst = pLast->pNext ;
pKth = pFirst->pNext ;
}
// altrimenti passo al nodo successivo
else
pKth = pKth->pNext ;
}
} }
else { else {
for ( NODE* pReverse = pFirst ; pReverse != pKth ;) { // nel caso di assenza di dipendenze
NODE* pSave = pReverse->pNext ; if ( ! ExistConstraints()) {
pReverse->pNext = pReverse->pPrev ; SwapNodesForHybrid2( pLast, pFirst, pKth) ;
pReverse->pPrev = pSave ; count = 0 ;
pReverse = pSave ; pFirst = pLast->pNext ;
pKth = pFirst->pNext ;
}
// nel caso di dipendeze, controllo se il nuovo percorso le rispetta
else {
CopyPathAdv( pPath, m_pCheckDep, pLast, pFirst, pKth, &pLastDep, &pFirstDep, &pKthDep) ;
// effettuo i cambi dei nodi sul path di test per le dipendenze
SwapNodesForHybrid2( pLastDep, pFirstDep, pKthDep) ;
// se il path di test rispetta i vincoli, allora effettuo i cambi sul percorso vero
if ( IsPathRespectingContraints( m_pCheckDep)) {
SwapNodesForHybrid2( pLast, pFirst, pKth) ;
count = 0 ;
pFirst = pLast->pNext ;
pKth = pFirst->pNext ;
}
// altrimenti passo al nodo successivo
else
pKth = pKth->pNext ;
} }
pFirst->pNext = pKth->pNext ;
pKth->pNext->pPrev = pFirst ;
pKth->pNext = pKth->pPrev ;
pKth->pPrev = pLast ;
pLast->pNext = pKth ;
} }
count = 0 ; }
pFirst = pLast->pNext ;
pKth = pFirst->pNext ;
}
else else
pKth = pKth->pNext ; pKth = pKth->pNext ;
} while ( pKth != pLast->pPrev->pPrev && count != 0) ; } while ( pKth != pLast->pPrev->pPrev && count != 0) ;
+926
View File
@@ -0,0 +1,926 @@
//----------------------------------------------------------------------------
// EgalTech 2025-2025
//----------------------------------------------------------------------------
// File : MachOptimization.cpp Data : 31.03.25 Versione : 2.7a1
// Contenuto : Classe per calcolo ottimizzato per le lavorazioni.
//
//
// Modifiche : 31.03.2025 RE Creazione modulo.
//
//
//----------------------------------------------------------------------------
//--------------------------- Include ----------------------------------------
#include "stdafx.h"
#include "DllMain.h"
#include "MachOptimization.h"
#include "/EgtDev/Include/EGnStringUtils.h"
#include "/EgtDev/Include/EGkGeoConst.h"
#include "/EgtDev/Include/ENkShortestPath.h"
#include "/EgtDev/Include/EgtPointerOwner.h"
#include <set>
#include <new>
/* Nomenclatura :
- TC = Tool Change ( cambio utensile )
*/
#define _DEBUG_OPT 0
#define _TIME_DEBUG 0
#if _TIME_DEBUG
#include "/EgtDev/Include/EgtPerfCounter.h"
#endif
using namespace std ;
// Tempo massimo di lavorazione
static const int MAXTIME = 1073741823U ;
// Dato che tutte le distanze sono salvate come intere ( se ho 4 lavorazioni disposte sui vertici di un
// quadrato unitario, la distanza tra i vertici di uno stesso lato e tra i vertici delle diagonali
// risulta sempre 1, quindi moltiplico per COEFF in modo da avere una maggiore precisione.
// ( vertici su un lato -> dist = 1000, vertici sulla diagonale -> dist = 1414)
// invece che ( vertici su un lato -> dist = int( 1) = 1, vertici sulla diagonale -> dist = int( sqrt( 2)) = 1)
static const int COEFF = 1000 ;
//----------------------------------------------------------------------------
IMachOptimization*
CreateMachOptimization( void)
{
return static_cast<IMachOptimization*> ( new( nothrow) MachOptimization) ;
}
//----------------------------------------------------------------------------
MachOptimization::MachOptimization( void)
{
m_vMachOptm.clear() ;
m_vToolOptm.clear() ;
m_vDependences.clear() ;
m_vSuggDependences.clear() ;
m_dFeedL = 1. ;
m_dFeedA = 1. ;
m_bAllMandatory = false ;
m_bOptInGroup = false ;
m_vOpenBounds.clear() ;
}
//----------------------------------------------------------------------------
MachOptimization::~MachOptimization( void)
{
}
//----------------------------------------------------------------------------
/* Funzione per inserire un Utensile */
bool
MachOptimization::InsertTool( int nId, double dTCX, double dTCY, double dTCZ, double dTCA,
double dTCB, double dTCC, bool bX, bool bY, bool bZ, bool bA,
bool bB, bool bC, double dTLoad, double dTUnL)
{
// Controllo se Id già presente
for ( const ToolOptm& currTool : m_vToolOptm) {
if ( currTool.nId == nId) {
LOG_ERROR( GetENkLogger(), ( "Duplicated Tool id : " + ToString( nId)).c_str()) ;
return false ;
}
}
// Tempi sempre positivi
if ( dTLoad < 0. || dTUnL < 0.) {
LOG_ERROR( GetENkLogger(), string( ( "Time must be positive :")).c_str()) ;
return false ;
}
// Inserisco il nuovo record
m_vToolOptm.emplace_back( nId, dTCX, dTCY, dTCZ, dTCA, dTCB, dTCC, bX, bY, bZ, bA, bB, bC, dTLoad, dTUnL) ;
return true ;
}
//----------------------------------------------------------------------------
/* Funzione per inserire una Lavorazione */
bool
MachOptimization::InsertMachining( int nId, int nToolId, int nGroup,
double dX_Start, double dY_Start, double dZ_Start,
double dA_Start, double dB_Start, double dC_Start,
double dX_End, double dY_End, double dZ_End,
double dA_End, double dB_End, double dC_End)
{
// Controllo se Id già presente
for ( const MachOptm& currMach : m_vMachOptm) {
if ( currMach.nId == nId) {
LOG_ERROR( GetENkLogger(), ( "Duplicated Machining id : " + ToString( nId)).c_str()) ;
return false ;
}
}
// Controllo che l'utensile sia stato precedentemente inserito
bool bOk = false ;
for ( const ToolOptm& currTool : m_vToolOptm) {
bOk = currTool.nId == nToolId ;
if ( bOk)
break ;
}
if ( ! bOk) {
LOG_ERROR( GetENkLogger(), ( "Tool not found : " + ToString( nToolId)).c_str()) ;
return false ;
}
// Inserisco il nuovo record
m_vMachOptm.emplace_back( nId, nToolId, nGroup, dX_Start, dY_Start, dZ_Start,
dA_Start, dB_Start,dC_Start, dX_End, dY_End, dZ_End, dA_End, dB_End, dC_End) ;
return true ;
}
//----------------------------------------------------------------------------
/* Funzione per l'inserimento delle dipendenze di ordine tra le lavorazioni [devono essere rispettate]
( nIdPrev deve essere eseguita prima di nIdNext ) */
bool
MachOptimization::InsertDependence( int nIdPrev, int nIdNext)
{
// Check della dipendenza con quelle inserite
bool bExist = false ;
bool bConflict = false ;
if ( ! CheckDependences( nIdPrev, nIdNext, m_vDependences, false, bExist, bConflict))
return false ;
// Se esiste di già, non faccio nulla
if ( bExist)
return true ;
// Se in conflitto, allora errore
if ( bConflict)
return false ;
// Inserisco la nuova dipendenza
m_vDependences.emplace_back( make_pair( nIdPrev, nIdNext)) ;
return true ;
}
//----------------------------------------------------------------------------
/* Funzione per l'inserimento delle dipendenze di ordine tra le lavorazioni [si cerca di rispettarle]
( nIdPrev dovrebbe essere eseguita prima di nIdNext ) */
bool
MachOptimization::InsertSuggestedDependences( int nIdPrev, int nIdNext)
{
// Check della dipendenza con quelle inserite
bool bExist = false ;
bool bConflict = false ;
if ( ! CheckDependences( nIdPrev, nIdNext, m_vSuggDependences, false, bExist, bConflict))
return false ;
// Se già presente non faccio nulla
if ( bExist)
return true ;
// Inserisco la nuova dipendenza
m_vSuggDependences.emplace_back( make_pair( nIdPrev, nIdNext)) ;
return true ;
}
//----------------------------------------------------------------------------
/* Funzione per impostare la prima Lavorazione */
bool
MachOptimization::SetFirstMachining( int nId)
{
// Controllo che l'Id sia presente
if ( find_if( m_vMachOptm.begin(), m_vMachOptm.end(), [&]( const MachOptm& Lav) {
return Lav.nId == nId ;
}) == m_vMachOptm.end()) {
LOG_ERROR( GetENkLogger(), ( "Machining id not found : " + ToString( nId)).c_str()) ;
return false ;
}
// Assegno la prima lavorazione
for ( int i = 0 ; i < int( m_vMachOptm.size()) ; ++ i) {
if ( m_vMachOptm[i].nId == nId)
continue ;
if ( ! InsertDependence( nId, m_vMachOptm[i].nId))
return false ;
}
return true ;
}
//----------------------------------------------------------------------------
/* Funzione per impostare l'ultima Lavorazione */
bool
MachOptimization::SetLastMachining( int nId)
{
// Controllo che l'Id sia presente
if ( find_if( m_vMachOptm.begin(), m_vMachOptm.end(), [&]( const MachOptm& Lav) {
return Lav.nId == nId ;
}) == m_vMachOptm.end()) {
LOG_ERROR( GetENkLogger(), ( "Machining id not found : " + ToString( nId)).c_str()) ;
return false ;
}
// Assegno l'ultima lavorazione
for ( int i = 0 ; i < int( m_vMachOptm.size()) ; ++ i) {
if ( m_vMachOptm[i].nId == nId)
continue ;
if ( ! InsertDependence( m_vMachOptm[i].nId, nId))
return false ;
}
return true ;
}
//----------------------------------------------------------------------------
/* Funzione per impostare la Feed Lineare e Angolare */
bool
MachOptimization::SetFeeds( double dFeedL, double dFeedA)
{
// Controllo dei valori
if ( dFeedL < EPS_ZERO || dFeedA < EPS_ZERO) {
LOG_ERROR( GetENkLogger(), string( " Feeds must be positive").c_str()) ;
return false ;
}
// Assegno le Feed
m_dFeedL = dFeedL ;
m_dFeedA = dFeedA ;
return true ;
}
//----------------------------------------------------------------------------
/* Funzione per impostare ogni dipendenza da Gruppo come vincolo */
bool
MachOptimization::SetAllGroupsAsMandatory( bool bAllMandatory)
{
m_bAllMandatory = bAllMandatory ;
return true ;
}
//----------------------------------------------------------------------------
bool
MachOptimization::SetOptimizationForGroups( bool bOptForGroups)
{
m_bOptInGroup = bOptForGroups ;
return true ;
}
//-----------------------------------------------------------------------------
bool
MachOptimization::SetOpenBound( bool bStartVsEnd, int nFlag, double dX, double dY, double dZ)
{
// Se parametro Start o End già impostato, lo sovrascrivo
for ( int i = 0 ; i < int( m_vOpenBounds.size()) ; ++ i) {
if ( m_vOpenBounds[i].bStartVsEnd == bStartVsEnd) {
m_vOpenBounds[i].nFlag = nFlag ;
m_vOpenBounds[i].dX = dX ;
m_vOpenBounds[i].dY = dY ;
m_vOpenBounds[i].dZ = dZ ;
return true ;
}
}
// altrimenti lo inserisco
m_vOpenBounds.emplace_back( -1, bStartVsEnd, nFlag, dX, dY, dZ) ;
return true ;
}
//----------------------------------------------------------------------------
bool
MachOptimization::SetOpenBoundForGroups( int nGroup, bool bStartVsEnd, int nFlag, double dX, double dY, double dZ)
{
// Se parametro Start o End del Gruppo scelto già impostato, lo sovrascrivo
for ( int i = 0 ; i < int( m_vOpenBounds.size()) ; ++ i) {
if ( m_vOpenBounds[i].nGroup == nGroup && m_vOpenBounds[i].bStartVsEnd == bStartVsEnd) {
m_vOpenBounds[i].nFlag = nFlag ;
m_vOpenBounds[i].dX = dX ;
m_vOpenBounds[i].dY = dY ;
m_vOpenBounds[i].dZ = dZ ;
return true ;
}
}
// altrimenti lo inserisco
m_vOpenBounds.emplace_back( nGroup, bStartVsEnd, nFlag, dX, dY, dZ) ;
return true ;
}
//----------------------------------------------------------------------------
/* Funzione che assegna le dipendenze suggerite in base ai Gruppi */
bool
MachOptimization::SetGroupDependences( void)
{
// Se ho meno di due lavorazioni, non devo fare nulla
if ( int( m_vMachOptm.size()) < 2)
return true ;
// Recupero i diversi gruppi ( ordinati per priorità, quindi ordine decrescente)
set<int, greater<int>> setGroup ;
for ( const MachOptm& currLav : m_vMachOptm)
setGroup.insert( currLav.nGroup) ;
// Se presente un solo gruppo, non devo fare nulla
if ( int( setGroup.size()) == 1)
return true ;
// Scorro i gruppi ordinati per priorità e assegno le dipendenze suggerite
for ( auto it = setGroup.begin() ; it != setGroup.end() ; ++ it) {
// Cerco tutti gli indici delle lavorazioni con quella priorità e quelli con priorità inferiore
INTVECTOR vIndSamePriorityLav ; vIndSamePriorityLav.reserve( m_vMachOptm.size()) ;
INTVECTOR vIndLowerPriorityLav ; vIndLowerPriorityLav.reserve( m_vMachOptm.size()) ;
for ( int i = 0 ; i < int( m_vMachOptm.size()) ; ++ i) {
if ( m_vMachOptm[i].nGroup == *it)
vIndSamePriorityLav.emplace_back( i) ;
else if ( m_vMachOptm[i].nGroup < *it)
vIndLowerPriorityLav.emplace_back( i) ;
}
// Scorro le Lavorazioni che hanno la priorità massima corrente
for ( const int& nInd : vIndSamePriorityLav) {
// Scorro le Lavorazioni con priorità inferiore
for ( const int& nInd_LowerPriority : vIndLowerPriorityLav) {
// Assegno la dipendenze
if ( m_bAllMandatory) {
if ( ! InsertDependence( m_vMachOptm[nInd].nId, m_vMachOptm[nInd_LowerPriority].nId))
return false ;
}
else {
if ( ! InsertSuggestedDependences( m_vMachOptm[nInd].nId, m_vMachOptm[nInd_LowerPriority].nId))
return false ;
}
}
}
}
return true ;
}
//----------------------------------------------------------------------------
/* Funzione per il controllo delle dipendenze inserite : se già presenti o se in conflitto */
bool
MachOptimization::CheckDependences( int nIdPrev, int nIdNext, const INTINTVECTOR& vDep,
bool bBlockMessages, bool& bExist, bool& bConflict) const
{
bExist = false ;
bConflict = false ;
// controllo che tali Id siano entrambi presenti tra le lavorazioni, in caso opposto errore
bool bOkIdPrev = false ;
bool bOkIdNext = false ;
for ( const MachOptm& currLav : m_vMachOptm) {
if ( ! bOkIdPrev && currLav.nId == nIdPrev)
bOkIdPrev = true ;
if ( ! bOkIdNext && currLav.nId == nIdNext)
bOkIdNext = true ;
if ( bOkIdPrev && bOkIdNext)
break ;
}
if ( ! bOkIdPrev || ! bOkIdNext) {
if ( ! bBlockMessages)
LOG_ERROR( GetENkLogger(), ( "Discharged Dependence, Id not found (" + ToString( nIdPrev) + "," + ToString( nIdNext) + ")").c_str()) ;
return false ;
}
// controllo se la dipendenza è già stata inserita e che non sia presente una dipendeza inversa (conflitto)
// (... (Id_i, Id_j) , ... , ( Id_j, Id_i), ...)
for ( const auto& currDep : vDep) {
if ( currDep.first == nIdPrev && currDep.second == nIdNext) {
bExist = true ;
if ( ! bBlockMessages)
LOG_INFO( GetENkLogger(), ( "Already found Dependence (" + ToString( nIdPrev) + "," + ToString( nIdNext) + ")").c_str()) ;
return true ;
}
if ( currDep.second == nIdPrev && currDep.first == nIdNext) {
bConflict = true ;
if ( ! bBlockMessages)
LOG_ERROR( GetENkLogger(), ( "Conflict Dependence (" + ToString( nIdPrev) + "," + ToString( nIdNext) + ")").c_str()) ;
return true ;
}
}
return true ;
}
//----------------------------------------------------------------------------
/* Funzione per il calcolo della distanza euclidea tra assi Lineari o Angolari di due lavorazioni
Considerando lo stesso utensile */
double
MachOptimization::CalcTimeLavLav( const MachOptm& Lav1, const MachOptm& Lav2, bool bLin) const
{
double dDist = 0. ;
double dFeed = EPS_SMALL ;
if ( bLin) {
/* Lav1 -- Feed Lineare --> Lav2 */
dDist = sqrt( ( Lav2.dX_Start - Lav1.dX_End) * ( Lav2.dX_Start - Lav1.dX_End) +
( Lav2.dY_Start - Lav1.dY_End) * ( Lav2.dY_Start - Lav1.dY_End) +
( Lav2.dZ_Start - Lav1.dZ_End) * ( Lav2.dZ_Start - Lav1.dZ_End)) ;
dFeed = m_dFeedL ;
}
else {
/* Lav1 -- Feed Angolare --> Lav2 */
dDist = sqrt( ( Lav2.dA_Start - Lav1.dA_End) * ( Lav2.dA_Start - Lav1.dA_End) +
( Lav2.dB_Start - Lav1.dB_End) * ( Lav2.dB_Start - Lav1.dB_End) +
( Lav2.dC_Start - Lav1.dC_End) * ( Lav2.dC_Start - Lav1.dC_End)) ;
dFeed = m_dFeedA ;
}
return COEFF * ( dDist / dFeed) ;
}
//----------------------------------------------------------------------------
/* Funzione per il calcolo della distanza euclidea tra assi Lineari o Angolari tra una lavorazione e
il suo TC */
bool
MachOptimization::CalcTimeLavLavTC( const MachOptm& Lav1, const MachOptm& Lav2, bool bLin,
double& dTimeLav1TC1, double& dTimeTC1TC2, double& dTimeTC2Lav2,
double& dTUnload1, double& dTLoad2) const
{
/*
dTimeLav1TC1 : Tempo tra EndPoint di Lav1 e Posizione di TC per Utensile di Lav1
dTimeTC1TC2 : Tempo di cambio utensile tra Tool di Lav1 e Lav2
dTimeTC2Lav2 : Tempo tra TC per utensile Lav2 e StartPoint di Lav2
*/
dTimeLav1TC1 = 0. ;
dTimeTC1TC2 = 0. ;
dTimeTC2Lav2 = 0. ;
dTUnload1 = 0. ;
dTLoad2 = 0. ;
// Recupero Utensile Lav1 e Lav2
int nIndToolLav1 = -1 ;
int nIndToolLav2 = -1 ;
bool bFoundToolLav1 = false ;
bool bFoundToolLav2 = false ;
for ( int i = 0 ; i < int( m_vToolOptm.size()) ; ++ i) {
bFoundToolLav1 = ( m_vToolOptm[i].nId == Lav1.nIdTool) ;
if ( bFoundToolLav1)
nIndToolLav1 = i ;
bFoundToolLav2 = ( m_vToolOptm[i].nId == Lav2.nIdTool) ;
if ( bFoundToolLav2)
nIndToolLav2 = i ;
if ( nIndToolLav1 != -1 && nIndToolLav2 != -1)
break ;
}
if ( nIndToolLav1 == -1)
LOG_INFO( GetENkLogger(), ( "Tool Not Found :" + ToString( Lav1.nIdTool)).c_str()) ;
if ( nIndToolLav2 == -1)
LOG_INFO( GetENkLogger(), ( "Tool Not Found :" + ToString( Lav2.nIdTool)).c_str()) ;
if ( nIndToolLav1 == -1 || nIndToolLav2 == -1)
return false ;
const ToolOptm& ToolLav1 = m_vToolOptm[nIndToolLav1] ;
const ToolOptm& ToolLav2 = m_vToolOptm[nIndToolLav2] ;
// Imposto i tempi di carico e scarico degli utensili
dTUnload1 = COEFF * ToolLav1.dTUnLoad ;
dTLoad2 = COEFF * ToolLav2.dTLoad ;
// Se distanza lineare
if ( bLin) {
// Come primo tempo considero quello tra la fine di Lav1 e TC1
double dXi = Lav1.dX_End ;
double dXe = ( ToolLav1.bTCX ? ToolLav1.dTCX : dXi) ;
double dYi = Lav1.dY_End ;
double dYe = ( ToolLav1.bTCY ? ToolLav1.dTCY : dYi) ;
double dZi = Lav1.dZ_End ;
double dZe = ( ToolLav1.bTCZ ? ToolLav1.dTCZ : dZi) ;
double dDist = sqrt( ( dXe - dXi) * ( dXe - dXi) + ( dYe - dYi) * ( dYe - dYi) + ( dZe - dZi) * ( dZe - dZi)) ;
dTimeLav1TC1 = COEFF * ( dDist / m_dFeedL) ;
// Come secondo tempo considero quello tra TC1 e TC2
dXi = dXe ;
dXe = ( ToolLav2.bTCX ? ToolLav2.dTCX : dXi) ;
dYi = dYe ;
dYe = ( ToolLav2.bTCY ? ToolLav2.dTCY : dYi) ;
dZi = dZe ;
dZe = ( ToolLav2.bTCZ ? ToolLav2.dTCZ : dZi) ;
dDist = sqrt( ( dXe - dXi) * ( dXe - dXi) + ( dYe - dYi) * ( dYe - dYi) + ( dZe - dZi) * ( dZe - dZi)) ;
dTimeTC1TC2 = COEFF * ( dDist / m_dFeedL) ;
// Come terzo tempo considero quello tra TC2 e Lav2
dXi = dXe ;
dYe = Lav2.dX_Start ;
dYi = dYe ;
dYe = Lav2.dY_Start ;
dZi = dZe ;
dZe = Lav2.dZ_Start ;
dDist = sqrt( ( dXe - dXi) * ( dXe - dXi) + ( dYe - dYi) * ( dYe - dYi) + ( dZe - dZi) * ( dZe - dZi)) ;
dTimeTC2Lav2 = COEFF * ( dDist / m_dFeedL) ;
}
// Se distanza angolare
else {
// Come primo tempo considero quello tra la fine di Lav1 e TC1
double dAi = Lav1.dA_Start ;
double dAe = ( ToolLav1.dTCA ? ToolLav1.dTCA : dAi) ;
double dBi = Lav1.dB_Start ;
double dBe = ( ToolLav1.dTCB ? ToolLav1.dTCB : dBi) ;
double dCi = Lav1.dC_Start ;
double dCe = ( ToolLav1.dTCC ? ToolLav1.dTCC : dCi) ;
double dDist = sqrt( ( dAe - dAi) * ( dAe - dAi) + ( dBe - dBi) * ( dBe - dBi) + ( dCe - dCi) * ( dCe - dCi)) ;
dTimeLav1TC1 = COEFF * ( dDist / m_dFeedA) ;
// Come secondo tempo considero quello tra TC1 e TC2
dAi = dAe ;
dAe = ( ToolLav2.bTCA ? ToolLav2.dTCA : dAi) ;
dBi = dBe ;
dBe = ( ToolLav2.bTCB ? ToolLav2.dTCB : dBi) ;
dCi = dCe ;
dCe = ( ToolLav2.bTCC ? ToolLav2.dTCC : dCi) ;
dDist = sqrt( ( dAe - dAi) * ( dAe - dAi) + ( dBe - dBi) * ( dBe - dBi) + ( dCe - dCi) * ( dCe - dCi)) ;
dTimeTC1TC2 = COEFF * ( dDist / m_dFeedA) ;
// Come terzo tempo considero quello tra TC2 e Lav2
dAi = dAe ;
dAe = Lav2.dA_Start ;
dBi = dBe ;
dBe = Lav2.dB_Start ;
dCi = dCe ;
dCe = Lav2.dC_Start ;
dDist = sqrt( ( dAe - dAi) * ( dAe - dAi) + ( dBe - dBi) * ( dBe - dBi) + ( dCe - dCi) * ( dCe - dCi)) ;
dTimeTC2Lav2 = COEFF * ( dDist / m_dFeedA) ;
}
return true ;
}
//----------------------------------------------------------------------------
/* Funzione per calcolare il tempo nel passare dalla lavorazione nInd1-esima alla lavorazione
nInd2-esima */
bool
MachOptimization::CalcMachTime( int nInd1, int nInd2, int& nTime) const
{
// Se Indice fuori dal range, errore
nTime = 0 ;
if ( nInd1 < 0 || nInd1 >= int( m_vMachOptm.size()) ||
nInd2 < 0 || nInd2 >= int( m_vMachOptm.size()))
return false ;
// Recupero riferimento delle due lavorazioni
const MachOptm& Lav1 = m_vMachOptm[nInd1] ;
const 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) const
{
// Se l'utensile è lo stesso
if ( Lav1.nIdTool == Lav2.nIdTool)
nTime = int( max( CalcTimeLavLav( Lav1, Lav2, true), CalcTimeLavLav( Lav1, Lav2, false))) ;
else {
double dLTime1, dLTime2, dLTime3 ;
double dATime1, dATime2, dATime3 ;
double dTUnload1, dTLoad2 ;
if ( ! CalcTimeLavLavTC( Lav1, Lav2, true, dLTime1, dLTime2, dLTime3, dTUnload1, dTLoad2) ||
! CalcTimeLavLavTC( Lav1, Lav2, false, dATime1, dATime2, dATime3, dTUnload1, dTLoad2)) {
LOG_ERROR( GetENkLogger(), "Error in computing time") ;
return false ;
}
nTime += int( max( dLTime1, dATime1) + max( dLTime2, dATime2) + max( dLTime3, dATime3)) ;
// Sommo i tempi di carico e scarico dei due utensili
nTime += int( dTUnload1) + int( dTLoad2) ;
}
return true ;
}
//----------------------------------------------------------------------------
/* Funzione per il calcolo della Matrice dei tempi (NxN), dove N = #Lavorazioni */
bool
MachOptimization::ComputeTimeMatrix( INTMATRIX& mTimes) const
{
// Creo una copia dei vettori delle dipendenze ( le cancello di volta in volta che le assegno)
const int N = int( m_vMachOptm.size()) ;
// Matrice NxN ( con Flag per cella già calcolata)
mTimes.clear() ;
mTimes.resize( N) ;
for ( auto& Row : mTimes)
Row.resize( N) ;
// Calcolo i tempi tra tutte le lavorazioni
for ( int i = 0 ; i < N ; ++ i) {
for ( int j = 0 ; j < N ; ++ j) {
// Se sono sulla diagonale, allora il tempo è infinito
if ( i == j) {
mTimes[i][j] = MAXTIME ;
continue ;
}
// Se sono nella cella ( i, j), calcolo il tempo necessario
if ( ! CalcMachTime( i, j, mTimes[i][j]))
return false ;
}
}
#if _DEBUG_OPT
string sRowSplit = "" ;
for ( int i = 0 ; i < N ; ++ i)
sRowSplit += "----------" ;
for ( int i = -1 ; i < N ; ++ i) {
// Intestazione
if ( i == -1) {
LOG_INFO( GetENkLogger(), sRowSplit.c_str()) ;
string sCell = "**********" ;
for ( int j = 0 ; j < N ; ++ j) {
int nId = m_vMachOptm[j].nId ;
string sId = ToString( nId) ;
int nLen = sId.length() ;
for ( int k = 0 ; k < 10 - nLen ; ++ k)
sCell += " " ;
sCell += sId ;
}
LOG_INFO( GetENkLogger(), sCell.c_str()) ;
continue ;
}
// Prima riga della colonna
string sRow = "|" ;
int nId = m_vMachOptm[i].nId ;
string sId = ToString( nId) ;
int nLen = sId.length() ;
for ( int k = 0 ; k < 8 - nLen ; ++ k)
sRow += " " ;
sRow += sId ;
sRow += "|" ;
for ( int j = 0 ; j < N ; ++ j) {
double dTime = mTimes[i][j] ;
string sTime = ( dTime > MAXTIME - 1 ? "inf" : ToString( dTime, 1)) ;
int nLen = sTime.length() ;
for ( int k = 0 ; k < 9 - nLen ; ++ k)
sRow += " " ;
sRow += sTime ;
sRow += "|" ;
}
LOG_INFO( GetENkLogger(), sRow.c_str()) ;
}
LOG_INFO( GetENkLogger(), sRowSplit.c_str()) ;
#endif
return true ;
}
//----------------------------------------------------------------------------
/* Funzione che restituisce la posizione della lavorazione di Id pari a nId nel vettore delle lavorazioni */
int
MachOptimization::GetIndById( int nId) const
{
// Scorro le lavorazioni
for ( int i = 0 ; i < int( m_vMachOptm.size()) ; ++ i) {
if ( m_vMachOptm[i].nId == nId)
return i ;
}
return -1 ;
}
//----------------------------------------------------------------------------
/* Funzione per separare le lavorazioni e le dipendenze a seconda dei gruppi */
bool
MachOptimization::SplitMachOptsInGroups( MACHOPTMMATRIX& matMachOpt, vector<INTINTVECTOR>& matDep,
vector<INTINTVECTOR>& 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::GetGlobalResult( INTVECTOR& vIds)
{
// 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<IShortestPath> 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 ;
}
}
// Se presenti dei incoli di OpenBound, li assegno
if ( ! m_vOpenBounds.empty()) {
for ( const OpenBoundOptm& OB : m_vOpenBounds) {
if ( OB.nGroup == -1) {
if ( ! mySP->SetOpenBound( OB.bStartVsEnd, OB.nFlag, OB.dX, OB.dY, OB.dZ, 0., 0.)) {
LOG_ERROR( GetENkLogger(), "Error in adding OpenBound") ;
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 ;
return true ;
}
//----------------------------------------------------------------------------
bool
MachOptimization::GetGroupResult( INTVECTOR& vIds)
{
// Se Flag ottimizzazione di gruppo non attivo, errore
if ( ! m_bOptInGroup)
return false ;
// Recupero tutti i gruppi e le dipendenze separatamente ed ordinate per priorità di gruppo
MACHOPTMMATRIX matMachOpt ;
vector<INTINTVECTOR> 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<IShortestPath> 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 presente un vincolo OpenBound lo assegno
bool bForStart = false ;
for ( const OpenBoundOptm& OB : m_vOpenBounds) {
if ( OB.nGroup == m_vMachOptm[0].nGroup) {
bForStart = ( bForStart || OB.bStartVsEnd) ;
if ( ! mySP->SetOpenBound( OB.bStartVsEnd, OB.nFlag, OB.dX, OB.dY, OB.dZ, 0., 0.)) {
LOG_ERROR( GetENkLogger(), "Error in adding OpenBound") ;
return false ;
}
}
}
// Se ho una lavorazione impostata in precedenza e nessun vincolo OpenBound
if ( ! bForStart && 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()]) ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
MachOptimization::Calculate( INTVECTOR& vIds)
{
// Se non ho lavorazioni, allora non faccio nulla
vIds.clear() ;
if ( m_vMachOptm.empty())
return true ;
// Se ho una sola lavorazione allora ritorno se stessa
if ( int( m_vMachOptm.size()) == 1) {
vIds.push_back( m_vMachOptm[0].nId) ;
return true ;
}
// --- Se richiesta ottimizzazione solo interna per i gruppi
if ( m_bOptInGroup)
return ( GetGroupResult( vIds)) ;
// --- Se invece ottimizzazione globale
return ( GetGlobalResult( vIds)) ;
}
+87
View File
@@ -0,0 +1,87 @@
//----------------------------------------------------------------------------
// EgalTech 2025-2025
//----------------------------------------------------------------------------
// File : MachOptimization.h Data : 31.03.25 Versione : 2.7a1
// Contenuto : Classe per calcolo ottimizzato per le lavorazioni.
//
//
// Modifiche : 31.03.2025 RE Creazione modulo.
//
//
//----------------------------------------------------------------------------
#pragma once
#include "/EgtDev/Include/ENkMachOptimization.h"
using namespace std ;
//----------------------------------------------------------------------------
class MachOptimization : public IMachOptimization
{
public :
~MachOptimization( void) override ;
// Inserimento
bool InsertTool( int nId, double dTCX, double dTCY, double dTCZ, double dTCA,
double dTCB, double dTCC, bool bX, bool bY, bool bZ, bool bA,
bool bB, bool bC, double dTLoad, double dTUnL) override ;
bool InsertMachining( int nId, int nToolId, int nGroup,
double dX_Start, double dY_Start, double dZ_Start,
double dA_Start, double dB_Start, double dC_Start,
double dX_End, double dY_End, double dZ_End,
double dA_End, double dB_End, double dC_End) override ;
bool InsertDependence( int nIdPrec, int nIdNext) override ;
bool InsertSuggestedDependences( int nIdPrec, int nIdNext) override ;
// Impostazione parametri lavorazione
bool SetFirstMachining( int nId) override ;
bool SetLastMachining( int nId) override ;
bool SetFeeds( double dFeedL, double dFeedA) override ;
bool SetAllGroupsAsMandatory( bool bAllMandatory) override ;
bool SetOptimizationForGroups( bool bOptForGroups) override ;
bool SetOpenBound( bool bStartVsEnd, int nFlag, double dX, double dY, double dZ) override ;
bool SetOpenBoundForGroups( int nGroup, bool bStartVsEnd, int nFlag, double dX, double dY, double dZ) override ;
// Risultati
bool Calculate( INTVECTOR& vIds) override ;
public :
MachOptimization( void) ;
private :
// Calcolo dei tempi tra le lavorazioni
double CalcTimeLavLav( const MachOptm& Lav1, const MachOptm& Lav2, bool bLin) const ;
bool CalcTimeLavLavTC( const MachOptm& Lav1, const MachOptm& Lav2, bool bLin,
double& dTimeLav1TC1, double& dTimeTC1TC2, double& dTimeTC2Lav2,
double& dTUnload1, double& dTLoad2) const ;
bool CalcMachTime( int nInd1, int nInd2, int& nTime) const ;
bool CalcMachTime( const MachOptm& Lav1, const MachOptm& Lav2, int& nTime) const ;
// Controllo Conflitti tra dipendenze e Gestione Dipendenze
bool CheckDependences( int nIdPrev, int nIdNext, const INTINTVECTOR& vDep,
bool bBlockMessages, bool& bExist, bool& bConflict) const ;
bool SetGroupDependences( void) ;
// Calcolo della Matrice dei tempi, Del fattore perso dipendenze suggerite e della soluzione ottimale
bool ComputeTimeMatrix( INTMATRIX& mTimes) const ;
// Calcolo dei risultati a seconda della modalità
bool GetGlobalResult( INTVECTOR& vIds) ;
bool GetGroupResult( INTVECTOR& vIds) ;
// Utility
int GetIndById( int nId) const ;
bool SplitMachOptsInGroups( MACHOPTMMATRIX& matMachOpt, vector<INTINTVECTOR>& matDep,
vector<INTINTVECTOR>& matSuggDep) ;
private :
MACHOPTMVECTOR m_vMachOptm ; // Vettore delle lavorazioni
TOOLOPTMVECTOR m_vToolOptm ; // Vettore degli utensili
INTINTVECTOR m_vDependences ; // Vettore di dipendenze ( IdPrev, IdSucc) -> deve essere rispettato
INTINTVECTOR m_vSuggDependences ; // Vettore delle dipendenze suggerite ( IdPrev, IdSucc) -> si cerca di rispettarle
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
MACHOPTOPENBOUNDVECTOR m_vOpenBounds ; // Vettore dei punti OpenBound
} ;
+50 -26
View File
@@ -26,34 +26,59 @@ ShortestPath::NearNeighbor( void)
m_Available[ Index( i, i)] = false ; m_Available[ Index( i, i)] = false ;
} }
// cerco il nodo con il più corto arco che se ne diparte // se non ho dipendenze
unsigned nCurr = 0 ; if ( ! ExistConstraints()) {
unsigned nNew = CheapArc( nCurr) ; // cerco il nodo con il più corto arco che se ne diparte
for ( unsigned i = 1 ; i < m_nNumPnts ; ++ i) { unsigned nCurr = 0 ;
unsigned j = CheapArc( i) ; unsigned nNew = CheapArc( nCurr) ;
if ( ArcCost( i, j) < ArcCost( nCurr, nNew)) { for ( unsigned i = 1 ; i < m_nNumPnts ; ++ i) {
nCurr = i ; unsigned j = CheapArc( i) ;
nNew = j ; if ( ArcCost( i, j) < ArcCost( nCurr, nNew)) {
nCurr = i ;
nNew = j ;
}
} }
// imposto il nodo corrente come base del percorso
NODE* pPath = m_pMain ;
pPath->nPos = nCurr ;
// ciclo
do {
// imposto tutti gli archi non disponibili al nodo corrente
for ( unsigned i = 0 ; i < m_nNumPnts ; ++ i)
m_Available[ Index( i, nCurr)] = false ;
// aggiungo un nuovo nodo al percorso
pPath = pPath->pNext ;
pPath->nPos = nNew ;
// imposto il nuovo nodo come nodo corrente
nCurr = nNew ;
// cerco il nuovo nodo all'estremo dell'arco più corto dal nodo corrente
nNew = CheapArc( nCurr) ;
} while ( m_Available[ Index( nCurr, nNew)]) ;
} }
// se esistono dipendenze
// imposto il nodo corrente come base del percorso else {
NODE* pPath = m_pMain ; // cerco il primo nodo da cui iniziare
pPath->nPos = nCurr ; unsigned nNew = -1 ;
if ( ! ChooseFirstNode( nNew))
// ciclo return MAXDIST ;
do { // imposto il nodo corrente come base del percorso
// imposto tutti gli archi non disponibili al nodo corrente NODE* pPath = m_pMain ;
for ( unsigned i = 0 ; i < m_nNumPnts ; ++ i)
m_Available[ Index( i, nCurr)] = false ;
// aggiungo un nuovo nodo al percorso
pPath = pPath->pNext ;
pPath->nPos = nNew ; pPath->nPos = nNew ;
// imposto il nuovo nodo come nodo corrente unsigned nSize = 1 ;
nCurr = nNew ; // ciclo
// cerco il nuovo nodo all'estremo dell'arco più corto dal nodo corrente do {
nNew = CheapArc( nCurr) ; // imposto tutti gli archi non disponibili al nodo corrente
} while ( m_Available[ Index( nCurr, nNew)]) ; for ( unsigned i = 0 ; i < m_nNumPnts ; ++ i)
m_Available[ Index( i, nNew)] = false ;
// cerco il nuovo nodo all'estremo dell'arco più corto dal nodo corrente
if ( ! ChooseNextNode( pPath, nSize, nNew, true))
return MAXDIST ;
// aggiungo un nuovo nodo al percorso
pPath = pPath->pNext ;
pPath->nPos = nNew ;
++ nSize ;
} while ( nSize < m_nNumPnts) ;
}
// calcolo il costo del percorso // calcolo il costo del percorso
return TotalCost( m_pMain) ; return TotalCost( m_pMain) ;
@@ -73,6 +98,5 @@ ShortestPath::CheapArc( unsigned i)
if ( ArcCost( i, k) < ArcCost( i, j)) if ( ArcCost( i, k) < ArcCost( i, j))
j = k ; j = k ;
} }
return j ; return j ;
} }
+50 -10
View File
@@ -20,6 +20,17 @@
#include "stdafx.h" #include "stdafx.h"
#include "ShortestPath.h" #include "ShortestPath.h"
static void
SwapNodesForPntOpt( NODE* pFirst, NODE* pLast, NODE* pBest)
{
pFirst->pPrev = pLast->pPrev ;
pLast->pPrev->pNext = pFirst ;
pLast->pPrev = pBest ;
pLast->pNext = pBest->pNext ;
pBest->pNext = pLast ;
pLast->pNext->pPrev = pLast ;
}
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
long long unsigned long long unsigned
ShortestPath::PointOpt( NODE* pPath) ShortestPath::PointOpt( NODE* pPath)
@@ -27,33 +38,62 @@ ShortestPath::PointOpt( NODE* pPath)
// ciclo di tentativi di spostamento di un punto // ciclo di tentativi di spostamento di un punto
unsigned nCount = 1 ; unsigned nCount = 1 ;
NODE* pFirst = pPath ; NODE* pFirst = pPath ;
NODE* pFirstDep = m_pCheckDep ;
do { do {
unsigned nBestImprove = 0 ; unsigned nBestImprove = 0 ;
NODE* pBest = nullptr ; NODE* pBest = nullptr ;
NODE* pLast = pFirst->pPrev ; NODE* pLast = pFirst->pPrev ;
NODE* pLastDep = pFirstDep->pPrev ;
NODE* pKthDep = pFirstDep ;
for ( NODE* pKth = pFirst ; pKth != pLast->pPrev->pPrev ; pKth = pKth->pNext) { for ( NODE* pKth = pFirst ; pKth != pLast->pPrev->pPrev ; pKth = pKth->pNext) {
// se non esistono dipendenze suggerite
unsigned nEXIST = ArcCost( pLast->pPrev->nPos, pLast->nPos) + unsigned nEXIST = ArcCost( pLast->pPrev->nPos, pLast->nPos) +
ArcCost( pLast->nPos, pFirst->nPos) + ArcCost( pLast->nPos, pFirst->nPos) +
ArcCost( pKth->nPos, pKth->pNext->nPos) ; ArcCost( pKth->nPos, pKth->pNext->nPos) ;
unsigned nTEST = ArcCost( pLast->pPrev->nPos, pFirst->nPos) + unsigned nTEST = ArcCost( pLast->pPrev->nPos, pFirst->nPos) +
ArcCost( pKth->nPos, pLast->nPos) + ArcCost( pKth->nPos, pLast->nPos) +
ArcCost( pLast->nPos, pKth->pNext->nPos) ; ArcCost( pLast->nPos, pKth->pNext->nPos) ;
if ( nTEST < nEXIST && ( nEXIST - nTEST) > nBestImprove) { if ( ! ExistSuggDependences()) {
nBestImprove = nEXIST - nTEST ; if ( nTEST < nEXIST && ( nEXIST - nTEST) > nBestImprove) {
pBest = pKth ; // nel caso di assenza di dipendenze
if ( ! ExistConstraints()) {
nBestImprove = nEXIST - nTEST ;
pBest = pKth ;
}
// nel caso di dipendenze
else {
CopyPathAdv( pPath, m_pCheckDep, pLast, pFirst, pKth, &pLastDep, &pFirstDep, &pKthDep) ;
SwapNodesForPntOpt( pFirstDep, pLastDep, pKthDep) ;
if ( IsPathRespectingContraints( m_pCheckDep)) {
nBestImprove = nEXIST - nTEST ;
pBest = pKth ;
}
}
}
}
// se esistono dipendenze suggerite
else {
CopyPathAdv( pPath, m_pCheckDep, pLast, pFirst, pKth, &pLastDep, &pFirstDep, &pKthDep) ;
SwapNodesForPntOpt( pFirstDep, pLastDep, pKthDep) ;
if ( IsPathRespectingContraints( m_pCheckDep)) {
int nBreak ;
IsPathRespectingSuggestedDependences( pPath, nBreak) ;
nEXIST += m_nMaxDistSuggDep * nBreak ;
IsPathRespectingSuggestedDependences( m_pCheckDep, nBreak) ;
nTEST += m_nMaxDistSuggDep * nBreak ;
if ( nTEST < nEXIST && ( nEXIST - nTEST) > nBestImprove) {
nBestImprove = nEXIST - nTEST ;
pBest = pKth ;
}
}
} }
} }
if ( nBestImprove == 0) { if ( nBestImprove == 0) {
pFirst = pFirst->pNext ; pFirst = pFirst->pNext ;
nCount ++ ; nCount ++ ;
} }
else { else {
pFirst->pPrev = pLast->pPrev ; SwapNodesForPntOpt( pFirst, pLast, pBest) ;
pLast->pPrev->pNext = pFirst ;
pLast->pPrev = pBest ;
pLast->pNext = pBest->pNext ;
pBest->pNext = pLast ;
pLast->pNext->pPrev = pLast ;
nCount = 1 ; nCount = 1 ;
} }
} while ( nCount < m_nNumPnts) ; } while ( nCount < m_nNumPnts) ;
+42 -1
View File
@@ -25,7 +25,7 @@ using namespace std ;
IShortestPath* IShortestPath*
CreateShortestPath( void) CreateShortestPath( void)
{ {
return static_cast<IShortestPath*> ( new(nothrow) ShortestPath) ; return static_cast<IShortestPath*> ( new(nothrow) ShortestPath) ;
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -45,6 +45,12 @@ ShortestPath::ShortestPath( void)
m_Available = nullptr ; m_Available = nullptr ;
m_pMain = nullptr ; m_pMain = nullptr ;
m_pDupl = nullptr ; m_pDupl = nullptr ;
m_pCheckDep = nullptr ;
m_vOrderConstr.clear() ;
m_vOrderSugg.clear() ;
m_vOrderSuggRowMap.clear() ;
m_nMaxDistSuggDep = 0 ;
m_ExtDistMat.clear() ;
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -62,6 +68,9 @@ ShortestPath::~ShortestPath( void)
if ( m_pDupl != nullptr) if ( m_pDupl != nullptr)
delete m_pDupl ; delete m_pDupl ;
m_pDupl = nullptr ; m_pDupl = nullptr ;
if ( m_pCheckDep != nullptr)
delete m_pCheckDep ;
m_pCheckDep = nullptr ;
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -235,3 +244,35 @@ ShortestPath::GetMinLength( double& dMinLen)
dMinLen = ( double)m_nMinCost ; dMinLen = ( double)m_nMinCost ;
return true ; return true ;
} }
//----------------------------------------------------------------------------
bool
ShortestPath::SetDistMatrix( const INTMATRIX& mDistMatrix)
{
// Assegno la matrice suggerita
m_ExtDistMat = mDistMatrix ;
return true ;
}
/* Funzioni per _dubug_ */
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
void
ShortestPath::_printPath( NODE* pPath, string sFun)
{
#if ENABLE_DEBUG
{
LOG_INFO( GetENkLogger(), sFun.c_str()) ;
NODE* pCurr = pPath ;
string sText = "" ;
for ( unsigned i = 0 ; i < m_nNumPnts ; ++ i) {
sText += ( ( i == 0 ? "" : " - ") + ToString( pCurr->nPos)) ;
pCurr = pCurr->pNext ;
}
LOG_INFO( GetENkLogger(), sText.c_str()) ;
}
#else
return ;
#endif
}
+33
View File
@@ -14,9 +14,11 @@
#pragma once #pragma once
#include "/EgtDev/Include/ENkShortestPath.h" #include "/EgtDev/Include/ENkShortestPath.h"
#include <string>
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
#define MAXDIST 1073741823U // 2^30 - 1 per evitare overflow #define MAXDIST 1073741823U // 2^30 - 1 per evitare overflow
#define ENABLE_DEBUG 0
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
struct SpPoint { struct SpPoint {
@@ -63,6 +65,9 @@ class ShortestPath : public IShortestPath
bool Calculate( int nType) override ; bool Calculate( int nType) override ;
bool GetOrder( INTVECTOR& vOrder) override ; bool GetOrder( INTVECTOR& vOrder) override ;
bool GetMinLength( double& dMinLen) override ; bool GetMinLength( double& dMinLen) override ;
bool SetDistMatrix( const INTMATRIX& mDistMatrix) override ;
bool SetConstraintOrder( int nPrev, int nNext) override ;
bool SetSuggestedOrder( int nPrev, int nNext) override ;
public : public :
ShortestPath( void) ; ShortestPath( void) ;
@@ -75,6 +80,10 @@ class ShortestPath : public IShortestPath
void PreparePath( NODE* pPath) ; void PreparePath( NODE* pPath) ;
void SavePath( NODE* pPath) ; void SavePath( NODE* pPath) ;
void RestorePath( NODE* pPath) ; void RestorePath( NODE* pPath) ;
void CopyPath( NODE* pPath, NODE* pPathCopy) ;
void CopyPathAdv( NODE* pPath, NODE* pPathCopy,
NODE* pLast, NODE* pFirst, NODE* pKth,
NODE** pLastCopy, NODE** pFirstCopy, NODE** pKthCopy) ;
long long unsigned TotalCost( NODE* pPath) ; long long unsigned TotalCost( NODE* pPath) ;
void UpdateOrder( NODE* pPath) ; void UpdateOrder( NODE* pPath) ;
unsigned Index( unsigned i, unsigned j) unsigned Index( unsigned i, unsigned j)
@@ -90,6 +99,21 @@ class ShortestPath : public IShortestPath
long long unsigned Hybrid( NODE* pPath) ; long long unsigned Hybrid( NODE* pPath) ;
bool ZigZag( void) ; bool ZigZag( void) ;
long long unsigned TotalCost( void) ; long long unsigned TotalCost( void) ;
bool IsViolatingContraints( int nPrev, int nNext) ;
bool IsPathRespectingContraints( NODE* pPath) ;
bool IsChangingStartPathRespectingConstraints( NODE* pPath, NODE* pFirst) ;
bool IsPathRespectingSuggestedDependences( NODE* pPath, int& nBreak) ;
unsigned CalcMaxDist( void) ;
bool ExistConstraints( void)
{ return ! ( m_vOrderConstr.empty()) ; }
bool ExistSuggDependences( void)
{ return ! ( m_vOrderSugg.empty()) ; }
bool ChooseFirstNode( unsigned& iFirst) ;
bool ChooseNextNode( NODE* pPath, unsigned nSize, unsigned& j, bool bNearVsFar) ;
// _debug
void _printPath( NODE* pPath, std::string sFun) ;
private : private :
static const int MAX_SPPS = 32766 ; // 2^15-2 per evitare problemi nell'allocazione di m_Dists a 32bit static const int MAX_SPPS = 32766 ; // 2^15-2 per evitare problemi nell'allocazione di m_Dists a 32bit
@@ -111,6 +135,15 @@ class ShortestPath : public IShortestPath
bool* m_Available ; bool* m_Available ;
NODE* m_pMain ; NODE* m_pMain ;
NODE* m_pDupl ; NODE* m_pDupl ;
NODE* m_pCheckDep ;
long long unsigned m_nTotMin ; long long unsigned m_nTotMin ;
long long unsigned m_nMinCost ; long long unsigned m_nMinCost ;
INTINTVECTOR m_vOrderConstr ;
INTINTVECTOR m_vOrderSugg_tmp ;
BOOLVECTOR m_vOrderSugg ;
BOOLVECTOR m_vOrderSuggRowMap ;
unsigned m_nMaxDistSuggDep ;
INTMATRIX m_ExtDistMat ;
} ; } ;
+99 -39
View File
@@ -54,7 +54,7 @@ ShortestPath::Tsp( void)
m_Dists = new(nothrow) unsigned[ m_nNumPnts * m_nNumPnts] ; m_Dists = new(nothrow) unsigned[ m_nNumPnts * m_nNumPnts] ;
if ( m_Dists == nullptr) if ( m_Dists == nullptr)
return false ; return false ;
// alloco la matrice ausiliaria // alloco la matrice ausiliaria
if ( m_Available != nullptr) if ( m_Available != nullptr)
delete m_Available ; delete m_Available ;
m_Available = new(nothrow) bool[ m_nNumPnts * m_nNumPnts] ; m_Available = new(nothrow) bool[ m_nNumPnts * m_nNumPnts] ;
@@ -72,6 +72,10 @@ ShortestPath::Tsp( void)
m_pDupl = new(nothrow) NODE[ m_nNumPnts] ; m_pDupl = new(nothrow) NODE[ m_nNumPnts] ;
if ( m_pDupl == nullptr) if ( m_pDupl == nullptr)
return false ; return false ;
// alloco la copia del path per controllo dipendenze
if ( m_pCheckDep != nullptr)
delete m_pCheckDep ;
m_pCheckDep = new(nothrow) NODE[ m_nNumPnts] ;
// calcolo la matrice delle distanze // calcolo la matrice delle distanze
CalcDistances() ; CalcDistances() ;
@@ -79,6 +83,7 @@ ShortestPath::Tsp( void)
// organizzo percorsi // organizzo percorsi
PreparePath( m_pMain) ; PreparePath( m_pMain) ;
PreparePath( m_pDupl) ; PreparePath( m_pDupl) ;
PreparePath( m_pCheckDep) ;
// inizializzo minimo costo // inizializzo minimo costo
m_nMinCost = LLONG_MAX ; m_nMinCost = LLONG_MAX ;
@@ -87,6 +92,7 @@ ShortestPath::Tsp( void)
long long unsigned nMinNN = NearNeighbor() ; long long unsigned nMinNN = NearNeighbor() ;
string sOut = "-- NearNeighbor : TotalCost = " + to_string( nMinNN) ; string sOut = "-- NearNeighbor : TotalCost = " + to_string( nMinNN) ;
MY_LOG( sOut.c_str()) ; MY_LOG( sOut.c_str()) ;
_printPath( m_pMain, ToString( "NN : ")) ;
// se migliora, salvo l'ordinamento // se migliora, salvo l'ordinamento
if ( nMinNN < m_nMinCost) { if ( nMinNN < m_nMinCost) {
MY_LOG( " Improve") ; MY_LOG( " Improve") ;
@@ -101,38 +107,42 @@ ShortestPath::Tsp( void)
// ---- Applico percorso invertito, se risultato precedente scarso ---- // ---- Applico percorso invertito, se risultato precedente scarso ----
const double COEFF_INVERTED = 1.2 ; const double COEFF_INVERTED = 1.2 ;
const int MIN_PNTS_INVERTED = 128 ; const int MIN_PNTS_INVERTED = 128 ;
if ( m_nMinCost > COEFF_INVERTED * m_nTotMin || m_nNumPnts < MIN_PNTS_INVERTED) { if ( ! ExistConstraints()) {
// inverto il percorso if ( m_nMinCost > COEFF_INVERTED * m_nTotMin || m_nNumPnts < MIN_PNTS_INVERTED) {
NODE* pCurr = m_pDupl->pPrev ; // inverto il percorso
NODE* pPath = m_pMain ; NODE* pCurr = m_pDupl->pPrev ;
for ( unsigned i = 0 ; i < m_nNumPnts ; ++ i) { NODE* pPath = m_pMain ;
pPath->nPos = pCurr->nPos ; for ( unsigned i = 0 ; i < m_nNumPnts ; ++ i) {
pPath = pPath->pNext ; pPath->nPos = pCurr->nPos ;
pCurr = pCurr->pPrev ; pPath = pPath->pNext ;
pCurr = pCurr->pPrev ;
}
// ne calcolo il risultato
long long unsigned nMinInv = TotalCost( m_pMain) ;
_printPath( m_pMain, "Inverted NN : ") ;
string sOut = "-- Inverted NN : TotalCost = " + to_string( nMinInv) ;
MY_LOG( sOut.c_str()) ;
// se migliora, salvo l'ordinamento
if ( nMinInv < m_nMinCost) {
MY_LOG( " Improve") ;
m_nMinCost = nMinInv ;
UpdateOrder( m_pMain) ;
}
// salvo il percorso in un duplicato
SavePath( m_pMain) ;
// miglioramenti aggiuntivi
CalculateImprovements( m_pMain) ;
} }
// ne calcolo il risultato else
long long unsigned nMinInv = TotalCost( m_pMain) ; MY_LOG( "-- Inverted NN : Not necessary") ;
string sOut = "-- Inverted NN : TotalCost = " + to_string( nMinInv) ;
MY_LOG( sOut.c_str()) ;
// se migliora, salvo l'ordinamento
if ( nMinInv < m_nMinCost) {
MY_LOG( " Improve") ;
m_nMinCost = nMinInv ;
UpdateOrder( m_pMain) ;
}
// salvo il percorso in un duplicato
SavePath( m_pMain) ;
// miglioramenti aggiuntivi
CalculateImprovements( m_pMain) ;
} }
else
MY_LOG( "-- Inverted NN : Not necessary") ;
// ---- Applico pessima partenza, se risultato precedente scarso ---- // ---- Applico pessima partenza, se risultato precedente scarso ----
const double COEFF_FARNEIG = 1.4 ; const double COEFF_FARNEIG = 1.4 ;
const int MIN_PNTS_FARNEIG = 128 ; const int MIN_PNTS_FARNEIG = 128 ;
if ( m_nMinCost > COEFF_FARNEIG * m_nTotMin || m_nNumPnts < MIN_PNTS_FARNEIG) { if ( m_nMinCost > COEFF_FARNEIG * m_nTotMin || m_nNumPnts < MIN_PNTS_FARNEIG) {
long long unsigned nMinFN = FarNeighbor() ; long long unsigned nMinFN = FarNeighbor() ;
_printPath( m_pMain, "FN : ") ;
string sOut = "-- FarNeighbor : TotalCost = " + to_string( nMinFN) ; string sOut = "-- FarNeighbor : TotalCost = " + to_string( nMinFN) ;
MY_LOG( sOut.c_str()) ; MY_LOG( sOut.c_str()) ;
// se migliora, salvo l'ordinamento // se migliora, salvo l'ordinamento
@@ -159,6 +169,7 @@ ShortestPath::CalculateImprovements( NODE* pPath)
// Ottimizzazione con movimento di singolo punto // Ottimizzazione con movimento di singolo punto
RestorePath( pPath) ; RestorePath( pPath) ;
long long unsigned nPntOpt = PointOpt( pPath) ; long long unsigned nPntOpt = PointOpt( pPath) ;
_printPath( pPath, "PointOpt : ") ;
string sOut = " PointOpt : TotalCost = " + to_string( nPntOpt) ; string sOut = " PointOpt : TotalCost = " + to_string( nPntOpt) ;
MY_LOG( sOut.c_str()) ; MY_LOG( sOut.c_str()) ;
// se migliora, salvo l'ordinamento // se migliora, salvo l'ordinamento
@@ -173,6 +184,7 @@ ShortestPath::CalculateImprovements( NODE* pPath)
if ( m_nNumPnts <= MAX_NODES_2OPT) { if ( m_nNumPnts <= MAX_NODES_2OPT) {
RestorePath( pPath) ; RestorePath( pPath) ;
long long unsigned nTwoOpt = TwoOpt( pPath) ; long long unsigned nTwoOpt = TwoOpt( pPath) ;
_printPath( pPath, "TwoOpt : ") ;
string sOut = " TwoOpt : TotalCost = " + to_string( nTwoOpt) ; string sOut = " TwoOpt : TotalCost = " + to_string( nTwoOpt) ;
MY_LOG( sOut.c_str()) ; MY_LOG( sOut.c_str()) ;
// se migliora, salvo l'ordinamento // se migliora, salvo l'ordinamento
@@ -188,6 +200,7 @@ ShortestPath::CalculateImprovements( NODE* pPath)
if ( m_nNumPnts <= MAX_NODES_HYBRID) { if ( m_nNumPnts <= MAX_NODES_HYBRID) {
RestorePath( pPath) ; RestorePath( pPath) ;
long long unsigned nHybOpt = Hybrid( pPath) ; long long unsigned nHybOpt = Hybrid( pPath) ;
_printPath( pPath, "Hybrid : ") ;
string sOut = " Hybrid : TotalCost = " + to_string( nHybOpt) ; string sOut = " Hybrid : TotalCost = " + to_string( nHybOpt) ;
MY_LOG( sOut.c_str()) ; MY_LOG( sOut.c_str()) ;
// se migliora, salvo l'ordinamento // se migliora, salvo l'ordinamento
@@ -342,29 +355,40 @@ ShortestPath::CalcDistances( void)
} }
// ciclo per calcolare le distanze tra tutte le coppie di nodi // ciclo per calcolare le distanze tra tutte le coppie di nodi
bool bCalcDistances = ( m_ExtDistMat.empty()) ;
for ( unsigned i = 0 ; i < nLimit ; ++ i) { for ( unsigned i = 0 ; i < nLimit ; ++ i) {
unsigned nRowMinDist = INT_MAX ; unsigned nRowMinDist = INT_MAX ;
for ( unsigned j = 0 ; j < nLimit ; ++ j) { for ( unsigned j = 0 ; j < nLimit ; ++ j) {
if ( i != j) { // se ho già impostato una matrice delle distanze, allora uso quella
// calcolo distanza i -> j if ( ! bCalcDistances)
float dDx = float( m_Points[i].dXf - m_Points[j].dXi) ; m_Dists[Index( i, j)] = m_ExtDistMat[i][j] ;
float dDy = float( m_Points[i].dYf - m_Points[j].dYi) ; // altrimenti calcolo le rispettive distanze
float dDz = float( m_Points[i].dZf - m_Points[j].dZi) ; else {
float dDh = float( m_Points[i].dHf - m_Points[j].dHi) ; if ( i != j) {
float dDv = float( m_Points[i].dVf - m_Points[j].dVi) ; // calcolo distanza i -> j
unsigned nDist = min( GetDistance( dDx, dDy, dDz, dDh, dDv), MAXDIST) ; float dDx = float( m_Points[i].dXf - m_Points[j].dXi) ;
m_Dists[ Index( i, j)] = nDist ; float dDy = float( m_Points[i].dYf - m_Points[j].dYi) ;
// verifico se nuovo minimo di linea float dDz = float( m_Points[i].dZf - m_Points[j].dZi) ;
if ( nDist < nRowMinDist) float dDh = float( m_Points[i].dHf - m_Points[j].dHi) ;
nRowMinDist = nDist ; float dDv = float( m_Points[i].dVf - m_Points[j].dVi) ;
unsigned nDist = min( GetDistance( dDx, dDy, dDz, dDh, dDv), MAXDIST) ;
m_Dists[ Index( i, j)] = nDist ;
// verifico se nuovo minimo di linea
if ( nDist < nRowMinDist)
nRowMinDist = nDist ;
}
else
m_Dists[ Index( i, j)] = MAXDIST ;
} }
else
m_Dists[ Index( i, j)] = MAXDIST ;
} }
// aggiorno il totale delle minime distanze // aggiorno il totale delle minime distanze
m_nTotMin += nRowMinDist ; m_nTotMin += nRowMinDist ;
} }
// nel caso di dipendenze suggerite, calcolo il coefficiente di costo massimo associato
if ( ExistSuggDependences())
m_nMaxDistSuggDep = CalcMaxDist() ;
// nel caso di percorso aperto senza vincoli, il numero delle distanze è uno meno di quello dei veri nodi // nel caso di percorso aperto senza vincoli, il numero delle distanze è uno meno di quello dei veri nodi
if ( m_nType == SP_OPEN && if ( m_nType == SP_OPEN &&
m_ObStart.nF == OB_NONE && m_ObEnd.nF == OB_NONE) m_ObStart.nF == OB_NONE && m_ObEnd.nF == OB_NONE)
@@ -423,6 +447,38 @@ ShortestPath::RestorePath( NODE* pPath)
} }
} }
//----------------------------------------------------------------------------
void
ShortestPath::CopyPath( NODE* pPath, NODE* pPathCopy)
{
NODE* pCurr = pPathCopy ;
for ( unsigned i = 0 ; i < m_nNumPnts ; ++ i) {
pCurr->nPos = pPath->nPos ;
pPath = pPath->pNext ;
pCurr = pCurr->pNext ;
}
}
//----------------------------------------------------------------------------
void
ShortestPath::CopyPathAdv( NODE* pPath, NODE* pPathCopy, NODE* pLast, NODE* pFirst, NODE* pKth,
NODE** pLastCopy, NODE** pFirstCopy, NODE** pKthCopy)
{
CopyPath( pPath, pPathCopy) ;
NODE* pCurr = pPath ;
NODE* pCurrCopy = pPathCopy ;
for ( unsigned i = 0 ; i < m_nNumPnts ; ++ i) {
if ( pCurr == pLast)
*pLastCopy = pCurrCopy ;
if ( pCurr == pKth)
*pKthCopy = pCurrCopy ;
if ( pCurr == pFirst)
*pFirstCopy = pCurrCopy ;
pCurr = pCurr->pNext ;
pCurrCopy = pCurrCopy->pNext ;
}
}
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
long long unsigned long long unsigned
ShortestPath::TotalCost( NODE* pPath) ShortestPath::TotalCost( NODE* pPath)
@@ -438,6 +494,10 @@ ShortestPath::TotalCost( NODE* pPath)
nCost += ArcCost( pCurr->nPos, pCurr->pNext->nPos) ; nCost += ArcCost( pCurr->nPos, pCurr->pNext->nPos) ;
pCurr = pCurr->pNext ; pCurr = pCurr->pNext ;
} }
// se sono presenti delle dipendenze suggerite violate, aumento il costo
int nBreak = 0 ;
if ( ! IsPathRespectingSuggestedDependences( pPath, nBreak))
nCost += m_nMaxDistSuggDep * nBreak ;
return nCost ; return nCost ;
} }
+81 -32
View File
@@ -21,6 +21,27 @@
#include "stdafx.h" #include "stdafx.h"
#include "ShortestPath.h" #include "ShortestPath.h"
// ----------------------------------------------------------------------------
static void
SwapNodesForTwoOpt( NODE* pFirst, NODE* pKth, NODE* pLast)
{
// inverto il tratto intermedio
for ( NODE* pCurr = pFirst ; pCurr != pKth ; ) {
NODE* pSave = pCurr->pNext ;
pCurr->pNext = pCurr->pPrev ;
pCurr->pPrev = pSave ;
pCurr = pSave ;
}
// sistemo gli estremi
pFirst->pNext = pKth->pNext ;
pKth->pNext->pPrev = pFirst ;
pKth->pNext = pKth->pPrev ;
pKth->pPrev = pLast ;
pLast->pNext = pKth ;
pFirst = pLast->pNext ;
pKth = pFirst->pNext ;
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
long long unsigned long long unsigned
ShortestPath::TwoOpt( NODE* pPath) ShortestPath::TwoOpt( NODE* pPath)
@@ -29,44 +50,72 @@ ShortestPath::TwoOpt( NODE* pPath)
unsigned nTry = 1 ; unsigned nTry = 1 ;
unsigned nCount = 1 ; unsigned nCount = 1 ;
NODE* pFirst = pPath ; NODE* pFirst = pPath ;
NODE* pFirstDep = m_pCheckDep ;
do { do {
NODE* pLast = pFirst->pPrev ; NODE* pLast = pFirst->pPrev ;
NODE* pKth = pFirst->pNext ; NODE* pKth = pFirst->pNext ;
NODE* pLastDep = pFirstDep->pPrev ;
NODE* pKthDep = pFirstDep->pNext ;
do { do {
// lunghezza originale dei tratti da scambiare // se non esistono dipendenze suggerite
unsigned nEXIST = ArcCost( pLast->nPos, pFirst->nPos) + if ( ! ExistSuggDependences()) {
ArcCost( pKth->nPos, pKth->pNext->nPos) ; // lunghezza originale dei tratti da scambiare
// nuova lunghezza dei tratti da scambiare unsigned nEXIST = ArcCost( pLast->nPos, pFirst->nPos) +
unsigned nTEST = ArcCost( pFirst->nPos, pKth->pNext->nPos) + ArcCost( pKth->nPos, pKth->pNext->nPos) ;
ArcCost( pLast->nPos, pKth->nPos) ; // nuova lunghezza dei tratti da scambiare
// lunghezze originali e nuova del tratto intermedio che viene invertito unsigned nTEST = ArcCost( pFirst->nPos, pKth->pNext->nPos) +
for ( NODE* pCurr = pFirst ; pCurr != pKth ; pCurr = pCurr->pNext) { ArcCost( pLast->nPos, pKth->nPos) ;
nEXIST += ArcCost( pCurr->nPos, pCurr->pNext->nPos) ; // lunghezze originali e nuova del tratto intermedio che viene invertito
nTEST += ArcCost( pCurr->pNext->nPos, pCurr->nPos) ; for ( NODE* pCurr = pFirst ; pCurr != pKth ; pCurr = pCurr->pNext) {
} nEXIST += ArcCost( pCurr->nPos, pCurr->pNext->nPos) ;
// se lo scambio fa risparmiare nTEST += ArcCost( pCurr->pNext->nPos, pCurr->nPos) ;
if ( nTEST < nEXIST) {
// inverto il tratto intermedio
for ( NODE* pCurr = pFirst ; pCurr != pKth ;) {
NODE* pSave = pCurr->pNext ;
pCurr->pNext = pCurr->pPrev ;
pCurr->pPrev = pSave ;
pCurr = pSave ;
} }
// sistemo gli estremi // se lo scambio fa risparmiare
pFirst->pNext = pKth->pNext ; if ( nTEST < nEXIST) {
pKth->pNext->pPrev = pFirst ; // se non esistono vincoli, effettuo i cambi
pKth->pNext = pKth->pPrev ; if ( ! ExistConstraints()) {
pKth->pPrev = pLast ; SwapNodesForTwoOpt( pFirst, pKth, pLast) ;
pLast->pNext = pKth ; nCount = 0 ;
pFirst = pLast->pNext ; }
pKth = pFirst->pNext ; // se esistono i vincoli
// faccio ripartire il conto else {
nCount = 0 ; // copio il Path e i puntatori sul Path di test per le dipendenze
CopyPathAdv( pPath, m_pCheckDep, pLast, pFirst, pKth, &pLastDep, &pFirstDep, &pKthDep) ;
// effettuo i cambi dei nodi sul path di test per le dipendenze
SwapNodesForTwoOpt( pFirstDep, pKthDep, pLastDep) ;
// se il path di test rispetta i vincoli, allora effettuo i cambi sul percorso vero
if ( IsPathRespectingContraints( m_pCheckDep)) {
SwapNodesForTwoOpt( pFirst, pKth, pLast) ;
nCount = 0 ;
}
// altrimenti passo al nodo successivo
else
pKth = pKth->pNext ;
}
}
// altrimenti passo al nodo successivo
else
pKth = pKth->pNext ;
}
// se esistono dipendenze suggerite
else {
CopyPathAdv( pPath, m_pCheckDep, pLast, pFirst, pKth, &pLastDep, &pFirstDep, &pKthDep) ;
SwapNodesForTwoOpt( pFirstDep, pKthDep, pLastDep) ;
if ( IsPathRespectingContraints( m_pCheckDep)) {
unsigned long long nEXIST = TotalCost( pPath) ;
unsigned long long nTEST = TotalCost( m_pCheckDep) ;
if ( nTEST < nEXIST) {
SwapNodesForTwoOpt( pFirst, pKth, pLast) ;
nCount = 0 ;
}
// altrimenti passo al nodo successivo
else
pKth = pKth->pNext ;
}
// altrimenti passo al nodo successivo
else
pKth = pKth->pNext ;
} }
// altrimenti passo al nodo successivo
else
pKth = pKth->pNext ;
} while ( pKth != pLast->pPrev->pPrev && nCount != 0) ; } while ( pKth != pLast->pPrev->pPrev && nCount != 0) ;
if ( nCount != 0) if ( nCount != 0)
pFirst = pFirst->pNext ; pFirst = pFirst->pNext ;