main.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750
  1. /*
  2. ****************************************************************************
  3. *
  4. * MODULE: d.rast.arrow
  5. * AUTHOR(S): Chris Rewerts, Agricultural Engineering, Purdue University
  6. * PURPOSE: Draw arrows on slope/aspect maps.
  7. * COPYRIGHT: (C) 2000, 2010 by the GRASS Development Team
  8. *
  9. * This program is free software under the GNU General Public
  10. * License (>=v2). Read the file COPYING that comes with GRASS
  11. * for details.
  12. *
  13. *****************************************************************************/
  14. /* some minor cleanup done by Andreas Lange, andreas.lange@rhein-main.de
  15. * Update to handle NULLs and floating point aspect maps: Hamish Bowman, Aug 2004
  16. * Update for 360 degree arrows and magnitude scaling: Hamish Bowman, Oct 2005
  17. */
  18. /*
  19. * Chris Rewerts, Agricultural Engineering, Purdue University
  20. * rewerts@ecn.purdue.edu March 1991
  21. *
  22. * d.rast.arrow
  23. *
  24. * Usage: d.rast.arrow
  25. *
  26. * This program used Dgrid's sources as a beginning. Purpose of Darrow
  27. * is to read an aspect layer produced by slope.aspect or by the
  28. * programs created for the ANSWERS or AGNPS Hydrology Toolbox
  29. * endeavors. d.rast.arrow draws an arrow on the graphic display
  30. * of each cell, so that the flow pattern computed as an aspect
  31. * layer can be easily seen. Other symbols ("?", "X") may be drawn
  32. * as needed.
  33. */
  34. #include <stdlib.h>
  35. #include <string.h>
  36. #include <math.h>
  37. #include <grass/gis.h>
  38. #include <grass/raster.h>
  39. #include <grass/display.h>
  40. #include <grass/colors.h>
  41. #include <grass/glocale.h>
  42. # define RpD ((2 * M_PI) / 360.) /* radians/degree */
  43. # define D2R(d) (double)(d * RpD) /* degrees->radians */
  44. static void arrow_mag(double, double);
  45. static void arrow_360(double);
  46. static void arrow_se(void);
  47. static void arrow_ne(void);
  48. static void arrow_nw(void);
  49. static void arrow_sw(void);
  50. static void arrow_e(void);
  51. static void arrow_w(void);
  52. static void arrow_s(void);
  53. static void arrow_n(void);
  54. static void draw_x(void);
  55. static void unknown_(void);
  56. static char *layer_name;
  57. static int map_type, arrow_color, grid_color, x_color, unknown_color;
  58. static int row, col;
  59. int main(int argc, char **argv)
  60. {
  61. struct Cell_head window;
  62. RASTER_MAP_TYPE raster_type, mag_raster_type = -1;
  63. int layer_fd;
  64. void *raster_row, *ptr;
  65. int nrows, ncols;
  66. int aspect_c = -1;
  67. float aspect_f = -1.0;
  68. double scale;
  69. int skip, no_arrow;
  70. char *mag_map = NULL;
  71. void *mag_raster_row = NULL, *mag_ptr = NULL;
  72. double length = -1;
  73. int mag_fd = -1;
  74. struct FPRange range;
  75. double mag_min, mag_max;
  76. struct GModule *module;
  77. struct Option *opt1, *opt2, *opt3, *opt4, *opt5,
  78. *opt6, *opt7, *opt8, *opt9;
  79. struct Flag *align;
  80. double t, b, l, r;
  81. G_gisinit(argv[0]);
  82. module = G_define_module();
  83. G_add_keyword(_("display"));
  84. G_add_keyword(_("map annotations"));
  85. G_add_keyword(_("raster"));
  86. module->description =
  87. _("Draws arrows representing cell aspect direction "
  88. "for a raster map containing aspect data.");
  89. opt1 = G_define_standard_option(G_OPT_R_MAP);
  90. opt1->description = _("Name of raster aspect map to be displayed");
  91. opt2 = G_define_option();
  92. opt2->key = "type";
  93. opt2->type = TYPE_STRING;
  94. opt2->required = NO;
  95. opt2->answer = "grass";
  96. opt2->options = "grass,compass,agnps,answers";
  97. opt2->description = _("Type of existing raster aspect map");
  98. opt3 = G_define_option();
  99. opt3->key = "arrow_color";
  100. opt3->type = TYPE_STRING;
  101. opt3->required = NO;
  102. opt3->answer = "green";
  103. opt3->gisprompt = "old_color,color,color";
  104. opt3->description = _("Color for drawing arrows");
  105. opt3->guisection = _("Colors");
  106. opt4 = G_define_option();
  107. opt4->key = "grid_color";
  108. opt4->required = NO;
  109. opt4->answer = "gray";
  110. opt4->gisprompt = "old,color_none,color";
  111. opt4->description = _("Color for drawing grid or \"none\"");
  112. opt4->guisection = _("Colors");
  113. opt5 = G_define_option();
  114. opt5->key = "x_color";
  115. opt5->type = TYPE_STRING;
  116. opt5->required = NO;
  117. opt5->answer = DEFAULT_FG_COLOR;
  118. opt5->gisprompt = "old,color_none,color";
  119. opt5->description = _("Color for drawing X's (null values)");
  120. opt5->guisection = _("Colors");
  121. opt6 = G_define_option();
  122. opt6->key = "unknown_color";
  123. opt6->type = TYPE_STRING;
  124. opt6->required = NO;
  125. opt6->answer = "red";
  126. opt6->gisprompt = "old,color_none,color";
  127. opt6->description = _("Color for showing unknown information");
  128. opt6->guisection = _("Colors");
  129. opt9 = G_define_option();
  130. opt9->key = "skip";
  131. opt9->type = TYPE_INTEGER;
  132. opt9->required = NO;
  133. opt9->answer = "1";
  134. opt9->description = _("Draw arrow every Nth grid cell");
  135. opt7 = G_define_option();
  136. opt7->key = "magnitude_map";
  137. opt7->type = TYPE_STRING;
  138. opt7->required = NO;
  139. opt7->multiple = NO;
  140. opt7->gisprompt = "old,cell,raster";
  141. opt7->description =
  142. _("Raster map containing values used for arrow length");
  143. opt8 = G_define_option();
  144. opt8->key = "scale";
  145. opt8->type = TYPE_DOUBLE;
  146. opt8->required = NO;
  147. opt8->answer = "1.0";
  148. opt8->description = _("Scale factor for arrows (magnitude map)");
  149. align = G_define_flag();
  150. align->key = 'a';
  151. align->description = _("Align grids with raster cells");
  152. /* Check command line */
  153. if (G_parser(argc, argv))
  154. exit(EXIT_FAILURE);
  155. layer_name = opt1->answer;
  156. arrow_color = D_translate_color(opt3->answer);
  157. x_color = D_translate_color(opt5->answer);
  158. unknown_color = D_translate_color(opt6->answer);
  159. if (strcmp("none", opt4->answer) == 0)
  160. grid_color = -1;
  161. else
  162. grid_color = D_translate_color(opt4->answer);
  163. if (strcmp("grass", opt2->answer) == 0)
  164. map_type = 1;
  165. else if (strcmp("agnps", opt2->answer) == 0)
  166. map_type = 2;
  167. else if (strcmp("answers", opt2->answer) == 0)
  168. map_type = 3;
  169. else if (strcmp("compass", opt2->answer) == 0)
  170. map_type = 4;
  171. scale = atof(opt8->answer);
  172. if (scale <= 0.0)
  173. G_fatal_error(_("Illegal value for scale factor"));
  174. skip = atoi(opt9->answer);
  175. if (skip <= 0)
  176. G_fatal_error(_("Illegal value for skip factor"));
  177. if (opt7->answer) {
  178. if (map_type != 1 && map_type != 4)
  179. G_fatal_error(_("Magnitude is only supported for GRASS and compass aspect maps."));
  180. mag_map = opt7->answer;
  181. }
  182. else if (scale != 1.0)
  183. G_warning(_("Scale option requires magnitude_map"));
  184. /* Setup driver and check important information */
  185. if (D_open_driver() != 0)
  186. G_fatal_error(_("No graphics device selected. "
  187. "Use d.mon to select graphics device."));
  188. D_setup(0);
  189. /* Read in the map window associated with window */
  190. G_get_window(&window);
  191. if (align->answer) {
  192. struct Cell_head wind;
  193. Rast_get_cellhd(layer_name, "", &wind);
  194. /* expand window extent by one wind resolution */
  195. wind.west += wind.ew_res * ((int)((window.west - wind.west) / wind.ew_res) - (window.west < wind.west));
  196. wind.east += wind.ew_res * ((int)((window.east - wind.east) / wind.ew_res) + (window.east > wind.east));
  197. wind.south += wind.ns_res * ((int)((window.south - wind.south) / wind.ns_res) - (window.south < wind.south));
  198. wind.north += wind.ns_res * ((int)((window.north - wind.north) / wind.ns_res) + (window.north > wind.north));
  199. wind.rows = (wind.north - wind.south) / wind.ns_res;
  200. wind.cols = (wind.east - wind.west) / wind.ew_res;
  201. Rast_set_window(&wind);
  202. nrows = wind.rows;
  203. ncols = wind.cols;
  204. t = (wind.north - window.north) * nrows / (wind.north - wind.south);
  205. b = t + (window.north - window.south) * nrows / (wind.north - wind.south);
  206. l = (window.west - wind.west) * ncols / (wind.east - wind.west);
  207. r = l + (window.east - window.west) * ncols / (wind.east - wind.west);
  208. } else {
  209. nrows = window.rows;
  210. ncols = window.cols;
  211. t = 0;
  212. b = nrows;
  213. l = 0;
  214. r = ncols;
  215. }
  216. D_set_src(t, b, l, r);
  217. D_update_conversions();
  218. /* figure out arrow scaling if using a magnitude map */
  219. if (opt7->answer) {
  220. Rast_init_fp_range(&range); /* really needed? */
  221. if (Rast_read_fp_range(mag_map, "", &range) != 1)
  222. G_fatal_error(_("Problem reading range file"));
  223. Rast_get_fp_range_min_max(&range, &mag_min, &mag_max);
  224. scale *= 1.5 / fabs(mag_max);
  225. G_debug(3, "scaling=%.2f rast_max=%.2f", scale, mag_max);
  226. }
  227. if (grid_color > 0) { /* ie not "none" */
  228. /* Set color */
  229. D_use_color(grid_color);
  230. /* Draw vertical grids */
  231. for (col = 0; col < ncols; col++)
  232. D_line_abs(col, 0, col, nrows);
  233. /* Draw horizontal grids */
  234. for (row = 0; row < nrows; row++)
  235. D_line_abs(0, row, ncols, row);
  236. }
  237. /* open the raster map */
  238. layer_fd = Rast_open_old(layer_name, "");
  239. raster_type = Rast_get_map_type(layer_fd);
  240. /* allocate the cell array */
  241. raster_row = Rast_allocate_buf(raster_type);
  242. if (opt7->answer) {
  243. /* open the magnitude raster map */
  244. mag_fd = Rast_open_old(mag_map, "");
  245. mag_raster_type = Rast_get_map_type(mag_fd);
  246. /* allocate the cell array */
  247. mag_raster_row = Rast_allocate_buf(mag_raster_type);
  248. }
  249. /* loop through cells, find value, determine direction (n,s,e,w,ne,se,sw,nw),
  250. and call appropriate function to draw an arrow on the cell */
  251. for (row = 0; row < nrows; row++) {
  252. Rast_get_row(layer_fd, raster_row, row, raster_type);
  253. ptr = raster_row;
  254. if (opt7->answer) {
  255. Rast_get_row(mag_fd, mag_raster_row, row, mag_raster_type);
  256. mag_ptr = mag_raster_row;
  257. }
  258. for (col = 0; col < ncols; col++) {
  259. if (row % skip != 0)
  260. no_arrow = TRUE;
  261. else
  262. no_arrow = FALSE;
  263. if (col % skip != 0)
  264. no_arrow = TRUE;
  265. /* find aspect direction based on cell value */
  266. if (raster_type == CELL_TYPE)
  267. aspect_f = *((CELL *) ptr);
  268. else if (raster_type == FCELL_TYPE)
  269. aspect_f = *((FCELL *) ptr);
  270. else if (raster_type == DCELL_TYPE)
  271. aspect_f = *((DCELL *) ptr);
  272. if (opt7->answer) {
  273. if (mag_raster_type == CELL_TYPE)
  274. length = *((CELL *) mag_ptr);
  275. else if (mag_raster_type == FCELL_TYPE)
  276. length = *((FCELL *) mag_ptr);
  277. else if (mag_raster_type == DCELL_TYPE)
  278. length = *((DCELL *) mag_ptr);
  279. length *= scale;
  280. if (Rast_is_null_value(mag_ptr, mag_raster_type)) {
  281. G_debug(5, "Invalid arrow length [NULL]. Skipping.");
  282. no_arrow = TRUE;
  283. }
  284. else if (length <= 0.0) { /* use fabs() or theta+=180? */
  285. G_debug(5, "Illegal arrow length [%.3f]. Skipping.",
  286. length);
  287. no_arrow = TRUE;
  288. }
  289. }
  290. if (no_arrow) {
  291. ptr = G_incr_void_ptr(ptr, Rast_cell_size(raster_type));
  292. if (opt7->answer)
  293. mag_ptr =
  294. G_incr_void_ptr(mag_ptr,
  295. Rast_cell_size(mag_raster_type));
  296. no_arrow = FALSE;
  297. continue;
  298. }
  299. /* treat AGNPS and ANSWERS data like old zero-as-null CELL */
  300. /* TODO: update models */
  301. if (map_type == 2 || map_type == 3) {
  302. if (Rast_is_null_value(ptr, raster_type))
  303. aspect_c = 0;
  304. else
  305. aspect_c = (int)(aspect_f + 0.5);
  306. }
  307. /** Now draw the arrows **/
  308. /* case switch for standard GRASS aspect map
  309. measured in degrees counter-clockwise from east */
  310. if (map_type == 1) {
  311. D_use_color(arrow_color);
  312. if (Rast_is_null_value(ptr, raster_type)) {
  313. D_use_color(x_color);
  314. draw_x();
  315. D_use_color(arrow_color);
  316. }
  317. else if (aspect_f >= 0.0 && aspect_f <= 360.0) {
  318. if (opt7->answer)
  319. arrow_mag(aspect_f, length);
  320. else
  321. arrow_360(aspect_f);
  322. }
  323. else {
  324. D_use_color(unknown_color);
  325. unknown_();
  326. D_use_color(arrow_color);
  327. }
  328. }
  329. /* case switch for AGNPS type aspect map */
  330. else if (map_type == 2) {
  331. D_use_color(arrow_color);
  332. switch (aspect_c) {
  333. case 0:
  334. D_use_color(x_color);
  335. draw_x();
  336. D_use_color(arrow_color);
  337. break;
  338. case 1:
  339. arrow_n();
  340. break;
  341. case 2:
  342. arrow_ne();
  343. break;
  344. case 3:
  345. arrow_e();
  346. break;
  347. case 4:
  348. arrow_se();
  349. break;
  350. case 5:
  351. arrow_s();
  352. break;
  353. case 6:
  354. arrow_sw();
  355. break;
  356. case 7:
  357. arrow_w();
  358. break;
  359. case 8:
  360. arrow_nw();
  361. break;
  362. default:
  363. D_use_color(unknown_color);
  364. unknown_();
  365. D_use_color(arrow_color);
  366. break;
  367. }
  368. }
  369. /* case switch for ANSWERS type aspect map */
  370. else if (map_type == 3) {
  371. D_use_color(arrow_color);
  372. if (aspect_c >= 15 && aspect_c <= 360) /* start at zero? */
  373. arrow_360((double)aspect_c);
  374. else if (aspect_c == 400) {
  375. D_use_color(unknown_color);
  376. unknown_();
  377. D_use_color(arrow_color);
  378. }
  379. else {
  380. D_use_color(x_color);
  381. draw_x();
  382. D_use_color(arrow_color);
  383. }
  384. }
  385. /* case switch for compass type aspect map
  386. measured in degrees clockwise from north */
  387. else if (map_type == 4) {
  388. D_use_color(arrow_color);
  389. if (Rast_is_null_value(ptr, raster_type)) {
  390. D_use_color(x_color);
  391. draw_x();
  392. D_use_color(arrow_color);
  393. }
  394. else if (aspect_f >= 0.0 && aspect_f <= 360.0) {
  395. if (opt7->answer)
  396. arrow_mag(90 - aspect_f, length);
  397. else
  398. arrow_360(90 - aspect_f);
  399. }
  400. else {
  401. D_use_color(unknown_color);
  402. unknown_();
  403. D_use_color(arrow_color);
  404. }
  405. }
  406. ptr = G_incr_void_ptr(ptr, Rast_cell_size(raster_type));
  407. if (opt7->answer)
  408. mag_ptr =
  409. G_incr_void_ptr(mag_ptr, Rast_cell_size(mag_raster_type));
  410. }
  411. }
  412. Rast_close(layer_fd);
  413. if (opt7->answer)
  414. Rast_close(mag_fd);
  415. D_save_command(G_recreate_command());
  416. D_close_driver();
  417. exit(EXIT_SUCCESS);
  418. }
  419. /* --- end of main --- */
  420. /*---------------------------------------------------------------*/
  421. static void arrow_mag(double theta, double length)
  422. { /* angle is measured in degrees counter-clockwise from east */
  423. double x, y, dx, dy, mid_x, mid_y;
  424. double theta_offset;
  425. theta *= -1; /* display coords use inverse y */
  426. /* find the display coordinates of the middle of the cell */
  427. mid_x = col + (.5);
  428. mid_y = row + (.5);
  429. D_begin();
  430. /* tail */
  431. D_move_abs(mid_x, mid_y);
  432. /* head */
  433. x = mid_x + (length * cos(D2R(theta)));
  434. y = mid_y + (length * sin(D2R(theta)));
  435. D_cont_abs(x, y);
  436. /* fin 1 */
  437. theta_offset = theta + 20;
  438. dx = mid_x + (0.6 * length * cos(D2R(theta_offset)));
  439. dy = mid_y + (0.6 * length * sin(D2R(theta_offset)));
  440. D_cont_abs(dx, dy);
  441. /* fin 2 */
  442. D_move_abs(x, y);
  443. theta_offset = theta - 20;
  444. dx = mid_x + (0.6 * length * cos(D2R(theta_offset)));
  445. dy = mid_y + (0.6 * length * sin(D2R(theta_offset)));
  446. D_cont_abs(dx, dy);
  447. D_end();
  448. D_stroke();
  449. }
  450. static void arrow_360(double theta)
  451. { /* angle is measured in degrees counter-clockwise from east */
  452. double x, y, dx, dy, mid_x, mid_y;
  453. double max_radius, theta_offset;
  454. theta *= -1; /* display coords use inverse y */
  455. max_radius = 0.8 / 2;
  456. /* find the display coordinates of the middle of the cell */
  457. mid_x = col + (0.5);
  458. mid_y = row + (0.5);
  459. D_begin();
  460. /* head */
  461. x = mid_x + (max_radius * cos(D2R(theta)));
  462. y = mid_y + (max_radius * sin(D2R(theta)));
  463. D_move_abs(x, y);
  464. /* tail */
  465. dx = -2 * (max_radius * cos(D2R(theta)));
  466. dy = -2 * (max_radius * sin(D2R(theta)));
  467. D_cont_rel(dx, dy);
  468. /* fin 1 */
  469. D_move_abs(x, y);
  470. theta_offset = theta + 90;
  471. dx = mid_x + (0.5 * max_radius * cos(D2R(theta_offset)));
  472. dy = mid_y + (0.5 * max_radius * sin(D2R(theta_offset)));
  473. D_cont_abs(dx, dy);
  474. /* fin 2 */
  475. D_move_abs(x, y);
  476. theta_offset = theta - 90;
  477. dx = mid_x + (0.5 * max_radius * cos(D2R(theta_offset)));
  478. dy = mid_y + (0.5 * max_radius * sin(D2R(theta_offset)));
  479. D_cont_abs(dx, dy);
  480. D_end();
  481. D_stroke();
  482. }
  483. static void arrow_se(void)
  484. {
  485. double x = col + (.8);
  486. double y = row + (.8);
  487. D_begin();
  488. D_move_abs(x, y);
  489. D_cont_rel(((-.6)), (((-.6))));
  490. D_move_abs(x, y);
  491. D_cont_rel(0, ((-.4)));
  492. D_move_abs(x, y);
  493. D_cont_rel(((-.4)), 0);
  494. D_end();
  495. D_stroke();
  496. }
  497. static void arrow_ne(void)
  498. {
  499. double x = col + (.8);
  500. double y = row + (.2);
  501. D_begin();
  502. D_move_abs(x, y);
  503. D_cont_rel(((-.6)), (((.6))));
  504. D_move_abs(x, y);
  505. D_cont_rel(0, ((.4)));
  506. D_move_abs(x, y);
  507. D_cont_rel(((-.4)), 0);
  508. D_end();
  509. D_stroke();
  510. }
  511. static void arrow_nw(void)
  512. {
  513. double x = col + (.2);
  514. double y = row + (.2);
  515. D_begin();
  516. D_move_abs(x, y);
  517. D_cont_rel(((.6)), (((.6))));
  518. D_move_abs(x, y);
  519. D_cont_rel(0, ((.4)));
  520. D_move_abs(x, y);
  521. D_cont_rel(((.4)), 0);
  522. D_end();
  523. D_stroke();
  524. }
  525. static void arrow_sw(void)
  526. {
  527. double x = col + (.2);
  528. double y = row + (.8);
  529. D_begin();
  530. D_move_abs(x, y);
  531. D_cont_rel(((.6)), (((-.6))));
  532. D_move_abs(x, y);
  533. D_cont_rel(0, ((-.4)));
  534. D_move_abs(x, y);
  535. D_cont_rel(((.4)), 0);
  536. D_end();
  537. D_stroke();
  538. }
  539. static void arrow_e(void)
  540. {
  541. double x = col + (.9);
  542. double y = row + (.5);
  543. D_begin();
  544. D_move_abs(x, y);
  545. D_cont_rel(((-.8)), 0);
  546. D_move_abs(x, y);
  547. D_cont_rel(((-.3)), ((-.3)));
  548. D_move_abs(x, y);
  549. D_cont_rel(((-.3)), ((.3)));
  550. D_end();
  551. D_stroke();
  552. }
  553. static void arrow_w(void)
  554. {
  555. double x = col + (.1);
  556. double y = row + (.5);
  557. D_begin();
  558. D_move_abs(x, y);
  559. D_cont_rel(((.8)), 0);
  560. D_move_abs(x, y);
  561. D_cont_rel(((.3)), ((-.3)));
  562. D_move_abs(x, y);
  563. D_cont_rel(((.3)), ((.3)));
  564. D_end();
  565. D_stroke();
  566. }
  567. static void arrow_s(void)
  568. {
  569. double x = col + (.5);
  570. double y = row + (.9);
  571. D_begin();
  572. D_move_abs(x, y);
  573. D_cont_rel(0, ((-.8)));
  574. D_move_abs(x, y);
  575. D_cont_rel(((.3)), ((-.3)));
  576. D_move_abs(x, y);
  577. D_cont_rel(((-.3)), ((-.3)));
  578. D_end();
  579. D_stroke();
  580. }
  581. static void arrow_n(void)
  582. {
  583. double x = col + (.5);
  584. double y = row + (.1);
  585. D_begin();
  586. D_move_abs(x, y);
  587. D_cont_rel(0, ((.8)));
  588. D_move_abs(x, y);
  589. D_cont_rel(((.3)), ((.3)));
  590. D_move_abs(x, y);
  591. D_cont_rel(((-.3)), ((.3)));
  592. D_end();
  593. D_stroke();
  594. }
  595. static void draw_x(void)
  596. {
  597. double x = col;
  598. double y = row;
  599. D_begin();
  600. D_move_abs(x, y);
  601. D_cont_rel(1, 1);
  602. y = row + 1;
  603. D_move_abs(x, y);
  604. D_cont_rel(1, (-1));
  605. D_end();
  606. D_stroke();
  607. }
  608. static void unknown_(void)
  609. {
  610. double x = col + (.3);
  611. double y = row + (.4);
  612. D_begin();
  613. D_move_abs(x, y);
  614. D_cont_rel(0, ((-.15)));
  615. D_cont_rel(((.1)), ((-.1)));
  616. D_cont_rel(((.2)), 0);
  617. D_cont_rel(((.1)), ((.1)));
  618. D_cont_rel(0, ((.2)));
  619. D_cont_rel(((-.1)), ((.1)));
  620. D_cont_rel(((-.1)), 0);
  621. D_cont_rel(0, ((.25)));
  622. D_move_rel(0, ((.1)));
  623. D_cont_rel(0, ((.1)));
  624. D_end();
  625. D_stroke();
  626. }