/*
 ************************************************************
 * MODULE: r.le.pixel/driver.c                              *
 *         Version 5.0                Nov. 1, 2001          *
 *                                                         *
 * AUTHOR: W.L. Baker, University of Wyoming                *
 *         BAKERWL@UWYO.EDU                                 *
 *                                                          *
 * PURPOSE: To analyze pixel-scale landscape properties     *
 *         driver.c opens the input and output files and    *
 *         then calls the moving window, unit, and whole    *
 *         map drivers                                      *
 *                                                         *
 * COPYRIGHT: (C) 2001 by W.L. Baker                        *
 *                                                          *
 * This program is free software under the GNU General      *
 * Public License(>=v2).  Read the file COPYING that comes  *
 * with GRASS for details                                   *
 *                                                         *
 ************************************************************/


#include <grass/gis.h>
#include "pixel.h"
#include <grass/config.h>



int finput, g_scale = 1, g_unit = 1;
extern struct CHOICE *choice;
char cmdbuf[100];
RASTER_MAP_TYPE data_type;

/*
   Variables:
   GLOBAL:
   finput =      the raster map to be analyzed
   g_scale =     the number of sampling scales
   g_unit =      the number of sampling units
   data_type =   the type of raster map: integer, floating point, or double
 */


					/* RUN R.LE.PIXEL IN FOREGROUND */

void texture_fore()
{
    FILE *fp0, *fp1, *fp2, *fp3, *fp4, *fp5;

    fprintf(stdout, "\nR.LE.PIXEL IS WORKING....;\n\n");

    /* check for input raster map */

    if (0 > (finput = G_open_cell_old(choice->fn, G_mapset()))) {
	fprintf(stdout, "\n");
	fprintf(stdout,
		"   ********************************************************\n");
	fprintf(stdout,
		"    The raster map you specified with the 'map=' parameter \n");
	fprintf(stdout,
		"    was not found in your mapset.                          \n");
	fprintf(stdout,
		"   ********************************************************\n");
	exit(1);
    }

    /* determine whether the raster map is integer
       (CELL_TYPE),floating point (FCELL_TYPE), or
       double (DCELL_TYPE) and make globally available */

    else
	data_type = G_raster_map_type(choice->fn, G_mapset());

    /* if using a moving window, get the parameters,
       and start the moving window driver */

    if (choice->wrum == 'm')
	mv_driver();

    /*  if using the whole raster map as the sampling
       area or sampling with units or regions, open 
       the output files */

    else {

	if (choice->att[0]) {
	    fp0 = fopen0("r.le.out/b1-4.out", "w");
	    fprintf(fp0,
		    "                 MEAN        ST. DEV.    MINIMUM     MAXIMUM\n");
	    fprintf(fp0,
		    "Scale Unit       PIXEL ATT.  PIXEL ATT.  PIXEL ATT.  PIXEL ATT.\n");
	    fclose(fp0);
	}

	if (choice->div[0]) {
	    fp1 = fopen0("r.le.out/d1-4.out", "w");
	    fprintf(fp1,
		    "                                                     INVERSE\n");
	    fprintf(fp1,
		    "Scale Unit       RICHNESS    SHANNON     DOMINANCE   SIMPSON\n");
	    fclose(fp1);
	}

	if (choice->te2[0]) {
	    fp2 = fopen0("r.le.out/t1-5.out", "w");
	    fprintf(fp2,
		    "                             ANGULAR     INVERSE\n");
	    fprintf(fp2,
		    "Scale Unit       CONTAGION   SEC. MOM.   DIFF. MOM.  ENTROPY     CONTRAST\n");
	    fclose(fp2);
	}

	if (choice->jux[0]) {
	    fp3 = fopen0("r.le.out/j1-2.out", "w");
	    fprintf(fp3, "                 MEAN        ST. DEV..\n");
	    fprintf(fp3, "Scale Unit       JUXTAPOS.   JUXTAPOS.\n");
	    fclose(fp3);
	}

	if (choice->edg[0]) {
	    if (choice->edg[1]) {
		fp4 = fopen0("r.le.out/e1.out", "w");
		fprintf(fp4, "                 SUM\n");
		fprintf(fp4, "Scale Unit       OF EDGES\n");
		fclose(fp4);
	    }
	    if (choice->edg[2]) {
		fp5 = fopen0("r.le.out/e2.out", "w");
		fprintf(fp5, "                 SUM\n");
		fprintf(fp5, "Scale Unit       OF EDGES\n");
		fclose(fp5);
	    }
	}

	if (choice->wrum == 'w' || choice->wrum == 'r')
	    whole_reg_driver();
	else if (choice->wrum == 'u')
	    unit_driver();
    }

    G_close_cell(finput);

    fputs("R.LE.PIXEL IS DONE;  ", stderr);

    if (choice->wrum != 'm')
	fputs("OUTPUT FILES IN SUBDIRECTORY \"r.le.out\"\n", stderr);

    return;
}




					/* MOVING WINDOW DRIVER */

