main.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630
  1. /****************************************************************************
  2. *
  3. * MODULE: xganim
  4. * AUTHOR(S): Bill Brown <brown gis.uiuc.edu> CERL (original contributor),
  5. * Markus Neteler <neteler itc.it>,
  6. * Roberto Flor <flor itc.it>,
  7. * Bernhard Reiter <bernhard intevation.de>,
  8. * Brad Douglas <rez touchofmadness.com>,
  9. * Glynn Clements <glynn gclements.plus.com>
  10. * PURPOSE: a tool for animating a series of GRASS raster files
  11. * COPYRIGHT: (C) 1999-2006 by the GRASS Development Team
  12. *
  13. * This program is free software under the GNU General Public
  14. * License (>=v2). Read the file COPYING that comes with GRASS
  15. * for details.
  16. *
  17. *****************************************************************************/
  18. #include <stdio.h>
  19. #include <string.h>
  20. #include <stdlib.h>
  21. #include <math.h>
  22. #include <limits.h>
  23. #include <unistd.h>
  24. #include <grass/gis.h>
  25. #include <grass/glocale.h>
  26. #include "gui.h"
  27. #include "local_proto.h"
  28. #define COLOR_OFFSET 0
  29. #define MAXIMAGES 400
  30. #define DEF_MAX 900
  31. #define DEF_MIN 600
  32. #define MAXVIEWS 4
  33. #define BORDER_W 2
  34. /* function prototypes */
  35. static int load_files();
  36. static Boolean do_run(XtPointer);
  37. static char **gee_wildfiles(char *wildarg, char *element, int *num);
  38. static void change_label(Widget wid, char *str);
  39. static void parse_command(int argc, char **argv,
  40. char *vfiles[MAXVIEWS][MAXIMAGES],
  41. int *numviews, int *numframes);
  42. /* global variables */
  43. Widget canvas, flabel;
  44. Display *theDisplay;
  45. XImage *pic_array[MAXIMAGES];
  46. GC invertGC, drawGC;
  47. unsigned int nrows, ncols;
  48. int numviews;
  49. int Top = 0, Left = 0;
  50. char frame[MAXIMAGES][4];
  51. char *vfiles[MAXVIEWS][MAXIMAGES];
  52. int LabelPos[MAXVIEWS][2];
  53. float vscale, scale; /* resampling scale factors */
  54. int irows, icols, vrows, vcols;
  55. int frames;
  56. unsigned int depth;
  57. Visual *use_visual;
  58. int main(int argc, char **argv)
  59. {
  60. Widget toplevel, mainwin, trc;
  61. int scrn;
  62. Display *dpy;
  63. Window grwin;
  64. Colormap fixedcmap;
  65. int i, j;
  66. unsigned int *sdimp;
  67. int longdim;
  68. unsigned long blackPix, whitePix;
  69. struct gui_data cd;
  70. XtAppContext AppC;
  71. Arg wargs[15];
  72. unsigned int n;
  73. toplevel = XtAppInitialize(&AppC, "xganimate", NULL, 0,
  74. &argc, argv, NULL, wargs, 0);
  75. theDisplay = XtDisplay(toplevel);
  76. G_gisinit(argv[0]);
  77. parse_command(argc, argv, vfiles, &numviews, &frames);
  78. /* debug */
  79. if (G_verbose() > G_verbose_std()) {
  80. for (i = 0; i < numviews; i++) {
  81. fprintf(stderr, "\nVIEW %d: ", i + 1);
  82. for (j = 0; j < frames; j++) {
  83. fprintf(stderr, "%s ", vfiles[i][j]);
  84. }
  85. }
  86. }
  87. fprintf(stderr, "\n");
  88. vrows = G_window_rows();
  89. vcols = G_window_cols();
  90. nrows = vrows;
  91. ncols = vcols;
  92. /* short dimension */
  93. sdimp = nrows > ncols ? &ncols : &nrows;
  94. /* these proportions should work fine for 1 or 4 views, but for
  95. 2 views, want to double the narrow dim & for 3 views triple it */
  96. if (numviews == 2)
  97. *sdimp *= 2;
  98. else if (numviews == 3)
  99. *sdimp *= 3;
  100. longdim = nrows > ncols ? nrows : ncols;
  101. scale = 1.0;
  102. { /* find animation image size */
  103. int max, min;
  104. char *p;
  105. max = DEF_MAX;
  106. min = DEF_MIN;
  107. if ((p = getenv("XGANIM_SIZE")))
  108. max = min = atoi(p);
  109. if (longdim > max) /* scale down */
  110. scale = (float)max / longdim;
  111. else if (longdim < min) /* scale up */
  112. scale = (float)min / longdim;
  113. }
  114. vscale = scale;
  115. if (numviews == 4)
  116. vscale = scale / 2.;
  117. nrows *= scale;
  118. ncols *= scale;
  119. /* now nrows & ncols are the size of the combined - views image */
  120. vrows *= vscale;
  121. vcols *= vscale;
  122. /* now vrows & vcols are the size for each sub-image */
  123. /* add to nrows & ncols for borders */
  124. /* irows, icols used for vert/horizontal determination in loop below */
  125. irows = nrows;
  126. icols = ncols;
  127. nrows += (1 + (nrows / vrows)) * BORDER_W;
  128. ncols += (1 + (ncols / vcols)) * BORDER_W;
  129. n = 0;
  130. if (ncols > nrows) {
  131. XtSetArg(wargs[n], XmNwidth, ncols);
  132. n++;
  133. XtSetArg(wargs[n], XmNheight, nrows + 60);
  134. n++;
  135. }
  136. else {
  137. XtSetArg(wargs[n], XmNwidth, ncols + 80);
  138. n++;
  139. XtSetArg(wargs[n], XmNheight, nrows);
  140. n++;
  141. }
  142. mainwin = XtCreateManagedWidget("GRASS Animate", xmFormWidgetClass,
  143. toplevel, wargs, n);
  144. cd.speed = 100;
  145. cd.direction = 1;
  146. cd.shownames = 1;
  147. n = 0;
  148. XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_FORM);
  149. n++;
  150. XtSetArg(wargs[n], XmNleftAttachment, XmATTACH_FORM);
  151. n++;
  152. XtSetArg(wargs[n], XmNwidth, ncols);
  153. n++;
  154. XtSetArg(wargs[n], XmNheight, nrows);
  155. n++;
  156. canvas = XtCreateManagedWidget("canvas", xmDrawingAreaWidgetClass,
  157. mainwin, wargs, n);
  158. n = 0;
  159. if (ncols > nrows) {
  160. XtSetArg(wargs[n], XmNorientation, XmHORIZONTAL);
  161. n++;
  162. XtSetArg(wargs[n], XmNleftAttachment, XmATTACH_FORM);
  163. n++;
  164. XtSetArg(wargs[n], XmNrightAttachment, XmATTACH_FORM);
  165. n++;
  166. XtSetArg(wargs[n], XmNbottomAttachment, XmATTACH_FORM);
  167. n++;
  168. XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_WIDGET);
  169. n++;
  170. XtSetArg(wargs[n], XmNtopWidget, canvas);
  171. n++;
  172. }
  173. else {
  174. XtSetArg(wargs[n], XmNorientation, XmVERTICAL);
  175. n++;
  176. XtSetArg(wargs[n], XmNleftAttachment, XmATTACH_WIDGET);
  177. n++;
  178. XtSetArg(wargs[n], XmNleftWidget, canvas);
  179. n++;
  180. XtSetArg(wargs[n], XmNrightAttachment, XmATTACH_FORM);
  181. n++;
  182. XtSetArg(wargs[n], XmNbottomAttachment, XmATTACH_FORM);
  183. n++;
  184. XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_FORM);
  185. n++;
  186. }
  187. XtSetArg(wargs[n], XmNbackground, WhitePixelOfScreen(XtScreen(toplevel)));
  188. n++;
  189. XtSetArg(wargs[n], XmNadjustMargin, False);
  190. n++;
  191. trc = XtCreateManagedWidget("controls_rc",
  192. xmRowColumnWidgetClass, mainwin, wargs, n);
  193. make_buttons(&cd, trc, XtScreen(toplevel));
  194. n = 0;
  195. XtSetArg(wargs[n], XmNalignment, XmALIGNMENT_END);
  196. n++;
  197. flabel = XtCreateManagedWidget("cfr", xmLabelWidgetClass, trc, wargs, n);
  198. XtRealizeWidget(toplevel);
  199. set_buttons_pixmap(theDisplay, XtWindow(canvas));
  200. /**************************************************************/
  201. dpy = XtDisplay(canvas);
  202. grwin = XtWindow(canvas);
  203. scrn = DefaultScreen(dpy);
  204. use_visual = DefaultVisual(dpy, scrn);
  205. #if 1
  206. fixedcmap = XCreateColormap(dpy, grwin, use_visual, AllocNone);
  207. #else
  208. fixedcmap = DefaultColormap(dpy, scrn);
  209. #endif
  210. fixedcmap = InitColorTableFixed(fixedcmap);
  211. XtVaGetValues(canvas, XmNdepth, &depth, NULL);
  212. XtVaSetValues(toplevel, XmNcolormap, fixedcmap, NULL);
  213. XtSetWMColormapWindows(toplevel, &canvas, 1);
  214. /**************************************************************/
  215. blackPix = _get_lookup_for_color(0, 0, 0);
  216. whitePix = _get_lookup_for_color(255, 255, 255);
  217. drawGC =
  218. XCreateGC(XtDisplay(canvas), XtWindow(canvas), (unsigned long)0,
  219. NULL);
  220. XSetFunction(theDisplay, drawGC, GXcopy);
  221. XSetForeground(theDisplay, drawGC, blackPix);
  222. XSetBackground(theDisplay, drawGC, whitePix);
  223. invertGC =
  224. XCreateGC(XtDisplay(canvas), XtWindow(canvas), (unsigned long)0,
  225. NULL);
  226. XSetFunction(theDisplay, invertGC, GXcopy);
  227. XSetForeground(theDisplay, invertGC, whitePix);
  228. XSetBackground(theDisplay, invertGC, blackPix);
  229. for (j = 0; j < MAXIMAGES; j++)
  230. sprintf(frame[j], "%2d", j + 1);
  231. while (1) { /* wait for window */
  232. XEvent xev;
  233. XNextEvent(theDisplay, &xev);
  234. if (xev.type == MapNotify && xev.xmap.event == XtWindow(mainwin))
  235. break;
  236. }
  237. XtAppAddWorkProc(AppC, do_run, &cd);
  238. XtAppMainLoop(AppC);
  239. return 0;
  240. }
  241. static int load_files()
  242. {
  243. CELL *cell;
  244. FCELL *fcell;
  245. DCELL *dcell;
  246. void *voidc = NULL;
  247. unsigned char *tr, *tg, *tb, *tset;
  248. int tsiz, coff;
  249. int rowoff, row, col, vxoff, vyoff;
  250. int cnt, ret, fd;
  251. int vnum;
  252. XImage *pa;
  253. char *mapset, name[BUFSIZ];
  254. struct Colors colors;
  255. int rtype;
  256. cell = G_allocate_c_raster_buf();
  257. fcell = G_allocate_f_raster_buf();
  258. dcell = G_allocate_d_raster_buf();
  259. tsiz = G_window_cols();
  260. /* allocate memory */
  261. tr = G_malloc(tsiz * sizeof(char));
  262. tg = G_malloc(tsiz * sizeof(char));
  263. tb = G_malloc(tsiz * sizeof(char));
  264. tset = G_malloc(tsiz * sizeof(char));
  265. for (cnt = 0; cnt < frames; cnt++) {
  266. if (cnt > MAXIMAGES) {
  267. cnt--;
  268. break;
  269. }
  270. pa = XCreateImage(theDisplay, use_visual, depth, ZPixmap,
  271. 0, NULL, ncols, nrows, 8, 0);
  272. pa->data = G_malloc((size_t) nrows * pa->bytes_per_line);
  273. pic_array[cnt] = pa;
  274. for (vnum = 0; vnum < numviews; vnum++) {
  275. if (icols == vcols) {
  276. vxoff = BORDER_W;
  277. vyoff = (irows == vrows) ? BORDER_W :
  278. BORDER_W + vnum * (BORDER_W + vrows);
  279. }
  280. else if (irows == vrows) {
  281. vxoff = (icols == vcols) ? BORDER_W :
  282. BORDER_W + vnum * (BORDER_W + vcols);
  283. vyoff = BORDER_W;
  284. }
  285. else { /* 4 views */
  286. /* assumes we want :
  287. view1 view2
  288. view3 view4
  289. */
  290. vxoff = vnum % 2 ? BORDER_W : vcols + 2 * BORDER_W;
  291. vyoff = vnum > 1 ? vrows + 2 * BORDER_W : BORDER_W;
  292. }
  293. if (!cnt) {
  294. LabelPos[vnum][0] = vxoff;
  295. LabelPos[vnum][1] = vyoff + vrows - 1;
  296. }
  297. strcpy(name, vfiles[vnum][cnt]);
  298. G_message(_("Reading file [%s]..."), name);
  299. mapset = G_find_cell2(name, "");
  300. if (mapset == NULL)
  301. G_fatal_error(_("Raster map <%s> not found"), name);
  302. fd = G_open_cell_old(name, mapset);
  303. if (fd < 0)
  304. G_fatal_error(_("Unable to open raster map <%s>"), name);
  305. /*
  306. strcpy(title[cnt],G_get_cell_title(name, mapset));
  307. */
  308. rtype = G_get_raster_map_type(fd);
  309. if (rtype == CELL_TYPE)
  310. voidc = (CELL *) cell;
  311. else if (rtype == FCELL_TYPE)
  312. voidc = (FCELL *) fcell;
  313. else if (rtype == DCELL_TYPE)
  314. voidc = (DCELL *) dcell;
  315. else
  316. /* should not reach here */
  317. G_fatal_error(_("Unable to determine raster cell type"));
  318. ret = G_read_colors(name, mapset, &colors);
  319. if (ret < 0)
  320. G_fatal_error(_("Unable to read color file"));
  321. for (row = 0; row < vrows; row++) {
  322. if (G_get_raster_row
  323. (fd, (void *)voidc, (int)(row / vscale), rtype) < 0)
  324. G_fatal_error(_("Unable to read raster row"));
  325. rowoff = (vyoff + row) * ncols;
  326. G_lookup_raster_colors((void *)voidc, tr, tg, tb, tset, tsiz,
  327. &colors, rtype);
  328. for (col = 0; col < vcols; col++) {
  329. coff = (int)(col / vscale);
  330. if (!tset[coff])
  331. tr[coff] = tg[coff] = tb[coff] = 255;
  332. XPutPixel(pa, vxoff + col, vyoff + row,
  333. _get_lookup_for_color(tr[coff],
  334. tg[coff], tb[coff]));
  335. }
  336. }
  337. G_close_cell(fd);
  338. }
  339. XPutImage(theDisplay, XtWindow(canvas), drawGC, pa, 0, 0,
  340. Left, Top, ncols, nrows);
  341. change_label(flabel, frame[cnt]);
  342. }
  343. G_free(cell);
  344. G_free(fcell);
  345. G_free(dcell);
  346. G_free(tr);
  347. G_free(tg);
  348. G_free(tb);
  349. G_free(tset);
  350. return (cnt);
  351. }
  352. /* ###################################################### */
  353. static Boolean do_run(XtPointer p)
  354. {
  355. static int first = 1;
  356. struct gui_data *cd = p;
  357. int i, cnt;
  358. Drawable dr;
  359. if (first) {
  360. first = 0;
  361. cnt = load_files();
  362. cd->curframe = cd->direction > 0 ? 0 : cnt - 1;
  363. cd->prevframe = cd->curframe;
  364. cd->step = cd->stop = 0;
  365. cd->loop = cd->swing = 0;
  366. cd->nframes = cnt;
  367. }
  368. if (cd->rewind) {
  369. cd->rewind = 0;
  370. cd->curframe = 0;
  371. cd->direction = 1;
  372. cd->step = 1;
  373. }
  374. if (cd->swing) {
  375. if (cd->curframe == cd->nframes || cd->curframe < 0) {
  376. cd->direction = -cd->direction;
  377. cd->curframe += cd->direction;
  378. }
  379. }
  380. else if (cd->loop) {
  381. if (cd->curframe == cd->nframes)
  382. cd->curframe = 0;
  383. else if (cd->curframe < 0)
  384. cd->curframe = cd->nframes - 1;
  385. }
  386. else if (cd->curframe == cd->nframes || cd->curframe < 0)
  387. cd->stop = 1;
  388. if (cd->stop && !cd->step)
  389. return (False);
  390. if (cd->curframe < cd->nframes && cd->curframe >= 0) {
  391. /* little pause */
  392. {
  393. float tf;
  394. for (tf = 0.0; tf < cd->speed; tf += .01) ;
  395. }
  396. dr = XtWindow(canvas);
  397. XPutImage(theDisplay, dr, drawGC, pic_array[cd->curframe], 0, 0,
  398. Left, Top, ncols, nrows);
  399. /* draw labels */
  400. if (cd->shownames == 1)
  401. for (i = 0; i < numviews; i++) {
  402. XDrawString(theDisplay, dr, drawGC,
  403. LabelPos[i][0] + 5, LabelPos[i][1] - 5,
  404. vfiles[i][cd->curframe],
  405. (int)strlen(vfiles[i][cd->curframe]));
  406. }
  407. else if (cd->shownames == 2)
  408. for (i = 0; i < numviews; i++) {
  409. XDrawString(theDisplay, dr, invertGC,
  410. LabelPos[i][0] + 5, LabelPos[i][1] - 5,
  411. vfiles[i][cd->curframe],
  412. (int)strlen(vfiles[i][cd->curframe]));
  413. }
  414. change_label(flabel, frame[cd->curframe]);
  415. cd->prevframe = cd->curframe;
  416. }
  417. cd->curframe += cd->direction;
  418. if (cd->step) {
  419. cd->step = 0;
  420. cd->stop = 1;
  421. }
  422. return False; /* to keep it running */
  423. }
  424. /* ###################################################### */
  425. static char **gee_wildfiles(char *wildarg, char *element, int *num)
  426. {
  427. int n, cnt = 0;
  428. char path[GPATH_MAX], *mapset, cmd[GPATH_MAX], buf[512];
  429. char *p, *tfile;
  430. static char *newfiles[MAXIMAGES];
  431. FILE *tf;
  432. *num = 0;
  433. tfile = G_tempfile();
  434. /* build list of filenames */
  435. for (n = 0; (mapset = G__mapset_name(n)); n++) {
  436. if (strcmp(mapset, ".") == 0)
  437. mapset = G_mapset();
  438. G__file_name(path, element, "", mapset);
  439. if (access(path, 0) == 0) {
  440. sprintf(cmd, "cd %s; \\ls %s >> %s 2> /dev/null", path, wildarg,
  441. tfile);
  442. system(cmd);
  443. }
  444. }
  445. if (NULL == (tf = fopen(tfile, "r")))
  446. G_warning(_("Error reading wildcard"));
  447. else {
  448. while (NULL != fgets(buf, 512, tf)) {
  449. /* replace newline with null */
  450. if ((p = strchr(buf, '\n')))
  451. *p = '\0';
  452. /* replace first space with null */
  453. else if ((p = strchr(buf, ' ')))
  454. *p = '\0';
  455. if (strlen(buf) > 1) {
  456. newfiles[cnt++] = G_store(buf);
  457. }
  458. }
  459. fclose(tf);
  460. }
  461. *num = cnt;
  462. G_free(tfile);
  463. return (newfiles);
  464. }
  465. /********************************************************************/
  466. /* to change label in label widget */
  467. static void change_label(Widget wid, char *str)
  468. {
  469. Arg wargs[1];
  470. XmString xmstr;
  471. xmstr = XmStringCreateSimple(str);
  472. XtSetArg(wargs[0], XmNlabelString, xmstr);
  473. XtSetValues(wid, wargs, 1);
  474. XmStringFree(xmstr);
  475. }
  476. /********************************************************************/
  477. static void parse_command(int argc, char **argv,
  478. char *vfiles[MAXVIEWS][MAXIMAGES],
  479. int *numviews, int *numframes)
  480. {
  481. struct Option *viewopts[MAXVIEWS];
  482. char buf[BUFSIZ], **wildfiles;
  483. int i, j, k, numi, wildnum;
  484. *numviews = *numframes = 0;
  485. for (i = 0; i < MAXVIEWS; i++) {
  486. viewopts[i] = G_define_option();
  487. sprintf(buf, "view%d", i + 1);
  488. viewopts[i]->key = G_store(buf);
  489. viewopts[i]->type = TYPE_STRING;
  490. viewopts[i]->required = (i ? NO : YES);
  491. viewopts[i]->multiple = YES;
  492. viewopts[i]->gisprompt = "old,cell,Raster";;
  493. sprintf(buf, _("Raster file(s) for View%d"), i + 1);
  494. viewopts[i]->description = G_store(buf);
  495. }
  496. if (G_parser(argc, argv))
  497. exit(EXIT_FAILURE);
  498. for (i = 0; i < MAXVIEWS; i++) {
  499. if (viewopts[i]->answers) {
  500. (*numviews)++;
  501. for (j = 0, numi = 0; viewopts[i]->answers[j]; j++) {
  502. if ((NULL != strchr(viewopts[i]->answers[j], '*')) ||
  503. (NULL != strchr(viewopts[i]->answers[j], '?')) ||
  504. (NULL != strchr(viewopts[i]->answers[j], '['))) {
  505. wildfiles = gee_wildfiles(viewopts[i]->answers[j],
  506. "cell", &wildnum);
  507. for (k = 0; k < wildnum; k++)
  508. vfiles[i][numi++] = wildfiles[k];
  509. }
  510. else
  511. vfiles[i][numi++] = G_store(viewopts[i]->answers[j]);
  512. }
  513. /* keep track of smallest number of frames */
  514. *numframes =
  515. *numframes ? *numframes > numi ? numi : *numframes : numi;
  516. }
  517. }
  518. }