123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662 |
- /**********************************************************************
- *
- * 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 <unistd.h>
- #include <rpc/types.h> /* need this for sgi */
- #include <rpc/xdr.h>
- #include "G.h"
- #include <grass/glocale.h>
- #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 <em>r</em> 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 <tt>f_range</tt>. This file is
- * written in binary using XDR format. If there is no defined min/max in <em>r</em>,
- * an empty <tt>f_range</tt>file 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 <tt>G_construct_default_range()</tt>.
- *
- * \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 <b>name</b> in <b>mapset</b> into the <b>range</b>
- * 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 <tt>G_construct_default_range()</tt>.
- *
- * \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
- * <b>name</b> in the current mapset from the <b>range</b> 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 <tt>f_range</tt>. This file is written in binary using XDR format. If
- * there is no defined min/max in <em>r</em>, an empty <tt>f_range</tt>file 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 <b>cat</b> value with the minimum and maximum
- * values in the <b>range</b> structure, modifying the range if <b>cat</b>
- * 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 <b>range</b> data
- * just like <i>G_update_range</i>, but for <b>n</b> values from the
- * <b>cell</b> 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 <b>range</b> structure for updates by
- * <i>G_update_range</i> and <i>G_row_update_range.</i>
- *
- * Must set a flag in the range structure that indicates that
- * no min/max have been defined - probably a <tt>"first"</tt> 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 <b>min</b>inum and <b>max</b>imum CELL
- * values are extracted from the <b>range</b> 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
- * <tt>"first"</tt> 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 <em>r</em>.
- * 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;
- }
- }
|