Files
EgtGeomKernel/Intervals.cpp
T
Dario Sassi 6faae39afd EgtGeomKernel 1.8e2 :
- correzioni a HashGrid2d e 3d (molto importanti)
- correzioni a Intervals per operazioni booleane.
2017-05-08 08:21:54 +00:00

221 lines
6.9 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_lInts.clear() ;
m_Iter = m_lInts.end() ;
}
//----------------------------------------------------------------------------
void
Intervals::Set( double dMin, double dMax)
{
Reset() ;
// verifico ordine
if ( dMin > dMax)
swap( dMin, dMax) ;
// aggiungo
m_lInts.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_lInts.end() ;
auto iIter = m_lInts.begin() ;
while ( iIter != m_lInts.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_lInts.end()) {
// aggiorno il massimo dell'intervallo già interessato
iInsert->second = max( dMax, iIter->second) ;
// cancello il corrente
iIter = m_lInts.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_lInts.end())
iInsert = m_lInts.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_lInts.end())
m_lInts.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_lInts.begin() ;
while ( iIter != m_lInts.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
iIter = m_lInts.emplace( iIter, iIter->first, dMin) ;
// modifico l'intervallo successivo
++ iIter ;
iIter->first = dMax ;
// passo al successivo
++ iIter ;
}
// altrimenti devo eliminarlo
else {
iIter = m_lInts.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::Add( const Intervals& Other)
{
// aggiungo tutti gli intervalli dell'altro
for ( auto& Interv : Other.m_lInts)
Add( Interv.first, Interv.second) ;
}
//----------------------------------------------------------------------------
void
Intervals::Subtract( const Intervals& Other)
{
// sottraggo tutti gli intervalli dell'altro
for ( auto& Interv : Other.m_lInts)
Subtract( Interv.first, Interv.second) ;
}
//----------------------------------------------------------------------------
void
Intervals::Intersect( const Intervals& Other)
{
// se l'insieme è vuoto non devo fare alcunché
if ( m_lInts.empty())
return ;
// Insieme di intervalli ausiliario ampio come il corrente
Intervals Aux ;
Aux.Set( m_lInts.front().first, m_lInts.back().second) ;
// Sottraggo Other da Aux
Aux.Subtract( Other) ;
// Sottraggo Aux dal corrente
Subtract( Aux) ;
}
//----------------------------------------------------------------------------
bool
Intervals::GetMinMax( double& dMin, double& dMax)
{
// verifico ci siano intervalli
if ( m_lInts.empty())
return false ;
// l'estensione va dall'inizio del primo intervallo alla fine dell'ultimo
dMin = m_lInts.front().first ;
dMax = m_lInts.back().second ;
return true ;
}
//----------------------------------------------------------------------------
bool
Intervals::GetFirst( double& dMin, double& dMax)
{
// vado all'inizio
m_Iter = m_lInts.begin() ;
// verifico sia definito
if ( m_Iter == m_lInts.end())
return false ;
// recupero i dati
dMin = m_Iter->first ;
dMax = m_Iter->second ;
return true ;
}
//----------------------------------------------------------------------------
bool
Intervals::GetNext( double& dMin, double& dMax)
{
// vado al successivo
if ( m_Iter == m_lInts.end())
return false ;
++ m_Iter ;
// verifico sia definito
if ( m_Iter == m_lInts.end())
return false ;
// recupero i dati
dMin = m_Iter->first ;
dMax = m_Iter->second ;
return true ;
}