/********************************************************************** * * G_read_range (name, mapset, range) * const char *name name of map * const char *mapset mapset that map belongs to * struct Range *range struct to hold range info * * Reads the data range information associated with map layer "map" * in mapset "mapset" * * returns: 1 if successful * 2 range is empty * 3 map is fp: get range from quant rules * -1 on fail * * note: a warning message is printed if the file is missing or incorrect * ********************************************************************** * * G_read_fp_range (name, mapset, range) * const char *name name of map * const char *mapset mapset that map belongs to * struct FPRange *range struct to hold range info * * Reads the fp data range information associated with map layer "map" * in mapset "mapset" . If map is integer, the integer range is read * and the max and min values are casted to doubles and copied to FPRange * * returns: 1 if successful * 2 range is empty * -1 on fail * * note: a warning message is printed if the file is missing or incorrect * ********************************************************************** * * G_write_[fp_]range (name, range) * const char *name name of map * struct [FP]Range *range struct holding range info * * Writes the range information associated with map layer "map" * * returns: 0 if successful * -1 on fail (or if the map is fp ) * ********************************************************************** * * G_init_[fp_]range (range) * struct [FP]Range *range struct for range info * * initializes range structure for call to G_update_[fp_]range() * ********************************************************************** * * G_construct_default_range (range) * struct Range *range struct for range info * * returns 1 and range is set to DEFAULT_CELL_MIN * and DEFAULT_SET_MAX, otherwise returns -1 * ********************************************************************** * * G_update_[fp_]range (cat, range) * DCELL cat cat to be factored into range * struct [FP]Range *range struct for range info ********************************************************************** * * G_row_update_[fp_]range (rast, range, data_type) * void *rast raster row to be factored into range * struct [FP]Range *range struct for range info * RASTER_MAP_TYPE data_type; ********************************************************************** * * G_get_[fp_]range_min_max (range, min, max) * struct [FP]Range *range; * [D]CELL *min, *max; **********************************************************************/ #include #include /* need this for sgi */ #include #include "G.h" #include #define DEFAULT_CELL_MIN 1 #define DEFAULT_CELL_MAX 255 /*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/ /* range functions for type "Range" */ /*-------------------------------------------------------------------------*/ void G__remove_fp_range(const char *name) { G_remove_misc("cell_misc", "f_range", name); } /*! * \brief * * Sets the integer range r to [1,255] * * \param r * \return */ void G_construct_default_range(struct Range *range) { G_update_range(DEFAULT_CELL_MIN, range); G_update_range(DEFAULT_CELL_MAX, range); } /*! * \brief * * 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(). * * \param r * \param name * \param mapset * \return int */ int G_read_fp_range(const char *name, const char *mapset, struct FPRange *drange) { struct Range range; int fd; char buf[200], xdr_buf[100]; DCELL dcell1, dcell2; XDR xdr_str; G_init_fp_range(drange); if (G_raster_map_type(name, mapset) == CELL_TYPE) { /* if map is integer read integer range and convert it to double */ if (G_read_range(name, mapset, &range) >= 0) { /* if the integer range is empty */ if (range.first_time) return 2; G_update_fp_range((DCELL) range.min, drange); G_update_fp_range((DCELL) range.max, drange); return 1; } return -1; } fd = -1; if (G_find_file2_misc("cell_misc", "f_range", name, mapset)) { fd = G_open_old_misc("cell_misc", "f_range", name, mapset); if (fd < 0) goto error; if (read(fd, xdr_buf, 2 * XDR_DOUBLE_NBYTES) != 2 * XDR_DOUBLE_NBYTES) return 2; xdrmem_create(&xdr_str, xdr_buf, (u_int) XDR_DOUBLE_NBYTES * 2, XDR_DECODE); /* if the f_range file exists, but empty */ if (!xdr_double(&xdr_str, &dcell1) || !xdr_double(&xdr_str, &dcell2)) goto error; G_update_fp_range(dcell1, drange); G_update_fp_range(dcell2, drange); close(fd); return 1; } error: if (fd > 0) close(fd); sprintf(buf, _("can't read f_range file for [%s in %s]"), name, mapset); G_warning(buf); return -1; } /*-------------------------------------------------------------------------*/ /*! * \brief read raster range * * This routine reads the range information for the * raster map name in mapset into the range * structure. * A diagnostic message is printed and -1 is returned if there is an error * reading the range file. Otherwise, 0 is returned. * * 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(). * * \param name * \param mapset * \param range * * \return int */ int G_read_range(const char *name, const char *mapset, struct Range *range) { FILE *fd; CELL x[4]; char buf[200]; int n, count; struct Quant quant; struct FPRange drange; G_init_range(range); fd = NULL; /* if map is not integer, read quant rules, and get limits */ if (G_raster_map_type(name, mapset) != CELL_TYPE) { DCELL dmin, dmax; if (G_read_quant(name, mapset, &quant) < 0) { sprintf(buf, "G_read_range(): can't read quant rules for fp map %s@%s", name, mapset); G_warning(buf); return -1; } if (G_quant_is_truncate(&quant) || G_quant_is_round(&quant)) { if (G_read_fp_range(name, mapset, &drange) >= 0) { G_get_fp_range_min_max(&drange, &dmin, &dmax); if (G_quant_is_truncate(&quant)) { x[0] = (CELL) dmin; x[1] = (CELL) dmax; } else { /* round */ if (dmin > 0) x[0] = (CELL) (dmin + .5); else x[0] = (CELL) (dmin - .5); if (dmax > 0) x[1] = (CELL) (dmax + .5); else x[1] = (CELL) (dmax - .5); } } else return -1; } else G_quant_get_limits(&quant, &dmin, &dmax, &x[0], &x[1]); G_update_range(x[0], range); G_update_range(x[1], range); return 3; } if (G_find_file2_misc("cell_misc", "range", name, mapset)) { fd = G_fopen_old_misc("cell_misc", "range", name, mapset); if (!fd) goto error; /* if range file exists but empty */ if (!fgets(buf, sizeof buf, fd)) return 2; x[0] = x[1] = x[2] = x[3] = 0; count = sscanf(buf, "%d%d%d%d", &x[0], &x[1], &x[2], &x[3]); /* if wrong format */ if (count <= 0) goto error; for (n = 0; n < count; n++) { /* if count==4, the range file is old (4.1) and 0's in it have to be ignored */ if (count < 4 || x[n]) G_update_range((CELL) x[n], range); } fclose(fd); return 1; } error: if (fd) fclose(fd); sprintf(buf, _("can't read range file for [%s in %s]"), name, mapset); G_warning(buf); return -1; } /*-------------------------------------------------------------------------*/ /*! * \brief write raster range file * * This routine writes the range information for the raster map * name in the current mapset from the range structure. * A diagnostic message is printed and -1 is returned if there is an error * writing the range file. Otherwise, 0 is returned. * * 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. * * \param name * \param range * * \return int */ int G_write_range(const char *name, const struct Range *range) { FILE *fd; if (G_raster_map_type(name, G_mapset()) != CELL_TYPE) goto error; fd = G_fopen_new_misc("cell_misc", "range", name); if (!fd) goto error; if (range->first_time) /* if range hasn't been updated */ { fclose(fd); return 0; } fprintf(fd, "%ld %ld\n", (long)range->min, (long)range->max); fclose(fd); return 0; error: G_remove_misc("cell_misc", "range", name); /* remove the old file with this name */ G_warning(_("can't write range file for [%s in %s]"), name, G_mapset()); return -1; } /*-------------------------------------------------------------------------*/ /*! * \brief * * 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. * * \param r * \return */ int G_write_fp_range(const char *name, const struct FPRange *range) { int fd; char xdr_buf[100]; XDR xdr_str; fd = G_open_new_misc("cell_misc", "f_range", name); if (fd < 0) goto error; if (range->first_time) /* if range hasn't been updated, write empty file meaning Nulls */ { close(fd); return 0; } xdrmem_create(&xdr_str, xdr_buf, (u_int) XDR_DOUBLE_NBYTES * 2, XDR_ENCODE); if (!xdr_double(&xdr_str, (double *)&(range->min))) goto error; if (!xdr_double(&xdr_str, (double *)&(range->max))) goto error; write(fd, xdr_buf, XDR_DOUBLE_NBYTES * 2); close(fd); return 0; error: G_remove_misc("cell_misc", "f_range", name); /* remove the old file with this name */ G_warning(_("can't write range file for [%s in %s]"), name, G_mapset()); return -1; } /*-------------------------------------------------------------------------*/ /*! * \brief update range structure * * Compares the cat value with the minimum and maximum * values in the range structure, modifying the range if cat * extends the range. * * NULL-values must be detected and ignored. * * \param cat * \param range * * \return */ void G_update_range(CELL cat, struct Range *range) { if (!G_is_c_null_value(&cat)) { if (range->first_time) { range->first_time = 0; range->min = cat; range->max = cat; return; } if (cat < range->min) range->min = cat; if (cat > range->max) range->max = cat; } } /*-------------------------------------------------------------------------*/ void G_update_fp_range(DCELL val, struct FPRange *range) { if (!G_is_d_null_value(&val)) { if (range->first_time) { range->first_time = 0; range->min = val; range->max = val; return; } if (val < range->min) range->min = val; if (val > range->max) range->max = val; } } /*-------------------------------------------------------------------------*/ /*! * \brief update range structure * * This routine updates the range data * just like G_update_range, but for n values from the * cell array. * * \param cell * \param n * \param range * \return */ void G_row_update_range(const CELL *cell, int n, struct Range *range) { G__row_update_range(cell, n, range, 0); } /*-------------------------------------------------------------------------*/ void G__row_update_range(const CELL *cell, int n, struct Range *range, int ignore_zeros) { CELL cat; while (n-- > 0) { cat = *cell++; if (G_is_c_null_value(&cat) || (ignore_zeros && !cat)) continue; if (range->first_time) { range->first_time = 0; range->min = cat; range->max = cat; continue; } if (cat < range->min) range->min = cat; if (cat > range->max) range->max = cat; } } /*-------------------------------------------------------------------------*/ void G_row_update_fp_range(const void *rast, int n, struct FPRange *range, RASTER_MAP_TYPE data_type) { DCELL val = 0L; while (n-- > 0) { switch (data_type) { case CELL_TYPE: val = (DCELL) * ((CELL *) rast); break; case FCELL_TYPE: val = (DCELL) * ((FCELL *) rast); break; case DCELL_TYPE: val = *((DCELL *) rast); break; } if (G_is_null_value(rast, data_type)) { rast = G_incr_void_ptr(rast, G_raster_size(data_type)); continue; } if (range->first_time) { range->first_time = 0; range->min = val; range->max = val; } else { if (val < range->min) range->min = val; if (val > range->max) range->max = val; } rast = G_incr_void_ptr(rast, G_raster_size(data_type)); } } /*-------------------------------------------------------------------------*/ /*! * \brief initialize range structure * * Initializes the range structure for updates by * G_update_range and G_row_update_range. * * Must set a flag in the range structure that indicates that * no min/max have been defined - probably a "first" boolean flag. * * \param range * \return */ void G_init_range(struct Range *range) { G_set_c_null_value(&(range->min), 1); G_set_c_null_value(&(range->max), 1); range->first_time = 1; } /*-------------------------------------------------------------------------*/ /*! * \brief get range min and max * * The mininum and maximum CELL * values are extracted from the range structure. * * 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. * * \param range * \param min * \param max * \return */ void G_get_range_min_max(const struct Range *range, CELL * min, CELL * max) { if (range->first_time) { G_set_c_null_value(min, 1); G_set_c_null_value(max, 1); } else { if (G_is_c_null_value(&(range->min))) G_set_c_null_value(min, 1); else *min = range->min; if (G_is_c_null_value(&(range->max))) G_set_c_null_value(max, 1); else *max = range->max; } } /*-------------------------------------------------------------------------*/ /*! * \brief * * Must set a flag in the range * structure that indicates that no min/max have been defined - probably a * "first" boolean flag. * * \param r * \return */ void G_init_fp_range(struct FPRange *range) { G_set_d_null_value(&(range->min), 1); G_set_d_null_value(&(range->max), 1); range->first_time = 1; } /*-------------------------------------------------------------------------*/ /*! * \brief * * 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. * * \param r * \param min * \param max * \return */ void G_get_fp_range_min_max(const struct FPRange *range, DCELL *min, DCELL *max) { if (range->first_time) { G_set_d_null_value(min, 1); G_set_d_null_value(max, 1); } else { if (G_is_d_null_value(&(range->min))) G_set_d_null_value(min, 1); else *min = range->min; if (G_is_d_null_value(&(range->max))) G_set_d_null_value(max, 1); else *max = range->max; } }