#include #include #include #include #include #define DEFAULT_NOVAL 0.0 #define ROWWISE 1 #define COLWISE 2 #define TOP2BOT -1 #define BOT2TOP 1 int iabs( int i ) { return( (i<0) ? (-i) : i ); } //========================================================================= // Zero Constructor cOgrd::cOgrd( ) { xmin = xmax = dx = 0.; nx = 0; ymin = ymax = dy = 0.; ny = 0; nnod = 0; noval = DEFAULT_NOVAL; val = NULL; } //========================================================================= // Copy constructor similar to operator = cOgrd::cOgrd( const cOgrd& grd ) { xmin=grd.xmin; xmax=grd.xmax; dx=grd.dx; nx=grd.nx; ymin=grd.ymin; ymax=grd.ymax; dy=grd.dy; ny=grd.ny; nnod=grd.nnod; noval=grd.noval; val = new double[nnod]; memcpy( val, grd.val, nnod*sizeof(double) ); } //========================================================================= cOgrd::cOgrd( double xmin0, double xmax0, int nx0, double ymin0, double ymax0, int ny0 ) { noval = DEFAULT_NOVAL; val = NULL; initialize( xmin0, xmax0, nx0, ymin0, ymax0, ny0 ); } //========================================================================= cOgrd::cOgrd( double xmin0, double xmax0, double dx0, double ymin0, double ymax0, double dy0 ) { noval = DEFAULT_NOVAL; val = NULL; initialize( xmin0, xmax0, dx0, ymin0, ymax0, dy0 ); } //========================================================================= // Destructor cOgrd::~cOgrd() { if(val) delete [] val; } //========================================================================= // Initialize with number of nodes int cOgrd::initialize( double xmin0, double xmax0, int nx0, double ymin0, double ymax0, int ny0 ) { xmin = xmin0; xmax = xmax0; nx = nx0; dx = (xmax-xmin)/(nx-1); ymin = ymin0; ymax = ymax0; ny = ny0; dy = (ymax-ymin)/(ny-1); nnod = nx*ny; if( val ) delete [] val; val = new double[nnod]; for( int l=0; l xmax ) xmax = x; if( y < ymin ) ymin = y; if( y > ymax ) ymax = y; } // Read first two lines and define if file is row- or column-wise rewind( fp ); line = 0; utlReadNextDataRecord( fp, record, &line ); sscanf( record, "%lf %lf %lf", &x0, &y0, &z ); utlReadNextDataRecord( fp, record, &line ); sscanf( record, "%lf %lf %lf", &x, &y, &z ); if( x0==x && y0!=y ) ordering = COLWISE; else if( x0!=x && y0==y ) ordering = ROWWISE; else return Err.post(Err.msgReadFile( fname, line, "Cannot recognise data ordering" )); // Define nx and ny rewind( fp ); line = 0; utlReadNextDataRecord( fp, record, &line ); sscanf( record, "%lf %lf %lf", &x0, &y0, &z ); if( ordering == ROWWISE ) { nx = 1; while( utlReadNextDataRecord( fp, record, &line ) != EOF ) { sscanf( record, "%lf %lf %lf", &x, &y, &z ); if( y != y0 ) break; nx++; } ny = nxny / nx; if( y > y0 ) ydirection = BOT2TOP; else ydirection = TOP2BOT; } else if( ordering == COLWISE ) { ny = 1; while( utlReadNextDataRecord( fp, record, &line ) != EOF ) { sscanf( record, "%lf %lf %lf", &x, &y, &z ); if( x != x0 ) break; if( ny == 1 ) { if( y > y0 ) ydirection = BOT2TOP; else ydirection = TOP2BOT; } ny++; } nx = nxny / ny; } if( nx*ny != nxny ) return Err.post( "cOgrd::readXYZ -> nx*ny != nxny" ); // Other grid parameters dx = (xmax-xmin)/(nx-1); dy = (ymax-ymin)/(ny-1); nnod = nx*ny; // Allocate memory for z-values if( val ) delete [] val; val = new double[nnod]; for( int l=0; l=0; j-- ) { for( i=0; i=0; j-- ) { utlReadNextDataRecord( fp, record, &line ); sscanf( record, "%*s %*s %lf", &val[idx(i,j)] ); } } } } fclose( fp ); return 0; } //========================================================================= // Read grid from ASCII-raster file int cOgrd::readRasterStream( FILE *fp, int ordering, int ydirection ) { int i,j; double x0,x,y0,y,z; if( ordering == ROWWISE ) { if( ydirection == BOT2TOP ) { for( j=0; j=0; j-- ) for( i=0; i=0; j-- ) if( fscanf( fp, "%lf", &val[idx(i,j)] ) != 1 ) return Err.post("Unexpected EOF"); } else return Err.post("Unexpected direction"); } else return Err.post("Unexpected Ordering"); return 0; } //========================================================================= // Cut-off a subgrid cOgrd* cOgrd::extract( int i1, int i2, int j1, int j2 ) { cOgrd *grd; if( i1 < 0 || i2 > (nx-1) || j1 < 0 || j2 > (ny-1) ) { Err.post("subGrid: bad ranges"); return NULL; } grd = new cOgrd( getX(i1,0), getX(i2,0), (i2-i1+1), getY(0,j1), getY(0,j2), (j2-j1+1) ); for( int i=i1; i<=i2; i++ ) { for( int j=j1; j<=j2; j++ ) { (*grd).setVal( getVal(i,j), (i-i1), (j-j1) ); } } return grd; } //========================================================================= // Cut-off a subgrid cOgrd* cOgrd::extract( double x1, double x2, double y1, double y2 ) { int i1,i2,j1,j2; i1 = (int)((x1-xmin)/dx); if( i1 < 0 ) i1 = 0; i2 = (int)((x2-xmin)/dx); if( i2 > (nx-1) ) i2 = nx-1; j1 = (int)((y1-ymin)/dy); if( j1 < 0 ) j1 = 0; j2 = (int)((y2-ymin)/dy); if( j2 > (ny-1) ) j2 = ny-1; return extract( i1, i2, j1, j2 ); } //========================================================================= // Total reset void cOgrd::reset() { xmin = xmax = dx = 0.; nx = 0; ymin = ymax = dy = 0.; ny = 0; nnod = 0; noval = DEFAULT_NOVAL; if( val != NULL ) delete [] val; val = NULL; } //========================================================================= // Reset values to zero void cOgrd::resetVal() { for( int l=0; l nx-1 ) i2 = nx-1; j1 = (int)((grd.ymin-ymin)/dy); if( j1 < 0 ) j1 = 0; j2 = (int)((grd.ymax-ymin)/dy) + 1; if( j2 > ny-1 ) j2 = ny-1; for( i=i1; i<=i2; i++ ) { for( j=j1; j<=j2; j++ ) { val[idx(i,j)] += grd.getVal( getX(i,j), getY(i,j) ); } } } return *this; } //========================================================================= double& cOgrd::operator() ( int i, int j ) { return( val[idx(i,j)] ); } //========================================================================= double& cOgrd::operator() ( int l ) { return( val[l] ); } //========================================================================= // Get IJ-indices from the offset void cOgrd::getIJ( int idx, int& i, int& j ) { // J is the inner loop (increments faster than I) i = idx/ny; j = idx - i*ny; } //========================================================================= // Get IJ-indices from coordinates int cOgrd::getIJ( double x, double y, int& i, int& j ) { i = (int)( (x-xmin)/(xmax-xmin)*nx ); if( i<0 || i>(nx-1) ) return -1; j = (int)( (y-ymin)/(ymax-ymin)*ny ); if( j<0 || j>(ny-1) ) return -1; return 0; } //========================================================================= // Get offset from IJ-indices int cOgrd::idx( int i, int j ) { // J is the inner loop (increments faster than I) return( int( (int)ny*i + j ) ); } //========================================================================= // Get value at given node double cOgrd::getVal( int i, int j ) { return( val[idx(i,j)] ); } //========================================================================= // Get value at given node double cOgrd::getVal( int idx ) { return( val[idx] ); } //========================================================================= // Set value at given node void cOgrd::setVal( double value, int i, int j ) { val[idx(i,j)] = value; } //========================================================================= // Set value at given node void cOgrd::setVal( double value, int idx ) { val[idx] = value; } //========================================================================= // Get maximal value on a grid double cOgrd::getMaxVal() { int l; double vmax; for( vmax=-RealMax, l=0; l vmax ) vmax = val[l]; return vmax; } //========================================================================= // Get maximal value and its position on a grid double cOgrd::getMaxVal( int& i, int& j ) { int l,lmax; double vmax; for( lmax=0,vmax=-RealMax, l=0; l vmax ) { vmax = val[l]; lmax = l; } } getIJ( lmax, i, j ); return vmax; } //========================================================================= // Get minimal value on a grid double cOgrd::getMinVal() { int l; double vmin; for( vmin=RealMax, l=0; l vmax ) vmax = fabs(val[l]); return vmax; } //========================================================================= // Get maximal absolute value and its position on a grid double cOgrd::getMaxAbsVal( int& i, int& j ) { int l,lmax; double vmax; for( lmax=0,vmax=-RealMax, l=0; l vmax ) { vmax = fabs(val[l]); lmax = l; } } getIJ( lmax, i, j ); return vmax; } //========================================================================= // Get maximal absolute value along grid boundaries double cOgrd::getMaxAbsValBnd() { int i,j; double vmax=-RealMax; for( i=0; i vmax ) vmax = fabs(val[idx(i,0)]); if( fabs(val[idx(i,ny-1)]) > vmax ) vmax = fabs(val[idx(i,ny-1)]); } for( j=0; j vmax ) vmax = fabs(val[idx(0,j)]); if( fabs(val[idx(nx-1,j)]) > vmax ) vmax = fabs(val[idx(nx-1,j)]); } return vmax; } //========================================================================= // Get value with interpolation (bi-linear) double cOgrd::getVal( double x, double y ) { int i0,j0; double fx,fy,val_l,val_r,result; i0 = (int)((x-xmin)/dx); if( i0<0 || (i0+1)>=nx ) return(noval); j0 = (int)((y-ymin)/dy); if( j0<0 || (j0+1)>=ny ) return(noval); fx = (x - (xmin+dx*i0))/dx; fy = (y - (ymin+dy*j0))/dy; val_l = (1-fy)*getVal(i0,j0) + fy*getVal(i0,j0+1); val_r = (1-fy)*getVal(i0+1,j0) + fy*getVal(i0+1,j0+1); result = (1-fx)*val_l + fx*val_r; return( result ); } //========================================================================= // Get longitude from IJ-indeces double cOgrd::getX( int i, int j ) { return( xmin + i*dx ); } //========================================================================= // Get longitude from the offset double cOgrd::getX( int idx ) { int i,j; getIJ( idx, i, j ); return( xmin + i*dx ); } //========================================================================= // Get lattitude from IJ-indeces double cOgrd::getY( int i, int j ) { return( ymin + j*dy ); } //========================================================================= // Get lattitude from the offset double cOgrd::getY( int idx ) { int i,j; getIJ( idx, i, j ); return( ymin + j*dy ); } //========================================================================= // Check if the shapes are equal int cOgrd::isSameShapeTo( cOgrd& grd ) { if( xmin != grd.xmin ) return 0; if( xmax != grd.xmax ) return 0; if( nx != grd.nx ) return 0; if( ymin != grd.ymin ) return 0; if( ymax != grd.ymax ) return 0; if( ny != grd.ny ) return 0; return 1; } //========================================================================= // INtersection region with another grid int cOgrd::getIntersectionRegion( const cOgrd &grd, int& imin, int& imax, int& jmin, int& jmax ) { if( xmin < grd.xmin ) { if( xmax < grd.xmin ) return -1; imin = (int)((grd.xmin-xmin)/dx); } else if( xmin <= grd.xmax ) { imin = 0; } else return -1; if( xmax < grd.xmin ) return -1; else if( xmax <= grd.xmax ) { imax = nx-1; } else { imax = (int)((grd.xmax-xmin)/dx); } if( ymin < grd.ymin ) { if( ymax < grd.ymin ) return -1; jmin = (int)((grd.ymin-ymin)/dy); } else if( ymin <= grd.ymax ) { jmin = 0; } else return -1; if( ymax < grd.ymin ) return -1; else if( ymax <= grd.ymax ) { jmax = ny-1; } else { jmax = (int)((grd.ymax-ymin)/dy); } return 0; } //========================================================================= // Interpolate grid values from another O-grid (bi-linear) int cOgrd::interpolateFrom( cOgrd &grd, int resetValues ) { int ierr,imin,imax,jmin,jmax; double value; if( resetValues ) resetVal(); ierr = getIntersectionRegion( grd, imin, imax, jmin, jmax ); if(ierr) return 0; for( int i=imin; i<=imax; i++ ) { for( int j=jmin; j<=jmax; j++ ) { value = grd.getVal( getX(i,j), getY(i,j) ); if( value != grd.noval ) val[idx(i,j)] = value; } } return( 0 ); } //========================================================================= // Get nearest node int cOgrd::getNearestIdx( double x0, double y0 ) { int i0,j0; int l,lmin; double dist2,dist2min; if( x0xmax || y0ymax ) return -1; i0 = (int)((x0-xmin)/dx); j0 = (int)((y0-ymin)/dy); l = idx(i0,j0); dist2min = (x0-getX(l))*(x0-getX(l)) + (y0-getY(l))*(y0-getY(l)); lmin = l; l = idx(i0+1,j0); dist2 = (x0-getX(l))*(x0-getX(l)) + (y0-getY(l))*(y0-getY(l)); if( dist2 < dist2min ) { dist2min = dist2; lmin = l; } l = idx(i0,j0+1); dist2 = (x0-getX(l))*(x0-getX(l)) + (y0-getY(l))*(y0-getY(l)); if( dist2 < dist2min ) { dist2min = dist2; lmin = l; } l = idx(i0+1,j0+1); dist2 = (x0-getX(l))*(x0-getX(l)) + (y0-getY(l))*(y0-getY(l)); if( dist2 < dist2min ) { dist2min = dist2; lmin = l; } return lmin; } //========================================================================= // Get nearest conditioned node int cOgrd::getNearestIdx( double x0, double y0, double rangemin, double rangemax ) { int i,j,i0,j0,rad; int l,lmin; double dist2,dist2min; lmin = getNearestIdx( x0, y0 ); if( lmin == -1 ) return lmin; if( val[lmin] >= rangemin && val[lmin] <= rangemax ) return lmin; getIJ( lmin, i0,j0 ); for( lmin=-1,rad=1; radnx-1 || j<0 || j>ny-1 ) continue; l = idx(i,j); if( val[l] < rangemin || val[l] > rangemax ) continue; dist2 = (x0-getX(l))*(x0-getX(l)) + (y0-getY(l))*(y0-getY(l)); if( dist2 < dist2min ) { dist2min = dist2; lmin = l; } } if( lmin > 0 ) break; } return lmin; } //========================================================================= // Smooth data on grid void cOgrd::smooth( int radius ) { int i,j,k,ik,jk; int l; double sumwt; double wt[10] = { 1.0, 0.5, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25 }; if( radius == 0 ) return; cOgrd tmp( *this ); for( i=0; i=nx ) continue; for( jk=j-k; jk<=j+k; jk++ ) { if( jk<0 || jk>=ny ) continue; if( iabs(ik-i)==k || iabs(jk-j)==k ) { tmp(l) += wt[k] * ((*this)(ik,jk)); sumwt += wt[k]; } } } } tmp(l) /= sumwt; } } *this = tmp; } //========================================================================= // write to GRD-file int cOgrd::writeGRD( const char *fname ) { FILE *fp; int i,j,cnt; fp = fopen( fname, "wt" ); fprintf( fp, "DSAA\n" ); fprintf( fp, "%d %d\n", nx, ny ); fprintf( fp, "%f %f\n", xmin, xmax ); fprintf( fp, "%f %f\n", ymin, ymax ); fprintf( fp, "%f %f\n", getMinVal(), getMaxVal() ); for( cnt=0, j=0; j