/* smooth.c:  read matlab file, smooth data, write results  */
/* JPB  '95  */

#include <stdio.h>
#include <stdlib.h>             /* ansi malloc */
#include <math.h>
#include <string.h>

#define NUM_FMT 0       /* 0 IEEE Little Endian (80x86, DEC Risc) */
			/* 1 IEEE Big Endian (SPARC, SGI, Motorola, etc.) */
#define PREC 1          /* storing Matlab file as floats rather than longs */
#define PTYPE float     /* internal representation of float numbers */

#define Eh(vv, xq, yq)  vv[((yq) * (xsize+2)) + xq]  /* elmt of hf array */
#define Ehn(vv, xq, yq) vv[((yq+1)*(xsize+2))+(xq+1)] /* hf indexed like ua */
#define El(vv, xq, yq)  vv[((yq) * xsize) + xq]  /* elmt of array */

			/* Matlab Level 1.0 format data file header */
typedef struct {
	long type;      /* type */
	long mrows;     /* row dimension */
	long ncols;     /* column dimension */
	long imagf;     /* flag indicating imag part */
	long namelen;    /* name length (including NULL) */
} Fmatrix;

int write_mfile(char *f, char *p);     /* write out matrix as matlab file */
int read_mfile(char *f);               /* read in matlab file to matrix */
void smooth();                         /* write smoothed pr into pr2 */

static Fmatrix x;                       /* matlab-format file header */
static PTYPE *pr, *pr2;                 /* pointer to real data */
static int xsize, ysize;                /* size of input data array */
static int x4[4] =                      /* 4-dir index offset arr */
   { -1,0,1,0 };
static int y4[4] =
   { 0,-1,0,1 };


int main()
{
  char fname[80] = "input.dat";
  int i,j,ii,mn,passes;

  printf("\nEnter input file name:");
  scanf("%s",fname);
  printf("\nEnter number of passes:");
  scanf("%d",&passes);

  read_mfile(fname);                  /* read in the data */

  for (j=1;j<ysize+1;j++) {     /* fill in L+R edges */
   Eh(pr,0,j) = Eh(pr,1,j);
   Eh(pr,xsize+1,j) = Eh(pr,xsize,j);
  }
  for (i=0;i<xsize+2;i++) {     /* fill in T+B edges */
   Eh(pr,i,0) = Eh(pr,i,1);
   Eh(pr,i,ysize+1) = Eh(pr,i,ysize);
  }

  printf("Data array read:\n");
  if (xsize*ysize < 100) {
  for (j=0;j<ysize+2;j++) {
   for (i=0;i<xsize+2;i++) {
    printf("%3.1f ",Eh(pr,i,j));
   }
   printf("\n");
  } /* end for j */
  } /* end if */

  mn = (xsize+2) * (ysize+2);   /* allocate new matrix */
  if ((pr2 = (PTYPE *) malloc(mn*sizeof(PTYPE)) ) == NULL) {
     perror("Could not allocate memory for input array.\n");
     exit(1);
   }

  for (ii=0;ii<passes;ii++) {
    printf("%d.",ii);
    fflush(stdout);
    smooth();
    for (j=0;j<ysize;j++) {     /* copy middle of pr2 into pr */
     for (i=0;i<xsize;i++) {
      Ehn(pr,i,j) = Ehn(pr2,i,j);
     } /* end for i */
    } /* end for j */
  } /* end for ii */
  printf("\n");


  printf("Data array avgd.:\n");
  if (xsize*ysize < 100) {
   for (j=0;j<ysize+2;j++) {
    for (i=0;i<xsize+2;i++) {
     printf("%3.1f ",Eh(pr,i,j));
    }
    printf("\n");
   } /* end for j */
  }

  printf("\nEnter output file name:");
  scanf("%s",fname);

  write_mfile(fname,"data1");                 /* write data out */

 return(0);
} /* end */

/* -------------------------------------------------------------- */
/* write_mfile -- write out data matrix in Matlab Level 1.0 format */
/*               given a header structure "x" and data array "pr" */
/* -------------------------------------------------------------- */

int write_mfile(char *fname, char *pname)
{
FILE *fpout;
int rv,mn,i,j,c;

   fpout = fopen(fname,"wb");
   if (fpout == NULL)
    { perror("Error opening file.\n");
      exit(1);
    }

   x.type = NUM_FMT*1000 + PREC*10;
   rv = fwrite(&x, sizeof(Fmatrix),(size_t)1, fpout);          /* write header */
   if (rv != 1) {
     perror("Error writing file.\n");
     exit(1);
   }
   rv = fwrite(pname, sizeof(char), (size_t)x.namelen, fpout);   /* write mx name */
   if (rv != x.namelen) {
     perror("Error writing file.\n");
     exit(1);
   }
   mn = x.mrows * x.ncols;

   for (i=0;i<xsize;i++) {
      for (j=0;j<ysize;j++) {   /* format is columns saved first */

       c = fwrite(&Ehn(pr,i,j), sizeof(PTYPE), 1, fpout);
       if (c != 1) {
	 perror("Trouble writing data to file.\n");
	 exit(1);
       }
      } /* end for j */
   } /* end for i */

  if (fclose( fpout ) == EOF) {
	perror("Error closing file.\n");
	exit(1);
  }

  printf("All done with file operations.\n");
  return(0);
}