void mv_driver()
{
    register int i, j;
    int nr, nc, u_w, u_l, x0, y0, d, fmask, m, p, cntwhole = 0, b, *row_buf;
    char *nul_buf, *nulltmp;
    int *tmp;
    float *ftmp;
    double *dtmp;
    double *tmp_buf, *tmp_buf2, **buff = NULL, *richwhole;
    int b1, b2, b3, b4, d1, d2, d3, d4, t1, t2, t3, t4, t5, j1, j2, e1, e2;
    long finished_time;
    float radius;
    struct Cell_head wind;

    /* variables: 
       nc = #cols. in search area minus (1/2 width of mov. wind. + 1) =
       number of cols with values in out map
       nr = #rows in search area minus (1/2 height of mov. wind. + 1) =
       number of rows with values in out map
       x0 = starting column for upper L corner of search area
       y0 = starting row for upper L corner of search area
       u_w = width of mov. wind. in cells
       u_l = width of mov. wind. in cells
       x0 = starting column for upper L corner of mov. wind.
       y0 = starting row for upper L corner of mov. wind.
       row = row for moving-window center
       col = column for moving-window center
       *row_buf = temporary array that holds one row of the
       MASK if there is one
       *tmp_buf = temporary array that holds one moving wind.
       measure for a single row
       **buff = temporary array that holds the set of chosen 
       measures for a row
       radius = radius of the sampling unit, if circles are used
     */


    /* open the appropriate output
       maps */

    if (choice->att[1]) {
	if (G_find_cell("b1", G_mapset()) != NULL) {
	    sprintf(cmdbuf, "%s %s", "g.rename -o", "rast=b1,b1bak");
	    system(cmdbuf);
	}
	b1 = G_open_raster_new("b1", DCELL_TYPE);
    }
    if (choice->att[2]) {
	if (G_find_cell("b2", G_mapset()) != NULL) {
	    sprintf(cmdbuf, "%s %s", "g.rename -o", "rast=b2,b2bak");
	    system(cmdbuf);
	}
	b2 = G_open_raster_new("b2", DCELL_TYPE);
    }
    if (choice->att[3]) {
	if (G_find_cell("b3", G_mapset()) != NULL) {
	    sprintf(cmdbuf, "%s %s", "g.rename -o", "rast=b3,b3bak");
	    system(cmdbuf);
	}
	b3 = G_open_raster_new("b3", DCELL_TYPE);
    }
    if (choice->att[4]) {
	if (G_find_cell("b4", G_mapset()) != NULL) {
	    sprintf(cmdbuf, "%s %s", "g.rename -o", "rast=b4,b4bak");
	    system(cmdbuf);
	}
	b4 = G_open_raster_new("b4", DCELL_TYPE);
    }

    if (choice->div[1]) {
	if (G_find_cell("d1", G_mapset()) != NULL) {
	    sprintf(cmdbuf, "%s %s", "g.rename -o", "rast=d1,d1bak");
	    system(cmdbuf);
	}
	d1 = G_open_raster_new("d1", DCELL_TYPE);
    }
    if (choice->div[2]) {
	if (G_find_cell("d2", G_mapset()) != NULL) {
	    sprintf(cmdbuf, "%s %s", "g.rename -o", "rast=d2,d2bak");
	    system(cmdbuf);
	}
	d2 = G_open_raster_new("d2", DCELL_TYPE);
    }
    if (choice->div[3]) {
	if (G_find_cell("d3", G_mapset()) != NULL) {
	    sprintf(cmdbuf, "%s %s", "g.rename -o", "rast=d3,d3bak");
	    system(cmdbuf);
	}
	d3 = G_open_raster_new("d3", DCELL_TYPE);
    }
    if (choice->div[4]) {
	if (G_find_cell("d4", G_mapset()) != NULL) {
	    sprintf(cmdbuf, "%s %s", "g.rename -o", "rast=d4,d4bak");
	    system(cmdbuf);
	}
	d4 = G_open_raster_new("d4", DCELL_TYPE);
    }

    if (choice->te2[1]) {
	if (G_find_cell("t1", G_mapset()) != NULL) {
	    sprintf(cmdbuf, "%s %s", "g.rename -o", "rast=t1,t1bak");
	    system(cmdbuf);
	}
	t1 = G_open_raster_new("t1", DCELL_TYPE);
    }
    if (choice->te2[2]) {
	if (G_find_cell("t2", G_mapset()) != NULL) {
	    sprintf(cmdbuf, "%s %s", "g.rename -o", "rast=t2,t2bak");
	    system(cmdbuf);
	}
	t2 = G_open_raster_new("t2", DCELL_TYPE);
    }
    if (choice->te2[3]) {
	if (G_find_cell("t3", G_mapset()) != NULL) {
	    sprintf(cmdbuf, "%s %s", "g.rename -o", "rast=t3,t3bak");
	    system(cmdbuf);
	}
	t3 = G_open_raster_new("t3", DCELL_TYPE);
    }
    if (choice->te2[4]) {
	if (G_find_cell("t4", G_mapset()) != NULL) {
	    sprintf(cmdbuf, "%s %s", "g.rename -o", "rast=t4,t4bak");
	    system(cmdbuf);
	}
	t4 = G_open_raster_new("t4", DCELL_TYPE);
    }
    if (choice->te2[5]) {
	if (G_find_cell("t5", G_mapset()) != NULL) {
	    sprintf(cmdbuf, "%s %s", "g.rename -o", "rast=t5,t5bak");
	    system(cmdbuf);
	}
	t5 = G_open_raster_new("t5", DCELL_TYPE);
    }

    if (choice->jux[1]) {
	if (G_find_cell("j1", G_mapset()) != NULL) {
	    sprintf(cmdbuf, "%s %s", "g.rename -o", "rast=j1,j1bak");
	    system(cmdbuf);
	}
	j1 = G_open_raster_new("j1", DCELL_TYPE);
    }
    if (choice->jux[2]) {
	if (G_find_cell("j2", G_mapset()) != NULL) {
	    sprintf(cmdbuf, "%s %s", "g.rename -o", "rast=j2,j2bak");
	    system(cmdbuf);
	}
	j2 = G_open_raster_new("j2", DCELL_TYPE);
    }
    if (choice->edg[1]) {
	if (G_find_cell("e1", G_mapset()) != NULL) {
	    sprintf(cmdbuf, "%s %s", "g.rename -o", "rast=e1,e1bak");
	    system(cmdbuf);
	}
	e1 = G_open_raster_new("e1", DCELL_TYPE);
    }
    if (choice->edg[2]) {
	if (G_find_cell("e2", G_mapset()) != NULL) {
	    sprintf(cmdbuf, "%s %s", "g.rename -o", "rast=e2,e2bak");
	    system(cmdbuf);
	}
	e2 = G_open_raster_new("e2", DCELL_TYPE);
    }


    /* get the moving window parameters */

    read_mwind(&u_w, &u_l, &nc, &nr, &x0, &y0, &radius);

    /* check for an unacceptable 
       moving-window size */

    if (nc < 1 || nr < 1) {
	fprintf(stdout, "\n");
	fprintf(stdout,
		"   *******************************************************\n");
	fprintf(stdout,
		"    The moving window size specified in file r.le.para/   \n");
	fprintf(stdout,
		"    move_wind is less than 1 row or column.  Check this   \n");
	fprintf(stdout,
		"    file or redefine the moving window using r.le.setup.  \n");
	fprintf(stdout,
		"   *******************************************************\n");
	exit(1);
    }

    /* check for an unacceptable
       search area */

    G_get_set_window(&wind);
    if (wind.rows < nr + y0 || wind.cols < nc + x0) {
	fprintf(stdout, "\n");
	fprintf(stdout,
		"   *******************************************************\n");
	fprintf(stdout,
		"    Moving window search area in file r.le.para/move_wind \n");
	fprintf(stdout,
		"    does not match the dimensions of the current region.  \n");
	fprintf(stdout,
		"    You must either rerun r.le.setup to make a new        \n");
	fprintf(stdout,
		"    r.le.para/move_wind file or reset the region to match \n");
	fprintf(stdout,
		"    the r.le.para/move_wind file 		               \n");
	fprintf(stdout,
		"   *******************************************************\n");
	exit(1);
    }


    /* begin main moving window loop 
       section */

    /* set the d parameter for the 
       performance meter */

    if (nr * nc > 10000)
	d = nr * nc / 1000;
    else if (nr * nc > 2500)
	d = nr * nc / 100;
    else
	d = 10;
    /* return a value > 0 to fmask if
       there is a MASK present */

    fprintf(stdout,
	    "If a MASK is not present (see r.mask) a beep may sound and a\n");
    fprintf(stdout,
	    "   warning may be printed or appear in a window; ignore this warning.\n");
    fprintf(stdout, "If a MASK is present there will be no warning.\n");
    fmask = G_open_cell_old("MASK", G_mapset());
    fprintf(stdout, "\n");

    /* allocate memory for the buffer */

    buff = (double **)G_calloc(nc + 1, sizeof(double *));

    /* allocate memory for each of 17 measures */

    for (p = 0; p < nc + 1; p++)
	buff[p] = (double *)G_calloc(17, sizeof(double));


    /* allocate memory for a row buffer if
       there is a mask */

    if (fmask > 0)
	row_buf = G_allocate_raster_buf(CELL_TYPE);


    if (choice->edg[2] || choice->jux[0]) {

	/* dynamically allocate memory for
	   the richness array */

	richwhole = (double *)G_calloc(MAX, sizeof(double));

	/* initialize the richness array
	   elements with the value -999 */

	for (i = 0; i < MAX; i++)
	    richwhole[i] = -999.0;

	/* allocate memory to store a row of the
	   raster map, depending on the type of
	   input raster map; keep track of the
	   name of the buffer for each raster type */

	switch (data_type) {
	case CELL_TYPE:
	    tmp = G_allocate_raster_buf(CELL_TYPE);
	    break;
	case FCELL_TYPE:
	    ftmp = G_allocate_raster_buf(FCELL_TYPE);
	    break;
	case DCELL_TYPE:
	    dtmp = G_allocate_raster_buf(DCELL_TYPE);
	    break;
	}

	nul_buf = G_allocate_null_buf();

	/* go through the search area
	   pixel by pixel */

	for (i = 0; i < nr; i++) {

	    switch (data_type) {
	    case (CELL_TYPE):
		G_zero_raster_buf(tmp, CELL_TYPE);
		G_get_raster_row(finput, tmp, i, CELL_TYPE);
		break;
	    case (FCELL_TYPE):
		G_zero_raster_buf(ftmp, FCELL_TYPE);
		G_get_raster_row(finput, ftmp, i, FCELL_TYPE);
		break;
	    case (DCELL_TYPE):
		G_zero_raster_buf(dtmp, DCELL_TYPE);
		G_get_raster_row(finput, dtmp, i, DCELL_TYPE);
		break;
	    }

	    G_get_null_value_row(finput, nul_buf, i);

	    for (j = 0; j < nc; j++) {

		/* if the raster value is not null,
		   call get_rich_whole to tally up the
		   number of different attributes
		   in the search area and fill
		   the richness array with those
		   attributes */
		switch (data_type) {
		case (CELL_TYPE):
		    if ((*(tmp + j) ||
			 *(tmp + j) == 0) && *(nul_buf + j) == 0.0)
			get_rich_whole((double)*(tmp + j), richwhole,
				       &cntwhole);
		    break;
		case (FCELL_TYPE):
		    if ((*(ftmp + j) ||
			 *(ftmp + j) == 0) && *(nul_buf + j) == 0.0)
			get_rich_whole((double)*(ftmp + j), richwhole,
				       &cntwhole);
		    break;
		case (DCELL_TYPE):
		    if ((*(dtmp + j) ||
			 *(dtmp + j) == 0) && *(nul_buf + j) == 0.0)
			get_rich_whole(*(dtmp + j), richwhole, &cntwhole);
		    break;
		}
	    }
	}

	switch (data_type) {
	case (CELL_TYPE):
	    G_free(tmp);
	    break;
	case (FCELL_TYPE):
	    G_free(ftmp);
	    break;
	case (DCELL_TYPE):
	    G_free(dtmp);
	    break;
	}
	G_free(nul_buf);
	G_free(richwhole);
    }

    /* main loop for clipping & measuring 
       using the moving-window; index i
       refers to which moving window, not
       the row of the original map */

    for (i = 0; i < nr; i++) {

	/* zero the buffer before filling it
	   again */

	for (m = 0; m < nc + 1; m++) {
	    for (p = 0; p < 17; p++)
		*(*(buff + m) + p) = 0.0;
	}

	/* if there is a MASK, then read in
	   a row of MASK - this part skips 
	   cells with the value "0" in the 
	   MASK to speed up the moving window
	   process */

	if (fmask > 0) {
	    G_zero_raster_buf(row_buf, CELL_TYPE);
	    G_get_raster_row_nomask(fmask, row_buf, y0 + i + u_l / 2,
				    CELL_TYPE);

	    /* for each cell whose value is "1"
	       in MASK */

	    for (j = 0; j < nc; j++) {

		/* display #cells left to do */

		if (i == 0 && j == 0)
		    fprintf(stdout, "TOTAL WINDOWS = %8d\n", nr * nc);
		meter2(nr * nc, (i * nc + (j + 1)), d);

		/* call the cell clip driver */

		if (row_buf[x0 + j + u_w / 2])
		    cell_clip_drv(x0 + j, y0 + i, u_w, u_l, buff, j, cntwhole,
				  radius);
	    }
	}

	/* if there is no MASK, then clip
	   and measure at every cell */

	else {

	    for (j = 0; j < nc; j++) {

		/* display #cells left to do */

		if (i == 0 && j == 0)
		    fprintf(stdout, "TOTAL WINDOWS = %8d\n", nr * nc);
		meter2(nr * nc, (i * nc + (j + 1)), d);

		/* call the cell clip driver.  This routine will clip
		   the rectangle at x0 + j, y0 + i and u_w X u_l wide
		   (or in a circle with radius), and put the results
		   for each chosen moving windown measure in buff;
		   note that the center of the moving window is not
		   at x0 + j, y0 + i, but at x0 + j + u_w/2, y0 + i +
		   u_l/2 */

		cell_clip_drv(x0 + j, y0 + i, u_w, u_l, buff, j, cntwhole,
			      radius);
	    }
	}

	/* copy the chosen measures into a temporary row
	   buffer which is then fed into the chosen output
	   maps; the map location is adjusted to the center
	   of the moving window */

	tmp_buf = G_allocate_raster_buf(DCELL_TYPE);
	nulltmp = G_allocate_null_buf();

	if (choice->att[1]) {
	    G_zero_raster_buf(tmp_buf, DCELL_TYPE);
	    G_set_null_value(tmp_buf, x0 + nc + u_w, DCELL_TYPE);
	    if (i == 0) {
		for (b = 0; b < u_l / 2; b++)
		    G_put_d_raster_row(b1, tmp_buf);
	    }
	    if (i < nr) {
		for (m = 0; m < nc; m++) {
		    if (*(*(buff + m) + 0) > -BIG)
			*(tmp_buf + (x0 + m + u_w / 2)) = *(*(buff + m) + 0);
		}
		G_put_d_raster_row(b1, tmp_buf);
	    }
	    if (i == nr - 1) {
		tmp_buf2 = G_allocate_raster_buf(DCELL_TYPE);
		G_set_null_value(tmp_buf2, x0 + nc + u_w, DCELL_TYPE);
		for (b = 0; b < u_l / 2; b++)
		    G_put_d_raster_row(b1, tmp_buf2);
		G_free(tmp_buf2);
	    }
	}
	if (choice->att[2]) {
	    G_zero_raster_buf(tmp_buf, DCELL_TYPE);
	    G_set_null_value(tmp_buf, x0 + nc + u_w, DCELL_TYPE);
	    if (i == 0) {
		for (b = 0; b < u_l / 2; b++)
		    G_put_d_raster_row(b2, tmp_buf);
	    }
	    if (i < nr) {
		for (m = 0; m < nc; m++) {
		    if (*(*(buff + m) + 1) > -BIG)
			*(tmp_buf + (x0 + m + u_w / 2)) = *(*(buff + m) + 1);
		}
		G_put_d_raster_row(b2, tmp_buf);
	    }
	    if (i == nr - 1) {
		tmp_buf2 = G_allocate_raster_buf(DCELL_TYPE);
		G_set_null_value(tmp_buf2, x0 + nc + u_w, DCELL_TYPE);
		for (b = 0; b < u_l / 2; b++)
		    G_put_d_raster_row(b2, tmp_buf2);
		G_free(tmp_buf2);
	    }
	}
	if (choice->att[3]) {
	    G_zero_raster_buf(tmp_buf, DCELL_TYPE);
	    G_set_null_value(tmp_buf, x0 + nc + u_w, DCELL_TYPE);
	    if (i == 0) {
		for (b = 0; b < u_l / 2; b++)
		    G_put_d_raster_row(b3, tmp_buf);
	    }
	    if (i < nr) {
		for (m = 0; m < nc; m++) {
		    if (*(*(buff + m) + 2) > -BIG)
			*(tmp_buf + (x0 + m + u_w / 2)) = *(*(buff + m) + 2);
		}
		G_put_d_raster_row(b3, tmp_buf);
	    }
	    if (i == nr - 1) {
		tmp_buf2 = G_allocate_raster_buf(DCELL_TYPE);
		G_set_null_value(tmp_buf2, x0 + nc + u_w, DCELL_TYPE);
		for (b = 0; b < u_l / 2; b++)
		    G_put_d_raster_row(b3, tmp_buf2);
		G_free(tmp_buf2);
	    }
	}
	if (choice->att[4]) {
	    G_zero_raster_buf(tmp_buf, DCELL_TYPE);
	    G_set_null_value(tmp_buf, x0 + nc + u_w, DCELL_TYPE);
	    if (i == 0) {
		for (b = 0; b < u_l / 2; b++)
		    G_put_d_raster_row(b4, tmp_buf);
	    }
	    if (i < nr) {
		for (m = 0; m < nc; m++) {
		    if (*(*(buff + m) + 3) > -BIG)
			*(tmp_buf + (x0 + m + u_w / 2)) = *(*(buff + m) + 3);
		}
		G_put_d_raster_row(b4, tmp_buf);
	    }
	    if (i == nr - 1) {
		tmp_buf2 = G_allocate_raster_buf(DCELL_TYPE);
		G_set_null_value(tmp_buf2, x0 + nc + u_w, DCELL_TYPE);
		for (b = 0; b < u_l / 2; b++)
		    G_put_d_raster_row(b4, tmp_buf2);
		G_free(tmp_buf2);
	    }
	}
	if (choice->div[1]) {
	    G_zero_raster_buf(tmp_buf, DCELL_TYPE);
	    G_set_null_value(tmp_buf, x0 + nc + u_w, DCELL_TYPE);
	    if (i == 0) {
		for (b = 0; b < u_l / 2; b++)
		    G_put_d_raster_row(d1, tmp_buf);
	    }
	    if (i < nr) {
		for (m = 0; m < nc; m++) {
		    if (*(*(buff + m) + 4) > -BIG)
			*(tmp_buf + (x0 + m + u_w / 2)) = *(*(buff + m) + 4);
		}
		G_put_d_raster_row(d1, tmp_buf);
	    }
	    if (i == nr - 1) {
		tmp_buf2 = G_allocate_raster_buf(DCELL_TYPE);
		G_set_null_value(tmp_buf2, x0 + nc + u_w, DCELL_TYPE);
		for (b = 0; b < u_l / 2; b++)
		    G_put_d_raster_row(d1, tmp_buf2);
		G_free(tmp_buf2);
	    }
	}
	if (choice->div[2]) {
	    G_zero_raster_buf(tmp_buf, DCELL_TYPE);
	    G_set_null_value(tmp_buf, x0 + nc + u_w, DCELL_TYPE);
	    if (i == 0) {
		for (b = 0; b < u_l / 2; b++)
		    G_put_d_raster_row(d2, tmp_buf);
	    }
	    if (i < nr) {
		for (m = 0; m < nc; m++) {
		    if (*(*(buff + m) + 5) > -BIG)
			*(tmp_buf + (x0 + m + u_w / 2)) = *(*(buff + m) + 5);
		}
		G_put_d_raster_row(d2, tmp_buf);
	    }
	    if (i == nr - 1) {
		tmp_buf2 = G_allocate_raster_buf(DCELL_TYPE);
		G_set_null_value(tmp_buf2, x0 + nc + u_w, DCELL_TYPE);
		for (b = 0; b < u_l / 2; b++)
		    G_put_d_raster_row(d2, tmp_buf2);
		G_free(tmp_buf2);
	    }
	}
	if (choice->div[3]) {
	    G_zero_raster_buf(tmp_buf, DCELL_TYPE);
	    G_set_null_value(tmp_buf, x0 + nc + u_w, DCELL_TYPE);
	    if (i == 0) {
		for (b = 0; b < u_l / 2; b++)
		    G_put_d_raster_row(d3, tmp_buf);
	    }
	    if (i < nr) {
		for (m = 0; m < nc; m++) {
		    if (*(*(buff + m) + 6) > -BIG)
			*(tmp_buf + (x0 + m + u_w / 2)) = *(*(buff + m) + 6);
		}
		G_put_d_raster_row(d3, tmp_buf);
	    }
	    if (i == nr - 1) {
		tmp_buf2 = G_allocate_raster_buf(DCELL_TYPE);
		G_set_null_value(tmp_buf2, x0 + nc + u_w, DCELL_TYPE);
		for (b = 0; b < u_l / 2; b++)
		    G_put_d_raster_row(d3, tmp_buf2);
		G_free(tmp_buf2);
	    }
	}
	if (choice->div[4]) {
	    G_zero_raster_buf(tmp_buf, DCELL_TYPE);
	    G_set_null_value(tmp_buf, x0 + nc + u_w, DCELL_TYPE);
	    if (i == 0) {
		for (b = 0; b < u_l / 2; b++)
		    G_put_d_raster_row(d4, tmp_buf);
	    }
	    if (i < nr) {
		for (m = 0; m < nc; m++) {
		    if (*(*(buff + m) + 7) > -BIG)
			*(tmp_buf + (x0 + m + u_w / 2)) = *(*(buff + m) + 7);
		}
		G_put_d_raster_row(d4, tmp_buf);
	    }
	    if (i == nr - 1) {
		tmp_buf2 = G_allocate_raster_buf(DCELL_TYPE);
		G_set_null_value(tmp_buf2, x0 + nc + u_w, DCELL_TYPE);
		for (b = 0; b < u_l / 2; b++)
		    G_put_d_raster_row(d4, tmp_buf2);
		G_free(tmp_buf2);
	    }
	}
	if (choice->te2[1]) {
	    G_zero_raster_buf(tmp_buf, DCELL_TYPE);
	    G_set_null_value(tmp_buf, x0 + nc + u_w, DCELL_TYPE);
	    if (i == 0) {
		for (b = 0; b < u_l / 2; b++)
		    G_put_d_raster_row(t1, tmp_buf);
	    }
	    if (i < nr) {
		for (m = 0; m < nc; m++) {
		    if (*(*(buff + m) + 8) > -BIG)
			*(tmp_buf + (x0 + m + u_w / 2)) = *(*(buff + m) + 8);
		}
		G_put_d_raster_row(t1, tmp_buf);
	    }
	    if (i == nr - 1) {
		tmp_buf2 = G_allocate_raster_buf(DCELL_TYPE);
		G_set_null_value(tmp_buf2, x0 + nc + u_w, DCELL_TYPE);
		for (b = 0; b < u_l / 2; b++)
		    G_put_d_raster_row(t1, tmp_buf2);
		G_free(tmp_buf2);
	    }
	}
	if (choice->te2[2]) {
	    G_zero_raster_buf(tmp_buf, DCELL_TYPE);
	    G_set_null_value(tmp_buf, x0 + nc + u_w, DCELL_TYPE);
	    if (i == 0) {
		for (b = 0; b < u_l / 2; b++)
		    G_put_d_raster_row(t2, tmp_buf);
	    }
	    if (i < nr) {
		for (m = 0; m < nc; m++) {
		    if (*(*(buff + m) + 9) > -BIG)
			*(tmp_buf + (x0 + m + u_w / 2)) = *(*(buff + m) + 9);
		}
		G_put_d_raster_row(t2, tmp_buf);
	    }
	    if (i == nr - 1) {
		tmp_buf2 = G_allocate_raster_buf(DCELL_TYPE);
		G_set_null_value(tmp_buf2, x0 + nc + u_w, DCELL_TYPE);
		for (b = 0; b < u_l / 2; b++)
		    G_put_d_raster_row(t2, tmp_buf2);
		G_free(tmp_buf2);
	    }
	}
	if (choice->te2[3]) {
	    G_zero_raster_buf(tmp_buf, DCELL_TYPE);
	    G_set_null_value(tmp_buf, x0 + nc + u_w, DCELL_TYPE);
	    if (i == 0) {
		for (b = 0; b < u_l / 2; b++)
		    G_put_d_raster_row(t3, tmp_buf);
	    }
	    if (i < nr) {
		for (m = 0; m < nc; m++) {
		    if (*(*(buff + m) + 10) > -BIG)
			*(tmp_buf + (x0 + m + u_w / 2)) = *(*(buff + m) + 10);
		}
		G_put_d_raster_row(t3, tmp_buf);
	    }
	    if (i == nr - 1) {
		tmp_buf2 = G_allocate_raster_buf(DCELL_TYPE);
		G_set_null_value(tmp_buf2, x0 + nc + u_w, DCELL_TYPE);
		for (b = 0; b < u_l / 2; b++)
		    G_put_d_raster_row(t3, tmp_buf2);
		G_free(tmp_buf2);
	    }
	}
	if (choice->te2[4]) {
	    G_zero_raster_buf(tmp_buf, DCELL_TYPE);
	    G_set_null_value(tmp_buf, x0 + nc + u_w, DCELL_TYPE);
	    if (i == 0) {
		for (b = 0; b < u_l / 2; b++)
		    G_put_d_raster_row(t4, tmp_buf);
	    }
	    if (i < nr) {
		for (m = 0; m < nc; m++) {
		    if (*(*(buff + m) + 11) > -BIG)
			*(tmp_buf + (x0 + m + u_w / 2)) = *(*(buff + m) + 11);
		}
		G_put_d_raster_row(t4, tmp_buf);
	    }
	    if (i == nr - 1) {
		tmp_buf2 = G_allocate_raster_buf(DCELL_TYPE);
		G_set_null_value(tmp_buf2, x0 + nc + u_w, DCELL_TYPE);
		for (b = 0; b < u_l / 2; b++)
		    G_put_d_raster_row(t4, tmp_buf2);
		G_free(tmp_buf2);
	    }
	}
	if (choice->te2[5]) {
	    G_zero_raster_buf(tmp_buf, DCELL_TYPE);
	    G_set_null_value(tmp_buf, x0 + nc + u_w, DCELL_TYPE);
	    if (i == 0) {
		for (b = 0; b < u_l / 2; b++)
		    G_put_d_raster_row(t5, tmp_buf);
	    }
	    if (i < nr) {
		for (m = 0; m < nc; m++) {
		    if (*(*(buff + m) + 12) > -BIG)
			*(tmp_buf + (x0 + m + u_w / 2)) = *(*(buff + m) + 12);
		}
		G_put_d_raster_row(t5, tmp_buf);
	    }
	    if (i == nr - 1) {
		tmp_buf2 = G_allocate_raster_buf(DCELL_TYPE);
		G_set_null_value(tmp_buf2, x0 + nc + u_w, DCELL_TYPE);
		for (b = 0; b < u_l / 2; b++)
		    G_put_d_raster_row(t5, tmp_buf2);
		G_free(tmp_buf2);
	    }
	}
	if (choice->jux[1]) {
	    G_zero_raster_buf(tmp_buf, DCELL_TYPE);
	    G_set_null_value(tmp_buf, x0 + nc + u_w, DCELL_TYPE);
	    if (i == 0) {
		for (b = 0; b < u_l / 2; b++)
		    G_put_d_raster_row(j1, tmp_buf);
	    }
	    if (i < nr) {
		for (m = 0; m < nc; m++) {
		    if (*(*(buff + m) + 13) > -BIG)
			*(tmp_buf + (x0 + m + u_w / 2)) = *(*(buff + m) + 13);
		}
		G_put_d_raster_row(j1, tmp_buf);
	    }
	    if (i == nr - 1) {
		tmp_buf2 = G_allocate_raster_buf(DCELL_TYPE);
		G_set_null_value(tmp_buf2, x0 + nc + u_w, DCELL_TYPE);
		for (b = 0; b < u_l / 2; b++)
		    G_put_d_raster_row(j1, tmp_buf2);
		G_free(tmp_buf2);
	    }
	}
	if (choice->jux[2]) {
	    G_zero_raster_buf(tmp_buf, DCELL_TYPE);
	    G_set_null_value(tmp_buf, x0 + nc + u_w, DCELL_TYPE);
	    if (i == 0) {
		for (b = 0; b < u_l / 2; b++)
		    G_put_d_raster_row(j2, tmp_buf);
	    }
	    if (i < nr) {
		for (m = 0; m < nc; m++) {
		    if (*(*(buff + m) + 14) > -BIG)
			*(tmp_buf + (x0 + m + u_w / 2)) = *(*(buff + m) + 14);
		}
		G_put_d_raster_row(j2, tmp_buf);
	    }
	    if (i == nr - 1) {
		tmp_buf2 = G_allocate_raster_buf(DCELL_TYPE);
		G_set_null_value(tmp_buf2, x0 + nc + u_w, DCELL_TYPE);
		for (b = 0; b < u_l / 2; b++)
		    G_put_d_raster_row(j2, tmp_buf2);
		G_free(tmp_buf2);
	    }
	}
	if (choice->edg[1]) {
	    G_zero_raster_buf(tmp_buf, DCELL_TYPE);
	    G_set_null_value(tmp_buf, x0 + nc + u_w, DCELL_TYPE);
	    if (i == 0) {
		for (b = 0; b < u_l / 2; b++)
		    G_put_d_raster_row(e1, tmp_buf);
	    }
	    if (i < nr) {
		for (m = 0; m < nc; m++) {
		    if (*(*(buff + m) + 15) > -BIG)
			*(tmp_buf + (x0 + m + u_w / 2)) = *(*(buff + m) + 15);
		}
		G_put_d_raster_row(e1, tmp_buf);
	    }
	    if (i == nr - 1) {
		tmp_buf2 = G_allocate_raster_buf(DCELL_TYPE);
		G_set_null_value(tmp_buf2, x0 + nc + u_w, DCELL_TYPE);
		for (b = 0; b < u_l / 2; b++)
		    G_put_d_raster_row(e1, tmp_buf2);
		G_free(tmp_buf2);
	    }
	}
	if (choice->edg[2]) {
	    G_zero_raster_buf(tmp_buf, DCELL_TYPE);
	    G_set_null_value(tmp_buf, x0 + nc + u_w, DCELL_TYPE);
	    if (i == 0) {
		for (b = 0; b < u_l / 2; b++)
		    G_put_d_raster_row(e2, tmp_buf);
	    }
	    if (i < nr) {
		for (m = 0; m < nc; m++) {
		    if (*(*(buff + m) + 16) > -BIG)
			*(tmp_buf + (x0 + m + u_w / 2)) = *(*(buff + m) + 16);
		}
		G_put_d_raster_row(e2, tmp_buf);
	    }
	    if (i == nr - 1) {
		tmp_buf2 = G_allocate_raster_buf(DCELL_TYPE);
		G_set_null_value(tmp_buf2, x0 + nc + u_w, DCELL_TYPE);
		for (b = 0; b < u_l / 2; b++)
		    G_put_d_raster_row(e2, tmp_buf2);
		G_free(tmp_buf2);
	    }
	}


	G_free(tmp_buf);
    }

    time(&finished_time);
    fprintf(stdout, "\nACTUAL COMPLETION = %s",
	    asctime(localtime(&finished_time)));
    fflush(stdout);

    /* free the memory allocated for the 
       mask and other buffer */

    if (fmask > 0)
	G_free(row_buf);
    for (p = 0; p < nc + 1; p++)
	G_free(buff[p]);
    G_free(buff);

    /* close the raster maps, set the
       color table for the new raster
       map and compress the map */


    if (choice->att[1]) {
	G_close_cell(b1);
	set_colors("b1");
	sprintf(cmdbuf, "%s %s", "r.compress", "b1");
	system(cmdbuf);
    }
    if (choice->att[2]) {
	G_close_cell(b2);
	set_colors("b2");
	sprintf(cmdbuf, "%s %s", "r.compress", "b2");
	system(cmdbuf);
    }
    if (choice->att[3]) {
	G_close_cell(b3);
	set_colors("b3");
	sprintf(cmdbuf, "%s %s", "r.compress", "b3");
	system(cmdbuf);
    }
    if (choice->att[4]) {
	G_close_cell(b4);
	set_colors("b4");
	sprintf(cmdbuf, "%s %s", "r.compress", "b4");
	system(cmdbuf);
    }
    if (choice->div[1]) {
	G_close_cell(d1);
	set_colors("d1");
	sprintf(cmdbuf, "%s %s", "r.compress", "d1");
	system(cmdbuf);
    }
    if (choice->div[2]) {
	G_close_cell(d2);
	set_colors("d2");
	sprintf(cmdbuf, "%s %s", "r.compress", "d2");
	system(cmdbuf);
    }
    if (choice->div[3]) {
	G_close_cell(d3);
	set_colors("d3");
	sprintf(cmdbuf, "%s %s", "r.compress", "d3");
	system(cmdbuf);
    }
    if (choice->div[4]) {
	G_close_cell(d4);
	set_colors("d4");
	sprintf(cmdbuf, "%s %s", "r.compress", "d4");
	system(cmdbuf);
    }
    if (choice->te2[1]) {
	G_close_cell(t1);
	set_colors("t1");
	sprintf(cmdbuf, "%s %s", "r.compress", "t1");
	system(cmdbuf);
    }
    if (choice->te2[2]) {
	G_close_cell(t2);
	set_colors("t2");
	sprintf(cmdbuf, "%s %s", "r.compress", "t2");
	system(cmdbuf);
    }
    if (choice->te2[3]) {
	G_close_cell(t3);
	set_colors("t3");
	sprintf(cmdbuf, "%s %s", "r.compress", "t3");
	system(cmdbuf);
    }
    if (choice->te2[4]) {
	G_close_cell(t4);
	set_colors("t4");
	sprintf(cmdbuf, "%s %s", "r.compress", "t4");
	system(cmdbuf);
    }
    if (choice->te2[5]) {
	G_close_cell(t5);
	set_colors("t5");
	sprintf(cmdbuf, "%s %s", "r.compress", "t5");
	system(cmdbuf);
    }
    if (choice->jux[1]) {
	G_close_cell(j1);
	set_colors("j1");
	sprintf(cmdbuf, "%s %s", "r.compress", "j1");
	system(cmdbuf);
    }
    if (choice->jux[2]) {
	G_close_cell(j2);
	set_colors("j2");
	sprintf(cmdbuf, "%s %s", "r.compress", "j2");
	system(cmdbuf);
    }
    if (choice->edg[1]) {
	G_close_cell(e1);
	set_colors("e1");
	sprintf(cmdbuf, "%s %s", "r.compress", "e1");
	system(cmdbuf);
    }
    if (choice->edg[2]) {
	G_close_cell(e2);
	set_colors("e2");
	sprintf(cmdbuf, "%s %s", "r.compress", "e2");
	system(cmdbuf);
    }

    G_close_cell(fmask);

    return;
}







					/* SET "OUT" RASTER FILE COLOR
					   TABLE TO G-Y-R */

