Files
secondo/Algebras/GIS/contour.cpp

2793 lines
85 KiB
C++
Raw Normal View History

2026-01-23 17:03:45 +08:00
/*
This file is part of SECONDO.
Copyright (C) 2011, University in Hagen, Department of Computer Science,
Database Systems for New Applications.
SECONDO 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 2 of the License, or
(at your option) any later version.
SECONDO 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 SECONDO; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <algorithm>
#include <stdio.h>
/*
GIS includes
*/
#include "contour.h"
/*
Raster2 and Tile includes
*/
#include "Algebras/Raster2/sint.h"
#include "Algebras/Raster2/sreal.h"
#include "Algebras/Tile/t/tint.h"
#include "Algebras/Tile/t/treal.h"
#include "StopWatch.h"
#include "Algebras/Spatial/DLine.h"
#include "WinUnix.h"
typedef DLine LineType;
using namespace std;
/*
declaration of namespace GISAlgebra
*/
namespace GISAlgebra {
/*
declaration of struct ResultInfo
*/
struct ResultInfo {
ResultInfo(int dummy): level(-32000), cline(0){
}
ResultInfo() {}
int level;
LineType* cline;
};
class ContourLocalInfo{
public:
ContourLocalInfo(const int _num, const double _min,
const int _interval, ListExpr tupleType) :
clines(_num), num(_num),min(_min), interval(_interval){
ResultInfo line(1);
for (int i = 0; i<num; i++) {
clines.Put(i,line);
}
tt = new TupleType(tupleType);
}
~ContourLocalInfo(){
tt->DeleteIfAllowed();
}
void addSegment(int level, const Point& p1, const Point & p2){
HalfSegment hs(true, p1, p2);
// calculate array element
int i = floor((level - min) / interval);
// find correct contour line
ResultInfo temp(1);
clines.Get(i,temp);
// if contour line exists, add segment
if (temp.level != -32000)
{
LineType* line = temp.cline;
int s = line->Size();
hs.attr.edgeno = s/2;
(*line) += hs;
hs.SetLeftDomPoint(false);
(*line) += hs;
}
else
// if not, create new line
{
LineType* line = new LineType(0);
line->StartBulkLoad();
hs.attr.edgeno = 0;
(*line) += hs;
hs.SetLeftDomPoint(false);
(*line) += hs;
int l2 = static_cast<int>(level);
ResultInfo lines(0);
lines.level = l2;
lines.cline = line;
clines.Put(i,lines);
}
}
void finish(){};
Tuple* getNext() {
int i = clines.Size();
if(i<= 0){
return 0;
}
ResultInfo temp(1);
clines.Get(i-1,temp);
clines.resize(i-1);
int j = 2;
while ((temp.level == -32000) && (j <= i)) {
clines.Get(i-j,temp);
clines.resize(i-j);
j++;
}
if ( temp.level == -32000 ) {
return 0;
}
CcInt* level = new CcInt(true,temp.level);
LineType* line = temp.cline;
line->EndBulkLoad();
Tuple* result = new Tuple(tt);
result->PutAttribute(0,level);
result->PutAttribute(1,line);
return result;
}
private:
DbArray<ResultInfo> clines;
int num;
double min;
int interval;
TupleType* tt;
};
/*
1 class ~hSegment~
This class represents a single segment assigned to a height.
There are two spezial values for a normal mark and a specialized
end mark.
*/
class hSegment{
public:
hSegment(){}
hSegment(const int _level, const Point& _p1, const Point& _p2):
level(_level), p1(_p1), p2(_p2){
if(p1.IsDefined() && p2.IsDefined() && (p1< p2)) swap(p1,p2);
}
hSegment(const hSegment& h): level(h.level), p1(h.p1), p2(h.p2){}
~hSegment(){}
hSegment& operator=(const hSegment& h){
level = h.level;
p1 = h.p1;
p2 = h.p2;
return *this;
}
bool operator==(const hSegment& h)const{
return (level==h.level) && AlmostEqual(p1,h.p1) && AlmostEqual(p2,h.p2);
}
bool operator<(const hSegment& h) const{
if(level!=h.level){
return level < h.level;
}
if(!AlmostEqual(p1,h.p1)){
return p1 < h.p1;
}
if(!AlmostEqual(p2,h.p2)){
return p2 < h.p2;
}
return false;
}
inline int getLevel() const{ return level; }
inline const Point& getP1()const{ return p1; }
inline const Point& getP2()const{ return p2; }
static hSegment getEnd(){
return hSegment(0,Point(false,0,0),Point(false,0,0));
}
static hSegment getMarker(){
return hSegment(0,Point(false,0,0),Point(true,0,0));
}
bool isMarker(){
return !p1.IsDefined();
}
bool isEnd(){
return !p1.IsDefined() && !p2.IsDefined();
}
private:
int level;
Point p1;
Point p2;
};
/*
2 class restrictedHeap
This class provides a heap implementation having a restricted size.
The size is given during construction an instance of this class.
When inserting a new element into the heap, the smallest value
(including the new element) is removed from the set of heap elements
and the new element and given back.
*/
template<class T>
class restrictedHeap{
public:
restrictedHeap(size_t slots): slots(slots), used(0){
content = new T[slots];
}
~restrictedHeap(){
delete[] content;
}
/*
Inserts a new element. If the heap overflows, the element's value
is set to the smallest value in the heap (including the element itselfs.
The smallest element is removed from the heap and the result will be true;
*/
bool insert( T& element){
if(used<slots){ // there is space available
content[used] = element;
used++;
climb();
return false;
}
if(element == content[0] || element < content[0]){
return true;
}
std::swap(element,content[0]);
sink();
return true;
}
size_t size() const{
return used;
}
bool empty() const{
return used==0;
}
bool full() const{
return used == slots;
}
const T& getMin(){
assert(used>0);
return content[0];
}
const void deleteMin(){
if(used>0){
swap(content[0], content[used-1]);
used --;
sink();
}
}
private:
size_t slots;
size_t used;
T* content;
/*
lets the last element in the heap climb to its final position
*/
void climb(){
size_t pos = used;
while(pos>1){
size_t father= pos/2;
if(content[father-1] < content[pos-1]){
return;
}
swap(content[father-1], content[pos-1]);
pos = father;
}
}
/*
lets the first element in heap sink to its final position
*/
void sink(){
size_t pos = 1;
while(pos < slots){
size_t s1 = pos*2;
if(s1>used){
return;
}
size_t s2 = s1 + 1;
size_t s;
if(s2>used){
// only one son available
s = s1;
} else {
s = content[s1-1] < content[s2-1]?s1:s2;
}
if(content[pos-1] < content[s-1]){
return; // reached final position
}
swap(content[pos-1],content[s-1]);
pos = s;
}
}
};
/*
3 class segmentStorage
This class provides a storage for hSegment objects.
There are two stages of usage this storage. Within the
first stage, elements can be inserted into this storage.
This stage is finished using the finish() method.
In the second stage (after calling finished), elements
can be retrieved from the storage. The segments are
returned according to its order.
*/
class segmentStorage{
public:
/*
3.1 Contructor
This constructor takes the available memory in bytes as its input.
*/
segmentStorage(size_t mem){
if(mem<4096){
mem = 4096;
}
slots = mem/(sizeof(hSegment) + sizeof(void*) );
if(slots<2){
slots = 2;
}
h1 = new restrictedHeap<hSegment>(slots/2);
h2 = 0;
f1 = 0;
f2 = 0;
outputCache = 0;
buffersize = 8192; // buffersize for file operations
}
/*
3.2 Destructor
*/
~segmentStorage(){
if(h1) delete h1;
if(h2) delete h1;
if(outputCache) delete[] outputCache;
if(f1){ f1->close(); delete f1; }
if(f2){ f2->close(); delete f2; };
for(size_t i=0;i<filenames.size();i++){
remove(filenames[i].c_str());
}
for(size_t i=0;i<filebuffers.size();i++){
delete[] filebuffers[i];
}
}
/*
3.3 insert
This function inserts a new element to this storage.
*/
void insert(hSegment& seg){
if(!h2 && !h1->full()){
// first filling of h1
bool overflow = h1->insert(seg);
assert(!overflow);
return;
}
// stage 2
hSegment cmin = h1->getMin();
h1->deleteMin();
append(f1,cmin); // append to file
if(seg < cmin){
if(!h2){
h2 = new restrictedHeap<hSegment>(slots/2);
}
h2->insert(seg);
} else {
h1->insert(seg);
}
if(h1->size()==0){
appendMarker(f1);
swap(f1,f2);
swap(h1,h2);
}
}
/*
3.4 finish
switch from insertion phase to retrieval phase.
*/
void finish(){
// case 1: h2, f1 and f2 are not present : all items are included in h1
if(h1 && !h2 && !f1 && !f2){
//cout << "Case : all elements are in h1" << endl;
size_t size = h1->size();
if(size>0){
outputCache = new hSegment[size];
int i=0;
while(!h1->empty()){
outputCache[i] = h1->getMin();
i++;
h1->deleteMin();
}
outPos = 0;
outMax = size;
} else {
outPos = 0;
outMax = 0;
}
return;
}
// case 2: h1 and f1 are in use
if(f1 && !h2 && !f2){
// all elements in h1 are greater than those in
// f1, thus we just move the content of h1 to
// the file, generate the output buffer and
// fill the buffer with the content of f1
//cout << "case 2: h1 and f1 are used, h2 and f2 not" << endl;
append(f1,h1,false,true);
outMax = slots;
outputCache = new hSegment[outMax];
f1->seekg(0);
fillOutputCache();
return;
}
// case 3: h1, h2 and f1 is used, f2 not
if(h1 && h2 && f1){
//cout << "case 3 : one or two files and both heaps is used" << endl;
// all elements in f1 are smaller than
// those in h1, elements in h2 are
// smaller than the last element in f1
append(f1,h1,true,true);
append(f2,h2,true,true);
merge(f1,f2);
outputCache = new hSegment[slots];
outMax = slots;
f1->seekg(0);
fillOutputCache();
return;
}
assert(false); // forgotten case
}
/*
3.5 ~hasNext~
Within the retrieval phase, it can be checked whether more elements are available.
*/
bool hasNext() const{
return outPos < outMax;
}
const hSegment& current(){
return outputCache[outPos];
}
void next(){
outPos++;
if(outPos == outMax){
if(f1){
fillOutputCache();
}
}
}
private:
restrictedHeap<hSegment>* h1; // heap
restrictedHeap<hSegment>* h2; // heap
fstream* f1; // file for heap overflow
fstream* f2; // second file
vector<char*> filebuffers; // vector of buffers
size_t slots;
hSegment* outputCache;
size_t outPos;
size_t outMax;
vector<string> filenames;
size_t buffersize;
/*
3.6 append
Appends ~seg~ to ~f~. if ~f~ does not exist, it will be created.
*/
void append(fstream*& f , const hSegment& seg){
if(!f){
string fname = generateFName();
f = new fstream(fname.c_str(), ios_base::in | ios_base::out
| ios_base::binary | ios_base::trunc);
char* buffer = new char[buffersize];
filebuffers.push_back(buffer);
f->rdbuf()->pubsetbuf(buffer, buffersize);
}
f->write((char*) &seg, sizeof(hSegment));
}
/*
3.7 append
Appends a normal marker to the given file.
*/
void appendMarker(fstream*& f){
static hSegment marker = hSegment::getMarker();
append(f,marker);
}
/*
3.8 gerenateFName
Generates a new filename.
*/
string generateFName(){
static int no = 0;
stringstream ss;
ss << "tmp/T_" << WinUnix::getpid() << "_segStorage_" << no;
no++;
filenames.push_back(ss.str());
return ss.str();
}
/*
3.9 fillOutputcache
Copies data from file f1 to the outputcache.
*/
void fillOutputCache(){
assert(f1);
outPos = 0;
size_t pos = 0;
hSegment seg;
while( (pos < outMax) && !f1->eof()){
f1->read((char*)&seg, sizeof(hSegment));
if(!seg.isMarker()){
outputCache[pos] = seg;
pos++;
} else if(seg.isEnd()){
f1->close();
delete f1;
f1 = 0;
outMax = pos;
return;
}
}
if(f1->eof()){
f1->close();
delete f1;
f1 = 0;
}
outMax = pos;
}
/*
3.10 append
Appends all elements within the heap to ~f~. If finishMarker
is set to ~true~, an marker will be appended after the elements
of ~h~. If destroy Heap is set to true, the heap is destroyed
after copying the elements.
*/
void append(fstream*& f,
restrictedHeap<hSegment>*& h,
bool finishMarker, bool destroyHeap){
while(!h->empty()){
append(f,h->getMin());
h->deleteMin();
}
if(finishMarker){
appendMarker(f);
}
if(destroyHeap){
delete h;
h = 0;
}
}
/*
3.11 merge
Merges the contents of f1 and f2 together in result.
The result is written to f1.
*/
void merge(fstream*& f1, fstream*& f2){
StopWatch sw;
size_t phases = 0;
fstream* g1 = new fstream(generateFName().c_str(), ios_base::in |
ios_base::out | ios_base::binary |
ios_base::trunc);
fstream* g2 = new fstream(generateFName().c_str(), ios_base::in |
ios_base::out | ios_base::binary |
ios_base::trunc);
append(f1, hSegment::getEnd());
append(f2, hSegment::getEnd());
char g1buf[buffersize];
char g2buf[buffersize];
g1->rdbuf()->pubsetbuf(g1buf,buffersize);
g2->rdbuf()->pubsetbuf(g2buf,buffersize);
int runs=0;
do{
runs = merge(f1,f2,g1,g2);
swap(f1,g1);
swap(f2,g2);
phases++;
} while(runs > 1);
delete f2;
f2 = 0;
delete g1;
g1 = 0;
delete g2;
g2 = 0;
}
/*
3.12 merge
This function perform a single phase of merging f1 and f2. The merged
runs are written to g1 and g2.
*/
int merge(fstream* f1, fstream* f2, fstream* g1, fstream* g2){
f1->seekg(0);
f2->seekg(0);
g1->seekp(0);
g2->seekp(0);
hSegment f1Cur;
hSegment f2Cur;
int runs = 0;
f1->read((char*) &f1Cur, sizeof(hSegment));
f2->read((char*) &f2Cur, sizeof(hSegment));
while(!f1Cur.isEnd() || !f2Cur.isEnd()){
while(!f1Cur.isMarker() || !f2Cur.isMarker()){
if(f1Cur.isMarker()){
append(g1,f2Cur);
f2->read((char*) &f2Cur, sizeof(hSegment));
} else if(f2Cur.isMarker()){
append(g1,f1Cur);
f1->read((char*) &f1Cur, sizeof(hSegment));
} else {
if(f1Cur < f2Cur){
append(g1,f1Cur);
f1->read((char*) &f1Cur, sizeof(hSegment));
} else {
append(g1,f2Cur);
f2->read((char*) &f2Cur, sizeof(hSegment));
}
}
}
// both element are markers
append(g1,hSegment::getMarker());
runs++;
swap(g1,g2);
if(!f1Cur.isEnd()){
f1->read((char*) &f1Cur, sizeof(hSegment));
}
if(!f2Cur.isEnd()){
f2->read((char*) &f2Cur, sizeof(hSegment));
}
}
append(g1,hSegment::getEnd());
append(g2,hSegment::getEnd());
return runs ;
}
};
class ContourLineLocalInfo2{
public:
ContourLineLocalInfo2(ListExpr tupleType, size_t mem)
{
tt = new TupleType(tupleType);
store = new segmentStorage(mem);
}
~ContourLineLocalInfo2(){
tt->DeleteIfAllowed();
delete store;
}
void addSegment(int level, const Point& p1, const Point & p2){
hSegment seg(level,p1,p2);
store->insert(seg);
}
void finish(){
store->finish();
}
Tuple* getNext() {
if(!store->hasNext()){
return 0;
}
LineType* line = new LineType(0);
line->StartBulkLoad();
hSegment seg = store->current();
int level = seg.getLevel();
int edge = 0;
while(store->hasNext() && level == seg.getLevel()){
insert(seg,line, edge);
edge++;
store->next();
if(store->hasNext()){
seg = store->current();
}
}
line->EndBulkLoad();
Tuple* result = new Tuple(tt);
result->PutAttribute(0,new CcInt(true,level));
result->PutAttribute(1,line);
return result;
}
private:
segmentStorage* store;
TupleType* tt;
void insert(const hSegment seg, LineType* line, int edgeno){
HalfSegment hs(true,seg.getP1(), seg.getP2());
hs.attr.edgeno=edgeno;
(*line) += hs;
hs.SetLeftDomPoint(false);
(*line) += hs;
}
};
/*
Method ProcessRectangle returns true if processing was successful
Parameters: values and coordinates of four points, the wanted interval,
the minimum value and DbArray ResultInfo to store the found
segments
*/
template<class LI>
bool ProcessRectangle(double, double, double,
double, double, double,
double, double, double,
double, double, double,
int, LI*);
/*
Method AddSegment addes the found segments to the ResultInfo DbArray
Parameters: level value, coordinates of segments start and stop point,
the minimum value, the interval value and DbArray ResultInfo
to store the segments
*/
template<class LI>
void AddSegment(int, double, double,
double, double, LI*);
/*
Method contourFuns: calculates the contour lines for a given sint or sreal
object
Return value: stream of tuple (level, line)
*/
template <typename T>
int contourFun(Word* args, Word& result,
int message, Word& local, Supplier s)
{
int returnValue = FAILURE;
typename T::this_type* s_in =
static_cast<typename T::this_type*>(args[0].addr);
CcInt* lines = static_cast<CcInt*>(args[1].addr);
typedef ContourLineLocalInfo2 LIT;
LIT* li = (LIT*) local.addr;
switch(message)
{
case OPEN:
{
// initialize the local storage
double min = s_in->getMinimum();
double max = s_in->getMaximum();
if( !lines->IsDefined()
|| s_in->isUndefined(min) || s_in->isUndefined(max)){
return 0;
}
int interval = lines->GetValue();
if ( interval < 1 )
{
cmsg.error() << "Interval < 1 not allowed" << endl;
cmsg.send();
return CANCEL;
}
// double diff = max - min;
// int num = ceil(diff / interval) + 1;
if(li){ delete li; }
// li = new LIT(num,min, interval,
// nl->Second(GetTupleResultType(s)));
size_t mem;
#ifdef contourlines_fixed_cache
mem = 64*1024*1024;
#else
mem = qp->GetMemorySize(s)*1024*1024;
#endif
li = new LIT( nl->Second(GetTupleResultType(s)), mem);
local.addr = li;
raster2::grid2 grid = s_in->getGrid();
Rectangle<2> bbox = s_in->bbox();
double gridOriginX = grid.getOriginX();
double gridOriginY = grid.getOriginY();
double cellsize = grid.getLength();
raster2::RasterIndex<2> from =
grid.getIndex(bbox.MinD(0), bbox.MinD(1));
raster2::RasterIndex<2> to =
grid.getIndex(bbox.MaxD(0), bbox.MaxD(1));
for (raster2::RasterIndex<2> index = from; index < to;
index.increment(from, to))
{
// central cell
double e = s_in->get(index);
if (!(s_in->isUndefined(e)))
{
double a = s_in->get((int[]){index[0] - 1, index[1] + 1});
double a1 = s_in->get((int[]){index[0] - 1, index[1] + 2});
double b = s_in->get((int[]){index[0], index[1] + 1});
double b1 = s_in->get((int[]){index[0], index[1] + 2});
double c = s_in->get((int[]){index[0] + 1, index[1] + 1});
double d = s_in->get((int[]){index[0] - 1, index[1]});
double g = s_in->get((int[]){index[0] - 1, index[1] - 1});
double h = s_in->get((int[]){index[0], index[1] - 1});
double f = s_in->get((int[]){index[0] + 1, index[1]});
// calculate coordinates
double X = index[0] * cellsize + cellsize/2 + gridOriginX;
double Y = index[1] * cellsize + cellsize/2 + gridOriginY;
// if all four cells have valid values
if (!(s_in->isUndefined(a)) && !(s_in->isUndefined(b)) &&
!(s_in->isUndefined(d)) && !(s_in->isUndefined(e)))
{
// special case for bottom right cell
if ((s_in->isUndefined(h)) && (s_in->isUndefined(f)))
{
ProcessRectangle(a, X - cellsize, Y + cellsize,
d, X - cellsize, Y - cellsize/2,
e, X + cellsize/2, Y - cellsize/2,
b, X + cellsize/2, Y + cellsize,
interval, li);
}
// special case for first row
else if ((s_in->isUndefined(h)) && (s_in->isUndefined(g)))
{
ProcessRectangle(a, X - cellsize, Y + cellsize,
d, X - cellsize, Y - cellsize/2,
e, X, Y - cellsize/2,
b, X, Y + cellsize,
interval, li);
}
// special case for top right cell
else if ((s_in->isUndefined(f)) && (s_in->isUndefined(a1))
&& (s_in->isUndefined(b1)))
{
ProcessRectangle(a, X - cellsize, Y + cellsize + cellsize/2,
d, X - cellsize, Y,
e, X + cellsize/2, Y,
b, X + cellsize/2, Y + cellsize+cellsize/2,
interval, li);
}
// special case for last column
else if ((s_in->isUndefined(f)) && (s_in->isUndefined(c)))
{
ProcessRectangle(a, X - cellsize, Y + cellsize,
d, X - cellsize, Y,
e, X + cellsize/2, Y,
b, X + cellsize/2, Y + cellsize,
interval, li);
}
// special case for top row
else if ((s_in->isUndefined(a1)) && (s_in->isUndefined(b1)))
{
ProcessRectangle(a, X - cellsize, Y + cellsize + cellsize/2,
d, X - cellsize, Y,
e, X, Y,
b, X, Y + cellsize+cellsize/2,
interval, li);
}
// normal case
else
{
ProcessRectangle(a, X - cellsize, Y + cellsize,
d, X - cellsize, Y,
e, X, Y,
b, X, Y + cellsize,
interval, li);
}
}
else
{
// determine which cells have defined values, accumulate values
// and divide through number of valid cells
double sum = 0;
int good = 0;
double center = 0;
if (!(s_in->isUndefined(a)))
{
sum += a;
good++;
}
if (!(s_in->isUndefined(b)))
{
sum += b;
good++;
}
if (!(s_in->isUndefined(d)))
{
sum += d;
good++;
}
if (!(s_in->isUndefined(e)))
{
sum += e;
good++;
}
center = sum / good;
// calculate alternative values
double top;
double left;
double right;
double bottom;
if(!(s_in->isUndefined(a)))
{
if(!(s_in->isUndefined(b)))
top = (a + b) / 2.0;
else
top = a;
if(!(s_in->isUndefined(d)))
left = (a + d) / 2.0;
else
left = a;
}
else
{
if (!(s_in->isUndefined(b)))
top = b;
else
top = e;
if (!(s_in->isUndefined(d)))
left = d;
else
left = e;
}
if(!(s_in->isUndefined(b)))
right = (e + b) / 2.0;
else
right = e;
if(!(s_in->isUndefined(d)))
bottom = (e + d) / 2.0;
else
bottom = e;
// if one cell is not defined
// -> calculation with alternative values
if (!(s_in->isUndefined(a)))
{
ProcessRectangle(a, X - cellsize, Y + cellsize,
left, X - cellsize, Y + cellsize/2,
center, X - cellsize/2, Y + cellsize/2,
top, X - cellsize/2, Y + cellsize,
interval, li);
}
if (!(s_in->isUndefined(d)))
{
if ((s_in->isUndefined(f)) && (s_in->isUndefined(b)))
{
// special case top right cell
}
else if (!(s_in->isUndefined(e)) && !(s_in->isUndefined(d)) &&
(s_in->isUndefined(a)) && !(s_in->isUndefined(b)))
{
// special case cell under undefined cell
ProcessRectangle(left, X - cellsize, Y + cellsize/2,
d, X - cellsize, Y,
bottom, X - cellsize/2, Y,
center, X - cellsize/2, Y + cellsize/2,
interval, li);
}
else if (!(s_in->isUndefined(e)) && !(s_in->isUndefined(d)) &&
!(s_in->isUndefined(a)) && (s_in->isUndefined(b)))
{
// special case cell left under undefined cell
ProcessRectangle(left, X - cellsize, Y + cellsize/2,
d, X - cellsize, Y,
bottom, X - cellsize/2, Y,
center, X - cellsize/2, Y + cellsize/2,
interval, li);
}
}
if (!(s_in->isUndefined(e)) && (s_in->isUndefined(h))
&& (s_in->isUndefined(d)))
{
// special case left bottom cell
}
else if (!(s_in->isUndefined(e)) && (s_in->isUndefined(a)) &&
!(s_in->isUndefined(b)) && (s_in->isUndefined(b1)))
{
// special case top left cell
ProcessRectangle(b, X-cellsize/2, Y+cellsize+cellsize/2,
bottom, X - cellsize/2, Y,
e, X, Y,
b, X, Y + cellsize + cellsize/2,
interval, li);
}
else if (!(s_in->isUndefined(e)) && (s_in->isUndefined(a))
&& (s_in->isUndefined(b)))
{
// special case top row
}
else if (!(s_in->isUndefined(e)) && !(s_in->isUndefined(f)))
{
// special case right top cell
ProcessRectangle(center, X - cellsize/2, Y + cellsize/2,
bottom, X - cellsize/2, Y,
e, X, Y,
right, X, Y + cellsize/2,
interval, li);
}
if (!(s_in->isUndefined(e)) && (s_in->isUndefined(a)) &&
!(s_in->isUndefined(b)) && (s_in->isUndefined(b1)) &&
(s_in->isUndefined(a1)))
{
// special case left top cell
}
else if (!(s_in->isUndefined(b)) && (s_in->isUndefined(h)))
{
ProcessRectangle(top, X - cellsize/2, Y + cellsize,
e, X - cellsize/2, Y - cellsize/2,
e, X, Y - cellsize/2,
b, X, Y + cellsize,
interval, li);
}
else if (!(s_in->isUndefined(b)) && (s_in->isUndefined(d))
&& !(s_in->isUndefined(b1)))
{
ProcessRectangle(top, X - cellsize/2, Y + cellsize,
center, X - cellsize/2, Y + cellsize/2,
right, X, Y + cellsize/2,
b, X, Y + cellsize,
interval, li);
}
else if (!(s_in->isUndefined(b)) && !(s_in->isUndefined(e))
&& (s_in->isUndefined(a)))
{
// special case right of undefined
ProcessRectangle(top, X - cellsize/2, Y + cellsize,
center, X - cellsize/2, Y + cellsize/2,
right, X, Y + cellsize/2,
b, X, Y + cellsize,
interval, li);
}
}
}//if e def
}// for
li->finish();
return 0;
}
case REQUEST:
{
result.addr = li?li->getNext():0;
return result.addr?YIELD:CANCEL;
}
case CLOSE:
{
if(li){
delete li;
local.addr = 0;
}
return 0;
}
default:
{
assert(false);
}
}
return returnValue;
}
/*
Method contourFuns: calculates the contour lines for a given stream of
tint or treal objects
Return value: stream of tuple (level, line)
*/
template <typename T, typename SourceTypeProperties>
int contourFunTile(Word* args, Word& result,
int message, Word& local, Supplier s)
{
int returnValue = FAILURE;
CcInt* lines = static_cast<CcInt*>(args[1].addr);
vector<Tuple*> current;
vector<Tuple*> last;
vector<Tuple*> next;
Tuple* nextElement;
double fromX;
double fromY;
double toX;
double toY;
double tileSize;
double cellSize;
bool firstTuple = true;
bool readNextElement = true;
bool newLine = false;
bool skipNextRow;
bool skipLastRow;
int currentSize;
int nextSize;
int lastSize;
int currentTuple = 0;
int xDimensionSize = TileAlgebra::tProperties<char>::GetXDimensionSize();
int yDimensionSize = TileAlgebra::tProperties<char>::GetYDimensionSize();
int maxX = xDimensionSize - 1;
int maxY = yDimensionSize - 1;
//ContourLocalInfo* li = (ContourLocalInfo*) local.addr;
ContourLineLocalInfo2* li = (ContourLineLocalInfo2*) local.addr;
switch(message)
{
case OPEN:
{
if(!lines->IsDefined()){
return 0;
}
int interval = lines->GetValue();
// Check for valid interval
if ( interval < 1 )
{
cmsg.error() << "Interval < 1 not allowed" << endl;
cmsg.send();
return CANCEL;
}
Word elem;
Tuple* tuple;
T* s_in;
typename SourceTypeProperties::TypeProperties::PropertiesType min;
typename SourceTypeProperties::TypeProperties::PropertiesType max;
qp->Open(args[0].addr);
qp->Request(args[0].addr, elem);
bool firstValue = true;
// Get minimum and maximum values of complete tile
while(qp->Received(args[0].addr))
{
tuple = (Tuple*)elem.addr;
s_in = static_cast<T*>(tuple->GetAttribute(0));
typename SourceTypeProperties::TypeProperties::PropertiesType minTemp;
s_in->minimum(minTemp);
typename SourceTypeProperties::TypeProperties::PropertiesType maxTemp;
s_in->maximum(maxTemp);
if (firstValue ||(minTemp < min) )
{
min = minTemp;
}
if (firstValue || (maxTemp > max) )
{
max = maxTemp;
}
firstValue = false;
tuple->DeleteIfAllowed();
qp->Request(args[0].addr, elem);
}
qp->Close(args[0].addr);
// double diff = max - min;
// int num = ceil(diff / interval) + 1;
if(li) delete li;
// li = new ContourLocalInfo(num, min, interval,
// nl->Second(GetTupleResultType(s)));
size_t mem;
#ifdef contourlines_fixed_cache
mem = 64*1024*1024;
#else
mem = qp->GetMemorySize(s)*1024*1024;
#endif
li = new ContourLineLocalInfo2(
nl->Second(GetTupleResultType(s)),
mem);
local.addr = li;
qp->Open(args[0].addr);
double gridOriginX;
double gridOriginY;
double lastOriginX;
double lastOriginY;
while (readNextElement == true)
{
qp->Request(args[0].addr, elem);
if(qp->Received(args[0].addr))
{
tuple = (Tuple*)elem.addr;
s_in = static_cast<T*>(tuple->GetAttribute(0));
TileAlgebra::tgrid grid;
s_in->getgrid(grid);
gridOriginX = grid.GetX();
gridOriginY = grid.GetY();
cellSize = grid.GetLength();
tileSize = cellSize * xDimensionSize;
// read cells until Y coordinate changes
if ( firstTuple || (gridOriginY == lastOriginY) )
{
if (!(firstTuple == true))
{
// if there is a gap between two read tiles, fill vector
// with dummy tile
while ((gridOriginX - lastOriginX) - tileSize > cellSize)
{
TupleType *tupleType = tuple->GetTupleType();
Tuple* dummy = new Tuple( tupleType );
T* s_out = new T(true);
dummy->PutAttribute(0,s_out);
current.push_back(dummy);
lastOriginX = lastOriginX + tileSize;
}
}
current.push_back(tuple);
lastOriginX = gridOriginX;
lastOriginY = gridOriginY;
firstTuple = false;
}
else
{
readNextElement = false;
firstTuple = true;
next.push_back(tuple);
lastOriginX = gridOriginX;
}
}
else
{
readNextElement = false;
}
} // while currentLine
currentSize = current.size();
readNextElement = true;
while (currentSize != 0)
{
while (readNextElement == true)
{
qp->Request(args[0].addr, elem);
if(qp->Received(args[0].addr))
{
tuple = (Tuple*)elem.addr;
s_in = static_cast<T*>(tuple->GetAttribute(0));
TileAlgebra::tgrid grid;
s_in->getgrid(grid);
gridOriginX = grid.GetX();
gridOriginY = grid.GetY();
cellSize = grid.GetLength();
// read cells until Y coordinate changes
if ((gridOriginY == lastOriginY) || (firstTuple == true))
{
// if there is a gap between two read tiles, fill vector
// with dummy tile
while ((gridOriginX-lastOriginX) - tileSize > cellSize)
{
TupleType *tupleType = tuple->GetTupleType();
Tuple* dummy = new Tuple( tupleType );
T* s_out = new T(true);
dummy->PutAttribute(0,s_out);
next.push_back(dummy);
lastOriginX = lastOriginX + tileSize;
}
next.push_back(tuple);
lastOriginX = gridOriginX;
lastOriginY = gridOriginY;
firstTuple = false;
}
else
{
readNextElement = false;
firstTuple = true;
newLine = true;
nextElement = tuple;
lastOriginX = gridOriginX;
}
}
else
{
readNextElement = false;
}
} // while NextLine
int factorNext = 0;
int factorLast = 0;
skipNextRow = false;
skipLastRow = false;
nextSize = next.size();
lastSize = last.size();
Tuple* cTuple = current[0];
T* c = static_cast<T*>(cTuple->GetAttribute(0));
TileAlgebra::tgrid cGrid;
c->getgrid(cGrid);
double cGridOriginX = cGrid.GetX();
double cGridOriginY = cGrid.GetY();
if (nextSize > 0)
{
Tuple* nTuple = next[0];
T* n = static_cast<T*>(nTuple->GetAttribute(0));
TileAlgebra::tgrid nGrid;
n->getgrid(nGrid);
double nGridOriginX = nGrid.GetX();
double nGridOriginY = nGrid.GetY();
// calculate factor if tile rows starts at different coordinates
if ((cGridOriginX - nGridOriginX) > 0)
{
while ((cGridOriginX - nGridOriginX) > 0)
{
factorNext++;
nGridOriginX = nGridOriginX + tileSize;
}
}
else if ((cGridOriginX - nGridOriginX) < 0)
{
while ((cGridOriginX - nGridOriginX) < 0)
{
factorNext--;
cGridOriginX = cGridOriginX + tileSize;
}
}
// check if one or more rows are missing
if ((nGridOriginY - cGridOriginY) > tileSize)
{
skipNextRow = true;
}
}
if (lastSize > 0)
{
Tuple* lTuple = last[0];
T* l = static_cast<T*>(lTuple->GetAttribute(0));
TileAlgebra::tgrid lGrid;
l->getgrid(lGrid);
double lGridOriginX = lGrid.GetX();
double lGridOriginY = lGrid.GetY();
cGridOriginX = cGrid.GetX();
cGridOriginY = cGrid.GetY();
// calculate factor if tile rows starts at different coordinates
if ((cGridOriginX - lGridOriginX) > 0)
{
while ((cGridOriginX - lGridOriginX) > 0)
{
factorLast++;
lGridOriginX = lGridOriginX + tileSize;
}
}
else if ((cGridOriginX - lGridOriginX) < 0)
{
while ((cGridOriginX - lGridOriginX) < 0)
{
factorLast--;
cGridOriginX = cGridOriginX + tileSize;
}
}
// check if one or more rows are missing
if ((cGridOriginY - lGridOriginY) > tileSize)
{
skipLastRow = true;
}
}
while (currentTuple < currentSize)
{
tuple = current[currentTuple];
if ((tuple == 0) || (tuple->GetNoAttributes() != 1))
{
while (tuple == 0)
{
currentTuple++;
tuple = current[currentTuple];
}
while (tuple->GetNoAttributes() != 1)
{
currentTuple++;
tuple = current[currentTuple];
}
}
s_in = static_cast<T*>(tuple->GetAttribute(0));
TileAlgebra::Index<2> from;
TileAlgebra::Index<2> to;
s_in->GetBoundingBoxIndexes(from, to);
fromX = from[0];
fromY = from[1];
toX = to[0];
toY = to[1];
TileAlgebra::tgrid grid;
s_in->getgrid(grid);
cellSize = grid.GetLength();
gridOriginX = grid.GetX();
gridOriginY = grid.GetY();
for(int row = fromY; row <= toY; row++)
{
for(int column = fromX; column <= toX; column++)
{
TileAlgebra::Index<2> index((int[]){column, row});
// central cell
double e = s_in->GetValue(index);
if(!(SourceTypeProperties::TypeProperties::IsUndefinedValue(e)))
{
double a =
SourceTypeProperties::TypeProperties::GetUndefinedValue();
double a1 =
SourceTypeProperties::TypeProperties::GetUndefinedValue();
double b =
SourceTypeProperties::TypeProperties::GetUndefinedValue();
double b1 =
SourceTypeProperties::TypeProperties::GetUndefinedValue();
double c =
SourceTypeProperties::TypeProperties::GetUndefinedValue();
double d =
SourceTypeProperties::TypeProperties::GetUndefinedValue();
double f =
SourceTypeProperties::TypeProperties::GetUndefinedValue();
double g =
SourceTypeProperties::TypeProperties::GetUndefinedValue();
double h =
SourceTypeProperties::TypeProperties::GetUndefinedValue();
GetValuesContour<T, SourceTypeProperties>
(&a, &a1, &b, &b1, &c, &d, &f, &g, &h, row, column,
currentTuple, s_in,
maxX, maxY, factorNext, factorLast,
skipNextRow, skipLastRow,
current, next, last,
currentSize, nextSize, lastSize);
// calculate coordinates
double X = index[0] * cellSize + cellSize/2 + gridOriginX;
double Y = index[1] * cellSize + cellSize/2 + gridOriginY;
// if all four cells have valid values
if (!(SourceTypeProperties::TypeProperties::
IsUndefinedValue(a)) &&
!(SourceTypeProperties::TypeProperties::
IsUndefinedValue(b)) &&
!(SourceTypeProperties::TypeProperties::
IsUndefinedValue(d)) &&
!(SourceTypeProperties::TypeProperties::
IsUndefinedValue(e)))
{
// special case for bottom right cell
if ((SourceTypeProperties::TypeProperties::
IsUndefinedValue(h)) &&
(SourceTypeProperties::TypeProperties::
IsUndefinedValue(f)))
{
ProcessRectangle(a, X - cellSize, Y + cellSize,
d, X - cellSize, Y - cellSize/2,
e, X + cellSize/2, Y - cellSize/2,
b, X + cellSize/2, Y + cellSize,
interval, li);
}
// special case for first row
else if ((SourceTypeProperties::TypeProperties::
IsUndefinedValue(h)) &&
(SourceTypeProperties::TypeProperties::
IsUndefinedValue(g)))
{
ProcessRectangle(a, X - cellSize, Y + cellSize,
d, X - cellSize, Y - cellSize/2,
e, X, Y - cellSize/2,
b, X, Y + cellSize,
interval, li);
}
// special case for top right cell
else if ((SourceTypeProperties::TypeProperties::
IsUndefinedValue(f)) &&
(SourceTypeProperties::TypeProperties::
IsUndefinedValue(a1)) &&
(SourceTypeProperties::TypeProperties::
IsUndefinedValue(b1)))
{
ProcessRectangle(a, X - cellSize, Y+cellSize+cellSize/2,
d, X - cellSize, Y,
e, X + cellSize/2, Y,
b, X + cellSize/2, Y+cellSize+cellSize/2,
interval, li);
}
// special case for last column
else if ((SourceTypeProperties::TypeProperties::
IsUndefinedValue(f)) &&
(SourceTypeProperties::TypeProperties::
IsUndefinedValue(c)))
{
ProcessRectangle(a, X - cellSize, Y + cellSize,
d, X - cellSize, Y,
e, X + cellSize/2, Y,
b, X + cellSize/2, Y + cellSize,
interval, li);
}
// special case for top row
else if ((SourceTypeProperties::TypeProperties::
IsUndefinedValue(a1)) &&
(SourceTypeProperties::TypeProperties::
IsUndefinedValue(b1)))
{
ProcessRectangle(a, X - cellSize, Y + cellSize+cellSize/2,
d, X - cellSize, Y,
e, X, Y,
b, X, Y + cellSize + cellSize/2,
interval, li);
}
// normal case
else
{
ProcessRectangle(a, X - cellSize, Y + cellSize,
d, X - cellSize, Y,
e, X, Y,
b, X, Y + cellSize,
interval, li);
}
}
else
{
// determine which cells have defined values, accumulate
// values and divide through number of valid cells
double sum = 0;
int good = 0;
double center = 0;
if (!(SourceTypeProperties::TypeProperties::
IsUndefinedValue(a)))
{
sum += a;
good++;
}
if (!(SourceTypeProperties::TypeProperties::
IsUndefinedValue(b)))
{
sum += b;
good++;
}
if (!(SourceTypeProperties::TypeProperties::
IsUndefinedValue(d)))
{
sum += d;
good++;
}
if (!(SourceTypeProperties::TypeProperties::
IsUndefinedValue(e)))
{
sum += e;
good++;
}
center = sum / good;
// calculate alternative values
double top;
double left;
double right;
double bottom;
if(!(SourceTypeProperties::TypeProperties::
IsUndefinedValue(a)))
{
if(!(SourceTypeProperties::TypeProperties::
IsUndefinedValue(b)))
top = (a + b) / 2.0;
else
top = a;
if(!(SourceTypeProperties::TypeProperties::
IsUndefinedValue(d)))
left = (a + d) / 2.0;
else
left = a;
}
else
{
if (!(SourceTypeProperties::TypeProperties::
IsUndefinedValue(b)))
top = b;
else
top = e;
if (!(SourceTypeProperties::TypeProperties::
IsUndefinedValue(d)))
left = d;
else
left = e;
}
if(!(SourceTypeProperties::TypeProperties::
IsUndefinedValue(b)))
right = (e + b) / 2.0;
else
right = e;
if(!(SourceTypeProperties::TypeProperties::
IsUndefinedValue(d)))
bottom = (e + d) / 2.0;
else
bottom = e;
// if one cell is not defined
// -> calculation with alternative values
if (!(SourceTypeProperties::TypeProperties::
IsUndefinedValue(a)))
{
ProcessRectangle(a, X - cellSize, Y + cellSize,
left, X - cellSize, Y + cellSize/2,
center, X - cellSize/2, Y + cellSize/2,
top, X - cellSize/2, Y + cellSize,
interval, li);
}
if (!(SourceTypeProperties::TypeProperties::
IsUndefinedValue(d)))
{
if ((SourceTypeProperties::TypeProperties::
IsUndefinedValue(f)) &&
(SourceTypeProperties::TypeProperties::
IsUndefinedValue(b)))
{
// special case top right cell
}
else if (!(SourceTypeProperties::TypeProperties::
IsUndefinedValue(e)) &&
!(SourceTypeProperties::TypeProperties::
IsUndefinedValue(d)) &&
(SourceTypeProperties::TypeProperties::
IsUndefinedValue(a)) &&
!(SourceTypeProperties::TypeProperties::
IsUndefinedValue(b)))
{
// special case cell under undefined cell
ProcessRectangle(left, X - cellSize, Y + cellSize/2,
d, X - cellSize, Y,
bottom, X - cellSize/2, Y,
center, X - cellSize/2, Y + cellSize/2,
interval, li);
}
else if (!(SourceTypeProperties::TypeProperties::
IsUndefinedValue(e)) &&
!(SourceTypeProperties::TypeProperties::
IsUndefinedValue(d)) &&
!(SourceTypeProperties::TypeProperties::
IsUndefinedValue(a)) &&
(SourceTypeProperties::TypeProperties::
IsUndefinedValue(b)))
{
// special case cell left under undefined cell
ProcessRectangle(left, X - cellSize, Y + cellSize/2,
d, X - cellSize, Y,
bottom, X - cellSize/2, Y,
center, X - cellSize/2, Y + cellSize/2,
interval, li);
}
}
if (!(SourceTypeProperties::TypeProperties::
IsUndefinedValue(e)) &&
(SourceTypeProperties::TypeProperties::
IsUndefinedValue(h)) &&
(SourceTypeProperties::TypeProperties::
IsUndefinedValue(d)))
{
// special case left bottom cell
}
else if (!(SourceTypeProperties::TypeProperties::
IsUndefinedValue(e)) &&
(SourceTypeProperties::TypeProperties::
IsUndefinedValue(a)) &&
!(SourceTypeProperties::TypeProperties::
IsUndefinedValue(b)) &&
(SourceTypeProperties::TypeProperties::
IsUndefinedValue(b1)))
{
// special case top left cell
ProcessRectangle(b, X-cellSize/2, Y+cellSize+cellSize/2,
bottom, X - cellSize/2, Y,
e, X, Y,
b, X, Y + cellSize + cellSize/2,
interval, li);
}
else if (!(SourceTypeProperties::TypeProperties::
IsUndefinedValue(e)) &&
(SourceTypeProperties::TypeProperties::
IsUndefinedValue(a)) &&
(SourceTypeProperties::TypeProperties::
IsUndefinedValue(b)))
{
// special case top row
}
else if (!(SourceTypeProperties::TypeProperties::
IsUndefinedValue(e)) &&
!(SourceTypeProperties::TypeProperties::
IsUndefinedValue(f)))
{
// special case right top cell
ProcessRectangle(center, X - cellSize/2, Y + cellSize/2,
bottom, X - cellSize/2, Y,
e, X, Y,
right, X, Y + cellSize/2,
interval, li);
}
if (!(SourceTypeProperties::TypeProperties::
IsUndefinedValue(e)) &&
(SourceTypeProperties::TypeProperties::
IsUndefinedValue(a)) &&
!(SourceTypeProperties::TypeProperties::
IsUndefinedValue(b)) &&
(SourceTypeProperties::TypeProperties::
IsUndefinedValue(b1)) &&
(SourceTypeProperties::TypeProperties::
IsUndefinedValue(a1)))
{
// special case left top cell
}
else if (!(SourceTypeProperties::TypeProperties::
IsUndefinedValue(b)) &&
(SourceTypeProperties::TypeProperties::
IsUndefinedValue(h)))
{
ProcessRectangle(top, X - cellSize/2, Y + cellSize,
e, X - cellSize/2, Y - cellSize/2,
e, X, Y - cellSize/2,
b, X, Y + cellSize,
interval, li);
}
else if (!(SourceTypeProperties::TypeProperties::
IsUndefinedValue(b)) &&
(SourceTypeProperties::TypeProperties::
IsUndefinedValue(d)) &&
!(SourceTypeProperties::TypeProperties::
IsUndefinedValue(b1)))
{
ProcessRectangle(top, X - cellSize/2, Y + cellSize,
center, X - cellSize/2, Y + cellSize/2,
right, X, Y + cellSize/2,
b, X, Y + cellSize,
interval, li);
}
else if (!(SourceTypeProperties::TypeProperties::
IsUndefinedValue(b)) &&
!(SourceTypeProperties::TypeProperties::
IsUndefinedValue(e)) &&
(SourceTypeProperties::TypeProperties::
IsUndefinedValue(a)))
{
// special case right of undefined
ProcessRectangle(top, X - cellSize/2, Y + cellSize,
center, X - cellSize/2, Y + cellSize/2,
right, X, Y + cellSize/2,
b, X, Y + cellSize,
interval, li);
}
}
}//if e def
}// for
}// for
currentTuple++;
}
// change of tile rows
for(size_t i=0;i<last.size();i++){
last[i]->DeleteIfAllowed();
}
last = current;
current = next;
next.clear();
currentSize = current.size();
if (newLine == true)
{
next.push_back(nextElement);
newLine = false;
}
currentTuple = 0;
readNextElement = true;
}
for(size_t i=0;i<last.size();i++){
last[i]->DeleteIfAllowed();
}
li->finish();
return 0;
}
case REQUEST:
{
result.addr=li?li->getNext():0;
return result.addr?YIELD:CANCEL;
}
case CLOSE:
{
if(li){
delete li;
local.addr = 0;
}
return 0;
}
default:
{
assert(false);
}
}
return returnValue;
}
/*
declaration of contourFuns array
*/
ValueMapping contourFuns[] =
{
contourFun<raster2::sint>,
contourFun<raster2::sreal>,
contourFunTile<TileAlgebra::tint, TileAlgebra::tProperties<int> >,
contourFunTile<TileAlgebra::treal, TileAlgebra::tProperties<double> >,
0
};
/*
Value Mapping
*/
int contourSelectFun(ListExpr args)
{
int nSelection = -1;
NList type(args);
if (type.first() == NList(raster2::sint::BasicType()))
{
return 0;
}
else if (type.first() == NList(raster2::sreal::BasicType()))
{
return 1;
}
ListExpr stream = nl->First(args);
NList list = nl->Second(nl->First(nl->Second(nl->Second(stream))));
if (list == TileAlgebra::tint::BasicType())
{
return 2;
}
if (list == TileAlgebra::treal::BasicType())
{
return 3;
}
return nSelection;
}
/*
Type Mapping
*/
ListExpr contourTypeMap(ListExpr args)
{
string error = "Expecting an sint, sreal or a stream of "
"tint or treal and an integer (interval).";
NList type(args);
ListExpr attrList=nl->TheEmptyList();
ListExpr attr1 = nl->TwoElemList( nl->SymbolAtom("Height"),
nl->SymbolAtom(CcInt::BasicType()));
ListExpr attr2 = nl->TwoElemList( nl->SymbolAtom("Contour"),
nl->SymbolAtom(LineType::BasicType()));
attrList = nl->TwoElemList( attr1, attr2 );
if(type.length() != 2)
{
return NList::typeError("two arguments required");
}
if ((type == NList(raster2::sint::BasicType(), CcInt::BasicType())) ||
(type == NList(raster2::sreal::BasicType(), CcInt::BasicType())))
{
return nl->TwoElemList(nl->SymbolAtom(Stream<Tuple>::BasicType()),
nl->TwoElemList(nl->SymbolAtom(Tuple::BasicType()),
attrList));
}
ListExpr stream = nl->First(args);
NList attr = nl->Second(args);
if(!listutils::isTupleStream(stream))
{
return listutils::typeError(error);
}
NList list = nl->Second(nl->First(nl->Second(nl->Second(stream))));
if((list == TileAlgebra::tint::BasicType() && attr == CcInt::BasicType()) ||
(list == TileAlgebra::treal::BasicType() && attr == CcInt::BasicType()))
{
return nl->TwoElemList(nl->SymbolAtom(Stream<Tuple>::BasicType()),
nl->TwoElemList(nl->SymbolAtom(Tuple::BasicType()),
attrList));
}
return listutils::typeError(error);
}
/*
Method ProcessRectangle returns true if processing was successful
Parameters: values and coordinates of four points, the wanted interval,
the minimum value and DbArray ResultInfo to store the found
segments
*/
template<class LI>
bool ProcessRectangle(double a, double aX, double aY,
double g, double gX, double gY,
double i, double iX, double iY,
double c, double cX, double cY,
int interval,
LI* li)
{
// calculate minimum and maximum
double Min = MIN(MIN(a,c),MIN(g,i));
double Max = MAX(MAX(a,c),MAX(g,i));
int startLevel = (int) floor(Min / interval);
int endLevel = (int) ceil(Max / interval);
// calculate intersection
for(int iLevel = startLevel; iLevel <= endLevel; iLevel++)
{
int level = iLevel * interval;
int nPoints = 0;
int nPoints1 = 0, nPoints2 = 0, nPoints3 = 0;
double pointsX[4], pointsY[4];
Intersect( a, aX, aY, g, gX, gY, i,
level, &nPoints, pointsX, pointsY );
nPoints1 = nPoints;
Intersect( g, gX, gY, i, iX, iY, c,
level, &nPoints, pointsX, pointsY );
nPoints2 = nPoints;
Intersect( i, iX, iY, c, cX, cY, a,
level, &nPoints, pointsX, pointsY );
nPoints3 = nPoints;
Intersect( c, cX, cY, a, aX, aY, g,
level, &nPoints, pointsX, pointsY );
if( nPoints == 2 )
{
// left and bottom
if ( nPoints1 == 1 && nPoints2 == 2)
{
if ( !(g == level && i == level) )
AddSegment( level, pointsX[0], pointsY[0],
pointsX[1], pointsY[1], li);
}
// left and right
else if ( nPoints1 == 1 && nPoints3 == 2 )
{
AddSegment( level, pointsX[0], pointsY[0],
pointsX[1], pointsY[1], li);
}
// left and top
else if ( nPoints1 == 1 && nPoints == 2 )
{
AddSegment( level, pointsX[0], pointsY[0],
pointsX[1], pointsY[1], li);
}
// bottom and right
else if( nPoints2 == 1 && nPoints3 == 2)
{
if ( !(c == level && i == level) )
AddSegment( level, pointsX[0], pointsY[0],
pointsX[1], pointsY[1], li);
}
// bottom and top
else if ( nPoints2 == 1 && nPoints == 2 )
{
AddSegment( level, pointsX[0], pointsY[0],
pointsX[1], pointsY[1], li);
}
// right and top
else if ( nPoints3 == 1 && nPoints == 2 )
{
AddSegment( level, pointsX[0], pointsY[0],
pointsX[1], pointsY[1], li);
}
else
{
return false;
}
}
if( nPoints == 3 )
{
// left, bottom and right
if ( nPoints1 == 1 && nPoints2 == 2 && nPoints3 == 3 )
{
AddSegment( level, pointsX[0], pointsY[0],
pointsX[1], pointsY[1], li);
AddSegment( level, pointsX[1], pointsY[1],
pointsX[2], pointsY[2], li);
}
// left, bottom and top
else if ( nPoints1 == 1 && nPoints2 == 2 && nPoints == 3 )
{
AddSegment( level, pointsX[0], pointsY[0],
pointsX[1], pointsY[1], li);
AddSegment( level, pointsX[0], pointsY[0],
pointsX[2], pointsY[2], li);
}
// bottom, right and top
else if ( nPoints2 == 1 && nPoints3 == 2 && nPoints == 3 )
{
AddSegment( level, pointsX[0], pointsY[0],
pointsX[1], pointsY[1], li);
AddSegment( level, pointsX[1], pointsY[1],
pointsX[2], pointsY[2], li);
}
// left, right and top
else if ( nPoints1 == 1 && nPoints3 == 2 && nPoints == 3 )
{
AddSegment( level, pointsX[0], pointsY[0],
pointsX[1], pointsY[1], li);
AddSegment( level, pointsX[1], pointsY[1],
pointsX[2], pointsY[2], li);
}
}
if( nPoints == 4 )
{
if ( !(c == level && a == level) )
{
AddSegment( level, pointsX[1], pointsY[1],
pointsX[2], pointsY[2], li);
AddSegment( level, pointsX[0], pointsY[0],
pointsX[3], pointsY[3], li);
}
}
}
return false;
}
/*
Method Intersects calculates if a line between two points intersects the level
Parameters: values and coordinates of two points, value of a third point,
the level value, a pointer for a counter to store the number
of intersect and two pointer two store the point where the line is
intersected
*/
void Intersect(double val1, double val1X, double val1Y,
double val2, double val2X, double val2Y,
double val3, double level, int *pnPoints,
double *ppointsX, double *ppointsY )
{
if( val1 < level && val2 >= level )
{
double diff = (level - val1) / (val2 - val1);
ppointsX[*pnPoints] = val1X * (1.0 - diff) + val2X * diff;
ppointsY[*pnPoints] = val1Y * (1.0 - diff) + val2Y * diff;
(*pnPoints)++;
}
else if( val1 > level && val2 <= level )
{
double diff = (level - val2) / (val1 - val2);
ppointsX[*pnPoints] = val2X * (1.0 - diff) + val1X * diff;
ppointsY[*pnPoints] = val2Y * (1.0 - diff) + val1Y * diff;
(*pnPoints)++;
}
else if( val1 == level && val2 == level && val3 != level )
{
ppointsX[*pnPoints] = val2X;
ppointsY[*pnPoints] = val2Y;
(*pnPoints)++;
}
}
/*
Method AddSegment addes the found segments to the ResultInfo DbArray
Parameters: level value, coordinates of segments start and stop point,
the minimum value, the interval value and DbArray ResultInfo
to store the segments
*/
template<class LI>
void AddSegment(int l, double startX, double startY,
double endX, double endY, LI* clines)
{
Point p1(true, startX, startY);
Point p2(true, endX, endY);
clines->addSegment(l,p1,p2);
}
/*
Method GetValuesContour reads the values for 3x3 cells
parameters:
a - reference to top left cell \\
a1 - reference to top left cell + 1 \\
b - reference to top middle cell \\
b1 - reference to top middle cell + 1 \\
c - reference to top right cell \\
d - reference to middle left cell \\
f - reference to middle right cell \\
g - reference to bottom left cell \\
h - reference to bottom right cell \\
row - number of current row \\
column - number of current column \\
currentTuple - number of current tuple \\
s\_in - current tuple \\
maxX - maximum X in a tuple \\
maxY - maximum Y in a tuple \\
factorNext - if vector current and next have different start points \\
factorlast - if vector current and last have different start points \\
skipNextRow - if difference between next and current is more
than one tile \\
skipLastRow - if difference between last and current is more
than one tile \\
current - current vector \\
next - next vector \\
last - last vector \\
currentSize - size of current vector \\
nextSize - size of next vector \\
lastSize - size of last vector \\
return value: -
exceptions: -
*/
template <typename T, typename SourceTypeProperties>
void GetValuesContour(double* a, double* a1, double* b, double* b1, double* c,
double* d, double* f, double* g, double* h,
int row, int column, int currentTuple, T* s_in,
int maxX, int maxY,
int factorNext, int factorLast,
bool skipNextRow, bool skipLastRow,
vector<Tuple*> current, vector<Tuple*> next,
vector<Tuple*> last,
int currentSize, int nextSize, int lastSize)
{
Tuple* tuple_help;
T* s_in_help;
// left lower corner
if ((column == 0) && (row == 0))
{
if (currentTuple > 0)
{
tuple_help = current[currentTuple - 1];
if ((tuple_help != 0) && (tuple_help->GetNoAttributes() == 1))
{
s_in_help = static_cast<T*>(tuple_help->GetAttribute(0));
*a = s_in_help->GetValue((int[]){maxX, 1});
*a1 = s_in_help->GetValue((int[]){maxX, 2});
*d = s_in_help->GetValue((int[]){maxX, 0});
}
}
*b = s_in->GetValue((int[]){column, row + 1});
*b1 = s_in->GetValue((int[]){column, row + 2});
*c = s_in->GetValue((int[]){column + 1, row + 1});
*f = s_in->GetValue((int[]){column + 1, row});
if ((lastSize > 0) && (skipLastRow == false))
{
if ((currentTuple + factorLast > 0) &&
(currentTuple + factorLast - 1 < lastSize))
{
tuple_help = last[currentTuple - 1 + factorLast];
if ((tuple_help != 0) && (tuple_help->GetNoAttributes() == 1))
{
s_in_help = static_cast<T*>(tuple_help->GetAttribute(0));
*g = s_in_help->GetValue((int[]){maxX, maxY});
}
}
if ((currentTuple + factorLast >= 0) &&
(currentTuple + factorLast < lastSize))
{
tuple_help = last[currentTuple + factorLast];
if ((tuple_help != 0) && (tuple_help->GetNoAttributes() == 1))
{
s_in_help = static_cast<T*>(tuple_help->GetAttribute(0));
*h = s_in_help->GetValue((int[]){0, maxY});
}
}
}
}
// left upper corner - 1
else if ((column == 0) && (row == maxY - 1))
{
if ((nextSize > 0) && (skipNextRow == false))
{
if ((currentTuple + factorNext > 0) &&
(currentTuple + factorNext - 1 < nextSize))
{
tuple_help = next[currentTuple - 1 + factorNext];
if ((tuple_help != 0) && (tuple_help->GetNoAttributes() == 1))
{
s_in_help = static_cast<T*>(tuple_help->GetAttribute(0));
*a1 = s_in_help->GetValue((int[]){maxX, 0});
}
}
if ((currentTuple + factorNext >= 0) &&
(currentTuple + factorNext < nextSize))
{
tuple_help = next[currentTuple + factorNext];
if ((tuple_help != 0) && (tuple_help->GetNoAttributes() == 1))
{
s_in_help = static_cast<T*>(tuple_help->GetAttribute(0));
*b1 = s_in_help->GetValue((int[]){0, 0});
}
}
}
if (currentTuple > 0)
{
tuple_help = current[currentTuple - 1];
if ((tuple_help != 0) && (tuple_help->GetNoAttributes() == 1))
{
s_in_help = static_cast<T*>(tuple_help->GetAttribute(0));
*a = s_in_help->GetValue((int[]){maxX, maxY});
*d = s_in_help->GetValue((int[]){maxX, maxY - 1});
*g = s_in_help->GetValue((int[]){maxX, maxY - 2});
}
}
*b = s_in->GetValue((int[]){column, row + 1});
*c = s_in->GetValue((int[]){column + 1, row + 1});
*f = s_in->GetValue((int[]){column + 1, row});
*h = s_in->GetValue((int[]){column, row - 1});
}
// left upper corner
else if ((column == 0) && (row == maxY))
{
if ((nextSize > 0) && (skipNextRow == false))
{
if ((currentTuple + factorNext > 0) &&
(currentTuple + factorNext - 1 < nextSize))
{
tuple_help = next[currentTuple - 1 + factorNext];
if ((tuple_help != 0) && (tuple_help->GetNoAttributes() == 1))
{
s_in_help = static_cast<T*>(tuple_help->GetAttribute(0));
*a = s_in_help->GetValue((int[]){maxX, 0});
*a1 = s_in_help->GetValue((int[]){maxX, 1});
}
}
if ((currentTuple + factorNext >= 0) &&
(currentTuple + factorNext < nextSize))
{
tuple_help = next[currentTuple + factorNext];
if ((tuple_help != 0) && (tuple_help->GetNoAttributes() == 1))
{
s_in_help = static_cast<T*>(tuple_help->GetAttribute(0));
*b = s_in_help->GetValue((int[]){0, 0});
*b1 = s_in_help->GetValue((int[]){0, 1});
*c = s_in_help->GetValue((int[]){1, 0});
}
}
}
if (currentTuple > 0)
{
tuple_help = current[currentTuple - 1];
if ((tuple_help != 0) && (tuple_help->GetNoAttributes() == 1))
{
s_in_help = static_cast<T*>(tuple_help->GetAttribute(0));
*d = s_in_help->GetValue((int[]){maxX, maxY});
*g = s_in_help->GetValue((int[]){maxX, maxY - 1});
}
}
*f = s_in->GetValue((int[]){column + 1, row});
*h = s_in->GetValue((int[]){column, row - 1});
}
// right lower corner
else if ((column == maxX) && (row == 0))
{
*a = s_in->GetValue((int[]){column - 1, row + 1});
*a1 = s_in->GetValue((int[]){column - 1, row + 2});
*b = s_in->GetValue((int[]){column, row + 1});
*b1 = s_in->GetValue((int[]){column, row + 2});
*d = s_in->GetValue((int[]){column - 1, row});
if (currentTuple + 1 < currentSize)
{
tuple_help = current[currentTuple + 1];
if ((tuple_help != 0) && (tuple_help->GetNoAttributes() == 1))
{
s_in_help = static_cast<T*>(tuple_help->GetAttribute(0));
*c = s_in_help->GetValue((int[]){0, 1});
*f = s_in_help->GetValue((int[]){0, 0});
}
}
if ((lastSize > 0) && (skipLastRow == false))
{
if ((currentTuple + factorLast >= 0) &&
(currentTuple + factorLast < lastSize))
{
tuple_help = last[currentTuple + factorLast];
if ((tuple_help != 0) && (tuple_help->GetNoAttributes() == 1))
{
s_in_help = static_cast<T*>(tuple_help->GetAttribute(0));
*g = s_in_help->GetValue((int[]){maxX - 1, maxY});
*h = s_in_help->GetValue((int[]){maxX, maxY});
}
}
}
}
// right upper corner - 1
else if ((column == maxX) && (row == maxY - 1))
{
if ((nextSize > 0) && (skipNextRow == false))
{
if ((currentTuple + factorNext >= 0) &&
(currentTuple + factorNext < nextSize))
{
tuple_help = next[currentTuple + factorNext];
if ((tuple_help != 0) && (tuple_help->GetNoAttributes() == 1))
{
s_in_help = static_cast<T*>(tuple_help->GetAttribute(0));
*a1 = s_in_help->GetValue((int[]){maxX - 1, 0});
*b1 = s_in_help->GetValue((int[]){maxX, 0});
}
}
}
*a = s_in->GetValue((int[]){column - 1, row + 1});
*b = s_in->GetValue((int[]){column, row + 1});
*d = s_in->GetValue((int[]){column - 1, row});
*g = s_in->GetValue((int[]){column - 1, row - 1});
*h = s_in->GetValue((int[]){column, row - 1});
if (currentTuple + 1 < currentSize)
{
tuple_help = current[currentTuple + 1];
if ((tuple_help != 0) && (tuple_help->GetNoAttributes() == 1))
{
s_in_help = static_cast<T*>(tuple_help->GetAttribute(0));
*c = s_in_help->GetValue((int[]){0, maxY});
*f = s_in_help->GetValue((int[]){0, maxY - 1});
}
}
}
// right upper corner
else if ((column == maxX) && (row == maxY))
{
if ((nextSize > 0) && (skipNextRow == false))
{
if ((currentTuple + factorNext >= 0) &&
(currentTuple + factorNext < nextSize))
{
tuple_help = next[currentTuple + factorNext];
if ((tuple_help != 0) && (tuple_help->GetNoAttributes() == 1))
{
s_in_help = static_cast<T*>(tuple_help->GetAttribute(0));
*a = s_in_help->GetValue((int[]){maxX - 1, 0});
*a1 = s_in_help->GetValue((int[]){maxX - 1, 1});
*b = s_in_help->GetValue((int[]){maxX, 0});
*b1 = s_in_help->GetValue((int[]){maxX, 1});
}
}
if ((currentTuple + factorNext >= 0) &&
(currentTuple + factorNext + 1 < nextSize))
{
tuple_help = next[currentTuple + 1 + factorNext];
if ((tuple_help != 0) && (tuple_help->GetNoAttributes() == 1))
{
s_in_help = static_cast<T*>(tuple_help->GetAttribute(0));
*c = s_in_help->GetValue((int[]){0, 0});
}
}
}
*d = s_in->GetValue((int[]){column - 1, row});
*g = s_in->GetValue((int[]){column - 1, row - 1});
*h = s_in->GetValue((int[]){column, row - 1});
if (currentTuple + 1 < currentSize)
{
tuple_help = current[currentTuple + 1];
if ((tuple_help != 0) && (tuple_help->GetNoAttributes() == 1))
{
s_in_help = static_cast<T*>(tuple_help->GetAttribute(0));
*f = s_in_help->GetValue((int[]){0, maxY});
}
}
}
// left column
else if (column == 0)
{
*b = s_in->GetValue((int[]){column, row + 1});
*b1 = s_in->GetValue((int[]){column, row + 2});
*c = s_in->GetValue((int[]){column + 1, row + 1});
*f = s_in->GetValue((int[]){column + 1, row});
*h = s_in->GetValue((int[]){column, row - 1});
if (currentTuple > 0)
{
tuple_help = current[currentTuple - 1];
if ((tuple_help != 0) && (tuple_help->GetNoAttributes() == 1))
{
s_in_help = static_cast<T*>(tuple_help->GetAttribute(0));
*a = s_in_help->GetValue((int[]){maxX, row + 1});
*a1 = s_in_help->GetValue((int[]){maxX, row + 2});
*d = s_in_help->GetValue((int[]){maxX, row});
*g = s_in_help->GetValue((int[]){maxX, row - 1});
}
}
}
// lower row
else if (row == 0)
{
*a = s_in->GetValue((int[]){column - 1, row + 1});
*a1 = s_in->GetValue((int[]){column - 1, row + 2});
*b = s_in->GetValue((int[]){column, row + 1});
*b1 = s_in->GetValue((int[]){column, row + 2});
*c = s_in->GetValue((int[]){column + 1, row + 1});
*d = s_in->GetValue((int[]){column - 1, row});
*f = s_in->GetValue((int[]){column + 1, row});
if ((lastSize > 0) && (skipLastRow == false))
{
if ((currentTuple + factorLast >= 0) &&
(currentTuple + factorLast < lastSize))
{
tuple_help = last[currentTuple + factorLast];
if ((tuple_help != 0) && (tuple_help->GetNoAttributes() == 1))
{
s_in_help = static_cast<T*>(tuple_help->GetAttribute(0));
*g = s_in_help->GetValue((int[]){column - 1, maxY});
*h = s_in_help->GetValue((int[]){column, maxY});
}
}
}
}
// right column
else if (column == maxX)
{
*a = s_in->GetValue((int[]){column - 1, row + 1});
*a1 = s_in->GetValue((int[]){column - 1, row + 2});
*b = s_in->GetValue((int[]){column, row + 1});
*b1 = s_in->GetValue((int[]){column, row + 2});
*d = s_in->GetValue((int[]){column - 1, row});
*g = s_in->GetValue((int[]){column - 1, row - 1});
*h = s_in->GetValue((int[]){column, row - 1});
if (currentTuple + 1 < currentSize)
{
tuple_help = current[currentTuple + 1];
if ((tuple_help != 0) && (tuple_help->GetNoAttributes() == 1))
{
s_in_help = static_cast<T*>(tuple_help->GetAttribute(0));
*c = s_in_help->GetValue((int[]){0, row + 1});
*f = s_in_help->GetValue((int[]){0, row});
}
}
}
// upper row - 1
else if (row == maxY - 1)
{
*a = s_in->GetValue((int[]){column - 1, row + 1});
*b = s_in->GetValue((int[]){column, row + 1});
*c = s_in->GetValue((int[]){column + 1, row + 1});
*d = s_in->GetValue((int[]){column - 1, row});
*f = s_in->GetValue((int[]){column + 1, row});
*g = s_in->GetValue((int[]){column - 1, row - 1});
*h = s_in->GetValue((int[]){column, row - 1});
if ((nextSize > 0) && (skipNextRow == false))
{
if ((currentTuple + factorNext >= 0) &&
(currentTuple + factorNext < nextSize))
{
tuple_help = next[currentTuple + factorNext];
if ((tuple_help != 0) && (tuple_help->GetNoAttributes() == 1))
{
s_in_help = static_cast<T*>(tuple_help->GetAttribute(0));
*a1 = s_in_help->GetValue((int[]){column - 1, 0});
*b1 = s_in_help->GetValue((int[]){column, 0});
}
}
}
}
// upper row
else if (row == maxY)
{
*d = s_in->GetValue((int[]){column - 1, row});
*f = s_in->GetValue((int[]){column + 1, row});
*g = s_in->GetValue((int[]){column - 1, row - 1});
*h = s_in->GetValue((int[]){column, row - 1});
if ((nextSize > 0) && (skipNextRow == false))
{
if ((currentTuple + factorNext >= 0) &&
(currentTuple + factorNext < nextSize))
{
tuple_help = next[currentTuple + factorNext];
if ((tuple_help != 0) && (tuple_help->GetNoAttributes() == 1))
{
s_in_help = static_cast<T*>(tuple_help->GetAttribute(0));
*a = s_in_help->GetValue((int[]){column - 1, 0});
*a1 = s_in_help->GetValue((int[]){column - 1, 1});
*b = s_in_help->GetValue((int[]){column, 0});
*b1 = s_in_help->GetValue((int[]){column, 1});
*c = s_in_help->GetValue((int[]){column + 1, 0});
}
}
}
}
// no border cells
else
{
*a = s_in->GetValue((int[]){column - 1, row + 1});
*a1 = s_in->GetValue((int[]){column - 1, row + 2});
*b = s_in->GetValue((int[]){column, row + 1});
*b1 = s_in->GetValue((int[]){column, row + 2});
*c = s_in->GetValue((int[]){column + 1, row + 1});
*d = s_in->GetValue((int[]){column - 1, row});
*f = s_in->GetValue((int[]){column + 1, row});
*g = s_in->GetValue((int[]){column - 1, row - 1});
*h = s_in->GetValue((int[]){column, row - 1});
}
}
}