38
38
int main(int argc, char **argv)
43
int black, white, color;
49
int thin, lines, steps;
55
int hide_catnum, hide_catstr, hide_nodata, do_smooth, use_mouse;
52
int hide_catnum, hide_catstr, hide_nodata, do_smooth;
54
double x_box[5], y_box[5];
60
55
struct Categories cats;
61
56
struct Colors colors;
62
57
struct GModule *module;
63
struct Option *opt1, *opt2, *opt4, *opt5, *opt6, *opt7, *opt8, *opt9;
64
struct Flag *hidestr, *hidenum, *hidenodata, *smooth, *mouse, *flipit;
58
struct Option *opt_rast2d, *opt_rast3d, *opt_color, *opt_lines,
59
*opt_thin, *opt_labelnum, *opt_at, *opt_use, *opt_range,
60
*opt_font, *opt_path, *opt_charset, *opt_fontsize;
61
struct Flag *hidestr, *hidenum, *hidenodata, *smooth, *flipit, *histo;
65
62
struct Range range;
66
63
struct FPRange fprange;
67
CELL min_ind, max_ind, null_cell;
64
CELL min_ind, max_ind;
68
65
DCELL dmin, dmax, val;
69
66
CELL min_colr, max_colr;
70
67
DCELL min_dcolr, max_dcolr;
77
74
double UserRangeMin, UserRangeMax, UserRangeTemp;
78
75
double *catlist, maxCat;
79
76
int catlistCount, use_catlist;
82
81
/* Initialize the GIS calls */
83
82
G_gisinit(argv[0]);
85
84
module = G_define_module();
86
module->keywords = _("display, cartography");
85
G_add_keyword(_("display"));
86
G_add_keyword(_("cartography"));
87
87
module->description =
88
_("Displays a legend for a raster map in the active frame "
88
_("Displays a legend for a 2D or 3D raster map in the active frame "
89
89
"of the graphics monitor.");
91
opt1 = G_define_standard_option(G_OPT_R_MAP);
92
opt1->description = _("Name of raster map");
94
opt2 = G_define_standard_option(G_OPT_C_FG);
95
opt2->label = _("Text color");
97
opt4 = G_define_option();
99
opt4->type = TYPE_INTEGER;
101
opt4->options = "0-1000";
91
opt_rast2d = G_define_standard_option(G_OPT_R_MAP);
92
opt_rast2d->key = "raster";
93
opt_rast2d->required = NO;
94
opt_rast2d->guisection = _("Input");
96
opt_rast3d = G_define_standard_option(G_OPT_R3_MAP);
97
opt_rast3d->key = "raster_3d";
98
opt_rast3d->required = NO;
99
opt_rast3d->guisection = _("Input");
101
opt_lines = G_define_option();
102
opt_lines->key = "lines";
103
opt_lines->type = TYPE_INTEGER;
104
opt_lines->answer = "0";
105
opt_lines->options = "0-1000";
106
opt_lines->description =
103
107
_("Number of text lines (useful for truncating long legends)");
104
opt4->guisection = _("Advanced");
106
opt5 = G_define_option();
108
opt5->type = TYPE_INTEGER;
111
opt5->options = "1-1000";
112
opt5->description = _("Thinning factor (thin=10 gives cats 0,10,20...)");
113
opt5->guisection = _("Advanced");
115
opt6 = G_define_option();
116
opt6->key = "labelnum";
117
opt6->type = TYPE_INTEGER;
119
opt6->options = "2-100";
120
opt6->description = _("Number of text labels for smooth gradient legend");
121
opt6->guisection = _("Advanced");
123
opt7 = G_define_option();
125
opt7->key_desc = "bottom,top,left,right";
126
opt7->type = TYPE_DOUBLE; /* needs to be TYPE_DOUBLE to get past options check */
128
opt7->options = "0-100";
130
_("Size and placement as percentage of screen coordinates (0,0 is lower left)");
131
opt7->description = opt7->key_desc;
134
opt8 = G_define_option();
136
opt8->key_desc = "catnum";
137
opt8->type = TYPE_DOUBLE; /* string as it is fed through the parser? */
108
opt_lines->guisection = _("Advanced");
110
opt_thin = G_define_option();
111
opt_thin->key = "thin";
112
opt_thin->type = TYPE_INTEGER;
113
opt_thin->required = NO;
114
opt_thin->answer = "1";
115
opt_thin->options = "1-1000";
116
opt_thin->description =
117
_("Thinning factor (thin=10 gives cats 0,10,20...)");
118
opt_thin->guisection = _("Advanced");
120
opt_labelnum = G_define_option();
121
opt_labelnum->key = "labelnum";
122
opt_labelnum->type = TYPE_INTEGER;
123
opt_labelnum->answer = "5";
124
opt_labelnum->options = "2-100";
125
opt_labelnum->description =
126
_("Number of text labels for smooth gradient legend");
127
opt_labelnum->guisection = _("Gradient");
129
opt_at = G_define_option();
131
opt_at->key_desc = "bottom,top,left,right";
132
opt_at->type = TYPE_DOUBLE; /* needs to be TYPE_DOUBLE to get past options check */
133
opt_at->required = NO;
134
opt_at->options = "0-100";
136
_("Size and placement as percentage of screen coordinates "
137
"(0,0 is lower left)");
138
opt_at->description = opt_at->key_desc;
139
opt_at->answer = NULL;
141
opt_use = G_define_option();
142
opt_use->key = "use";
143
opt_use->type = TYPE_DOUBLE; /* string as it is fed through the parser? */
144
opt_use->required = NO;
145
opt_use->description =
140
146
_("List of discrete category numbers/values for legend");
141
opt8->multiple = YES;
142
opt8->guisection = _("Advanced");
147
opt_use->multiple = YES;
148
opt_use->guisection = _("Subset");
144
opt9 = G_define_option();
146
opt9->key_desc = "min,max";
147
opt9->type = TYPE_DOUBLE; /* should it be type_double or _string ?? */
150
opt_range = G_define_option();
151
opt_range->key = "range";
152
opt_range->key_desc = "min,max";
153
opt_range->type = TYPE_DOUBLE; /* should it be type_double or _string ?? */
154
opt_range->required = NO;
155
opt_range->description =
150
156
_("Use a subset of the map range for the legend (min,max)");
151
opt9->guisection = _("Advanced");
154
mouse = G_define_flag();
156
mouse->description = _("Use mouse to size & place legend");
157
opt_range->guisection = _("Subset");
159
opt_color = G_define_standard_option(G_OPT_C);
160
opt_color->label = _("Text color");
161
opt_color->guisection = _("Font settings");
163
opt_font = G_define_option();
164
opt_font->key = "font";
165
opt_font->type = TYPE_STRING;
166
opt_font->required = NO;
167
opt_font->description = _("Font name");
168
opt_font->guisection = _("Font settings");
170
opt_fontsize = G_define_option();
171
opt_fontsize->key = "fontsize";
172
opt_fontsize->type = TYPE_DOUBLE;
173
opt_fontsize->required = NO;
174
opt_fontsize->options = "1-360";
175
opt_fontsize->label = _("Font size");
176
opt_fontsize->description = _("Default: Auto-scaled");
177
opt_fontsize->guisection = _("Font settings");
179
opt_path = G_define_standard_option(G_OPT_F_INPUT);
180
opt_path->key = "path";
181
opt_path->required = NO;
182
opt_path->description = _("Path to font file");
183
opt_path->gisprompt = "old_file,font,file";
184
opt_path->guisection = _("Font settings");
186
opt_charset = G_define_option();
187
opt_charset->key = "charset";
188
opt_charset->type = TYPE_STRING;
189
opt_charset->required = NO;
190
opt_charset->description =
191
_("Text encoding (only applicable to TrueType fonts)");
192
opt_charset->guisection = _("Font settings");
158
194
hidestr = G_define_flag();
159
195
hidestr->key = 'v';
173
209
smooth = G_define_flag();
174
210
smooth->key = 's';
175
211
smooth->description = _("Draw smooth gradient");
176
smooth->guisection = _("Advanced");
212
smooth->guisection = _("Gradient");
178
214
flipit = G_define_flag();
179
215
flipit->key = 'f';
180
216
flipit->description = _("Flip legend");
181
217
flipit->guisection = _("Advanced");
219
histo = G_define_flag();
221
histo->description = _("Add histogram to smoothed legend");
222
histo->guisection = _("Gradient");
184
225
/* Check command line */
185
226
if (G_parser(argc, argv))
186
227
exit(EXIT_FAILURE);
229
/* FIXME: add GUI launching logic to G_parser() call */
230
if ((opt_rast2d->answer && opt_rast3d->answer) ||
231
!(opt_rast2d->answer || opt_rast3d->answer))
232
G_fatal_error(_("Please specify a single map name. To launch GUI use d.legend --ui."));
189
map_name = opt1->answer;
234
if (opt_rast2d->answer) {
235
map_name = opt_rast2d->answer;
236
maptype = MAP_TYPE_RASTER2D;
239
map_name = opt_rast3d->answer;
240
maptype = MAP_TYPE_RASTER3D;
191
243
hide_catstr = hidestr->answer; /* note hide_catstr gets changed and re-read below */
192
244
hide_catnum = hidenum->answer;
193
245
hide_nodata = hidenodata->answer;
194
246
do_smooth = smooth->answer;
195
use_mouse = mouse->answer;
196
247
flip = flipit->answer;
198
color = D_parse_color(opt2->answer, TRUE);
249
color = D_parse_color(opt_color->answer, TRUE);
200
if (opt4->answer != NULL)
201
sscanf(opt4->answer, "%d", &lines);
251
if (opt_lines->answer != NULL)
252
sscanf(opt_lines->answer, "%d", &lines);
204
if (opt5->answer != NULL)
205
sscanf(opt5->answer, "%d", &thin);
255
if (opt_thin->answer != NULL)
256
sscanf(opt_thin->answer, "%d", &thin);
209
if (opt6->answer != NULL)
210
sscanf(opt6->answer, "%d", &steps);
260
if (opt_labelnum->answer != NULL)
261
sscanf(opt_labelnum->answer, "%d", &steps);
212
263
catlistCount = 0;
213
if (opt8->answer != NULL) { /* should this be answerS ? */
264
if (opt_use->answer != NULL) { /* should this be answerS ? */
214
265
use_catlist = TRUE;
216
267
catlist = (double *)G_calloc(100 + 1, sizeof(double));
244
/* Make sure map is available */
245
mapset = G_find_cell2(map_name, "");
247
G_fatal_error(_("Raster map <%s> not found"), map_name);
249
if (G_read_colors(map_name, mapset, &colors) == -1)
250
G_fatal_error(_("Color file for <%s> not available"), map_name);
252
fp = G_raster_map_is_fp(map_name, mapset);
294
if (maptype == MAP_TYPE_RASTER2D) {
295
if (Rast_read_colors(map_name, "", &colors) == -1)
296
G_fatal_error(_("Color file for <%s> not available"), map_name);
298
fp = Rast_map_is_fp(map_name, "");
300
Rast_read_cats(map_name, "", &cats);
303
if (Rast3d_read_colors(map_name, "", &colors) == -1)
304
G_fatal_error(_("Color file for <%s> not available"), map_name);
306
fp = TRUE; /* currently raster 3D is always floating point */
308
Rast3d_read_cats(map_name, "", &cats);
253
311
if (fp && !use_catlist) {
254
312
do_smooth = TRUE;
255
313
/* fprintf(stderr, "FP map found - switching gradient legend on\n"); */
259
if (G_read_cats(map_name, mapset, &cats) == -1)
260
G_warning(_("Category file for <%s> not available"), map_name);
262
G_set_c_null_value(&null_cell, 1);
264
if (R_open_driver() != 0)
265
G_fatal_error(_("No graphics device selected"));
267
if (D_get_cur_wind(window_name))
268
G_fatal_error(_("No current window"));
270
if (D_set_cur_wind(window_name))
271
G_fatal_error(_("Current window not available"));
273
319
white = D_translate_color(DEFAULT_FG_COLOR);
274
320
black = D_translate_color(DEFAULT_BG_COLOR);
322
if (opt_font->answer)
323
D_font(opt_font->answer);
324
else if (opt_path->answer)
325
D_font(opt_path->answer);
327
if (opt_fontsize->answer != NULL)
328
fontsize = atof(opt_fontsize->answer);
330
fontsize = 12; /* dummy placeholder, should never be called */
332
if (opt_charset->answer)
333
D_encoding(opt_charset->answer);
276
335
/* Figure out where to put text */
277
D_get_screen_window(&t, &b, &l, &r);
278
R_set_window(t, b, l, r);
281
if (!get_legend_box(&x0, &x1, &y0, &y1))
283
G_debug(1, "mouse placement as percentage of display window "
284
"[bottom,top,left,right]:\n \"at=%.2f,%.2f,%.2f,%.2f\"",
285
100. * (b - y1) / (b - t), 100. * (b - y0) / (b - t),
286
100. * x0 / (r - l), 100. * x1 / (r - l));
288
Y1 = 100. - (y1 - t) * 100. / (b - t);
289
Y0 = 100. - (y0 - t) * 100. / (b - t);
290
X0 = (x0 - l) * 100. / (r - l);
291
X1 = (x1 - l) * 100. / (r - l);
294
if (opt7->answer != NULL) {
295
sscanf(opt7->answers[0], "%lf", &Y1);
296
sscanf(opt7->answers[1], "%lf", &Y0);
297
sscanf(opt7->answers[2], "%lf", &X0);
298
sscanf(opt7->answers[3], "%lf", &X1);
307
x0 = l + (int)((r - l) * X0 / 100.);
308
x1 = l + (int)((r - l) * X1 / 100.);
309
y0 = t + (int)((b - t) * (100. - Y0) / 100.); /* make lower left the origin */
310
y1 = t + (int)((b - t) * (100. - Y1) / 100.);
337
D_get_src(&t, &b, &l, &r);
339
if (opt_at->answer != NULL) {
340
sscanf(opt_at->answers[0], "%lf", &Y1);
341
sscanf(opt_at->answers[1], "%lf", &Y0);
342
sscanf(opt_at->answers[2], "%lf", &X0);
343
sscanf(opt_at->answers[3], "%lf", &X1);
357
x0 = l + (int)((r - l) * X0 / 100.);
358
x1 = l + (int)((r - l) * X1 / 100.);
359
y0 = t + (int)((b - t) * (100. - Y0) / 100.); /* make lower left the origin */
360
y1 = t + (int)((b - t) * (100. - Y1) / 100.);
313
362
if (y0 > y1) { /* allow for variety in order of corner */
314
363
flip = !flip; /* selection without broken output */
659
/* this probably shouldn't happen mid-loop as text sizes
718
/* this probably shouldn't happen mid-loop as text sizes
660
719
might not end up being uniform, but it's a start */
661
720
if (strlen(buff) > MaxLabelLen)
662
721
MaxLabelLen = strlen(buff);
666
txsiz = (int)((y1 - y0) / 20);
725
txsiz = (y1 - y0) / 20;
668
txsiz = (int)((x1 - x0) / 20);
727
txsiz = (x1 - x0) / 20;
670
729
/* scale text to fit in window if position not manually set */
671
730
/* usually not needed, except when frame is really narrow */
672
if (!use_mouse && opt7->answer == NULL) { /* ie defualt scaling */
731
if (opt_at->answer == NULL) { /* ie default scaling */
673
732
ScaleFactor = ((r - x1) / ((MaxLabelLen + 1) * txsiz * 0.81)); /* ?? txsiz*.81=actual text width. */
674
733
if (ScaleFactor < 1.0) {
675
txsiz = (int)(txsiz * ScaleFactor);
734
txsiz = txsiz * ScaleFactor;
738
if (opt_fontsize->answer != NULL)
680
742
txsiz = 0; /* keep it sane */
682
R_text_size(txsiz, txsiz);
683
D_raster_use_color(color);
744
D_text_size(txsiz, txsiz);
685
747
ppl = (lleg) / (steps - 1);
688
750
if (!k) /* first */
689
R_move_abs(x1 + 4, y0 + txsiz);
751
D_pos_abs(x1 + 4, y0 + txsiz);
690
752
else if (k == steps - 1) /* last */
691
R_move_abs(x1 + 4, y1);
753
D_pos_abs(x1 + 4, y1);
693
R_move_abs(x1 + 4, y0 + ppl * k + txsiz / 2);
755
D_pos_abs(x1 + 4, y0 + ppl * k + txsiz / 2);
696
/* text width is 0.81 of text height? so even though we set width
697
to txsiz with R_text_size(), we still have to reduce.. hmmm */
758
/* text width is 0.81 of text height? so even though we set width
759
to txsiz with D_text_size(), we still have to reduce.. hmmm */
698
760
if (!k) /* first */
699
R_move_abs(x0 - (strlen(buff) * txsiz * .81 / 2),
761
D_pos_abs(x0 - (strlen(buff) * txsiz * .81 / 2),
701
763
else if (k == steps - 1) /* last */
702
R_move_abs(x1 - (strlen(buff) * txsiz * .81 / 2),
764
D_pos_abs(x1 - (strlen(buff) * txsiz * .81 / 2),
705
R_move_abs(x0 + ppl * k -
706
(strlen(buff) * txsiz * .81 / 2),
767
D_pos_abs(x0 + ppl * k -
768
(strlen(buff) * txsiz * .81 / 2),
719
R_standard_color(black);
720
R_move_abs(x0 + 1, y0 + 1);
721
R_cont_rel(0, lleg - 2);
722
R_cont_rel(wleg - 2, 0);
723
R_cont_rel(0, 2 - lleg);
724
R_cont_rel(2 - wleg, 0);
783
D_move_abs(x0 + 1, y0 + 1);
784
D_cont_rel(0, lleg - 2);
785
D_cont_rel(wleg - 2, 0);
786
D_cont_rel(0, 2 - lleg);
727
R_standard_color(white);
731
R_cont_rel(0, -lleg);
732
R_cont_rel(-wleg, 0);
797
D_cont_rel(0, -lleg);
803
/* print units label, if present */
804
if (maptype == MAP_TYPE_RASTER2D)
805
units = Rast_read_units(map_name, "");
808
/* FIXME: does the raster3d really need to be opened to read the units?
809
units = Rast3d_get_unit(map_fid); */
816
int default_pos = TRUE;
819
/* D_text_size() should be already set */
822
x_pos = (x0 + x1)/2. - (strlen(units) * txsiz * 0.81)/2;
823
y_pos = y1 + (txsiz * 3);
828
y_pos = y0 - (txsiz * 1.75);
830
y_pos = y1 + (txsiz * 2.75);
833
D_pos_abs(x_pos, y_pos);
838
/* display sidebar histogram, if requested */
840
if (opt_range->answer != NULL)
841
G_warning(_("Histogram constrained by range not yet implemented"));
843
draw_histogram(map_name, x0, y0, wleg, lleg, color, flip,
735
else { /* non FP, no smoothing */
848
else { /* non FP, no smoothing */
737
int txsiz, true_l, true_r;
738
852
float ScaleFactor = 1.0;
740
854
/* set legend box bounds */
742
true_r = r; /* preserve window width */
856
true_r = r; /* preserve window width */
750
864
/* figure out box height */
751
865
if (do_cats == cats_num)
814
931
k++; /* count of actual boxes drawn (hide_nodata option invaidates using j-1) */
817
R_standard_color(white);
818
934
cur_dot_row += dots_per_line;
819
R_move_abs(l + 2, (cur_dot_row - 1));
820
R_cont_rel(0, (2 - dots_per_line));
821
R_cont_rel((dots_per_line - 2), 0);
822
R_cont_rel(0, (dots_per_line - 2));
823
R_cont_rel((2 - dots_per_line), 0);
937
D_move_abs(l + 2, (cur_dot_row - 1));
938
D_cont_rel(0, (3 - dots_per_line));
939
D_cont_rel((dots_per_line - 3), 0);
940
D_cont_rel(0, (dots_per_line - 3));
826
R_standard_color(black);
827
R_move_abs(l + 3, (cur_dot_row - 2));
828
R_cont_rel(0, (4 - dots_per_line));
829
R_cont_rel((dots_per_line - 4), 0);
830
R_cont_rel(0, (dots_per_line - 4));
831
R_cont_rel((4 - dots_per_line), 0);
948
D_move_abs(l + 3, (cur_dot_row - 2));
949
D_cont_rel(0, (5 - dots_per_line));
950
D_cont_rel((dots_per_line - 5), 0);
951
D_cont_rel(0, (dots_per_line - 5));
833
956
/* Color solid box */