void set_colors(char *name)
{
    struct Colors colors;
    struct FPRange fprange;

    G_read_fp_range(name, G_mapset(), &fprange);
    G_make_gyr_fp_colors(&colors, fprange.min, fprange.max);
    G_write_colors(name, G_mapset(), &colors);
    return;
}






					/* OPEN OUTPUT FILE WITH ERROR TRAP */

FILE *fopen0(char *name, char *flag)
{
    FILE *fp;

    if (!(fp = fopen(name, flag))) {
	fprintf(stdout, "\n");
	fprintf(stdout, "   ******************************************\n");
	fprintf(stdout, "    Can't open output file \"%s\"            \n",
		name);
	fprintf(stdout, "    Do you have write permission in r.le.out \n");
	fprintf(stdout, "    subdirectory?                            \n");
	fprintf(stdout, "   ******************************************\n");
	exit(1);
    }
    return fp;
}





					/* OPEN INPUT FILE WITH ERROR TRAP */

FILE *fopen1(char *name, char *flag)
{
    FILE *fp;

    if (!(fp = fopen(name, flag))) {
	fprintf(stdout, "\n");
	fprintf(stdout,
		"   ******************************************************\n");
	fprintf(stdout,
		"    You chose a moving window or sampling units analysis \n");
	fprintf(stdout,
		"       but r.le.pixel can't find file \"%s\"             \n",
		name);
	fprintf(stdout,
		"       which defines the moving window or sampling units \n");
	fprintf(stdout,
		"    First use r.le.setup for to setup a moving window or \n");
	fprintf(stdout,
		"       sampling units to make this file                  \n");
	fprintf(stdout,
		"   ******************************************************\n");
	exit(1);
    }
    return fp;
}



					/* OPEN WEIGHT FILE WITH ERROR TRAP */

