123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818 |
- /*
- ****************************************************************************
- *
- * MODULE: d.rast.arrow
- * AUTHOR(S): Chris Rewerts, Agricultural Engineering, Purdue University
- * PURPOSE: Draw arrows on slope/aspect maps.
- * COPYRIGHT: (C) 2000, 2010 by the GRASS Development Team
- *
- * This program is free software under the GNU General Public
- * License (>=v2). Read the file COPYING that comes with GRASS
- * for details.
- *
- *****************************************************************************/
- /* some minor cleanup done by Andreas Lange, andreas.lange@rhein-main.de
- * Update to handle NULLs and floating point aspect maps: Hamish Bowman, Aug 2004
- * Update for 360 degree arrows and magnitude scaling: Hamish Bowman, Oct 2005
- * Align grids with raster cells: Huidae Cho, Apr 2009
- * Drainage aspect type: Huidae Cho, Sep 2015
- */
- /*
- * Chris Rewerts, Agricultural Engineering, Purdue University
- * rewerts@ecn.purdue.edu March 1991
- *
- * d.rast.arrow
- *
- * Usage: d.rast.arrow
- *
- * This program used Dgrid's sources as a beginning. Purpose of Darrow
- * is to read an aspect layer produced by slope.aspect or by the
- * programs created for the ANSWERS or AGNPS Hydrology Toolbox
- * endeavors. d.rast.arrow draws an arrow on the graphic display
- * of each cell, so that the flow pattern computed as an aspect
- * layer can be easily seen. Other symbols ("?", "X") may be drawn
- * as needed.
- */
- #include <stdlib.h>
- #include <string.h>
- #include <math.h>
- #include <grass/gis.h>
- #include <grass/raster.h>
- #include <grass/display.h>
- #include <grass/colors.h>
- #include <grass/glocale.h>
- # define RpD ((2 * M_PI) / 360.) /* radians/degree */
- # define D2R(d) (double)(d * RpD) /* degrees->radians */
- static void arrow_mag(double, double);
- static void arrow_360(double);
- static void arrow_se(void);
- static void arrow_ne(void);
- static void arrow_nw(void);
- static void arrow_sw(void);
- static void arrow_e(void);
- static void arrow_w(void);
- static void arrow_s(void);
- static void arrow_n(void);
- static void draw_x(void);
- static void unknown_(void);
- static char *layer_name;
- static int map_type, arrow_color, grid_color, x_color, unknown_color;
- static int row, col;
- int main(int argc, char **argv)
- {
- struct Cell_head window;
- RASTER_MAP_TYPE raster_type, mag_raster_type = -1;
- int layer_fd;
- void *raster_row, *ptr;
- int nrows, ncols;
- int aspect_c = -1;
- float aspect_f = -1.0;
- double scale;
- int skip, no_arrow;
- char *mag_map = NULL;
- void *mag_raster_row = NULL, *mag_ptr = NULL;
- double length = -1;
- int mag_fd = -1;
- struct FPRange range;
- double mag_min, mag_max;
- struct GModule *module;
- struct Option *opt1, *opt2, *opt3, *opt4, *opt5,
- *opt6, *opt7, *opt8, *opt9;
- struct Flag *align;
- double t, b, l, r;
- G_gisinit(argv[0]);
- module = G_define_module();
- G_add_keyword(_("display"));
- G_add_keyword(_("map annotations"));
- G_add_keyword(_("raster"));
- module->description =
- _("Draws arrows representing cell aspect direction "
- "for a raster map containing aspect data.");
- opt1 = G_define_standard_option(G_OPT_R_MAP);
- opt1->description = _("Name of raster aspect map to be displayed");
- opt2 = G_define_option();
- opt2->key = "type";
- opt2->type = TYPE_STRING;
- opt2->required = NO;
- opt2->answer = "grass";
- opt2->options = "grass,compass,drainage,agnps,answers";
- opt2->description = _("Type of existing raster aspect map");
- opt3 = G_define_standard_option(G_OPT_C);
- opt3->key = "color";
- opt3->answer = "green";
- opt3->label = _("Color for drawing arrows");
- opt3->guisection = _("Colors");
-
- opt4 = G_define_standard_option(G_OPT_CN);
- opt4->key = "grid_color";
- opt4->answer = "gray";
- opt4->label = _("Color for drawing drawing grid");
- opt4->guisection = _("Colors");
- opt5 = G_define_standard_option(G_OPT_CN);
- opt5->key = "null_color";
- opt5->answer = DEFAULT_FG_COLOR;
- opt5->label = _("Color for drawing null values (X symbol)");
- opt5->guisection = _("Colors");
- opt6 = G_define_standard_option(G_OPT_CN);
- opt6->key = "unknown_color";
- opt6->answer = "red";
- opt6->label = _("Color for showing unknown information (? symbol)");
- opt6->guisection = _("Colors");
- opt9 = G_define_option();
- opt9->key = "skip";
- opt9->type = TYPE_INTEGER;
- opt9->required = NO;
- opt9->answer = "1";
- opt9->description = _("Draw arrow every Nth grid cell");
- opt7 = G_define_option();
- opt7->key = "magnitude_map";
- opt7->type = TYPE_STRING;
- opt7->required = NO;
- opt7->multiple = NO;
- opt7->gisprompt = "old,cell,raster";
- opt7->description =
- _("Raster map containing values used for arrow length");
- opt8 = G_define_option();
- opt8->key = "scale";
- opt8->type = TYPE_DOUBLE;
- opt8->required = NO;
- opt8->answer = "1.0";
- opt8->description = _("Scale factor for arrows (magnitude map)");
- align = G_define_flag();
- align->key = 'a';
- align->description = _("Align grids with raster cells");
- /* Check command line */
- if (G_parser(argc, argv))
- exit(EXIT_FAILURE);
- layer_name = opt1->answer;
- arrow_color = D_translate_color(opt3->answer);
- /* Convert none (transparent) to -1 which in this module means
- that we will not draw things having this color (-1).
- We don't do that for arrow because we always want them.
- (This is specified by the gisprompt ('type') of the options.)
- */
- if (strcmp("none", opt4->answer) == 0)
- grid_color = -1;
- else
- grid_color = D_translate_color(opt4->answer);
- if (strcmp("none", opt5->answer) == 0)
- x_color = -1;
- else
- x_color = D_translate_color(opt5->answer);
- if (strcmp("none", opt6->answer) == 0)
- unknown_color = -1;
- else
- unknown_color = D_translate_color(opt6->answer);
- if (strcmp("grass", opt2->answer) == 0)
- map_type = 1;
- else if (strcmp("agnps", opt2->answer) == 0)
- map_type = 2;
- else if (strcmp("answers", opt2->answer) == 0)
- map_type = 3;
- else if (strcmp("compass", opt2->answer) == 0)
- map_type = 4;
- else if (strcmp("drainage", opt2->answer) == 0)
- map_type = 5;
- scale = atof(opt8->answer);
- if (scale <= 0.0)
- G_fatal_error(_("Illegal value for scale factor"));
- skip = atoi(opt9->answer);
- if (skip <= 0)
- G_fatal_error(_("Illegal value for skip factor"));
- if (opt7->answer) {
- if (map_type != 1 && map_type != 4)
- G_fatal_error(_("Magnitude is only supported for GRASS and compass aspect maps."));
- mag_map = opt7->answer;
- }
- else if (scale != 1.0)
- G_warning(_("Scale option requires magnitude_map"));
- /* Setup driver and check important information */
- D_open_driver();
-
- D_setup(0);
- /* Read in the map window associated with window */
- G_get_window(&window);
- if (align->answer) {
- struct Cell_head wind;
- Rast_get_cellhd(layer_name, "", &wind);
- /* expand window extent by one wind resolution */
- wind.west += wind.ew_res * ((int)((window.west - wind.west) / wind.ew_res) - (window.west < wind.west));
- wind.east += wind.ew_res * ((int)((window.east - wind.east) / wind.ew_res) + (window.east > wind.east));
- wind.south += wind.ns_res * ((int)((window.south - wind.south) / wind.ns_res) - (window.south < wind.south));
- wind.north += wind.ns_res * ((int)((window.north - wind.north) / wind.ns_res) + (window.north > wind.north));
- wind.rows = (wind.north - wind.south) / wind.ns_res;
- wind.cols = (wind.east - wind.west) / wind.ew_res;
- Rast_set_window(&wind);
- nrows = wind.rows;
- ncols = wind.cols;
- t = (wind.north - window.north) * nrows / (wind.north - wind.south);
- b = t + (window.north - window.south) * nrows / (wind.north - wind.south);
- l = (window.west - wind.west) * ncols / (wind.east - wind.west);
- r = l + (window.east - window.west) * ncols / (wind.east - wind.west);
- } else {
- nrows = window.rows;
- ncols = window.cols;
- t = 0;
- b = nrows;
- l = 0;
- r = ncols;
- }
- D_set_src(t, b, l, r);
- D_update_conversions();
- /* figure out arrow scaling if using a magnitude map */
- if (opt7->answer) {
- Rast_init_fp_range(&range); /* really needed? */
- if (Rast_read_fp_range(mag_map, "", &range) != 1)
- G_fatal_error(_("Problem reading range file"));
- Rast_get_fp_range_min_max(&range, &mag_min, &mag_max);
- scale *= 1.5 / fabs(mag_max);
- G_debug(3, "scaling=%.2f rast_max=%.2f", scale, mag_max);
- }
- if (grid_color > 0) { /* ie not "none" */
- /* Set color */
- D_use_color(grid_color);
- /* Draw vertical grids */
- for (col = 0; col < ncols; col++)
- D_line_abs(col, 0, col, nrows);
- /* Draw horizontal grids */
- for (row = 0; row < nrows; row++)
- D_line_abs(0, row, ncols, row);
- }
- /* open the raster map */
- layer_fd = Rast_open_old(layer_name, "");
- raster_type = Rast_get_map_type(layer_fd);
- /* allocate the cell array */
- raster_row = Rast_allocate_buf(raster_type);
- if (opt7->answer) {
- /* open the magnitude raster map */
- mag_fd = Rast_open_old(mag_map, "");
- mag_raster_type = Rast_get_map_type(mag_fd);
- /* allocate the cell array */
- mag_raster_row = Rast_allocate_buf(mag_raster_type);
- }
- /* loop through cells, find value, determine direction (n,s,e,w,ne,se,sw,nw),
- and call appropriate function to draw an arrow on the cell */
- for (row = 0; row < nrows; row++) {
- Rast_get_row(layer_fd, raster_row, row, raster_type);
- ptr = raster_row;
- if (opt7->answer) {
- Rast_get_row(mag_fd, mag_raster_row, row, mag_raster_type);
- mag_ptr = mag_raster_row;
- }
- for (col = 0; col < ncols; col++) {
- if (row % skip != 0)
- no_arrow = TRUE;
- else
- no_arrow = FALSE;
- if (col % skip != 0)
- no_arrow = TRUE;
- /* find aspect direction based on cell value */
- if (raster_type == CELL_TYPE)
- aspect_f = *((CELL *) ptr);
- else if (raster_type == FCELL_TYPE)
- aspect_f = *((FCELL *) ptr);
- else if (raster_type == DCELL_TYPE)
- aspect_f = *((DCELL *) ptr);
- if (opt7->answer) {
- if (mag_raster_type == CELL_TYPE)
- length = *((CELL *) mag_ptr);
- else if (mag_raster_type == FCELL_TYPE)
- length = *((FCELL *) mag_ptr);
- else if (mag_raster_type == DCELL_TYPE)
- length = *((DCELL *) mag_ptr);
- length *= scale;
- if (Rast_is_null_value(mag_ptr, mag_raster_type)) {
- G_debug(5, "Invalid arrow length [NULL]. Skipping.");
- no_arrow = TRUE;
- }
- else if (length <= 0.0) { /* use fabs() or theta+=180? */
- G_debug(5, "Illegal arrow length [%.3f]. Skipping.",
- length);
- no_arrow = TRUE;
- }
- }
- if (no_arrow) {
- ptr = G_incr_void_ptr(ptr, Rast_cell_size(raster_type));
- if (opt7->answer)
- mag_ptr =
- G_incr_void_ptr(mag_ptr,
- Rast_cell_size(mag_raster_type));
- no_arrow = FALSE;
- continue;
- }
- /* treat AGNPS and ANSWERS data like old zero-as-null CELL */
- /* TODO: update models */
- if (map_type == 2 || map_type == 3 || map_type == 5) {
- if (Rast_is_null_value(ptr, raster_type))
- aspect_c = 0;
- else
- aspect_c = (int)(aspect_f + 0.5);
- }
- /** Now draw the arrows **/
- /* case switch for standard GRASS aspect map
- measured in degrees counter-clockwise from east */
- if (map_type == 1) {
- D_use_color(arrow_color);
- if (Rast_is_null_value(ptr, raster_type)) {
- /* don't draw anything if x_color is none (transparent) */
- if (x_color > 0) {
- D_use_color(x_color);
- draw_x();
- D_use_color(arrow_color);
- }
- }
- else if (aspect_f >= 0.0 && aspect_f <= 360.0) {
- if (opt7->answer)
- arrow_mag(aspect_f, length);
- else
- arrow_360(aspect_f);
- }
- else if (unknown_color > 0) {
- /* don't draw if unknown_color is none (transparent) */
- D_use_color(unknown_color);
- unknown_();
- D_use_color(arrow_color);
- }
- }
- /* case switch for AGNPS type aspect map */
- else if (map_type == 2) {
- D_use_color(arrow_color);
- switch (aspect_c) {
- case 0:
- /* only draw if x_color is not none (transparent) */
- if (x_color > 0) {
- D_use_color(x_color);
- draw_x();
- D_use_color(arrow_color);
- }
- break;
- case 1:
- arrow_n();
- break;
- case 2:
- arrow_ne();
- break;
- case 3:
- arrow_e();
- break;
- case 4:
- arrow_se();
- break;
- case 5:
- arrow_s();
- break;
- case 6:
- arrow_sw();
- break;
- case 7:
- arrow_w();
- break;
- case 8:
- arrow_nw();
- break;
- default:
- /* only draw if unknown_color is not none */
- if (unknown_color > 0) {
- D_use_color(unknown_color);
- unknown_();
- D_use_color(arrow_color);
- }
- break;
- }
- }
- /* case switch for ANSWERS type aspect map */
- else if (map_type == 3) {
- D_use_color(arrow_color);
- if (aspect_c >= 15 && aspect_c <= 360) /* start at zero? */
- arrow_360((double)aspect_c);
- else if (aspect_c == 400) {
- if (unknown_color > 0) {
- /* only draw if unknown_color is not none */
- D_use_color(unknown_color);
- unknown_();
- D_use_color(arrow_color);
- }
- }
- else if (x_color > 0) {
- /* only draw if x_color is not none (transparent) */
- D_use_color(x_color);
- draw_x();
- D_use_color(arrow_color);
- }
- }
- /* case switch for compass type aspect map
- measured in degrees clockwise from north */
- else if (map_type == 4) {
- D_use_color(arrow_color);
- if (Rast_is_null_value(ptr, raster_type)) {
- if (x_color > 0) {
- /* only draw if x_color is not none */
- D_use_color(x_color);
- draw_x();
- D_use_color(arrow_color);
- }
- }
- else if (aspect_f >= 0.0 && aspect_f <= 360.0) {
- if (opt7->answer)
- arrow_mag(90 - aspect_f, length);
- else
- arrow_360(90 - aspect_f);
- }
- else if (unknown_color > 0) {
- /* only draw if unknown_color is not none */
- D_use_color(unknown_color);
- unknown_();
- D_use_color(arrow_color);
- }
- }
- /* case switch for r.watershed drainage type aspect map */
- else if (map_type == 5) {
- D_use_color(arrow_color);
- switch (aspect_c >= 0 ? aspect_c : -aspect_c) {
- case 0:
- /* only draw if x_color is not none (transparent) */
- if (x_color > 0) {
- D_use_color(x_color);
- draw_x();
- D_use_color(arrow_color);
- }
- break;
- case 1:
- arrow_ne();
- break;
- case 2:
- arrow_n();
- break;
- case 3:
- arrow_nw();
- break;
- case 4:
- arrow_w();
- break;
- case 5:
- arrow_sw();
- break;
- case 6:
- arrow_s();
- break;
- case 7:
- arrow_se();
- break;
- case 8:
- arrow_e();
- break;
- default:
- /* only draw if unknown_color is not none */
- if (unknown_color > 0) {
- D_use_color(unknown_color);
- unknown_();
- D_use_color(arrow_color);
- }
- break;
- }
- }
- ptr = G_incr_void_ptr(ptr, Rast_cell_size(raster_type));
- if (opt7->answer)
- mag_ptr =
- G_incr_void_ptr(mag_ptr, Rast_cell_size(mag_raster_type));
- }
- }
- Rast_close(layer_fd);
- if (opt7->answer)
- Rast_close(mag_fd);
- D_save_command(G_recreate_command());
- D_close_driver();
- exit(EXIT_SUCCESS);
- }
- /* --- end of main --- */
- /*---------------------------------------------------------------*/
- static void arrow_mag(double theta, double length)
- { /* angle is measured in degrees counter-clockwise from east */
- double x, y, dx, dy, mid_x, mid_y;
- double theta_offset;
- theta *= -1; /* display coords use inverse y */
- /* find the display coordinates of the middle of the cell */
- mid_x = col + (.5);
- mid_y = row + (.5);
- D_begin();
- /* tail */
- D_move_abs(mid_x, mid_y);
- /* head */
- x = mid_x + (length * cos(D2R(theta)));
- y = mid_y + (length * sin(D2R(theta)));
- D_cont_abs(x, y);
- /* fin 1 */
- theta_offset = theta + 20;
- dx = mid_x + (0.6 * length * cos(D2R(theta_offset)));
- dy = mid_y + (0.6 * length * sin(D2R(theta_offset)));
- D_cont_abs(dx, dy);
- /* fin 2 */
- D_move_abs(x, y);
- theta_offset = theta - 20;
- dx = mid_x + (0.6 * length * cos(D2R(theta_offset)));
- dy = mid_y + (0.6 * length * sin(D2R(theta_offset)));
- D_cont_abs(dx, dy);
- D_end();
- D_stroke();
- }
- static void arrow_360(double theta)
- { /* angle is measured in degrees counter-clockwise from east */
- double x, y, dx, dy, mid_x, mid_y;
- double max_radius, theta_offset;
- theta *= -1; /* display coords use inverse y */
- max_radius = 0.8 / 2;
- /* find the display coordinates of the middle of the cell */
- mid_x = col + (0.5);
- mid_y = row + (0.5);
- D_begin();
- /* head */
- x = mid_x + (max_radius * cos(D2R(theta)));
- y = mid_y + (max_radius * sin(D2R(theta)));
- D_move_abs(x, y);
- /* tail */
- dx = -2 * (max_radius * cos(D2R(theta)));
- dy = -2 * (max_radius * sin(D2R(theta)));
- D_cont_rel(dx, dy);
- /* fin 1 */
- D_move_abs(x, y);
- theta_offset = theta + 90;
- dx = mid_x + (0.5 * max_radius * cos(D2R(theta_offset)));
- dy = mid_y + (0.5 * max_radius * sin(D2R(theta_offset)));
- D_cont_abs(dx, dy);
- /* fin 2 */
- D_move_abs(x, y);
- theta_offset = theta - 90;
- dx = mid_x + (0.5 * max_radius * cos(D2R(theta_offset)));
- dy = mid_y + (0.5 * max_radius * sin(D2R(theta_offset)));
- D_cont_abs(dx, dy);
- D_end();
- D_stroke();
- }
- static void arrow_se(void)
- {
- double x = col + (.8);
- double y = row + (.8);
- D_begin();
- D_move_abs(x, y);
- D_cont_rel(((-.6)), (((-.6))));
- D_move_abs(x, y);
- D_cont_rel(0, ((-.4)));
- D_move_abs(x, y);
- D_cont_rel(((-.4)), 0);
- D_end();
- D_stroke();
- }
- static void arrow_ne(void)
- {
- double x = col + (.8);
- double y = row + (.2);
- D_begin();
- D_move_abs(x, y);
- D_cont_rel(((-.6)), (((.6))));
- D_move_abs(x, y);
- D_cont_rel(0, ((.4)));
- D_move_abs(x, y);
- D_cont_rel(((-.4)), 0);
- D_end();
- D_stroke();
- }
- static void arrow_nw(void)
- {
- double x = col + (.2);
- double y = row + (.2);
- D_begin();
- D_move_abs(x, y);
- D_cont_rel(((.6)), (((.6))));
- D_move_abs(x, y);
- D_cont_rel(0, ((.4)));
- D_move_abs(x, y);
- D_cont_rel(((.4)), 0);
- D_end();
- D_stroke();
- }
- static void arrow_sw(void)
- {
- double x = col + (.2);
- double y = row + (.8);
- D_begin();
- D_move_abs(x, y);
- D_cont_rel(((.6)), (((-.6))));
- D_move_abs(x, y);
- D_cont_rel(0, ((-.4)));
- D_move_abs(x, y);
- D_cont_rel(((.4)), 0);
- D_end();
- D_stroke();
- }
- static void arrow_e(void)
- {
- double x = col + (.9);
- double y = row + (.5);
- D_begin();
- D_move_abs(x, y);
- D_cont_rel(((-.8)), 0);
- D_move_abs(x, y);
- D_cont_rel(((-.3)), ((-.3)));
- D_move_abs(x, y);
- D_cont_rel(((-.3)), ((.3)));
- D_end();
- D_stroke();
- }
- static void arrow_w(void)
- {
- double x = col + (.1);
- double y = row + (.5);
- D_begin();
- D_move_abs(x, y);
- D_cont_rel(((.8)), 0);
- D_move_abs(x, y);
- D_cont_rel(((.3)), ((-.3)));
- D_move_abs(x, y);
- D_cont_rel(((.3)), ((.3)));
- D_end();
- D_stroke();
- }
- static void arrow_s(void)
- {
- double x = col + (.5);
- double y = row + (.9);
- D_begin();
- D_move_abs(x, y);
- D_cont_rel(0, ((-.8)));
- D_move_abs(x, y);
- D_cont_rel(((.3)), ((-.3)));
- D_move_abs(x, y);
- D_cont_rel(((-.3)), ((-.3)));
- D_end();
- D_stroke();
- }
- static void arrow_n(void)
- {
- double x = col + (.5);
- double y = row + (.1);
- D_begin();
- D_move_abs(x, y);
- D_cont_rel(0, ((.8)));
- D_move_abs(x, y);
- D_cont_rel(((.3)), ((.3)));
- D_move_abs(x, y);
- D_cont_rel(((-.3)), ((.3)));
- D_end();
- D_stroke();
- }
- static void draw_x(void)
- {
- double x = col;
- double y = row;
- D_begin();
- D_move_abs(x, y);
- D_cont_rel(1, 1);
- y = row + 1;
- D_move_abs(x, y);
- D_cont_rel(1, (-1));
- D_end();
- D_stroke();
- }
- static void unknown_(void)
- {
- double x = col + (.3);
- double y = row + (.4);
- D_begin();
- D_move_abs(x, y);
- D_cont_rel(0, ((-.15)));
- D_cont_rel(((.1)), ((-.1)));
- D_cont_rel(((.2)), 0);
- D_cont_rel(((.1)), ((.1)));
- D_cont_rel(0, ((.2)));
- D_cont_rel(((-.1)), ((.1)));
- D_cont_rel(((-.1)), 0);
- D_cont_rel(0, ((.25)));
- D_move_rel(0, ((.1)));
- D_cont_rel(0, ((.1)));
- D_end();
- D_stroke();
- }
|