123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430 |
- /****************************************************************************
- *
- * MODULE: r.series.interp
- * AUTHOR(S): Soeren Gebbert <soerengebbert googlemail.com>
- * Code is based on r.series from Glynn Clements <glynn gclements.plus.com>
- *
- * PURPOSE: Interpolate raster maps located (temporal or spatial) in between input raster maps at specific sampling positions
- * COPYRIGHT: (C) 2011-2012 by the GRASS Development Team
- *
- * This program is free software under the GNU General Public
- * License (>=v2). Read the infile COPYING that comes with GRASS
- * for details.
- *
- *****************************************************************************/
- #include <string.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <math.h>
- #include <grass/gis.h>
- #include <grass/raster.h>
- #include <grass/glocale.h>
- #include <grass/stats.h>
- #define LINEAR_INTERPOLATION 1
- #define SPLINE_INTERPOLATION 2
- struct map_store
- {
- const char *name;
- double pos;
- DCELL *buf;
- int fd;
- int has_run;
- };
- void selection_sort(struct map_store **array, int num);
- static struct map_store *get_parameter_input(const char *type, char **map_names, char **positions, char *file, int *number_of_maps);
- static void linear_interpolation(struct map_store **inp, int num_inputs, struct map_store **outp, int num_outputs);
- static void interpolate_row_linear(struct map_store *left, struct map_store *right, struct map_store *out, int ncols);
- static void start_interpolation(struct map_store *inputs, int num_inputs, struct map_store *outputs, int num_outputs, int interpol_method);
- /* *************************************************************** */
- /* *************************************************************** */
- /* *************************************************************** */
- int main(int argc, char *argv[])
- {
- struct GModule *module;
- struct
- {
- struct Option *input, *datapos, *infile, *output, *samplingpos, *outfile, *method;
- } parm;
- int num_outputs;
- int num_inputs;
- struct map_store *inputs = NULL;
- struct map_store *outputs = NULL;
- int interpol_method = LINEAR_INTERPOLATION;
- G_gisinit(argv[0]);
- module = G_define_module();
- G_add_keyword(_("raster"));
- G_add_keyword(_("series"));
- G_add_keyword(_("interpolation"));
- /* TODO: re-phrase the description */
- module->description =
- _("Interpolates raster maps located (temporal or spatial) "
- "in between input raster maps at specific sampling positions.");
- parm.input = G_define_standard_option(G_OPT_R_INPUTS);
- parm.input->required = NO;
-
- parm.datapos = G_define_option();
- parm.datapos->key = "datapos";
- parm.datapos->type = TYPE_DOUBLE;
- parm.datapos->required = NO;
- parm.datapos->description = _("Data point position for each input map");
- parm.datapos->multiple = YES;
- parm.infile = G_define_standard_option(G_OPT_F_INPUT);
- parm.infile->key = "infile";
- parm.infile->description = _("Input file with one input raster map name and data point position per line,"
- " field separator between name and sample point is |");
- parm.infile->required = NO;
- parm.output = G_define_standard_option(G_OPT_R_OUTPUT);
- parm.output->multiple = YES;
- parm.output->required = NO;
- parm.samplingpos = G_define_option();
- parm.samplingpos->key = "samplingpos";
- parm.samplingpos->type = TYPE_DOUBLE;
- parm.samplingpos->required = NO;
- parm.samplingpos->multiple = YES;
- parm.samplingpos->description = _("Sampling point position for each output map");
- parm.outfile = G_define_standard_option(G_OPT_F_INPUT);
- parm.outfile->key = "outfile";
- parm.outfile->description = _("Input file with one output raster map name and sample point position per line,"
- " field separator between name and sample point is |");
- parm.outfile->required = NO;
- parm.method = G_define_option();
- parm.method->key = "method";
- parm.method->type = TYPE_STRING;
- parm.method->required = NO;
- parm.method->options = "linear";
- parm.method->answer = "linear";
- parm.method->description = _("Interpolation method, currently only linear interpolation is supported");
- parm.method->multiple = NO;
- if (G_parser(argc, argv))
- exit(EXIT_FAILURE);
- if (parm.output->answer && parm.outfile->answer)
- G_fatal_error(_("%s= and %s= are mutually exclusive"),
- parm.output->key, parm.outfile->key);
-
- if (parm.samplingpos->answer && parm.outfile->answer)
- G_fatal_error(_("%s= and %s= are mutually exclusive"),
- parm.samplingpos->key, parm.outfile->key);
-
- if (!parm.output->answer && !parm.outfile->answer)
- G_fatal_error(_("Please specify %s= or %s="),
- parm.output->key, parm.outfile->key);
-
- if (parm.output->answer && !parm.samplingpos->answer)
- G_fatal_error(_("Please specify %s= and %s="),
- parm.output->key, parm.samplingpos->key);
- if (parm.input->answer && parm.infile->answer)
- G_fatal_error(_("%s= and %s= are mutually exclusive"),
- parm.input->key, parm.infile->key);
-
- if (parm.datapos->answer && parm.infile->answer)
- G_fatal_error(_("%s= and %s= are mutually exclusive"),
- parm.datapos->key, parm.infile->key);
-
- if (!parm.input->answer && !parm.infile->answer)
- G_fatal_error(_("Please specify %s= or %s="),
- parm.input->key, parm.infile->key);
-
- if (parm.input->answer && !parm.datapos->answer)
- G_fatal_error(_("Please specify %s= and %s="),
- parm.input->key, parm.datapos->key);
- if(G_strncasecmp(parm.method->answer, "linear", 6) == 0)
- interpol_method = LINEAR_INTERPOLATION;
- if(G_strncasecmp(parm.method->answer, "spline", 6) == 0)
- interpol_method = SPLINE_INTERPOLATION;
- inputs = get_parameter_input("input", parm.input->answers, parm.datapos->answers, parm.infile->answer, &num_inputs);
- outputs = get_parameter_input("output", parm.output->answers, parm.samplingpos->answers, parm.outfile->answer, &num_outputs);
- start_interpolation(inputs, num_inputs, outputs, num_outputs, interpol_method);
- exit(EXIT_SUCCESS);
- }
- /* *************************************************************** */
- /* *************************************************************** */
- /* *************************************************************** */
- struct map_store *get_parameter_input(const char *type, char **map_names, char **positions, char *file, int *number_of_maps)
- {
- struct map_store *maps = NULL;
- int max_maps;
- int num_maps;
- int num_points;
- /* process the output maps from the infile */
- if (file) {
- FILE *in;
-
- in = fopen(file, "r");
- if (!in)
- G_fatal_error(_("Unable to open %s file <%s>"), type, file);
-
- num_maps = 0;
- max_maps = 0;
- for (;;) {
- char buf[GNAME_MAX + 50]; /* Name and position */
- char tok_buf[GNAME_MAX + 50]; /* Name and position */
- char *name;
- int ntokens;
- char **tokens;
- struct map_store *p;
- double pos = -1;
- if (!G_getl2(buf, sizeof(buf), in))
- break;
- strcpy(tok_buf, buf);
- tokens = G_tokenize(tok_buf, "|");
- ntokens = G_number_of_tokens(tokens);
- if(ntokens > 1) {
- name = G_chop(tokens[0]);
- pos = atof(G_chop(tokens[1]));
- } else {
- name = G_chop(buf);
- }
- /* Ignore empty lines */
- if (!*name)
- continue;
-
- if(pos == -1)
- G_fatal_error(_("Missing point position for %s map <%s>"
- " in file <%s> near line %i"),
- type, name, file, num_maps);
- if (num_maps >= max_maps) {
- max_maps += 100;
- maps = G_realloc(maps, max_maps * sizeof(struct map_store));
- }
- p = &maps[num_maps++];
- p->name = G_store(name);
- p->pos = pos;
- p->fd = -1;
- p->buf = NULL;
- p->has_run = 0;
- G_verbose_message(_("Preparing %s map <%s> at position %g"), type, p->name, p->pos);
- }
- if (num_maps < 1)
- G_fatal_error(_("No raster map name found in %s file <%s>"), type, file);
-
- fclose(in);
- }
- else {
- int i;
- for (i = 0; map_names[i]; i++)
- ;
- num_maps = i;
- if (num_maps < 1)
- G_fatal_error(_("No %s raster map not found"), type);
- for (i = 0; positions[i]; i++)
- ;
- num_points = i;
-
- if (num_points != num_maps)
- G_fatal_error(_("The number of %s maps and %s point positions must be equal"), type, type);
-
- maps = G_malloc(num_maps * sizeof(struct map_store));
- for (i = 0; i < num_maps; i++) {
- struct map_store *p = &maps[i];
- p->name = map_names[i];
- p->pos = (DCELL)atof(positions[i]);
- p->fd = -1;
- p->buf = NULL;
- p->has_run = 0;
- G_verbose_message(_("Preparing %s map <%s> at position %g"), type, p->name, p->pos);
- }
- }
- *number_of_maps = num_maps;
- return maps;
- }
- /* *************************************************************** */
- /* *************************************************************** */
- /* *************************************************************** */
- void start_interpolation(struct map_store *inputs, int num_inputs, struct map_store *outputs, int num_outputs, int interpol_method)
- {
- int i;
- struct map_store **inp = (struct map_store**) G_malloc(num_inputs * sizeof(struct map_store*));
- struct map_store **outp = (struct map_store**) G_malloc(num_outputs * sizeof(struct map_store*));
- G_verbose_message(_("Start interpolation run with %i input maps and %i output maps"),
- num_inputs, num_outputs);
- for(i = 0; i < num_inputs; i++)
- inp[i] = &inputs[i];
- for(i = 0; i < num_outputs; i++)
- outp[i] = &outputs[i];
- /* Sort input and output pointer by their point position
- * using brute force. :)
- */
- selection_sort(inp, num_inputs);
- selection_sort(outp, num_outputs);
- if(interpol_method == LINEAR_INTERPOLATION)
- linear_interpolation(inp, num_inputs, outp, num_outputs);
- for(i = 0; i < num_outputs; i++) {
- if(outp[i]->has_run == 0)
- G_warning(_("map <%s> at position %g was not interpolated. Check the interpolation interval."), outp[i]->name, outp[i]->pos);
- }
- }
- /* *************************************************************** */
- /* *************************************************************** */
- /* *************************************************************** */
- void linear_interpolation(struct map_store **inp, int num_inputs,
- struct map_store **outp, int num_outputs)
- {
- struct map_store *left;
- struct map_store *right;
- struct History history;
- int interval, l, row;
- int nrows = Rast_window_rows();
- int ncols = Rast_window_cols();
- int start = 0;
- if(num_inputs < 2)
- G_fatal_error(_("At least 2 input maps are required for linear interpolation"));
- /* Interpolate for each interval */
- for(interval = 0; interval < num_inputs - 1; interval++) {
- left = inp[interval];
- right = inp[interval + 1];
- left->fd = Rast_open_old(left->name, "");
- right->fd = Rast_open_old(right->name, "");
- left->buf = Rast_allocate_d_buf();
- right->buf = Rast_allocate_d_buf();
- for(l = start; l < num_outputs; l++) {
- /* Check if the map is in the interval and process it */
- if(outp[l]->pos >= left->pos && outp[l]->pos <= right->pos) {
- outp[l]->fd = Rast_open_new(outp[l]->name, DCELL_TYPE);
- outp[l]->buf = Rast_allocate_d_buf();
- G_verbose_message(_("Interpolate map <%s> at position %g in interval (%g;%g)"),
- outp[l]->name, outp[l]->pos, left->pos, right->pos);
- G_verbose_message(_("Percent complete..."));
- for (row = 0; row < nrows; row++) {
- G_percent(row, nrows, 2);
- Rast_get_d_row(left->fd, left->buf, row);
- Rast_get_d_row(right->fd, right->buf, row);
- interpolate_row_linear(left, right, outp[l], ncols);
- Rast_put_d_row(outp[l]->fd, outp[l]->buf);
- }
- G_percent(row, nrows, 2);
- Rast_close(outp[l]->fd);
- Rast_short_history(outp[l]->name, "raster", &history);
- Rast_command_history(&history);
- Rast_write_history(outp[l]->name, &history);
- G_free(outp[l]->buf);
- outp[l]->has_run = 1;
-
- start = l;
- }
- }
- Rast_close(left->fd);
- G_free(left->buf);
- Rast_close(right->fd);
- G_free(right->buf);
- }
- }
- /* *************************************************************** */
- /* *************************************************************** */
- /* *************************************************************** */
- /* linear function v = (1 - pos/dist) * u1 + pos/dist * u2
- *
- * v -> The value of the output map
- * pos -> The normalized position of the output map
- * u1 -> The value of the left input map
- * u2 -> The value of the right input map
- * dist -> The distance between the position of u1 and u2
- *
- * */
- void interpolate_row_linear(struct map_store *left, struct map_store *right, struct map_store *out, int ncols)
- {
- DCELL v;
- DCELL u1;
- DCELL u2;
- DCELL dist;
- int col;
- for (col = 0; col < ncols; col++) {
- u1 = left->buf[col];
- u2 = right->buf[col];
- dist = fabs(right->pos - left->pos);
- if(Rast_is_d_null_value(&u1) || Rast_is_d_null_value(&u2)) {
- Rast_set_d_null_value(&v, 1);
- } else {
- v = (1 - ((out->pos - left->pos)/dist)) * u1 + ((out->pos - left->pos)/dist) * u2;
- }
- out->buf[col] = v;
- }
- return;
- }
- /* *************************************************************** */
- /* *************************************************************** */
- /* *************************************************************** */
- void selection_sort(struct map_store **array, int num)
- {
- int i, j, b;
- struct map_store *min;
- for (i = 0; i < num - 1; i++) {
- b = i;
- min = array[b];
- for (j = i + 1; j < num; j++) {
- if (array[j]->pos < min->pos) {
- b = j;
- min = array[b];
- }
- }
- array[b] = array[i];
- array[i] = min;
- }
- }
|