/*
* This file is part of rasdaman community.
*
* Rasdaman community is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Rasdaman community is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with rasdaman community. If not, see .
*
* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
rasdaman GmbH.
*
* For more information please see
* or contact Peter Baumann via .
/
/**
* SOURCE: sinterval.cc
*
* MODULE: raslib
* CLASS: r_Sinterval
*
* COMMENTS:
*
*/
static const char rcsid[] = "@(#)raslib, r_Sinterval: $Id: sinterval.cc,v 1.29 2002/08/19 11:11:25 coman Exp $";
#include "sinterval.hh"
#include
#include
#ifdef __VISUALC__
#include
#else
#include
#endif
// for min and max
#include
using namespace std;
#include "raslib/error.hh"
#include "raslib/rminit.hh"
r_Sinterval::r_Sinterval()
: lower_bound(0),
upper_bound(0),
low_fixed(false),
high_fixed(false)
{
}
r_Sinterval::r_Sinterval( char* stringRep ) throw(r_Eno_interval)
: lower_bound(0),
upper_bound(0),
low_fixed(false),
high_fixed(false)
{
if(!stringRep) {
RMInit::dbgOut << "r_Sinterval::r_Sinterval(" << (stringRep?stringRep: "NULL") << ")" << std::endl;
throw r_Eno_interval();
}
char charToken = 0;
r_Range valueToken = 0;
// for parsing the string
std::istrstream str(stringRep, strlen(stringRep) + 1);
str >> charToken;
if(charToken == '*')
set_low('*');
else
{
str.putback(charToken);
str >> valueToken;
set_low(valueToken);
}
str >> charToken;
if(charToken != ':')
{
// error
lower_bound=0;
upper_bound=0;
low_fixed=false;
high_fixed=false;
RMInit::dbgOut << "r_Sinterval::r_Sinterval(" << stringRep << ") string doesn't have the pattern a:b" << endl;
throw r_Eno_interval();
}
str >> charToken;
if(charToken == '*')
set_high('*');
else
{
str.putback(charToken);
str >> valueToken;
set_high(valueToken);
}
}
r_Sinterval::r_Sinterval( r_Range low, r_Range high ) throw( r_Eno_interval )
: lower_bound(low),
upper_bound(high),
low_fixed(true),
high_fixed(true)
{
if( low > high )
{
RMInit::dbgOut << "r_Sinterval::r_Sinterval(" << low << ", " << high << ") not a interval" << endl;
throw r_Eno_interval();
}
}
r_Sinterval::r_Sinterval( char, r_Range high )
: lower_bound(0),
upper_bound(high),
low_fixed(false),
high_fixed(true)
{
}
r_Sinterval::r_Sinterval( r_Range low, char )
: lower_bound(low),
upper_bound(0),
low_fixed(true),
high_fixed(false)
{
}
r_Sinterval::r_Sinterval( char, char)
: lower_bound(0),
upper_bound(0),
low_fixed(false),
high_fixed(false)
{
}
bool
r_Sinterval::operator==( const r_Sinterval& interval ) const
{
bool returnValue=true;
if (low_fixed)
returnValue = interval.low_fixed && lower_bound == interval.lower_bound;
else
returnValue = !interval.low_fixed;//other is fixed -> false
if (returnValue)
{
if( high_fixed )
returnValue = interval.high_fixed && upper_bound == interval.upper_bound;
else
returnValue = !interval.high_fixed;
}
return returnValue;
}
bool
r_Sinterval::operator!=( const r_Sinterval& interval ) const
{
return !operator==( interval );
}
r_Range
r_Sinterval::get_extent() const throw(r_Error)
{
r_Range ext;
if(!low_fixed || !high_fixed) {
RMInit::dbgOut << "r_Sinterval::get_extent() low or high are not fixed (" << *this << ")" << std::endl;
throw r_Error(INTERVALOPEN);
}
ext = upper_bound - lower_bound + 1;
return ext;
}
void
r_Sinterval::set_low ( r_Range low ) throw( r_Eno_interval ) {
if( high_fixed && low > upper_bound ) {
RMInit::dbgOut << "r_Sinterval::set_low(" << low << ") not an interval (" << *this << ")" << endl;
throw r_Eno_interval();
}
lower_bound = low;
low_fixed = true;
}
void
r_Sinterval::set_high( r_Range high ) throw( r_Eno_interval )
{
if( low_fixed && high < lower_bound ) {
RMInit::dbgOut << "r_Sinterval::set_high(" << high << ") not an interval (" << *this << ")" << endl;
throw r_Eno_interval();
}
upper_bound = high;
high_fixed = true;
}
void
r_Sinterval::set_interval( r_Range low, r_Range high ) throw( r_Eno_interval )
{
if( low > high ) {
RMInit::dbgOut << "r_Sinterval::set_interval(" << low << ", " << high << ") not an interval (" << *this << ")" << endl;
throw r_Eno_interval();
}
lower_bound = low;
upper_bound = high;
low_fixed = true;
high_fixed = true;
}
void
r_Sinterval::set_interval( char, r_Range high )
{
lower_bound = 0;
upper_bound = high;
low_fixed = false;
high_fixed = true;
}
void
r_Sinterval::set_interval( r_Range low, char )
{
lower_bound = low;
upper_bound = 0;
low_fixed = true;
high_fixed = false;
}
void
r_Sinterval::set_interval( char, char )
{
lower_bound = 0;
upper_bound = 0;
low_fixed = false;
high_fixed = false;
}
bool
r_Sinterval::intersects_with( const r_Sinterval& interval ) const
{
int classnr = classify( *this, interval );
return classnr != 1 && classnr != 6 && classnr != 16 && classnr != 21 &&
classnr != 26 && classnr != 31 && classnr != 34 && classnr != 37;
}
r_Sinterval&
r_Sinterval::union_of( const r_Sinterval& interval1, const r_Sinterval& interval2 ) throw( r_Eno_interval )
{
*this = calc_union( interval1, interval2 );
return *this;
}
r_Sinterval&
r_Sinterval::union_with( const r_Sinterval& interval ) throw( r_Eno_interval )
{
*this = calc_union( interval, *this );
return *this;
}
r_Sinterval&
r_Sinterval::operator+=( const r_Sinterval& interval ) throw( r_Eno_interval )
{
*this = calc_union( interval, *this );
return *this;
}
r_Sinterval
r_Sinterval::create_union( const r_Sinterval& interval ) const throw( r_Eno_interval )
{
r_Sinterval result;
result = calc_union( interval, *this );
return result;
}
r_Sinterval
r_Sinterval::operator+( const r_Sinterval& interval ) const throw( r_Eno_interval )
{
r_Sinterval result;
result = calc_union( interval, *this );
return result;
}
r_Sinterval&
r_Sinterval::difference_of( const r_Sinterval& interval1, const r_Sinterval& interval2 ) throw( r_Eno_interval )
{
*this = calc_difference( interval1, interval2 );
return *this;
}
r_Sinterval&
r_Sinterval::difference_with( const r_Sinterval& interval ) throw( r_Eno_interval )
{
*this = calc_difference( interval, *this );
return *this;
}
r_Sinterval&
r_Sinterval::operator-=( const r_Sinterval& interval ) throw( r_Eno_interval )
{
*this = calc_difference( interval, *this );
return *this;
}
r_Sinterval
r_Sinterval::create_difference( const r_Sinterval& interval ) const throw( r_Eno_interval )
{
r_Sinterval result;
result = calc_difference( interval, *this );
return result;
}
r_Sinterval
r_Sinterval::operator-( const r_Sinterval& interval ) const throw( r_Eno_interval )
{
r_Sinterval result;
result = calc_difference( interval, *this );
return result;
}
r_Sinterval&
r_Sinterval::intersection_of( const r_Sinterval& interval1, const r_Sinterval& interval2 ) throw( r_Eno_interval )
{
*this = calc_intersection( interval1, interval2 );
return *this;
}
r_Sinterval&
r_Sinterval::intersection_with( const r_Sinterval& interval ) throw( r_Eno_interval )
{
*this = calc_intersection( interval, *this );
return *this;
}
r_Sinterval&
r_Sinterval::operator*=( const r_Sinterval& interval ) throw( r_Eno_interval )
{
*this = calc_intersection( interval, *this );
return *this;
}
r_Sinterval
r_Sinterval::create_intersection( const r_Sinterval& interval ) const throw( r_Eno_interval )
{
r_Sinterval result;
result = calc_intersection( interval, *this );
return result;
}
r_Sinterval
r_Sinterval::operator*( const r_Sinterval& interval ) const throw( r_Eno_interval )
{
r_Sinterval result;
result = calc_intersection( interval, *this );
return result;
}
r_Sinterval&
r_Sinterval::closure_of( const r_Sinterval& interval1, const r_Sinterval& interval2 ) throw( r_Eno_interval )
{
*this = calc_closure( interval1, interval2 );
return *this;
}
r_Sinterval&
r_Sinterval::closure_with( const r_Sinterval& interval ) throw( r_Eno_interval )
{
*this = calc_closure( interval, *this );
return *this;
}
r_Sinterval
r_Sinterval::create_closure( const r_Sinterval& interval ) const throw( r_Eno_interval )
{
r_Sinterval result;
result = calc_closure( interval, *this );
return result;
}
void
r_Sinterval::print_status( std::ostream& s ) const
{
if( low_fixed )
s << lower_bound;
else
s << "*";
s << ":";
if( high_fixed )
s << upper_bound;
else
s << "*";
}
r_Bytes
r_Sinterval::get_storage_size( ) const
{
return ( 2 * ( sizeof( r_Range ) + sizeof(bool) ) );
}
r_Sinterval
r_Sinterval::calc_union( const r_Sinterval& a, const r_Sinterval& b ) const throw( r_Eno_interval )
{
r_Sinterval result;
switch( classify( a, b ) )
{
case 2:
case 7:
case 9:
case 12:
case 22:
case 23:
case 27:
case 28:
case 35:
case 36:
// result = [a1:b2]
if( a.is_low_fixed() )
result.set_low( a.low() );
else
result.set_low('*');
if( b.is_high_fixed() )
result.set_high( b.high() );
else
result.set_high('*');
break;
case 4:
case 8:
case 10:
case 13:
case 17:
case 18:
case 32:
case 33:
case 38:
case 39:
// result = [b1:a2]
if( b.is_low_fixed() )
result.set_low( b.low() );
else
result.set_low('*');
if( a.is_high_fixed() )
result.set_high( a.high() );
else
result.set_high('*');
break;
case 3:
case 11:
case 14:
case 15:
case 19:
case 20:
case 41:
case 42:
case 43:
case 44:
case 46:
case 48:
case 49:
case 52:
result = a;
break;
case 5:
case 24:
case 25:
case 29:
case 30:
case 40:
case 45:
case 47:
case 50:
case 51:
result = b;
break;
default: // case in { 1, 6, 16, 21, 26, 31, 34, 37 }
{
RMInit::dbgOut << "r_Sinterval::calc_union(" << a << ", " << b << ") not an interval" << endl;
throw r_Eno_interval();
}
}
return result;
}
r_Sinterval
r_Sinterval::calc_difference( const r_Sinterval& a, const r_Sinterval& b ) const throw( r_Eno_interval )
{
r_Sinterval result;
switch( classify( a, b ) )
{
case 2:
case 9:
case 20:
case 23:
case 28:
case 36:
case 39:
case 43:
case 49:
// result = [a1:b1]
if( a.is_low_fixed() )
result.set_low( a.low() );
else
result.set_low('*');
if( b.is_low_fixed() )
result.set_high( b.low() );
else
result.set_high('*');
break;
case 1:
case 6:
case 7:
case 8:
case 16:
case 17:
case 21:
case 22:
case 26:
case 27:
case 31:
case 32:
case 34:
case 35:
case 37:
case 38:
result = a;
break;
case 4:
case 10:
case 15:
case 18:
case 33:
case 42:
case 48:
// result = [b2:a2]
if( b.is_high_fixed() )
result.set_low( b.high() );
else
result.set_low('*');
if( a.is_high_fixed() )
result.set_high( a.high() );
else
result.set_high('*');
break;
default: // case in { 3, 5, 11, 12, 13, 14, 19, 24, 25, 29, 30, 40, 41, 44, 45, 46, 47, 50, 51, 52 }
{
RMInit::dbgOut << "r_Sinterval::calc_difference(" << a << ", " << b << ") not an interval" << endl;
throw r_Eno_interval();
}
}
return result;
}
r_Sinterval
r_Sinterval::calc_intersection( const r_Sinterval& a, const r_Sinterval& b ) const throw( r_Eno_interval )
{
r_Sinterval result;
switch( classify( a, b ) )
{
case 4:
case 18:
case 33:
case 39:
// result = [a1:b2]
if( a.is_low_fixed() )
result.set_low( a.low() );
else
result.set_low('*');
if( b.is_high_fixed() )
result.set_high( b.high() );
else
result.set_high('*');
break;
case 2:
case 23:
case 28:
case 36:
// result = [b1:a2]
if( b.is_low_fixed() )
result.set_low( b.low() );
else
result.set_low('*');
if( a.is_high_fixed() )
result.set_high( a.high() );
else
result.set_high('*');
break;
case 5:
case 11:
case 12:
case 13:
case 24:
case 25:
case 29:
case 30:
case 40:
case 41:
case 44:
case 45:
case 47:
case 50:
case 51:
case 52:
result = a;
break;
case 3:
case 9:
case 10:
case 14:
case 15:
case 19:
case 20:
case 42:
case 43:
case 46:
case 48:
case 49:
result = b;
break;
case 7:
case 22:
case 27:
case 35:
// result = [a2:a2]
if( a.is_high_fixed() )
result.set_interval( a.high(), a.high() );
else
result.set_interval( '*', '*' );
break;
case 8:
case 17:
case 32:
case 38:
// result = [b2:b2]
if( b.is_high_fixed() )
result.set_interval( b.high(), b.high() );
else
result.set_interval( '*', '*' );
break;
default: // case in { 1, 6, 16, 21, 26, 31, 34, 37 }
RMInit::dbgOut << "r_Sinterval::calc_intersection(" << a << ", " << b << ") not an interval" << endl;
throw r_Eno_interval();
}
return result;
}
r_Sinterval
r_Sinterval::calc_closure( const r_Sinterval& a, const r_Sinterval& b ) const throw( r_Eno_interval )
{
r_Sinterval closure;
if( !a.is_low_fixed() || !b.is_low_fixed() )
closure.set_low('*');
else
closure.set_low( std::min( a.low(), b.low() ) );
if( !a.is_high_fixed() || !b.is_high_fixed() )
closure.set_high('*');
else
closure.set_high( std::max( a.high(), b.high() ) );
return closure;
}
/*************************************************************
* Method name...: classify
*
* Arguments.....: Two intervals for the classification.
* Return value..: The classification class number (1..52).
* Description...: The method classifies the two intervals into
* one of 13 classes according to their spatial
* relationship. Based on the classification, the
* result of the operations union, difference,
* and intersection can be calculated as shown
* in the table in file sinterval.hh:
************************************************************/
int
r_Sinterval::classify( const r_Sinterval& a, const r_Sinterval& b ) const
{
int classification = 0;
if( a.is_low_fixed() && a.is_high_fixed() && b.is_low_fixed() && b.is_high_fixed() )
{
// classification 1..13
if( a.low() < b.low() )
{
if( a.high() < b.high() )
{
if( a.high() < b.low() )
classification = 1;
else
if( a.high() == b.low() )
classification = 7;
else
classification = 2;
}
else if( a.high() == b.high() )
classification = 9;
else
classification = 3;
}
else if( a.low() == b.low() )
{
if( a.high() < b.high() )
classification = 12;
else if( a.high() == b.high() )
classification = 11;
else
classification = 10;
}
else
if( a.high() < b.high() )
classification = 5;
else if( a.high() == b.high() )
classification = 13;
else
{
if( a.low() < b.high() )
classification = 4;
else if( a.low() == b.high() )
classification = 8;
else
classification = 6;
}
}
else if( a.is_low_fixed() && !a.is_high_fixed() && b.is_low_fixed() && b.is_high_fixed() )
{
// classification 14..18
if( a.low() < b.low() )
classification = 14;
else if( a.low() == b.low() )
classification = 15;
else
{
if( b.high() < a.low() )
classification = 16;
else if( b.high() == a.low() )
classification = 17;
else
classification = 18;
}
}
else if( !a.is_low_fixed() && a.is_high_fixed() && b.is_low_fixed() && b.is_high_fixed() )
{
// classification 19..23
if( a.high() > b.high() )
classification = 19;
else if( a.high() == b.high() )
classification = 20;
else
{
if( a.high() < b.low() )
classification = 21;
else if( a.high() == b.low() )
classification = 22;
else
classification = 23;
}
}
else if( a.is_low_fixed() && a.is_high_fixed() && b.is_low_fixed() && !b.is_high_fixed() )
{
// classification 24..28
if( b.low() < a.low() )
classification = 24;
else if( b.low() == a.low() )
classification = 25;
else
{
if( a.high() < b.low() )
classification = 26;
else if( a.high() == b.low() )
classification = 27;
else
classification = 28;
}
}
else if( a.is_low_fixed() && a.is_high_fixed() && !b.is_low_fixed() && b.is_high_fixed() )
{
// classification 29..33
if( b.high() > a.high() )
classification = 29;
else if( b.high() == a.high() )
classification = 30;
else
{
if( b.high() < a.low() )
classification = 31;
else if( b.high() == a.low() )
classification = 32;
else
classification = 33;
}
}
else if( !a.is_low_fixed() && a.is_high_fixed() && b.is_low_fixed() && !b.is_high_fixed() )
{
// classification 34..36
if( a.high() < b.low() )
classification = 34;
else if( a.high() == b.low() )
classification = 35;
else
classification = 36;
}
else if( a.is_low_fixed() && !a.is_high_fixed() && !b.is_low_fixed() && b.is_high_fixed() )
{
// classification 37..39
if( b.high() < a.low() )
classification = 37;
else if( b.high() == a.low() )
classification = 38;
else
classification = 39;
}
else if( !a.is_low_fixed() && a.is_high_fixed() && !b.is_low_fixed() && b.is_high_fixed() )
{
// classification 40..42
if( a.high() < b.high() )
classification = 40;
else if( a.high() == b.high() )
classification = 41;
else
classification = 42;
}
else if( a.is_low_fixed() && !a.is_high_fixed() && b.is_low_fixed() && !b.is_high_fixed() )
{
// classification 43..45
if( a.low() < b.low() )
classification = 43;
else if( a.low() == b.low() )
classification = 44;
else
classification = 45;
}
else if( !a.is_low_fixed() && !a.is_high_fixed() && b.is_low_fixed() && b.is_high_fixed() )
classification = 46;
else if( a.is_low_fixed() && a.is_high_fixed() && !b.is_low_fixed() && !b.is_high_fixed() )
classification = 47;
else if( !a.is_low_fixed() && !a.is_high_fixed() && !b.is_low_fixed() && b.is_high_fixed() )
classification = 48;
else if( !a.is_low_fixed() && !a.is_high_fixed() && b.is_low_fixed() && !b.is_high_fixed() )
classification = 49;
else if( !a.is_low_fixed() && a.is_high_fixed() && !b.is_low_fixed() && !b.is_high_fixed() )
classification = 50;
else if( a.is_low_fixed() && !a.is_high_fixed() && !b.is_low_fixed() && !b.is_high_fixed() )
classification = 51;
else // !a.is_low_fixed() && !a.is_high_fixed() && !b.is_low_fixed() && !b.is_high_fixed()
classification = 52;
return classification;
}
char*
r_Sinterval::get_string_representation() const
{
unsigned int bufferSize = 128; // should be enough
// allocate buffer and initialize string stream
char* buffer = new char[bufferSize];
std::ostrstream domainStream( buffer, bufferSize );
// write into string stream
domainStream << (*this) << ends;
// allocate memory taking the final string
char* returnString = strdup(buffer);
// delete buffer
delete[] buffer;
return returnString;
}
/*************************************************************
* Method name...: operator<<( std::ostream& s, r_Sinterval& d )
************************************************************/
std::ostream& operator<<( std::ostream& s, const r_Sinterval& d )
{
d.print_status( s );
return s;
}