main.c 20 KB

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