/* ------------------------------------------------------------------- */
/* erode_1()  --  erode one step, taking input hf1[] into output hf2[] */
/* ------------------------------------------------------------------- */

void erode_1(PTYPE *hf1, PTYPE *hf2)
{
/* Erodef(slope,flow)  is the function controlling erosion rate */
/*                               slope exponent   flow exponent */
#define Erodef(a,b)  sgn1(a) * pow(fabs(atan(a)),1.4) * pow((b),0.8)
  
  int ix,iy,i,dir=0;              /* indexes into arrays */
  int upd;                       /* direction of uphill neighbor */
  double inslope, outslope;      /* product of slope and flow_rate */
  double outflow;                /* flow out of this cell */
  double erval;                  /* erosion potential at this point */
  int x1,y1;
  double slopefactor;            /* correction factor to scale slope */
  double h, dh, slope;  /* dh- delta height  dr- horizontal travel */

  slopefactor = MAXALT / (EDGELEN / xsize);  /* slope of 0.0 next to 1.0 */

  /* recall that hf1,hf2 are arrays [0..xsize+1, 0..ysize+1]   */
  for (iy=0;iy<(ysize+2);iy++) {      /* copy edges of hf1 (-eps) into hf2*/
     h = Eh(hf1,0,iy) - errate; if (h<0) h=0;
     Eh(hf2,0,iy) = h;
     h = Eh(hf1,xsize+1,iy) - errate; if (h<0) h=0;
     Eh(hf2,xsize+1,iy) = h;
  }
  for (ix=1;ix<(xsize+1);ix++) {
     h = Eh(hf1,ix,0) - errate; if (h<0) h=0;
     Eh(hf2,ix,0) = h;
     h = Eh(hf1,ix,ysize+1) - errate; if (h<0) h=0;
     Eh(hf2,ix,ysize+1) = h;
   }

   for (iy = 0; iy<ysize; iy++) {  /* skip the edges */
    for (ix = 0; ix<xsize; ix++) {
     h = Ehn(hf1,ix,iy);        /* altitude at this point ix,iy */
     if (h < er_thresh) {
      inslope = 0;       /* find sum of inflowing neighbors (slope*flow) */
      for (i=1;i<9;i++) {               /* loop over neighbors of ix,iy */
       x1 = ix+xo[i]; 
       y1 = iy+yo[i];
                                /* check if off edge of array */
       if ((x1>=0) && (y1>=0) && (x1<xsize) && (y1<ysize)) {
        dir = El(fl,x1,y1);   /* direction index of this neighbor */
        if ((xo[i]+xo[dir]==0) && (yo[i]+yo[dir]==0)) { /* inflow from here */
          slope = Ehn(hf1,x1,y1) - Ehn(hf1,ix,iy); /* pos = neigh. higher */
          slope *= slopefactor;                 /* scale to corr. units */
          if ((i==1) || (i==3) || (i==5) || (i==7))
            slope = slope / 1.414;      /* diagonal neighbor; reduce slope */
          inslope += Erodef(slope,(double)El(ua,x1,y1));

         } /* end if ((xo... */
       } /* end if x1>=0 ... */
      } /* end for i */         /* now we've got sum of (slope*flow) */

      /* dir = lowestn(hf1,ix,iy,(float *)&slope);  direction of outflow */
      dir = El(fl,ix,iy);       /* direction of outflow */
                                        /* slope positive: neighbor lower */
      if (dir > 0) { /* if not a minimum... */
       h = Ehn(hf1,ix,iy);      /* current elevation at this point */
       if (h > 1.0) {
         fprintf(stderr,"! h(%d,%d)=%1.3f\n",ix,iy,h);
         h = 1.0;
       }
       slope = h - Ehn(hf1,ix+xo[dir],iy+yo[dir]); 
       slope *= slopefactor;
           if ((dir==1) || (dir==3) || (dir==5) || (dir==7))
             slope = slope / 1.414;      /* diagonal neighbor; reduce slope */
       outflow = (double) El(ua,ix,iy);

       if (outflow<1) outflow = 0.9;
       outslope = Erodef(slope,outflow);
              
        /* positive dh = erosion happens, neg = sedimentation */
        /* sedimentation when (inslope) greater than (er_sedfac*outslope) */

       erval = errate * (er_sedfac*outslope - inslope); 
       erval *= pow(outflow,er_pow);
       dh = errate * erval; 
       h = Ehn(hf1,ix,iy);      /* old altitude at this point */

       if (dh > er_debug) {  /* print debugging info */
    printf("(%d,%d): dh=%1.1e %0.2f ins=%1.1e outs=%1.1e sl=%1.1e fl=%1.1e\n",
                ix,iy,dh,h,inslope,outslope,slope,outflow);
       }
       if (dh > errate) dh = errate;   /* don't erode too fast */
       if  ( (h-dh) < 0 ) {  /* don't let altitudes go negative */
          dh = -h;           /* min elevation will be == 0.0 */
        }
                /* don't sediment too fast... */
                /* this should really depend on neighboring elevations */
       if (dh < -(0.03*errate)) dh = -(0.03*errate); 
                                   
                                   /* ------------------------------- */
                                   /* the actual erosion. right here! */
                                   /* ------------------------------- */
       Ehn(hf2,ix,iy) = h - dh; 
       El(bn,ix,iy) -= dh;       /* accumulate erosion rate separately */      

      } else {  /* if point is a local minimum (oops!) */
        upd = El(flag,ix,iy) & 0x0f;   /* direction of uphill neighbor */
        Ehn(hf2,ix,iy) = Ehn(hf1,ix+xo[upd],iy+yo[upd])+0.00001;
      } /* end if (dir>0) */
     } else {  /* NO erosion if point above erosion threshold */
        Ehn(hf2,ix,iy) = Ehn(hf1,ix,iy);
     } /* end if (h < er_thresh) */
    } /* end for ix */
   } /* end for iy */

} /* end erode_1() (whew!) */
