Floating-Point / NULL Values in GRASS Raster Maps

STATUS: I am presently working on defining the upgrades to existing GRASS programs and any input would be very helpful. Please email suggestions to olga@zorro.

Contents

Objectives
Design decisions
C-API
Upgrades to existing programs
New programs

1. Objectives

2. Design decisions

This section describes some of the design decisions that have been made so far.

2.1 Floating-point maps

2.2 NULL-values

3. C-API

Contents of this section
Changes to "gis.h"
New NULL-value functions
New floating-point and type independant functions
Upgrades to raster functions
Color functions (new and upgraded)
Range functions (new and upgraded)
Upgraded Cell_stats functions
New Quantization functions
New and upgraded struct Categories interface functions
Deprecated functions

3.1. Changes to "gis.h"

The "gis.h" will contain 5 new items
	typedef float FCELL
	typedef double DCELL

	typedef int RASTER_MAP_TYPE;
	#define CELL_TYPE 0
	#define FCELL_TYPE 1
	#define DCELL_TYPE 2

Also gis.h will contain the definitions for new structures:
      struct FPReclass;
      struct FPRange;
      struct Quant;
Some of the old structures such as
      struct Categories
      struct Cell_stats;
      struct Range;
      struct _Color_Rule_;
      struct _Color_Info_;
      struct Colors;
were modified, so it is very important to use functional interface to access and set elements of these structures instead of accessing elements of the structures directly. Because some former elements such as for example (struct Range range.pmin ) do not exist anymore. I made sure non of the former elements have different meaning, so that the programs which do access the old elements directly either do not compile or work exactly the same way as prior to change.

3.2. New NULL-value functions

G_set_null_value (void *rast, int count, RASTER_MAP_TYPE data_type)
If the data_type is CELL_TYPE, calls G_set_c_null_value((CELL *) rast, count);

If the data_type is FCELL_TYPE, calls G_set_f_null_value((FCELL *) rast, count);

If the data_type is DCELL_TYPE, calls G_set_d_null_value((DCELL *) rast, count);

G_set_c_null_value (CELL *cell, int count)
Set the count elements in the cell array to the NULL value (the largest positive integer).

