main.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753
  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 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. module->keywords = _("display");
  84. module->description =
  85. _("Draws arrows representing cell aspect direction "
  86. "for a raster map containing aspect data.");
  87. opt1 = G_define_option();
  88. opt1->key = "map";
  89. opt1->type = TYPE_STRING;
  90. opt1->required = YES;
  91. opt1->multiple = NO;
  92. opt1->gisprompt = "old,cell,raster";
  93. opt1->description = _("Name of raster aspect map to be displayed");
  94. opt2 = G_define_option();
  95. opt2->key = "type";
  96. opt2->type = TYPE_STRING;
  97. opt2->required = NO;
  98. opt2->answer = "grass";
  99. opt2->options = "grass,compass,agnps,answers";
  100. opt2->description = _("Type of existing raster aspect map");
  101. opt3 = G_define_option();
  102. opt3->key = "arrow_color";
  103. opt3->type = TYPE_STRING;
  104. opt3->required = NO;
  105. opt3->answer = "green";
  106. opt3->gisprompt = GISPROMPT_COLOR;
  107. opt3->description = _("Color for drawing arrows");
  108. opt4 = G_define_option();
  109. opt4->key = "grid_color";
  110. opt4->type = TYPE_STRING;
  111. opt4->required = NO;
  112. opt4->answer = "gray";
  113. opt4->gisprompt = "old_color,color,color_none";
  114. opt4->description = _("Color for drawing grid or \"none\"");
  115. opt5 = G_define_option();
  116. opt5->key = "x_color";
  117. opt5->type = TYPE_STRING;
  118. opt5->required = NO;
  119. opt5->answer = DEFAULT_FG_COLOR;
  120. opt5->gisprompt = "old_color,color,color_none";
  121. opt5->description = _("Color for drawing X's (Null values)");
  122. opt6 = G_define_option();
  123. opt6->key = "unknown_color";
  124. opt6->type = TYPE_STRING;
  125. opt6->required = NO;
  126. opt6->answer = "red";
  127. opt6->gisprompt = "old_color,color,color_none";
  128. opt6->description = _("Color for showing unknown information");
  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. D_setup(0);
  188. /* Read in the map window associated with window */
  189. G_get_window(&window);
  190. if (align->answer) {
  191. struct Cell_head wind;
  192. if (Rast_get_cellhd(layer_name, "", &wind) < 0)
  193. G_fatal_error(_("Unable to read header of raster map <%s>"), layer_name);
  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_cell_old(layer_name, "");
  239. if (layer_fd < 0)
  240. G_fatal_error(_("Unable to open raster map <%s>"), layer_name);
  241. raster_type = Rast_get_raster_map_type(layer_fd);
  242. /* allocate the cell array */
  243. raster_row = Rast_allocate_raster_buf(raster_type);
  244. if (opt7->answer) {
  245. /* open the magnitude raster map */
  246. mag_fd = Rast_open_cell_old(mag_map, "");
  247. if (mag_fd < 0)
  248. G_fatal_error("Unable to open raster map <%s>", mag_map);
  249. mag_raster_type = Rast_get_raster_map_type(mag_fd);
  250. /* allocate the cell array */
  251. mag_raster_row = Rast_allocate_raster_buf(mag_raster_type);
  252. }
  253. /* loop through cells, find value, determine direction (n,s,e,w,ne,se,sw,nw),
  254. and call appropriate function to draw an arrow on the cell */
  255. for (row = 0; row < nrows; row++) {
  256. Rast_get_raster_row(layer_fd, raster_row, row, raster_type);
  257. ptr = raster_row;
  258. if (opt7->answer) {
  259. Rast_get_raster_row(mag_fd, mag_raster_row, row, mag_raster_type);
  260. mag_ptr = mag_raster_row;
  261. }
  262. for (col = 0; col < ncols; col++) {
  263. if (row % skip != 0)
  264. no_arrow = TRUE;
  265. else
  266. no_arrow = FALSE;
  267. if (col % skip != 0)
  268. no_arrow = TRUE;
  269. /* find aspect direction based on cell value */
  270. if (raster_type == CELL_TYPE)
  271. aspect_f = *((CELL *) ptr);
  272. else if (raster_type == FCELL_TYPE)
  273. aspect_f = *((FCELL *) ptr);
  274. else if (raster_type == DCELL_TYPE)
  275. aspect_f = *((DCELL *) ptr);
  276. if (opt7->answer) {
  277. if (mag_raster_type == CELL_TYPE)
  278. length = *((CELL *) mag_ptr);
  279. else if (mag_raster_type == FCELL_TYPE)
  280. length = *((FCELL *) mag_ptr);
  281. else if (mag_raster_type == DCELL_TYPE)
  282. length = *((DCELL *) mag_ptr);
  283. length *= scale;
  284. if (Rast_is_null_value(mag_ptr, mag_raster_type)) {
  285. G_debug(5, "Invalid arrow length [NULL]. Skipping.");
  286. no_arrow = TRUE;
  287. }
  288. else if (length <= 0.0) { /* use fabs() or theta+=180? */
  289. G_debug(5, "Illegal arrow length [%.3f]. Skipping.",
  290. length);
  291. no_arrow = TRUE;
  292. }
  293. }
  294. if (no_arrow) {
  295. ptr = Rast_incr_void_ptr(ptr, Rast_raster_size(raster_type));
  296. if (opt7->answer)
  297. mag_ptr =
  298. Rast_incr_void_ptr(mag_ptr,
  299. Rast_raster_size(mag_raster_type));
  300. no_arrow = FALSE;
  301. continue;
  302. }
  303. /* treat AGNPS and ANSWERS data like old zero-as-null CELL */
  304. /* TODO: update models */
  305. if (map_type == 2 || map_type == 3) {
  306. if (Rast_is_null_value(ptr, raster_type))
  307. aspect_c = 0;
  308. else
  309. aspect_c = (int)(aspect_f + 0.5);
  310. }
  311. /** Now draw the arrows **/
  312. /* case switch for standard GRASS aspect map
  313. measured in degrees counter-clockwise from east */
  314. if (map_type == 1) {
  315. D_use_color(arrow_color);
  316. if (Rast_is_null_value(ptr, raster_type)) {
  317. D_use_color(x_color);
  318. draw_x();
  319. D_use_color(arrow_color);
  320. }
  321. else if (aspect_f >= 0.0 && aspect_f <= 360.0) {
  322. if (opt7->answer)
  323. arrow_mag(aspect_f, length);
  324. else
  325. arrow_360(aspect_f);
  326. }
  327. else {
  328. D_use_color(unknown_color);
  329. unknown_();
  330. D_use_color(arrow_color);
  331. }
  332. }
  333. /* case switch for AGNPS type aspect map */
  334. else if (map_type == 2) {
  335. D_use_color(arrow_color);
  336. switch (aspect_c) {
  337. case 0:
  338. D_use_color(x_color);
  339. draw_x();
  340. D_use_color(arrow_color);
  341. break;
  342. case 1:
  343. arrow_n();
  344. break;
  345. case 2:
  346. arrow_ne();
  347. break;
  348. case 3:
  349. arrow_e();
  350. break;
  351. case 4:
  352. arrow_se();
  353. break;
  354. case 5:
  355. arrow_s();
  356. break;
  357. case 6:
  358. arrow_sw();
  359. break;
  360. case 7:
  361. arrow_w();
  362. break;
  363. case 8:
  364. arrow_nw();
  365. break;
  366. default:
  367. D_use_color(unknown_color);
  368. unknown_();
  369. D_use_color(arrow_color);
  370. break;
  371. }
  372. }
  373. /* case switch for ANSWERS type aspect map */
  374. else if (map_type == 3) {
  375. D_use_color(arrow_color);
  376. if (aspect_c >= 15 && aspect_c <= 360) /* start at zero? */
  377. arrow_360((double)aspect_c);
  378. else if (aspect_c == 400) {
  379. D_use_color(unknown_color);
  380. unknown_();
  381. D_use_color(arrow_color);
  382. }
  383. else {
  384. D_use_color(x_color);
  385. draw_x();
  386. D_use_color(arrow_color);
  387. }
  388. }
  389. /* case switch for compass type aspect map
  390. measured in degrees clockwise from north */
  391. else if (map_type == 4) {
  392. D_use_color(arrow_color);
  393. if (Rast_is_null_value(ptr, raster_type)) {
  394. D_use_color(x_color);
  395. draw_x();
  396. D_use_color(arrow_color);
  397. }
  398. else if (aspect_f >= 0.0 && aspect_f <= 360.0) {
  399. if (opt7->answer)
  400. arrow_mag(90 - aspect_f, length);
  401. else
  402. arrow_360(90 - aspect_f);
  403. }
  404. else {
  405. D_use_color(unknown_color);
  406. unknown_();
  407. D_use_color(arrow_color);
  408. }
  409. }
  410. ptr = Rast_incr_void_ptr(ptr, Rast_raster_size(raster_type));
  411. if (opt7->answer)
  412. mag_ptr =
  413. Rast_incr_void_ptr(mag_ptr, Rast_raster_size(mag_raster_type));
  414. }
  415. }
  416. Rast_close_cell(layer_fd);
  417. if (opt7->answer)
  418. Rast_close_cell(mag_fd);
  419. D_close_driver();
  420. exit(0);
  421. }
  422. /* --- end of main --- */
  423. /*---------------------------------------------------------------*/
  424. static void arrow_mag(double theta, double length)
  425. { /* angle is measured in degrees counter-clockwise from east */
  426. double x, y, dx, dy, mid_x, mid_y;
  427. double theta_offset;
  428. theta *= -1; /* display coords use inverse y */
  429. /* find the display coordinates of the middle of the cell */
  430. mid_x = col + (.5);
  431. mid_y = row + (.5);
  432. D_begin();
  433. /* tail */
  434. D_move_abs(mid_x, mid_y);
  435. /* head */
  436. x = mid_x + (length * cos(D2R(theta)));
  437. y = mid_y + (length * sin(D2R(theta)));
  438. D_cont_abs(x, y);
  439. /* fin 1 */
  440. theta_offset = theta + 20;
  441. dx = mid_x + (0.6 * length * cos(D2R(theta_offset)));
  442. dy = mid_y + (0.6 * length * sin(D2R(theta_offset)));
  443. D_cont_abs(dx, dy);
  444. /* fin 2 */
  445. D_move_abs(x, y);
  446. theta_offset = theta - 20;
  447. dx = mid_x + (0.6 * length * cos(D2R(theta_offset)));
  448. dy = mid_y + (0.6 * length * sin(D2R(theta_offset)));
  449. D_cont_abs(dx, dy);
  450. D_end();
  451. D_stroke();
  452. }
  453. static void arrow_360(double theta)
  454. { /* angle is measured in degrees counter-clockwise from east */
  455. double x, y, dx, dy, mid_x, mid_y;
  456. double max_radius, theta_offset;
  457. theta *= -1; /* display coords use inverse y */
  458. max_radius = 0.8 / 2;
  459. /* find the display coordinates of the middle of the cell */
  460. mid_x = col + (0.5);
  461. mid_y = row + (0.5);
  462. D_begin();
  463. /* head */
  464. x = mid_x + (max_radius * cos(D2R(theta)));
  465. y = mid_y + (max_radius * sin(D2R(theta)));
  466. D_move_abs(x, y);
  467. /* tail */
  468. dx = -2 * (max_radius * cos(D2R(theta)));
  469. dy = -2 * (max_radius * sin(D2R(theta)));
  470. D_cont_rel(dx, dy);
  471. /* fin 1 */
  472. D_move_abs(x, y);
  473. theta_offset = theta + 90;
  474. dx = mid_x + (0.5 * max_radius * cos(D2R(theta_offset)));
  475. dy = mid_y + (0.5 * max_radius * sin(D2R(theta_offset)));
  476. D_cont_abs(dx, dy);
  477. /* fin 2 */
  478. D_move_abs(x, y);
  479. theta_offset = theta - 90;
  480. dx = mid_x + (0.5 * max_radius * cos(D2R(theta_offset)));
  481. dy = mid_y + (0.5 * max_radius * sin(D2R(theta_offset)));
  482. D_cont_abs(dx, dy);
  483. D_end();
  484. D_stroke();
  485. }
  486. static void arrow_se(void)
  487. {
  488. double x = col + (.8);
  489. double y = row + (.8);
  490. D_begin();
  491. D_move_abs(x, y);
  492. D_cont_rel(((-.6)), (((-.6))));
  493. D_move_abs(x, y);
  494. D_cont_rel(0, ((-.4)));
  495. D_move_abs(x, y);
  496. D_cont_rel(((-.4)), 0);
  497. D_end();
  498. D_stroke();
  499. }
  500. static void arrow_ne(void)
  501. {
  502. double x = col + (.8);
  503. double y = row + (.2);
  504. D_begin();
  505. D_move_abs(x, y);
  506. D_cont_rel(((-.6)), (((.6))));
  507. D_move_abs(x, y);
  508. D_cont_rel(0, ((.4)));
  509. D_move_abs(x, y);
  510. D_cont_rel(((-.4)), 0);
  511. D_end();
  512. D_stroke();
  513. }
  514. static void arrow_nw(void)
  515. {
  516. double x = col + (.2);
  517. double y = row + (.2);
  518. D_begin();
  519. D_move_abs(x, y);
  520. D_cont_rel(((.6)), (((.6))));
  521. D_move_abs(x, y);
  522. D_cont_rel(0, ((.4)));
  523. D_move_abs(x, y);
  524. D_cont_rel(((.4)), 0);
  525. D_end();
  526. D_stroke();
  527. }
  528. static void arrow_sw(void)
  529. {
  530. double x = col + (.2);
  531. double y = row + (.8);
  532. D_begin();
  533. D_move_abs(x, y);
  534. D_cont_rel(((.6)), (((-.6))));
  535. D_move_abs(x, y);
  536. D_cont_rel(0, ((-.4)));
  537. D_move_abs(x, y);
  538. D_cont_rel(((.4)), 0);
  539. D_end();
  540. D_stroke();
  541. }
  542. static void arrow_e(void)
  543. {
  544. double x = col + (.9);
  545. double y = row + (.5);
  546. D_begin();
  547. D_move_abs(x, y);
  548. D_cont_rel(((-.8)), 0);
  549. D_move_abs(x, y);
  550. D_cont_rel(((-.3)), ((-.3)));
  551. D_move_abs(x, y);
  552. D_cont_rel(((-.3)), ((.3)));
  553. D_end();
  554. D_stroke();
  555. }
  556. static void arrow_w(void)
  557. {
  558. double x = col + (.1);
  559. double y = row + (.5);
  560. D_begin();
  561. D_move_abs(x, y);
  562. D_cont_rel(((.8)), 0);
  563. D_move_abs(x, y);
  564. D_cont_rel(((.3)), ((-.3)));
  565. D_move_abs(x, y);
  566. D_cont_rel(((.3)), ((.3)));
  567. D_end();
  568. D_stroke();
  569. }
  570. static void arrow_s(void)
  571. {
  572. double x = col + (.5);
  573. double y = row + (.9);
  574. D_begin();
  575. D_move_abs(x, y);
  576. D_cont_rel(0, ((-.8)));
  577. D_move_abs(x, y);
  578. D_cont_rel(((.3)), ((-.3)));
  579. D_move_abs(x, y);
  580. D_cont_rel(((-.3)), ((-.3)));
  581. D_end();
  582. D_stroke();
  583. }
  584. static void arrow_n(void)
  585. {
  586. double x = col + (.5);
  587. double y = row + (.1);
  588. D_begin();
  589. D_move_abs(x, y);
  590. D_cont_rel(0, ((.8)));
  591. D_move_abs(x, y);
  592. D_cont_rel(((.3)), ((.3)));
  593. D_move_abs(x, y);
  594. D_cont_rel(((-.3)), ((.3)));
  595. D_end();
  596. D_stroke();
  597. }
  598. static void draw_x(void)
  599. {
  600. double x = col;
  601. double y = row;
  602. D_begin();
  603. D_move_abs(x, y);
  604. D_cont_rel(1, 1);
  605. y = row + 1;
  606. D_move_abs(x, y);
  607. D_cont_rel(1, (-1));
  608. D_end();
  609. D_stroke();
  610. }
  611. static void unknown_(void)
  612. {
  613. double x = col + (.3);
  614. double y = row + (.4);
  615. D_begin();
  616. D_move_abs(x, y);
  617. D_cont_rel(0, ((-.15)));
  618. D_cont_rel(((.1)), ((-.1)));
  619. D_cont_rel(((.2)), 0);
  620. D_cont_rel(((.1)), ((.1)));
  621. D_cont_rel(0, ((.2)));
  622. D_cont_rel(((-.1)), ((.1)));
  623. D_cont_rel(((-.1)), 0);
  624. D_cont_rel(0, ((.25)));
  625. D_move_rel(0, ((.1)));
  626. D_cont_rel(0, ((.1)));
  627. D_end();
  628. D_stroke();
  629. }