FILE *fopen2(char *name, char *flag)
{
    FILE *fp;

    if (!(fp = fopen(name, flag))) {
	fprintf(stdout, "\n");
	fprintf(stdout,
		"   ***************************************************\n");
	fprintf(stdout,
		"    You chose a juxtaposition measure, but r.le.pixel \n");
	fprintf(stdout,
		"       can't find file \"%s\"             		   \n",
		name);
	fprintf(stdout,
		"       which defines the weights for different edges  \n");
	fprintf(stdout,
		"    First use a text editor to make this file         \n");
	fprintf(stdout,
		"   ***************************************************\n");
	exit(1);
    }
    return fp;
}



					/* OPEN EDGE FILE WITH ERROR TRAP */

FILE *fopen3(char *name, char *flag)
{
    FILE *fp;

    if (!(fp = fopen(name, flag))) {
	fprintf(stdout, "\n");
	fprintf(stdout,
		"   ***************************************************\n");
	fprintf(stdout,
		"    You chose an edge measure, but r.le.pixel         \n");
	fprintf(stdout,
		"       can't find file \"%s\"             		   \n",
		name);
	fprintf(stdout,
		"       which defines the types of edges to be counted \n");
	fprintf(stdout,
		"    First use a text editor to make this file         \n");
	fprintf(stdout,
		"   ***************************************************\n");
	exit(1);
    }
    return fp;
}


					/* PERFORMANCE METER - DISPLAYS
					   THE PROGRESS OF THE MOVING WINDOW
					   AS A COUNT AND ESTIMATED COMPLETION
					   TIME WHILE THE PROGRAM RUNS */

