main.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522
  1. /****************************************************************************
  2. *
  3. * MODULE: m.nviz.script (nee d.nviz)
  4. * AUTHOR(S): Bob Covill <bcovill@tekmap.ns.ca>
  5. * PURPOSE: interactively create fly-through script for NVIZ
  6. * Functions:
  7. * main -- parse parameters and get key frame coorinates
  8. * do_profile-- calculate camera and eye coordinates from
  9. * raster map
  10. * move -- part of screen coords
  11. * cont -- part of screen coords
  12. * read_rast -- return camera and eye coordinates
  13. *
  14. * COPYRIGHT: (C) 2000 by the GRASS Development Team
  15. *
  16. * This program is free software under the GNU General Public
  17. * License (>=v2). Read the file COPYING that comes with GRASS
  18. * for details.
  19. *
  20. *****************************************************************************/
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <math.h>
  24. #include <string.h>
  25. #include <grass/gis.h>
  26. #include <grass/raster.h>
  27. #include <grass/display.h>
  28. #include "local.h"
  29. #include <grass/glocale.h>
  30. int cut_val, frame = 0;
  31. int height_flag = 0;
  32. double OLD_DEPTH;
  33. char img_name[512];
  34. int no_frames;
  35. int cnt = 1;
  36. int key_frames = 0;
  37. int off_screen = 0;
  38. double key_time = 0.;
  39. FILE *fp, *fp2;
  40. int main(int argc, char *argv[])
  41. {
  42. const char *name;
  43. char outfile[GNAME_MAX];
  44. int fd, projection;
  45. char buf[512], buf1[1024], buf2[1024];
  46. int screen_x, screen_y;
  47. int i, k;
  48. int frame_start = 0;
  49. double e1, e2, n1, n2;
  50. RASTER_MAP_TYPE data_type;
  51. struct Cell_head window;
  52. struct
  53. {
  54. struct Option *opt1, *route, *name, *output, *dist, *ht, *frames,
  55. *start;
  56. struct Flag *f, *c, *k, *o, *e;
  57. }
  58. parm;
  59. struct GModule *module;
  60. G_gisinit(argv[0]);
  61. /* Set description */
  62. module = G_define_module();
  63. G_add_keyword(_("miscellaneous"));
  64. G_add_keyword(_("graphics"));
  65. G_add_keyword(_("raster"));
  66. G_add_keyword(_("raster3d"));
  67. G_add_keyword(_("vector"));
  68. G_add_keyword(_("visualization"));
  69. module->description = _("Creates fly-through script to run in NVIZ.");
  70. parm.opt1 = G_define_standard_option(G_OPT_R_INPUT);
  71. parm.output = G_define_standard_option(G_OPT_F_OUTPUT);
  72. parm.output->description = _("Name of output script");
  73. parm.name = G_define_option();
  74. parm.name->key = "name";
  75. parm.name->type = TYPE_STRING;
  76. parm.name->required = NO;
  77. parm.name->description = _("Prefix of output images (default = NVIZ)");
  78. parm.route = G_define_option();
  79. parm.route->key = "route";
  80. parm.route->type = TYPE_STRING;
  81. parm.route->required = NO;
  82. parm.route->multiple = YES;
  83. parm.route->key_desc = "east,north";
  84. parm.route->description = _("Route coordinates (east,north)");
  85. parm.dist = G_define_option();
  86. parm.dist->key = "dist";
  87. parm.dist->type = TYPE_DOUBLE;
  88. parm.dist->required = YES;
  89. parm.dist->description = _("Camera layback distance (in map units)");
  90. parm.ht = G_define_option();
  91. parm.ht->key = "ht";
  92. parm.ht->type = TYPE_DOUBLE;
  93. parm.ht->required = YES;
  94. parm.ht->description = _("Camera height above terrain");
  95. parm.frames = G_define_option();
  96. parm.frames->key = "frames";
  97. parm.frames->type = TYPE_INTEGER;
  98. parm.frames->required = YES;
  99. parm.frames->description = _("Number of frames");
  100. parm.start = G_define_option();
  101. parm.start->key = "start";
  102. parm.start->type = TYPE_INTEGER;
  103. parm.start->required = NO;
  104. parm.start->description = _("Start frame number (default=0)");
  105. parm.f = G_define_flag();
  106. parm.f->key = 'f';
  107. parm.f->description = _("Full render -- Save images");
  108. parm.c = G_define_flag();
  109. parm.c->key = 'c';
  110. parm.c->description = _("Fly at constant elevation (ht)");
  111. parm.k = G_define_flag();
  112. parm.k->key = 'k';
  113. parm.k->description =
  114. _("Include command in the script to output a KeyFrame file");
  115. parm.o = G_define_flag();
  116. parm.o->key = 'o';
  117. parm.o->description = _("Render images off-screen");
  118. parm.e = G_define_flag();
  119. parm.e->key = 'e';
  120. parm.e->description = _("Enable vector and sites drawing");
  121. if (G_parser(argc, argv))
  122. exit(EXIT_FAILURE);
  123. /* check arguments */
  124. if (!parm.route->answer)
  125. G_fatal_error(_("Either -i flag and/or route parameter must be used"));
  126. /* get GRASS parameters */
  127. G_get_window(&window);
  128. projection = G_projection();
  129. D_do_conversions(&window, 0, 1, 0, 1);
  130. /* setup screen coords */
  131. screen_x = ((int)D_get_d_west() + (int)D_get_d_east()) / 2;
  132. screen_y = ((int)D_get_d_north() + (int)D_get_d_south()) / 2;
  133. /* get camera parameters */
  134. DIST = atof(parm.dist->answer);
  135. HT = atof(parm.ht->answer);
  136. no_frames = atoi(parm.frames->answer);
  137. if (parm.start->answer)
  138. frame_start = atoi(parm.start->answer);
  139. if (parm.c->answer)
  140. height_flag = 1;
  141. if (parm.k->answer)
  142. key_frames = 1;
  143. if (parm.o->answer && !parm.f->answer)
  144. G_fatal_error(_("Off-screen only available with full render mode"));
  145. if (parm.o->answer)
  146. off_screen = 1;
  147. /* Initialize coords */
  148. e1 = e2 = n1 = n2 = -9999.;
  149. G_begin_distance_calculations();
  150. /* Open Input File for reading */
  151. name = parm.opt1->answer;
  152. /* Open Raster File */
  153. fd = Rast_open_old(name, "");
  154. /* Set Image name */
  155. if (parm.name->answer)
  156. sprintf(img_name, "%s", parm.name->answer);
  157. else
  158. sprintf(img_name, "NVIZ");
  159. /* Open ASCII file for output */
  160. /* append ".nvscr" to filename if it doesn't already have it */
  161. strncpy(outfile, parm.output->answer, GNAME_MAX - 7);
  162. outfile[GNAME_MAX - 7] = '\0'; /* strncpy() doesn't null terminate the string */
  163. if (strcmp(&outfile[strlen(outfile) - 6], ".nvscr") != 0)
  164. strcat(outfile, ".nvscr");
  165. if (NULL == (fp = fopen(outfile, "w")))
  166. G_fatal_error(_("Unable to open file <%s>"), outfile);
  167. /* Get Raster Type */
  168. data_type = Rast_get_map_type(fd);
  169. /* Done with file */
  170. /* Output initial startup stuff */
  171. sprintf(buf1,
  172. "## REGION: n=%f s=%f e=%f w=%f\n## Input=%s Dist=%f Ht=%f\n",
  173. window.north, window.south, window.east, window.west, outfile,
  174. DIST, HT);
  175. sprintf(buf2, "\nset FRAMES %d\n", no_frames);
  176. strcat(buf1, buf2);
  177. fprintf(fp, "%s", buf1);
  178. sprintf(buf1, "SendScriptLine \"Nclear_keys\"");
  179. sprintf(buf2, "\nSendScriptLine \"Nupdate_frames\"");
  180. strcat(buf1, buf2);
  181. fprintf(fp, "%s", buf1);
  182. sprintf(buf1, "\nSendScriptLine \"Nset_numsteps $FRAMES\"");
  183. sprintf(buf2, "\nSendScriptLine \"Nupdate_frames\"\n");
  184. strcat(buf1, buf2);
  185. fprintf(fp, "%s", buf1);
  186. /* Use Linear mode for smooth frame transition */
  187. sprintf(buf1, "\nSendScriptLine \"Nset_interp_mode linear\"");
  188. sprintf(buf2, "\nSendScriptLine \"Nupdate_frames\"\n\n");
  189. strcat(buf1, buf2);
  190. fprintf(fp, "%s", buf1);
  191. /* eanble vector and sites drawing */
  192. if (parm.e->answer) {
  193. sprintf(buf1, "\nSendScriptLine \"Nshow_vect on\"");
  194. sprintf(buf2, "\nSendScriptLine \"Nshow_sites on\"\n\n");
  195. strcat(buf1, buf2);
  196. fprintf(fp, "%s", buf1);
  197. }
  198. /* Coords from Command Line */
  199. k = 0;
  200. for (i = 0; parm.route->answers[i]; i += 2) {
  201. /* Test for number coordinate pairs */
  202. k = i;
  203. }
  204. if (k < 6) {
  205. /* Only one coordinate pair supplied */
  206. G_fatal_error(_("You must provide at least four points %d"), k);
  207. }
  208. else {
  209. for (i = 0; i <= k - 2; i += 2) {
  210. sscanf(parm.route->answers[i], "%lf", &e1);
  211. sscanf(parm.route->answers[i + 1], "%lf", &n1);
  212. sscanf(parm.route->answers[i + 2], "%lf", &e2);
  213. sscanf(parm.route->answers[i + 3], "%lf", &n2);
  214. /* Get profile info */
  215. do_profile(e1, e2, n1, n2, name, fd, data_type);
  216. /* Get last coord */
  217. if (i == k - 2)
  218. do_profile(e2, e2, n2, n2, name, fd, data_type);
  219. }
  220. }
  221. /* done with coordinates */
  222. /* Output final part of script */
  223. /* generate key-frame script */
  224. if (key_frames) {
  225. strcpy(buf, outfile);
  226. buf[strlen(outfile) - 6] = '\0'; /* skip extension */
  227. strcat(buf, ".kanim");
  228. fprintf(fp, "\n## The following saves the animation to a format\n");
  229. fprintf(fp, "## suitable for editing with the kanimator panel\n");
  230. fprintf(fp, "SendScriptLine \"Nprint_keys %s\"\n", buf);
  231. fprintf(fp, "puts \"Saving Key Frame file %s\"\n", buf);
  232. }
  233. /* output off-screen option */
  234. if (off_screen) {
  235. fprintf(fp, "\n## Off screen rendering enabled \n");
  236. fprintf(fp, "## Ensure main window is minimized before running\n");
  237. fprintf(fp, "SendScriptLine \"Noff_screen 1\"\n");
  238. }
  239. fprintf(fp, "\n\nset num %d", frame_start);
  240. fprintf(fp, "\n\nfor {set frame 1} {$frame <= $FRAMES} {incr frame} {");
  241. if (parm.f->answer) {
  242. /* Full render and save */
  243. fprintf(fp, "\nset name %s", img_name);
  244. fprintf(fp, "\nset num2 [format \"%%04d\" $num]");
  245. fprintf(fp, "\nappend name $num2 \".ppm\"");
  246. fprintf(fp, "\nSendScriptLine \"Ndo_framestep $frame 1\"");
  247. fprintf(fp, "\nSendScriptLine \"Nwrite_ppm $name \"");
  248. fprintf(fp, "\nincr num");
  249. }
  250. else {
  251. /* Quick draw wire */
  252. /* output full variables commented so can be easily changed */
  253. fprintf(fp, "\nset name %s", img_name);
  254. fprintf(fp, "\nset num2 [format \"%%04d\" $num]");
  255. fprintf(fp, "\nappend name $num2 \".ppm\"");
  256. fprintf(fp,
  257. "\n## To render in full set to 1 and uncomment Nwrite_ppm \"");
  258. fprintf(fp, "\nSendScriptLine \"Ndo_framestep $frame 0\"");
  259. fprintf(fp, "\n#SendScriptLine \"Nwrite_ppm $name \"");
  260. fprintf(fp, "\nincr num");
  261. }
  262. fprintf(fp, "\n}\n");
  263. if (off_screen)
  264. fprintf(fp, "SendScriptLine \"Noff_screen 0\"\n");
  265. fprintf(fp, "SendScriptLine \"set ScriptPlaying 0\"\n");
  266. fprintf(fp, "puts \"DONE!\"\n");
  267. Rast_close(fd);
  268. fclose(fp);
  269. G_done_msg(_("Created NVIZ script <%s>."), outfile);
  270. exit(EXIT_SUCCESS);
  271. } /* Done with main */
  272. /* ************************************
  273. * Calculate camera and eye coordinates
  274. **************************************/
  275. int do_profile(double e1, double e2, double n1, double n2,
  276. const char *name, int fd, int data_type)
  277. {
  278. float rows, cols, LEN;
  279. double Y, X, AZI;
  280. cols = e1 - e2;
  281. rows = n1 - n2;
  282. LEN = G_distance(e1, n1, e2, n2);
  283. /* Calculate Azimuth of Line */
  284. if (rows == 0 && cols == 0) {
  285. /* Special case for no movement */
  286. /* do nothing */
  287. return 0;
  288. }
  289. /* dist is not initialized ! */
  290. if (rows >= 0 && cols < 0) {
  291. /* SE Quad or due east */
  292. AZI = fabs(atan((rows / cols)));
  293. Y = (double)DIST *sin(AZI);
  294. X = (double)DIST *cos(AZI);
  295. if (e != 0.0 && (e != e1 || n != n1)) {
  296. dist -= G_distance(e, n, e1, n1);
  297. }
  298. read_rast(e2 - X, n2 + Y, LEN, fd, 1, data_type);
  299. read_rast(e2, n2, LEN, fd, 0, data_type);
  300. }
  301. if (rows < 0 && cols <= 0) {
  302. /* NE Quad or due north */
  303. AZI = fabs(atan((cols / rows)));
  304. X = (double)DIST *sin(AZI);
  305. Y = (double)DIST *cos(AZI);
  306. if (e != 0.0 && (e != e1 || n != n1)) {
  307. dist -= G_distance(e, n, e1, n1);
  308. }
  309. read_rast(e2 - X, n2 - Y, LEN, fd, 1, data_type);
  310. read_rast(e2, n2, LEN, fd, 0, data_type);
  311. }
  312. if (rows > 0 && cols >= 0) {
  313. /* SW Quad or due south */
  314. AZI = fabs(atan((rows / cols)));
  315. X = (double)DIST *cos(AZI);
  316. Y = (double)DIST *sin(AZI);
  317. if (e != 0.0 && (e != e1 || n != n1)) {
  318. dist -= G_distance(e, n, e1, n1);
  319. }
  320. read_rast(e2 + X, n2 + Y, LEN, fd, 1, data_type);
  321. read_rast(e2, n2, LEN, fd, 0, data_type);
  322. }
  323. if (rows <= 0 && cols > 0) {
  324. /* NW Quad or due west */
  325. AZI = fabs(atan((rows / cols)));
  326. X = (double)DIST *cos(AZI);
  327. Y = (double)DIST *sin(AZI);
  328. if (e != 0.0 && (e != e1 || n != n1)) {
  329. dist -= G_distance(e, n, e1, n1);
  330. }
  331. read_rast(e2 + X, n2 - Y, LEN, fd, 1, data_type);
  332. read_rast(e2, n2, LEN, fd, 0, data_type);
  333. }
  334. /* dist is not used ! */
  335. return 0;
  336. } /* done with do_profile */
  337. /*****************************
  338. * read_rast
  339. * function to get raster value at set location
  340. * and output nviz script
  341. *****************************/
  342. int read_rast
  343. (double east,
  344. double north,
  345. double rrdist, int fd, int out_type, RASTER_MAP_TYPE data_type)
  346. {
  347. int row, col, nrows, ncols;
  348. struct Cell_head window;
  349. CELL *cell;
  350. char buf[1024] = "";
  351. char buf2[1024];
  352. FCELL *fcell;
  353. DCELL *dcell;
  354. double camera_height;
  355. G_get_window(&window);
  356. nrows = window.rows;
  357. ncols = window.cols;
  358. row = (int)(0.5 + D_u_to_a_row(north));
  359. col = (int)(0.5 + D_u_to_a_col(east));
  360. if (row < 0 || row > nrows || col < 0 || col > ncols) {
  361. G_debug(3, "Fail: row=%d nrows=%d col=%d ncols=%d", row, nrows,
  362. col, ncols);
  363. G_warning(_("Skipping this point, selected point is outside region. "
  364. "Perhaps the camera setback distance puts it beyond the edge?"));
  365. frame++;
  366. return 1;
  367. }
  368. if (data_type == CELL_TYPE) {
  369. cell = Rast_allocate_c_buf();
  370. Rast_get_c_row(fd, cell, row);
  371. if (Rast_is_c_null_value(&cell[col]))
  372. camera_height = (double)9999.;
  373. else
  374. camera_height = (double)cell[col];
  375. G_free(cell);
  376. }
  377. if (data_type == FCELL_TYPE) {
  378. fcell = Rast_allocate_f_buf();
  379. Rast_get_f_row(fd, fcell, row);
  380. if (Rast_is_f_null_value(&fcell[col]))
  381. camera_height = (double)9999.;
  382. else
  383. camera_height = (double)fcell[col];
  384. G_free(fcell);
  385. }
  386. if (data_type == DCELL_TYPE) {
  387. dcell = Rast_allocate_d_buf();
  388. Rast_get_d_row(fd, dcell, row);
  389. if (Rast_is_d_null_value(&dcell[col]))
  390. camera_height = (double)9999.;
  391. else
  392. camera_height = (double)dcell[col];
  393. G_free(dcell);
  394. }
  395. /* Output script commands */
  396. /*************************/
  397. /* Set camera Height value */
  398. if (camera_height == 9999.)
  399. camera_height = OLD_DEPTH;
  400. if (height_flag && out_type)
  401. camera_height = HT;
  402. else if (!height_flag && out_type)
  403. camera_height = camera_height + HT;
  404. if (out_type) {
  405. /* Set Camera Position */
  406. sprintf(buf2, "\nSendScriptLine \"Nmove_to_real %f %f %f\"",
  407. east, north, camera_height);
  408. key_time += (rrdist + fabs(camera_height - OLD_DEPTH)) / 10000.;
  409. }
  410. else {
  411. /* Set Center of View */
  412. sprintf(buf2, "\nSendScriptLine \"Nset_focus %f %f %f\"",
  413. east - window.west - (window.ew_res / 2),
  414. north - window.south - (window.ns_res / 2), camera_height);
  415. /* Use frame number for now -- TODO figure even increment
  416. * based on no. of frames and distance */
  417. sprintf(buf,
  418. "\nSendScriptLine \"Nadd_key %f KF_ALL_MASK 1 0.0\"\n",
  419. key_time);
  420. strcat(buf2, buf);
  421. cnt++;
  422. }
  423. /* Out to file */
  424. fprintf(fp, "%s", buf2);
  425. OLD_DEPTH = camera_height;
  426. frame++;
  427. return 0;
  428. }