//---------------------------------------------------------------------------- // EgalTech 2015-2015 //---------------------------------------------------------------------------- // File : Intervals.cpp Data : 03.08.15 Versione : 1.6h1 // Contenuto : Implementazione della classe insieme di intervalli Intervals. // // // // Modifiche : 03.08.15 DS Creazione modulo. // // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "\EgtDev\Include\EGkGeoConst.h" #include "\EgtDev\Include\EGkIntervals.h" #include using namespace std ; //---------------------------------------------------------------------------- void Intervals::Reset( void) { m_vInts.clear() ; m_Iter = m_vInts.end() ; } //---------------------------------------------------------------------------- void Intervals::Set( double dMin, double dMax) { Reset() ; // verifico ordine if ( dMin > dMax) swap( dMin, dMax) ; // aggiungo m_vInts.emplace_back( dMin, dMax) ; } //---------------------------------------------------------------------------- void Intervals::Add( double dMin, double dMax) { // verifico ordine if ( dMin > dMax) swap( dMin, dMax) ; // aggiungo, tenendo conto di interazioni con eventuali intervalli già presenti auto iInsert = m_vInts.end() ; auto iIter = m_vInts.begin() ; while ( iIter != m_vInts.end()) { // se interseca l'intervallo corrente if ( dMin < iIter->second + m_dToler && dMax > iIter->first - m_dToler) { // se ha già interessato un intervallo precedente if ( iInsert != m_vInts.end()) { // aggiorno il massimo dell'intervallo già interessato iInsert->second = max( dMax, iIter->second) ; // cancello il corrente iIter = m_vInts.erase( iIter) ; // il nuovo iteratore è già il successivo } // altrimenti modifico il corrente else { // salvo l'intervallo di inserimento iInsert = iIter ; // lo modifico iInsert->first = min( iInsert->first, dMin) ; iInsert->second = max( iInsert->second, dMax) ; // passo al successivo ++ iIter ; } } // se il nuovo intervallo finisce prima else if ( dMax <= iIter->first - m_dToler) { // se non già inserito, lo faccio ora if ( iInsert == m_vInts.end()) iInsert = m_vInts.emplace( iIter, dMin, dMax) ; // termino break ; } // se il nuovo intervallo inizia dopo else if ( dMin >= iIter->second + m_dToler) // passo al successivo ++ iIter ; } // se non ancora inserito, va aggiunto alla fine if ( iInsert == m_vInts.end()) m_vInts.emplace_back( dMin, dMax) ; } //---------------------------------------------------------------------------- void Intervals::Subtract( double dMin, double dMax) { // verifico ordine if ( dMin > dMax) swap( dMin, dMax) ; // scorro gli intervalli auto iIter = m_vInts.begin() ; while ( iIter != m_vInts.end()) { // se interseca l'intervallo corrente if ( dMin < iIter->second && dMax > iIter->first) { // se devo limitarlo inferiormente if ( dMin <= ( iIter->first + m_dToler) && dMax < ( iIter->second - m_dToler)) { iIter->first = dMax ; // passo al successivo ++ iIter ; } // se devo limitarlo superiormente else if ( dMin > ( iIter->first + m_dToler) && dMax >= ( iIter->second - m_dToler)) { iIter->second = dMin ; // passo al successivo ++ iIter ; } // se devo dividerlo in due parti else if ( dMin > ( iIter->first + m_dToler) && dMax < ( iIter->second - m_dToler)) { // inserisco il nuovo intervallo che corrisponde alla parte inferiore double dFirst = iIter->first ; // necessario perché usato per riferimento iIter = m_vInts.emplace( iIter, dFirst, dMin) ; // modifico l'intervallo successivo ++ iIter ; iIter->first = dMax ; // passo al successivo ++ iIter ; } // altrimenti devo eliminarlo else { iIter = m_vInts.erase( iIter) ; // il nuovo iteratore è già il successivo } } // se è tutto minore dell'intervallo corrente, ho finito else if ( dMax <= iIter->first) break ; // altrimenti è tutto maggiore dell'intervallo corrente, passo al successivo else // dMin >= iIter->second ++ iIter ; } } //---------------------------------------------------------------------------- void Intervals::Intersect( double dMin, double dMax) { // se l'insieme è vuoto non devo fare alcunché if ( m_vInts.empty()) return ; // se l'insieme contiene un solo intervallo if ( m_vInts.size() == 1) { // verifico ordine if ( dMin > dMax) swap( dMin, dMax) ; // se non si sovrappongono, il risultato è vuoto if ( dMax < m_vInts.front().first - m_dToler || dMin > m_vInts.front().second + m_dToler) { m_vInts.clear() ; return ; } // calcolo l'intersezione m_vInts.front().first = max( m_vInts.front().first, dMin) ; m_vInts.front().second = min( m_vInts.front().second, dMax) ; return ; } // Insieme di intervalli ausiliario ampio come il corrente Intervals Aux ; Aux.Set( m_vInts.front().first, m_vInts.back().second) ; // Sottraggo Other da Aux Aux.Subtract( dMin, dMax) ; // Sottraggo Aux dal corrente Subtract( Aux) ; } //---------------------------------------------------------------------------- void Intervals::Add( const Intervals& Other) { // aggiungo tutti gli intervalli dell'altro for ( auto& Interv : Other.m_vInts) Add( Interv.first, Interv.second) ; } //---------------------------------------------------------------------------- void Intervals::Subtract( const Intervals& Other) { // sottraggo tutti gli intervalli dell'altro for ( auto& Interv : Other.m_vInts) Subtract( Interv.first, Interv.second) ; } //---------------------------------------------------------------------------- void Intervals::Intersect( const Intervals& Other) { // se l'insieme è vuoto non devo fare alcunché if ( m_vInts.empty()) return ; // Insieme di intervalli ausiliario ampio come il corrente Intervals Aux ; Aux.Set( m_vInts.front().first, m_vInts.back().second) ; // Sottraggo Other da Aux Aux.Subtract( Other) ; // Sottraggo Aux dal corrente Subtract( Aux) ; } //---------------------------------------------------------------------------- bool Intervals::GetMinMax( double& dMin, double& dMax) const { // verifico ci siano intervalli if ( m_vInts.empty()) return false ; // l'estensione va dall'inizio del primo intervallo alla fine dell'ultimo dMin = m_vInts.front().first ; dMax = m_vInts.back().second ; return true ; } //---------------------------------------------------------------------------- bool Intervals::GetFirst( double& dMin, double& dMax) const { // vado all'inizio m_Iter = m_vInts.begin() ; // verifico sia definito if ( m_Iter == m_vInts.end()) return false ; // recupero i dati dMin = m_Iter->first ; dMax = m_Iter->second ; return true ; } //---------------------------------------------------------------------------- bool Intervals::GetNext( double& dMin, double& dMax) const { // vado al successivo if ( m_Iter == m_vInts.end()) return false ; ++ m_Iter ; // verifico sia definito if ( m_Iter == m_vInts.end()) return false ; // recupero i dati dMin = m_Iter->first ; dMax = m_Iter->second ; return true ; } //---------------------------------------------------------------------------- bool Intervals::GetLast( double& dMin, double& dMax) const { // vado alla fine m_Iter = m_vInts.end() ; if ( m_Iter == m_vInts.begin()) return false ; -- m_Iter ; // verifico sia definito if ( m_Iter == m_vInts.end()) return false ; // recupero i dati dMin = m_Iter->first ; dMax = m_Iter->second ; return true ; } //---------------------------------------------------------------------------- bool Intervals::GetPrev( double& dMin, double& dMax) const { // vado al precedente if ( m_Iter == m_vInts.begin()) return false ; -- m_Iter ; // verifico sia definito if ( m_Iter == m_vInts.end()) return false ; // recupero i dati dMin = m_Iter->first ; dMax = m_Iter->second ; return true ; } //---------------------------------------------------------------------------- bool Intervals::IsInside( double dP) const { for ( const auto& Interv : m_vInts) { if ( dP > Interv.first - m_dToler && dP < Interv.second + m_dToler) return true ; } return false ; } //---------------------------------------------------------------------------- bool Intervals::GetPrevNearest( double dP, double& dPrev) const { // se non ci sono intervalli validi if ( m_vInts.empty()) return false ; // se prima dell'inizio if ( dP < m_vInts.front().first - m_dToler) return false ; for ( int i = int( m_vInts.size()) - 1 ; i >= 0 ; -- i) { // se tra due intervalli validi if ( dP > m_vInts[i].second + m_dToler) { dPrev = m_vInts[i].second ; return true ; } // se in un intervallo valido else if ( dP > m_vInts[i].first - m_dToler) { dPrev = dP ; return true ; } } // non trovato return false ; } //---------------------------------------------------------------------------- bool Intervals::GetNextNearest( double dP, double& dNext) const { // se non ci sono intervalli validi if ( m_vInts.empty()) return false ; // se dopo la fine if ( dP > m_vInts.back().second + m_dToler) return false ; // ricerca tra e negli intervalli for ( int i = 0 ; i < int( m_vInts.size()) ; ++ i) { // se tra due intervalli validi if ( dP < m_vInts[i].first - m_dToler) { dNext = m_vInts[i].first ; return true ; } // se in un intervallo valido else if ( dP < m_vInts[i].second + m_dToler) { dNext = dP ; return true ; } } // non trovato return false ; }