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>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>EgtNumKernel</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0.20348.0</WindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>v141_xp</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
@@ -42,7 +42,7 @@
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>v141_xp</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
@@ -103,7 +103,7 @@
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;I_AM_ENK;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<OpenMPSupport>false</OpenMPSupport>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
@@ -125,7 +125,7 @@ copy $(TargetPath) \EgtProg\DllD32</Command>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;I_AM_ENK;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<OpenMPSupport>true</OpenMPSupport>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||
<AdditionalOptions>-Wno-tautological-undefined-compare</AdditionalOptions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
@@ -156,7 +156,7 @@ copy $(TargetPath) \EgtProg\DllD64</Command>
|
||||
<EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations>
|
||||
<EnableParallelCodeGeneration>true</EnableParallelCodeGeneration>
|
||||
<OmitFramePointers>true</OmitFramePointers>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
@@ -188,7 +188,7 @@ copy $(TargetPath) \EgtProg\Dll32</Command>
|
||||
<EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet>
|
||||
<EnableFiberSafeOptimizations>false</EnableFiberSafeOptimizations>
|
||||
<EnableParallelCodeGeneration>true</EnableParallelCodeGeneration>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||
<AdditionalOptions>-Wno-tautological-undefined-compare</AdditionalOptions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
@@ -207,12 +207,15 @@ copy $(TargetPath) \EgtProg\Dll64</Command>
|
||||
</ResourceCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Dijkstra.cpp" />
|
||||
<ClCompile Include="ENkDllMain.cpp" />
|
||||
<ClCompile Include="Fn.cpp" />
|
||||
<ClCompile Include="Hybrid.cpp" />
|
||||
<ClCompile Include="JenkinsTraub.cpp" />
|
||||
<ClCompile Include="MachOptimization.cpp" />
|
||||
<ClCompile Include="MaximumFiller.cpp" />
|
||||
<ClCompile Include="Nn.cpp" />
|
||||
<ClCompile Include="Dependences.cpp" />
|
||||
<ClCompile Include="Polynomial.cpp" />
|
||||
<ClCompile Include="PolynomialRoots.cpp" />
|
||||
<ClCompile Include="PntOpt.cpp" />
|
||||
@@ -236,8 +239,10 @@ copy $(TargetPath) \EgtProg\Dll64</Command>
|
||||
<ClInclude Include="..\Include\ENkDllMain.h" />
|
||||
<ClInclude Include="..\Include\ENkPolynomial.h" />
|
||||
<ClInclude Include="..\Include\ENkPolynomialRoots.h" />
|
||||
<ClInclude Include="Dijkstra.h" />
|
||||
<ClInclude Include="DllMain.h" />
|
||||
<ClInclude Include="JenkinsTraub.h" />
|
||||
<ClInclude Include="MachOptimization.h" />
|
||||
<ClInclude Include="MaximumFiller.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
<ClInclude Include="ShortestPath.h" />
|
||||
|
||||
@@ -22,6 +22,12 @@
|
||||
<Filter Include="File di origine\MaximumFilling">
|
||||
<UniqueIdentifier>{205f239f-c48e-4049-bac5-74708a6c530c}</UniqueIdentifier>
|
||||
</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>
|
||||
<ClCompile Include="ENkDllMain.cpp">
|
||||
@@ -66,6 +72,15 @@
|
||||
<ClCompile Include="MaximumFiller.cpp">
|
||||
<Filter>File di origine\MaximumFilling</Filter>
|
||||
</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>
|
||||
<ClInclude Include="stdafx.h">
|
||||
@@ -110,6 +125,12 @@
|
||||
<ClInclude Include="MaximumFiller.h">
|
||||
<Filter>File di intestazione</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Dijkstra.h">
|
||||
<Filter>File di intestazione</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MachOptimization.h">
|
||||
<Filter>File di intestazione</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="EgtNumKernel.rc">
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// EgalTech 2015-2015
|
||||
//----------------------------------------------------------------------------
|
||||
// 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.
|
||||
//
|
||||
//
|
||||
@@ -15,7 +15,7 @@
|
||||
#include "stdafx.h"
|
||||
#include "ShortestPath.h"
|
||||
|
||||
/*-------------------------------------------------------------------------- */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
long long unsigned
|
||||
ShortestPath::FarNeighbor( void)
|
||||
{
|
||||
@@ -26,34 +26,59 @@ ShortestPath::FarNeighbor( void)
|
||||
m_Available[ Index( i, i)] = false ;
|
||||
}
|
||||
|
||||
// cerco il nodo con il più corto arco che se ne diparte
|
||||
unsigned nCurr = 0 ;
|
||||
unsigned nNew = HighArc( nCurr) ;
|
||||
for ( unsigned i = 1 ; i < m_nNumPnts ; ++ i) {
|
||||
unsigned j = HighArc( i) ;
|
||||
if ( ArcCost( i, j) > ArcCost( nCurr, nNew)) {
|
||||
nCurr = i ;
|
||||
nNew = j ;
|
||||
// se non ho dipendenze
|
||||
if ( ! ExistConstraints()) {
|
||||
// cerco il nodo con il più corto arco che se ne diparte
|
||||
unsigned nCurr = 0 ;
|
||||
unsigned nNew = HighArc( nCurr) ;
|
||||
for ( unsigned i = 1 ; i < m_nNumPnts ; ++ i) {
|
||||
unsigned j = HighArc( i) ;
|
||||
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)]) ;
|
||||
}
|
||||
|
||||
// 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 ;
|
||||
// se esistono dipendenze
|
||||
else {
|
||||
// cerco il primo nodo da cui iniziare
|
||||
unsigned nNew = -1 ;
|
||||
if ( ! ChooseFirstNode( nNew))
|
||||
return MAXDIST ;
|
||||
// imposto il nodo corrente come base del percorso
|
||||
NODE* pPath = m_pMain ;
|
||||
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)]) ;
|
||||
unsigned nSize = 1 ;
|
||||
// ciclo
|
||||
do {
|
||||
// imposto tutti gli archi non disponibili al nodo corrente
|
||||
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
|
||||
return TotalCost( m_pMain) ;
|
||||
|
||||
+120
-37
@@ -17,6 +17,36 @@
|
||||
#include "stdafx.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
|
||||
ShortestPath::Hybrid( NODE* pPath)
|
||||
@@ -24,56 +54,109 @@ ShortestPath::Hybrid( NODE* pPath)
|
||||
const int MAX_TRY = 2048 ;
|
||||
unsigned count = 1 ;
|
||||
NODE* pFirst = pPath ;
|
||||
NODE* pFirstDep = m_pCheckDep ;
|
||||
unsigned nTry = 1 ;
|
||||
do {
|
||||
NODE* pLast = pFirst->pPrev ;
|
||||
NODE* pKth = pFirst->pNext ;
|
||||
NODE* pLastDep = pFirstDep->pPrev ;
|
||||
NODE* pKthDep = pFirstDep->pNext ;
|
||||
do {
|
||||
// Point-Opt ( D1=new, D3=original)
|
||||
unsigned D1 = ArcCost( pKth->nPos, pKth->pNext->pNext->nPos) +
|
||||
ArcCost( pKth->pNext->nPos, pFirst->nPos) +
|
||||
ArcCost( pLast->nPos, pKth->pNext->nPos) ;
|
||||
unsigned D3 = ArcCost( pLast->nPos, pFirst->nPos) +
|
||||
ArcCost( pKth->nPos, pKth->pNext->nPos) +
|
||||
ArcCost( pKth->pNext->nPos, pKth->pNext->pNext->nPos) ;
|
||||
// Two-Opt ( D2=new, D4=original)
|
||||
unsigned D2 = ArcCost( pFirst->nPos, pKth->pNext->nPos) +
|
||||
ArcCost( pLast->nPos, pKth->nPos) ;
|
||||
unsigned 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) ;
|
||||
unsigned D1 = 0 ;
|
||||
unsigned D2 = 0 ;
|
||||
unsigned D3 = 0 ;
|
||||
unsigned D4 = 0 ;
|
||||
// se non esistono dipendenze suggerite
|
||||
if ( ! ExistSuggDependences()) {
|
||||
// Point-Opt ( D1=new, D3=original)
|
||||
D1 = ArcCost( pKth->nPos, pKth->pNext->pNext->nPos) +
|
||||
ArcCost( pKth->pNext->nPos, pFirst->nPos) +
|
||||
ArcCost( pLast->nPos, pKth->pNext->nPos) ;
|
||||
D3 = ArcCost( pLast->nPos, pFirst->nPos) +
|
||||
ArcCost( pKth->nPos, pKth->pNext->nPos) +
|
||||
ArcCost( pKth->pNext->nPos, pKth->pNext->pNext->nPos) ;
|
||||
// Two-Opt ( D2=new, D4=original)
|
||||
D2 = ArcCost( pFirst->nPos, pKth->pNext->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 || ( D3 - D1) >= ( D4 - D2))) {
|
||||
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 ;
|
||||
// nel caso di assenza di dipendenze
|
||||
if ( ! ExistConstraints()) {
|
||||
SwapNodesForHybrid1( pLast, pFirst, pKth) ;
|
||||
count = 0 ;
|
||||
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
|
||||
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 {
|
||||
for ( NODE* pReverse = pFirst ; pReverse != pKth ;) {
|
||||
NODE* pSave = pReverse->pNext ;
|
||||
pReverse->pNext = pReverse->pPrev ;
|
||||
pReverse->pPrev = pSave ;
|
||||
pReverse = pSave ;
|
||||
// nel caso di assenza di dipendenze
|
||||
if ( ! ExistConstraints()) {
|
||||
SwapNodesForHybrid2( pLast, pFirst, pKth) ;
|
||||
count = 0 ;
|
||||
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
|
||||
pKth = pKth->pNext ;
|
||||
} 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 ;
|
||||
}
|
||||
|
||||
// cerco il nodo con il più corto arco che se ne diparte
|
||||
unsigned nCurr = 0 ;
|
||||
unsigned nNew = CheapArc( nCurr) ;
|
||||
for ( unsigned i = 1 ; i < m_nNumPnts ; ++ i) {
|
||||
unsigned j = CheapArc( i) ;
|
||||
if ( ArcCost( i, j) < ArcCost( nCurr, nNew)) {
|
||||
nCurr = i ;
|
||||
nNew = j ;
|
||||
// se non ho dipendenze
|
||||
if ( ! ExistConstraints()) {
|
||||
// cerco il nodo con il più corto arco che se ne diparte
|
||||
unsigned nCurr = 0 ;
|
||||
unsigned nNew = CheapArc( nCurr) ;
|
||||
for ( unsigned i = 1 ; i < m_nNumPnts ; ++ i) {
|
||||
unsigned j = CheapArc( i) ;
|
||||
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)]) ;
|
||||
}
|
||||
|
||||
// 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 ;
|
||||
// se esistono dipendenze
|
||||
else {
|
||||
// cerco il primo nodo da cui iniziare
|
||||
unsigned nNew = -1 ;
|
||||
if ( ! ChooseFirstNode( nNew))
|
||||
return MAXDIST ;
|
||||
// imposto il nodo corrente come base del percorso
|
||||
NODE* pPath = m_pMain ;
|
||||
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)]) ;
|
||||
unsigned nSize = 1 ;
|
||||
// ciclo
|
||||
do {
|
||||
// imposto tutti gli archi non disponibili al nodo corrente
|
||||
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
|
||||
return TotalCost( m_pMain) ;
|
||||
@@ -73,6 +98,5 @@ ShortestPath::CheapArc( unsigned i)
|
||||
if ( ArcCost( i, k) < ArcCost( i, j))
|
||||
j = k ;
|
||||
}
|
||||
|
||||
return j ;
|
||||
}
|
||||
|
||||
+50
-10
@@ -20,6 +20,17 @@
|
||||
#include "stdafx.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
|
||||
ShortestPath::PointOpt( NODE* pPath)
|
||||
@@ -27,33 +38,62 @@ ShortestPath::PointOpt( NODE* pPath)
|
||||
// ciclo di tentativi di spostamento di un punto
|
||||
unsigned nCount = 1 ;
|
||||
NODE* pFirst = pPath ;
|
||||
NODE* pFirstDep = m_pCheckDep ;
|
||||
do {
|
||||
unsigned nBestImprove = 0 ;
|
||||
NODE* pBest = nullptr ;
|
||||
NODE* pLast = pFirst->pPrev ;
|
||||
NODE* pLastDep = pFirstDep->pPrev ;
|
||||
NODE* pKthDep = pFirstDep ;
|
||||
for ( NODE* pKth = pFirst ; pKth != pLast->pPrev->pPrev ; pKth = pKth->pNext) {
|
||||
// se non esistono dipendenze suggerite
|
||||
unsigned nEXIST = ArcCost( pLast->pPrev->nPos, pLast->nPos) +
|
||||
ArcCost( pLast->nPos, pFirst->nPos) +
|
||||
ArcCost( pKth->nPos, pKth->pNext->nPos) ;
|
||||
unsigned nTEST = ArcCost( pLast->pPrev->nPos, pFirst->nPos) +
|
||||
ArcCost( pKth->nPos, pLast->nPos) +
|
||||
ArcCost( pLast->nPos, pKth->pNext->nPos) ;
|
||||
if ( nTEST < nEXIST && ( nEXIST - nTEST) > nBestImprove) {
|
||||
nBestImprove = nEXIST - nTEST ;
|
||||
pBest = pKth ;
|
||||
if ( ! ExistSuggDependences()) {
|
||||
if ( nTEST < nEXIST && ( nEXIST - nTEST) > nBestImprove) {
|
||||
// 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) {
|
||||
pFirst = pFirst->pNext ;
|
||||
nCount ++ ;
|
||||
}
|
||||
}
|
||||
else {
|
||||
pFirst->pPrev = pLast->pPrev ;
|
||||
pLast->pPrev->pNext = pFirst ;
|
||||
pLast->pPrev = pBest ;
|
||||
pLast->pNext = pBest->pNext ;
|
||||
pBest->pNext = pLast ;
|
||||
pLast->pNext->pPrev = pLast ;
|
||||
SwapNodesForPntOpt( pFirst, pLast, pBest) ;
|
||||
nCount = 1 ;
|
||||
}
|
||||
} while ( nCount < m_nNumPnts) ;
|
||||
|
||||
+42
-1
@@ -25,7 +25,7 @@ using namespace std ;
|
||||
IShortestPath*
|
||||
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_pMain = 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)
|
||||
delete m_pDupl ;
|
||||
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 ;
|
||||
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
|
||||
|
||||
#include "/EgtDev/Include/ENkShortestPath.h"
|
||||
#include <string>
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
#define MAXDIST 1073741823U // 2^30 - 1 per evitare overflow
|
||||
#define ENABLE_DEBUG 0
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
struct SpPoint {
|
||||
@@ -63,6 +65,9 @@ class ShortestPath : public IShortestPath
|
||||
bool Calculate( int nType) override ;
|
||||
bool GetOrder( INTVECTOR& vOrder) 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 :
|
||||
ShortestPath( void) ;
|
||||
@@ -75,6 +80,10 @@ class ShortestPath : public IShortestPath
|
||||
void PreparePath( NODE* pPath) ;
|
||||
void SavePath( 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) ;
|
||||
void UpdateOrder( NODE* pPath) ;
|
||||
unsigned Index( unsigned i, unsigned j)
|
||||
@@ -90,6 +99,21 @@ class ShortestPath : public IShortestPath
|
||||
long long unsigned Hybrid( NODE* pPath) ;
|
||||
bool ZigZag( 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 :
|
||||
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 ;
|
||||
NODE* m_pMain ;
|
||||
NODE* m_pDupl ;
|
||||
NODE* m_pCheckDep ;
|
||||
long long unsigned m_nTotMin ;
|
||||
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] ;
|
||||
if ( m_Dists == nullptr)
|
||||
return false ;
|
||||
// alloco la matrice ausiliaria
|
||||
// alloco la matrice ausiliaria
|
||||
if ( m_Available != nullptr)
|
||||
delete m_Available ;
|
||||
m_Available = new(nothrow) bool[ m_nNumPnts * m_nNumPnts] ;
|
||||
@@ -72,6 +72,10 @@ ShortestPath::Tsp( void)
|
||||
m_pDupl = new(nothrow) NODE[ m_nNumPnts] ;
|
||||
if ( m_pDupl == nullptr)
|
||||
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
|
||||
CalcDistances() ;
|
||||
@@ -79,6 +83,7 @@ ShortestPath::Tsp( void)
|
||||
// organizzo percorsi
|
||||
PreparePath( m_pMain) ;
|
||||
PreparePath( m_pDupl) ;
|
||||
PreparePath( m_pCheckDep) ;
|
||||
|
||||
// inizializzo minimo costo
|
||||
m_nMinCost = LLONG_MAX ;
|
||||
@@ -87,6 +92,7 @@ ShortestPath::Tsp( void)
|
||||
long long unsigned nMinNN = NearNeighbor() ;
|
||||
string sOut = "-- NearNeighbor : TotalCost = " + to_string( nMinNN) ;
|
||||
MY_LOG( sOut.c_str()) ;
|
||||
_printPath( m_pMain, ToString( "NN : ")) ;
|
||||
// se migliora, salvo l'ordinamento
|
||||
if ( nMinNN < m_nMinCost) {
|
||||
MY_LOG( " Improve") ;
|
||||
@@ -101,38 +107,42 @@ ShortestPath::Tsp( void)
|
||||
// ---- Applico percorso invertito, se risultato precedente scarso ----
|
||||
const double COEFF_INVERTED = 1.2 ;
|
||||
const int MIN_PNTS_INVERTED = 128 ;
|
||||
if ( m_nMinCost > COEFF_INVERTED * m_nTotMin || m_nNumPnts < MIN_PNTS_INVERTED) {
|
||||
// inverto il percorso
|
||||
NODE* pCurr = m_pDupl->pPrev ;
|
||||
NODE* pPath = m_pMain ;
|
||||
for ( unsigned i = 0 ; i < m_nNumPnts ; ++ i) {
|
||||
pPath->nPos = pCurr->nPos ;
|
||||
pPath = pPath->pNext ;
|
||||
pCurr = pCurr->pPrev ;
|
||||
if ( ! ExistConstraints()) {
|
||||
if ( m_nMinCost > COEFF_INVERTED * m_nTotMin || m_nNumPnts < MIN_PNTS_INVERTED) {
|
||||
// inverto il percorso
|
||||
NODE* pCurr = m_pDupl->pPrev ;
|
||||
NODE* pPath = m_pMain ;
|
||||
for ( unsigned i = 0 ; i < m_nNumPnts ; ++ i) {
|
||||
pPath->nPos = pCurr->nPos ;
|
||||
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
|
||||
long long unsigned nMinInv = TotalCost( m_pMain) ;
|
||||
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") ;
|
||||
}
|
||||
else
|
||||
MY_LOG( "-- Inverted NN : Not necessary") ;
|
||||
|
||||
// ---- Applico pessima partenza, se risultato precedente scarso ----
|
||||
const double COEFF_FARNEIG = 1.4 ;
|
||||
const int MIN_PNTS_FARNEIG = 128 ;
|
||||
if ( m_nMinCost > COEFF_FARNEIG * m_nTotMin || m_nNumPnts < MIN_PNTS_FARNEIG) {
|
||||
long long unsigned nMinFN = FarNeighbor() ;
|
||||
_printPath( m_pMain, "FN : ") ;
|
||||
string sOut = "-- FarNeighbor : TotalCost = " + to_string( nMinFN) ;
|
||||
MY_LOG( sOut.c_str()) ;
|
||||
// se migliora, salvo l'ordinamento
|
||||
@@ -159,6 +169,7 @@ ShortestPath::CalculateImprovements( NODE* pPath)
|
||||
// Ottimizzazione con movimento di singolo punto
|
||||
RestorePath( pPath) ;
|
||||
long long unsigned nPntOpt = PointOpt( pPath) ;
|
||||
_printPath( pPath, "PointOpt : ") ;
|
||||
string sOut = " PointOpt : TotalCost = " + to_string( nPntOpt) ;
|
||||
MY_LOG( sOut.c_str()) ;
|
||||
// se migliora, salvo l'ordinamento
|
||||
@@ -173,6 +184,7 @@ ShortestPath::CalculateImprovements( NODE* pPath)
|
||||
if ( m_nNumPnts <= MAX_NODES_2OPT) {
|
||||
RestorePath( pPath) ;
|
||||
long long unsigned nTwoOpt = TwoOpt( pPath) ;
|
||||
_printPath( pPath, "TwoOpt : ") ;
|
||||
string sOut = " TwoOpt : TotalCost = " + to_string( nTwoOpt) ;
|
||||
MY_LOG( sOut.c_str()) ;
|
||||
// se migliora, salvo l'ordinamento
|
||||
@@ -188,6 +200,7 @@ ShortestPath::CalculateImprovements( NODE* pPath)
|
||||
if ( m_nNumPnts <= MAX_NODES_HYBRID) {
|
||||
RestorePath( pPath) ;
|
||||
long long unsigned nHybOpt = Hybrid( pPath) ;
|
||||
_printPath( pPath, "Hybrid : ") ;
|
||||
string sOut = " Hybrid : TotalCost = " + to_string( nHybOpt) ;
|
||||
MY_LOG( sOut.c_str()) ;
|
||||
// se migliora, salvo l'ordinamento
|
||||
@@ -342,29 +355,40 @@ ShortestPath::CalcDistances( void)
|
||||
}
|
||||
|
||||
// ciclo per calcolare le distanze tra tutte le coppie di nodi
|
||||
bool bCalcDistances = ( m_ExtDistMat.empty()) ;
|
||||
for ( unsigned i = 0 ; i < nLimit ; ++ i) {
|
||||
unsigned nRowMinDist = INT_MAX ;
|
||||
for ( unsigned j = 0 ; j < nLimit ; ++ j) {
|
||||
if ( i != j) {
|
||||
// calcolo distanza i -> j
|
||||
float dDx = float( m_Points[i].dXf - m_Points[j].dXi) ;
|
||||
float dDy = float( m_Points[i].dYf - m_Points[j].dYi) ;
|
||||
float dDz = float( m_Points[i].dZf - m_Points[j].dZi) ;
|
||||
float dDh = float( m_Points[i].dHf - m_Points[j].dHi) ;
|
||||
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 ;
|
||||
// se ho già impostato una matrice delle distanze, allora uso quella
|
||||
if ( ! bCalcDistances)
|
||||
m_Dists[Index( i, j)] = m_ExtDistMat[i][j] ;
|
||||
// altrimenti calcolo le rispettive distanze
|
||||
else {
|
||||
if ( i != j) {
|
||||
// calcolo distanza i -> j
|
||||
float dDx = float( m_Points[i].dXf - m_Points[j].dXi) ;
|
||||
float dDy = float( m_Points[i].dYf - m_Points[j].dYi) ;
|
||||
float dDz = float( m_Points[i].dZf - m_Points[j].dZi) ;
|
||||
float dDh = float( m_Points[i].dHf - m_Points[j].dHi) ;
|
||||
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
|
||||
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
|
||||
if ( m_nType == SP_OPEN &&
|
||||
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
|
||||
ShortestPath::TotalCost( NODE* pPath)
|
||||
@@ -438,6 +494,10 @@ ShortestPath::TotalCost( NODE* pPath)
|
||||
nCost += ArcCost( pCurr->nPos, pCurr->pNext->nPos) ;
|
||||
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 ;
|
||||
}
|
||||
|
||||
|
||||
+81
-32
@@ -21,6 +21,27 @@
|
||||
#include "stdafx.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
|
||||
ShortestPath::TwoOpt( NODE* pPath)
|
||||
@@ -29,44 +50,72 @@ ShortestPath::TwoOpt( NODE* pPath)
|
||||
unsigned nTry = 1 ;
|
||||
unsigned nCount = 1 ;
|
||||
NODE* pFirst = pPath ;
|
||||
NODE* pFirstDep = m_pCheckDep ;
|
||||
do {
|
||||
NODE* pLast = pFirst->pPrev ;
|
||||
NODE* pKth = pFirst->pNext ;
|
||||
NODE* pLastDep = pFirstDep->pPrev ;
|
||||
NODE* pKthDep = pFirstDep->pNext ;
|
||||
do {
|
||||
// lunghezza originale dei tratti da scambiare
|
||||
unsigned nEXIST = ArcCost( pLast->nPos, pFirst->nPos) +
|
||||
ArcCost( pKth->nPos, pKth->pNext->nPos) ;
|
||||
// nuova lunghezza dei tratti da scambiare
|
||||
unsigned nTEST = ArcCost( pFirst->nPos, pKth->pNext->nPos) +
|
||||
ArcCost( pLast->nPos, pKth->nPos) ;
|
||||
// lunghezze originali e nuova del tratto intermedio che viene invertito
|
||||
for ( NODE* pCurr = pFirst ; pCurr != pKth ; pCurr = pCurr->pNext) {
|
||||
nEXIST += ArcCost( pCurr->nPos, pCurr->pNext->nPos) ;
|
||||
nTEST += ArcCost( pCurr->pNext->nPos, pCurr->nPos) ;
|
||||
}
|
||||
// se lo scambio fa risparmiare
|
||||
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 ;
|
||||
// se non esistono dipendenze suggerite
|
||||
if ( ! ExistSuggDependences()) {
|
||||
// lunghezza originale dei tratti da scambiare
|
||||
unsigned nEXIST = ArcCost( pLast->nPos, pFirst->nPos) +
|
||||
ArcCost( pKth->nPos, pKth->pNext->nPos) ;
|
||||
// nuova lunghezza dei tratti da scambiare
|
||||
unsigned nTEST = ArcCost( pFirst->nPos, pKth->pNext->nPos) +
|
||||
ArcCost( pLast->nPos, pKth->nPos) ;
|
||||
// lunghezze originali e nuova del tratto intermedio che viene invertito
|
||||
for ( NODE* pCurr = pFirst ; pCurr != pKth ; pCurr = pCurr->pNext) {
|
||||
nEXIST += ArcCost( pCurr->nPos, pCurr->pNext->nPos) ;
|
||||
nTEST += ArcCost( pCurr->pNext->nPos, pCurr->nPos) ;
|
||||
}
|
||||
// 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 ;
|
||||
// faccio ripartire il conto
|
||||
nCount = 0 ;
|
||||
// se lo scambio fa risparmiare
|
||||
if ( nTEST < nEXIST) {
|
||||
// se non esistono vincoli, effettuo i cambi
|
||||
if ( ! ExistConstraints()) {
|
||||
SwapNodesForTwoOpt( pFirst, pKth, pLast) ;
|
||||
nCount = 0 ;
|
||||
}
|
||||
// se esistono i vincoli
|
||||
else {
|
||||
// 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) ;
|
||||
if ( nCount != 0)
|
||||
pFirst = pFirst->pNext ;
|
||||
|
||||
Reference in New Issue
Block a user