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 1c6030e..2d62834 100644 Binary files a/EgtNumKernel.rc and b/EgtNumKernel.rc differ 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) ; +} +