void meter2(int n, int i, int div)
{
    long current_time, time_left, elapsed, complete;
    static long start;
    float window_time;
    static int k = 0;
    char done2[30];
    int d;


    if (i <= 1) {
	time(&start);
    }

    if (i < 10)
	d = 1;
    else
	d = div;

    if (k > 2000) {
	if (fseek(stdout, 0L, 0))
	    G_fatal_error("Can't reset the \"stdout\", exit.\n");
	k = 0;
    }

    if ((n - i) % d == 0) {
	time(&current_time);
	elapsed = current_time - start;
	window_time = ((float)elapsed) / (i + 1);
	time_left = (long)((n - i) * window_time);
	complete = current_time + time_left;
	strncpy(done2, asctime(localtime(&complete)), 24);
	done2[24] = '\0';
	fprintf(stdout, "WINDOWS LEFT  = %8d     EST. COMPLETION = %s\r",
		(n - i), done2);
	fflush(stdout);
	k++;
    }
    return;
}


					/* READ IN THE MOVING WINDOW
					   PARAMETERS */

void read_mwind(int *uw, int *ul, int *nc, int *nr, int *x0, int *y0,
		float *radius)
{
    FILE *fp;
    int ww, wl;
    char *buf;

    fp = fopen1("r.le.para/move_wind", "r");
    buf = G_malloc(513);

    fgets(buf, 512, fp);
    sscanf(buf, "%d%d", uw, ul);

    fgets(buf, 512, fp);
    sscanf(buf, "%f", radius);

    fgets(buf, 512, fp);
    sscanf(buf, "%d%d", &ww, &wl);

    fgets(buf, 512, fp);
    sscanf(buf, "%d%d", x0, y0);

    *nc = ww - *uw + 1;
    *nr = wl - *ul + 1;

    G_free(buf);
    fclose(fp);

    return;
}


					/* READ IN THE SAMPLING UNIT 
					   PARAMETERS AND RUN R.LE.PIXEL */

