/*! * \brief Read raster range (CELL) * * This routine reads the range information for the raster map * <i>name</i> in <i>mapset</i> into the <i>range</i> 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 map name * \param mapset mapset name * \param[out] range pointer to Range structure which holds range info * * \return -1 on error * \return 1 on success * \return 2 if range is empty * \return 3 if raster map is floating-point, get range from quant rules */ int Rast_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; Rast_init_range(range); fd = NULL; /* if map is not integer, read quant rules, and get limits */ if (Rast_map_type(name, mapset) != CELL_TYPE) { DCELL dmin, dmax; if (Rast_read_quant(name, mapset, &quant) < 0) { G_warning(_("Unable to read quant rules for raster map <%s>"), G_fully_qualified_name(name, mapset)); return -1; } if (Rast_quant_is_truncate(&quant) || Rast_quant_is_round(&quant)) { if (Rast_read_fp_range(name, mapset, &drange) >= 0) { Rast_get_fp_range_min_max(&drange, &dmin, &dmax); if (Rast_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 Rast_quant_get_limits(&quant, &dmin, &dmax, &x[0], &x[1]); Rast_update_range(x[0], range); Rast_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) { G_warning(_("Unable to read range file for <%s>"), G_fully_qualified_name(name, mapset)); return -1; } /* if range file exists but empty */ if (!fgets(buf, sizeof buf, fd)) { if (fd) fclose(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) { if (fd) fclose(fd); G_warning(_("Unable to read range file for <%s>"), G_fully_qualified_name(name, mapset)); return -1; } 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]) Rast_update_range((CELL) x[n], range); } fclose(fd); } return 1; }
int main(int argc, char *argv[]) { int *fd; char **names; char **ptr; char *name; /* flags */ int raw_data; int with_coordinates; int with_xy; int with_percents; int with_counts; int with_areas; int with_labels; /* printf format */ char fmt[20]; int dp; struct Range range; struct FPRange fp_range; struct Quant q; CELL min, max, null_set = 0; DCELL dmin, dmax; struct GModule *module; struct { struct Flag *A; /* print averaged values instead of intervals */ struct Flag *a; /* area */ struct Flag *c; /* cell counts */ struct Flag *p; /* percents */ struct Flag *l; /* with labels */ struct Flag *q; /* quiet */ struct Flag *n; /* Suppress reporting of any NULLs */ struct Flag *N; /* Suppress reporting of NULLs when all values are NULL */ struct Flag *one; /* one cell per line */ struct Flag *x; /* with row/col */ struct Flag *g; /* with east/north */ struct Flag *i; /* use quant rules for fp map, i.e. read it as int */ struct Flag *r; /* raw output: when nsteps option is used, report indexes of ranges instead of ranges themselves; when -C (cats) option is used reports indexes of fp ranges = ind. of labels */ struct Flag *C; /* report stats for labeled ranges in cats files */ } flag; struct { struct Option *cell; struct Option *fs; struct Option *nv; struct Option *output; struct Option *nsteps; /* divide data range into nsteps and report stats for these ranges: only for fp maps NOTE: when -C flag is used, and there are explicit fp ranges in cats or when the map is int, nsteps is ignored */ } option; G_gisinit(argv[0]); module = G_define_module(); G_add_keyword(_("raster")); G_add_keyword(_("statistics")); module->description = _("Generates area statistics for raster map layers."); /* Define the different options */ option.cell = G_define_standard_option(G_OPT_R_INPUTS); option.output = G_define_standard_option(G_OPT_F_OUTPUT); option.output->required = NO; option.output->description = _("Name for output file (if omitted or \"-\" output to stdout)"); option.fs = G_define_standard_option(G_OPT_F_SEP); option.fs->key_desc = "character|space|tab"; option.fs->answer = "space"; option.fs->description = _("Output field separator"); option.nv = G_define_option(); option.nv->key = "nv"; option.nv->type = TYPE_STRING; option.nv->required = NO; option.nv->multiple = NO; option.nv->answer = "*"; option.nv->description = _("String representing no data cell value"); option.nsteps = G_define_option(); option.nsteps->key = "nsteps"; option.nsteps->type = TYPE_INTEGER; option.nsteps->required = NO; option.nsteps->multiple = NO; option.nsteps->answer = "255"; option.nsteps->description = _("Number of fp subranges to collect stats from"); /* Define the different flags */ flag.one = G_define_flag(); flag.one->key = '1'; flag.one->description = _("One cell (range) per line"); flag.A = G_define_flag(); flag.A->key = 'A'; flag.A->description = _("Print averaged values instead of intervals"); flag.A->guisection = _("Print"); flag.a = G_define_flag(); flag.a->key = 'a'; flag.a->description = _("Print area totals"); flag.a->guisection = _("Print"); flag.c = G_define_flag(); flag.c->key = 'c'; flag.c->description = _("Print cell counts"); flag.c->guisection = _("Print"); flag.p = G_define_flag(); flag.p->key = 'p'; flag.p->description = _("Print APPROXIMATE percents (total percent may not be 100%)"); flag.p->guisection = _("Print"); flag.l = G_define_flag(); flag.l->key = 'l'; flag.l->description = _("Print category labels"); flag.l->guisection = _("Print"); flag.g = G_define_flag(); flag.g->key = 'g'; flag.g->description = _("Print grid coordinates (east and north)"); flag.g->guisection = _("Print"); flag.x = G_define_flag(); flag.x->key = 'x'; flag.x->description = _("Print x and y (column and row)"); flag.x->guisection = _("Print"); flag.r = G_define_flag(); flag.r->key = 'r'; flag.r->description = _("Print raw indexes of fp ranges (fp maps only)"); flag.r->guisection = _("Print"); flag.n = G_define_flag(); flag.n->key = 'n'; flag.n->description = _("Suppress reporting of any NULLs"); flag.N = G_define_flag(); flag.N->key = 'N'; flag.N->description = _("Suppress reporting of NULLs when all values are NULL"); flag.C = G_define_flag(); flag.C->key = 'C'; flag.C->description = _("Report for cats fp ranges (fp maps only)"); flag.i = G_define_flag(); flag.i->key = 'i'; flag.i->description = _("Read fp map as integer (use map's quant rules)"); if (G_parser(argc, argv)) exit(EXIT_FAILURE); name = option.output->answer; if (name != NULL && strcmp(name, "-") != 0) { if (NULL == freopen(name, "w", stdout)) { G_fatal_error(_("Unable to open file <%s> for writing"), name); } } sscanf(option.nsteps->answer, "%d", &nsteps); if (nsteps <= 0) { G_warning(_("'%s' must be greater than zero; using %s=255"), option.nsteps->key, option.nsteps->key); nsteps = 255; } cat_ranges = flag.C->answer; averaged = flag.A->answer; raw_output = flag.r->answer; as_int = flag.i->answer; nrows = Rast_window_rows(); ncols = Rast_window_cols(); fd = NULL; nfiles = 0; dp = -1; with_percents = flag.p->answer; with_counts = flag.c->answer; with_areas = flag.a->answer; with_labels = flag.l->answer; no_nulls = flag.n->answer; no_nulls_all = flag.N->answer; no_data_str = option.nv->answer; raw_data = flag.one->answer; with_coordinates = flag.g->answer; with_xy = flag.x->answer; if (with_coordinates || with_xy) raw_data = 1; /* get field separator */ strcpy(fs, " "); if (option.fs->answer) { if (strcmp(option.fs->answer, "space") == 0) *fs = ' '; else if (strcmp(option.fs->answer, "tab") == 0) *fs = '\t'; else if (strcmp(option.fs->answer, "\\t") == 0) *fs = '\t'; else *fs = *option.fs->answer; } /* open all raster maps */ if (option.cell->answers[0] == NULL) G_fatal_error(_("Raster map not found")); names = option.cell->answers; ptr = option.cell->answers; for (; *ptr != NULL; ptr++) { name = *ptr; fd = (int *)G_realloc(fd, (nfiles + 1) * sizeof(int)); is_fp = (int *)G_realloc(is_fp, (nfiles + 1) * sizeof(int)); DMAX = (DCELL *) G_realloc(DMAX, (nfiles + 1) * sizeof(DCELL)); DMIN = (DCELL *) G_realloc(DMIN, (nfiles + 1) * sizeof(DCELL)); fd[nfiles] = Rast_open_old(name, ""); if (!as_int) is_fp[nfiles] = Rast_map_is_fp(name, ""); else { is_fp[nfiles] = 0; if (cat_ranges || nsteps != 255) G_warning(_("Raster map <%s> is reading as integer map! " "Flag '-%c' and/or '%s' option will be ignored."), name, flag.C->key, option.nsteps->key); } if (with_labels || (cat_ranges && is_fp[nfiles])) { labels = (struct Categories *) G_realloc(labels, (nfiles + 1) * sizeof(struct Categories)); if (Rast_read_cats(name, "", &labels[nfiles]) < 0) Rast_init_cats("", &labels[nfiles]); } if (is_fp[nfiles]) /* floating point map */ { Rast_quant_init(&q); if (cat_ranges) { if (!Rast_quant_nof_rules(&labels[nfiles].q)) { G_warning(_("Cats for raster map <%s> are either missing or have no explicit labels. " "Using %s=%d."), name, option.nsteps->key, nsteps); cat_ranges = 0; } else if (nsteps != 255) G_warning(_("Flag '-%c' was given, using cats fp ranges of raster map <%s>, " "ignoring '%s' option"), flag.C->key, name, option.nsteps->key); } if (!cat_ranges) { /* DO NOT use else here, cat_ranges can change */ if (Rast_read_fp_range(name, "", &fp_range) < 0) G_fatal_error(_("Unable to read fp range of raster map <%s>"), name); Rast_get_fp_range_min_max(&fp_range, &DMIN[nfiles], &DMAX[nfiles]); G_debug(3, "file %2d: dmin=%f dmax=%f", nfiles, DMIN[nfiles], DMAX[nfiles]); Rast_quant_add_rule(&q, DMIN[nfiles], DMAX[nfiles], 1, nsteps+1); /* set the quant rules for reading the map */ Rast_set_quant_rules(fd[nfiles], &q); Rast_quant_get_limits(&q, &dmin, &dmax, &min, &max); G_debug(2, "overall: dmin=%f dmax=%f, qmin=%d qmax=%d", dmin, dmax, min, max); Rast_quant_free(&q); } else { /* cats ranges */ /* set the quant rules for reading the map */ Rast_set_quant_rules(fd[nfiles], &labels[nfiles].q); Rast_quant_get_limits(&labels[nfiles].q, &dmin, &dmax, &min, &max); } } else { if (Rast_read_range(name, "", &range) < 0) G_fatal_error(_("Unable to read range for map <%s>"), name); Rast_get_range_min_max(&range, &min, &max); } if (!null_set) { null_set = 1; NULL_CELL = max + 1; } else if (NULL_CELL < max + 1) NULL_CELL = max + 1; nfiles++; } if (dp < 0) strcpy(fmt, "%lf"); else sprintf(fmt, "%%.%dlf", dp); if (raw_data) raw_stats(fd, with_coordinates, with_xy, with_labels); else cell_stats(fd, with_percents, with_counts, with_areas, with_labels, fmt); exit(EXIT_SUCCESS); }
int read_rules(const char *filename) { char buf[1024]; DCELL dLow, dHigh; CELL iLow, iHigh; int line, n, nrules = 0; int first = 1; DCELL dmin, dmax; CELL cmin, cmax; FILE *fp; if (strcmp(filename, "-") == 0) fp = stdin; else { fp = fopen(filename, "r"); if (!fp) G_fatal_error(_("unable to open input file <%s>"), filename); } read_range(); report_range(); if (isatty(fileno(fp))) fprintf(stderr, _("\nEnter the rule or 'help' for the format description or 'end' to exit:\n")); Rast_quant_init(&quant_struct); for (line = 1;; line++) { if (isatty(fileno(fp))) fprintf(stderr, "> "); if (!G_getl2(buf, sizeof(buf), fp)) break; for (n = 0; buf[n]; n++) if (buf[n] == ',') buf[n] = ' '; G_strip(buf); G_chop(buf); if (*buf == 0) continue; if (*buf == '#') continue; if (strcmp(buf, "end") == 0) { if (nrules == 0) break; /* if no new rules have been specified */ /* give warning when quant rules do not cover the whole range of map */ Rast_quant_get_limits(&quant_struct, &dmin, &dmax, &cmin, &cmax); if ((dmin > old_dmin || dmax < old_dmax) && !first) G_warning(_("quant rules do not cover the whole range map")); break; } if (strcmp(buf, "help") == 0) { fprintf(stderr, "Enter a rule in one of these formats:\n" "float_low:float_high:int_low:int_high\n" "float_low:float_high:int_val (i.e. int_high == int_low)\n" "*:float_val:int_val (interval [inf, float_val])\n" "float_val:*:int_val (interval [float_val, inf])\n"); } /* we read and record into quant table all values, even int as doubles we convert the range and domain values to the right format when we lookup the values in the quant table */ switch (sscanf(buf, "%lf:%lf:%d:%d", &dLow, &dHigh, &iLow, &iHigh)) { case 3: Rast_quant_add_rule(&quant_struct, dLow, dHigh, iLow, iLow); nrules++; first = 0; break; case 4: Rast_quant_add_rule(&quant_struct, dLow, dHigh, iLow, iHigh); nrules++; first = 0; break; default: if (sscanf(buf, "%lf:*:%d", &dLow, &iLow) == 2) { Rast_quant_set_pos_infinite_rule(&quant_struct, dLow, iLow); nrules++; first = 0; } else if (sscanf(buf, "*:%lf:%d", &dHigh, &iLow) == 2) { Rast_quant_set_neg_infinite_rule(&quant_struct, dHigh, iLow); nrules++; first = 0; } else if (strcmp(buf, "help") == 0) break; else G_warning(_("%s is not a valid rule"), buf); break; } /* switch */ } /* loop */ if (fp != stdin) fclose(fp); return nrules; }