sandbox/nlemoine/esri-binary-grids.h
output_flt(): ESRI Binary Float Grid (.FLT,.HDR) format
The Esri Binary Float Grid format consists of 2 files: a binary .FLT image file and ASCII .HDR header file with the same file name but different file extension. For example, Test.FLT and Test.HDR.
The arguments are:
- f
- a scalar field (compulsory).
- file
- an array of char, path to the output file (with .FLT extension)
- \Delta
- size of a grid element. Default is 1/N.
- linear
- whether to use bilinear or first-order interpolation. Default is first-order.
- box
- the lower-left and upper-right coordinates of the domain to consider. Default is the entire domain.
- mask
- if set, this field will be used to mask out, the regions of the domain for which mask is negative.
struct OutputFLT {
scalar f;
char * file;
double Delta;
bool linear;
double box[2][2];
scalar mask;
};
trace
int output_flt (struct OutputFLT p)
{
FILE * flt , * hdr ;
scalar input = p.f;
char * pch;
char buffer[100];
double * data_double;
char hdrfile[200];
// default values
if (p.box[0][0] == 0. && p.box[0][1] == 0. &&
p.box[1][0] == 0. && p.box[1][1] == 0.) {
p.box[0][0] = X0; p.box[0][1] = Y0;
p.box[1][0] = X0 + L0; p.box[1][1] = Y0 + L0;
if (p.Delta == 0) p.Delta = L0/N;
}
double Delta = p.Delta;
int nx = (p.box[1][0] - p.box[0][0])/Delta;
int ny = (p.box[1][1] - p.box[0][1])/Delta;
data_double = (double *)malloc(nx*ny*sizeof(double));
for(int i=0;i<(nx*ny);i++)
data_double[i] = nodata;
// data
for (int j = ny-1; j >= 0; j--) {
double yp = Delta*j + p.box[0][1] + Delta/2.; // center of pixel
for (int i = 0; i < nx; i++) {
double xp = Delta*i + p.box[0][0] + Delta/2., v;
float vf;
if (p.mask.i) { // masking
if (p.linear) {
double m = interpolate (p.mask, xp, yp);
if (m < 0.)
v = nodata;
else
v = interpolate (p.f, xp, yp);
}
else {
Point point = locate (xp, yp);
if (point.level < 0 || val(p.mask) < 0.)
v = nodata;
else
v = val(p.f);
}
}
else if (p.linear)
v = interpolate (p.f, xp, yp);
else {
Point point = locate (xp, yp);
v = point.level >= 0 ? val(p.f) : nodata;
}
if (v == nodata)
data_double[i+(ny-1-j)*nx] = -9999.;
else
data_double[i+(ny-1-j)*nx] = v;
}
}
if (pid() == 0) { // master writes .FLT and .HDR files
@if _MPI
MPI_Reduce (MPI_IN_PLACE, data_double, nx*ny, MPI_DOUBLE, MPI_MAX, 0,
MPI_COMM_WORLD);
@endif
// Set path to header file
// hdrfile = (char *)malloc(sizeof(char)*strlen(p.file));
strcpy(hdrfile,p.file);
pch = hdrfile + strlen(hdrfile)-3;
// strncpy (pch,"hdr",3);
memcpy (pch,"hdr",3);
if(!(hdr = fopen (hdrfile, "w")))
{
printf("Failed to open header file %s\n",hdrfile);
return -1;
}
// header
fprintf (hdr, "ncols %d\n", nx);
fprintf (hdr, "nrows %d\n", ny);
fprintf (hdr, "xllcorner %.8g\n", p.box[0][0]);
fprintf (hdr, "yllcorner %.8g\n", p.box[0][1]);
fprintf (hdr, "cellsize %.8g\n", Delta);
fprintf (hdr, "nodata_value -9999\n");
fprintf (hdr, "byteorder LSBFIRST\n");
fflush(hdr);
fclose(hdr);
// free(hdrfile);
// open flt file
bool opened = false;
if( !(flt = fopen (p.file, "wb")) ) {
perror (p.file);
exit(1);
}
else
opened = true;
for(int i=0;i<(nx*ny);i++)
{
float vf = (float)data_double[i];
fwrite(&vf,1,sizeof(float),flt);
}
fclose(flt);
}
@if _MPI
else // slave does not write anything
MPI_Reduce (data_double, NULL, nx*ny, MPI_DOUBLE, MPI_MAX, 0,
MPI_COMM_WORLD);
@endif
free(data_double);
return(0);
}
int SYSTEM_IS_LITTLE_ENDIAN(void)
{
// First, we declare a 16-bit integer (short int), which has the value 0x0001
short int word = 0x0001;
// then we get a pointer and dereference it
char *b = (char *)&word;
// If the LSB is stored at lower address (e.g. the value that pointer points to), then system is LSBFIRST i.e. Litte Endian
return (b[0] ? 1 : 0);
}
float ReverseFloat( float inFloat )
{
float retVal;
char *floatToConvert = ( char* ) & inFloat;
char *returnFloat = ( char* ) & retVal;
// swap the bytes into a temporary buffer
returnFloat[0] = floatToConvert[3];
returnFloat[1] = floatToConvert[2];
returnFloat[2] = floatToConvert[1];
returnFloat[3] = floatToConvert[0];
return retVal;
}
void lower_string(char s[]) {
int c = 0;
while (s[c] != '\0') {
if (s[c] >= 'A' && s[c] <= 'Z') {
s[c] = s[c] + 32;
}
c++;
}
}
input_flt(): ESRI Binary Float Grid (.FLT,.HDR) format
The Esri Binary Float Grid format consists of 2 files: a binary .FLT image file and ASCII .HDR header file with the same file name but different file extension. For example, Test.FLT and Test.HDR. http://surferhelp.goldensoftware.com/subsys/subsys_ESRI_binary_float_grid_file_descr.htm This is the reciprocal function of output_flt().
The arguments and their default values are:
- s
- the scalar where the data will be stored. No default value. You must specify this parameter
- file
- the name of the file to read from. The path to the header file is assumed to be the same as the binary file with the extension “.hdr”
- nodatavalue
- the value of the NoDataValue. Default is the same as that defined in the raster file.
- linear
- if true, the raster data is bilinearly interpolated. Default is false.
struct InputFLT {
scalar s;
char * file;
double nodatavalue;
bool linear;
};
int input_flt (struct InputFLT p)
{
FILE * flt , * hdr ;
scalar input = p.s;
char * hdrfile, * pch;
char buffer[100];
double DeltaGRD;
int nx, ny,i,j;
double XG0, YG0, ndv,center,dx,dy;
bool lsbfirst,reverse_bytes;
float f;
// Get path to header file
hdrfile = (char *)malloc(sizeof(char)*strlen(p.file));
strcpy(hdrfile,p.file);
pch = hdrfile + strlen(hdrfile)-3;
strncpy (pch,"hdr",3);
if(!(hdr = fopen (hdrfile, "r")))
{
printf("Failed to open header file %s\n",hdrfile);
return -1;
}
// Parse header file
while(fscanf(hdr,"%s",buffer)!=EOF)
{
lower_string(buffer);
if(!(strcmp(buffer,"ncols")))
fscanf(hdr,"%d",& nx);
if(!(strcmp(buffer,"nrows")))
fscanf(hdr,"%d",& ny);
if(!(strcmp(buffer,"cellsize")))
fscanf(hdr,"%lf",& DeltaGRD);
if(!(strcmp(buffer,"xllcenter")))
{
fscanf(hdr,"%lf",& XG0);
center=1.0;
}
if(!(strcmp(buffer,"yllcenter")))
{
fscanf(hdr,"%lf",& YG0);
center=1.0;
}
if(!(strcmp(buffer,"xllcorner")))
{
fscanf(hdr,"%lf",& XG0);
center=0.0;
}
if(!(strcmp(buffer,"yllcorner")))
{
fscanf(hdr,"%lf",& YG0);
center=0.0;
}
if(!(strcmp(buffer,"nodata_value")))
fscanf(hdr,"%lf",& ndv);
if(!(strcmp(buffer,"byteorder")))
{
fscanf(hdr,"%s",buffer);
lower_string(buffer);
lsbfirst = !strcmp(buffer,"lsbfirst");
}
}
XG0 -= 0.5*DeltaGRD*center;
YG0 -= 0.5*DeltaGRD*center;
fclose(hdr);
bool opened = false;
if( !(flt = fopen (p.file, "rb")) ) {
perror (p.file);
exit(1);
}
else
opened = true;
//default value of NoData value
if (!p.nodatavalue)
p.nodatavalue = ndv;
// Allocation of pointers to columns' start (size : nx)
double ** value ;
if( !(value = (double **) malloc(nx*sizeof(double *)) ) )
return(-1);
// Allocation of each column (each of size ny)
for(i=0;i<nx;i++)
{
if ( !(value[i] = (double *) malloc(ny*sizeof(double)) ) )
return(-1);
}
// read the data (float to double conversion and byte reverse if necessary)
if ( ( lsbfirst && !SYSTEM_IS_LITTLE_ENDIAN() ) |
( !lsbfirst && SYSTEM_IS_LITTLE_ENDIAN() ) )
reverse_bytes = true;
else
reverse_bytes = false;
for(j = ny-1; j >= 0; j--){
for(i = 0 ; i < nx; i++){
fread(&f,sizeof(float),1,flt);
if (reverse_bytes)
f = ReverseFloat(f);
value[i][j] = f ;
}}
printf(" %d values read\n",nx*ny);
double LGx0 = nx*DeltaGRD;
double LGy0 = ny*DeltaGRD;
bool warning = false;
bool internal,incl;
double val;
double onehalf=1./2.;
double xllcenter = XG0+DeltaGRD/2., yllcenter = YG0+DeltaGRD/2.;
foreach() {
dx = (x - xllcenter)/DeltaGRD ; // relative offset in x w.r.t. center of LL pixel
i = (int)floor(dx);
dy = (y - yllcenter)/DeltaGRD ; // relative offset in y w.r.t. center of LL pixel
j = (int)floor(dy);
internal = (i >= 0 &&
i < nx-1 &&
j >= 0 &&
j < ny-1 );
if (p.linear && internal ) { // bi-linear interpolation
dx -= i;
dy -= j;
val = (1.-dx)*(1.-dy)*value[i][j]
+ dx*(1.-dy)*value[i+1][j]
+ (1.-dx)*dy*value[i][j+1]
+ dx*dy*value[i+1][j+1];
}
else {
// Test if the point in the Basilisk area is included in the raster area
incl = (x >= XG0 &&
x <= XG0 + LGx0 &&
y >= YG0 &&
y <= YG0 + LGy0 );
if(incl) {
// snap relative offsets dx and dy to nearest integers
i = (int)(dx+onehalf);
j = (int)(dy+onehalf);
val = value[i][j];
}
else {
val = p.nodatavalue;
warning = true;
}
}
input[] = val ;
}
// Deallocation of each column
for(i=0;i<nx;i++)
free(value[i]);
// Deallocation of pointers to columns' start
free(value);
free(hdrfile);
if (warning)
fprintf (stderr,
"input_flt(): Warning: Raster data is not covering all"
" the simulation area\n");
fclose (flt);
return(0);
}