void unit_driver()
{
    register int i, j, k, m;
    int top, left, u_w, u_l, nscl, nu, fd, *tmp;
    float *ftmp;
    double *richwhole, *dtmp;
    char *nul_buf;
    char *buf, unitname[10], istr[3];
    int cntwhole = 0;
    FILE *fp;
    CELL **units, *unit_buf;
    float radius = 0.0;
    struct Cell_head wind;


    G_get_set_window(&wind);
    fp = fopen1("r.le.para/units", "r");

    buf = G_malloc(513);

    /* get the number of scales */

    fgets(buf, 512, fp);
    sscanf(buf, "%d", &nscl);


    if (choice->edg[2] || choice->jux[0]) {

	/* dynamically allocate memory for
	   the richness array */

	richwhole = (double *)G_calloc(MAX, sizeof(double));

	/* initialize the richness array
	   elements with the value -999 */

	for (i = 0; i < MAX; i++)
	    richwhole[i] = -999.0;

	switch (data_type) {
	case CELL_TYPE:
	    tmp = G_allocate_raster_buf(CELL_TYPE);
	    break;
	case FCELL_TYPE:
	    ftmp = G_allocate_raster_buf(FCELL_TYPE);
	    break;
	case DCELL_TYPE:
	    dtmp = G_allocate_raster_buf(DCELL_TYPE);
	    break;
	}

	nul_buf = G_allocate_null_buf();

	/* go through the search area
	   pixel by pixel */

	for (i = 0; i < wind.rows; i++) {

	    switch (data_type) {
	    case (CELL_TYPE):
		G_zero_raster_buf(tmp, CELL_TYPE);
		G_get_raster_row(finput, tmp, i, CELL_TYPE);
		break;
	    case (FCELL_TYPE):
		G_zero_raster_buf(ftmp, FCELL_TYPE);
		G_get_raster_row(finput, ftmp, i, FCELL_TYPE);
		break;
	    case (DCELL_TYPE):
		G_zero_raster_buf(dtmp, DCELL_TYPE);
		G_get_raster_row(finput, dtmp, i, DCELL_TYPE);
		break;
	    }

	    G_get_null_value_row(finput, nul_buf, i);


	    for (j = 0; j < wind.cols; j++) {

		/* if the raster value is not null,
		   call get_rich_whole to tally up the
		   number of different attributes
		   in the search area and fill
		   the richness array with those
		   attributes */
		switch (data_type) {
		case (CELL_TYPE):
		    if ((*(tmp + j) ||
			 *(tmp + j) == 0) && *(nul_buf + j) == 0.0)
			get_rich_whole((double)*(tmp + j), richwhole,
				       &cntwhole);
		    break;
		case (FCELL_TYPE):
		    if ((*(ftmp + j) ||
			 *(ftmp + j) == 0) && *(nul_buf + j) == 0.0)
			get_rich_whole((double)*(ftmp + j), richwhole,
				       &cntwhole);
		    break;
		case (DCELL_TYPE):
		    if ((*(dtmp + j) ||
			 *(dtmp + j) == 0) && *(nul_buf + j) == 0.0)
			get_rich_whole(*(dtmp + j), richwhole, &cntwhole);
		    break;
		}
	    }
	}
	switch (data_type) {
	case (CELL_TYPE):
	    G_free(tmp);
	    break;
	case (FCELL_TYPE):
	    G_free(ftmp);
	    break;
	case (DCELL_TYPE):
	    G_free(dtmp);
	    break;
	}
	G_free(nul_buf);
	G_free(richwhole);
    }

    /* dynamically allocate storage for the
       buffer that will hold the map of the
       sampling units */

    if (choice->units) {
	units = (CELL **) G_calloc(wind.rows + 3, sizeof(CELL *));
	for (i = 0; i < wind.rows + 3; i++)
	    units[i] = (CELL *) G_calloc(wind.cols + 3, sizeof(CELL));
    }

    /* for each scale */

    for (i = 0; i < nscl; i++) {
	g_scale = i + 1;
	fgets(buf, 512, fp);
	sscanf(buf, "%d", &nu);

	/* get the width and length */

	fgets(buf, 512, fp);
	sscanf(buf, "%d%d", &u_w, &u_l);

	/* get the radius to see if sampling
	   units are circles */

	fgets(buf, 512, fp);
	sscanf(buf, "%f", &radius);

	/* if units map was chosen, zero it,
	   then copy the number of the map
	   to the end of the word "units" */

	if (choice->units) {
	    for (k = 0; k < wind.rows + 3; k++) {
		for (m = 0; m < wind.cols + 3; m++)
		    *(*(units + k) + m) = 0;
	    }

	    if (i == 0)
		G_strcpy(istr, "1");
	    else if (i == 1)
		G_strcpy(istr, "2");
	    else if (i == 2)
		G_strcpy(istr, "3");
	    else if (i == 3)
		G_strcpy(istr, "4");
	    else if (i == 4)
		G_strcpy(istr, "5");
	    else if (i == 5)
		G_strcpy(istr, "6");
	    else if (i == 6)
		G_strcpy(istr, "7");
	    else if (i == 7)
		G_strcpy(istr, "8");
	    else if (i == 8)
		G_strcpy(istr, "9");
	    else if (i == 9)
		G_strcpy(istr, "10");
	    else if (i == 10)
		G_strcpy(istr, "11");
	    else if (i == 11)
		G_strcpy(istr, "12");
	    else if (i == 12)
		G_strcpy(istr, "13");
	    else if (i == 13)
		G_strcpy(istr, "14");
	    else if (i == 14)
		G_strcpy(istr, "15");
	    else if (i > 14) {
		fprintf(stdout, "\n");
		fprintf(stdout,
			"   ***************************************************\n");
		fprintf(stdout,
			"    You cannot choose more than 15 scales             \n");
		fprintf(stdout,
			"   ***************************************************\n");
		exit(0);
	    }
	}

	/* for each unit */

	for (j = 0; j < nu; j++) {
	    g_unit = j + 1;
	    fgets(buf, 512, fp);
	    sscanf(buf, "%d%d", &left, &top);

	    /* call cell_clip driver */

	    run_clip(wind.cols, wind.rows, u_w, u_l, left, top, units, j,
		     cntwhole, radius);
	}

	/* if a map of the sampling units
	   was requested */

	if (choice->units) {
	    G_strcpy(unitname, "units_");
	    G_strcat(unitname, istr);
	    fd = G_open_raster_new(unitname, CELL_TYPE);
	    unit_buf = G_allocate_raster_buf(CELL_TYPE);
	    for (k = 1; k < wind.rows + 1; k++) {
		G_zero_raster_buf(unit_buf, CELL_TYPE);
		G_set_null_value(unit_buf, wind.cols + 1, CELL_TYPE);
		for (m = 1; m < wind.cols + 3; m++) {
		    if (*(*(units + k) + m))
			*(unit_buf + m - 1) = *(*(units + k) + m);
		}
		G_put_raster_row(fd, unit_buf, CELL_TYPE);
	    }
	    G_close_cell(fd);
	    G_free(unit_buf);
	}
    }

    if (choice->units) {
	for (m = 0; m < wind.rows + 3; m++)
	    G_free(units[m]);
	G_free(units);
    }
    G_free(buf);
    fclose(fp);
    return;
}





					/* CHECK FOR OUT-OF MAP UNIT, THEN
					   CALL CELL CLIP DRIVER */


