Files
EgtGeomKernel/Intervals.cpp
T
Dario Sassi cfbf187e9e EgtGeomKernel :
- estese funzionalità della classe Intervals.
2020-06-15 06:30:43 +00:00

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