cfbf187e9e
- estese funzionalità della classe Intervals.
352 lines
11 KiB
C++
352 lines
11 KiB
C++
//----------------------------------------------------------------------------
|
|
// 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 <algorithm>
|
|
|
|
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 ;
|
|
}
|