/* -------------------------------------------------------------- */
/* read_mfile --  read in data matrix in Matlab Level 1.0 format   */
/*               and put data in header "x" and data array "pr"   */
/* -------------------------------------------------------------- */

int read_mfile(char *fname)
{
  char pname[80]="dat1\x00";           /* data matrix name, null-terminated*/
  int mn;

  int a,b,c,i,j;
  int etype;
  int mtype,prec,rem,numtype;
  double tdbl;
  float tflt;
  FILE *fpin;

   /* --------- read in Matlab-format (Level 1.0) file ------- */

   etype = (NUM_FMT*1000) + (PREC*10);    /* expected data type flag */

   if ((fpin = fopen(fname,"rb")) == NULL) {
    perror("could not open file.\n");
    exit(1);
   }

   printf("Opening matlab file %s...\n",fname);

   a = fread(&x, sizeof(Fmatrix),(size_t)1, fpin);          /* read header */
    if (a != 1) {
      perror("Problem reading matlab file header.\n");
      exit(1);
    }
   numtype = (x.type % 10000)/1000;
   prec = (x.type % 100)/10;
   mtype = (x.type % 10);
   rem = (x.type - (1000*numtype + 10*prec + mtype));
   printf("Data type flag: M%d P%d T%d R%d\n",
       numtype,prec,mtype,rem);
   if ( (numtype!=0) || ((prec!=0)&&(prec!=1)) || (mtype!=0) )  {
     perror("Unsupported file format type\n");
     exit(1);
   }
   b = fread(pname, sizeof(char), (size_t)x.namelen, fpin); /* read mx name */
   xsize = x.mrows;
   ysize = x.ncols;
   printf("Array name: %s [%dx%d]\n",pname,xsize,ysize);
   mn = (x.mrows+2) * (x.ncols+2); /* size of array +1 each edge */
   if ((pr = (PTYPE *) malloc(mn*sizeof(PTYPE)) ) == NULL) {
     perror("Could not allocate memory for input array.\n");
     exit(1);
   }
   if (prec==1) {               /* read in floats 1 by 1 */
     for (i=0;i<xsize;i++) {
      for (j=0;j<ysize;j++) {   /* format is columns saved first */
       c = fread(&tflt, sizeof(float), 1, fpin);
       if (c != 1) {
	 perror("Trouble reading data from file.\n");
	 exit(1);
       }
       Ehn(pr,i,j) = (PTYPE) tflt;
      } /* end for j */
     } /* end for i */
   } else if (prec==0) {                     /* read doubles 1 by 1 and convert */

     for (i=0;i<xsize;i++) {
      for (j=0;j<ysize;j++) {   /* format is columns saved first */
       c = fread(&tdbl, sizeof(double), 1, fpin);
       if (c != 1) {
	 perror("Trouble reading data from file.\n");
	 exit(1);
       }
       Ehn(pr,i,j) = (PTYPE) tdbl;
      } /* end for j */
     } /* end for i */

   } else {
	perror("Unsupported floating-point type\n");
	exit(1);
   } /* end else */

   fclose( fpin );

  return(0);

} /* end read_mfile */

/* ------------------------------------------------------------------- */
/* smooth() -- Fill matrix pr2 with 4-neighbor average from matrix pr. */
/*             Copy edge elements of pr to pr2.                        */
/* ------------------------------------------------------------------- */

void smooth()
{
 int ix,iy,i,j;
 PTYPE sum;

  for (iy = 0; iy<ysize; iy++) {
    for (ix = 0; ix<xsize; ix++) {
      sum = 0;
      for(i=0;i<4;i++) {
	  sum += Ehn(pr,ix+x4[i],iy+y4[i]);
      }  /* end for i=1..4 */
      Ehn(pr2,ix,iy) = sum / 4;   /* replace element with avg. of neighbors */
    }  /* end for x=1..xsize-1 */
  } /* end for y=1..ysize-1 */

  for (j=1;j<ysize+1;j++) {     /* fill in L+R edges */
   Eh(pr2,0,j) = Eh(pr,1,j);
   Eh(pr2,xsize+1,j) = Eh(pr,xsize,j);
  }
  for (i=0;i<xsize+2;i++) {     /* fill in T+B edges */
   Eh(pr2,i,0) = Eh(pr,i,1);
   Eh(pr2,i,ysize+1) = Eh(pr,i,ysize);
  }

}