G_set_f_null_value (FCELL *fcell, int count)
Set the count elements in the fcell array to the NULL value (a bit pattern for a float NaN - 32 bits of 1's).

G_set_d_null_value (DCELL *dcell, int count)
Set the count elements in the dcell array to the NULL value - which (a bit pattern for a double NaN - 64 bits of 1's).

G_insert_null_values (rast, flags, count, data_type)
void *rast;
char *flags;
int count;
RASTER_MAP_TYPE data_type;
If the data_type is CELL_TYPE, calls G_insert_c_null_values ((CELL *) rast, flags, count);

If the data_type is FCELL_TYPE, calls G_insert_f_null_values ((FCELL *) rast, flags, count);

If the data_type is DCELL_TYPE, calls G_insert_d_null_values ((DCELL *) rast, flags, count);

G_insert_c_null_values (cell, flags, count)
CELL *cell;
char *flags;
int count;
For each of the count flags which is true(!=0), set the corresponding cell to the NULL value.

G_insert_f_null_values (fcell, flags, count)
FCELL *fcell;
char *flags;
int count;
For each of the count flags which is true(!=0), set the corresponding fcell to the NULL value.

G_insert_d_null_values (dcell, flags, count)
DCELL *dcell;
char *flags;
int count;
For each for the count flag which is true(!=0), set the corresponding dcell to the NULL value.

G_is_null_value (void *rast, RASTER_MAP_TYPE data_type)
If the data_type is CELL_TYPE, calls G_is_c_null_value ((CELL *) rast);

If the data_type is FCELL_TYPE, calls G_is_f_null_value (*(FCELL *) rast);

If the data_type is DCELL_TYPE, calls G_is_d_null_value ((DCELL *) rast);

G_is_c_null_value (CELL *cell)
Returns 1 if cell is NULL, 0 otherwise. This will test if the value cell is the largest int.

G_is_f_null_value (FCELL *fcell)
Returns 1 if fcell is NULL, 0 otherwise. This will test if the value fcell is a NaN. It isn't good enough to test for a particular NaN bit pattern since the machine code may change this bit pattern to a different NaN. The test will be

	if(fcell==0.0) return 0;
        if(fcell>0.0) return 0;
	if(fcell<0.0) return 0;
        return 1;
	
or (as suggested by Mark Line)
        return (fcell != fcell);
	

G_is_d_null_value (DCELL *dcell)
Returns 1 if dcell is NULL, 0 otherwise. This will test if the value dcell is a NaN. Same test as in G_is_f_null_value().

char *G_allocate_null_buf()
Allocate an array of char based on the number of columns in the current region.

G_get_null_value_row (int fd, char *flags, int row)
Reads a row from NULL value bitmap file for the raster map open for read on fd. If there is no bitmap file, then this routine simulates the read as follows: non-zero values in the raster map correspond to non-NULL; zero values correspond to NULL. When MASk exists, masked cells are set to null. flags is a resulting array of 0's and 1's where 1 corresponds to "no data" cell.

3.2. New Floating-point and type-independant functions

G_raster_map_is_fp(char *name, char *mapset)
Returns true(1) if raster map name in mapset is a floating-point dataset; false(0) otherwise

G_raster_map_type(char *name, char *mapset)
Returns the storage type for raster map name in mapset: CELL_TYPE (int); FCELL_TYPE (float); or DCELL_TYPE (double)

G_open_raster_new[_uncompressed](char *name, RASTER_MAP_TYPE map_type)
If map_type == CELL_TYPE, calls G_open_map_new[_uncompressed](name);

If map_type == FCELL_TYPE, calls G_set_fp_type (FCELL_TYPE); G_open_fp_map_new[_uncompressed](name);

If map_type == DCELL_TYPE, calls G_set_fp_type (DCELL_TYPE); G_open_fp_map_new[_uncompressed](name);

The use of this routine by applications is discouraged since its use would override user preferences (what precision to use).

G_set_fp_type (RASTER_MAP_TYPE type)
This controls the storage type for floating-point maps. It affects subsequent calls to G_open_fp_map_new(). The type must be one of FCELL_TYPE (float) or DCELL_TYPE (double). The use of this routine by applications is discouraged since its use would override user preferences.

G_open_fp_map_new (char *name)
Opens a new floating-point raster map (in .tmp) and returns a file descriptor. The storage type (float or double) is determined by the last call to G_set_fp_type() or the default (float - unless the Unix env variable GRASS_FP_DOUBLE is set).

void *G_allocate_raster_buf(RASTER_MAP_TYPE data_type)
Allocate an array of CELL, FCELL, or DCELL (depending on data_type) based on the number of columns in the current region.

CELL *G_allocate_c_raster_buf()
Allocate an array of CELL based on the number of columns in the current region.

FCELL *G_allocate_f_raster_buf()
Allocate an array of FCELL based on the number of columns in the current region.

DCELL *G_allocate_d_raster_buf()
Allocate an array of DCELL based on the number of columns in the current region.

void *G_incr_void_ptr (void *ptr, int size)
Advances void pointer by n bytes. returns new pointer value. Usefull in raster row processing loops, substitutes CELL *cell; cell += n; Now rast = G_incr_void_ptr(rast, G_raster_size(data_type)) (where rast is void* and data_type is RASTER_MAP_TYPE can be used instead of rast++.) very usefull to generalize the row processing - loop (i.e. void * buf_ptr += G_raster_size(data_type)

int G_raster_size (RASTER_MAP_TYPE data_type)
If data_type is CELL_TYPE, returns sizeof(CELL)

If data_type is FCELL_TYPE, returns sizeof(FCELL)

If data_type is DCELL_TYPE, returns sizeof(DCELL)

int G_raster_cmp (void *p, *q, RASTER_MAP_TYPE data_type)
compares raster vlues p and q. Returns 1 if p > q or only q is null value -1 if p < q or only p is null value 0 if p == q or p==q==null value

int G_raster_cpy (void *p, *q, RASTER_MAP_TYPE data_type)
copies raster vlues q into p. If q is null value, sets q to null value.

G_set_raster_value_c (void *p, CELL val, RASTER_MAP_TYPE data_type)
If G_is_c_null_value(val) is true, sets p to null value. Converts CELL val to data_type (type of p) and stores result in p. Used for assigning CELL values to raster cells of any type.

G_set_raster_value_f (void *p, FCELL val, RASTER_MAP_TYPE data_type)
If G_is_f_null_value(val) is true, sets p to null value. Converts FCELL val to data_type (type of p) and stores result in p. Used for assigning FCELL values to raster cells of any type.

G_set_raster_value_d (void *p, DCELL val, RASTER_MAP_TYPE data_type)
If G_is_d_null_value(val) is true, sets p to null value. Converts DCELL val to data_type (type of p) and stores result in p. Used for assigning DCELL values to raster cells of any type.

CELL G_get_raster_value_c (void *p, RASTER_MAP_TYPE data_type)
Retrieves the value of type data_type from pointer p, converts it to CELL type and returns the result. If null value is stored in p, returns CELL null value. Used for retreiving CELL values from raster cells of any type. NOTE: when data_type != CELL_TYPE, no quantization is used, only type conversion.

FCELL G_get_raster_value_f (void *p, RASTER_MAP_TYPE data_type)
Retrieves the value of type data_type from pointer p, converts it to FCELL type and returns the result. If null value is stored in p, returns FCELL null value. Used for retreiving FCELL values from raster cells of any type.

DCELL G_get_raster_value_d (void *p, RASTER_MAP_TYPE data_type)
Retrieves the value of type data_type from pointer p, converts it to DCELL type and returns the result. If null value is stored in p, returns DCELL null value. Used for retreiving DCELL values from raster cells of any type.

G_get_raster_row (int fd, void *rast, int row, RASTER_MAP_TYPE data_type)
If data_type is CELL_TYPE, calls G_get_c_raster_row(fd, (CELL *) rast, row);

If data_type is FCELL_TYPE, calls G_get_f_raster_row(fd, (FCELL *) rast, row);

If data_type is DCELL_TYPE, calls G_get_d_raster_row(fd, (DCELL *) rast, row);

G_get_raster_row_nomask (fd, fcell, row, map_type)
int fd;
FCELL *fcell;
int row;
RASTER_MAP_TYPE map_type;
Same as G_get_f_raster_row() except no masking occurs.

G_get_f_raster_row (int fd, FCELL fcell, int row)
Read a row from the raster map open on fd into the float array fcell performing type conversions as necessary based on the actual storage type of the map. Masking, resampling into the current region. NULL-values are always embedded in fcell (never converted to a value).

G_get_f_raster_row_nomask (fd, fcell, row)
int fd;
FCELL *fcell;
int row;
Same as G_get_f_raster_row() except no masking occurs.

G_get_d_raster_row (int fd, DCELL dcell, int row)
Same as G_get_f_raster_row() except that the array dcell is double.

G_get_d_raster_row_nomask (fd, dcell, row)
int fd;
DCELL *dcell;
int row;
Same as G_get_d_raster_row() except no masking occurs.

G_get_c_raster_row (int fd, CELL buf, int row)

Reads a row of raster data and leaves the NULL values intact. (As opposed to the deprecated function G_get_map_row() which converts NULL values to zero.) NOTE: when the raster map is old and null file doesn't exist, it is assumed that all 0-cells are no-data. When map is floating point, uses quant rules set explicitly by G_set_quant_rules or stored in map's quant file to convert floats to integers.

G_get_c_raster_row_nomask (int fd, CELL buf, int row)

Same as G_get_c_raster_row() except no masking occurs.

G_put_raster_row (int fd, void *rast, RASTER_MAP_TYPE data_type)
If data_type is CELL_TYPE, calls G_put_c_raster_row(fd, (CELL *) rast);

If data_type is FCELL_TYPE, calls G_put_f_raster_row(fd, (FCELL *) rast);

If data_type is DCELL_TYPE, calls G_put_d_raster_row(fd, (DCELL *) rast);

G_put_f_raster_row (int fd, FCELL *fcell)
Write the next row of the raster map open on fd from the float array fcell, performing type conversion to the actual storage type of the resultant map. Keep track of the range of floating-point values. Also writes the NULL-value bitmap from the NULL-values embedded in the fcell array.

G_put_d_raster_row (int fd, DCELL *dcell)
Same as G_put_f_raster_row() except that the array dcell is double.

G_put_c_raster_row (int fd, CELL buf)
Writes a row of raster data and a row of the null-value bitmap, only treating NULL as NULL. (As opposed to the deprecated function G_put_map_row() which treats zero values also as NULL.)

G_zero_raster_row (void *rast, RASTER_MAP_TYPE data_type)
Depending on data_type zeroes out G_window_cols() CELLs, FCELLs, or DCELLs stored in cell buffer.

3.3. Upgrades to Raster Functions

These routines will be modified (internally) to work with floating-point and NULL-values.

These routines are in the GISLIB.

G_close_cell()
If the map is a new floating point, move the .tmp file into the fcell element, create an empty file in the cell directory; write the floating-point range file; write a default quantization file quantization file is set here to round fp numbers (this is a default for now). create an empty category file, with max cat = max value (for backwards compatibility). Move the .tmp NULL-value bitmap file to the cell_misc directory.

G_open_cell_old()
Arrange for the NULL-value bitmap to be read as well as the raster map. If no NULL-value bitmap exists, arrange for the production of NULL-values based on zeros in the raster map.

If the map is floating-point, arrange for quantization to integer for G_get_c_raster_row(), et. al., by reading the quantization rules for the map using G_read_quant().

If the programmer wants to read the floating point map using uing quant rules other than the ones stored in map's quant file, he should call G_set_quant_rules() after the call to G_open_cell_old().

G_get_map_row()
If the map is floating-point, quantize the floating-point values to integer using the quantization rules established for the map when the map was opened for reading (this quantization is read from cell_misc/name/f_quant file, but can be reset after opening raster map by G_set_quant_rules()).

NULL values are converted to zeros.

This routine is deprecated .

G_put_map_row()
Zero values are converted to NULLs. Write a row of the NULL value bit map.

This routine is deprecated .

These routines are in the D_LIB.

Dcell()
If the map is a floating-point map, read the map using G_get_d_map_row() and plot using D_draw_d_cell(). If the map is an integer map, read the map using G_get_c_raster_row() and plot using D_draw_cell().

3.4. Color Functions (new and upgraded)

3.4.0 Upgraded Colors structures

struct _Color_Rule_
{
    struct
    {
	DCELL value;
	unsigned char red,grn,blu;
    } low, high;
    struct _Color_Rule_ *next;
    struct _Color_Rule_ *prev;
};

struct _Color_Info_
{
    struct _Color_Rule_ *rules;
    int n_rules;
    struct
    {
	unsigned char *red;
	unsigned char *grn;
	unsigned char *blu;
	unsigned char *set;
	int nalloc;
	int active;
    } lookup;
    struct
    {
        DCELL *vals;
	/* pointers to color rules corresponding to the intervals btwn vals */
	struct _Color_Rule_ **rules;
	int nalloc;
	int active;
    } fp_lookup;
    DCELL min, max;
};

struct Colors
{
    int version;	/* set by read_colors: -1=old,1=new */
    DCELL shift;
    int invert;
    int is_float;             /* defined on floating point raster data? */
    int null_set; /* the colors for null are set? */
    unsigned char null_red, null_grn, null_blu;
    int undef_set; /* the colors for cells not in range are set? */
    unsigned char undef_red, undef_grn, undef_blu;
    struct _Color_Info_ fixed, modular;
    DCELL cmin, cmax;
};

3.4.1 New functions to support colors for floating-point.

These routines are in the GISLIB.

G_lookup_raster_colors (rast, r, g, b, set, n, colors, cell_type)
void *rast;
char *r, *g, *b, *set;
int n;
struct Colors *colors;
RASTER_MAP_TYPE cell_type;
If the cell_type is CELL_TYPE, calls G_lookup_colors((CELL *)cell, r, g, b, set, n, colors);

If the cell_type is FCELL_TYPE, calls G_lookup_f_raster_colors(FCELL *)cell, r, g, b, set, n, colors);

If the cell_type is DCELL_TYPE, calls G_lookup_d_raster_colors(DCELL *)cell, r, g, b, set, n, colors);

G_lookup_c_raster_colors (cell, r, g, b, set, n, colors)
CELL *cell;
char *r, *g, *b, *set;
int n;
struct Colors *colors;
The same as G_lookup_colors(cell, r, g, b, set, n, colors).

G_lookup_f_raster_colors (fcell, r, g, b, set, n, colors)
FCELL *fcell;
char *r, *g, *b, *set;
int n;
struct Colors *colors;
Converts the n floating-point values in the fcell array to their r,g,b color components. Embedded NULL-values are handled properly as well.

G_lookup_d_raster_colors (dcell, r, g, b, set, n, colors)
DCELL *dcell;
char *r, *g, *b, *set;
int n;
struct Colors *colors;
Converts the n floating-point values in the dcell array to their r,g,b color components. Embedded NULL-values are handled properly as well.

G_add_raster_color_rule (v1, r1, g1, b1, v2, r2, g2, b2, colors, map_type)
void *v1, *v2;
int r1, g1, b1;
int r2, g2, b2;
struct Colors *colors;
RASTER_MAP_TYPE map_type;
If map_type is CELL_TYPE, calls G_add_c_raster_color_rule ((CELL *) v1, r1, g1, b1, (CELL *) v2, r2, g2, b2, colors);

If map_type is FCELL_TYPE, calls G_add_f_raster_color_rule ((FCELL *) v1, r1, g1, b1, (FCELL *) v2, r2, g2, b2, colors);

If map_type is DCELL_TYPE, calls G_add_d_raster_color_rule ((DCELL *) v1, r1, g1, b1, (DCELL *) v2, r2, g2, b2, colors);

G_add_c_raster_color_rule (v1, r1, g1, b1, v2, r2, g2, b2, colors)
CELL *v1, *v2;
int r1, g1, b1;
int r2, g2, b2;
struct Colors *colors;
Calls G_add_color_rule(*v1, r1, g1, b1, *v2, r2, g2, b2, colors).

G_add_f_raster_color_rule (v1, r1, g1, b1, v2, r2, g2, b2, colors)
FCELL *v1, *v2;
int r1, g1, b1;
int r2, g2, b2;
struct Colors *colors;
Adds the floating-point rule that the range [v1,v2] gets a linear ramp of colors from [r1,g1,b1] to [r2,g2,b2].

If either v1 or v2 is the NULL-value, this call is converted into G_set_null_value_color (r1, g1, b1, colors)

G_add_d_raster_color_rule (v1, r1, g1, b1, v2, r2, g2, b2, colors)
DCELL *v1, *v2;
int r1, g1, b1;
int r2, g2, b2;
struct Colors *colors;
Adds the floating-point rule that the range [v1,v2] gets a linear ramp of colors from [r1,g1,b1] to [r2,g2,b2].

If either v1 or v2 is the NULL-value, this call is converted into G_set_null_value_color (r1, g1, b1, colors)

G_get_raster_color (v, r, g, b, colors, data_type)
void *v;
int *r, *g, *b;
struct Colors *colors;
RASTER_MAP_TYPE data_type;
Looks up the rgb colors for v in the color table colors

G_get_c_raster_color (v, r, g, b, colors)
CELL *v;
int *r, *g, *b;
struct Colors *colors;
Calls G_get_color(*v, r, g, b, colors).

G_get_f_raster_color (v, r, g, b, colors)
FCELL *v;
int *r, *g, *b;
struct Colors *colors;
Looks up the rgb colors for v in the color table colors

G_get_d_raster_color (v, r, g, b, colors)
DCELL *v;
int *r, *g, *b;
struct Colors *colors;
Looks up the rgb colors for v in the color table colors

G_set_raster_color (v, r, g, b, colors, data_type)
void *v;
int r, g, b;
struct Colors *colors;
RASTER_MAP_TYPE data_type;
calls G_add_raster_color_rule (v, r, g, b, v, r, g, r, colors, data_type);

G_set_c_raster_color (v, r, g, b, colors)
CELL *v;
int r, g, b;
struct Colors *colors;
Calls G_set_color(*v, r, g, b, colors).

G_set_f_raster_color (v, r, g, b, colors)
FCELL *v;
int r, g, b;
struct Colors *colors;
Inserts a rule that assigns the color r,g,b to v. It is implemented as:

G_add_f_raster_color_rule (v, r, g, b, v, r, g, r, colors);

G_set_d_raster_color (v, r, g, b, colors)
DCELL *v;
int r, g, b;
struct Colors *colors;
Inserts a rule that assigns the color r,g,b to v. It is implemented as:

G_add_d_raster_color_rule (v, r, g, b, v, r, g, r, colors);

G_mark_colors_as_fp (struct Colors *colors)
Sets a flag in the colors structure that indicates that these colors should only be looked up using floating-point raster data (not integer data).

In particular if this flag is set, the routine G_get_colors_min_max() should return min=-255^3 and max=255^3.

These routines are in the DISPLAYLIB.

D_raster_of_type (rast, ncols, nrows, colors, data_type)
void *rast;
int ncols, nrows;
struct Colors *colors;
RASTER_MAP_TYPE data_type;
If map_type is CELL_TYPE, calls D_raster((CELL *) rast, ncols, nrows, colors);

If map_type is FCELL_TYPE, calls D_f_raster((FCELL *) rast, ncols, nrows, colors);

If map_type is DCELL_TYPE, calls D_d_raster((DCELL *) rast, ncols, nrows, colors);

D_f_raster (fcell, ncols, nrows, colors)
FCELL *fcell;
int ncols, nrows;
struct Colors *colors;
Same functionality as D_raster() except that the fcell array is type FCELL. This implies that the floating-point interfaces to the colors are used by this routine.

D_d_raster (dcell, ncols, nrows, colors)
DCELL *dcell;
int ncols, nrows;
struct Colors *colors;
Same functionality as D_raster() except that the dcell array is type DCELL. This implies that the floating-point interfaces to the colors are used by this routine.

D_color_of_type (value, colors, data_type)
void *value;
struct Colors *colors;
RASTER_MAP_TYPE data_type;
If the data_type is CELL_TYPE, calls D_color((CELL *value, colors);

If the data_type is FCELL_TYPE, calls D_f_color((FCELL *value, colors);

If the data_type is DCELL_TYPE, calls D_d_color((DCELL *value, colors);

D_f_color (value, colors)
FCELL *value;
struct Colors *colors;
Same functionality as D_color() except that the value is type FCELL. This implies that the floating-point interfaces to the colors are used by this routine.

D_d_color (value, colors)
DCELL *value;
struct Colors *colors;
Same functionality as D_color() except that the value is type DCELL. This implies that the floating-point interfaces to the colors are used by this routine.

D_lookup_raster_colors (rast, colornum, n, colors, data_type)
void *rast;
int *colornum;
int n;
struct Colors *colors;
RASTER_MAP_TYPE data_type;
If the data_type is CELL_TYPE, calls D_lookup_c_raster_colors((CELL *) rast, colornum, n, colors);

If the data_type is FCELL_TYPE, calls D_lookup_f_raster_colors((FCELL *) rast, colornum, n, colors);

If the data_type is DCELL_TYPE, calls D_lookup_d_raster_colors((DCELL *) rast, colornum, n, colors);

D_lookup_c_raster_colors (dcell, colornum, n, colors)
CELL *cell;
int *colornum;
int n;
struct Colors *colors;
Same functionality as D_lookup_colors() except that the resultant color numbers are placed into a separate colornum array (which the caller must allocate).

D_lookup_f_raster_colors (fcell, colornum, n, colors)
FCELL *fcell;
int *colornum;
int n;
struct Colors *colors;
Same functionality as D_lookup_colors() except that the fcell array is type FCELL and that the resultant color numbers are placed into a separate colornum array (which the caller must allocate).

D_lookup_d_raster_colors (dcell, colornum, n, colors)
DCELL *dcell;
int *colornum;
int n;
struct Colors *colors;
Same functionality as D_lookup_colors() except that the dcell array is type DCELL and that the resultant color numbers are placed into a separate colornum array (which the caller must allocate).

D_draw_cell_of_type(A_row, xarray, colors, map_type)
int A_row;
DCELL *xarray;
struct Colors *colors;
RASTER_MAP_TYPE map_type;
If map_type is CELL_TYPE, calls D_draw_cell (A_row, (CELL *) xarray, colors);

If map_type is FCELL_TYPE, calls D_draw_f_cell (A_row, (FCELL *) xarray, colors);

If map_type is DCELL_TYPE, calls D_draw_d_cell (A_row, (DCELL *) xarray, colors);

D_draw_f_cell (A_row, xarray, colors)
int A_row;
FCELL *xarray;
struct Colors *colors;
Same functionality as D_draw_cell() except that the xarray array is type FCELL which implies a call to D_f_raster() instead of a call to D_raster().

D_draw_d_cell (A_row, xarray, colors)
int A_row;
DCELL *xarray;
struct Colors *colors;
Same functionality as D_draw_cell() except that the xarray array is type DCELL which implies a call to D_d_raster() instead of a call to D_raster().

3.4.2. New functions to support a color for the NULL-value.

G_set_null_value_color (r, g, b, colors)
int r, g, b;
struct Colors *colors;
Sets the color (in colors) for the NULL-value to r,g,b.

G_get_null_value_color (r, g, b, colors)
int *r, *g, *b;
struct Colors *colors;
Puts the red, green, and blue components of the color for the NULL-value into r,g,b.

3.4.3. New functions to support a default color.

G_set_default_color (r, g, b, colors)
int r, g, b;
struct Colors *colors;
Sets the default color (in colors) to r,g,b. This is the color for values which do not have an explicit rule.

G_get_default_color (r, g, b, colors)
int *r, *g, *b;
struct Colors *colors;
Puts the red, green, and blue components of the "default" color into r,g,b.

3.4.4. Upgraded color functions

G_read_colors()
This routine reads the rules from the color file. If the input raster map is is a floating-point map it calls G_mark_colors_as_fp().

G_write_colors()
The rules are written out using floating-point format, removing trailing zeros (possibly producing integers). The flag marking the colors as floating-point is not written.

G_get_colors_min_max()
If the color table is marked as "float", then return the minimum as -(255^3 * 128) and the maximum as (255^3 * 128). This is to simulate a very large range so that GRASS doesn't attempt to use colormode float to allow interactive toggling of colors.

G_lookup_colors()
Modified to return a color for NULL-values.

G_get_color()
Modified to return a color for the NULL-value.

3.4.5. Changes to the Colors structure

Modifications to the Colors structure to support colors for floating-point data and the NULL-value consist of

  • the _Color_Rule_ struct was changed to have DCELL value (instead of CELL cat) to have the range be floating-point values instead of integer cats.
  • a color for NULL was added
  • the special color for zero was eliminated
  • a default color for values which have no assigned color was added
  • a flag was added to the Colors structure to indicate if either the map itself is floating-point (If the map is integer and the floating point functions are used to lookup colors, the values are checked to see if they are integer, and if they are, the integer mechanism is used)
  • fp_lookup - a lookup table for floating point numbers is added. It orders the end points of fp intervals into array with a pointer to a color rule for each inteval, and the binary search is then used when looking up colors instead of linearly searching through all color rules.

3.4.6. Changes to the colr file

  • The rules are written out using floating-point format, removing trailing zeros (possibly producing integers). For example, to ramp from red to green for the range [1.3,5.0]:

               1.3:255:0:0  5:0:255:0
    
  • The NULL-value color is written as:
               nv:red:grn:blu
    
  • The default color (for values that don't have an explicit rule) is written as:
               *:red:grn:blu
    

3.5. Range functions (new and upgraded)

3.5.1. Modified range functions

G_read_range()
Old range file (those with 4 numbers) should treat zeros in this file as NULL-values. New range files (those with just 2 numbers) should treat these numbers as real data (zeros are real data in this case).

An empty range file indicates that the min, max are undefined. This is a valid case, and the result should be an initialized range struct with no defined min/max.

If the range file is missing and the map is a floating-point map, this function will create a default range by calling G_construct_default_range().

G_init_range()
Must set a flag in the range structure that indicates that no min/max have been defined - probably a "first" boolean flag.

G_update_range()
NULL-values must be detected and ignored.

G_get_range_min_max()
If the range structure has no defined min/max (first!=0) there will not be a valid range. In this case the min and max returned must be the NULL-value.

G_write_range()
This routine only writes 2 numbers (min,max) to the range file, instead of the 4 (pmin,pmax,nmin,nmax) previously written. If there is no defined min,max, an empty file is written.

3.5.2. New range functions

G_construct_default_range (struct Range *r)
Sets the integer range r to [1,255]

G_read_raster_range (void *r, char *name, char *mapset, RASTER_MAP_TYPE map_type)
If map_type is CELL_TYPE, calls G_read_range((struct Range *) r, name, mapset); otherwise calls G_read_fp_range((struct FPRange *) r, name, mapset);

G_read_fp_range (struct FPRange *r, char *name, char *mapset)
Read the floating point range file f_range. This file is written in binary using XDR format. If there is no defined min/max in r, an empty f_rangefile is created.

An empty range file indicates that the min, max are undefined. This is a valid case, and the result should be an initialized range struct with no defined min/max.

If the range file is missing and the map is a floating-point map, this function will create a default range by calling G_construct_default_range().

G_init_raster_range (FPRange *r, RASTER_MAP_TYPE map_type)
If map_type is CELL_TYPE, calls G_init_range(struct Range *) r); otherwise calls G_init_fp_range((struct FPRange *) r);

G_init_fp_range (FPRange *r)
Must set a flag in the range structure that indicates that no min/max have been defined - probably a "first" boolean flag.

G_update_f_range (FPRange *r, FCELL *fcell, int n)
Updates the floating-point range r from the n FCELL values in fcell NULL-values must be detected and ignored.

G_update_d_range (FPRange *r, DCELL *dcell, int n)
Updates the floating-point range r from the n DCELL values in dcell NULL-values must be detected and ignored.

G_get_fp_range_min_max (FPRange *r, DCELL *min, DCELL *max)
Extract the min/max from the range structure r.

If the range structure has no defined min/max (first!=0) there will not be a valid range. In this case the min and max returned must be the NULL-value.

G_write_fp_range (FPRange *r)
Write the floating point range file f_range. This file is written in binary using XDR format. If there is no defined min/max in r, an empty f_rangefile is created.

3.6. New and Upgraded Cell_stats functions

Modified Cell_stats functions to handle NULL-values:
G_init_cell_stats()
Set the count for NULL-values to zero.
G_update_cell_stats()
Look for NULLs and update the NULL-value count.
G_next_cell_stat()
Do not return a record for the NULL-value
G_find_cell_stat()
Allow finding the count for the NULL-value
G_get_stats_for_null_value(int *count, struct Cell_stats *s)
Get a number of null values from stats structure. Note: when reporting values which appear in a map using G_next_cell_stats(), to get stats for null, call G_get_stats_for_null_value() first, since G_next_cell_stats() does not report stats for null.

3.7. New Quantization Functions

New functions to support quantization of floating-point to integer.
G_write_quant (char *name, char *mapset, struct Quant *q)
Writes the f_quant file for the raster map name from q.

if mapset==G_mapset() i.e. the map is in current mapset, then the original quant file in cell_misc/map/f_quant is written. Otherwise q is written into quant2/mapset/name (much like colr2 element). This results in map@mapset being read using quant rules stored in q from G_mapset(). Seee G_read_quant() for detailes.

G_set_quant_rules (int fd, struct Quant *q)
Sets quant translation rules for raster map opened for reading. fd is a file descriptor returned by G_open_cell_old(). After calling this function, G_get_c_raster_row() and G_get_map_row() will use rules defined by q (instead of using rules defined in map's quant file) to convert floats to ints.

G_read_quant (char *name, char *mapset, struct Quant *q)
reads quantization rules for "name" in "mapset" and stores them in the quantization structure "quant". If the map is in another mapset, first checks for quant2 table for this map in current mapset.

Return codes:

-2 if raster map is of type integer

-1 if (! G__name_is_fully_qualified ())

0 if quantization file does not exist, or the file is empty or has wrong format.

1 if non-empty quantization file exists.

G_quant_init (struct Quant *q)
Initializes the q struct.

G_quant_free (struct Quant *q)
Frees any memory allocated in q and re-initializes q by calling G_quant_init().

G_quant_truncate (struct Quant *q)
sets the quant for q rules to perform simple truncation on floats.

G_quant_truncate (struct Quant *q)
sets the quant for q rules to perform simple rounding on floats.

G_quant_organize_fp_lookup (struct Quant *quant)
Organizes fp_lookup table for faster (logarithmic) lookup time G_quant_organize_fp_lookup() creates a list of min and max for each quant rule, sorts this list, and stores the pointer to quant rule that should be used inbetween any 2 numbers in this list Also it stores extreme points for 2 infinite rules, if exist After the call to G_quant_organize_fp_lookup() instead of linearly searching through list of rules to find a rule to apply, quant lookup will perform a binary search to find an interval containing floating point value, and then use the rule associated with this interval. when the value doesn't fall within any interval, check for the infinite rules.

G_quant_add_rule (q, dmin, dmax, cmin, cmax)
struct Quant *q;
DCELL dmin, dmax;
CELL cmin, cmax;
Add the rule that the floating-point range [dmin,dmin] produces an integer in the range [cmin,cmax] by linear interpolation.

Rules that are added later have higher precedence when searching.

If any of of dmin, dmax cmin, or cmax is the NULL-value, this rule is not added and 0 is returned. Otherwise return 1. if the fp_lookup is organized, destroy it.

G_quant_set_positive_infinite_rule (q, dmax, c)
struct Quant *q;
DCELL dmax;
CELL c;
Set the rule that values greater than or equal to dmax produce the integer c. If dmax or c is the NULL-value, return 0 and don't set the rule. Otherwise return 1.

This rule has lower precedence than rules added with G_quant_add_rule().

G_quant_get_positive_infinite_rule (q, dmax, c)
struct Quant *q;
DCELL *dmax;
CELL *c;
Sets dmax and c to the positive "infinite" rule in q if there is one and returns 1. If there is no such rule, it just returns 0. if the fp_lookup is organized, updates infinite limits.

G_quant_set_negative_infinite_rule (q, dmin, c)
struct Quant *q;
DCELL dmin;
CELL c;
Set the rule that values less than or equal to dmin produce the integer c. If dmin or c is the NULL-value, return 0 and don't set the rule. Otherwise return 1. if the fp_lookup is organized, updates infinite limits.

This rule has lower precedence than rules added with G_quant_add_rule().

G_quant_get_negative_infinite_rule (q, dmin, c)
struct Quant *q;
DCELL *dmax;
CELL *c;
Sets dmin and c to the negative "infinite" rule in q if there is one and returns 1. If there is no such rule, it just returns 0.

G_quant_get_limits (q, dmin, dmax, cmin, cmax)
struct Quant *q;
DCELL *dmin, *dmax;
CELL *cmin, *cmax;
Extracts the minimum and maximum floating-point and integer values from all the rules (except the "infinite" rules) in q into dmin, dmax, cmin, and cmax. Returns 1 if there are any explicit rules. If there are no explicit rules, (this includes cases when q is set to truncate or round map), it returns 0 and sets dmin, dmax, cmin, and cmax to NULL.

G_quant_nrules (struct Quant *q)
Returns the number of rules in q, excluding the negative and positive "infinite" rules.

G_quant_get_rule (q, n, dmin, dmax, cmin, cmax)
struct Quant *q;
int n;
DCELL *dmin, *dmax;
CELL *cmin, *cmax;
Get the nth rule from q. If 0 <= n < nrules(q), extract the rule and return 1. Otherwise return 0. This function can't be used to get the "infinite" rules.

The order of the rules returned by increasing n is the order in which the rules are applied when quantizing a value - the first rule applicable is used.

CELL G_quant_get_cell_value (struct Quant *q, DCELL value)
Returns a CELL category for the floating-point value based on the quantization rules in q. The first rule found that applies is used. The rules are searched in the reverse order they are added to q. If no rule is found, the value is first tested against the negative infinite rule, and finally against the positive infinite rule. if none of these rules apply, the NULL-value is returned.

NOTE: see G_quant_organize_fp_lookup() for details on how the values are looked up from fp_lookup table when it is active. (Right now fp_lookup is automatically organized during the first call to G_quant_get_cell_value()

G_quant_perform_d (q, dcell, cell, n)
struct Quant *q;
DCELL *dcell;
CELL *cell;
int n;
Performs a quantization of the n DCELL values in the dcell array and puts the results into the cell array.

G_quant_perform_f (q, fcell, cell, n)
struct Quant *q;
FCELL *fcell;
CELL *cell;
int n;
Performs a quantization of the n FCELL values in the fcell array and puts the results into the cell array.

These next two functions are convenience functions to allow applications to easily create quantization rules other than the defaults.
G_quantize_fp_map (char *name, CELL cmin, CELL cmax)
Writes the f_quant file for the raster map name with one rule. The rule is generated using the floating-point range in f_range producing the integer range [cmin,cmax].

G_quantize_fp_map_range (name, dmin, dmax, cmin, cmax)
char *name;
DCELL dmin, dmax;
CELL cmin, cmax;
Writes the f_quant file for the raster map name with one rule. The rule is generated using the floating-point range [dmin,dmax] and the integer range [min,max].

This routine differs from the one above in that the application controls the floating-point range. For example, r.slope.aspect will use this routine to quantize the slope map from [0.0, 90.0] to [0, 90] even if the range of slopes is not 0-90. The aspect map would be quantized from [0.0, 360.0] to [0, 360].

3.8. Categories Labeling Functions (new and upgraded)

3.8.0 Upgraded Categories structure

All the new programs which are using Categories structure directly have to be modified to use API functions to update and retreive info from Categories structure. Both new and old API function can be used, since old functions still have exact same functionality (even though internally they are implemented very differently). New function names end with raster_cats(); old function names end with _cats().

We made sure that all old fields in Categories structure are either missing in new Categories structure or have exactly the same meaning. We did it so that the programs using Categories structure directly either do not compile with new gis library or work exactly the same as bnefore. A programmer might want to read the data in a floating point map in a way that each cell value stores index of it's category label and data range. The way to do it is to call G_set_quant_rules(fd, &pcats->q) after openning the map.

This is helpful when trying to collect statistics (how many cells of each category are in the map. (although there is another new mechanism to collect such stats - see G_mark_raster_cats()). Another reason to get a category index instead of fp values is that this index will be the FID into GRASS-DBMS link. Also he can use G_get_ith_raster_cat() to get the category information for each cell using this index.

Here is the new Categories structure defined in gis.h:

struct Categories
{
    CELL ncats            ;   /* total number of categories              */
    CELL num              ;   /* the highest cell values. Only exists    
				 for backwards compatibility = (CELL)
				 max_fp_values in quant rules            */
    char *title           ;   /* name of data layer                      */ 
    char *fmt             ;   /* printf-like format to generate labels   */
    float m1              ;   /* Multiplication coefficient 1            */
    float a1              ;   /* Addition coefficient 1                  */
    float m2              ;   /* Multiplication coefficient 2            */
    float a2              ;   /* Addition coefficient 2                  */
    struct Quant q        ;   /* rules mapping cell values to index in
				 list of labels                          */
    char **labels         ;   /* array of labels of size num             */	
    int * marks           ;   /* was the value with this label was used? */
    int nalloc;
    int last_marked_rule  ;
} ;

3.4.6. Changes to the cats file

The format of explicit label entries is the same for integer maps.

   cat:description
In addition label entries of new format is supported for floating point maps.

   val:descr (where val is a floating point number)
or

   val1:val2:descr (where val1, val2 is a floating point range)
Internally the labels are stored for fp ranges of data. However when the cats file is written, all the decimal zeros are stripped so that integer values appear as integers in the file. Also if values are the same, only 1 value is written (i.e. first format).

This way even though the old cats files will be processed differently internally, the user or application programmer will not notice this difference as long as the proper api is used and the elements of Categories structure are not accessed directly without API calls.

3.5. Range functions (new and upgraded)

3.8.1 New Functions to read/write access and modify Categories structure.

G_read_raster_cats (char *name, *mapset, struct Categories *pcats)
Is the same as existing G_read_cats()

G_copy_raster_cats (struct Categories *pcats_to, struct Categories *pcats_from)
Allocates NEW space for quant rules and labels n pcats_to and copies all info from pcats_from cats to pcats_to cats.

returns: 0 if successful -1 on fail

char *G_get_raster_cat (val, pcats, data_type)
void *val;
struct Categories *pcats;
RASTER_MAP_TYPE data_type;
given a raster value val of type data_type Returns pointer to a string describing category.

char *G_get_c_raster_cat (val, pcats)
CELL *val;
struct Categories *pcats;
given a CELL value val Returns pointer to a string describing category.

char *G_get_d_raster_cat (val, pcats)
DCELL *val;
struct Categories *pcats;
given a DCELL value val Returns pointer to a string describing category.

char *G_get_f_raster_cat (val, pcats)
FCELL *val;
struct Categories *pcats;
given a FCELL value val Returns pointer to a string describing category.

G_set_raster_cat (rast1, rast2, pcats, data_type)
void *rast1, *rast2;
struct Categories *pcats;
RASTER_MAP_TYPE data_type;
Adds the label for range rast1 through rast2 in category structure pcats.

G_set_c_raster_cat (rast1, rast2, pcats)
CELL *rast1, *rast2;
struct Categories *pcats;
Adds the label for range rast1 through rast2 in category structure pcats.

G_set_f_raster_cat (rast1, rast2, pcats)
FCELL *rast1, *rast2;
struct Categories *pcats;
Adds the label for range rast1 through rast2 in category structure pcats.

G_set_d_raster_cat (rast1, rast2, pcats)
DCELL *rast1, *rast2;
struct Categories *pcats;
Adds the label for range rast1 through rast2 in category structure pcats.

int *G_number_of_raster_cats (pcats)
Returns the number of labels. DO NOT use G_number_of_cats() (it returns max cat number)

char *G_get_ith_raster_cat (pcats, i, rast1, rast2, data_type)
void *rast1, *rast2; /* value range */
struct Categories *pcats;
int i;
RASTER_MAP_TYPE data_type;
Returns i-th description and i-th data range from the list of category descriptions with corresponding data ranges. Stores end points of data interval in rast1 and rast2 (after converting them to data_type.

char *G_get_ith_c_raster_cat (pcats, i, rast1, rast2)
CELL *rast1, *rast2; /* value range */
struct Categories *pcats;
int i;
Returns i-th description and i-th data range from the list of category descriptions with corresponding data ranges. end points of data interval in rast1 and rast2.

char *G_get_ith_d_raster_cat (pcats, i, rast1, rast2)
DCELL *rast1, *rast2; /* value range */
struct Categories *pcats;
int i;
Returns i-th description and i-th data range from the list of category descriptions with corresponding data ranges. end points of data interval in rast1 and rast2.

char *G_get_ith_f_raster_cat (pcats, i, rast1, rast2)
FCELL *rast1, *rast2; /* value range */
struct Categories *pcats;
int i;
Returns i-th description and i-th data range from the list of category descriptions with corresponding data ranges. end points of data interval in rast1 and rast2.

char *G_get_raster_cats_title (struct Categories *pcats)
Returns pointer to a string with title.

G_unmark_raster_cats (struct Categories *pcats)
Sets marks for all categories to 0. This initializes Categories structure for subsequest calls to G_mark_raster_cats (rast_row,...) for each row of data, where non-zero mark for i-th label means that some of the cells in rast_row are labeled with i-th label and fall into i-th data range.

These marks help determine from the Categories structure which labels were used and which weren't.

G_get_next_marked_raster_cat(pcats, rast1, rast2, stats, data_type)
void *rast1, *rast2; /* value range */
struct Categories *pcats;
long *stats;
RASTER_MAP_TYPE data_type;
Finds the next label and corresponding data range in the list of marked categories. The category (label + data range) is marked by G_mark_raster_cats (). End points of the data range are converted to data_type and returned in rast1, rast2. the number of times value from i-th cat. data range appeared so far is returned in stats. See G_unmark_raster_cats(), G_rewind_raster_cats() and G_mark_raster_cats ().

G_get_next_marked_c_raster_cat(pcats, rast1, rast2, stats)
CELL *rast1, *rast2; /* value range */
struct Categories *pcats;
long *stats;
Finds the next label and corresponding data range in the list of marked categories. The category (label + data range) is marked by G_mark_raster_cats (). End points of the data range are converted to data_type and returned in rast1, rast2. the number of times value from i-th cat. data range appeared so far is returned in stats. See G_unmark_raster_cats(), G_rewind_raster_cats() and G_mark_raster_cats ().

G_get_next_marked_f_raster_cat(pcats, rast1, rast2, stats)
FCELL *rast1, *rast2; /* value range */
struct Categories *pcats;
long *stats;
Finds the next label and corresponding data range in the list of marked categories. The category (label + data range) is marked by G_mark_raster_cats (). End points of the data range are converted to data_type and returned in rast1, rast2. the number of times value from i-th cat. data range appeared so far is returned in stats. See G_unmark_raster_cats(), G_rewind_raster_cats() and G_mark_raster_cats ().

G_get_next_marked_d_raster_cat(pcats, rast1, rast2, stats)
DCELL *rast1, *rast2; /* value range */
struct Categories *pcats;
long *stats;
Finds the next label and corresponding data range in the list of marked categories. The category (label + data range) is marked by G_mark_raster_cats (). End points of the data range are converted to data_type and returned in rast1, rast2. the number of times value from i-th cat. data range appeared so far is returned in stats. See G_unmark_raster_cats(), G_rewind_raster_cats() and G_mark_raster_cats ().

G_mark_raster_cats (rast_row, ncols, pcats, data_type)
void *rast_row; /* row of rtaster cell values */
struct Categories *pcats;
int ncols;
RASTER_MAP_TYPE data_type;
Looks up the category label for each raster value in the rast_row and updates the marks for labels found.

NOTE: non-zero mark for i-th label stores the number of of raster cells read so far which are labeled with i-th label and fall into i-th data range.

G_mark_c_raster_cats (rast_row, ncols, pcats)
CELL *rast_row; /* row of rtaster cell values */
struct Categories *pcats;
int ncols;
Looks up the category label for each raster value in the rast_row and updates the marks for labels found.

NOTE: non-zero mark for i-th label stores the number of of raster cells read so far which are labeled with i-th label and fall into i-th data range.

G_mark_f_raster_cats (rast_row, ncols, pcats)
FCELL *rast_row; /* row of rtaster cell values */
struct Categories *pcats;
int ncols;
Looks up the category label for each raster value in the rast_row and updates the marks for labels found.

NOTE: non-zero mark for i-th label stores the number of of raster cells read so far which are labeled with i-th label and fall into i-th data range.

G_mark_d_raster_cats (rast_row, ncols, pcats)
DCELL *rast_row; /* row of rtaster cell values */
struct Categories *pcats;
int ncols;
Looks up the category label for each raster value in the rast_row and updates the marks for labels found.

NOTE: non-zero mark for i-th label stores the number of of raster cells read so far which are labeled with i-th label and fall into i-th data range.

G_rewind_raster_cats ( struct Categories *pcats)
after calll to this function G_get_next_marked_raster_cat() returns rhe first marked cat label.

G_init_raster_cats (char *title, struct Categories *pcats)
Same as existing G_init_raster_cats() only ncats argument is missign. ncats has no meaning in new Categories structure and only stores (int) largets data value for backwards compatibility.

G_set_raster_cats_fmt (char *fmt, float m1, a1, m2, a2, struct Categories *pcats)
Same as existing G_set_cats_fmt()

G_set_raster_cats_title (char *title, struct Categories *pcats)
Same as existing G_set_cats_title()

G_write_raster_cats (char *name, struct Categories *pcats)
Same as existing G_write_cats()

G_free_raster_cats (struct Categories *pcats)
Same as existing G_free_cats()

3.9. Library Functions that are Deprecated

These functions are deprecated, since they imply that the application that uses them has not been upgraded to handle NULL-values and should be eliminated from GRASS code.
  • G_get_map_row()

    To be replaced by G_get_c_raster_row().

  • G_get_map_row_nomask()

    To be replaced by G_get_c_raster_row_nomask().

  • G_put_map_row()

    To be replaced by G_put_c_raster_row().

These functions are deprecated, since they can not be upgraded to support NULL-values, and should be eliminated from GRASS code.

  • G_open_map_new_random()
  • G_put_map_row_random()

Also, no support for random writing of floating-point rasters will be provided.

4. Upgrades to existing GRASS programs

Contents of this section
Upgrades to raster programs
Upgrades to vector programs
Upgrades to sites programs
Upgrades to display programs
Upgrades to hardcopy output programs
Upgrades to g.* programs
Upgrades to m.* programs
Upgrades to imagery programs
Upgrades to shell scripts
This section provides guidelines for upgrading GRASS programs to process floating-point values and NULL-values. It also provides specific recommendations for many of the GRASS programs regarding user-interface and functional changes.

NOTE: There will be programs for which there is no recommedation given. This is because I didn't have time to examine these programs. The lack of specific recommendations should not be taken to mean that no upgrades are necessary, but that someone should examine the program and make recommendations.

4.1. Guidelines for upgrading GRASS programs

  • Programs that process raster maps as continuous data should read raster maps as floating-point. Programs that process raster maps as nominal data should read raster maps as integer.

    Exception: Programs that process raster colors or the programs which report on raster categories labels should either always read the maps as floating-point, or read the maps as integer if the map is integer and floating-point if the map is floating-point.

  • The quantization of floating-point to integer should NOT change the color table. The color lookup should have its own separate quantization.
  • The quantization of floating-point to integer should NOT change the Categories table. The Categories structure should have its own separate quantization.
  • Programs that read or write floating-point raster maps should use double (DCELL) arrays instead of float (FCELL) arrays.
  • Programs should process NULL values in a well defined (consistent) manner. Programs that processed zero as the pseudo NULL-value should be changed to use the true NULL-value for this and process zero as normal value.
  • Programs should process non-NULL values as normal numbers and not treat any particular numbers (e.g. zero) as special.

4.2. Upgrades to raster programs

In general programs that use G_get_map_row(). should use G_get_c_raster_row() instead.

Programs that use G_put_map_row(). should use G_put_c_raster_row() instead.


r.allocate
  • The program should ignore NULLs instead of ignoring zeros -- don't allocate in NULL-valued cells.

r.average
  • The program should ignore NULLs instead of ignoring zeros:
    • The call to r.stats should not specify the -z flag.
    • Parsing the output from r.stats should ignore output that is non-numeric (e.g. * which represents NULL).
  • The covermap should be read as floating-point.
  • The average should only be computed from non-null values
  • Both base, and cover map can be floating point. When computing averages for each category label of base map, the data to be averaged is taken form same cells in the cover map. but not the average of all such cell values in coval map is taken, but average of midlle points of category ranges these cell values fall into.

    For example if cells 3.4 12.9 and 30.78 of cover map coinside with cells 100.4, 100.5 and of base map all falling into category range "100.0 - 102.0 Fist category" in the bae map cats file.

    Also suppose in cover map there are category ranges:

         1 - 10 .1
         10 - 20 .2
         20 - 30 .3
         30 - 40 .4
    <\pre>
         then the resulting average will not be (3.4 + 12.9 + 30.78)/3
         but (5 + 15 + 35)/3
    
         

    This is because r.stats is used to collect relative stats for covar and base maps, and r.stats can only collect stats for cats ranges, not for each cell value. If in the same situation -c flag is used, then the resulting average will be (.1 + .2 + .4)/3

  • ?? the result map should always be written as floating point, (not the integer reclass like before )

r.basins.fill

r.binfer

r.buffer
  • The read_input_map should look for NULLs instead of zeros. Line 49 of read_map.c should be changed from
        if(*ptr++ = (*cell++ != 0))
    
    to
        if(*ptr++ = !G_is_c_null_value(cell++))
    

r.cats
  • The input map should be read using G_get_raster_row(). And to lookup labels using G_get_raster_cat(). No other changes are required to treat zero as a normal number and to ignore NULLs. The code uses the Cell_stats functions which have been upgraded to suppress reporting NULLs. New argument: vallist: a comma-separated list of values to show labels for. If map is floating point, and vals areen't used, program exists with an error.

r.clump
  • The use of zero should be replaced by NULLs. In clump.c line 68-74 should be changed from
    /* fake a previous row which is all zero */
        G_zero (prev_in, len);
        G_zero (prev_clump, len);
    
    /* create a left edge of zero */
        cur_in[0] = 0;
        cur_clump[0] = 0;
    
    to
    /* fake a previous row which is all NULLs */
        G_set_c_null_value (prev_in, ncols+1);
        G_set_c_null_value (prev_clump, ncols+1);
    
    /* create a left edge of NULLs */
        G_set_c_null_value(cur_in,1);
        G_set_c_null_value(cur_clump,1);
    
    and lines 86-95 from
    X = 0;
    for (col = 1; col <= ncols; col++)
    {
        LEFT = X;
        X = cur_in[col];
        if (X == 0)            /* don't clump zero data */
        {
            cur_clump[col] = 0;
            continue;
        }
    
    
    to
    G_set_null_value(&X,1);
    for (col = 1; col <= ncols; col++)
    {
        LEFT = X;
        X = cur_in[col];
        if (G_is_c_null_value(&X))     /* don't clump NULL data */
        {
            cur_clump[col] = 0;
            continue;
        }
    

r.coin

r.colors
  • This program must consider if the map is floating point
  • It must also allow creation of the same color table with a common range of colors for multiple maps.

    r.colors maps=name[,name...] [basemap=name] [range=min,max]

    maps=
    The maps for which the colors are to be created. If more than one map is specified, then this implies that the data range range is the miniumum and maximum of all the maps together. unless either basemap=map or range=min,max is specified.
    basemap=name
    This map sets the data range to receive colors
    range=min,max
    This sets the data range to receive colors

    NOTE: it is an error for both basemap and range to be specified.

  • It must have some built-in quantization rules

    r.colors maps=name [quant=type]

    where type could be log, histoeq, mmse (mimimum median squared error), linear, etc.


r.colors.paint

r.combine

r.compress
  • If the map if floating-point, the map should be read/written as floating point. Also, the storage type should be preserved - G_set_fp_type() should be called to preserve the storage type of the map.

r.contour

r.cost

r.covar
  • The input map should be read as floating-point instead of integer
  • The -m flag should be eliminated.
  • Reading the mask should be eliminated.
  • NULLs should be excluded from the calculations.
  • The message that there a no non-zero values should be changed to a message that there are no non-NULL values.

r.cross

r.describe
    new option: nv (a string representing "no_data" )

    new optionfor fp maps: nsteps

    reports floating point ranges with non-zero statistics. if nsteps option is used, it breaks the data range into nsteps subranges and looks for values in these subranges. (for example if data range is .5-4.5 and nsteps is 8, nv= "NULL", and there are values in the ranges .5-1, 1-1.5, 1.5-2, and 4-4.5 and Null values, it will report "NULL 0.5-2 4-4.5")

    If the map is integer, r.describe reports integer ranges and null value string if there are any null values in the map.


r.digit
  • No upgrade necessary since all the real work is done by r.in.poly.

r.distance
  • The function find_edge_cells() should be modified to look for NULLs instead of zeros.

    Lines 38-43 of edges.c should be changed from

        for (col = 0; col < (ncols+2); col++)
        {
    	buf0[col] = 0;
    	buf1[col] = 0;
    	buf2[col] = 0;
        }
    
    
    to
        G_set_c_null_value (buf0, ncols+2);
        G_set_c_null_value (buf1, ncols+2);
        G_set_c_null_value (buf2, ncols+2);
    
    And lines 66 of edges.c should be changed from
        if (buf1[col]              /* is a valid category */
    
    to
        if (!G_is_c_null_value(&buf1[col])  /* is a valid category */
    

r.drain

r.flow

r.gdbase

r.grow
  • Look for NULLs instead of positive values.
This code needs attention. It seems to me that it is not coded correctly.
  • Negative values are treated like NULLs. The code should be changed to allow negative values to be grown as well. For exampe, lines 124-128 of main.c:
        if (*c2 > 0)
    	if (binmap) *c4++ = 1;
    	else *c4++ = *c2;
        else *c4++ = 0;
    
    
    This could be coded as:
        if (!G_is_c_null_value(c2)))
    	if (binmap) *c4++ = 1;
    	else *c4++ = *c2;
        else G_set_c_null_value(c4++ ,1);
    
    or even better
        if (binmap && !G_is_c_null_value(c2)))
    	*c4++ = 1;
        else *c4++ = *c2;
    
  • There are places in the code where the binmap toggle isn't handled properly. Lines 134-138 look suspicious:
        if (*c2 == 0)
        {
            if ( *(c2+1) > 0 || *c3 > 0)
                *c4 = 1;            <--- this looks wrong
        }
    

r.in.ascii
    Can now produce floating point and integer maps with embedded null value cells. There are new flags: -f,-d produce float/double, -i produce integer. And new option: nv="string representing no-data cells in the input file" if -f -d or -i are not used, r.in.ascii looks into the header of input file. The header now can have entries: multiplier, null, and type. If type is not set in the header, the new map is created integer if all of the values in the input file are integer, and float otherwise.

r.in.elas

r.in.ll

r.in.poly

r.in.sunrast

r.infer

r.info

r.kappa
    removed -z and -m flags

r.line

r.los

r.mask

r.mapcalc
  • Floating-point maps should be read as floating-point and treated as floating-point numbers in the expression. Integer maps should be read as integer and treated as integer in the expression.

    Exceptions

    @map
    The map should be read as integer, even if the map is a floating-point map. The integer is then used (as usual) to get a floating-point value from the category label.
    #map
    r#map
    g#map
    b#map
    The map should be read as floating-point, even if the map is integer. The floating-point value is then used to get an integer color value from the color table. This reflects the new way colors are processed for floating-point.
  • If the entire expression is a floating-point result, the resultant map should be a floating-point map, written using the default storage mode for floating-point. Otherwise it should be an integer map.

    This is a non-backward-compatible change and should be noted in the manual entry for r.mapcalc as well as in any release notes.

  • Division by zero should result in NULL.

    This is a non-backward-compatible change and should be noted in the manual entry for r.mapcalc as well as in any release notes.

  • Modulus by zero should result in NULL.

    This is a non-backward-compatible change and should be noted in the manual entry for r.mapcalc as well as in any release notes.

  • NULL-values in any arithmetic operation should result in NULL.
  • NULL-values in logical operations should be handled as follows:
    NULL || true = true
    NULL || false = NULL
    NULL || NULL = NULL
    NULL && true = NULL
    NULL && false = false
    NULL && NULL = NULL
  • NULL-values in function arguments should result in NULL.

    Even though this is also true for the if() function, if() is spelled out here for clarification:

    if(x)
    NULL if x is NULL; 0 if x is zero; 1 otherwise
    if(x,a)
    NULL if x is NULL; a if x is non-zero; 0 otherwise
    if(x,a,b)
    NULL if x is NULL; a if x is non-zero; b otherwise
    if(x,n,z,p)
    NULL if x is NULL; n if x is negative; z if x is zero; p if x is positive

    Exceptions: The (new) function isnull(x) returns: 1 if x is NULL; 0 otherwise. The (new) function null() (which has no arguments) returns an integer NULL.

  • Non-NULL, but invalid, arguments to functions should result in NULL.

    Examples:

    log(-2)
    pow(a,b) where a is negative and b is not an integer

    Exception: sqrt(-n) returns -sqrt(n)


r.mask.points

r.median

r.mfilter

r.mode

r.neighbors
    now works with fp data

r.out.ascii
    New options: nv (a string representing no-data cells) and dp (number of decimal places when reporting floating point values). New flag: -i (means read the map using map's quant rules and report integers.

r.out.elas

r.out.mpeg

r.out.tga

r.patch
    works with floating point raster maps and null vallues overwrites nulls in input maps with non-null data in other input maps when the map is floating point, copies all the category and files to make new category file, and takes the first color file to be the new color files. (this is because it's very hard to combine all color rules in one file) creating new one. The output type of the map is the highest precision of all input maps.

r.poly

r.profile

r.random

r.reclass
  • Interactive version: Now gives an option to set all result fields to null (as well as to themselves and to 0) The result field can now containt string "null" and the reclass value is then set to null.
  • Command line version: Now accepts new kinds of rules:
    the rules n1 [thru n2] = null
    * = n
    * = null
    * = *
    
    where "*" means "every other value" and "=*" means "stays the same"

r.report
  • Reports stats on floating point ranges. If nsteps is set, divides data range of the map into nsteps subranges, and reports stats on each range. The labels are "From (cat. descr. for min) to (cat. descr. for max)" Also reports stats for null cells unless -n or -N are used.
  • If -C flag is used reports on floating point ranges in cats file, (the labels for these ranges are stored in the same file) Also reports stats for null cells unless -n or -N are used.
  • The user should have the option of requesting/suppressing the reporting of NULLs. In the case of multiple maps, the supression could have two flavors: suppress if any vaalue is NULL; suppress only if all values are NULL.

    The command-line options here could be:

    -n
    Suppress reporting of any NULLs
    -N
    Suppress reporting of NULLs if all values are NULL.
    -C
    report for cats fp ranges (fp maps only)
    -i
    Read fp map as integer (use map's quant rules)
    nsteps=int
    number of fp subranges to collect stats from
    (In the case of a single map, -n or -N give the same result). -m flag should be removed as in r.stats

r.resample
    r.resample is now modified to do resampling on floating point maps as well. It preserves all the null values and creates the category file which contains only the labels for the values which appear in the new map.

r.resample.tps.float
    Should handle cats file in the same manner as r.resample and work with floating numbers and no-data

r.rescale

r.rescale.eq

r.slope.aspect
  • The input map should be read as floating-point, even if it is integer
  • NULLs in the input should generate NULLs in the output.
  • The edges should be written as NULL since the 3x3 filter can't produce slope or aspect for the edge cells.
  • No slope (flat) should generate NULL aspect.
  • The output maps (slope, aspect) should be written as float unless the precision argument is set explicitly to write double or int.
  • The aspect map should have one quantization rule: [0.0,360.0] = [0,360]
  • The slope map should have one quantization rule: [0.0,90.0] = [0,90]

r.stats
  • The -m should be eliminated. The code that reads the MASK should be removed.
  • A -n should be added to request that NULLs be reported. NULLs should be represented by *. For example
  • new option for fp maps: nsteps and new flags -C (cats fp ranges) and -r (raw) (nsteps and -C are mutually exclusive. -C is default) NOTE: when -1 option is used -C will be ignored, because the actuall floating point values are the output.

    When the map is floating point, Unless -1 option is used (in which case output is stream of actuall cell values) r.stats reports stats for floating point subranges of the map. if nsteps option is used, it breaks the data range into nsteps subranges and collects stats for these subranges. NOTE: when -1 option is used nsteps will be ignored, because the actuall floating point values are the output.

    When -C flag is used it will report stats for the fp ranges specified in cats file. When both -C and -r are used, it will report stats for indexes of fp. ranges in cats file. This is mostly used by r.report calling r.stats.

    When -i flag is used, reads data as integer using quant rules.

  • another new option: nv (a string representing "no data" cells)

  • Later -n and -N flags just like in r.report should be added

    
    r.stats -cn soils
    
      *:200
      1:3040
      2:6000
      7:3456
    

r.support
  • Range updates must now update the floating point range if the map is floating point.
  • Support for creating/modifying cats file was updated to edit/modify category labels for floating point ranges.
  • Support for creating/modifying the NULL-value bit map must be added. This will be an interface to r.null
  • Color table creation/modification must consider if the map is floating-point.

r.surf.contour

r.surf.idw

r.surf.idw2

r.surf.voronoi

r.thin

r.transect

r.volume

r.watershed

r.watershed4.0

r.weight

r.weight.new

r.what

r.what.new

4.2. Upgrades to vector programs


v.to.rast
  • Set the background (or the universe) to NULL instead of zero
  • Rasterize unlabeled areas as NULL
  • Do not rasterize unlabeled lines or points
  • If a vector object is labeled as zero, consider this object as labeled

v.digit
  • The raster backdrop should be drawn either always using floating-point raster data/colors, or should be drawn using integer if the map is integer and drawn using floating-point if the map is floating-point.

xdigit
  • The raster backdrop should be drawn either always using floating-point raster data/colors, or should be drawn using integer if the map is integer and using floating-point if the map is floating-point.

4.3. Upgrades to sites programs

General Guidelines: The conversion of sites to raster should be modified in all sites programs as follows:
  • The conversion of sites to raster should code non-site cells as NULL instead of zero.
  • The use of random writing of raster maps should be replaced by an in-memory paging mechanism similar to what v.to.rast employs.

    This could be handled by writing a creating a new program r.in.rowcol that implements the in-memory paging.


s.menu
  • Those modules which analyze site data against a raster map (for reporting) should read the raster map using G_get_c_raster_row() and replace any special processing of zero by NULL.

    ?? If the map is floating-point ??


s.gdbase

s.in.ascii

s.out.ascii

s.reclass

s.surf.2d.float

s.surf.2d.float.alt

s.surf.2df

s.surf.idw

s.surf.tps

s.to.rast
    processes new site format and creates a raster map of the same type as site data.

4.4. Upgrades to display programs


d.3d
    can draw both interger and floating point raster maps. Raster maps of any type can be used as base map and elevation map. -z flag changed to -n flag. Argument "draw zero elevation" changed to "draw null elevation".

d.colors
    lets edit null color for integer maps. Refuses to execute for fp maps

d.colortable
    Shows null color box, otherwise works the same way for integer maps, ignores lines and cols arguments and draws color ramp for fp maps with first 5 pixels drawn in null value color

d.display

d.his

d.histogram
    -n flag to include nulls -C report for cats ranges nsteps (default 255) -z flag removed. d.histogram now displays bars for each category. In case of floating point map for each category range the bar is split itno 1-pixel think lines and each line is displayed in color computed for corresponding value form category range. The result is that the bar is not one color, but smooth color range showing colors of values in category range.

d.legend
  • For floating-point maps, for each category label produce a continuous color bar based on the floating-point range of this label. If Category file is empty, show continuous color ramp for the whole range.
  • Shows box for null value as the first item.

d.paint.labels

d.profile

d.rast
  • The -o overlay flag should suppress the plotting of NULLs instead of zeros.
  • If the map is floating-point, read the raster data as floating-point and use the floating-point color interface for plotting.

d.rast.arrow

d.rast.edit
    allows editing all types of maps with considering null values

d.rast.num

d.rgb

d.what.rast
    Now reports wether or not the cell is "no data". Also for floating point maps reports the actuall value, the label and the quantized value.

4.5. Upgrades to hardcopy output programs


p.map
  • Set the color for NULL to white.
  • Upgrade the setcolor command to allow setting the color for fp numbers and ranges, also user can now say "setcolor null color" and "setcolor default color" also for NULL as well as the default color.
  • When reading the map for colors, read the map as floating-point.
  • When reading the map to produce a legend, set the quantiztion to categories quant rules, read the map as integer, where the cell values will be the category indexes when producing legend and colortable. then for each category label split the color box into rows for each pixel and for each such row compute the color. (a box represents range of date in case of fp maps) Separately show the box for null value
  • Replace any special handling of zero with NULL.

ps.map
  • Same recommendations as for p.map

p.colors
  • Eliminate any special handling of zero
  • In case of floating point maps ask for number of steps to split the range into and assign color for each subrange. (assigning color to fp value on the screen actually changes color for the range from this value to the next value )

4.5. Upgrades to g.* programs


g.copy
g.list
g.remove
g.rename
  • The Element_List file in src/general/manage/lib is changed to make the fcell directory visible and part of the cell type, as follows:

    
    cell:rast:raster:raster files
      cellhd:header
      cats:category
      colr:color
      hist:history
      cell_misc:misc
      fcell:fcell
    fcell:fprast:fp raster:floating-point raster files
      cell:cell
      cellhd:header
      cats:category
      colr:color
      hist:history
      cell_misc:misc
    
    

g.region
  • The zoom=map must read the null-value bitmap using G_get_null_value_row() and look for non-NULL instead of non-zero.

4.6. Upgrades to m.* programs


m.clump
  • No change required. This program is not a raster analysis tool.

m.dem.extract
    changed to write out null values for no data instead of zeros

m.dmaUSGSread

m.dted.extract

m.lulc.USGS

m.lulc.read

4.7. Upgrades to imagery programs

General Guidelines:
  • When reading the image map for colors, read the map as floating-point.
  • Image data could always be read as floating-point since it is really continuous data.

i.cca

i.class
  • When reading the image map for colors, read the map as floating-point.

i.cluster
  • Read the maps using embedded mode and ignore NULL values.

i.colors
  • Read the maps as floating-point.

i.composite

i.fft

i.gensig

These changes are for the cmd version.

  • Replace calls to G_get_map_row() with G_get_c_raster_row().
  • In get_train.c remove any checking for category 0. (This code uses Cell_stats functions that process zeros as real data and suppress NULLs.)

    In particular, the comment at line 23 should be changed from

        /* determine the non-zero categories in the map */
    
    to
        /* determine the categories in the map */
    
    Line 39, which checks for zero,
        if (cat != 0)
    
    should be deleted. (The block which is part of the if will become the block for the while above it, which is the right thing.

    Line 67 should be changed from

        if (cat != 0 && count > 1)
    
    to
        if (count > 1)
    
  • In lookup_class.c line 17 should be changed from
        if (c == 0)
    
    to
        if (G_is_c_null_value(&c))
    
  • In means.c and covariance.c NULLs should be excluded from the calculations. This will require some care. If any of the pixels in the band files are NULL, then this reduces the number of points when calculating the means and variances. Three things need to be done.
    • Detect NULLs in the band files and do NOT use them in the sums
    • Count the number of NULLs
    • Reduce the number of pixels when producing the means or variances by the number of NULLs.

      Warning! This last item could result in too few pixels (zero for the means, zero or one for the variances) which will invalidate the class. This will not be so simple to remedy. I recommend that if the number of pixels is get this small, that the program abort. This behavior should be documented as a bug in the manual entry.

  • The band files could be read as floating-point maps instead of integer. Imagery data is a discretization of continuous data. The means and variances produced from the image data are floating-point values. Upgrading this program to read the band files are floating-point would be a good thing. (for now the processing is integer Olga)

i.gensigset

The comments for i.gensig apply here since i.gensigset shares a lot of code with i.gensig. The principle difference is that all the data is read into memory before processing.

In read_data.c test for NULLs and do not count them or insert them into the Data array. The same Warning! applies as for i.gensig.


i.grey.scale

i.his.rgb

i.ifft

i.in.erdas

i.kappa

i.maxlik
  • Classify NULL values as NULL.

i.ortho.photo

i.pca

i.points
i.points3 I can't find it
i.vpoints
  • When reading the image map for colors, read the map as floating-point.

i.quantize

i.rectify
i.rectify2
i.rectify3 I can't find
  • if map is float adjust quant rules
  • Make sure that the function that finds the input pixel corresponding to the output pixel returns NULL instead of zero if the pixel is outside the bounds of the input dataset.

i.rgb.his

i.smap
  • Classify NULL values as NULL.

i.tape.mss
i.tape.other
i.tape.spot
i.tape.tm
i.tape.tm.fast
i.tape.tm3 I can't find
  • Use G_put_c_raster_row() instead of G_put_map_row() since zeros are valid data.

i.zc

4.8. Upgrades to shell scripts


3d.view.sh

blend.sh

dcorrelate.sh

demo.scripts

demo.sh

hsv.rgb.sh

intens.sh

rgb.hsv.sh

shade.clr.sh

shade.rel.sh

4.9. New Programs

These are programs that have been identified as needed to support the upgrade to floating-point raster maps as well is the introduction of a NULL-value.
r.null
r.null -fin maps=name[,name...] [setnull=range,[range]] [null=value]

The function of r.null is to explicitly create the NULL-value bitmap file. The intended usage is to fix "old" maps that don't have a NULL-value bitmap file (i.e. to indicate if zero is valid value or is to be converted to NULL).

The design is flexible. Ranges of values can be set to NULL and/or the NULL value can be eliminated and replace with a specified value.

-f
Only do the work if the map is floating-point.
-i
Only do the work if the map is integer.
-n
Only do the work if the map doesn't have a NULL-value bitmap file.

-r
create NULL-value bitmap file which validates all data cells.

-d
remoe NULL-value bitmap file.

setnull=range[,range...]
The values specified in the ranges are to be set to NULL. A range is either a single value (e.g., 5.3), or a pair of values (e.g., 4.76-34.56). Existing NULL-values are left NULL, unless the null argument is requested.
null=value
Eliminate the NULL value and replace it with value This argument is applied only to existing NULL values, and not to the NULLs created by the setnull argument.

Note that value is restricted to integer if the map is an integer map.

r.in.rowcol
r.in.rowcol map=name [input=name]

This program would create a raster map with cells set to values for input row/col pairs (based on the current region). This program would be used by other programs that produce raster maps from site data. The input file format would be:

column row value [label]
The input would be from stdin if not specified or specified as input=-.

This program should be implemented using a paging scheme like that used by v.to.rast to allow the row/col lines to be unordered, yet write the resultant map using sequential raster writes.

If the input is from stdin, it would be copied to a tempfile first and then process from the tempfile. This is due to the above sequential-write requirement. The input may have to be read more than once.

If all the values in the input are integers, the map should be create as integer and the optional labels put into the category file. Missing labels do not update the catgeory label. This allows the input to have one label for the one occurrence of a value without having to label every occurrence

If any of the values are non-integer, the map should be created as floating-point and the optional labels ignored. No explicit category file would created for the resultant floating-point map.

r.recode
r.recode input=name output=name title=name [-a] Creates a new map in which cell values are results of applying user specified rules to the coresponding values in the input map. User is asked to enter the rules interactively. If some values on the right-hand side of the rules are floating point, the new map is double, otherwise it is integer.

r.quant
r.quant map=name[,map...] [basemap=map] [-tr] [fprange=min,max] [range=min,max]

This routine produces the quantization file for a floating-point map

map=name
The map for which the rules be to be created. If more than one map is specified, then this implies that the floating-point range is the miniumum and maximum of all the maps together, unless either basemap=map or fprange=min,max is specified.
basemap=map
The quant rules of this map set the quantization.
fprange=min,max
This sets the floating-point range for the quantization.
-t flag
Truncate the map.
-r flag
Round the map.
range=min,max
This sets the integer range for the quantization. Otherwise a default of 1-255 is used.
quant rules
The quant rules have to be entered interactively

If rules is specified, the input has the form:

value1:value2:cat1:[cat2]
where value1 and value2 are floating point values and cat1 cand cat2 are integers. If cat2 is missing, it is taken to be equal to cat1. All values can be "*" which means infinity.
NOTE: it is an error for both basemap and fprange to be specified.


Michael Shapiro <shapiro@zorro.cecer.army.mil>
Olga Waupotitcsh <olga@zorro.cecer.army.mil>