//---------------------------------------------------------------------------- // EgalTech 2025-2025 //---------------------------------------------------------------------------- // File : Dependences.cpp Data : 16.04.25 Versione : 2.7a1 // Contenuto : Scelta dei nodi in base alle dipenze per ShortestPath ; // // // Modifiche : 16.04.25 RE Creazione modulo. // // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "DllMain.h" #include "ShortestPath.h" #include "/EgtDev/Include/EGnStringUtils.h" #include using namespace std ; //---------------------------------------------------------------------------- /* Funzione per impostare i vincoli di precendeza obbligatori */ bool ShortestPath::SetConstraintOrder( int nPrev, int nNext) { // se ho già delle dipendenze inserite, controllo che non sia già inserita o in conflitto for ( auto it = m_vOrderConstr.begin() ; it != m_vOrderConstr.end() ; ++ it) { // se dipendenza già presente, non la considero if ( ( *it).first == nPrev && ( *it).second == nNext) { LOG_INFO( GetENkLogger(), string( "Constraint Dependence already in : " + ToString( nPrev) + ", " + ToString( nNext)).c_str()) ; return true ; } // se conflitto allora ritorno errore if ( ( *it).first == nNext && ( *it).second == nPrev) { LOG_INFO( GetENkLogger(), string( "Constraint Dependence conflict: " + ToString( nPrev) + ", " + ToString( nNext)).c_str()) ; return false ; } } // inserisco la dipendenze m_vOrderConstr.emplace_back( make_pair( nPrev, nNext)) ; return true ; } //---------------------------------------------------------------------------- /* Funzione per impostare i vincoli di precedenza suggeriti */ bool ShortestPath::SetSuggestedOrder( int nPrev, int nNext) { // se vettore dipendenze vuoto, lo alloco if ( m_vOrderSugg.empty()) { m_vOrderSugg.resize( m_nNumPnts * m_nNumPnts, false) ; m_vOrderSuggRowMap.resize( m_nNumPnts, false) ; } // se in conflitto, allora non la inserisco e cancello quella presente if ( m_vOrderSugg[ nNext * m_nNumPnts + nPrev]) { m_vOrderSugg[ nNext * m_nNumPnts + nPrev] = false ; return true ; } // inserisco la dipendenze m_vOrderSugg[ nPrev * m_nNumPnts + nNext] = true ; m_vOrderSuggRowMap[ nPrev] = true ; return true ; } //---------------------------------------------------------------------------- /* Funzione per verificare se un vincolo è violato o meno */ bool ShortestPath::IsViolatingContraints( int nPrev, int nNext) { // scorro i vincoli for ( const INTINT nC : m_vOrderConstr) { // se il vincolo è ( nNext, nPrev) allora non è violato if ( nC.first == nNext && nC.second == nPrev) return true ; } return false ; } //---------------------------------------------------------------------------- /* Funzione per verificare se un Path rispetta tutti i vincoli obbligatori */ bool ShortestPath::IsPathRespectingContraints( NODE* pPath) { // controllo validità del percorso if ( pPath == nullptr) return false ; // controllo se il percorso ricavato, viola un vincolo for ( unsigned nC = 0 ; nC < m_vOrderConstr.size() ; ++ nC) { // scorro il percorso NODE* pCurr = pPath ; for ( unsigned i = 0 ; i < m_nNumPnts ; ++ i) { if ( pCurr->nPos == m_vOrderConstr[nC].first) break ; if ( pCurr->nPos == m_vOrderConstr[nC].second) return false ; pCurr = pCurr->pNext ; } } return true ; } //---------------------------------------------------------------------------- /* Funzione per verificare se una rotazione ciclica di nodi viola dei vincoli */ bool ShortestPath::IsChangingStartPathRespectingConstraints( NODE* pPath, NODE* pFirst) { // copio il percorso in quello per le dipendenze CopyPath( pPath, m_pCheckDep) ; NODE* pCurr = m_pCheckDep ; for ( unsigned i = 0 ; i < m_nNumPnts ; ++ i) { // mi muovo alla posizione succesisva nel percorso di test pCurr = pCurr->pNext ; // controllo se il nuovo percorso rispetta i vincoli if ( IsPathRespectingContraints( pCurr)) { pFirst = pFirst->pNext ; return true ; } } return false ; } //---------------------------------------------------------------------------- /* Funzione per calcolare il numero di dipendenze SUGGERITE non rispettate da un Path */ bool ShortestPath::IsPathRespectingSuggestedDependences( NODE* pPath, int& nBreak) { // se non ho dipendenze suggerite, ho finito if ( m_vOrderSugg.empty()) return true ; // controllo validità del percorso nBreak = 0 ; if ( pPath == nullptr) return false ; // scrorro i nodi coinvolti da dipendenze unsigned nDim = m_nNumPnts - ( m_nType == SP_OPEN ? 1 : 0) ; for ( unsigned i = 0 ; i < nDim ; ++ i) { // controllo se il nodo corrente è legato da dipendenze suggerite if ( m_vOrderSuggRowMap[i]) { // scorro il percorso NODE* pCurr = pPath ; for ( unsigned j = 0 ; j < m_nNumPnts ; ++ j) { if ( pCurr->nPos != m_nNumPnts - 1) { if ( pCurr->nPos == i) break ; if ( m_vOrderSugg[ i * nDim + pCurr->nPos]) ++ nBreak ; } pCurr = pCurr->pNext ; } } } return ( nBreak == 0) ; } //---------------------------------------------------------------------------- /* Funzione per calcolare il coefficiente di costo per ogni dipedenza suggerita violata */ unsigned ShortestPath::CalcMaxDist( void) { // scorro gli elementi della matrice delle distanze // NB. Si può decidere di calcolarlo diversamente if ( m_Dists == nullptr) return false ; unsigned nMaxDist = 0 ; for ( unsigned i = 0 ; i < m_nNumPnts ; ++ i) { for ( unsigned j = 0 ; j < m_nNumPnts ; ++ j) { if ( i != j && m_Dists[ Index( i, j)] < MAXDIST - 1) nMaxDist = max( nMaxDist, m_Dists[ Index( i, j)]) ; } } return nMaxDist ; } /* ------------------------------------------------------------------------- */ bool ShortestPath::ChooseFirstNode( unsigned& iFirst) { // definisco un vettore dei soli nodi che posso inserire vector vOkNodes ; vOkNodes.reserve( m_nNumPnts) ; // scorro i nodi i-esimi for ( unsigned i = 0 ; i < m_nNumPnts ; ++ i) { // non deve esistere alcun vincolo del tipo ( j, i) bool bOk = true ; for ( unsigned nC = 0 ; nC < m_vOrderConstr.size() && bOk ; ++ nC) { // recupero il vincolo ( a, b) const INTINT& nnDep = m_vOrderConstr[nC] ; bOk = nnDep.second != i ; } if ( bOk) vOkNodes.push_back( i) ; } // se non ho nodi, allora errore if ( vOkNodes.empty()) return false ; // scelgo l'ultimo ( per percorsi OPEN) iFirst = vOkNodes.back() ; return true ; } /* ------------------------------------------------------------------------- */ bool ShortestPath::ChooseNextNode( NODE* pPath, unsigned nSize, unsigned& jNext, bool bNearVsFar) { // recupero i nodi non inseriti nel path jNext = -1 ; vector vUninstertedNodes ; vUninstertedNodes.reserve( m_nNumPnts) ; for ( unsigned nInd = 0 ; nInd < m_nNumPnts ; ++ nInd) { bool bIn = false ; NODE* pNode = pPath ; for ( unsigned nNode = 0 ; nNode < nSize && ! bIn ; ++ nNode) { bIn = ( pNode->nPos == nInd) ; pNode = pNode->pPrev ; } if ( ! bIn) vUninstertedNodes.push_back( nInd) ; } // se tutti i nodi sono inseriti, allora non faccio nulla if ( vUninstertedNodes.empty()) return true ; // se un solo nodo non inserito, allora non ho altra scelta if ( vUninstertedNodes.size() == unsigned( 1)) { jNext = vUninstertedNodes[0] ; return true ; } // definisco un vettore dei soli nodi che posso inserire vector vOkNodes ; vOkNodes.reserve( m_nNumPnts) ; // scorro i nodi che devo ancora posizionare for ( unsigned j : vUninstertedNodes) { /* * l'ultimo nodo inserito è l'i-esimo, e il successivo sarà il j-esimo ( i ---> j) * devo controllare che tra i nodi inseriti non ci sia un nodo k tale per cui viene violato * il vincolo ( k, j) */ // controllo che l'arco ( i --> j) sia valido if ( ! m_Available[ Index( pPath->nPos, j)]) continue ; // scorro i vincoli bool bOk = true ; for ( unsigned nC = 0 ; nC < m_vOrderConstr.size() && bOk ; ++ nC) { // recupero il vincolo ( a, b) const INTINT& nnDep = m_vOrderConstr[nC] ; // controllo se esiste un vincolo del tipo ( ?, j) if ( nnDep.second == j) { // in questo caso controllo se esiste un nodo k != j che viola il vincolo ( k, j) for ( unsigned k = 0 ; k < vUninstertedNodes.size() && bOk ; ++ k) { if ( vUninstertedNodes[k] != j) bOk = ( vUninstertedNodes[k] != nnDep.first) ; } } } // se vincolo non violato, allora il nodo j può essere inserito if ( bOk) vOkNodes.push_back( j) ; } // se non posso inserire alcun nodo, allora errore if ( vOkNodes.empty()) return false ; // se un solo nodo possibile, allora è quello if ( vOkNodes.size() == unsigned( 1)) { jNext = vOkNodes[0] ; return true ; } // altrimenti seleziono il nodo j-esimo tale per cui l'arco ( i --> j) ha costo minimo/assimo ( bNearVsFar) int nRefDist = bNearVsFar ? MAXDIST : -1 ; for ( unsigned j : vOkNodes) { int nDist = int( ArcCost( pPath->nPos, j)) ; bool bUpdate = false ; if ( bNearVsFar) bUpdate = ( nDist < nRefDist) ; else bUpdate = ( nDist > nRefDist) ; if ( bUpdate) { nRefDist = nDist ; jNext = j ; } } return true ; }