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) ;
+}
+