2
****************************************************************************
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
9
* This program is free software under the GNU General Public
10
* License (>=v2). Read the file COPYING that comes with GRASS
13
*****************************************************************************/
15
/* some minor cleanup done by Andreas Lange, andreas.lange@rhein-main.de
16
* Update to handle NULLs and floating point aspect maps: Hamish Bowman, Aug 2004
17
* Update for 360 degree arrows and magnitude scaling: Hamish Bowman, Oct 2005
21
* Chris Rewerts, Agricultural Engineering, Purdue University
22
* rewerts@ecn.purdue.edu March 1991
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
40
#include <grass/gis.h>
41
#include <grass/raster.h>
42
#include <grass/display.h>
43
#include <grass/colors.h>
44
#include <grass/glocale.h>
46
# define RpD ((2 * M_PI) / 360.) /* radians/degree */
47
# define D2R(d) (double)(d * RpD) /* degrees->radians */
50
static void arrow_mag(double, double);
51
static void arrow_360(double);
52
static void arrow_se(void);
53
static void arrow_ne(void);
54
static void arrow_nw(void);
55
static void arrow_sw(void);
56
static void arrow_e(void);
57
static void arrow_w(void);
58
static void arrow_s(void);
59
static void arrow_n(void);
60
static void draw_x(void);
61
static void unknown_(void);
68
int map_type, arrow_color, grid_color, x_color, unknown_color;
71
int main(int argc, char **argv)
73
extern double D_ew, D_ns;
75
char window_name[128];
76
struct Cell_head window;
79
RASTER_MAP_TYPE raster_type, mag_raster_type = -1;
81
void *raster_row, *ptr;
82
int nrows, ncols, row, col;
84
float aspect_f = -1.0;
85
double ew_res, ns_res;
86
double D_south, D_west;
87
double D_north, D_east;
88
double U_to_D_xconv, U_to_D_yconv;
89
double U_west, U_south;
90
double U_east, U_north;
96
char *mag_map = NULL, *mag_mapset = NULL;
97
void *mag_raster_row = NULL, *mag_ptr = NULL;
100
struct FPRange range;
101
double mag_min, mag_max;
103
struct GModule *module;
104
struct Option *opt1, *opt2, *opt3, *opt4, *opt5,
105
*opt6, *opt7, *opt8, *opt9;
109
module = G_define_module();
110
module->keywords = _("display");
111
module->description =
112
_("Draws arrows representing cell aspect direction "
113
"for a raster map containing aspect data.");
115
opt1 = G_define_option();
117
opt1->type = TYPE_STRING;
120
opt1->gisprompt = "old,cell,raster";
121
opt1->description = _("Name of raster aspect map to be displayed");
123
opt2 = G_define_option();
125
opt2->type = TYPE_STRING;
127
opt2->answer = "grass";
128
opt2->options = "grass,compass,agnps,answers";
129
opt2->description = _("Type of existing raster aspect map");
131
opt3 = G_define_option();
132
opt3->key = "arrow_color";
133
opt3->type = TYPE_STRING;
135
opt3->answer = "green";
136
opt3->options = D_COLOR_LIST;
137
opt3->description = _("Color for drawing arrows");
139
opt4 = G_define_option();
140
opt4->key = "grid_color";
141
opt4->type = TYPE_STRING;
143
opt4->answer = "gray";
144
opt4->options = D_COLOR_LIST ",none";
145
opt4->description = _("Color for drawing grid or \"none\"");
147
opt5 = G_define_option();
148
opt5->key = "x_color";
149
opt5->type = TYPE_STRING;
151
opt5->answer = DEFAULT_FG_COLOR;
152
opt5->options = D_COLOR_LIST;
153
opt5->description = _("Color for drawing X's (Null values)");
155
opt6 = G_define_option();
156
opt6->key = "unknown_color";
157
opt6->type = TYPE_STRING;
159
opt6->answer = "red";
160
opt6->options = D_COLOR_LIST;
161
opt6->description = _("Color for showing unknown information");
163
opt9 = G_define_option();
165
opt9->type = TYPE_INTEGER;
168
opt9->description = _("Draw arrow every Nth grid cell");
170
opt7 = G_define_option();
171
opt7->key = "magnitude_map";
172
opt7->type = TYPE_STRING;
175
opt7->gisprompt = "old,cell,raster";
177
_("Raster map containing values used for arrow length");
179
opt8 = G_define_option();
181
opt8->type = TYPE_DOUBLE;
183
opt8->answer = "1.0";
184
opt8->description = _("Scale factor for arrows (magnitude map)");
187
/* Check command line */
188
if (G_parser(argc, argv))
193
G_strncpy(layer_name, opt1->answer, sizeof(layer_name) - 1);
194
if ((mapset = G_find_cell2(layer_name, "")) == NULL)
195
G_fatal_error(_("Raster map <%s> not found"), layer_name);
202
arrow_color = D_translate_color(opt3->answer);
203
x_color = D_translate_color(opt5->answer);
204
unknown_color = D_translate_color(opt6->answer);
206
if (strcmp("none", opt4->answer) == 0)
209
grid_color = D_translate_color(opt4->answer);
212
if (strcmp("grass", opt2->answer) == 0)
214
else if (strcmp("agnps", opt2->answer) == 0)
216
else if (strcmp("answers", opt2->answer) == 0)
218
else if (strcmp("compass", opt2->answer) == 0)
222
scale = atof(opt8->answer);
224
G_fatal_error(_("Illegal value for scale factor"));
226
skip = atoi(opt9->answer);
228
G_fatal_error(_("Illegal value for skip factor"));
232
if (map_type != 1 && map_type != 4)
233
G_fatal_error(_("Magnitude is only supported for GRASS and compass aspect maps."));
235
mag_map = opt7->answer;
236
if ((mag_mapset = G_find_cell2(mag_map, "")) == NULL)
237
G_fatal_error(_("Raster map <%s> not found"), mag_map);
239
else if (scale != 1.0)
240
G_warning(_("Scale option requires magnitude_map"));
243
/* Setup driver and check important information */
244
if (R_open_driver() != 0)
245
G_fatal_error(_("No graphics device selected"));
247
if (D_get_cur_wind(window_name))
248
G_fatal_error(_("No current window"));
250
if (D_set_cur_wind(window_name))
251
G_fatal_error(_("Current window not available"));
253
/* Read in the map window associated with window */
254
G_get_window(&window);
256
if (D_check_map_window(&window))
257
G_fatal_error(_("Setting map window"));
259
if (G_set_window(&window) == -1)
260
G_fatal_error(_("Current window not settable"));
262
/* Determine conversion factors */
263
if (D_get_screen_window(&t, &b, &l, &r))
264
G_fatal_error(_("Getting screen window"));
265
if (D_do_conversions(&window, t, b, l, r))
266
G_fatal_error(_("Error in calculating conversions"));
268
/* where are we, both geographically and on the screen? */
269
D_south = D_get_d_south();
270
D_north = D_get_d_north();
271
D_east = D_get_d_east();
272
D_west = D_get_d_west();
274
U_west = D_get_u_west();
275
U_east = D_get_u_east();
276
U_south = D_get_u_south();
277
U_north = D_get_u_north();
279
U_to_D_xconv = D_get_u_to_d_xconv();
280
U_to_D_yconv = D_get_u_to_d_yconv();
282
/* number of rows and cols in window */
287
if ((nrows > 75) || (ncols > 75)){
288
fprintf (stdout,"\n");
289
fprintf (stdout,"Current window size:\n");
290
fprintf (stdout,"rows: %d\n", nrows);
291
fprintf (stdout,"columns: %d\n", ncols);
292
fprintf (stdout,"\n");
293
fprintf (stdout,"Your current window setting may be too large.\n");
294
fprintf (stdout,"Cells displayed on your graphics window may be too\n");
295
fprintf (stdout,"small for arrows to be visible.\n\n");
296
if (!G_yes("Do you wish to continue", 0))
302
ew_res = window.ew_res;
303
ns_res = window.ns_res;
305
/* how many screen units of distance for each cell */
306
D_ew = (D_east - D_west) / ncols;
307
D_ns = (D_south - D_north) / nrows;
309
/* figure out arrow scaling if using a magnitude map */
311
G_init_fp_range(&range); /* really needed? */
312
if (G_read_fp_range(mag_map, mag_mapset, &range) != 1)
313
G_fatal_error(_("Problem reading range file"));
314
G_get_fp_range_min_max(&range, &mag_min, &mag_max);
316
scale *= 1.5 * ((D_ew < D_ns) ? D_ew : D_ns) / fabs(mag_max);
317
G_debug(3, "scaling=%.2f rast_max=%.2f D_ew=%.2f", scale, mag_max,
321
/*------------------------------------------
322
fprintf (stdout,"ew_res: %.2f\n", window.ew_res);
323
fprintf (stdout,"ns_res: %.2f\n", window.ns_res);
324
fprintf (stdout,"D_ew: %f D_ns: %f \n", D_ew, D_ns);
325
fprintf (stdout,"nrows: %d\n", nrows);
326
fprintf (stdout,"ncols: %d\n", ncols);
327
fprintf (stdout,"t: %d\n", t);
328
fprintf (stdout,"b: %d\n", b);
329
fprintf (stdout,"l: %d\n", l);
330
fprintf (stdout,"r: %d\n", r);
331
fprintf (stdout,"U_west: %f\n", U_west);
332
fprintf (stdout,"U_east: %f\n", U_east);
333
fprintf (stdout,"U_south: %f\n", U_south);
334
fprintf (stdout,"U_north: %f\n", U_north);
335
fprintf (stdout,"D_west: %f\n", D_west);
336
fprintf (stdout,"D_east: %f\n", D_east);
337
fprintf (stdout,"D_south: %f\n", D_south);
338
fprintf (stdout,"D_north: %f\n", D_north);
339
fprintf (stdout,"U_to_D_xconv: %f\n", U_to_D_xconv);
340
fprintf (stdout,"U_to_D_yconv: %f\n", U_to_D_yconv);
341
--------------------------------------------------------*/
343
if (grid_color > 0) { /* ie not "none" */
345
R_standard_color(grid_color);
347
/* Draw vertical grids */
349
for (U_x = U_start; U_x >= U_west; U_x -= ew_res) {
350
D_x = (int)((U_x - U_west) * U_to_D_xconv + D_west);
351
R_move_abs(D_x, (int)D_south);
352
R_cont_abs(D_x, (int)D_north);
355
/* Draw horizontal grids */
357
for (U_y = U_start; U_y >= U_south; U_y -= ns_res) {
358
D_y = (int)((U_south - U_y) * U_to_D_yconv + D_south);
359
R_move_abs((int)D_west, D_y);
360
R_cont_abs((int)D_east, D_y);
364
/* if we didn't get a layer name from the arg options, then
365
get name of layer that is on the screen */
367
if (D_get_cell_name(full_name))
368
G_fatal_error(_("No raster map exists in the current window"));
370
mapset = G_find_cell(full_name, "");
372
G_fatal_error(_("Raster map <%s> not found"), full_name);
374
sscanf(full_name, "%s", layer_name);
377
/* open the raster map */
378
layer_fd = G_open_cell_old(layer_name, mapset);
380
G_fatal_error(_("Unable to open raster map <%s>"), layer_name);
382
raster_type = G_get_raster_map_type(layer_fd);
384
/* allocate the cell array */
385
raster_row = G_allocate_raster_buf(raster_type);
389
/* open the magnitude raster map */
390
mag_fd = G_open_cell_old(mag_map, mag_mapset);
392
G_fatal_error("Unable to open raster map <%s>", mag_map);
394
mag_raster_type = G_get_raster_map_type(mag_fd);
396
/* allocate the cell array */
397
mag_raster_row = G_allocate_raster_buf(mag_raster_type);
401
/* loop through cells, find value, determine direction (n,s,e,w,ne,se,sw,nw),
402
and call appropriate function to draw an arrow on the cell */
404
for (row = 0; row < nrows; row++) {
405
G_get_raster_row(layer_fd, raster_row, row, raster_type);
409
G_get_raster_row(mag_fd, mag_raster_row, row, mag_raster_type);
410
mag_ptr = mag_raster_row;
413
/* determine screen y coordinate of top of current cell */
414
D_y = (int)(row * D_ns + D_north);
416
for (col = 0; col < ncols; col++) {
426
/* determine screen x coordinate of west side of current cell */
427
D_x = (int)(col * D_ew + D_west);
429
/* find aspect direction based on cell value */
430
if (raster_type == CELL_TYPE)
431
aspect_f = *((CELL *) ptr);
432
else if (raster_type == FCELL_TYPE)
433
aspect_f = *((FCELL *) ptr);
434
else if (raster_type == DCELL_TYPE)
435
aspect_f = *((DCELL *) ptr);
440
if (mag_raster_type == CELL_TYPE)
441
length = *((CELL *) mag_ptr);
442
else if (mag_raster_type == FCELL_TYPE)
443
length = *((FCELL *) mag_ptr);
444
else if (mag_raster_type == DCELL_TYPE)
445
length = *((DCELL *) mag_ptr);
449
if (G_is_null_value(mag_ptr, mag_raster_type)) {
450
G_debug(5, "Invalid arrow length [NULL]. Skipping.");
453
else if (length <= 0.0) { /* use fabs() or theta+=180? */
454
G_debug(5, "Illegal arrow length [%.3f]. Skipping.",
461
ptr = G_incr_void_ptr(ptr, G_raster_size(raster_type));
464
G_incr_void_ptr(mag_ptr,
465
G_raster_size(mag_raster_type));
470
/* treat AGNPS and ANSWERS data like old zero-as-null CELL */
471
/* TODO: update models */
472
if (map_type == 2 || map_type == 3) {
473
if (G_is_null_value(ptr, raster_type))
476
aspect_c = (int)(aspect_f + 0.5);
480
/** Now draw the arrows **/
482
/* case switch for standard GRASS aspect map
483
measured in degrees counter-clockwise from east */
485
R_standard_color(arrow_color);
487
if (G_is_null_value(ptr, raster_type)) {
488
R_standard_color(x_color);
490
R_standard_color(arrow_color);
492
else if (aspect_f >= 0.0 && aspect_f <= 360.0) {
494
arrow_mag(aspect_f, length);
499
R_standard_color(unknown_color);
501
R_standard_color(arrow_color);
506
/* case switch for AGNPS type aspect map */
507
else if (map_type == 2) {
508
R_standard_color(arrow_color);
511
R_standard_color(x_color);
513
R_standard_color(arrow_color);
540
R_standard_color(unknown_color);
542
R_standard_color(arrow_color);
548
/* case switch for ANSWERS type aspect map */
549
else if (map_type == 3) {
550
R_standard_color(arrow_color);
551
if (aspect_c >= 15 && aspect_c <= 360) /* start at zero? */
552
arrow_360((double)aspect_c);
553
else if (aspect_c == 400) {
554
R_standard_color(unknown_color);
556
R_standard_color(arrow_color);
559
R_standard_color(x_color);
561
R_standard_color(arrow_color);
565
/* case switch for compass type aspect map
566
measured in degrees clockwise from north */
567
else if (map_type == 4) {
568
R_standard_color(arrow_color);
570
if (G_is_null_value(ptr, raster_type)) {
571
R_standard_color(x_color);
573
R_standard_color(arrow_color);
575
else if (aspect_f >= 0.0 && aspect_f <= 360.0) {
577
arrow_mag(90 - aspect_f, length);
579
arrow_360(90 - aspect_f);
582
R_standard_color(unknown_color);
584
R_standard_color(arrow_color);
588
ptr = G_incr_void_ptr(ptr, G_raster_size(raster_type));
591
G_incr_void_ptr(mag_ptr, G_raster_size(mag_raster_type));
595
G_close_cell(layer_fd);
597
G_close_cell(mag_fd);
598
D_add_to_list(G_recreate_command());
604
/* --- end of main --- */
606
/*---------------------------------------------------------------*/
609
static void arrow_mag(double theta, double length)
610
{ /* angle is measured in degrees counter-clockwise from east */
611
extern double D_ew, D_ns;
613
int x, y, dx, dy, mid_x, mid_y;
616
theta *= -1; /* display coords use inverse y */
618
/* find the display coordinates of the middle of the cell */
619
mid_x = D_x + (int)(D_ew * .5);
620
mid_y = D_y + (int)(D_ns * .5);
623
R_move_abs(mid_x, mid_y);
626
x = mid_x + (int)(length * cos(D2R(theta)));
627
y = mid_y + (int)(length * sin(D2R(theta)));
631
theta_offset = theta + 20;
632
dx = mid_x + (int)(0.6 * length * cos(D2R(theta_offset)));
633
dy = mid_y + (int)(0.6 * length * sin(D2R(theta_offset)));
638
theta_offset = theta - 20;
639
dx = mid_x + (int)(0.6 * length * cos(D2R(theta_offset)));
640
dy = mid_y + (int)(0.6 * length * sin(D2R(theta_offset)));
645
static void arrow_360(double theta)
646
{ /* angle is measured in degrees counter-clockwise from east */
647
extern double D_ew, D_ns;
649
int x, y, dx, dy, mid_x, mid_y;
650
double max_radius, theta_offset;
652
theta *= -1; /* display coords use inverse y */
653
max_radius = ((D_ew < D_ns) ? D_ew : D_ns) * 0.8 / 2;
655
/* find the display coordinates of the middle of the cell */
656
mid_x = D_x + (int)(D_ew * 0.5);
657
mid_y = D_y + (int)(D_ns * 0.5);
660
x = mid_x + (int)(max_radius * cos(D2R(theta)));
661
y = mid_y + (int)(max_radius * sin(D2R(theta)));
665
dx = -2 * (int)(max_radius * cos(D2R(theta)));
666
dy = -2 * (int)(max_radius * sin(D2R(theta)));
671
theta_offset = theta + 90;
672
dx = mid_x + (int)(0.5 * max_radius * cos(D2R(theta_offset)));
673
dy = mid_y + (int)(0.5 * max_radius * sin(D2R(theta_offset)));
678
theta_offset = theta - 90;
679
dx = mid_x + (int)(0.5 * max_radius * cos(D2R(theta_offset)));
680
dy = mid_y + (int)(0.5 * max_radius * sin(D2R(theta_offset)));
685
static void arrow_se(void)
687
extern double D_ew, D_ns;
691
x = D_x + (int)(D_ew * .8);
692
y = D_y + (int)(D_ns * .8);
694
R_cont_rel((int)(D_ew * (-.6)), ((int)(D_ns * (-.6))));
696
R_cont_rel(0, (int)(D_ns * (-.4)));
698
R_cont_rel((int)(D_ew * (-.4)), 0);
702
static void arrow_ne(void)
704
extern double D_ew, D_ns;
708
x = D_x + (int)(D_ew * .8);
709
y = D_y + (int)(D_ns * .2);
711
R_cont_rel((int)(D_ew * (-.6)), ((int)(D_ns * (.6))));
713
R_cont_rel(0, (int)(D_ns * (.4)));
715
R_cont_rel((int)(D_ew * (-.4)), 0);
719
static void arrow_nw(void)
721
extern double D_ew, D_ns;
725
x = D_x + (int)(D_ew * .2);
726
y = D_y + (int)(D_ns * .2);
728
R_cont_rel((int)(D_ew * (.6)), ((int)(D_ns * (.6))));
730
R_cont_rel(0, (int)(D_ns * (.4)));
732
R_cont_rel((int)(D_ew * (.4)), 0);
736
static void arrow_sw(void)
738
extern double D_ew, D_ns;
742
x = D_x + (int)(D_ew * .2);
743
y = D_y + (int)(D_ns * .8);
745
R_cont_rel((int)(D_ew * (.6)), ((int)(D_ns * (-.6))));
747
R_cont_rel(0, (int)(D_ns * (-.4)));
749
R_cont_rel((int)(D_ew * (.4)), 0);
752
static void arrow_e(void)
754
extern double D_ew, D_ns;
758
x = D_x + (int)(D_ew * .9);
759
y = D_y + (int)(D_ns * .5);
761
R_cont_rel((int)(D_ew * (-.8)), 0);
763
R_cont_rel((int)(D_ew * (-.3)), (int)(D_ns * (-.3)));
765
R_cont_rel((int)(D_ew * (-.3)), (int)(D_ns * (.3)));
768
static void arrow_w(void)
770
extern double D_ew, D_ns;
774
x = D_x + (int)(D_ew * .1);
775
y = D_y + (int)(D_ns * .5);
777
R_cont_rel((int)(D_ew * (.8)), 0);
779
R_cont_rel((int)(D_ew * (.3)), (int)(D_ns * (-.3)));
781
R_cont_rel((int)(D_ew * (.3)), (int)(D_ns * (.3)));
784
static void arrow_s(void)
786
extern double D_ew, D_ns;
790
x = D_x + (int)(D_ew * .5);
791
y = D_y + (int)(D_ns * .9);
793
R_cont_rel(0, (int)(D_ns * (-.8)));
795
R_cont_rel((int)(D_ew * (.3)), (int)(D_ns * (-.3)));
797
R_cont_rel((int)(D_ew * (-.3)), (int)(D_ns * (-.3)));
800
static void arrow_n(void)
802
extern double D_ew, D_ns;
806
x = D_x + (int)(D_ew * .5);
807
y = D_y + (int)(D_ns * .1);
809
R_cont_rel(0, (int)(D_ns * (.8)));
811
R_cont_rel((int)(D_ew * (.3)), (int)(D_ns * (.3)));
813
R_cont_rel((int)(D_ew * (-.3)), (int)(D_ns * (.3)));
816
static void draw_x(void)
818
extern double D_ew, D_ns;
825
R_cont_rel((int)D_ew, (int)D_ns);
828
R_cont_rel((int)D_ew, (int)(D_ns * -1));
830
static void unknown_(void)
832
extern double D_ew, D_ns;
836
x = D_x + (int)(D_ew * .3);
837
y = D_y + (int)(D_ns * .4);
839
R_cont_rel(0, (int)(D_ns * (-.15)));
840
R_cont_rel((int)(D_ew * (.1)), (int)(D_ns * (-.1)));
841
R_cont_rel((int)(D_ew * (.2)), 0);
842
R_cont_rel((int)(D_ew * (.1)), (int)(D_ns * (.1)));
843
R_cont_rel(0, (int)(D_ns * (.2)));
844
R_cont_rel((int)(D_ew * (-.1)), (int)(D_ns * (.1)));
845
R_cont_rel((int)(D_ew * (-.1)), 0);
846
R_cont_rel(0, (int)(D_ns * (.25)));
847
R_move_rel(0, (int)(D_ns * (.1)));
848
R_cont_rel(0, (int)(D_ns * (.1)));