void run_clip(int ncols, int nrows, int u_w, int u_l, int left, int top,
	      CELL ** units, int id, int cntwhole, float radius)
{
    int i, j;
    double center_row, center_col;
    double dist;

    G_sleep_on_error(0);

    /* check unit */

    if (ncols < left + u_w || nrows < top + u_l) {
	fprintf(stdout, "\n");
	fprintf(stdout,
		"   ******************************************************\n");
	fprintf(stdout,
		"    Sampling units do not fit within the current region. \n");
	fprintf(stdout,
		"    Either correct the region or redo the sampling unit  \n");
	fprintf(stdout,
		"    selection using r.le.setup.  This error message came \n");
	fprintf(stdout,
		"    from an analysis of the r.le.para/units file and the \n");
	fprintf(stdout,
		"    current region setting.                              \n");
	fprintf(stdout,
		"   ******************************************************\n");
	exit(1);
    }

    if (choice->units) {
	if (radius) {
	    center_row = ((double)(top + 1) + ((double)u_l - 1) / 2);
	    center_col = ((double)(left + 1) + ((double)u_w - 1) / 2);

	    for (i = top + 1; i < top + 1 + u_l; i++) {
		for (j = left + 1; j < left + 1 + u_w; j++) {
		    dist =
			sqrt(((double)i - center_row) * ((double)i -
							 center_row) +
			     ((double)j - center_col) * ((double)j -
							 center_col));
		    if (dist < radius) {
			*(*(units + i) + j) = id + 1;
			/*printf("units[%d][%d]=%d id=%d\n",i,j, *(*(units + i) + j),id + 1);  */
		    }
		}
	    }
	}
	else {
	    for (i = top + 1; i < top + 1 + u_l; i++) {
		for (j = left + 1; j < left + 1 + u_w; j++)
		    *(*(units + i) + j) = id + 1;
	    }
	}
    }

    cell_clip_drv(left, top, u_w, u_l, NULL, 0, cntwhole, radius);

    return;
}





					/* CLIP THE REGION, THEN
					   RUN R.LE.PIXEL */


