Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| da69366833 | |||
| afe4648575 | |||
| 0efb3082d0 | |||
| f258acefd0 | |||
| 6d34e7accb | |||
| f7d51cc5cb | |||
| a78c20ca50 | |||
| 431fefcf9d | |||
| 558b590810 | |||
| d9818970e7 | |||
| dd87289571 | |||
| e02619caaf | |||
| 4af2386744 | |||
| 510e39db1e | |||
| 897b45e549 | |||
| 31a96af3ba | |||
| dcf1812704 |
+279
@@ -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
@@ -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
@@ -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 ;
|
||||||
|
} ;
|
||||||
|
|
||||||
Binary file not shown.
+12
-7
@@ -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" />
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
@@ -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
@@ -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) ;
|
||||||
|
|||||||
@@ -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)) ;
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
} ;
|
||||||
@@ -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
@@ -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
@@ -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
|
||||||
|
}
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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 ;
|
||||||
|
|||||||
Reference in New Issue
Block a user