/* 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 #include /* 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; iDeleteIfAllowed(); } 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(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 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 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(used0); 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(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;ifull()){ // 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(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* h1; // heap restrictedHeap* h2; // heap fstream* f1; // file for heap overflow fstream* f2; // second file vector filebuffers; // vector of buffers size_t slots; hSegment* outputCache; size_t outPos; size_t outMax; vector 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*& 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 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 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 int contourFun(Word* args, Word& result, int message, Word& local, Supplier s) { int returnValue = FAILURE; typename T::this_type* s_in = static_cast(args[0].addr); CcInt* lines = static_cast(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 int contourFunTile(Word* args, Word& result, int message, Word& local, Supplier s) { int returnValue = FAILURE; CcInt* lines = static_cast(args[1].addr); vector current; vector last; vector 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::GetXDimensionSize(); int yDimensionSize = TileAlgebra::tProperties::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(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(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(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(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(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(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(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 (&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;iDeleteIfAllowed(); } 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;iDeleteIfAllowed(); } 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, contourFun, contourFunTile >, contourFunTile >, 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::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::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 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 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 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 current, vector next, vector 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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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}); } } }