/*
* 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: Minterval.cc
*
* MODULE: raslib
* CLASS: r_Minterval
*
* COMMENTS:
*
*/
static const char rcsid[] = "@(#)raslib, r_Minterval: $Header: /home/rasdev/CVS-repository/rasdaman/raslib/minterval.cc,v 1.54 2005/09/03 20:31:22 rasdev Exp $";
using namespace std;
using namespace std;
#include "raslib/rmdebug.hh"
#include "raslib/minterval.hh"
#include "raslib/odmgtypes.hh"
#include "raslib/dlist.hh"
#include "mymalloc/mymalloc.h"
#include
#include
#include
#ifdef __VISUALC__
#include
#else
#include
#endif
r_Minterval::r_Minterval(r_Dimension dim)
: dimensionality(dim),
streamInitCnt(0),
intervals(NULL)
{
RMDBGONCE(20, RMDebug::module_raslib, "r_Minterval", "r_Minterval(r_Dimension), this=" << (long)this)
intervals = new r_Sinterval[ dimensionality ];
}
void
r_Minterval::constructorinit(char* mIntStr) throw(r_Eno_interval)
{
if(!mIntStr)
{
RMInit::logOut << "r_Minterval::r_Minterval(" << (mIntStr?mIntStr:"NULL") << ")" << endl;
throw r_Eno_interval();
}
char* p = NULL; // for counting ','
// for parsing the string
std::istrstream str(mIntStr, strlen(mIntStr) + 1);
char c = 0;
r_Sinterval sint;
r_Range b = 0; // bound for Sinterval
if (intervals != NULL)
{
delete intervals;
intervals = NULL;
}
// calculate dimensionality
p = mIntStr;
while(p = strchr(++p, ','))
dimensionality++;
// allocate space for intervals
intervals = new r_Sinterval[ dimensionality ];
// check for left bracket '['
str >> c;
if (c != '[')
{
// error, should perhaps raise exception
dimensionality = 0;
delete[] intervals;
intervals = NULL;
RMInit::logOut << "r_Minterval::r_Minterval(" << mIntStr << "): the string doesn't have pattern [a:b,c:d]" << endl;
throw r_Eno_interval();
}
// for each dimension: get sinterval
for (r_Dimension i=0; i> c; // test read first char
if (c == '*') // low bound is '*'
sint.set_low('*');
else // low bound must be a number
{
str.putback(c);
str >> b; // read type r_Range
if ( ! str ) // check for proper int recognition
{
RMInit::logOut << "minterval constructor failed on dim " << i << ", lo" << endl << flush;
throw r_Eno_interval();
}
sint.set_low(b); // store lo bound
}
// --- check for ':' between lower and upper bound -------
str >> c;
if (c != ':')
{
// error
dimensionality = 0;
delete[] intervals;
intervals = NULL;
RMInit::logOut << "r_Minterval::r_Minterval(" << mIntStr << "): missing ':', string not like [a:b,c:d]" << endl;
throw r_Eno_interval();
}
// --- evaluate upper bound ------------------------------
str >> c;
if (c == '*')
sint.set_high('*');
else
{
str.putback(c);
str >> b;
if ( ! str )
{
RMInit::logOut << "minterval constructor failed on dim " << i << ", hi" << endl << flush;
throw r_Eno_interval();
}
sint.set_high(b);
}
str >> c;
// --- next dimension needs either ',' separator or ']' end tag
if (i != dimensionality-1 && c != ',' || i == dimensionality-1 && c != ']')
{
dimensionality = 0;
delete[] intervals;
intervals = NULL;
RMInit::logOut << "r_Minterval::r_Minterval(" << mIntStr << "): missing ',' or ']', string not like [a:b,c:d]" << endl;
throw r_Eno_interval();
}
intervals[i] = sint;
sint.set_interval('*','*');
}
}
r_Minterval::r_Minterval(char* mIntStr) throw(r_Eno_interval)
: dimensionality(1),
streamInitCnt(0),
intervals(NULL)
{
RMDBGONCE(20, RMDebug::module_raslib, "r_Minterval", "r_Minterval(char*), this=" << (long)this)
constructorinit(mIntStr);
}
r_Minterval::r_Minterval(const char* mIntStr) throw(r_Eno_interval)
: dimensionality(1),
streamInitCnt(0),
intervals(NULL)
{
RMDBGONCE(20, RMDebug::module_raslib, "r_Minterval", "r_Minterval(char*), this=" << (long)this)
char* temp = (char*)mymalloc((1 + strlen(mIntStr)) * sizeof(char));
strcpy(temp, mIntStr);
try
{
constructorinit(temp);
free(temp);
}
catch(r_Error err)
{
free(temp);
throw;
}
temp = 0;
}
r_Minterval&
r_Minterval::operator<<(const r_Sinterval& newInterval) throw(r_Einit_overflow)
{
if (streamInitCnt >= dimensionality)
{
RMInit::logOut << "r_Minterval::operator<<(" << newInterval << ") domain is already full" << endl;
throw r_Einit_overflow();
}
intervals[streamInitCnt++] = newInterval;
return *this;
}
r_Minterval&
r_Minterval::operator<<(r_Range p) throw(r_Einit_overflow)
{
if (streamInitCnt >= dimensionality)
{
RMInit::logOut << "r_Minterval::operator<<(" << p << ") domain is already full" << endl;
throw r_Einit_overflow();
}
intervals[streamInitCnt++] = r_Sinterval(p, p);
return *this;
}
r_Minterval::r_Minterval()
: dimensionality(0),
streamInitCnt(0),
intervals(NULL)
{
RMDBGONCE(20, RMDebug::module_raslib, "r_Minterval", "r_Minterval(), this=" << this)
}
//cannot use the initialise function because it will crash
r_Minterval::r_Minterval(const r_Minterval& minterval)
: dimensionality(0),
streamInitCnt(0),
intervals(NULL)
{
RMDBGONCE(20, RMDebug::module_raslib, "r_Minterval", "r_Minterval(const r_Minterval&), this=" << this)
dimensionality = minterval.dimensionality;
streamInitCnt = minterval.streamInitCnt;
if(minterval.intervals)
{
intervals = new r_Sinterval[dimensionality];
for (r_Dimension i=0; i= dimensionality)
{
RMInit::logOut << "r_Minterval:::operator[](" << i << ") const index out of bounds (" << dimensionality << ")" << endl;
throw r_Eindex_violation(0, dimensionality-1, i);
}
return intervals[i];
}
r_Sinterval&
r_Minterval::operator[](r_Dimension i)
{
if (i < 0 || i >= dimensionality)
{
RMInit::logOut << "r_Minterval:::operator[](" << i << ") index out of bounds (" << dimensionality << ")" << endl;
throw r_Eindex_violation(0, dimensionality-1, i);
}
return intervals[i];
}
#endif
const r_Minterval&
r_Minterval::operator=(const r_Minterval& minterval)
{
if (this != &minterval)
{
if (intervals && dimensionality != minterval.dimension())
{
delete[] intervals;
intervals = NULL;
}
dimensionality = minterval.dimension();
streamInitCnt = minterval.streamInitCnt;
if(minterval.intervals)
{
if (!intervals)
intervals = new r_Sinterval[ dimensionality ];
for (r_Dimension i=0; i scaleVec;
//create scale vector
for (r_Dimension i = 0; i < dimensionality; i++){
scaleVec.push_back(d);
}
scale(scaleVec);
return *this;
}
r_Minterval&
r_Minterval::scale(const vector& scaleVec) throw(r_Eno_interval)
{
double high = 0., low = 0.;
RMDBGENTER(1, RMDebug::module_raslib, "r_Minterval", "scale(" << scaleVec << ") before " << *this );
// if the size of scale vector is different from dimensionality, undefined behaviour
if(scaleVec.size() != dimensionality) {
RMDBGEXIT(1, RMDebug::module_raslib, "r_Minterval", "scale(" << scaleVec << ") scaleVec has wrong size " << *this );
throw r_Edim_mismatch(scaleVec.size(), dimensionality);
}
for (r_Dimension i = 0; i < dimensionality; i++)
{
// do explicit rounding, because the cast down in set_interval doesn't do the good rounding for negative values -- PB 2005-jun-19
low = floor( scaleVec[i] * intervals[i].low() );
//correction by 1e-6 to avoid the strage bug when high was a
//integer value and floor return value-1(e.g. query 47.ql)
high = floor(scaleVec[i] * (intervals[i].high() +1) + 0.000001) - 1;
// FIXME BUG it was not forseen to be able to scale [a:a] with a very low factor f
// to [af, af]
// if((r_Range)high != (r_Range)low)
// high--; // substract 1 which was added to high()
intervals[i].set_interval((r_Range)low, (r_Range)high);
}
RMDBGEXIT(1, RMDebug::module_raslib, "r_Minterval", "scale(" << scaleVec << ") after " << *this );
return *this;
}
r_Minterval
r_Minterval::create_scale(const double& d) const throw(r_Eno_interval)
{
r_Minterval result(*this);
result.scale(d);
return result;
}
r_Minterval
r_Minterval::create_scale(const vector& scaleVec) const throw(r_Eno_interval)
{
r_Minterval result(*this);
result.scale(scaleVec);
return result;
}
r_Minterval&
r_Minterval::union_of(const r_Minterval& mint1, const r_Minterval& mint2) throw(r_Edim_mismatch, r_Eno_interval)
{
if (mint1.dimension() != mint2.dimension())
{
RMInit::logOut << "r_Minterval::union_of(" << mint1 << ", " << mint2 << ") dimensions do not match" << endl;
throw(r_Edim_mismatch( mint1.dimension(), mint2.dimension()));
}
// cleanup + initializing of this
if (dimensionality != mint1.dimension())
{
if (intervals)
delete[] intervals;
dimensionality = mint1.dimension();
streamInitCnt = dimensionality;
intervals = new r_Sinterval[ dimensionality ];
}
for (r_Dimension i=0; i 0)
{
for (r_Dimension i=0; i intervals[i].high())
{
RMInit::logOut << "r_Minterval::cell_offset(" << point << ") point is out of range (" << *this << ")" << endl;
throw(r_Eindex_violation(point[i], intervals[i].low(), intervals[i].high()));
}
offset = (offset + point[i] - intervals[i].low()) * ptExt[i+1];
}
// now i = dimensionality - 1
if (point[i] < intervals[i].low() || point[i] > intervals[i].high())
{
RMInit::logOut << "r_Minterval::cell_offset(" << point << ") point is out of range (" << *this << ")" << endl;
throw(r_Eindex_violation(point[i], intervals[i].low(), intervals[i].high()));
}
offset += point[i] - intervals[i].low();
return offset;
}
// Arguments.....: linear offset
// Return value..: point object which corresponds to the linear offset of the argument
// Description...: The method calucaltes the spatial domain coordinates as a point out of an offset specification. Lower dimensions are higher valued which means that the highest dimension is stored in a sequence.
r_Point
r_Minterval::cell_point(r_Area offset) const throw(r_Eno_cell, r_Error)
{
r_Dimension i;
unsigned int factor=1;
r_Point pt(dimensionality), ptExt;
if (offset >= cell_count())
{
RMInit::logOut << "r_Minterval::cell_point(" << offset << ") offset is out of range (" << cell_count() << ")" << endl;
throw r_Eno_cell();
}
ptExt=get_extent();
for (i=0; i= dimensionality)
{
RMInit::logOut << "r_Minterval::delete_dimension(" << dim << ") dimension is out of range (" << dimensionality << ")" << endl;
throw r_Eindex_violation(0, dimensionality-1, dim);
}
dimensionality -= 1;
streamInitCnt = dimensionality;
r_Sinterval* newIntervals = new r_Sinterval[ dimensionality ];
for (r_Dimension i=0, j=0; i 0)
sz += dimensionality * intervals->get_storage_size();
return sz;
}
bool
r_Minterval::is_mergeable(const r_Minterval& b) const
{
bool is_merg = true;
// An alias to this object
const r_Minterval& a = *this;
// The blocks must have the same dimensionality to be mergeable
if (a.dimensionality != b.dimensionality)
{
is_merg = false;
}
else {
// Count the number of adjacent frontiers
int ones_differences = 0;
// For all dimensions
for (r_Dimension i=0; i& doubleVec)
{
vector::const_iterator iter, iterEnd;
iter=doubleVec.begin();
iterEnd=doubleVec.end();
s << "{";
while(iter != iterEnd){
s << *iter;
++iter;
if(iter != iterEnd)
s << ", ";
}
s << "}";
return s;
}