123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413 |
- /*!
- * \file lib/raster/reclass.c
- *
- * \brief Raster Library - Check if raster map is reclassified
- *
- * (C) 2001-2009 by the GRASS Development Team
- *
- * This program is free software under the GNU General Public License
- * (>=v2). Read the file COPYING that comes with GRASS for details.
- *
- * \author Original author CERL
- */
- #include <string.h>
- #include <grass/gis.h>
- #include <grass/raster.h>
- #include <grass/glocale.h>
- static const char NULL_STRING[] = "null";
- static int reclass_type(FILE *, char **, char **);
- static FILE *fopen_cellhd_old(const char *, const char *);
- static FILE *fopen_cellhd_new(const char *);
- static int get_reclass_table(FILE *, struct Reclass *);
- /*!
- * \brief Check if raster map is reclassified
- *
- * This function determines if the raster map <i>name</i> in
- * <i>mapset</i> is a reclass file. If it is, then the name and mapset
- * of the referenced raster map are copied into the <i>rname</i> and
- * <i>rmapset</i> buffers.
- *
- * \param name map name
- * \param mapset mapset name
- * \param[out] rname name of reference map
- * \param[out] rmapset mapset where reference map lives
- *
- * \returns 1 if it is a reclass file
- * \return 0 if it is not
- * \return -1 if there was a problem reading the raster header
- */
- int Rast_is_reclass(const char *name, const char *mapset, char *rname,
- char *rmapset)
- {
- FILE *fd;
- int type;
- fd = fopen_cellhd_old(name, mapset);
- if (fd == NULL)
- return -1;
- type = reclass_type(fd, &rname, &rmapset);
- fclose(fd);
- if (type < 0)
- return -1;
- else
- return type != 0;
- }
- /*!
- * \brief Get child reclass maps list
- *
- * This function generates a child reclass maps list from the
- * cell_misc/reclassed_to file which stores this list. The
- * cell_misc/reclassed_to file is written by Rast_put_reclass().
- * Rast_is_reclassed_to() is used by <tt>g.rename</tt>, <tt>g.remove</tt>
- * and <tt>r.reclass</tt> to prevent accidentally deleting the parent
- * map of a reclassed raster map.
- *
- * \param name map name
- * \param mapset mapset name
- * \param[out] nrmaps number of reference maps
- * \param[out] rmaps array of names of reference maps
- *
- * \return number of reference maps
- * \return -1 on error
- */
- int Rast_is_reclassed_to(const char *name, const char *mapset, int *nrmaps,
- char ***rmaps)
- {
- FILE *fd;
- int i, j, k, l;
- char buf2[256], buf3[256];
- fd = G_fopen_old_misc("cell_misc", "reclassed_to", name, mapset);
- if (fd == NULL) {
- return -1;
- }
- if (rmaps)
- *rmaps = NULL;
- for (i = 0; !feof(fd) && fgets(buf2, 255, fd);) {
- l = strlen(buf2);
- for (j = 0, k = 0; j < l; j++) {
- if (buf2[j] == '#' ||
- ((buf2[j] == ' ' || buf2[j] == '\t' || buf2[j] == '\n') && k))
- break;
- else if (buf2[j] != ' ' && buf2[j] != '\t')
- buf3[k++] = buf2[j];
- }
- if (k) {
- buf3[k] = 0;
- i++;
- if (rmaps) {
- *rmaps = (char **)G_realloc(*rmaps, i * sizeof(char *));
- (*rmaps)[i - 1] = (char *)G_malloc(k + 1);
- strncpy((*rmaps)[i - 1], buf3, k);
- (*rmaps)[i - 1][k] = 0;
- }
- }
- }
- if (nrmaps)
- *nrmaps = i;
- if (i && rmaps) {
- i++;
- *rmaps = (char **)G_realloc(*rmaps, i * sizeof(char *));
- (*rmaps)[i - 1] = NULL;
- }
- fclose(fd);
- return i;
- }
- /*!
- \brief Get reclass
- \param name map name
- \param mapset mapset name
- \param[out] reclass pointer to Reclass structure
- \return -1 on error
- \return type code
- */
- int Rast_get_reclass(const char *name, const char *mapset,
- struct Reclass *reclass)
- {
- FILE *fd;
- int stat;
- fd = fopen_cellhd_old(name, mapset);
- if (fd == NULL)
- return -1;
- reclass->name = NULL;
- reclass->mapset = NULL;
- reclass->type = reclass_type(fd, &reclass->name, &reclass->mapset);
- if (reclass->type <= 0) {
- fclose(fd);
- return reclass->type;
- }
- switch (reclass->type) {
- case RECLASS_TABLE:
- stat = get_reclass_table(fd, reclass);
- break;
- default:
- stat = -1;
- }
- fclose(fd);
- if (stat < 0) {
- if (stat == -2)
- G_warning(_("Too many reclass categories for <%s@%s>"),
- name, mapset);
- else
- G_warning(_("Illegal reclass format in header file for <%s@%s>"),
- name, mapset);
- stat = -1;
- }
- return stat;
- }
- /*!
- \brief Free Reclass structure
- \param reclass pointer to Reclass structure
- */
- void Rast_free_reclass(struct Reclass *reclass)
- {
- switch (reclass->type) {
- case RECLASS_TABLE:
- if (reclass->num > 0)
- G_free(reclass->table);
- reclass->num = 0;
- if (reclass->name)
- G_free(reclass->name);
- if (reclass->mapset)
- G_free(reclass->mapset);
- reclass->name = NULL;
- reclass->mapset = NULL;
- break;
- default:
- break;
- }
- }
- static int reclass_type(FILE * fd, char **rname, char **rmapset)
- {
- char buf[128];
- char label[128], arg[128];
- int i;
- int type;
- /* Check to see if this is a reclass file */
- if (fgets(buf, sizeof(buf), fd) == NULL)
- return 0;
- if (strncmp(buf, "reclas", 6))
- return 0;
- /* later may add other types of reclass */
- type = RECLASS_TABLE;
- /* Read the mapset and file name of the REAL cell file */
- if (*rname)
- **rname = '\0';
- if (*rmapset)
- **rmapset = '\0';
- for (i = 0; i < 2; i++) {
- if (fgets(buf, sizeof buf, fd) == NULL)
- return -1;
- if (sscanf(buf, "%[^:]:%s", label, arg) != 2)
- return -1;
- if (strncmp(label, "maps", 4) == 0) {
- if (*rmapset)
- strcpy(*rmapset, arg);
- else
- *rmapset = G_store(arg);
- }
- else if (strncmp(label, "name", 4) == 0) {
- if (*rname)
- strcpy(*rname, arg);
- else
- *rname = G_store(arg);
- }
- else
- return -1;
- }
- if (**rmapset && **rname)
- return type;
- else
- return -1;
- }
- static FILE *fopen_cellhd_old(const char *name, const char *mapset)
- {
- return G_fopen_old("cellhd", name, mapset);
- }
- /*!
- \brief Put reclass
- \param name map name
- \param reclass pointer to Reclass structure
- \return -1 on error
- \return 1 on success
- */
- int Rast_put_reclass(const char *name, const struct Reclass *reclass)
- {
- FILE *fd;
- long min, max;
- int found;
- char buf1[GPATH_MAX], buf2[GNAME_MAX], *p;
- char *xname;
- switch (reclass->type) {
- case RECLASS_TABLE:
- if (reclass->min > reclass->max || reclass->num <= 0) {
- G_fatal_error(_("Illegal reclass request"));
- return -1;
- }
- break;
- default:
- G_fatal_error(_("Illegal reclass type"));
- return -1;
- }
- fd = fopen_cellhd_new(name);
- if (fd == NULL) {
- G_warning(_("Unable to create header file for <%s@%s>"),
- name, G_mapset());
- return -1;
- }
- fprintf(fd, "reclass\n");
- fprintf(fd, "name: %s\n", reclass->name);
- fprintf(fd, "mapset: %s\n", reclass->mapset);
- /* find first non-null entry */
- for (min = 0; min < reclass->num; min++)
- if (!Rast_is_c_null_value(&reclass->table[min]))
- break;
- /* find last non-zero entry */
- for (max = reclass->num - 1; max >= 0; max--)
- if (!Rast_is_c_null_value(&reclass->table[max]))
- break;
- /*
- * if the resultant table is empty, write out a dummy table
- * else write out the table
- * first entry is #min
- * rest are translations for cat min+i
- */
- if (min > max)
- fprintf(fd, "0\n");
- else {
- fprintf(fd, "#%ld\n", (long)reclass->min + min);
- while (min <= max) {
- if (Rast_is_c_null_value(&reclass->table[min]))
- fprintf(fd, "%s\n", NULL_STRING);
- else
- fprintf(fd, "%ld\n", (long)reclass->table[min]);
- min++;
- }
- }
- fclose(fd);
- strcpy(buf2, reclass->name);
- if ((p = strchr(buf2, '@')))
- *p = 0;
- G_file_name_misc(buf1, "cell_misc", "reclassed_to", reclass->name,
- reclass->mapset);
- fd = fopen(buf1, "a+");
- if (fd == NULL) {
- #if 0
- G_warning(_("Unable to create dependency file in <%s@%s>"),
- buf2, reclass->mapset);
- #endif
- return 1;
- }
- G_fseek(fd, 0L, SEEK_SET);
- xname = G_fully_qualified_name(name, G_mapset());
- found = 0;
- for (;;) {
- char buf[GNAME_MAX + GMAPSET_MAX];
- if (!G_getl2(buf, sizeof(buf), fd))
- break;
- if (strcmp(xname, buf) == 0) {
- found = 1;
- break;
- }
- }
- if (!found)
- fprintf(fd, "%s\n", xname);
- G_free(xname);
- fclose(fd);
- return 1;
- }
- static FILE *fopen_cellhd_new(const char *name)
- {
- return G_fopen_new("cellhd", name);
- }
- static int get_reclass_table(FILE * fd, struct Reclass *reclass)
- {
- char buf[128];
- int n;
- int first, null_str_size;
- CELL cat;
- long len;
- /*
- * allocate the table, expanding as each entry is read
- * note that G_realloc() will become G_malloc() if ptr in
- * NULL
- */
- reclass->min = 0;
- reclass->table = NULL;
- null_str_size = strlen(NULL_STRING);
- n = 0;
- first = 1;
- while (fgets(buf, sizeof buf, fd)) {
- if (first) {
- first = 0;
- if (sscanf(buf, "#%d", &cat) == 1) {
- reclass->min = cat;
- continue;
- }
- }
- if (strncmp(buf, NULL_STRING, null_str_size) == 0)
- Rast_set_c_null_value(&cat, 1);
- else {
- if (sscanf(buf, "%d", &cat) != 1)
- return -1;
- }
- n++;
- len = (long)n *sizeof(CELL);
- if (len != (int)len) { /* check for int overflow */
- if (reclass->table != NULL)
- G_free(reclass->table);
- return -2;
- }
- reclass->table = (CELL *) G_realloc((char *)reclass->table, (int)len);
- reclass->table[n - 1] = cat;
- }
- reclass->max = reclass->min + n - 1;
- reclass->num = n;
- return 1;
- }
|