From b71ff8c113542ee88fd2beed564f4bfd4cf36df2 Mon Sep 17 00:00:00 2001 From: Dario Sassi Date: Mon, 28 Dec 2015 10:33:46 +0000 Subject: [PATCH] EgtNumKernel 1.6l4 : - aggiunta gestione ShortestPath. --- ENkDllMain.cpp | 5 + EgtNumKernel.rc | Bin 11662 -> 11670 bytes EgtNumKernel.vcxproj | 9 + EgtNumKernel.vcxproj.filters | 45 +++- Fn.cpp | 78 ++++++ Hybrid.cpp | 89 +++++++ Nn.cpp | 78 ++++++ PntOpt.cpp | 64 +++++ ShortestPath.cpp | 237 +++++++++++++++++ ShortestPath.h | 117 +++++++++ ShortestPathTsp.cpp | 478 +++++++++++++++++++++++++++++++++++ ShortestPathZigZag.cpp | 181 +++++++++++++ TwoOpt.cpp | 80 ++++++ 13 files changed, 1455 insertions(+), 6 deletions(-) create mode 100644 Fn.cpp create mode 100644 Hybrid.cpp create mode 100644 Nn.cpp create mode 100644 PntOpt.cpp create mode 100644 ShortestPath.cpp create mode 100644 ShortestPath.h create mode 100644 ShortestPathTsp.cpp create mode 100644 ShortestPathZigZag.cpp create mode 100644 TwoOpt.cpp diff --git a/ENkDllMain.cpp b/ENkDllMain.cpp index 5d3bd59..033f2d5 100644 --- a/ENkDllMain.cpp +++ b/ENkDllMain.cpp @@ -50,6 +50,11 @@ DllMain( HMODULE hModule, DWORD dwReason, LPVOID lpReserved) // if ( IsDbgPresent) // return 0 ; //#endif + // se debug, imposto stampe memory leaks all'uscita + #if defined ( _DEBUG) + _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF) ; + #endif + // eseguo s_hModule = hModule ; EGT_TRACE( "EgtNumKernel.dll Initializing!\n") ; } diff --git a/EgtNumKernel.rc b/EgtNumKernel.rc index 1c6030e193049c8bad62001a488147006fddb92c..2d62834bd82fa3e05c1d9a753b2ec8086a40ba17 100644 GIT binary patch delta 126 zcmeB+o)*2~8ymYJgAs!cgUROga?;GqISeL~4=U?!{-x-`xVeklff+7+p3fXv+KF*< Sg|HJo=?rNkX*9#9a03AF79++0 delta 126 zcmbOh-50yl-RgARkm=D%#x%*^Qw7Lyr8bT{irIWcbT;&x(&OP*$$JV7!CNr4OF V<~m^qJPKM^;F{4*c2N%E0sy_+A)){P diff --git a/EgtNumKernel.vcxproj b/EgtNumKernel.vcxproj index 6ae18fb..3659d6b 100644 --- a/EgtNumKernel.vcxproj +++ b/EgtNumKernel.vcxproj @@ -195,15 +195,23 @@ copy $(TargetPath) \EgtProg\Dll64 + + + + + + + Create Create Create Create + @@ -218,6 +226,7 @@ copy $(TargetPath) \EgtProg\Dll64 + diff --git a/EgtNumKernel.vcxproj.filters b/EgtNumKernel.vcxproj.filters index 07c6c75..0443847 100644 --- a/EgtNumKernel.vcxproj.filters +++ b/EgtNumKernel.vcxproj.filters @@ -13,6 +13,12 @@ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + {0e9a4d71-148b-4ec0-b1c5-b6f406e3bafe} + + + {7fa12653-9875-42ee-b9e1-0c088a5846c4} + @@ -21,17 +27,41 @@ File di origine - - File di origine - - File di origine + File di origine\Polynomial + + + File di origine\Polynomial - File di origine + File di origine\Polynomial - File di origine + File di origine\Polynomial + + + File di origine\ShortestPath + + + File di origine\ShortestPath + + + File di origine\ShortestPath + + + File di origine\ShortestPath + + + File di origine\ShortestPath + + + File di origine\ShortestPath + + + File di origine\ShortestPath + + + File di origine\ShortestPath @@ -74,6 +104,9 @@ File di intestazione + + File di intestazione + diff --git a/Fn.cpp b/Fn.cpp new file mode 100644 index 0000000..8ff1087 --- /dev/null +++ b/Fn.cpp @@ -0,0 +1,78 @@ +//---------------------------------------------------------------------------- +// EgalTech 2015-2015 +//---------------------------------------------------------------------------- +// File : NN.cpp Data : 24.12.15 Versione : 1.6l4 +// Contenuto : Calcolo del percorso minimo basandosi su punto pių lontano ; +// pessima stima, utile come base per miglioramenti. +// +// +// Modifiche : 24.12.15 DS Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +//--------------------------- Include ---------------------------------------- +#include "stdafx.h" +#include "ShortestPath.h" + +/*-------------------------------------------------------------------------- */ +unsigned +ShortestPath::FarNeighbor( void) +{ + // abilito i collegamenti tra nodi diversi e disabilito gli auto-collegamenti + for ( unsigned i = 0 ; i < m_nNumPnts ; ++ i) { + for ( unsigned j = 0 ; j < m_nNumPnts ; ++ j) + m_Available[ Index( i, j)] = true ; + 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 ; + } + } + + // 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)]) ; + + // calcolo il costo del percorso + return TotalCost( m_pMain) ; +} + +/*-------------------------------------------------------------------------- */ +unsigned +ShortestPath::HighArc( unsigned i) +{ + // cerco la prima destinazione libera + unsigned j = 0 ; + for ( ; ( j < m_nNumPnts - 1 && ! m_Available[ Index( i, j)]) ; ++ j) + ; + // cerco la migliore destinazione libera + for ( unsigned k = j + 1 ; k < m_nNumPnts - 1 ; ++ k) { + if ( m_Available[ Index( i, k)]) + if ( ArcCost( i, k) > ArcCost( i, j)) + j = k ; + } + + return j ; +} diff --git a/Hybrid.cpp b/Hybrid.cpp new file mode 100644 index 0000000..3250325 --- /dev/null +++ b/Hybrid.cpp @@ -0,0 +1,89 @@ +//---------------------------------------------------------------------------- +// EgalTech 2015-2015 +//---------------------------------------------------------------------------- +// File : NN.cpp Data : 22.12.15 Versione : 1.6l4 +// Contenuto : Miglioramento del percorso con metodo ibrido (ad ogni passo +// si sceglie il meglio tra i metodi Popt e TwoOpt). * +// +// +// +// +// Modifiche : 22.12.15 DS Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +//--------------------------- Include ---------------------------------------- +#include "stdafx.h" +#include "ShortestPath.h" + +// ---------------------------------------------------------------------------- +unsigned +ShortestPath::Hybrid( NODE* pPath) +{ + const int MAX_TRY = 2048 ; + unsigned count = 1 ; + NODE* pFirst = pPath ; + unsigned nTry = 1 ; + do { + NODE* pLast = pFirst->pPrev ; + NODE* pKth = pFirst->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) ; + } + 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 ; + } + else { + 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 ; + } + count = 0 ; + pFirst = pLast->pNext ; + pKth = pFirst->pNext ; + } + else + pKth = pKth->pNext ; + } while ( pKth != pLast->pPrev->pPrev && count != 0) ; + if ( count != 0) + pFirst = pFirst->pNext ; + count ++ ; + nTry ++ ; + } while ( count < m_nNumPnts && nTry < MAX_TRY) ; + + // ricalcolo il costo del percorso + return TotalCost( pPath) ; +} + diff --git a/Nn.cpp b/Nn.cpp new file mode 100644 index 0000000..f7e90cc --- /dev/null +++ b/Nn.cpp @@ -0,0 +1,78 @@ +//---------------------------------------------------------------------------- +// EgalTech 2015-2015 +//---------------------------------------------------------------------------- +// File : NN.cpp Data : 22.12.15 Versione : 1.6l4 +// Contenuto : Calcolo del percorso minimo basandosi su punto pių vicino. +// +// +// +// Modifiche : 22.12.15 DS Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +//--------------------------- Include ---------------------------------------- +#include "stdafx.h" +#include "ShortestPath.h" + +/* ------------------------------------------------------------------------- */ +unsigned +ShortestPath::NearNeighbor( void) +{ + // abilito i collegamenti tra nodi diversi e disabilito gli auto-collegamenti + for ( unsigned i = 0 ; i < m_nNumPnts ; ++ i) { + for ( unsigned j = 0 ; j < m_nNumPnts ; ++ j) + m_Available[ Index( i, j)] = true ; + 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 ; + } + } + + // 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)]) ; + + // calcolo il costo del percorso + return TotalCost( m_pMain) ; +} + +/* ------------------------------------------------------------------------- */ +unsigned +ShortestPath::CheapArc( unsigned i) +{ + // cerco la prima destinazione libera + unsigned j = 0 ; + for ( ; ( j < m_nNumPnts - 1 && ! m_Available[ Index( i, j)]) ; ++ j) + ; + // cerco la migliore destinazione libera + for ( unsigned k = j + 1 ; k < m_nNumPnts - 1 ; ++ k) { + if ( m_Available[ Index( i, k)]) + if ( ArcCost( i, k) < ArcCost( i, j)) + j = k ; + } + + return j ; +} diff --git a/PntOpt.cpp b/PntOpt.cpp new file mode 100644 index 0000000..dd2f2b7 --- /dev/null +++ b/PntOpt.cpp @@ -0,0 +1,64 @@ +//---------------------------------------------------------------------------- +// EgalTech 2015-2015 +//---------------------------------------------------------------------------- +// File : PntOpt.cpp Data : 22.12.15 Versione : 1.6l4 +// Contenuto : Miglioramento del percorso spostando un punto per volta. +// +// K Last L-1 K Last L-1 +// o o-----o--<- o--o _/-o--<- +// |\/ | _|_/ +// |/\ |/ | +// o o---> o o---> +// First K+1 First K+1 +// +// Modifiche : 22.12.15 DS Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +//--------------------------- Include ---------------------------------------- +#include "stdafx.h" +#include "ShortestPath.h" + +/* ------------------------------------------------------------------------- */ +unsigned +ShortestPath::PointOpt( NODE* pPath) +{ + // ciclo di tentativi di spostamento di un punto + unsigned nCount = 1 ; + NODE* pFirst = pPath ; + do { + unsigned nBestImprove = 0 ; + NODE* pBest = nullptr ; + NODE* pLast = pFirst->pPrev ; + for ( NODE* pKth = pFirst ; pKth != pLast->pPrev->pPrev ; pKth = pKth->pNext) { + 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 ( 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 ; + nCount = 1 ; + } + } while ( nCount < m_nNumPnts) ; + + // ricalcolo il costo del percorso + return TotalCost( pPath) ; +} + diff --git a/ShortestPath.cpp b/ShortestPath.cpp new file mode 100644 index 0000000..3870c9e --- /dev/null +++ b/ShortestPath.cpp @@ -0,0 +1,237 @@ +//---------------------------------------------------------------------------- +// EgalTech 2015-2015 +//---------------------------------------------------------------------------- +// File : ShortestPath.cpp Data : 22.12.15 Versione : 1.6l3 +// Contenuto : Funzioni per il calcolo del percorso minimo. +// +// +// +// Modifiche : 22.12.15 DS Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +//--------------------------- Include ---------------------------------------- +#include "stdafx.h" +#include "DllMain.h" +#include "ShortestPath.h" +#include "/EgtDev/Include/EGnStringUtils.h" +#include "/EgtDev/Include/EgtILogger.h" +#include + +using namespace std ; + +//---------------------------------------------------------------------------- +IShortestPath* +CreateShortestPath( void) +{ + return static_cast ( new(nothrow) ShortestPath) ; +} + +//---------------------------------------------------------------------------- +ShortestPath::ShortestPath( void) +{ + m_nType = SP_NONE ; + m_bSolved = false ; + m_dAngHAdd = 1000 ; + m_dAngHMul = 10 ; + m_dAngVAdd = 2000 ; + m_dAngVMul = 40 ; + m_dStep = 100 ; + m_nNumPnts = 0 ; + m_ObStart.nF = OB_NONE ; + m_ObEnd.nF = OB_NONE ; + m_Dists = nullptr ; + m_Available = nullptr ; + m_pMain = nullptr ; + m_pDupl = nullptr ; +} + +//---------------------------------------------------------------------------- +ShortestPath::~ShortestPath( void) +{ + if ( m_Dists != nullptr) + delete m_Dists ; + m_Dists = nullptr ; + if ( m_Available != nullptr) + delete m_Available ; + m_Available = nullptr ; + if ( m_pMain != nullptr) + delete m_pMain ; + m_pMain = nullptr ; + if ( m_pDupl != nullptr) + delete m_pDupl ; + m_pDupl = nullptr ; +} + +//---------------------------------------------------------------------------- +bool +ShortestPath::AddPoint( double dX, double dY) +{ + return AddPoint( dX, dY, 0, 0, 0, dX, dY, 0, 0, 0) ; +} + +//---------------------------------------------------------------------------- +bool +ShortestPath::AddPoint( double dXi, double dYi, double dXf, double dYf) +{ + return AddPoint( dXi, dYi, 0, 0, 0, dXf, dYf, 0, 0, 0) ; +} + +//---------------------------------------------------------------------------- +bool +ShortestPath::AddPoint( double dXi, double dYi, double dZi, double dHi, double dVi, + double dXf, double dYf, double dZf, double dHf, double dVf) +{ + if ( m_nNumPnts >= MAX_SPPS) + return false ; + m_Points[m_nNumPnts].dXi = dXi ; + m_Points[m_nNumPnts].dYi = dYi ; + m_Points[m_nNumPnts].dZi = dZi ; + m_Points[m_nNumPnts].dHi = dHi ; + m_Points[m_nNumPnts].dVi = dVi ; + m_Points[m_nNumPnts].dXf = dXf ; + m_Points[m_nNumPnts].dYf = dYf ; + m_Points[m_nNumPnts].dZf = dZf ; + m_Points[m_nNumPnts].dHf = dHf ; + m_Points[m_nNumPnts].dVf = dVf ; + ++ m_nNumPnts ; + return true ; +} + +//---------------------------------------------------------------------------- +bool +ShortestPath::SetOpenBound( bool bStartVsEnd, int nFlag, double dX, double dY) +{ + return SetOpenBound( bStartVsEnd, nFlag, dX, dY, 0, 0, 0) ; +} + +//---------------------------------------------------------------------------- +bool +ShortestPath::SetOpenBound( bool bStartVsEnd, int nFlag, double dX, double dY, double dZ, double dH, double dV) +{ + // se inizio + if ( bStartVsEnd) { + switch ( nFlag) { + case OB_NONE : + m_ObStart.nF = nFlag ; + break ; + case OB_NEAR_PNT : + m_ObStart.nF = nFlag ; + m_ObStart.dX = dX ; + m_ObStart.dY = dY ; + m_ObStart.dZ = dZ ; + m_ObStart.dH = dH ; + m_ObStart.dV = dV ; + break ; + case OB_XMIN : + case OB_XMAX : + case OB_YMIN : + case OB_YMAX : + m_ObStart.nF = nFlag ; + break ; + default : + return false ; + } + } + // altrimenti fine + else { + switch ( nFlag) { + case OB_NONE : + m_ObEnd.nF = nFlag ; + break ; + case OB_NEAR_PNT : + m_ObEnd.nF = nFlag ; + m_ObEnd.dX = dX ; + m_ObEnd.dY = dY ; + m_ObEnd.dZ = dZ ; + m_ObEnd.dH = dH ; + m_ObEnd.dV = dV ; + break ; + case OB_XMIN : + case OB_XMAX : + case OB_YMIN : + case OB_YMAX : + m_ObEnd.nF = nFlag ; + break ; + default : + return false ; + } + } + + return true ; +} + +//---------------------------------------------------------------------------- +bool +ShortestPath::SetAngularParams( double dAngHAdd, double dAngHMul, double dAngVAdd, double dAngVMul) +{ + m_dAngHAdd = float( abs( dAngHAdd)) ; + m_dAngHMul = float( abs( dAngHMul)) ; + m_dAngVAdd = float( abs( dAngVAdd)) ; + m_dAngVMul = float( abs( dAngVMul)) ; + return true ; +} + +//---------------------------------------------------------------------------- +bool +ShortestPath::SetZzOwStep( double dStep) +{ + m_dStep = float( abs( dStep)) ; + return true ; +} + +//---------------------------------------------------------------------------- +bool +ShortestPath::Calculate( int nType) +{ + m_nType = nType ; + switch ( m_nType) { + case SP_CLOSED : + case SP_OPEN : + m_bSolved = Tsp() ; + break ; + case SP_ZIGZAG_X : + case SP_ZIGZAG_Y : + case SP_ONEWAY_XP : + case SP_ONEWAY_XM : + case SP_ONEWAY_YP : + case SP_ONEWAY_YM : + m_bSolved = ZigZag() ; + break ; + default : + m_bSolved = false ; + break ; + } + + return m_bSolved ; +} + +//---------------------------------------------------------------------------- +bool +ShortestPath::GetOrder( INTVECTOR& vOrder) +{ + // pulisco risultato + vOrder.clear() ; + // verifico sia stato risolto + if ( ! m_bSolved) + return false ; + // assegno risultato + unsigned nTot = ( ( m_nType == SP_OPEN) ? m_nNumPnts - 1 : m_nNumPnts) ; + vOrder.reserve( nTot) ; + for ( unsigned i = 0 ; i < nTot ; ++ i) + vOrder.push_back( m_nOrder[i]) ; + return true ; +} + +//---------------------------------------------------------------------------- +bool +ShortestPath::GetMinLength( double& dMinLen) +{ + // verifico sia stato risolto + if ( ! m_bSolved) + return false ; + // assegno risultato + dMinLen = m_nMinCost ; + return true ; +} diff --git a/ShortestPath.h b/ShortestPath.h new file mode 100644 index 0000000..050ef00 --- /dev/null +++ b/ShortestPath.h @@ -0,0 +1,117 @@ +//---------------------------------------------------------------------------- +// EgalTech 2015-2015 +//---------------------------------------------------------------------------- +// File : ShortestPath.h Data : 22.12.15 Versione : 1.6l3 +// Contenuto : Costanti, tipi e strutture per uso locale. +// +// +// +// Modifiche : 22.12.15 DS Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +#pragma once + +#include "/EgtDev/Include/ENkShortestPath.h" + + +//---------------------------------------------------------------------------- +#define MAXCARD 1048576 // 2^20 per evitare overflow con int e 1024 somme + +//---------------------------------------------------------------------------- +struct SpPoint { + double dXi ; + double dYi ; + double dZi ; + double dHi ; + double dVi ; + double dXf ; + double dYf ; + double dZf ; + double dHf ; + double dVf ; +} ; + +struct OpenBound { + int nF ; + double dX ; + double dY ; + double dZ ; + double dH ; + double dV ; +} ; + +struct NODE { + NODE* pPrev ; + unsigned nPos ; + NODE* pNext ; +} ; + +//---------------------------------------------------------------------------- +class ShortestPath : public IShortestPath +{ + public : + ~ShortestPath( void) override ; + bool AddPoint( double dX, double dY) override ; + bool AddPoint( double dXi, double dYi, double dXf, double dYf) override ; + bool AddPoint( double dXi, double dYi, double dZi, double dHi, double dVi, + double dXf, double dYf, double dZf, double dHf, double dVf) override ; + bool SetOpenBound( bool bStartVsEnd, int nFlag, double dX, double dY) override ; + bool SetOpenBound( bool bStartVsEnd, int nFlag, double dX, double dY, double dZ, double dH, double dV) override ; + bool SetAngularParams( double dAngHAdd, double dAngHMul, double dAngVAdd, double dAngVMul) override ; + bool SetZzOwStep( double dStep) override ; + bool Calculate( int nType) override ; + bool GetOrder( INTVECTOR& vOrder) override ; + bool GetMinLength( double& dMinLen) override ; + + public : + ShortestPath( void) ; + + private : + bool Tsp( void) ; + bool CalculateImprovements( NODE* pPath) ; + void CalcDistances( void) ; + unsigned GetDistance( float dDx, float dDy, float dDz, float dDh, float dDv) ; + void PreparePath( NODE* pPath) ; + void SavePath( NODE* pPath) ; + void RestorePath( NODE* pPath) ; + unsigned TotalCost( NODE* pPath) ; + void UpdateOrder( NODE* pPath) ; + unsigned Index( unsigned i, unsigned j) + { return ( i * m_nNumPnts + j) ; } + unsigned ArcCost( unsigned i, unsigned j) + { return m_Dists[ Index( i, j)] ; } + unsigned NearNeighbor( void) ; + unsigned CheapArc( unsigned i) ; + unsigned FarNeighbor( void) ; + unsigned HighArc( unsigned i) ; + unsigned PointOpt( NODE* pPath) ; + unsigned TwoOpt( NODE* pPath) ; + unsigned Hybrid( NODE* pPath) ; + bool ZigZag( void) ; + unsigned TotalCost( void) ; + + private : + static const int MAX_SPPS = 1024 ; + + private : + int m_nType ; + bool m_bSolved ; + float m_dAngHAdd ; + float m_dAngHMul ; + float m_dAngVAdd ; + float m_dAngVMul ; + float m_dStep ; + unsigned m_nNumPnts ; + SpPoint m_Points[MAX_SPPS+1] ; + unsigned m_nOrder[MAX_SPPS+1] ; + OpenBound m_ObStart ; + OpenBound m_ObEnd ; + unsigned* m_Dists ; + bool* m_Available ; + NODE* m_pMain ; + NODE* m_pDupl ; + unsigned m_nTotMin ; + unsigned m_nMinCost ; +} ; diff --git a/ShortestPathTsp.cpp b/ShortestPathTsp.cpp new file mode 100644 index 0000000..c5ad011 --- /dev/null +++ b/ShortestPathTsp.cpp @@ -0,0 +1,478 @@ +//---------------------------------------------------------------------------- +// EgalTech 2015-2015 +//---------------------------------------------------------------------------- +// File : ShortestPathTsp.cpp Data : 22.12.15 Versione : 1.6l4 +// Contenuto : Calcolo del percorso minimo nel caso generale. +// +// +// +// Modifiche : 22.12.15 DS Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +//--------------------------- Include ---------------------------------------- +#include "stdafx.h" +#include "DllMain.h" +#include "ShortestPath.h" +#include "/EgtDev/Include/EGnStringUtils.h" +#include + +using namespace std ; + +//---------------------------------------------------------------------------- +#if defined( _DEBUG) + #define MY_LOG(szOut) LOG_INFO( GetENkLogger(), szOut) ; +#else + #define MY_LOG(szOut) ; +#endif + +//---------------------------------------------------------------------------- +bool +ShortestPath::Tsp( void) +{ + // almeno un punto + if ( m_nNumPnts < 1) + return false ; + + // per path aperta aggiungo un punto con distanze nulle da tutti gli altri ( per poter creare il lato nullo) + if ( m_nType == SP_OPEN) { + if ( m_nNumPnts <= MAX_SPPS) { + m_Points[m_nNumPnts].dXi = 0 ; + m_Points[m_nNumPnts].dYi = 0 ; + m_Points[m_nNumPnts].dXf = 0 ; + m_Points[m_nNumPnts].dYf = 0 ; + ++ m_nNumPnts ; + } + else + return false ; + } + + // alloco la matrice delle distanze + if ( m_Dists != nullptr) + delete m_Dists ; + m_Dists = new(nothrow) unsigned[ m_nNumPnts * m_nNumPnts] ; + if ( m_Dists == nullptr) + return false ; + // alloco la matrice ausiliaria + if ( m_Available != nullptr) + delete m_Available ; + m_Available = new(nothrow) bool[ m_nNumPnts * m_nNumPnts] ; + if ( m_Available == nullptr) + return false ; + // alloco la path principale + if ( m_pMain != nullptr) + delete m_pMain ; + m_pMain = new(nothrow) NODE[ m_nNumPnts] ; + if ( m_pMain == nullptr) + return false ; + // alloco la copia della path principale + if ( m_pDupl != nullptr) + delete m_pDupl ; + m_pDupl = new(nothrow) NODE[ m_nNumPnts] ; + if ( m_pDupl == nullptr) + return false ; + + // calcolo la matrice delle distanze + CalcDistances() ; + + // organizzo percorsi + PreparePath( m_pMain) ; + PreparePath( m_pDupl) ; + + // inizializzo minimo costo + m_nMinCost = INT_MAX ; + + // ---- applico algoritmo NearNeighbor con miglioramenti aggiuntivi ---- + unsigned nMinNN = NearNeighbor() ; + string sOut = "-- NearNeighbor : TotalCost = " + ToString( (int)nMinNN) ; + MY_LOG( sOut.c_str()) ; + // se migliora, salvo l'ordinamento + if ( nMinNN < m_nMinCost) { + MY_LOG( " Improve") ; + m_nMinCost = nMinNN ; + UpdateOrder( m_pMain) ; + } + // salvo il percorso in un duplicato + SavePath( m_pMain) ; + // miglioramenti aggiuntivi + CalculateImprovements( m_pMain) ; + + // ---- 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 ; + } + // ne calcolo il risultato + unsigned nMinInv = TotalCost( m_pMain) ; + string sOut = "-- Inverted NN : TotalCost = " + ToString( (int)nMinInv) ; + MY_LOG( sOut.c_str()) ; + // se migliora, salvo l'ordinamento + if ( nMinInv < m_nMinCost) { + MY_LOG( " Improve") ; + m_nMinCost = nMinInv ; + UpdateOrder( m_pMain) ; + } + // salvo il percorso in un duplicato + SavePath( m_pMain) ; + // miglioramenti aggiuntivi + CalculateImprovements( m_pMain) ; + } + else + MY_LOG( "-- Inverted NN : Not necessary") ; + + // ---- Applico pessima partenza, se risultato precedente scarso ---- + const double COEFF_FARNEIG = 1.4 ; + const int MIN_PNTS_FARNEIG = 128 ; + if ( m_nMinCost > COEFF_FARNEIG * m_nTotMin || m_nNumPnts < MIN_PNTS_FARNEIG) { + unsigned nMinFN = FarNeighbor() ; + string sOut = "-- FarNeighbor : TotalCost = " + ToString( (int)nMinFN) ; + MY_LOG( sOut.c_str()) ; + // se migliora, salvo l'ordinamento + if ( nMinFN < m_nMinCost) { + MY_LOG( " Improve") ; + m_nMinCost = nMinFN ; + UpdateOrder( m_pMain) ; + } + // salvo il percorso in un duplicato + SavePath( m_pMain) ; + // miglioramenti aggiuntivi + CalculateImprovements( m_pMain) ; + } + else + MY_LOG( "-- FarNeighbor : Not necessary") ; + + return true ; +} + +//---------------------------------------------------------------------------- +bool +ShortestPath::CalculateImprovements( NODE* pPath) +{ + // Ottimizzazione con movimento di singolo punto + RestorePath( pPath) ; + unsigned nPntOpt = PointOpt( pPath) ; + string sOut = " PointOpt : TotalCost = " + ToString( (int)nPntOpt) ; + MY_LOG( sOut.c_str()) ; + // se migliora, salvo l'ordinamento + if ( nPntOpt < m_nMinCost) { + MY_LOG( " Improve") ; + m_nMinCost = nPntOpt ; + UpdateOrder( pPath) ; + } + + // Ottimizzazione con movimento di due punti (lanciata solo se non ci sono troppi punti) + const int MAX_NODES_2OPT = 768 ; + if ( m_nNumPnts <= MAX_NODES_2OPT) { + RestorePath( pPath) ; + unsigned nTwoOpt = TwoOpt( pPath) ; + string sOut = " TwoOpt : TotalCost = " + ToString( (int)nTwoOpt) ; + MY_LOG( sOut.c_str()) ; + // se migliora, salvo l'ordinamento + if ( nTwoOpt < m_nMinCost) { + MY_LOG( " Improve") ; + m_nMinCost = nTwoOpt ; + UpdateOrder( pPath) ; + } + } + + // Ottimizzazione ibrida (lanciata solo se non ci sono troppi punti) + const int MAX_NODES_HYBRID = 512 ; + if ( m_nNumPnts <= MAX_NODES_HYBRID) { + RestorePath( pPath) ; + unsigned nHybOpt = Hybrid( pPath) ; + string sOut = " Hybrid : TotalCost = " + ToString( (int)nHybOpt) ; + MY_LOG( sOut.c_str()) ; + // se migliora, salvo l'ordinamento + if ( nHybOpt < m_nMinCost) { + MY_LOG( " Improve") ; + m_nMinCost = nHybOpt ; + UpdateOrder( pPath) ; + } + } + + return true ; +} + +//---------------------------------------------------------------------------- +unsigned +ShortestPath::GetDistance( float dDx, float dDy, float dDz, float dDh, float dDv) +{ + // parte lineare + unsigned nDist = unsigned( sqrt( dDx * dDx + dDy * dDy + dDz * dDz) + 0.5) ; + // eventuali parti angolari + if ( abs( dDh) > 1 && abs( dDv) > 1) + nDist += unsigned( max( m_dAngHAdd, m_dAngVAdd) + m_dAngHMul * abs( dDh) + m_dAngVMul * abs( dDv)) ; + else if ( abs( dDh) > 1) + nDist += unsigned( m_dAngHAdd + m_dAngHMul * abs( dDh)) ; + else if ( abs( dDv) > 1) + nDist += unsigned( m_dAngVAdd + m_dAngVMul * abs( dDv)) ; + return nDist ; +} + +//---------------------------------------------------------------------------- +void +ShortestPath::CalcDistances( void) +{ + // inizializzo somma delle minime distanze + m_nTotMin = 0 ; + + // in generale si calcolano le distanze per tutti i punti + unsigned nLimit = m_nNumPnts ; + + // nel caso di percorso aperto, ultima riga e ultima colonna si calcolano in modo speciale + if ( m_nType == SP_OPEN) { + // calcolo box dei punti + float fXmin = (float) m_Points[0].dXi ; + float fXmax = (float) m_Points[0].dXi ; + float fYmin = (float) m_Points[0].dYi ; + float fYmax = (float) m_Points[0].dYi ; + float fZmin = (float) m_Points[0].dZi ; + float fZmax = (float) m_Points[0].dZi ; + // ciclo sui punti + for ( unsigned i = 0 ; i < m_nNumPnts - 1 ; ++ i) { + // X + if ( m_Points[i].dXi < fXmin) + fXmin = (float) m_Points[i].dXi ; + if ( m_Points[i].dXi > fXmax) + fXmax = (float) m_Points[i].dXi ; + if ( m_Points[i].dXf < fXmin) + fXmin = (float) m_Points[i-1].dXf ; + if ( m_Points[i].dXf > fXmax) + fXmax = (float) m_Points[i].dXf ; + // Y + if ( m_Points[i].dYi < fYmin) + fYmin = (float) m_Points[i].dYi ; + if ( m_Points[i].dYi > fYmax) + fYmax = (float) m_Points[i].dYi ; + if ( m_Points[i].dYf < fYmin) + fYmin = (float) m_Points[i].dYf ; + if ( m_Points[i].dYf> fYmax) + fYmax = (float) m_Points[i].dYf ; + // Z + if ( m_Points[i].dZi < fZmin) + fZmin = (float) m_Points[i].dZi ; + if ( m_Points[i].dZi > fZmax) + fZmax = (float) m_Points[i].dZi ; + if ( m_Points[i].dZf < fZmin) + fZmin = (float) m_Points[i].dZf ; + if ( m_Points[i].dZf > fZmax) + fZmax = (float) m_Points[i].dZf ; + } + // imposto minimo di linea + unsigned nRowMinDist = INT_MAX ; + // assegno le distanze sull'ultima riga ( dal precedente all'inizio del percorso aperto) tranne ultimo elemento + for ( unsigned i = 0 ; i < m_nNumPnts - 1 ; ++ i) { + unsigned nDist ; + // il valore dipende dalla condizione imposta + switch ( m_ObStart.nF) { + case OB_NEAR_PNT : { + float dDx = float( m_ObStart.dX - m_Points[i].dXi) ; + float dDy = float( m_ObStart.dY - m_Points[i].dYi) ; + float dDz = float( m_ObStart.dZ - m_Points[i].dZi) ; + float dDh = float( m_ObStart.dH - m_Points[i].dHi) ; + float dDv = float( m_ObStart.dV - m_Points[i].dVi) ; + nDist = GetDistance( dDx, dDy, dDz, dDh, dDv) ; + } break ; + case OB_XMIN : + nDist = unsigned( m_Points[i].dXi - fXmin + 0.5) ; + break ; + case OB_XMAX : + nDist = unsigned( fXmax - m_Points[i].dXi + 0.5) ; + break ; + case OB_YMIN : + nDist = unsigned( m_Points[i].dYi - fYmin + 0.5) ; + break ; + case OB_YMAX : + nDist = unsigned( fYmax - m_Points[i].dYi + 0.5) ; + break ; + default : // OB_NONE + nDist = 0 ; + break ; + } + m_Dists[ Index( m_nNumPnts - 1, i)] = nDist ; + // verifico se nuovo minimo di linea + if ( nDist < nRowMinDist) + nRowMinDist = nDist ; + } + // aggiorno il totale delle minime distanze + m_nTotMin += nRowMinDist ; + // assegno le distanze sull'ultima colonna ( dalla fine del percorso aperto al successivo) tranne ultimo elemento + for ( unsigned i = 0 ; i < m_nNumPnts - 1 ; ++ i) { + unsigned nDist ; + // il valore dipende dalla condizione imposta + switch ( m_ObEnd.nF) { + case OB_NEAR_PNT : { + float dDx = float( m_ObEnd.dX - m_Points[i].dXf) ; + float dDy = float( m_ObEnd.dY - m_Points[i].dYf) ; + float dDz = float( m_ObEnd.dZ - m_Points[i].dZf) ; + float dDh = float( m_ObEnd.dH - m_Points[i].dHf) ; + float dDv = float( m_ObEnd.dV - m_Points[i].dVf) ; + nDist = GetDistance( dDx, dDy, dDz, dDh, dDv) ; + } break ; + case OB_XMIN : + nDist = unsigned( m_Points[i].dXf - fXmin + 0.5) ; + break ; + case OB_XMAX : + nDist = unsigned( fXmax - m_Points[i].dXf + 0.5) ; + break ; + case OB_YMIN : + nDist = unsigned( m_Points[i].dYf - fYmin + 0.5) ; + break ; + case OB_YMAX : + nDist = unsigned( fYmax - m_Points[i].dYf + 0.5) ; + break ; + default : // OB_NONE + nDist = 0 ; + break ; + } + m_Dists[ Index( i, m_nNumPnts - 1)] = nDist ; + } + // punto su diagonale principale + m_Dists[ Index( m_nNumPnts - 1, m_nNumPnts - 1)] = MAXCARD ; + // devo ancora calcolare le righe/colonne precedenti + nLimit = m_nNumPnts - 1 ; + } + + // ciclo per calcolare le distanze tra tutte le coppie di nodi + 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 = GetDistance( dDx, dDy, dDz, dDh, dDv) ; + m_Dists[ Index( i, j)] = nDist ; + // verifico se nuovo minimo di linea + if ( nDist < nRowMinDist) + nRowMinDist = nDist ; + } + else + m_Dists[ Index( i, j)] = MAXCARD ; + } + // aggiorno il totale delle minime distanze + m_nTotMin += nRowMinDist ; + } + + // 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) + m_nTotMin = (unsigned) ( m_nTotMin / (double) nLimit * ( nLimit - 1)) ; + + // stampe di debug + #if 0 + MY_LOG( "----\nDistances :") ; + for ( unsigned i = 0 ; i < m_nNumPnts ; ++ i) { + string sOut ; + for ( unsigned j = 0 ; j < m_nNumPnts ; ++ j) { + sOut += ToString( int( m_Dists[ Index( i, j)]), 2) + " " ; + } + MY_LOG( sOut.c_str()) ; + } + #endif + string sOut = "MinCost = " + ToString( int( m_nTotMin)) ; + MY_LOG( sOut.c_str()) ; +} + +//---------------------------------------------------------------------------- +void +ShortestPath::PreparePath( NODE* pPath) +{ + NODE* pCurr = pPath ; + for ( unsigned i = 1 ; i < m_nNumPnts ; ++ i) { + pCurr->pNext = (NODE*) ( (size_t) pCurr + sizeof( NODE)) ; + pCurr->pNext->pPrev = pCurr ; + pCurr = pCurr->pNext ; + } + pPath->pPrev = pCurr ; + pCurr->pNext = pPath ; +} + +//---------------------------------------------------------------------------- +void +ShortestPath::SavePath( NODE* pPath) +{ + NODE* pCurr = m_pDupl ; + for ( unsigned i = 0 ; i < m_nNumPnts ; ++ i) { + pCurr->nPos = pPath->nPos ; + pPath = pPath->pNext ; + pCurr = pCurr->pNext ; + } +} + +//---------------------------------------------------------------------------- +void +ShortestPath::RestorePath( NODE* pPath) +{ + NODE* pCurr = m_pDupl ; + for ( unsigned i = 0 ; i < m_nNumPnts ; ++ i) { + pPath->nPos = pCurr->nPos ; + pPath = pPath->pNext ; + pCurr = pCurr->pNext ; + } +} + +//---------------------------------------------------------------------------- +unsigned +ShortestPath::TotalCost( NODE* pPath) +{ + // ci devono essere almeno due nodi + if ( pPath == nullptr || pPath->pNext == nullptr) + return 0 ; + // lunghezza del primo arco + unsigned nCost = ArcCost( pPath->nPos, pPath->pNext->nPos) ; + // ciclo sui nodi successivi (calcolo la lunghezza degli archi che li uniscono) + NODE* pCurr = pPath->pNext ; + while ( pCurr != pPath) { + nCost += ArcCost( pCurr->nPos, pCurr->pNext->nPos) ; + pCurr = pCurr->pNext ; + } + return nCost ; +} + +//---------------------------------------------------------------------------- +void +ShortestPath::UpdateOrder( NODE* pPath) +{ + // per circuiti aperti si parte dopo il nodo finale aggiunto per poter creare il lato nullo + if ( m_nType == SP_OPEN) { + NODE* pCurr = pPath ; + for ( unsigned i = 0 ; i < m_nNumPnts ; ++ i) { + if ( pCurr->nPos == m_nNumPnts - 1) { + pPath = pCurr->pNext ; + break ; + } + pCurr = pCurr->pNext ; + } + } + // assegno l'ordinamento trovato + for ( unsigned i = 0 ; i < m_nNumPnts ; ++ i) { + m_nOrder[i] = pPath->nPos ; + pPath = pPath->pNext ; + } + // stampe di debug + #if 0 + MY_LOG( "Positions :") ; + string sOut ; + for ( unsigned i = 0 ; i < m_nNumPnts ; ++ i) { + sOut += ToString( (int)m_nOrder[i]) + " " ; + if ( i % 20 == 19) { + MY_LOG( sOut.c_str()) ; + sOut.clear() ; + } + } + if ( ! sOut.empty()) + MY_LOG( sOut.c_str()) ; + #endif +} diff --git a/ShortestPathZigZag.cpp b/ShortestPathZigZag.cpp new file mode 100644 index 0000000..d49ac0a --- /dev/null +++ b/ShortestPathZigZag.cpp @@ -0,0 +1,181 @@ +//---------------------------------------------------------------------------- +// EgalTech 2015-2015 +//---------------------------------------------------------------------------- +// File : ShortestPathZigZag.cpp Data : 22.12.15 Versione : 1.6l4 +// Contenuto : Calcolo del percorso minimo per strisce parallele. +// Le coordinate di inizio e fine di ogni punto sono considerate +// coincidenti. +// +// +// Modifiche : 22.12.15 DS Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +//--------------------------- Include ---------------------------------------- +#include "stdafx.h" +#include "DllMain.h" +#include "ShortestPath.h" +#include "/EgtDev/Include/EGnStringUtils.h" + +using namespace std ; + +//---------------------------------------------------------------------------- +#if defined( _DEBUG) + #define MY_LOG(szOut) LOG_INFO( GetENkLogger(), szOut) ; +#else + #define MY_LOG(szOut) ; +#endif + +//---------------------------------------------------------------------------- +enum { SORT_NONE = 0, + SORT_X_INC = 1, + SORT_X_DEC = 2, + SORT_Y_INC = 3, + SORT_Y_DEC = 4} ; +const double LIN_TOL = 0.1 ; + +//---------------------------------------------------------------------------- +int +GetMainSort( int nType) +{ + switch ( nType) { + case IShortestPath::SP_ZIGZAG_X : + case IShortestPath::SP_ONEWAY_XP : + case IShortestPath::SP_ONEWAY_XM : + return SORT_Y_INC ; + case IShortestPath::SP_ZIGZAG_Y : + case IShortestPath::SP_ONEWAY_YP : + case IShortestPath::SP_ONEWAY_YM : + return SORT_X_INC ; + default : + return SORT_NONE ; + } +} + +//---------------------------------------------------------------------------- +int +GetStepSort( int nType, int nPrevSort) +{ + switch ( nType) { + case IShortestPath::SP_ZIGZAG_X : + return ( nPrevSort == SORT_X_INC) ? SORT_X_DEC : SORT_X_INC ; + case IShortestPath::SP_ZIGZAG_Y : + return ( nPrevSort == SORT_Y_INC) ? SORT_Y_DEC : SORT_Y_INC ; + case IShortestPath::SP_ONEWAY_XP : + return SORT_X_INC ; + case IShortestPath::SP_ONEWAY_XM : + return SORT_X_DEC ; + case IShortestPath::SP_ONEWAY_YP : + return SORT_Y_INC ; + case IShortestPath::SP_ONEWAY_YM : + return SORT_Y_DEC ; + default : + return SORT_NONE ; + } +} + +//---------------------------------------------------------------------------- +void +SortPaths( SpPoint aPoints[], unsigned aIndices[], unsigned nNumPnts, int nSort) +{ + // Bubble sort + for ( unsigned i = 0 ; i < nNumPnts ; ++ i) { + for ( unsigned j = nNumPnts - 1 ; j > i ; -- j) { + bool bSwap = false ; + switch ( nSort) { + default: + case SORT_X_INC : + if ( abs( aPoints[aIndices[j]].dXi - aPoints[aIndices[j - 1]].dXi) < LIN_TOL) + bSwap = ( aPoints[aIndices[j]].dYi < aPoints[aIndices[j - 1]].dYi) ; + else + bSwap = ( aPoints[aIndices[j]].dXi < aPoints[aIndices[j - 1]].dXi) ; + break ; + case SORT_X_DEC : + if ( abs( aPoints[aIndices[j]].dXi - aPoints[aIndices[j - 1]].dXi) < LIN_TOL) + bSwap = ( aPoints[aIndices[j]].dYi < aPoints[aIndices[j - 1]].dYi) ; + else + bSwap = ( aPoints[aIndices[j]].dXi > aPoints[aIndices[j - 1]].dXi + LIN_TOL) ; + break ; + case SORT_Y_INC : + if ( abs( aPoints[aIndices[j]].dYi - aPoints[aIndices[j - 1]].dYi) < LIN_TOL) + bSwap = ( aPoints[aIndices[j]].dXi < aPoints[aIndices[j - 1]].dXi) ; + else + bSwap = ( aPoints[aIndices[j]].dYi < aPoints[aIndices[j - 1]].dYi) ; + break ; + case SORT_Y_DEC : + if ( abs( aPoints[aIndices[j]].dYi - aPoints[aIndices[j - 1]].dYi) < LIN_TOL) + bSwap = ( aPoints[aIndices[j]].dXi < aPoints[aIndices[j - 1]].dXi) ; + else + bSwap = ( aPoints[aIndices[j]].dYi > aPoints[aIndices[j - 1]].dYi) ; + break ; + } + if ( bSwap) + swap( aIndices[j], aIndices[j - 1]) ; + } + } +} + +//---------------------------------------------------------------------------- +bool +ShortestPath::ZigZag( void) +{ + // Almeno un punto + if ( m_nNumPnts < 1) + return false ; + + // Ordino i percorsi secondo la direzione di avanzamento principale + int nSort = GetMainSort( m_nType) ; + for ( unsigned i = 0 ; i < m_nNumPnts ; ++ i) + m_nOrder[i] = i ; + SortPaths( m_Points, m_nOrder, m_nNumPnts, nSort) ; + + bool bGroupOnX = ( nSort == SORT_X_INC) ; + + // Fino a quando non ho ordinato tutti percorsi + unsigned nCount = 0 ; + unsigned i = 0 ; + nSort = GetStepSort( m_nType, SORT_NONE) ; + while ( nCount < m_nNumPnts) { + + // Cerco i percorsi che appartengono al range + if ( bGroupOnX) { + double dRange = m_Points[m_nOrder[nCount]].dXi + m_dStep ; + for ( i = nCount + 1 ; i < m_nNumPnts && m_Points[m_nOrder[i]].dXi < dRange - LIN_TOL ; ++ i) + ; + } + else { + double dRange = m_Points[m_nOrder[nCount]].dYi + m_dStep ; + for ( i = nCount + 1 ; i < m_nNumPnts && m_Points[m_nOrder[i]].dYi < dRange - LIN_TOL ; ++ i) + ; + } + + // Ordino i percorsi trovati + SortPaths( m_Points, &m_nOrder[nCount], i - nCount, nSort) ; + + nCount = i ; + nSort = GetStepSort( m_nType, nSort) ; + } + + // ne calcolo il risultato + m_nMinCost = TotalCost() ; + string sOut = "-- ZigZag/OneWay : TotalCost = " + ToString( (int)m_nMinCost) ; + MY_LOG( sOut.c_str()) ; + + return true ; +} + +//---------------------------------------------------------------------------- +unsigned +ShortestPath::TotalCost( void) +{ + unsigned nCost = 0 ; + // ciclo sui nodi + for ( unsigned i = 1 ; i < m_nNumPnts ; ++ i) { + double dDx = m_Points[m_nOrder[i]].dXi - m_Points[m_nOrder[i-1]].dXi ; + double dDy = m_Points[m_nOrder[i]].dYi - m_Points[m_nOrder[i-1]].dYi ; + double dDz = m_Points[m_nOrder[i]].dZi - m_Points[m_nOrder[i-1]].dZi ; + nCost += unsigned( sqrt( dDx * dDx + dDy * dDy + dDz * dDz)) ; + } + return nCost ; +} diff --git a/TwoOpt.cpp b/TwoOpt.cpp new file mode 100644 index 0000000..6f8bfce --- /dev/null +++ b/TwoOpt.cpp @@ -0,0 +1,80 @@ +//---------------------------------------------------------------------------- +// EgalTech 2015-2015 +//---------------------------------------------------------------------------- +// File : TwoOpt.cpp Data : 22.12.15 Versione : 1.6l4 +// Contenuto : Miglioramento del percorso spezzandolo in 2 parti e +// ricollegando con una delle due parti invertite. +// +// K Last K Last +// o o--<- o--o--<- +// |\/ | +// |/\ | +// o o---> o--o---> +// First K+1 First K+1 +// +// Modifiche : 22.12.15 DS Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +//--------------------------- Include ---------------------------------------- +#include "stdafx.h" +#include "ShortestPath.h" + +// ---------------------------------------------------------------------------- +unsigned +ShortestPath::TwoOpt( NODE* pPath) +{ + const int MAX_TRY = 2048 ; + unsigned nTry = 1 ; + unsigned nCount = 1 ; + NODE* pFirst = pPath ; + do { + NODE* pLast = pFirst->pPrev ; + NODE* pKth = pFirst->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 ; + } + // 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 ; + } + // altrimenti passo al nodo successivo + else + pKth = pKth->pNext ; + } while ( pKth != pLast->pPrev->pPrev && nCount != 0) ; + if ( nCount != 0) + pFirst = pFirst->pNext ; + nCount ++ ; + nTry ++ ; + } while ( nCount < m_nNumPnts && nTry < MAX_TRY) ; + + // ricalcolo il costo del percorso + return TotalCost( pPath) ; +} +