grid.cpp

Go to the documentation of this file.
00001 //---------------------------------------------------------------------------
00002 
00003 #include <iostream>
00004 #include <fstream>
00005 #include <stdlib.h>
00006 #include <algorithm> // for sorting
00007 #include <sstream>
00008 #include <valarray>
00009 #include <time.h> // for seed of random number generator
00010 #include <math.h>
00011 #include "r250.h"
00012 #include "grid.h"
00013 //---------------------------------------------------------------------------
00014 
00016 float RandG(int, int) {return float(dr250());}
00017 
00019 bool operator<(const xyC& a, const xyC& b) // new 20051222
00020 {
00021   return a.height < b.height;
00022 };
00023 
00028 std::string itoa(int value) {
00029   
00030   enum { kMaxDigits = 35 };
00031   
00032   std::string buf;
00033   
00034   buf.reserve( kMaxDigits ); // Pre-allocate enough space.
00035   
00036   int quotient = value;
00037   
00038   // Translating number to string with base:  
00039   do {  
00040         buf += "0123456789"[ std::abs(quotient%10) ];   
00041         quotient /= 10; 
00042   } while ( quotient );
00043   
00044   // Append the negative sign for base 10  
00045   if ( value < 0) buf += '-';
00046   
00047   std::reverse( buf.begin(), buf.end() );        
00048   return buf;        
00049 }
00050 
00051 
00052 TGrid::TGrid (void)
00053 { 
00054   time_t currentTime;
00055   int seed = time(&currentTime); // seed for random number generator, should be made variable
00056 
00057   r250_init(29); // start of the random number generator
00058   
00059   clearArrays(); // set all arrays to zero in a new grid
00060 }//konstruktor
00061 //---------------------------------------------------------------------------
00062 TGrid::~TGrid ()
00063 {
00064 
00065 }//Destruktor
00066 //---------------------------------------------------------------------------
00067 
00068 void TGrid::clearArrays(void) // new 20051222
00069 {
00070   for (int x=0; x<=N; x++)
00071     for (int y=0; y<=N; y++)
00072     {
00073        CellArray[x][y]=0;
00074        CellArrayF[x][y]=0;
00075        CellArrayL[x][y]=0;
00076        CellCount[x][y].Position=0;
00077            CellCount[x][y].NCellsAll=0;
00078     }//for y
00079 }
00080 //---------------------------------------------------------------------------
00081 inline float TGrid::f3 (float delta, float x0, float x1, float x2)
00082 {
00083   return(x0+x1+x2)/3.+delta*RandG (0,1);                       //RandG (0,1);
00084 } 
00085 //---------------------------------------------------------------------------
00086 inline float TGrid::f4 (float delta, float x0, float x1, float x2, float x3)
00087 {
00088   return(x0+x1+x2+x3)/4.+delta*RandG (0,1);
00089 }
00090 //---------------------------------------------------------------------------
00091 void TGrid::createMountain (int Iterations,int Sigma,float Hurst,bool Addition)
00092 {
00093 // set the initial random corners
00094 float delta=Sigma;
00095 CellArrayF[0][0]=delta*RandG (0,1);
00096 CellArrayF[0][N]=delta*RandG (0,1);
00097 CellArrayF[N][0]=delta*RandG (0,1);
00098 CellArrayF[N][N]=delta*RandG (0,1);
00099 int D=N;
00100 int d=N/2;
00101 
00102 for (int stage=1; stage<=Iterations; stage++)
00103 {
00104   delta=delta*pow(0.5,0.5*Hurst); //going from Type I to type II
00105                                                                   //interpolate and offset points
00106   for (int x=d; x<=(N-d);x+=D)
00107         for (int y=d; y<=(N-d);y+=D)
00108           CellArrayF[x][y]=f4(delta,CellArrayF[x+d][y+d],CellArrayF[x+d][y-d],CellArrayF[x-d][y+d],CellArrayF[x-d][y-d]);
00109 
00110           //displace other points also, if needed
00111   if (Addition==true)
00112   {
00113         for (int x=0; x<=N; x+=D)
00114           for (int y=0; y<=N; y+=D)
00115                 CellArrayF[x][y]+= delta*RandG (0,1);
00116   }//if addition
00117   
00118   //going from grid type II to type I
00119   delta *= pow(0.5,0.5*Hurst);
00120   
00121   //interpolate and offset boundary grid points
00122   for (int x=d; x<=(N-d); x+=D)
00123   {
00124         CellArrayF[x][0]=f3(delta,CellArrayF[x+d][0],CellArrayF[x-d][0],CellArrayF[x][d]);
00125         CellArrayF[x][N]=f3(delta,CellArrayF[x+d][N],CellArrayF[x-d][N],CellArrayF[x][N-d]);
00126         CellArrayF[0][x]=f3(delta,CellArrayF[0][x+d],CellArrayF[0][x-d],CellArrayF[d][x]);
00127         CellArrayF[N][x]=f3(delta,CellArrayF[N][x+d],CellArrayF[N][x-d],CellArrayF[N-d][x]);
00128   }//for
00129   
00130    //interpolate and offset interior Points
00131   for (int x=d; x<=(N-d);x+=D)
00132         for (int y=D; y<=(N-d);y+=D)
00133           CellArrayF[x][y]=f4(delta,CellArrayF[x][y+d],CellArrayF[x][y-d],CellArrayF[x+d][y],CellArrayF[x-d][y]);
00134 
00135   for (int x=D; x<=(N-d);x+=D)
00136         for (int y=d; y<=(N-d);y+=D)
00137           CellArrayF[x][y]=f4(delta,CellArrayF[x][y+d],CellArrayF[x][y-d],CellArrayF[x+d][y],CellArrayF[x-d][y]);
00138   
00139   //displace other points if needed
00140   if (Addition==true)
00141   {
00142         for (int x=0; x<=N; x+=D)
00143           for (int y=0; y<=N; y+=D)
00144                 CellArrayF[x][y]+= delta*RandG (0,1);
00145 
00146         for (int x=d; x<=(N-d); x+=D)
00147           for (int y=d; y<=(N-d); y+=D)
00148                 CellArrayF[x][y]+= delta*RandG (0,1);
00149   }//if Addition
00150   D=D/2;
00151   d=d/2;
00152 }//for stage
00153 } // end createMountain
00154 
00155 //---------------------------------------------------------------------------
00156 void TGrid::createWadi (float Grad, bool Parabel)
00157 {
00158   int Center=N/2;
00159   int DiffY; // distance from centre of wadi cross-section
00160   float gradient = Grad?tan(Grad/360.*2*3.14159):0.0; // transformation of degrees to rad and to a slope angle defined in terms of the length of the adjacent leg (Ankathete) ; new 20061016
00161   
00162   if (Parabel==false)
00163   {
00164         for (int x=0;x<=N;x++)
00165           for (int y=0;y<=N;y++)
00166           {
00167                 DiffY = Center-y;  // distance from centre of wadi cross-section
00168 
00169                 /*== create a V-shaped curve with adjustable minimum ==*/
00170                 CellArrayL [x][y]= (-gradient*26 + abs(DiffY)*gradient)*5; // setting elevation (m)             
00171                 if (abs(DiffY)<=25) // cut the V-curve at zero
00172                 { CellArrayL [x][y]=0.0;
00173                   CellCount [x][y].Position='W';// set Wadi habitat
00174                 }
00175                 if (Grad)
00176                 {               
00177                   if (CellArrayL [x][y]>=100)   
00178                   {   CellArrayL [x][y] =100;   // cut the V-curve at 100 m
00179                         CellCount [x][y].Position='P';//set Plateau habitat
00180                   }
00181                   if (DiffY>25 && CellArrayL [x][y]<100) CellCount [x][y].Position='N';//set North facing habitat
00182                   if (DiffY<-25 && CellArrayL [x][y]<100) CellCount [x][y].Position='S';//set South facing habitat
00183                 }
00184                 else // zero degrees, flat landscape; corrected 20061031
00185                 {
00186                   if (DiffY>133) CellCount [x][y].Position='P'; // set plateau habitat
00187                   else if (DiffY>25) CellCount [x][y].Position='N';// set North facing slope habitat
00188                   else if (DiffY>=-25) CellCount [x][y].Position='W'; // set Wadi habitat
00189                   else if (DiffY>-134) CellCount [x][y].Position='S';//set South facing slope habitat
00190                   else CellCount [x][y].Position='P'; // set plateau habitat
00191                 }
00192           }//for y
00193 
00194         /*== smoothe the edges of the wadiscape parallel to cross-section with a moving average ==*/
00195         float* MemArrayL = new float [(N+1)*(N+1)]; // temporary grid for smoothed elevation; new 20051222
00196         int smoother = 10; // length of moving average window
00197         float counter = 0.0; // changed 20060111
00198 
00199         for (int x=0;x<=N;x++) // go parallel to cross-section
00200           for (int y=smoother;y<=N-smoother;y++) // changed 20060110
00201           {
00202                 // add elevation in moving average window
00203                 counter=0;
00204                 for (int iz=-smoother; iz<=smoother; iz++)
00205                   counter+= CellArrayL[x][y+iz];
00206                 
00207                 // put average into temporary grid
00208         MemArrayL[x*(N+1)+y] = (1.0/(2.0*smoother+1.0))*counter;          
00209           }  //for x, y
00210                 
00211         for (int x=0;x<=N;x++)
00212           for (int y=smoother;y<=N-smoother;y++) // changed 20060110
00213                 CellArrayL[x][y]=MemArrayL[x*(N+1)+y]; // copy back the values
00214         
00215         delete(MemArrayL); // new 20051222
00216   }//if not parabola
00217   
00218   /*== create a wadi with parabolic cross section ==*/
00219   else if (Parabel==true)
00220   {
00221     for (int x=0;x<=N;x++)
00222       for (int y=0;y<=N;y++)
00223       {
00224                 DiffY = Center == y ? 1 : Center - y;
00225                 CellArrayL [x][y]=(gradient/-100.0)*(DiffY*DiffY);
00226       }//for x,y
00227   }// else if parabola
00228         
00229 }//createWadi
00230 
00231 
00232 //---------------------------------------------------------------------------
00233 void TGrid::calculateElevation ()
00234 {
00235   /*== add the elevation of all cells ==*/
00236   float sum_elevation = 0.0;
00237   for(int i = N/2-150; i<N/2+150; i++)
00238         for(int j = N/2-150; j<N/2+150; j++)
00239           sum_elevation += CellArrayF [i][j];
00240           
00241   /*== subtract the mean elevation from each cell's elevation ==*/
00242           for(int i = 0; i<=N; i++)
00243                 for(int j = 0; j<=N; j++)
00244                   CellArrayF [i][j] -= sum_elevation/float(300*300); // changed 20070215
00245 
00246   /*== drape fractal landscape over wadi landscape ==*/
00247   for (int i=0;i<=N;i++)
00248     for (int j=0;j<=N;j++)
00249           CellArray [i][j] = CellArrayL [i][j] + CellArrayF [i][j]; // The relation of fractal to wadi elevation could be changed here.   
00250   
00251   /*== smoothe wadiscape in 2 dimensions; new 20060110 ==*/
00252   float* MemArray = new float [(N+1)*(N+1)]; // temporary grid for smoothed elevation; new 20051222 
00253   int smoother = 2; // length of moving average window
00254   float counter; // changed 20060111
00255    
00256   for (int x=0; x<=N;x++)  // changed 20060110
00257     for (int y=0; y<=N;y++)  // changed 20060110
00258     {
00259           int a=0;
00260           // add elevation in moving average window
00261           counter=0; // reset
00262           for (int iz = -smoother; iz<= smoother; iz++) 
00263                 for (int is = -smoother; is<= smoother; is++)
00264           counter += CellArray[x+is][y+iz];
00265                   
00266           // put average into temporary grid
00267           MemArray[x*(N+1)+y]=(1.0/((2.0*smoother+1.0)*(2.0*smoother+1.0)))*counter; // new 20051222
00268   }  //for x, y
00269   
00270   for (int x=smoother;x<=N-smoother;x++) // changed 20060110
00271     for (int y=smoother;y<=N-smoother;y++) // changed 20060110
00272           CellArray[x][y]=MemArray[x*(N+1)+y];  // copy back the values
00273   
00274   delete MemArray; // new 20060110 
00275   
00276 }//calculateElevation ()
00277 
00278 //---------------------------------------------------------------------------
00279 // neu 20051222
00280 float flowinfo::getTotalContributing (flowinfo* receivingCell)
00281 { 
00282   if (checked == false)
00283   {
00284         for (int c=0; c<contributing; c++) // from all contributing cells
00285           if (receivingCell != nbsFrom[c])
00286                 total += nbsFrom[c]->getTotalContributing(this); // get their number of contributing cells
00287         checked = true;
00288   }
00289   return total*share;
00290 }
00291 
00292 //---------------------------------------------------------------------------
00293 // neu 20051206
00294 void flowinfo::setInflow (flowinfo* pCell)
00295 {  nbsFrom[contributing++] = pCell;
00296 }
00297 
00298 //---------------------------------------------------------------------------
00299 void TGrid::countHigherCellsGIS (void) // neu 20051222
00300 {
00301   /*== max. variation to add to neighbour cells with the same height ==*/
00302   // find out the lowest and highest point
00303   float maxHeight = CellArray[N/2][N/2]; // new 20051222
00304   float minHeight = CellArray[N/2][N/2]; // new 20051222
00305   for (int x=0; x<=N; x++)
00306         for (int y=0; y<=N; y++)
00307         {       
00308           maxHeight = CellArray[x][y]>maxHeight?CellArray[x][y]:maxHeight;
00309           minHeight = CellArray[x][y]<minHeight?CellArray[x][y]:minHeight;
00310         }
00311   
00312   const float smalldiff = (maxHeight-minHeight)/100.0; // changed 20051222
00313   
00314 
00315   /*== determine flow accumulation ==*/
00316   for (int x=0; x<=N; x++)
00317         for (int y=0; y<=N; y++)
00318         {       
00319           float a[8]; // angle from top of centre cell to top of each nb cell; water is assumed to flow down to the cell with the greatest negative angle.
00320           int nnbs = 0; // ID of neighbours
00321           flowinfo* myCell[8]; // addresses of neighbours
00322           
00324           for (int i=-1; i<=1; i++)
00325                 for (int j=-1; j<=1; j++)
00326                 { if (x+i < 0 || x+i > N) // avoid edge
00327                         continue;
00328                   if ( y+j < 0 || y+j > N) // avoid edge
00329                         continue;
00330                   if (!i && !j) // exempt self
00331                         continue;
00332                   
00333                   /* if direct neighbour cells have the same height, add a little variation to avoid endless loops in the recursive function getTotalContributing. */
00334 //                if (CellArray[x+i][y+j] == CellArray[x][y])
00335 //                      CellArray[x][y] += (RandG(0,1)-0.5)*2.0*smalldiff;
00336                   
00337                   // calculate angle in triangle
00338                   float ak = CellArray[x+i][y+j]-CellArray[x][y]; // adjacent leg (Ankathete)
00339                   float gk = sqrt(i*i + j*j); // opposite leg (Gegenkathete)
00340                   if (ak) a[nnbs] = atan(gk/ak); // remember all angles
00341                   else a[nnbs] = -3.14159/2.0; // same elevation, set a[] to zero; this case should never occur because I add a smalldiff when two neighbouring cells have the same elevation (see above)
00342                   myCell[nnbs] = &dir[x+i][y+j]; // store addresses of info of each nb
00343 
00344                   nnbs++; // count neighbours - important at edges
00345                 } // end for i,j
00346                   
00348                 float aMin = 0; // -90∞
00349                 int ties=-1; 
00350                 flowinfo* nbsTo[4]; // store info about nbs, there can be no more than 4 nbs with the same angle
00351                 for (int n=0; n<nnbs; n++) // look for smallest angle downwards
00352                 { if (a[n]<aMin) // if downward and greater than current steepest angle; changed 20070215
00353                   { aMin=a[n];  
00354                         ties=0; // if a steeper angle was found, start over at index zero
00355                         nbsTo[ties] = myCell[n]; // nbsTo contains the addresses of cells where water flows to
00356                   } // split flow if two or more nb cells have the same distance and height
00357                   else if (a[n] == aMin)
00358                   { ties++;
00359                         nbsTo[ties] = myCell[n]; // store in tiesMem the addresses of cells where water flows to
00360                   }
00361                 } // end for n
00362                 
00363                 
00364                 for (int t=0; t<ties+1; t++)                    
00365                   if (nbsTo[t] != &dir[x][y]) // exclude self
00366                    nbsTo[t]->setInflow(&dir[x][y]); // tell the lowest nbs where the water comes from
00367                   
00368                 if(ties>-1) dir[x][y].setShare(1.0/float(ties+1)); // if there were ties, split the water
00369   } //end for x,y
00370   
00371   /* *****************************************
00372         There were segmentation errors (SIGSEGV) when the grid was checked in the usual row-by-column way. Because getTotalContributing() is a recursive function, it could hit a very low cell and end up collecting data from 10'000+ cells. Now the whole grid is sorted by height and the contributing cells are checked from the highest to the lowest.
00373         ***************************************** */
00374   xyC* pDir = new xyC[(N+1)*(N+1)];
00375   for (int x=0; x<=N; x++)
00376         for (int y=0; y<=N; y++)
00377         {
00378           pDir[x*(N+1)+y].col = x;
00379           pDir[x*(N+1)+y].row = y;
00380           pDir[x*(N+1)+y].height = CellArray[x][y];
00381         }
00382           
00383         std::sort(pDir, pDir+(N+1)*(N+1));
00384   /******************************************/
00385  
00387   for (long w=(N+1)*(N+1)-1; w>=0; w--)
00388   { 
00389         int x = pDir[w].col; int y = pDir[w].row;
00390         float TC = dir[x][y].getTotalContributing(&dir[x][y]);
00391         CellCount [x][y].NCellsAll = TC<1.0?1.0:TC; // peaks with shared flow should be shown as one patch
00392   }
00393   delete(pDir);
00394   
00395 }
00396 
00397 
00398 //---------------------------------------------------------------------------
00399 void TGrid::outputTestVariable(void)
00400 {
00401   char* fn = "TestVariable.txt";
00402   std::ofstream Ausgabe;
00403   Ausgabe.open(fn);
00404   for (int i=0;i<=N; i++)
00405   {     for (int j=0; j<=N; j++)
00406         {
00407           Ausgabe<< CellArrayF[i][j];
00408           if (j<N)  Ausgabe  << "\t";
00409         }
00410         if (i<N)  Ausgabe << std::endl;
00411   }
00412   
00413   Ausgabe.close();
00414 }
00415 
00416 //---------------------------------------------------------------------------
00417 void TGrid::outputElevation(void)
00418 {
00419   char* fn = "Elevation.txt";
00420   std::ofstream Ausgabe;
00421   Ausgabe.open(fn);
00422   for (int i=0;i<=N; i++)
00423   {     for (int j=0; j<=N; j++)
00424   {
00425           Ausgabe<< CellArray[i][j];
00426         if (j<N)  Ausgabe  << "\t";
00427   }
00428         if (i<N)  Ausgabe << std::endl;
00429   }
00430 
00431   Ausgabe.close();
00432 }
00433 
00434 //---------------------------------------------------------------------------
00435 void TGrid::outputContributing(void)
00436 {
00437   char* fn = "Contributing.txt";
00438   std::ofstream Ausgabe;
00439   Ausgabe.open(fn);
00440   for (int i=0;i<=N; i++)
00441   {     for (int j=0; j<=N; j++)
00442   {
00443         Ausgabe << (CellCount[i][j]).NCellsAll;
00444         if (j<N)  Ausgabe  << "\t";
00445   }
00446         if (i<N)  Ausgabe << std::endl;
00447   }
00448   Ausgabe.close();
00449 }
00450 
00451 //---------------------------------------------------------------------------
00452 void TGrid::writeFile(float slope, int r)
00453 {
00454   std::string filename = "Wadiscape_slope_";
00455   std::string tag = ".txt";
00456   filename += itoa(int(slope)) ;
00457   filename += "_";
00458   filename += itoa(r);
00459   filename += tag;
00460   
00461   int center=N/2;
00462   
00463   std::ofstream DataFile;
00464   DataFile.open(filename.c_str()) ;
00465   if (!DataFile)
00466   {
00467         //ˆffnen ist gescheitert =>Fehlerbehandlung
00468         std::cerr<<"Die Ausgabedatei konnte nicht erfolgreich"
00469         " geˆffnet werden."<< std::endl;
00470         exit(0);
00471   }//if kein DataFile
00472   int xx = 150;
00473   for (int i=center-xx;i<center+xx;i++)
00474   {
00475     for (int j=center-xx;j<center+xx;j++)
00476     {
00477       DataFile<<i-(center-xx)<< "\t" << j-(center-xx)<< "\t"<< CellArray[i][j]<<"\t"; // X and Y coordinates
00478       DataFile<<CellCount[i][j].Position<<"\t"; // habitat
00479           DataFile<<CellCount[i][j].NCellsAll<<"\t"; //
00480                 DataFile<<slope; // slope angle in degrees
00481       DataFile<<"\n";
00482     }//for j
00483   }//for i
00484   DataFile.close ();
00485 
00486 }
00487 
00488 //---------------------------------------------------------------------------
00489 

Generated on Tue Mar 11 11:02:38 2008 for Wadiscape Generator by  doxygen 1.5.1