void whole_reg_driver()
{
    register int i, j;
    int *row_buf, regcnt, found, fr, nrows, ncols, cntwhole = 0, *tmp;
    float *ftmp;
    double *richwhole, *dtmp;
    char *nul_buf;
    REGLIST *ptrfirst, *ptrthis, *ptrnew;
    RASTER_MAP_TYPE data_type;

    data_type = G_raster_map_type(choice->fn, G_mapset());

    nrows = G_window_rows();
    ncols = G_window_cols();

    g_scale = 1;

    if (choice->edg[2] || choice->jux[0]) {

	/* dynamically allocate memory for
	   the richness array */

	richwhole = (double *)G_calloc(MAX, sizeof(double));

	/* initialize the richness array
	   elements with the value -999 */

	for (i = 0; i < MAX; i++)
	    richwhole[i] = -999.0;

	/* allocate memory to store a row of the
	   raster map, depending on the type of
	   input raster map; keep track of the
	   name of the buffer for each raster type */

	switch (data_type) {
	case CELL_TYPE:
	    tmp = G_allocate_raster_buf(CELL_TYPE);
	    break;
	case FCELL_TYPE:
	    ftmp = G_allocate_raster_buf(FCELL_TYPE);
	    break;
	case DCELL_TYPE:
	    dtmp = G_allocate_raster_buf(DCELL_TYPE);
	    break;
	}

	nul_buf = G_allocate_null_buf();

	/* go through the search area
	   pixel by pixel */

	for (i = 0; i < nrows; i++) {

	    switch (data_type) {
	    case (CELL_TYPE):
		G_zero_raster_buf(tmp, CELL_TYPE);
		G_get_raster_row(finput, tmp, i, CELL_TYPE);
		break;
	    case (FCELL_TYPE):
		G_zero_raster_buf(ftmp, FCELL_TYPE);
		G_get_raster_row(finput, ftmp, i, FCELL_TYPE);
		break;
	    case (DCELL_TYPE):
		G_zero_raster_buf(dtmp, DCELL_TYPE);
		G_get_raster_row(finput, dtmp, i, DCELL_TYPE);
		break;
	    }

	    G_get_null_value_row(finput, nul_buf, i);


	    for (j = 0; j < ncols; j++) {

		/* if the raster value is not null,
		   call get_rich_whole to tally up the
		   number of different attributes
		   in the search area and fill
		   the richness array with those
		   attributes */

		switch (data_type) {
		case (CELL_TYPE):
		    if ((*(tmp + j) ||
			 *(tmp + j) == 0) && *(nul_buf + j) == 0.0)
			get_rich_whole((double)*(tmp + j), richwhole,
				       &cntwhole);
		    break;
		case (FCELL_TYPE):
		    if ((*(ftmp + j) ||
			 *(ftmp + j) == 0.0) && *(nul_buf + j) == 0.0)
			get_rich_whole((double)*(ftmp + j), richwhole,
				       &cntwhole);
		    break;
		case (DCELL_TYPE):
		    if ((*(dtmp + j) ||
			 *(dtmp + j) == 0.0) && *(nul_buf + j) == 0.0)
			get_rich_whole(*(dtmp + j), richwhole, &cntwhole);
		    break;
		}
	    }
	}
	switch (data_type) {
	case (CELL_TYPE):
	    G_free(tmp);
	    break;
	case (FCELL_TYPE):
	    G_free(ftmp);
	    break;
	case (DCELL_TYPE):
	    G_free(dtmp);
	    break;
	}
	G_free(nul_buf);
	G_free(richwhole);
    }

    if (choice->wrum != 'r') {
	cell_clip_drv(0, 0, ncols, nrows, NULL, 0, cntwhole, 0.0);
    }
    else {
	regcnt = 0;
	fr = G_open_cell_old(choice->reg, G_mapset());
	row_buf = G_allocate_raster_buf(CELL_TYPE);
	for (i = 0; i < nrows; i++) {
	    G_zero_raster_buf(row_buf, CELL_TYPE);
	    G_get_raster_row(fr, row_buf, i, CELL_TYPE);
	    for (j = 0; j < ncols; j++) {
		if (*(row_buf + j)) {
		    if (regcnt == 0)
			ptrfirst = (REGLIST *) NULL;
		    ptrthis = ptrfirst;
		    found = 0;
		    while (ptrthis) {
			if (*(row_buf + j) == ptrthis->att) {
			    if (j < ptrthis->w)
				ptrthis->w = j;
			    if (j > ptrthis->e)
				ptrthis->e = j;
			    if (i < ptrthis->n)
				ptrthis->n = i;
			    if (i > ptrthis->s)
				ptrthis->s = i;
			    found = 1;
			}
			ptrthis = ptrthis->next;
		    }
		    if (!found) {
			ptrnew = (REGLIST *) G_calloc(1, sizeof(REGLIST));
			if (ptrfirst == (REGLIST *) NULL)
			    ptrfirst = ptrthis = ptrnew;
			else {
			    ptrthis = ptrfirst;
			    while (ptrthis->next != (REGLIST *) NULL)
				ptrthis = ptrthis->next;
			    ptrthis->next = ptrnew;
			    ptrthis = ptrnew;
			}
			ptrthis->att = *(row_buf + j);
			ptrthis->n = i;
			ptrthis->s = i;
			ptrthis->e = j;
			ptrthis->w = j;
			regcnt++;
		    }
		}
	    }
	}
	g_unit = 0;
	ptrthis = ptrfirst;
	while (ptrthis) {
	    g_unit = ptrthis->att;
	    cell_clip_drv(ptrthis->w, ptrthis->n, ptrthis->e - ptrthis->w + 1,
			  ptrthis->s - ptrthis->n + 1, NULL, ptrthis->att,
			  cntwhole, 0.0);
	    ptrthis = ptrthis->next;
	}
	G_close_cell(fr);
	G_free(row_buf);
	G_free(ptrnew);
    }

    return;
}






					/* FIND UNCOUNTED ATTRIBUTES, 
					   COUNT THEM UP, AND ADD THEM TO
					   THE RICHNESS ARRAY IN UNSORTED
					   ORDER */

void get_rich_whole(double att, double rich[], int *cnt)
{
    register int i;

    /* if this attribute is already
       in the richness array, then
       return */

    for (i = 0; i < *cnt; i++)
	if (att == rich[i])
	    break;


    /* if this attribute is not already
       in the richness array, then make
       it the "cnt" element of the 
       array, then increment the cnt */

    if (i >= *cnt) {
	rich[*cnt] = att;
	++(*cnt);
	/*printf("rich[%d]=%f\n",*cnt,att);  */
    }

    return;
}
