123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403 |
- /****************************************************************************
- *
- * MODULE: r.resamp.stats
- * AUTHOR(S): Glynn Clements <glynn gclements.plus.com> (original contributor)
- * Hamish Bowman <hamish_b yahoo.com>
- * PURPOSE:
- * COPYRIGHT: (C) 2006-2007 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.
- *
- *****************************************************************************/
- #include <stdlib.h>
- #include <string.h>
- #include <math.h>
- #include <grass/gis.h>
- #include <grass/raster.h>
- #include <grass/glocale.h>
- #include <grass/stats.h>
- static const struct menu
- {
- stat_func *method; /* routine to compute new value */
- stat_func_w *method_w; /* routine to compute new value (weighted) */
- char *name; /* method name */
- char *text; /* menu display - full description */
- } menu[] = {
- {c_ave, w_ave, "average", "average (mean) value"},
- {c_median, w_median, "median", "median value"},
- {c_mode, w_mode, "mode", "most frequently occurring value"},
- {c_min, w_min, "minimum", "lowest value"},
- {c_max, w_max, "maximum", "highest value"},
- {c_range, NULL, "range", "range value"},
- {c_quart1, w_quart1, "quart1", "first quartile"},
- {c_quart3, w_quart3, "quart3", "third quartile"},
- {c_perc90, w_perc90, "perc90", "ninetieth percentile"},
- {c_sum, w_sum, "sum", "sum of values"},
- {c_var, w_var, "variance", "variance value"},
- {c_stddev, w_stddev, "stddev", "standard deviation"},
- {c_quant, w_quant, "quantile", "arbitrary quantile"},
- {c_count, w_count, "count", "count of non-NULL values"},
- {c_divr, NULL, "diversity", "number of different values"},
- {NULL, NULL, NULL, NULL}
- };
- static char *build_method_list(void)
- {
- char *buf = G_malloc(1024);
- char *p = buf;
- int i;
- for (i = 0; menu[i].name; i++) {
- char *q;
- if (i)
- *p++ = ',';
- for (q = menu[i].name; *q; p++, q++)
- *p = *q;
- }
- *p = '\0';
- return buf;
- }
- static int find_method(const char *name)
- {
- int i;
- for (i = 0; menu[i].name; i++)
- if (strcmp(menu[i].name, name) == 0)
- return i;
- return -1;
- }
- static int nulls;
- static int infile, outfile;
- static struct Cell_head dst_w, src_w;
- static DCELL *outbuf;
- static DCELL **bufs;
- static int method;
- static const void *closure;
- static int row_scale, col_scale;
- static double quantile;
- static void resamp_unweighted(void)
- {
- stat_func *method_fn;
- DCELL *values;
- int *col_map, *row_map;
- int row, col;
- method_fn = menu[method].method;
- values = G_malloc(row_scale * col_scale * sizeof(DCELL));
- col_map = G_malloc((dst_w.cols + 1) * sizeof(int));
- row_map = G_malloc((dst_w.rows + 1) * sizeof(int));
- for (col = 0; col <= dst_w.cols; col++) {
- double x = Rast_col_to_easting(col, &dst_w);
- /* col_map[col] = (int)floor(Rast_easting_to_col(x, &src_w) + 0.5); */
- col_map[col] = (int)floor((x - src_w.west) / src_w.ew_res + 0.5);
- }
- for (row = 0; row <= dst_w.rows; row++) {
- double y = Rast_row_to_northing(row, &dst_w);
- row_map[row] = (int)floor(Rast_northing_to_row(y, &src_w) + 0.5);
- }
- for (row = 0; row < dst_w.rows; row++) {
- int maprow0 = row_map[row + 0];
- int maprow1 = row_map[row + 1];
- int count = maprow1 - maprow0;
- int i;
- G_percent(row, dst_w.rows, 4);
- for (i = 0; i < count; i++)
- Rast_get_d_row(infile, bufs[i], maprow0 + i);
- for (col = 0; col < dst_w.cols; col++) {
- int mapcol0 = col_map[col + 0];
- int mapcol1 = col_map[col + 1];
- int null = 0;
- int n = 0;
- int i, j;
- for (i = maprow0; i < maprow1; i++)
- for (j = mapcol0; j < mapcol1; j++) {
- DCELL *src = &bufs[i - maprow0][j];
- DCELL *dst = &values[n++];
- if (Rast_is_d_null_value(src)) {
- Rast_set_d_null_value(dst, 1);
- null = 1;
- }
- else
- *dst = *src;
- }
- if (null && nulls)
- Rast_set_d_null_value(&outbuf[col], 1);
- else
- (*method_fn) (&outbuf[col], values, n, closure);
- }
- Rast_put_d_row(outfile, outbuf);
- }
- }
- static void resamp_weighted(void)
- {
- stat_func_w *method_fn;
- DCELL(*values)[2];
- double *col_map, *row_map;
- int row, col;
- method_fn = menu[method].method_w;
- values = G_malloc(row_scale * col_scale * 2 * sizeof(DCELL));
- col_map = G_malloc((dst_w.cols + 1) * sizeof(double));
- row_map = G_malloc((dst_w.rows + 1) * sizeof(double));
- for (col = 0; col <= dst_w.cols; col++) {
- double x = Rast_col_to_easting(col, &dst_w);
- /* col_map[col] = Rast_easting_to_col(x, &src_w); */
- col_map[col] = (x - src_w.west) / src_w.ew_res;
- }
- for (row = 0; row <= dst_w.rows; row++) {
- double y = Rast_row_to_northing(row, &dst_w);
- row_map[row] = Rast_northing_to_row(y, &src_w);
- }
- for (row = 0; row < dst_w.rows; row++) {
- double y0 = row_map[row + 0];
- double y1 = row_map[row + 1];
- int maprow0 = (int)floor(y0);
- int maprow1 = (int)ceil(y1);
- int count = maprow1 - maprow0;
- int i;
- G_percent(row, dst_w.rows, 4);
- for (i = 0; i < count; i++)
- Rast_get_d_row(infile, bufs[i], maprow0 + i);
- for (col = 0; col < dst_w.cols; col++) {
- double x0 = col_map[col + 0];
- double x1 = col_map[col + 1];
- int mapcol0 = (int)floor(x0);
- int mapcol1 = (int)ceil(x1);
- int null = 0;
- int n = 0;
- int i, j;
- for (i = maprow0; i < maprow1; i++) {
- double ky = (i == maprow0) ? 1 - (y0 - maprow0)
- : (i == maprow1 - 1) ? 1 - (maprow1 - y1)
- : 1;
- for (j = mapcol0; j < mapcol1; j++) {
- double kx = (j == mapcol0) ? 1 - (x0 - mapcol0)
- : (j == mapcol1 - 1) ? 1 - (mapcol1 - x1)
- : 1;
- DCELL *src = &bufs[i - maprow0][j];
- DCELL *dst = &values[n++][0];
- if (Rast_is_d_null_value(src)) {
- Rast_set_d_null_value(&dst[0], 1);
- null = 1;
- }
- else {
- dst[0] = *src;
- dst[1] = kx * ky;
- }
- }
- }
- if (null && nulls)
- Rast_set_d_null_value(&outbuf[col], 1);
- else
- (*method_fn) (&outbuf[col], values, n, closure);
- }
- Rast_put_d_row(outfile, outbuf);
- }
- }
- int main(int argc, char *argv[])
- {
- struct GModule *module;
- struct
- {
- struct Option *rastin, *rastout, *method, *quantile;
- } parm;
- struct
- {
- struct Flag *nulls, *weight;
- } flag;
- struct History history;
- char title[64];
- char buf_nsres[100], buf_ewres[100];
- struct Colors colors;
- int row;
- G_gisinit(argv[0]);
- module = G_define_module();
- G_add_keyword(_("raster"));
- G_add_keyword(_("resample"));
- module->description =
- _("Resamples raster map layers to a coarser grid using aggregation.");
- parm.rastin = G_define_standard_option(G_OPT_R_INPUT);
- parm.rastout = G_define_standard_option(G_OPT_R_OUTPUT);
- parm.method = G_define_option();
- parm.method->key = "method";
- parm.method->type = TYPE_STRING;
- parm.method->required = NO;
- parm.method->description = _("Aggregation method");
- parm.method->options = build_method_list();
- parm.method->answer = "average";
- parm.quantile = G_define_option();
- parm.quantile->key = "quantile";
- parm.quantile->type = TYPE_DOUBLE;
- parm.quantile->required = NO;
- parm.quantile->description = _("Quantile to calculate for method=quantile");
- parm.quantile->options = "0.0-1.0";
- parm.quantile->answer = "0.5";
- flag.nulls = G_define_flag();
- flag.nulls->key = 'n';
- flag.nulls->description = _("Propagate NULLs");
- flag.weight = G_define_flag();
- flag.weight->key = 'w';
- flag.weight->description = _("Weight according to area (slower)");
- if (G_parser(argc, argv))
- exit(EXIT_FAILURE);
- nulls = flag.nulls->answer;
- method = find_method(parm.method->answer);
- if (method < 0)
- G_fatal_error(_("Unknown method <%s>"), parm.method->answer);
- if (menu[method].method == c_quant) {
- quantile = atoi(parm.quantile->answer);
- closure = &quantile;
- }
- G_get_set_window(&dst_w);
- /* set source window to old map */
- Rast_get_cellhd(parm.rastin->answer, "", &src_w);
- if (G_projection() == PROJECTION_LL) {
- /* try to shift source window to overlap with destination window */
- while (src_w.west >= dst_w.east && src_w.east - 360.0 > dst_w.west) {
- src_w.east -= 360.0;
- src_w.west -= 360.0;
- }
- while (src_w.east <= dst_w.west && src_w.west + 360.0 < dst_w.east) {
- src_w.east += 360.0;
- src_w.west += 360.0;
- }
- }
- /* adjust source window to cover destination window */
- {
- int r0 = (int)floor(Rast_northing_to_row(dst_w.north, &src_w));
- int r1 = (int)ceil(Rast_northing_to_row(dst_w.south, &src_w));
- /* do not use Rast_easting_to_col() because it does ll wrap */
- /*
- int c0 = (int)floor(Rast_easting_to_col(dst_w.west, &src_w));
- int c1 = (int)ceil(Rast_easting_to_col(dst_w.east, &src_w));
- */
- int c0 = (int)floor((dst_w.west - src_w.west) / src_w.ew_res);
- int c1 = src_w.cols + (int)ceil((dst_w.east - src_w.east) / src_w.ew_res);
- src_w.south -= src_w.ns_res * (r1 - src_w.rows);
- src_w.north += src_w.ns_res * (-r0);
- src_w.west -= src_w.ew_res * (-c0);
- src_w.east += src_w.ew_res * (c1 - src_w.cols);
- src_w.rows = r1 - r0;
- src_w.cols = c1 - c0;
- }
- Rast_set_input_window(&src_w);
- Rast_set_output_window(&dst_w);
- row_scale = 2 + ceil(dst_w.ns_res / src_w.ns_res);
- col_scale = 2 + ceil(dst_w.ew_res / src_w.ew_res);
- /* allocate buffers for input rows */
- bufs = G_malloc(row_scale * sizeof(DCELL *));
- for (row = 0; row < row_scale; row++)
- bufs[row] = Rast_allocate_d_input_buf();
- /* open old map */
- infile = Rast_open_old(parm.rastin->answer, "");
- /* allocate output buffer */
- outbuf = Rast_allocate_d_output_buf();
- /* open new map */
- outfile = Rast_open_new(parm.rastout->answer, DCELL_TYPE);
- if (flag.weight->answer && menu[method].method_w)
- resamp_weighted();
- else
- resamp_unweighted();
- G_percent(dst_w.rows, dst_w.rows, 2);
- Rast_close(infile);
- Rast_close(outfile);
- /* record map metadata/history info */
- sprintf(title, "Aggregate resample by %s", parm.method->answer);
- Rast_put_cell_title(parm.rastout->answer, title);
- Rast_short_history(parm.rastout->answer, "raster", &history);
- Rast_set_history(&history, HIST_DATSRC_1, parm.rastin->answer);
- G_format_resolution(src_w.ns_res, buf_nsres, src_w.proj);
- G_format_resolution(src_w.ew_res, buf_ewres, src_w.proj);
- Rast_format_history(&history, HIST_DATSRC_2,
- "Source map NS res: %s EW res: %s",
- buf_nsres, buf_ewres);
- Rast_command_history(&history);
- Rast_write_history(parm.rastout->answer, &history);
- /* copy color table from source map */
- if (strcmp(parm.method->answer, "sum") != 0 &&
- strcmp(parm.method->answer, "range") != 0 &&
- strcmp(parm.method->answer, "count") != 0 &&
- strcmp(parm.method->answer, "diversity") != 0) {
- if (Rast_read_colors(parm.rastin->answer, "", &colors) < 0)
- G_fatal_error(_("Unable to read color table for %s"),
- parm.rastin->answer);
- Rast_mark_colors_as_fp(&colors);
- Rast_write_colors(parm.rastout->answer, G_mapset(), &colors);
- }
- return (EXIT_SUCCESS);
- }
|