/**************************************************************************** * * MODULE: xganim * AUTHOR(S): Bill Brown CERL (original contributor), * Markus Neteler , * Roberto Flor , * Bernhard Reiter , * Brad Douglas , * Glynn Clements * PURPOSE: a tool for animating a series of GRASS raster files * COPYRIGHT: (C) 1999-2006 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 #include #include #include #include #include #include #include #include extern "C" { #include #include #include #include } #include "gui.h" #define DEF_MAX 900 #define DEF_MIN 600 #define BORDER_W 2 static char **gee_wildfiles(const char *wildarg, const char *element, int *num); static void parse_command( struct Option **viewopts, char *vfiles[MAXVIEWS][MAXIMAGES], int *numviews, int *numframes); struct Option *viewopts[MAXVIEWS]; unsigned int nrows, ncols; char *vfiles[MAXVIEWS][MAXIMAGES]; int numviews; int frames; int Top = 0, Left = 0; char frame[MAXIMAGES][4]; int LabelPos[MAXVIEWS][2]; float vscale, scale; /* resampling scale factors */ int irows, icols, vrows, vcols; BEGIN_EVENT_TABLE(MyApp, wxApp) EVT_IDLE(MyApp::do_run) END_EVENT_TABLE() int main(int argc, char **argv) { int i; G_gisinit(argv[0]); for (i = 0; i < MAXVIEWS; i++) { char buf[BUFSIZ]; viewopts[i] = G_define_option(); sprintf(buf, "view%d", i + 1); viewopts[i]->key = G_store(buf); viewopts[i]->type = TYPE_STRING; viewopts[i]->required = (i ? NO : YES); viewopts[i]->multiple = YES; viewopts[i]->gisprompt = "old,cell,Raster";; sprintf(buf, _("Raster file(s) for View%d"), i + 1); viewopts[i]->description = G_store(buf); } if (G_parser(argc, argv)) exit(EXIT_FAILURE); parse_command(viewopts, vfiles, &numviews, &frames); return wxEntry(argc, argv); } bool MyApp::OnInit() { int i, j; unsigned int *sdimp; int longdim; /* debug */ if (G_verbose() > G_verbose_std()) { for (i = 0; i < numviews; i++) { fprintf(stderr, "\nVIEW %d: ", i + 1); for (j = 0; j < frames; j++) { fprintf(stderr, "%s ", vfiles[i][j]); } } } fprintf(stderr, "\n"); vrows = Rast_window_rows(); vcols = Rast_window_cols(); nrows = vrows; ncols = vcols; /* short dimension */ sdimp = nrows > ncols ? &ncols : &nrows; /* these proportions should work fine for 1 or 4 views, but for 2 views, want to double the narrow dim & for 3 views triple it */ if (numviews == 2) *sdimp *= 2; else if (numviews == 3) *sdimp *= 3; longdim = nrows > ncols ? nrows : ncols; scale = 1.0; { /* find animation image size */ int max, min; char *p; max = DEF_MAX; min = DEF_MIN; if ((p = getenv("XGANIM_SIZE"))) max = min = atoi(p); if (longdim > max) /* scale down */ scale = (float)max / longdim; else if (longdim < min) /* scale up */ scale = (float)min / longdim; } vscale = scale; if (numviews == 4) vscale = scale / 2.; nrows = (unsigned int) (nrows * scale); ncols = (unsigned int) (ncols * scale); /* now nrows & ncols are the size of the combined - views image */ vrows = (int) (vrows * vscale); vcols = (int) (vcols * vscale); /* now vrows & vcols are the size for each sub-image */ /* add to nrows & ncols for borders */ /* irows, icols used for vert/horizontal determination in loop below */ irows = nrows; icols = ncols; nrows += (1 + (nrows / vrows)) * BORDER_W; ncols += (1 + (ncols / vcols)) * BORDER_W; gd.speed = 100; gd.direction = 1; gd.shownames = 1; mainwin = new MyFrame(wxString("GRASS Animate", wxConvISO8859_1), ncols, nrows, &gd); mainwin->Show(); SetTopWindow(mainwin); for (j = 0; j < MAXIMAGES; j++) sprintf(frame[j], "%2d", j + 1); return true; } int MyApp::load_files(void) { DCELL *dcell; unsigned char *tr, *tg, *tb, *tset; int tsiz, coff; int rowoff, row, col, vxoff, vyoff; int cnt, ret, fd; int vnum; const char *name; struct Colors colors; dcell = Rast_allocate_d_buf(); tsiz = Rast_window_cols(); /* allocate memory */ tr = (unsigned char *) G_malloc(tsiz * sizeof(char)); tg = (unsigned char *) G_malloc(tsiz * sizeof(char)); tb = (unsigned char *) G_malloc(tsiz * sizeof(char)); tset = (unsigned char *) G_malloc(tsiz * sizeof(char)); wxImage img(ncols, nrows); for (cnt = 0; cnt < frames; cnt++) { if (cnt > MAXIMAGES) { cnt--; break; } for (vnum = 0; vnum < numviews; vnum++) { if (icols == vcols) { vxoff = BORDER_W; vyoff = (irows == vrows) ? BORDER_W : BORDER_W + vnum * (BORDER_W + vrows); } else if (irows == vrows) { vxoff = (icols == vcols) ? BORDER_W : BORDER_W + vnum * (BORDER_W + vcols); vyoff = BORDER_W; } else { /* 4 views */ /* assumes we want : view1 view2 view3 view4 */ vxoff = vnum % 2 ? BORDER_W : vcols + 2 * BORDER_W; vyoff = vnum > 1 ? vrows + 2 * BORDER_W : BORDER_W; } if (!cnt) { LabelPos[vnum][0] = vxoff; LabelPos[vnum][1] = vyoff + vrows - 1; } name = vfiles[vnum][cnt]; G_message(_("Reading file [%s]..."), name); fd = Rast_open_old(name, ""); if (fd < 0) G_fatal_error(_("Unable to open raster map <%s>"), name); /* strcpy(title[cnt],G_get_cell_title(name, mapset)); */ ret = Rast_read_colors(name, "", &colors); if (ret < 0) G_fatal_error(_("Unable to read color file")); for (row = 0; row < vrows; row++) { Rast_get_d_row(fd, dcell, (int)(row / vscale)); rowoff = (vyoff + row) * ncols; Rast_lookup_d_colors(dcell, tr, tg, tb, tset, tsiz, &colors); for (col = 0; col < vcols; col++) { coff = (int)(col / vscale); if (!tset[coff]) img.SetRGB(vxoff + col, vyoff + row, 255, 255, 255); else img.SetRGB(vxoff + col, vyoff + row, tr[coff], tg[coff], tb[coff]); } } Rast_close(fd); } wxBitmap *bmp = new wxBitmap(img); pic_array[cnt] = bmp; mainwin->canvas->draw_image(bmp); mainwin->change_label(frame[cnt]); } G_free(dcell); G_free(tr); G_free(tg); G_free(tb); G_free(tset); return cnt; } /* ###################################################### */ void MyApp::do_run(wxIdleEvent &ev) { static int first = 1; struct gui_data *cd = &gd; int i, cnt; if (first) { first = 0; cnt = load_files(); cd->curframe = cd->direction > 0 ? 0 : cnt - 1; cd->prevframe = cd->curframe; cd->step = cd->stop = 0; cd->loop = cd->swing = 0; cd->nframes = cnt; } if (cd->rewind) { cd->rewind = 0; cd->curframe = 0; cd->direction = 1; cd->step = 1; } if (cd->swing) { if (cd->curframe == cd->nframes || cd->curframe < 0) { cd->direction = -cd->direction; cd->curframe += cd->direction; } } else if (cd->loop) { if (cd->curframe == cd->nframes) cd->curframe = 0; else if (cd->curframe < 0) cd->curframe = cd->nframes - 1; } else if (cd->curframe == cd->nframes || cd->curframe < 0) cd->stop = 1; if (cd->stop && !cd->step) return; if (cd->curframe < cd->nframes && cd->curframe >= 0) { /* little pause */ { float tf; for (tf = 0.0; tf < cd->speed; tf += .01) ; } mainwin->canvas->draw_image(pic_array[cd->curframe]); /* draw labels */ for (i = 0; i < numviews; i++) { mainwin->canvas->draw_text( cd->shownames, LabelPos[i][0] + 5, LabelPos[i][1] - 5, vfiles[i][cd->curframe]); } mainwin->change_label(frame[cd->curframe]); cd->prevframe = cd->curframe; } cd->curframe += cd->direction; if (cd->step) { cd->step = 0; cd->stop = 1; } } /* ###################################################### */ static void mlist(const char *element, const char *wildarg, const char *outfile) { int n; const char *mapset; for (n = 0; (mapset = G__mapset_name(n)); n++) { char type_arg[GNAME_MAX]; char pattern_arg[GNAME_MAX]; char mapset_arg[GMAPSET_MAX]; if (strcmp(mapset, ".") == 0) mapset = G_mapset(); sprintf(type_arg, "type=%s", element); sprintf(pattern_arg, "pattern=%s", wildarg); sprintf(mapset_arg, "mapset=%s", mapset); G_spawn_ex("g.mlist", "g.mlist", type_arg, pattern_arg, mapset_arg, SF_REDIRECT_FILE, SF_STDOUT, SF_MODE_APPEND, outfile, NULL); } } static char **parse(const char *filename, int *num) { char buf[GNAME_MAX]; char **files = NULL; int max_files = 0; int num_files = 0; FILE *fp; fp = fopen(filename, "r"); if (!fp) G_fatal_error(_("Error reading wildcard")); while (fgets(buf, sizeof(buf), fp)) { char *p = strchr(buf, '\n'); if (p) *p = '\0'; if (!*buf) continue; if (num_files >= max_files) { max_files += 50; files = (char **) G_realloc((void *) files, max_files * sizeof(char *)); } files[num_files++] = G_store(buf); } fclose(fp); *num = num_files; return files; } static char **gee_wildfiles(const char *wildarg, const char *element, int *num) { char *tfile; char **files; tfile = G_tempfile(); mlist(element, wildarg, tfile); files = parse(tfile, num); remove(tfile); G_free(tfile); return files; } static void parse_command(struct Option **viewopts, char *vfiles[MAXVIEWS][MAXIMAGES], int *numviews, int *numframes) { int i, j, k; *numviews = *numframes = 0; for (i = 0; i < MAXVIEWS; i++) { if (viewopts[i]->answers) { int numi, wildnum; (*numviews)++; for (j = 0, numi = 0; viewopts[i]->answers[j]; j++) { if ((NULL != strchr(viewopts[i]->answers[j], '*')) || (NULL != strchr(viewopts[i]->answers[j], '?')) || (NULL != strchr(viewopts[i]->answers[j], '['))) { char **wildfiles = gee_wildfiles(viewopts[i]->answers[j], "rast", &wildnum); for (k = 0; k < wildnum; k++) vfiles[i][numi++] = wildfiles[k]; } else vfiles[i][numi++] = G_store(viewopts[i]->answers[j]); } /* keep track of smallest number of frames */ *numframes = *numframes ? *numframes > numi ? numi : *numframes : numi; } } } /********************************************************************/ IMPLEMENT_APP_NO_MAIN(MyApp)