2
****************************************************************************
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
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 */
49
static void arrow_mag(double, double);
50
static void arrow_360(double);
51
static void arrow_se(void);
52
static void arrow_ne(void);
53
static void arrow_nw(void);
54
static void arrow_sw(void);
55
static void arrow_e(void);
56
static void arrow_w(void);
57
static void arrow_s(void);
58
static void arrow_n(void);
59
static void draw_x(void);
60
static void unknown_(void);
62
static char *layer_name;
63
static int map_type, arrow_color, grid_color, x_color, unknown_color;
66
int main(int argc, char **argv)
68
struct Cell_head window;
69
RASTER_MAP_TYPE raster_type, mag_raster_type = -1;
71
void *raster_row, *ptr;
74
float aspect_f = -1.0;
79
void *mag_raster_row = NULL, *mag_ptr = NULL;
83
double mag_min, mag_max;
85
struct GModule *module;
86
struct Option *opt1, *opt2, *opt3, *opt4, *opt5,
87
*opt6, *opt7, *opt8, *opt9;
94
module = G_define_module();
95
G_add_keyword(_("display"));
96
G_add_keyword(_("map annotations"));
97
G_add_keyword(_("raster"));
99
_("Draws arrows representing cell aspect direction "
100
"for a raster map containing aspect data.");
102
opt1 = G_define_standard_option(G_OPT_R_MAP);
103
opt1->description = _("Name of raster aspect map to be displayed");
105
opt2 = G_define_option();
107
opt2->type = TYPE_STRING;
109
opt2->answer = "grass";
110
opt2->options = "grass,compass,agnps,answers";
111
opt2->description = _("Type of existing raster aspect map");
113
opt3 = G_define_standard_option(G_OPT_C);
115
opt3->answer = "green";
116
opt3->label = _("Color for drawing arrows");
117
opt3->guisection = _("Colors");
119
opt4 = G_define_standard_option(G_OPT_CN);
120
opt4->key = "grid_color";
121
opt4->answer = "gray";
122
opt4->label = _("Color for drawing drawing grid");
123
opt4->guisection = _("Colors");
125
opt5 = G_define_standard_option(G_OPT_CN);
126
opt5->key = "null_color";
127
opt5->answer = DEFAULT_FG_COLOR;
128
opt5->label = _("Color for drawing null values (X symbol)");
129
opt5->guisection = _("Colors");
131
opt6 = G_define_standard_option(G_OPT_CN);
132
opt6->key = "unknown_color";
133
opt6->answer = "red";
134
opt6->label = _("Color for showing unknown information (? symbol)");
135
opt6->guisection = _("Colors");
137
opt9 = G_define_option();
139
opt9->type = TYPE_INTEGER;
142
opt9->description = _("Draw arrow every Nth grid cell");
144
opt7 = G_define_option();
145
opt7->key = "magnitude_map";
146
opt7->type = TYPE_STRING;
149
opt7->gisprompt = "old,cell,raster";
151
_("Raster map containing values used for arrow length");
153
opt8 = G_define_option();
155
opt8->type = TYPE_DOUBLE;
157
opt8->answer = "1.0";
158
opt8->description = _("Scale factor for arrows (magnitude map)");
160
align = G_define_flag();
162
align->description = _("Align grids with raster cells");
165
/* Check command line */
166
if (G_parser(argc, argv))
170
layer_name = opt1->answer;
172
arrow_color = D_translate_color(opt3->answer);
174
/* Convert none (transparent) to -1 which in this module means
175
that we will not draw things having this color (-1).
176
We don't do that for arrow because we always want them.
177
(This is specified by the gisprompt ('type') of the options.)
179
if (strcmp("none", opt4->answer) == 0)
182
grid_color = D_translate_color(opt4->answer);
184
if (strcmp("none", opt5->answer) == 0)
187
x_color = D_translate_color(opt5->answer);
189
if (strcmp("none", opt6->answer) == 0)
192
unknown_color = D_translate_color(opt6->answer);
194
if (strcmp("grass", opt2->answer) == 0)
196
else if (strcmp("agnps", opt2->answer) == 0)
198
else if (strcmp("answers", opt2->answer) == 0)
200
else if (strcmp("compass", opt2->answer) == 0)
204
scale = atof(opt8->answer);
206
G_fatal_error(_("Illegal value for scale factor"));
208
skip = atoi(opt9->answer);
210
G_fatal_error(_("Illegal value for skip factor"));
214
if (map_type != 1 && map_type != 4)
215
G_fatal_error(_("Magnitude is only supported for GRASS and compass aspect maps."));
217
mag_map = opt7->answer;
219
else if (scale != 1.0)
220
G_warning(_("Scale option requires magnitude_map"));
223
/* Setup driver and check important information */
228
/* Read in the map window associated with window */
229
G_get_window(&window);
232
struct Cell_head wind;
234
Rast_get_cellhd(layer_name, "", &wind);
236
/* expand window extent by one wind resolution */
237
wind.west += wind.ew_res * ((int)((window.west - wind.west) / wind.ew_res) - (window.west < wind.west));
238
wind.east += wind.ew_res * ((int)((window.east - wind.east) / wind.ew_res) + (window.east > wind.east));
239
wind.south += wind.ns_res * ((int)((window.south - wind.south) / wind.ns_res) - (window.south < wind.south));
240
wind.north += wind.ns_res * ((int)((window.north - wind.north) / wind.ns_res) + (window.north > wind.north));
242
wind.rows = (wind.north - wind.south) / wind.ns_res;
243
wind.cols = (wind.east - wind.west) / wind.ew_res;
245
Rast_set_window(&wind);
250
t = (wind.north - window.north) * nrows / (wind.north - wind.south);
251
b = t + (window.north - window.south) * nrows / (wind.north - wind.south);
252
l = (window.west - wind.west) * ncols / (wind.east - wind.west);
253
r = l + (window.east - window.west) * ncols / (wind.east - wind.west);
264
D_set_src(t, b, l, r);
265
D_update_conversions();
267
/* figure out arrow scaling if using a magnitude map */
269
Rast_init_fp_range(&range); /* really needed? */
270
if (Rast_read_fp_range(mag_map, "", &range) != 1)
271
G_fatal_error(_("Problem reading range file"));
272
Rast_get_fp_range_min_max(&range, &mag_min, &mag_max);
274
scale *= 1.5 / fabs(mag_max);
275
G_debug(3, "scaling=%.2f rast_max=%.2f", scale, mag_max);
278
if (grid_color > 0) { /* ie not "none" */
280
D_use_color(grid_color);
282
/* Draw vertical grids */
283
for (col = 0; col < ncols; col++)
284
D_line_abs(col, 0, col, nrows);
286
/* Draw horizontal grids */
287
for (row = 0; row < nrows; row++)
288
D_line_abs(0, row, ncols, row);
291
/* open the raster map */
292
layer_fd = Rast_open_old(layer_name, "");
294
raster_type = Rast_get_map_type(layer_fd);
296
/* allocate the cell array */
297
raster_row = Rast_allocate_buf(raster_type);
301
/* open the magnitude raster map */
302
mag_fd = Rast_open_old(mag_map, "");
304
mag_raster_type = Rast_get_map_type(mag_fd);
306
/* allocate the cell array */
307
mag_raster_row = Rast_allocate_buf(mag_raster_type);
311
/* loop through cells, find value, determine direction (n,s,e,w,ne,se,sw,nw),
312
and call appropriate function to draw an arrow on the cell */
314
for (row = 0; row < nrows; row++) {
315
Rast_get_row(layer_fd, raster_row, row, raster_type);
319
Rast_get_row(mag_fd, mag_raster_row, row, mag_raster_type);
320
mag_ptr = mag_raster_row;
323
for (col = 0; col < ncols; col++) {
333
/* find aspect direction based on cell value */
334
if (raster_type == CELL_TYPE)
335
aspect_f = *((CELL *) ptr);
336
else if (raster_type == FCELL_TYPE)
337
aspect_f = *((FCELL *) ptr);
338
else if (raster_type == DCELL_TYPE)
339
aspect_f = *((DCELL *) ptr);
344
if (mag_raster_type == CELL_TYPE)
345
length = *((CELL *) mag_ptr);
346
else if (mag_raster_type == FCELL_TYPE)
347
length = *((FCELL *) mag_ptr);
348
else if (mag_raster_type == DCELL_TYPE)
349
length = *((DCELL *) mag_ptr);
353
if (Rast_is_null_value(mag_ptr, mag_raster_type)) {
354
G_debug(5, "Invalid arrow length [NULL]. Skipping.");
357
else if (length <= 0.0) { /* use fabs() or theta+=180? */
358
G_debug(5, "Illegal arrow length [%.3f]. Skipping.",
365
ptr = G_incr_void_ptr(ptr, Rast_cell_size(raster_type));
368
G_incr_void_ptr(mag_ptr,
369
Rast_cell_size(mag_raster_type));
374
/* treat AGNPS and ANSWERS data like old zero-as-null CELL */
375
/* TODO: update models */
376
if (map_type == 2 || map_type == 3) {
377
if (Rast_is_null_value(ptr, raster_type))
380
aspect_c = (int)(aspect_f + 0.5);
384
/** Now draw the arrows **/
386
/* case switch for standard GRASS aspect map
387
measured in degrees counter-clockwise from east */
389
D_use_color(arrow_color);
391
if (Rast_is_null_value(ptr, raster_type)) {
392
/* don't draw anything if x_color is none (transparent) */
394
D_use_color(x_color);
396
D_use_color(arrow_color);
399
else if (aspect_f >= 0.0 && aspect_f <= 360.0) {
401
arrow_mag(aspect_f, length);
405
else if (unknown_color > 0) {
406
/* don't draw if unknown_color is none (transparent) */
407
D_use_color(unknown_color);
409
D_use_color(arrow_color);
414
/* case switch for AGNPS type aspect map */
415
else if (map_type == 2) {
416
D_use_color(arrow_color);
419
/* only draw if x_color is not none (transparent) */
421
D_use_color(x_color);
423
D_use_color(arrow_color);
451
/* only draw if unknown_color is not none */
452
if (unknown_color > 0) {
453
D_use_color(unknown_color);
455
D_use_color(arrow_color);
462
/* case switch for ANSWERS type aspect map */
463
else if (map_type == 3) {
464
D_use_color(arrow_color);
465
if (aspect_c >= 15 && aspect_c <= 360) /* start at zero? */
466
arrow_360((double)aspect_c);
467
else if (aspect_c == 400) {
468
if (unknown_color > 0) {
469
/* only draw if unknown_color is not none */
470
D_use_color(unknown_color);
472
D_use_color(arrow_color);
475
else if (x_color > 0) {
476
/* only draw if x_color is not none (transparent) */
477
D_use_color(x_color);
479
D_use_color(arrow_color);
483
/* case switch for compass type aspect map
484
measured in degrees clockwise from north */
485
else if (map_type == 4) {
486
D_use_color(arrow_color);
488
if (Rast_is_null_value(ptr, raster_type)) {
490
/* only draw if x_color is not none */
491
D_use_color(x_color);
493
D_use_color(arrow_color);
496
else if (aspect_f >= 0.0 && aspect_f <= 360.0) {
498
arrow_mag(90 - aspect_f, length);
500
arrow_360(90 - aspect_f);
502
else if (unknown_color > 0) {
503
/* only draw if unknown_color is not none */
504
D_use_color(unknown_color);
506
D_use_color(arrow_color);
510
ptr = G_incr_void_ptr(ptr, Rast_cell_size(raster_type));
513
G_incr_void_ptr(mag_ptr, Rast_cell_size(mag_raster_type));
517
Rast_close(layer_fd);
521
D_save_command(G_recreate_command());
527
/* --- end of main --- */
529
/*---------------------------------------------------------------*/
532
static void arrow_mag(double theta, double length)
533
{ /* angle is measured in degrees counter-clockwise from east */
534
double x, y, dx, dy, mid_x, mid_y;
537
theta *= -1; /* display coords use inverse y */
539
/* find the display coordinates of the middle of the cell */
546
D_move_abs(mid_x, mid_y);
549
x = mid_x + (length * cos(D2R(theta)));
550
y = mid_y + (length * sin(D2R(theta)));
554
theta_offset = theta + 20;
555
dx = mid_x + (0.6 * length * cos(D2R(theta_offset)));
556
dy = mid_y + (0.6 * length * sin(D2R(theta_offset)));
561
theta_offset = theta - 20;
562
dx = mid_x + (0.6 * length * cos(D2R(theta_offset)));
563
dy = mid_y + (0.6 * length * sin(D2R(theta_offset)));
571
static void arrow_360(double theta)
572
{ /* angle is measured in degrees counter-clockwise from east */
573
double x, y, dx, dy, mid_x, mid_y;
574
double max_radius, theta_offset;
576
theta *= -1; /* display coords use inverse y */
577
max_radius = 0.8 / 2;
579
/* find the display coordinates of the middle of the cell */
586
x = mid_x + (max_radius * cos(D2R(theta)));
587
y = mid_y + (max_radius * sin(D2R(theta)));
591
dx = -2 * (max_radius * cos(D2R(theta)));
592
dy = -2 * (max_radius * sin(D2R(theta)));
597
theta_offset = theta + 90;
598
dx = mid_x + (0.5 * max_radius * cos(D2R(theta_offset)));
599
dy = mid_y + (0.5 * max_radius * sin(D2R(theta_offset)));
604
theta_offset = theta - 90;
605
dx = mid_x + (0.5 * max_radius * cos(D2R(theta_offset)));
606
dy = mid_y + (0.5 * max_radius * sin(D2R(theta_offset)));
613
static void arrow_se(void)
615
double x = col + (.8);
616
double y = row + (.8);
619
D_cont_rel(((-.6)), (((-.6))));
621
D_cont_rel(0, ((-.4)));
623
D_cont_rel(((-.4)), 0);
628
static void arrow_ne(void)
630
double x = col + (.8);
631
double y = row + (.2);
634
D_cont_rel(((-.6)), (((.6))));
636
D_cont_rel(0, ((.4)));
638
D_cont_rel(((-.4)), 0);
643
static void arrow_nw(void)
645
double x = col + (.2);
646
double y = row + (.2);
649
D_cont_rel(((.6)), (((.6))));
651
D_cont_rel(0, ((.4)));
653
D_cont_rel(((.4)), 0);
658
static void arrow_sw(void)
660
double x = col + (.2);
661
double y = row + (.8);
664
D_cont_rel(((.6)), (((-.6))));
666
D_cont_rel(0, ((-.4)));
668
D_cont_rel(((.4)), 0);
673
static void arrow_e(void)
675
double x = col + (.9);
676
double y = row + (.5);
679
D_cont_rel(((-.8)), 0);
681
D_cont_rel(((-.3)), ((-.3)));
683
D_cont_rel(((-.3)), ((.3)));
688
static void arrow_w(void)
690
double x = col + (.1);
691
double y = row + (.5);
694
D_cont_rel(((.8)), 0);
696
D_cont_rel(((.3)), ((-.3)));
698
D_cont_rel(((.3)), ((.3)));
703
static void arrow_s(void)
705
double x = col + (.5);
706
double y = row + (.9);
709
D_cont_rel(0, ((-.8)));
711
D_cont_rel(((.3)), ((-.3)));
713
D_cont_rel(((-.3)), ((-.3)));
718
static void arrow_n(void)
720
double x = col + (.5);
721
double y = row + (.1);
724
D_cont_rel(0, ((.8)));
726
D_cont_rel(((.3)), ((.3)));
728
D_cont_rel(((-.3)), ((.3)));
733
static void draw_x(void)
747
static void unknown_(void)
749
double x = col + (.3);
750
double y = row + (.4);
754
D_cont_rel(0, ((-.15)));
755
D_cont_rel(((.1)), ((-.1)));
756
D_cont_rel(((.2)), 0);
757
D_cont_rel(((.1)), ((.1)));
758
D_cont_rel(0, ((.2)));
759
D_cont_rel(((-.1)), ((.1)));
760
D_cont_rel(((-.1)), 0);
761
D_cont_rel(0, ((.25)));
762
D_move_rel(0, ((.1)));
763
D_cont_rel(0, ((.1)));