[GRASS-SVN] r69037 - grass/branches/releasebranch_7_2/display/d.legend
svn_grass at osgeo.org
svn_grass at osgeo.org
Wed Jul 27 11:05:07 PDT 2016
Author: annakrat
Date: 2016-07-27 11:05:07 -0700 (Wed, 27 Jul 2016)
New Revision: 69037
Added:
grass/branches/releasebranch_7_2/display/d.legend/d_legend_custom_labels_and_background.png
grass/branches/releasebranch_7_2/display/d.legend/d_legend_logarithmic.png
grass/branches/releasebranch_7_2/display/d.legend/draw.c
Modified:
grass/branches/releasebranch_7_2/display/d.legend/d.legend.html
grass/branches/releasebranch_7_2/display/d.legend/get_stats.c
grass/branches/releasebranch_7_2/display/d.legend/histogram.c
grass/branches/releasebranch_7_2/display/d.legend/local_proto.h
grass/branches/releasebranch_7_2/display/d.legend/main.c
Log:
d.legend: backport recent GSoC improvements, author Adam Laza
Modified: grass/branches/releasebranch_7_2/display/d.legend/d.legend.html
===================================================================
--- grass/branches/releasebranch_7_2/display/d.legend/d.legend.html 2016-07-27 11:18:55 UTC (rev 69036)
+++ grass/branches/releasebranch_7_2/display/d.legend/d.legend.html 2016-07-27 18:05:07 UTC (rev 69037)
@@ -63,7 +63,9 @@
<p>
The text produced from floating-point raster maps will automatically create
output with a meaningful number of significant digits. For very small values,
-numbers will be expressed in scientific notation, e.g. "1.7e-9".
+numbers will be expressed in scientific notation, e.g. "1.7e-9". Option
+<b>digits</b> can be used to determine how many digits after decimal point
+will be displayed.
<p>
When the <b>-d</b> flag is used to display a histogram distribution along
side the smoothed gradient legend, note that the statistics are calculated
@@ -73,7 +75,25 @@
<p>
If the raster map's <i>units</i> metadata has been set with the
<em>r.support</em> module then it will be displayed along side the legend.
-
+<p>
+The option <b>title</b> will display the custom title at the top of the legend.
+In case of vertical legend the title is aligned to the left edge of legend, in case
+of horizontal legend the title is aligned to the center. <b>title_fontsize</b> can
+be used to set the size of legend title. By default the legend title font size is
+the same as labels font size.
+<p>
+There are different options to customize displayed labels. The <b>labelnum</b> set
+the number of labels which are displayed in regular intervals. The <b>label_values</b>
+will specify the values where the labels will be displayed. The <b>label_step</b> will
+display labels at values which are divisible by this value.
+<p>
+The flag <b>-t</b> will show ticks at labels.
+<p>
+The flag <b>-b</b> will show the background. Options <b>bgcolor</b> and <b>border_color</b> can be
+used to choose the color of border and background fill.
+<p>
+The flag <b>-l</b> will switch to logarithmic scale. In case this flag is used,
+the provided step in <b>label_step</b> is interpreted in the logarithmic space.
<h2>EXAMPLE</h2>
Displaying the legend along with a histogram (North Carolina Sample dataset):
@@ -88,7 +108,33 @@
<img src="d_legend.png" alt="Elevation map with legend" border=1>
</center>
+Displaying the legend with custom labels and background:
+<div class="code"><pre>
+g.region raster=elevation -p
+d.rast elevation
+d.legend raster=elevation -t label_step=20 label_values=108 title=Legend -b bgcolor=255:255:204 border_color=gray
+</pre></div>
+
+<center>
+<img src="d_legend_custom_labels_and_background.png" alt="Elevation map with custom legend" border=1>
+</center>
+
+Displaying the legend with logarithmic scale:
+
+<div class="code"><pre>
+g.region raster=elevation -p
+r.watershed -a elevation=elevation threshold=1000 accumulation=flowacc
+d.rast flowacc
+d.legend raster=flowacc -t -l label_step=1
+</pre></div>
+
+<center>
+<img src="d_legend_logarithmic.png" alt="Flow accumulation map with logarithmic legend" border=1>
+</center>
+
+
+
<h2>SEE ALSO</h2>
<em>
Copied: grass/branches/releasebranch_7_2/display/d.legend/d_legend_custom_labels_and_background.png (from rev 68759, grass/trunk/display/d.legend/d_legend_custom_labels_and_background.png)
===================================================================
(Binary files differ)
Copied: grass/branches/releasebranch_7_2/display/d.legend/d_legend_logarithmic.png (from rev 68759, grass/trunk/display/d.legend/d_legend_logarithmic.png)
===================================================================
(Binary files differ)
Copied: grass/branches/releasebranch_7_2/display/d.legend/draw.c (from rev 68699, grass/trunk/display/d.legend/draw.c)
===================================================================
--- grass/branches/releasebranch_7_2/display/d.legend/draw.c (rev 0)
+++ grass/branches/releasebranch_7_2/display/d.legend/draw.c 2016-07-27 18:05:07 UTC (rev 69037)
@@ -0,0 +1,1364 @@
+/* draw.c:
+ * Compute position of legend, title, labels and ticks
+ * Extracted from original d.legend/main.c for background purpose
+ * Moving to seperate file: Adam Laza, GSoC 2016
+ *
+ * Copyright (C) 2014 by Hamish Bowman, and the GRASS Development Team*
+ * This program is free software under the GPL (>=v2)
+ * Read the COPYING file that comes with GRASS for details.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <grass/gis.h>
+#include <grass/raster.h>
+#include <grass/raster3d.h>
+#include <grass/display.h>
+#include <grass/glocale.h>
+#include "local_proto.h"
+
+void draw(const char *map_name, int maptype, int color, int thin, int lines,
+ int steps, int fp, int label_indent, int hide_catnum,
+ int hide_catstr, int show_ticks, int hide_nodata, int do_smooth,
+ struct Categories cats, struct Colors colors, double X0, double X1,
+ double Y0, double Y1, int flip, int UserRange, double UserRangeMin,
+ double UserRangeMax, double *catlist, int catlistCount,
+ int use_catlist, int ticksCount, double fontsize,
+ double tit_fontsize, const char *title, double *tick_values,
+ double t_step, int colorb, int colorbg, struct Option *opt_use,
+ struct Option *opt_at, struct Option *opt_fontsize,
+ struct Option *opt_tstep, struct Option *opt_range, struct Flag *histo,
+ struct Flag *hidestr, int log_sc, int draw, int digits, char *units)
+{
+ char buff[512];
+ int black, white;
+ int cats_num;
+ int cur_dot_row;
+ int do_cats;
+ int dots_per_line;
+ int i, j, k;
+ double t, b, l, r;
+ char *cstr;
+ double x_box[5], y_box[5];
+ struct Range range;
+ struct FPRange fprange, render_range;
+ CELL min_ind, max_ind;
+ DCELL dmin, dmax, val;
+ CELL min_colr, max_colr;
+ DCELL min_dcolr, max_dcolr;
+ int x0, x1, y0, y1, xyTemp;
+ int SigDigits;
+ unsigned int MaxLabelLen;
+ char DispFormat[5]; /* %.Xf\0 */
+ double maxCat;
+ int horiz;
+ char *units_bottom;
+ double t_start;
+ double max_hist;
+ double txsiz, titsiz;
+ int tcell;
+ float ScaleFactor = 1.0;
+ double x_tit, y_tit, x1_tit;
+ double x0bg, y0bg, x1bg, y1bg;
+ double wleg, lleg;
+ int true_l, true_r;
+ int dx, dy;
+ double coef;
+ double ppl;
+ double bb,bt,bl,br;
+ char MaxLabel[512];
+ double num;
+ int MaxLabelW, LabelW;
+
+
+ if (draw) {
+ /* init colors */
+ black = D_translate_color(DEFAULT_FG_COLOR);
+ white = D_translate_color(DEFAULT_BG_COLOR);
+ }
+
+ /* Figure out where to put text */
+ D_setup_unity(0);
+ D_get_src(&t, &b, &l, &r);
+
+ x0 = l + (int)((r - l) * X0 / 100.);
+ x1 = l + (int)((r - l) * X1 / 100.);
+ y0 = t + (int)((b - t) * (100. - Y0) / 100.); /* make lower left the origin */
+ y1 = t + (int)((b - t) * (100. - Y1) / 100.);
+
+ if (y0 > y1) { /* allow for variety in order of corner */
+ flip = !flip; /* selection without broken output */
+ xyTemp = y0;
+ y0 = y1;
+ y1 = xyTemp;
+ }
+ if (x0 > x1) {
+ xyTemp = x0;
+ x0 = x1;
+ x1 = xyTemp;
+ }
+
+ if (x0 == x1)
+ x1++; /* avoid 0 width boxes */
+ if (y0 == y1)
+ y1++;
+
+ if (draw) {
+ if ((x0 < l) || (x1 > r) || (y0 < t) || (y1 > b)) /* for mouse or at= 0- or 100+; needs to be after order check */
+ G_warning(_("Legend box lies outside of frame. Text may not display properly."));
+ }
+
+ horiz = (x1 - x0 > y1 - y0);
+ if (horiz && draw)
+ G_message(_("Drawing horizontal legend as box width exceeds height"));
+
+ if (!fp && horiz) /* better than nothing */
+ do_smooth = TRUE;
+
+ MaxLabelLen = 0; /* init variable */
+ MaxLabelW = 0;
+
+ /* How many categories to show */
+ /* not fp */
+ if (!fp) {
+ if (Rast_read_range(map_name, "", &range) == -1)
+ G_fatal_error(_("Range information for <%s> not available (run r.support)"),
+ map_name);
+
+ Rast_get_range_min_max(&range, &min_ind, &max_ind);
+ if (Rast_is_c_null_value(&min_ind))
+ G_fatal_error(_("Input map contains no data"));
+
+ Rast_get_c_color_range(&min_colr, &max_colr, &colors);
+
+ if (UserRange) {
+ if (min_ind < UserRangeMin)
+ min_ind = (int)ceil(UserRangeMin);
+ if (max_ind > UserRangeMax)
+ max_ind = (int)floor(UserRangeMax);
+ if (min_ind > UserRangeMin) {
+ min_ind =
+ UserRangeMin <
+ min_colr ? min_colr : (int)ceil(UserRangeMin);
+ if (draw)
+ G_warning(_("Requested range exceeds lower limit of actual data"));
+ }
+ if (max_ind < UserRangeMax) {
+ max_ind =
+ UserRangeMax >
+ max_colr ? max_colr : (int)floor(UserRangeMax);
+ if (draw)
+ G_warning(_("Requested range exceeds upper limit of actual data"));
+ }
+ }
+
+ /* cats_num is total number of categories in raster */
+ /* do_cats is total number of categories to be displayed */
+ /* k is number of cats to be displayed after skipping unlabeled cats */
+ /* lines is number of text lines/legend window */
+
+ cats_num = max_ind - min_ind + 1;
+
+ if (lines == 0)
+ lines = cats_num;
+
+ do_cats = cats_num > lines ? lines : cats_num;
+
+ if (do_cats == cats_num)
+ lines = (int)ceil((1.0 * lines) / thin);
+
+ if (!use_catlist) {
+ catlist = (double *)G_calloc(lines + 1, sizeof(double));
+ catlistCount = lines;
+ }
+ /* see how many boxes there REALLY will be */
+ maxCat = 0.0;
+ for (i = min_ind, j = 1, k = 0; j <= do_cats && i <= max_ind;
+ j++, i += thin) {
+ if (!flip)
+ cstr = Rast_get_c_cat(&i, &cats);
+ else {
+ CELL cat = max_ind - (i - min_ind);
+
+ cstr = Rast_get_c_cat(&cat, &cats);
+ }
+
+ if (!use_catlist)
+ catlist[j - 1] = (double)i;
+
+ if (!cstr[0]) { /* no cat label found, skip str output */
+ if (hide_nodata)
+ continue;
+ }
+ else { /* ie has a label */
+ if (!hide_catstr && (MaxLabelLen < strlen(cstr))) {
+ MaxLabelLen = strlen(cstr);
+ sprintf(MaxLabel, "%s", cstr);
+ }
+ }
+
+ if (!hide_catnum)
+ if (i > maxCat)
+ maxCat = (double)i;
+ k++; /* count of actual boxes drawn (hide_nodata option invaidates using j-1) */
+ }
+ lines = k;
+
+ /* figure out how long the category + label will be */
+ if (use_catlist) {
+ MaxLabelLen = 0;
+ maxCat = 0; /* reset */
+ for (i = 0, k = 0; i < catlistCount; i++) {
+ if ((catlist[i] < min_ind) || (catlist[i] > max_ind)) {
+ G_fatal_error(_("use=%s out of range [%d,%d] (extend with range= ?)"),
+ opt_use->answers[i], min_ind, max_ind);
+ }
+
+ cstr = Rast_get_d_cat(&catlist[i], &cats);
+ if (!cstr[0]) { /* no cat label found, skip str output */
+ if (hide_nodata)
+ continue;
+ }
+ else { /* ie has a label */
+ if (!hide_catstr && (MaxLabelLen < strlen(cstr)))
+ MaxLabelLen = strlen(cstr);
+ }
+ if (!hide_catnum)
+ if (catlist[i] > maxCat)
+ maxCat = catlist[i];
+ k++;
+ }
+ if (0 == k) /* nothing to draw */
+ lines = 0;
+ }
+
+ /* following covers both the above if(do_cats == cats_num) and k++ loop */
+ if (lines < 1) {
+ lines = 1; /* ward off the dpl floating point exception */
+ G_fatal_error(_("Nothing to draw! (no categories with labels? out of range?)"));
+ }
+
+ /* Figure number of lines, number of pixles per line and text size */
+ dots_per_line = ((y1 - y0) / lines);
+
+ /* switch to a smooth legend for CELL maps with too many cats */
+ /* an alternate solution is to set dots_per_line=1 */
+ if ((dots_per_line == 0) && (do_smooth == FALSE)) {
+ if (!use_catlist) {
+ if (draw)
+ G_message(_("Forcing a smooth legend: too many categories for current window height"));
+ do_smooth = TRUE;
+ }
+ }
+
+ /* center really tiny legends */
+ if (opt_at->answer == NULL) { /* if defualt scaling */
+ if (!do_smooth && (dots_per_line < 4)) /* if so small that there's no box */
+ if ((b - (dots_per_line * lines)) / (b * 1.0) > 0.15) /* if there's more than a 15% blank at the bottom */
+ y0 = ((b - t) - (dots_per_line * lines)) / 2;
+ }
+
+ /* D_text_size(dots_per_line*4/5., dots_per_line*4/5.); redundant */
+ /* if(Rast_is_c_null_value(&min_ind) && Rast_is_c_null_value(&max_ind))
+ {
+ min_ind = 1;
+ max_ind = 0;
+ } */
+
+ if (horiz)
+ sprintf(DispFormat, "%%d");
+ else {
+ if (maxCat > 0.0)
+ sprintf(DispFormat, "%%%dd", (int)(log10(fabs(maxCat))) + 1);
+ else
+ sprintf(DispFormat, "%%2d");
+ }
+ } /* end of if(!fp) */
+
+ else { /* is fp */
+ if (maptype == MAP_TYPE_RASTER2D) {
+ if (Rast_read_fp_range(map_name, "", &fprange) == -1)
+ G_fatal_error(_("Range information for <%s> not available"),
+ map_name);
+ }
+ else {
+ if (Rast3d_read_range(map_name, "", &fprange) == -1)
+ G_fatal_error(_("Range information for <%s> not available"),
+ map_name);
+ }
+
+ Rast_get_fp_range_min_max(&fprange, &dmin, &dmax);
+ Rast_get_d_color_range(&min_dcolr, &max_dcolr, &colors);
+
+ if (UserRange) {
+ if (dmin < UserRangeMin)
+ dmin = UserRangeMin;
+ if (dmax > UserRangeMax)
+ dmax = UserRangeMax;
+ if (dmin > UserRangeMin) {
+ dmin = UserRangeMin < min_dcolr ? min_dcolr : UserRangeMin;
+ G_warning(_("Color range exceeds lower limit of actual data"));
+ }
+ if (dmax < UserRangeMax) {
+ dmax = UserRangeMax > max_dcolr ? max_dcolr : UserRangeMax;
+ G_warning(_("Color range exceeds upper limit of actual data"));
+ }
+ }
+
+ /* In case of log. scale raster doesn't contain negative or zero values */
+ if (log_sc)
+ if ((dmin<=0) || (dmax<=0))
+ G_fatal_error(_("Range [%.3f, %.3f] out of the logarithm domain."),
+ dmin, dmax);
+
+
+ if (use_catlist) {
+ for (i = 0; i < catlistCount; i++) {
+ if ((catlist[i] < dmin) || (catlist[i] > dmax)) {
+ G_fatal_error(_("use=%s out of range [%.3f, %.3f] (extend with range= ?)"),
+ opt_use->answers[i], dmin, dmax);
+ }
+ if (strlen(opt_use->answers[i]) > MaxLabelLen)
+ MaxLabelLen = strlen(opt_use->answers[i]);
+ }
+ }
+ do_cats = 0; /* if only to get rid of the compiler warning */
+ cats_num = 0; /* if only to get rid of the compiler warning */
+ /* determine how many significant digits to display based on range */
+ if (digits != -1) /* number of digits given by user */
+ sprintf(DispFormat, "%%.%df", digits);
+ else {/* automatic calculation */
+ if (0 == (dmax - dmin)) /* trap divide by 0 for single value rasters */
+ sprintf(DispFormat, "%%f");
+ else {
+ SigDigits = (int)ceil(log10(fabs(25 / (dmax - dmin))));
+ if (SigDigits < 0)
+ SigDigits = 0;
+ if (SigDigits < 7)
+ sprintf(DispFormat, "%%.%df", SigDigits);
+ else
+ sprintf(DispFormat, "%%.2g"); /* eg 4.2e-9 */
+ }
+ }
+ } /* end of is fp */
+
+ if (use_catlist) {
+ cats_num = catlistCount;
+ do_cats = catlistCount;
+ lines = catlistCount;
+ do_smooth = FALSE;
+ }
+
+
+ if (do_smooth) {
+ if (horiz) {
+ if (draw) {
+ lleg = x1 - x0;
+ dx = 0;
+ dy = y1 - y0;
+ }
+ if (fp)
+ flip = !flip; /* horiz floats look better not flipped by default */
+ }
+ else {
+ if (draw) {
+ lleg = y1 - y0;
+ dy = 0;
+ dx = x1 - x0;
+ }
+ }
+
+ /* Draw colors */
+ /* Draw the legend bar */
+ if (draw) {
+ for (k = 0; k < lleg; k++) {
+ if (log_sc) { /* logarithmic scale */
+ num = k / lleg;
+ val = dmin * pow(dmax/dmin, num);
+ D_d_color(val, &colors);
+ if (!flip) {
+ if (horiz)
+ D_box_abs(x0 + k, y0, x0 + k + 1, y0 + dy);
+ else
+ D_box_abs(x0, y0 + k, x0 + dx, y0 + k + 1);
+ }
+ else {
+ if (horiz)
+ D_box_abs(x1 - k, y0, x1 - k - 1, y0 + dy);
+ else
+ D_box_abs(x0, y1 - k, x0 + dx, y1 - k - 1);
+ }
+
+ } /* linear scale */
+ else{
+ if (!fp) {
+ if (!flip)
+ tcell = min_ind + k * (double)(1 + max_ind - min_ind) / lleg;
+ else
+ tcell = (max_ind + 1) - k * (double)(1 + max_ind - min_ind) / lleg;
+ D_color((CELL) tcell, &colors);
+ }
+ else {
+ if (!flip)
+ val = dmin + k / lleg * (dmax - dmin);
+ else
+ val = dmax - k / lleg * (dmax - dmin);
+ D_d_color(val, &colors);
+ }
+
+ if (dx < dy)
+ D_box_abs(x0 + k, y0, x0 + k + (dx ? -dx : 1),
+ y0 - (dy ? -dy : 1));
+ else
+ D_box_abs(x0, y0 + k, x0 - (dx ? -dx : 1),
+ y0 + k + (dy ? -dy : 1));
+ }
+ }
+ }
+
+ /* Format text */
+ if (!fp) { /* cut down labelnum so they don't repeat */
+ if (do_cats < steps)
+ steps = do_cats;
+ }
+
+ /* Draw text and ticks */
+ if (!horiz)
+ txsiz = (y1 - y0) / 20;
+ else
+ txsiz = (x1 - x0) / 20;
+
+ wleg = x1 - x0;
+ lleg = y1 - y0;
+
+ /* scale text to fit in window if position not manually set */
+ /* usually not needed, except when frame is really narrow */
+ if (opt_at->answer == NULL) { /* ie default scaling */
+ ScaleFactor = ((r - x1) / ((MaxLabelLen + 1) * txsiz * 0.81)); /* ?? txsiz*.81=actual text width. */
+ if (ScaleFactor < 1.0) {
+ txsiz = txsiz * ScaleFactor;
+ }
+ }
+
+ if (opt_fontsize->answer != NULL)
+ txsiz = fontsize;
+
+ if (txsiz < 0)
+ txsiz = 0; /* keep it sane */
+
+ if (tit_fontsize == 0)
+ titsiz = txsiz;
+ else
+ titsiz = tit_fontsize;
+
+ if (draw) {
+ D_text_size(txsiz, txsiz);
+ D_use_color(color);
+ }
+
+ /* Draw labels and ticks */
+ /* LABELNUM OPTION */
+ if (steps >= 2) {
+ for (k = 0; k < steps; k++) {
+ if (!fp) {
+ if (!flip)
+ tcell =
+ min_ind + k * (double)(max_ind -
+ min_ind) / (steps - 1);
+ else
+ tcell =
+ max_ind - k * (double)(max_ind -
+ min_ind) / (steps - 1);
+
+ if (!cstr[0]) /* no cats found, disable str output */
+ hide_catstr = 1;
+ else
+ hide_catstr = hidestr->answer;
+
+ buff[0] = 0; /* blank string */
+
+ if (!hide_catnum) { /* num */
+ sprintf(buff, DispFormat, tcell);
+ if (!hide_catstr) /* both */
+ strcat(buff, ")");
+ D_text_size(txsiz, txsiz);
+ D_get_text_box(buff,&bb,&bt, &bl, &br);
+ LabelW = br - bl;
+ if (LabelW > MaxLabelW) {
+ MaxLabelW = LabelW;
+ sprintf(MaxLabel, "%s", buff);
+ }
+ }
+ if (!hide_catstr) { /* str */
+ sprintf(buff + strlen(buff), " %s", cstr);
+ if (strlen(units)>0)
+ strcat(buff, units);
+ D_text_size(txsiz, txsiz);
+ D_get_text_box(buff,&bb,&bt, &bl, &br);
+ LabelW = br - bl;
+ if (LabelW > MaxLabelW) {
+ MaxLabelW = LabelW;
+ sprintf(MaxLabel, "%s", buff);
+ }
+ }
+ }
+ else { /* ie FP map */
+ if (hide_catnum)
+ buff[0] = 0; /* no text */
+ else {
+ if (log_sc) {
+ num = log10(dmax) - k * ((log10(dmax) - log10(dmin)) / (steps - 1));
+ val = pow(10,num);
+ }
+ else{
+ if (!flip)
+ val = dmin + k * (dmax - dmin) / (steps - 1);
+ else
+ val = dmax - k * (dmax - dmin) / (steps - 1);
+ }
+ sprintf(buff, DispFormat, val);
+ if (strlen(units)>0)
+ strcat(buff, units);
+ D_text_size(txsiz, txsiz);
+ D_get_text_box(buff,&bb,&bt, &bl, &br);
+ LabelW = br - bl;
+ if (LabelW > MaxLabelW) {
+ MaxLabelW = LabelW;
+ sprintf(MaxLabel, "%s", buff);
+ }
+ }
+ }
+
+ if (draw) {
+ if (!hide_catnum) {
+ D_text_size(txsiz, txsiz);
+ D_get_text_box(buff, &bb, &bt, &bl, &br);
+ if (!horiz) {
+ if (log_sc) {
+ coef = (log10(val) - log10(dmin)) / (log10(dmax) - log10(dmin));
+ if (flip)
+ D_pos_abs(x1 + label_indent,
+ y1 - coef * lleg + (bb - bt) / 2);
+ else
+ D_pos_abs(x1 + label_indent,
+ y0 + coef * lleg + (bb - bt) / 2);
+ }
+ else {
+ ppl = (lleg) / (steps * 1.0 - 1);
+ D_pos_abs(x1 + label_indent,
+ y0 + ppl * k + (bb - bt) / 2);
+ }
+ if (show_ticks) {
+ D_use_color(black);
+ if (log_sc)
+ if (flip)
+ D_line_abs(x1, y1 - coef * lleg,
+ x1 + 6, y1 - coef * lleg);
+ else
+ D_line_abs(x1, y0 + coef * lleg,
+ x1 + 6, y0 + coef * lleg);
+ else
+ D_line_abs(x1, y0 + ppl * k,
+ x1 + 6, y0 + ppl * k);
+ }
+ }
+ else {
+ if (log_sc) {
+ coef = (log10(val) - log10(dmin)) / (log10(dmax) - log10(dmin));
+ if (flip)
+ D_pos_abs(x1 - coef * wleg - ((br - bl) / 2),
+ y1 + label_indent + txsiz);
+ else
+ D_pos_abs(x0 + coef * wleg - ((br - bl) / 2),
+ y1 + label_indent + txsiz);
+ }
+ else {
+ ppl = (wleg) / (steps * 1.0 - 1);
+ D_pos_abs(x0 + ppl * k - ((br - bl) / 2),
+ y1 + label_indent + txsiz);
+ }
+ if (show_ticks) {
+ D_use_color(black);
+ if (log_sc)
+ if (flip)
+ D_line_abs(x1 - coef * wleg, y1,
+ x1 - coef * wleg, y1 + 6);
+ else
+ D_line_abs(x0 + coef * wleg, y1,
+ x0 + coef * wleg, y1 + 6);
+ else
+ D_line_abs(x0 + ppl * k, y1,
+ x0 + ppl * k, y1 + 6);
+ }
+ }
+ if (color)
+ D_use_color(color);
+ D_text(buff);
+ }
+ }
+ } /* for */
+ }
+
+ if (!fp) {
+ dmin = min_ind;
+ dmax = max_ind;
+ sprintf(DispFormat, "%s", "%.0f");
+ }
+
+ /* LABEL_VALUE OPTION */
+ if (ticksCount > 0) {
+ for (i = 0; i < ticksCount; i++) {
+ if ((tick_values[i] < dmin) || (tick_values[i] > dmax)) {
+ G_fatal_error(_("tick_value=%.3f out of range [%.3f, %.3f]"),
+ tick_values[i], dmin, dmax);
+ }
+ sprintf(buff, DispFormat, tick_values[i]);
+ if (strlen(units)>0)
+ strcat(buff, units);
+ D_text_size(txsiz, txsiz);
+ D_get_text_box(buff,&bb,&bt, &bl, &br);
+ LabelW = br - bl;
+ if (LabelW > MaxLabelW) {
+ MaxLabelW = LabelW;
+ sprintf(MaxLabel, "%s", buff);
+ }
+
+ if (log_sc) {
+ coef = (log10(tick_values[i]) - log10(dmin)) / (log10(dmax) - log10(dmin));
+ }
+ else
+ coef = (tick_values[i] - dmin) / ((dmax - dmin) * 1.0);
+
+ if (draw) {
+ if (!flip) {
+ if (!horiz) {
+ if (show_ticks) {
+ D_use_color(black);
+ D_line_abs(x1, y0 + coef * lleg,
+ x1 + 6, y0 + coef * lleg);
+ }
+ D_pos_abs(x1 + label_indent,
+ y0 + coef * lleg + txsiz / 2);
+ }
+ else {
+ if (show_ticks) {
+ D_use_color(black);
+ D_line_abs(x0 + coef * wleg, y1,
+ x0 + coef * wleg, y1 + 6);
+ }
+ D_pos_abs(x0 + coef * wleg -
+ (strlen(buff) * txsiz * .81 / 2),
+ y1 + label_indent + txsiz);
+ }
+ }
+ else {
+ if (!horiz) {
+ if (show_ticks) {
+ D_use_color(black);
+ D_line_abs(x1, y1 - coef * lleg,
+ x1 + 6, y1 - coef * lleg);
+ }
+ D_pos_abs(x1 + label_indent,
+ y1 - coef * lleg + txsiz / 2);
+ }
+ else {
+ if (show_ticks) {
+ D_use_color(black);
+ D_line_abs(x1 - coef * wleg, y1,
+ x1 - coef * wleg, y1 + 6);
+ }
+ D_pos_abs(x1 - coef * wleg -
+ (strlen(buff) * txsiz * .81 / 2),
+ y1 + label_indent + txsiz);
+ }
+ }
+ D_use_color(color);
+ D_text(buff);
+ }
+ }
+ }
+
+ /* LABEL_STEP OPTION */
+ if (opt_tstep->answer) {
+ if (log_sc) { /* logarithmic */
+ t_start=0;
+ while (log10(dmin) + t_start < log10(dmax)){
+ num = ceil(log10(dmin)) + t_start;
+ val = pow(10,num);
+ sprintf(buff, DispFormat, val);
+ if (strlen(units)>0)
+ strcat(buff, units);
+ D_text_size(txsiz, txsiz);
+ D_get_text_box(buff,&bb,&bt, &bl, &br);
+ LabelW = br - bl;
+ if (LabelW > MaxLabelW) {
+ MaxLabelW = LabelW;
+ sprintf(MaxLabel, "%s", buff);
+ }
+ coef = (log10(val) - log10(dmin)) / (log10(dmax) - log10(dmin));
+ if (draw){
+ if (!flip){
+ if (!horiz){
+ if (show_ticks) {
+ D_use_color(black);
+ D_line_abs(x1, y0 + coef * lleg,
+ x1 + 6, y0 + coef * lleg);
+ }
+ D_pos_abs(x1 + label_indent,
+ y0 + coef * lleg + txsiz / 2);
+ }
+ else{
+ if (show_ticks) {
+ D_use_color(black);
+ D_line_abs(x0 + coef * wleg, y1,
+ x0 + coef * wleg, y1 + 6);
+ }
+ D_pos_abs(x0 + coef * wleg -
+ (strlen(buff) * txsiz * .81 / 2),
+ y1 + label_indent + txsiz);
+ }
+ }
+ else{
+ if (!horiz){
+ if (show_ticks) {
+ D_use_color(black);
+ D_line_abs(x1, y1 - coef * lleg,
+ x1 + 6, y1 - coef * lleg);
+ }
+ D_pos_abs(x1 + label_indent,
+ y1 - coef * lleg + txsiz / 2);
+ }
+ else{
+ if (show_ticks){
+ D_use_color(black);
+ D_line_abs(x1 - coef * wleg, y1,
+ x1 - coef * wleg, y1 + 6);
+ }
+ D_pos_abs(x1 - coef * wleg -
+ (strlen(buff) * txsiz * .81 / 2),
+ y1 + label_indent + txsiz);
+ }
+ }
+ D_use_color(color);
+ D_text(buff);
+
+ }
+ t_start += t_step;
+ }
+ }
+ else { /* linear */
+ t_start = ceil(dmin / t_step) * t_step;
+ if (t_start == -0)
+ t_start = 0;
+
+ if (!flip) {
+ if (!horiz)
+ while (t_start <= dmax) {
+ sprintf(buff, DispFormat, t_start);
+ if (strlen(units)>0)
+ strcat(buff, units);
+ D_text_size(txsiz, txsiz);
+ D_get_text_box(buff,&bb,&bt, &bl, &br);
+ LabelW = br - bl;
+ if (LabelW > MaxLabelW) {
+ MaxLabelW = LabelW;
+ sprintf(MaxLabel, "%s", buff);
+ }
+ if (draw) {
+ coef = (t_start - dmin) / ((dmax - dmin) * 1.0);
+ if (show_ticks) {
+ D_use_color(black);
+ D_line_abs(x1, y0 + coef * lleg,
+ x1 + 6, y0 + coef * lleg);
+ }
+ D_pos_abs(x1 + label_indent,
+ y0 + coef * lleg + txsiz / 2);
+ D_use_color(color);
+ D_text(buff);
+ }
+ t_start += t_step;
+ }
+ else
+ while (t_start <= dmax) {
+ sprintf(buff, DispFormat, t_start);
+ if (strlen(units)>0)
+ strcat(buff, units);
+ D_text_size(txsiz, txsiz);
+ D_get_text_box(buff,&bb,&bt, &bl, &br);
+ LabelW = br - bl;
+ if (LabelW > MaxLabelW) {
+ MaxLabelW = LabelW;
+ sprintf(MaxLabel, "%s", buff);
+ }
+
+ if (draw) {
+ coef = (t_start - dmin) / ((dmax - dmin) * 1.0);
+ if (show_ticks) {
+ D_use_color(black);
+ D_line_abs(x0 + coef * wleg, y1,
+ x0 + coef * wleg, y1 + 6);
+ }
+ D_pos_abs(x0 + coef * wleg -
+ (strlen(buff) * txsiz * .81 / 2),
+ y1 + label_indent + txsiz);
+ D_use_color(color);
+ D_text(buff);
+ }
+ t_start += t_step;
+ }
+ }
+ else {
+ if (!horiz)
+ while (t_start <= dmax) {
+ sprintf(buff, DispFormat, t_start);
+ if (strlen(units)>0)
+ strcat(buff, units);
+ D_text_size(txsiz, txsiz);
+ D_get_text_box(buff,&bb,&bt, &bl, &br);
+ LabelW = br - bl;
+ if (LabelW > MaxLabelW) {
+ MaxLabelW = LabelW;
+ sprintf(MaxLabel, "%s", buff);
+ }
+
+ if (draw) {
+ coef = (t_start - dmin) / ((dmax - dmin) * 1.0);
+ if (show_ticks) {
+ D_use_color(black);
+ D_line_abs(x1, y1 - coef * lleg,
+ x1 + 6, y1 - coef * lleg);
+ }
+ D_pos_abs(x1 + label_indent,
+ y1 - coef * lleg + txsiz / 2);
+ D_use_color(color);
+ D_text(buff);
+ }
+ t_start += t_step;
+ }
+ else
+ while (t_start <= dmax) {
+ sprintf(buff, DispFormat, t_start);
+ if (strlen(units)>0)
+ strcat(buff, units);
+ D_text_size(txsiz, txsiz);
+ D_get_text_box(buff,&bb,&bt, &bl, &br);
+ LabelW = br - bl;
+ if (LabelW > MaxLabelW) {
+ MaxLabelW = LabelW;
+ sprintf(MaxLabel, "%s", buff);
+ }
+
+ if (draw) {
+ coef = (t_start - dmin) / ((dmax - dmin) * 1.0);
+ if (show_ticks){
+ D_use_color(black);
+ D_line_abs(x1 - coef * wleg, y1,
+ x1 - coef * wleg, y1 + 6);
+ }
+ D_pos_abs(x1 - coef * wleg -
+ (strlen(buff) * txsiz * .81 / 2),
+ y1 + label_indent + txsiz);
+ D_use_color(color);
+ D_text(buff);
+ }
+ t_start += t_step;
+ }
+ }
+ }
+ }
+
+ if (draw) {
+ /* Draw boxes outside of legend bar */
+ /* White box */
+ D_use_color(white);
+ D_begin();
+ D_move_abs(x0 + 1, y0 + 1);
+ D_cont_rel(0, lleg - 2);
+ D_cont_rel(wleg - 2, 0);
+ D_cont_rel(0, -lleg + 2);
+ D_close();
+ D_end();
+ D_stroke();
+
+ /* Black box */
+ D_use_color(black);
+ D_begin();
+ D_move_abs(x0, y0);
+ D_cont_rel(0, lleg);
+ D_cont_rel(wleg, 0);
+ D_cont_rel(0, -lleg);
+ D_close();
+ D_end();
+ D_stroke();
+ }
+
+ /* Display sidebar histogram, if requested.
+ / In case of horizontal legend, maximum of histogram - max_hist
+ will efect the title position */
+ max_hist = 0;
+ if (histo->answer) {
+ render_range.min = (DCELL) (fp ? dmin : min_ind);
+ render_range.max = (DCELL) (fp ? dmax : max_ind);
+ /* reuse flag to indicate if user-specified or default ranging */
+ render_range.first_time = opt_range->answer ? TRUE : FALSE;
+
+ if (draw)
+ max_hist =
+ histogram(map_name, x0, y0, wleg, lleg, color, flip,
+ horiz, maptype, fp, render_range, 1);
+ else
+ max_hist =
+ histogram(map_name, x0, y0, wleg, lleg, color, flip,
+ horiz, maptype, fp, render_range, 0);
+ }
+
+
+ /* display title or units */
+ if (strlen(title) > 0) {
+ D_text_size(titsiz, titsiz);
+ D_get_text_box(title, &bb, &bt, &bl, &br);
+ /* title */
+ if (horiz) {
+ x_tit = (x0 + x1) / 2. - (br - bl) / 2;
+ y_tit = y0 - (titsiz) - max_hist;
+ }
+ else {
+ x_tit = x0;
+ y_tit = y0 - txsiz;
+ }
+
+ x1_tit = x_tit + (br - bl);
+
+ if (draw) {
+ D_use_color(color);
+ /* use tit_fontsize */
+ D_text_size(titsiz, titsiz);
+
+ D_pos_abs(x_tit, y_tit);
+ D_text(title);
+ /* restart fontsize */
+ D_text_size(txsiz, txsiz);
+ }
+ }
+ else {
+ /* units */
+ /* print units label, if present */
+ if (maptype == MAP_TYPE_RASTER2D)
+ units_bottom = Rast_read_units(map_name, "");
+ else
+ units = "";
+ /* FIXME: does the raster3d really need to be opened to read the units?
+ units_bottom = Rast3d_get_unit(map_fid); */
+
+ if (!units_bottom)
+ units_bottom = "";
+
+ if (strlen(units_bottom)) {
+ D_text_size(titsiz, titsiz);
+ D_get_text_box(title, &bb, &bt, &bl, &br);
+ if (horiz) {
+ x_tit =
+ (x0 + x1) / 2. - (br - bl) / 2;
+ y_tit = y1 + (txsiz * 2.75);
+ }
+ else {
+ x_tit = x0;
+ }
+ x1_tit = x_tit + (br - bl);
+
+ if (draw) {
+ D_use_color(color);
+ D_pos_abs(x_tit, y_tit);
+ D_text(units_bottom);
+ }
+ }
+ } /* end of display units) */
+
+ if (!draw) {
+ /* Draw background */
+ D_text_size(txsiz, txsiz);
+ D_get_text_box(MaxLabel, &bb, &bt, &bl, &br);
+ if (!horiz) {
+ x0bg = x0 - max_hist - txsiz;
+ x1bg = x0 + wleg + label_indent + (br - bl) + txsiz;
+ if (x1bg < x1_tit)
+ x1bg = x1_tit + txsiz;
+ y1bg = y0 + lleg + txsiz;
+ if (strlen(title) > 0)
+ y0bg = y0 - titsiz -2 * txsiz;
+ else
+ y0bg = y0 - txsiz;
+ }
+ else {
+ x0bg = x0 - (br - bl) / 2 - txsiz;
+ x1bg = x0 + wleg + (br - bl) / 2 + txsiz;
+ if (x1bg < x1_tit) {
+ x0bg = x_tit - txsiz;
+ x1bg = x1_tit + txsiz;
+ }
+ y1bg = y0 + lleg + label_indent + 1.5 * txsiz;
+ if (strlen(title) > 0)
+ y0bg = y0 - (2.5 * titsiz) - max_hist;
+ else
+ y0bg = y0 - titsiz - max_hist;
+ }
+
+ if (colorbg != 0) {
+ D_use_color(colorbg);
+ D_box_abs(x0bg, y0bg, x1bg, y1bg);
+ }
+
+ D_use_color(colorb);
+ D_begin();
+ D_move_abs(x0bg, y0bg);
+ D_cont_abs(x0bg, y1bg);
+ D_cont_abs(x1bg, y1bg);
+ D_cont_abs(x1bg, y0bg);
+ D_close();
+ D_end();
+ D_stroke();
+ }
+
+ } /* end of if(do_smooth) */
+
+ else { /* non FP, no smoothing */
+ ScaleFactor = 1.0;
+
+ if (histo->answer)
+ G_warning(_("Histogram plotting not implemented for categorical legends. "
+ "Use the '-s' flag"));
+
+ /* set legend box bounds */
+ true_l = l;
+ true_r = r; /* preserve window width */
+ l = x0;
+ t = y0;
+ r = x1;
+ b = y1;
+
+ /* figure out box height */
+ if (do_cats == cats_num)
+ dots_per_line = (b - t) / (lines + 1); /* +1 line for the two 1/2s at top and bottom */
+ else
+ dots_per_line = (b - t) / (lines + 2); /* + another line for 'x of y categories' text */
+
+ /* adjust text size */
+ /* txsiz = (int)((y1-y0)/(1.5*(lines+5))); */
+ txsiz = (y1 - y0) / (2.0 * lines);
+
+ if (tit_fontsize == 0)
+ titsiz = txsiz;
+ else
+ titsiz = tit_fontsize;
+
+ /* scale text to fit in window if position not manually set */
+ if (opt_at->answer == NULL) { /* ie defualt scaling */
+ ScaleFactor = ((true_r - true_l) / ((MaxLabelLen + 3) * txsiz * 0.81)); /* ?? txsiz*.81=actual text width. */
+ if (ScaleFactor < 1.0) {
+ txsiz = txsiz * ScaleFactor;
+ dots_per_line = (int)floor(dots_per_line * ScaleFactor);
+ }
+ }
+
+ if (dots_per_line < txsiz)
+ txsiz = dots_per_line;
+
+ if (opt_fontsize->answer != NULL)
+ txsiz = fontsize;
+
+ /* Set up box arrays */
+ x_box[0] = 0;
+ y_box[0] = 0;
+ x_box[1] = 0;
+ y_box[1] = (5 - dots_per_line);
+ x_box[2] = (dots_per_line - 5);
+ y_box[2] = 0;
+ x_box[3] = 0;
+ y_box[3] = (dots_per_line - 5);
+ x_box[4] = (5 - dots_per_line);
+ y_box[4] = 0;
+
+
+ /* Draw away */
+
+ /* if(ScaleFactor < 1.0) */
+ /* cur_dot_row = ((b-t) - (dots_per_line*lines))/2; *//* this will center the legend */
+ /* else */
+ cur_dot_row = t + dots_per_line / 2;
+
+ /* j = (do_cats == cats_num ? 1 : 2 ); */
+
+ if (draw) {
+ D_pos_abs(x0, y0);
+ D_text_size(txsiz, txsiz);
+ }
+
+ for (i = 0, k = 0; i < catlistCount; i++)
+ /* for(i=min_ind, j=1, k=0; j<=do_cats && i<=max_ind; j++, i+=thin) */
+ {
+ if (!flip)
+ cstr = Rast_get_d_cat(&catlist[i], &cats);
+ else
+ cstr = Rast_get_d_cat(&catlist[catlistCount - i - 1], &cats);
+
+
+ if (!cstr[0]) { /* no cat label found, skip str output */
+ hide_catstr = 1;
+ if (hide_nodata)
+ continue;
+ }
+ else
+ hide_catstr = hidestr->answer;
+
+ k++; /* count of actual boxes drawn (hide_nodata option invaidates using j-1) */
+
+ cur_dot_row += dots_per_line;
+
+ if (draw) {
+ /* Black box */
+ D_use_color(black);
+ D_begin();
+ D_move_abs(l + 2, (cur_dot_row - 1));
+ D_cont_rel(0, (3 - dots_per_line));
+ D_cont_rel((dots_per_line - 3), 0);
+ D_cont_rel(0, (dots_per_line - 3));
+ D_close();
+ D_end();
+ D_stroke();
+
+ /* White box */
+ D_use_color(white);
+ D_begin();
+ D_move_abs(l + 3, (cur_dot_row - 2));
+ D_cont_rel(0, (5 - dots_per_line));
+ D_cont_rel((dots_per_line - 5), 0);
+ D_cont_rel(0, (dots_per_line - 5));
+ D_close();
+ D_end();
+ D_stroke();
+
+
+ /* Color solid box */
+ if (!fp) {
+ if (!flip)
+ D_color((CELL) (int)catlist[i], &colors);
+ else
+ D_color((CELL) (int)catlist[catlistCount - i - 1],
+ &colors);
+ }
+ else {
+ if (!flip)
+ D_d_color(catlist[i], &colors);
+ else
+ D_d_color(catlist[catlistCount - i - 1], &colors);
+ }
+
+ D_pos_abs(l + 3, (cur_dot_row - 2));
+ D_polygon_rel(x_box, y_box, 5);
+
+ /* Draw text */
+ D_use_color(color);
+ }
+
+
+ if (!fp) {
+ /* nothing, box only */
+ buff[0] = 0;
+ if (!hide_catnum) { /* num */
+ sprintf(buff, DispFormat, (int)catlist[i]);
+ if (strlen(units)>0)
+ strcat(buff, units);
+ D_text_size(txsiz, txsiz);
+ D_get_text_box(buff,&bb,&bt, &bl, &br);
+ LabelW = br - bl;
+ if (LabelW > MaxLabelW) {
+ MaxLabelW = LabelW;
+ sprintf(MaxLabel, "%s", buff);
+ }
+ if (!flip) {
+ sprintf(buff, DispFormat, (int)catlist[i]);
+ if (strlen(units)>0)
+ strcat(buff, units);
+ D_text_size(txsiz, txsiz);
+ D_get_text_box(buff,&bb,&bt, &bl, &br);
+ LabelW = br - bl;
+ if (LabelW > MaxLabelW) {
+ MaxLabelW = LabelW;
+ sprintf(MaxLabel, "%s", buff);
+ }
+ }
+ else {
+ sprintf(buff, DispFormat,
+ (int)catlist[catlistCount - i - 1]);
+ if (strlen(units)>0)
+ strcat(buff, units);
+ D_text_size(txsiz, txsiz);
+ D_get_text_box(buff,&bb,&bt, &bl, &br);
+ LabelW = br - bl;
+ if (LabelW > MaxLabelW) {
+ MaxLabelW = LabelW;
+ sprintf(MaxLabel, "%s", buff);
+ }
+ }
+ if (!hide_catstr) /* both */
+ strcat(buff, ")");
+ }
+ if (!hide_catstr) { /* str */
+ sprintf(buff + strlen(buff), " %s", cstr);
+ if (strlen(units)>0)
+ strcat(buff, units);
+ D_text_size(txsiz, txsiz);
+ D_get_text_box(buff,&bb,&bt, &bl, &br);
+ LabelW = br - bl;
+ if (LabelW > MaxLabelW) {
+ MaxLabelW = LabelW;
+ sprintf(MaxLabel, " %s", buff);
+ }
+ }
+ }
+ else { /* is fp */
+ if (!flip) {
+ if (use_catlist) {
+ /* pass through format exactly as given by the user in
+ the use= command line parameter (helps with log scale) */
+ sprintf(buff, "%s", opt_use->answers[i]);
+ if (strlen(units)>0)
+ strcat(buff, units);
+ D_text_size(txsiz, txsiz);
+ D_get_text_box(buff,&bb,&bt, &bl, &br);
+ LabelW = br - bl;
+ if (LabelW > MaxLabelW) {
+ MaxLabelW = LabelW;
+ sprintf(MaxLabel, " %s", buff);
+ }
+ }
+ else {
+ /* automatically generated/tuned decimal precision format */
+ sprintf(buff, DispFormat, catlist[i]);
+ if (strlen(units)>0)
+ strcat(buff, units);
+ D_text_size(txsiz, txsiz);
+ D_get_text_box(buff,&bb,&bt, &bl, &br);
+ LabelW = br - bl;
+ if (LabelW > MaxLabelW) {
+ MaxLabelW = LabelW;
+ sprintf(MaxLabel, "%s", buff);
+ }
+ }
+ }
+ else {
+ if (use_catlist){
+ sprintf(buff, "%s", opt_use->answers[catlistCount - i - 1]);
+ if (strlen(units)>0)
+ strcat(buff, units);
+ D_text_size(txsiz, txsiz);
+ D_get_text_box(buff,&bb,&bt, &bl, &br);
+ LabelW = br - bl;
+ if (LabelW > MaxLabelW) {
+ MaxLabelW = LabelW;
+ sprintf(MaxLabel, " %s", buff);
+ }
+ }
+ else {
+ sprintf(buff, DispFormat, catlist[catlistCount - i - 1]);
+ if (strlen(units)>0)
+ strcat(buff, units);
+ D_text_size(txsiz, txsiz);
+ D_get_text_box(buff,&bb,&bt, &bl, &br);
+ LabelW = br - bl;
+ if (LabelW > MaxLabelW) {
+ MaxLabelW = LabelW;
+ sprintf(MaxLabel, " %s", buff);
+ }
+ }
+ }
+ }
+
+ if (draw) {
+ D_pos_abs((l + 3 + dots_per_line), (cur_dot_row) - 3);
+ if (color)
+ D_text(buff);
+ }
+ }
+
+ if (0 == k)
+ G_fatal_error(_("Nothing to draw! (no categories with labels?)")); /* "(..., out of range?)" */
+
+ /* display title */
+ if (strlen(title) > 0) {
+ x_tit = x0;
+ y_tit = y0 - txsiz;
+
+ D_text_size(titsiz, titsiz);
+ D_get_text_box(title, &bb, &bt, &bl, &br);
+ x1_tit = x_tit + (br - bl);
+
+ if (draw) {
+ D_use_color(color);
+ /* use tit_fontsize */
+ D_text_size(titsiz, titsiz);
+ D_pos_abs(x_tit, y_tit);
+ D_text(title);
+ /* restart fontsize */
+ D_text_size(txsiz, txsiz);
+ }
+ }
+
+ /* Display info line about numbers of categories */
+ if (do_cats != cats_num) {
+ cur_dot_row += dots_per_line;
+ /* sprintf(buff, "%d of %d categories\n", (j-1), cats_num); */
+
+ sprintf(buff, "%d of %d categories\n", k, cats_num);
+ if (strlen(buff) > MaxLabelLen) {
+ MaxLabelLen = strlen(buff);
+ sprintf(MaxLabel, "%d of %d categories\n", k, cats_num);
+ }
+
+ if (draw) {
+ if (opt_fontsize->answer != NULL)
+ txsiz = fontsize;
+ D_text_size(txsiz, txsiz);
+ D_use_color(black);
+ D_pos_abs((l + 3 + dots_per_line), (cur_dot_row));
+ if (color)
+ D_text(buff);
+ }
+ }
+
+ if (!draw) {
+ /* Draw background */
+ D_text_size(txsiz, txsiz);
+ D_get_text_box(MaxLabel, &bb, &bt, &bl, &br);
+ x0bg = x0 - txsiz;
+ x1bg =
+ x0 + dots_per_line + 3 + (br - bl) + txsiz;
+ if (x1bg < x1_tit)
+ x1bg = x1_tit + txsiz;
+ y1bg = cur_dot_row + txsiz;
+ if (strlen(title) > 0)
+ y0bg = y0 - 2 * txsiz - titsiz;
+ else
+ y0bg = y0 - txsiz;
+
+
+ if (colorbg != 0) {
+ D_use_color(colorbg);
+ D_box_abs(x0bg, y0bg, x1bg, y1bg);
+ }
+
+ D_use_color(colorb);
+ D_begin();
+ D_move_abs(x0bg, y0bg);
+ D_cont_abs(x0bg, y1bg);
+ D_cont_abs(x1bg, y1bg);
+ D_cont_abs(x1bg, y0bg);
+ D_close();
+ D_end();
+ D_stroke();
+ }
+
+ }
+ D_save_command(G_recreate_command());
+}
Modified: grass/branches/releasebranch_7_2/display/d.legend/get_stats.c
===================================================================
--- grass/branches/releasebranch_7_2/display/d.legend/get_stats.c 2016-07-27 11:18:55 UTC (rev 69036)
+++ grass/branches/releasebranch_7_2/display/d.legend/get_stats.c 2016-07-27 18:05:07 UTC (rev 69037)
@@ -7,18 +7,18 @@
void run_stats(const char *mapname, int nsteps, const char *tempfile,
- int map_type)
+ int map_type)
{
char buf[32];
const char *argv[12];
int argc = 0;
if (map_type == MAP_TYPE_RASTER2D) {
- argv[argc++] = "r.stats";
- argv[argc++] = "-r";
+ argv[argc++] = "r.stats";
+ argv[argc++] = "-r";
}
else
- argv[argc++] = "r3.stats";
+ argv[argc++] = "r3.stats";
argv[argc++] = "-c";
argv[argc++] = mapname;
@@ -34,42 +34,43 @@
argv[argc++] = NULL;
if (G_vspawn_ex(argv[0], argv) != 0)
- G_fatal_error("error running r.stats");
+ G_fatal_error("error running r.stats");
}
/* linked list of stats */
void get_stats(const char *mapname, struct stat_list *dist_stats, int nsteps,
- int map_type)
+ int map_type)
{
- char buf[1024]; /* input buffer for reading stats */
+ char buf[1024]; /* input buffer for reading stats */
int done = FALSE;
- char *tempfile; /* temp file name */
- FILE *fd; /* temp file pointer */
-/*
- int is_fp;
- struct FPRange fp_range;
-*/
- long int cat; /* a category value */
- long int stat; /* a category stat value */
+ char *tempfile; /* temp file name */
+ FILE *fd; /* temp file pointer */
+
+ /*
+ int is_fp;
+ struct FPRange fp_range;
+ */
+ long int cat; /* a category value */
+ long int stat; /* a category stat value */
struct stat_node *ptr = NULL;
int first;
/* write stats to a temp file */
tempfile = G_tempfile();
-/*
- is_fp = Rast_map_is_fp(mapname, "");
- if (is_fp) {
- if (Rast_read_fp_range(mapname, "", &fp_range) <= 0)
- G_fatal_error("Can't read frange file");
- }
-*/
+ /*
+ is_fp = Rast_map_is_fp(mapname, "");
+ if (is_fp) {
+ if (Rast_read_fp_range(mapname, "", &fp_range) <= 0)
+ G_fatal_error("Can't read frange file");
+ }
+ */
run_stats(mapname, nsteps, tempfile, map_type);
/* open temp file and read the stats into a linked list */
fd = fopen(tempfile, "r");
if (fd == NULL) {
- perror("opening r.stats output file");
- G_fatal_error("unable to continue.");
+ perror("opening r.stats output file");
+ G_fatal_error("unable to continue.");
}
dist_stats->ptr = NULL;
dist_stats->count = 0;
@@ -78,71 +79,71 @@
first = TRUE;
while (!done) {
- if (fgets(buf, sizeof(buf), fd) != NULL) {
- /* WARNING!!!!!!
- * this will be very wrong if type!=COUNT
- * since the stat prodcued by r.stats will be a floating point value
- * possibly less than 1 (shapiro)
- */
- if (sscanf(buf, "* %ld", &stat) == 1) {
- dist_stats->null_stat = stat;
-/*
- if (stat > dist_stats->maxstat && nodata)
- dist_stats->maxstat = stat;
- if (stat < dist_stats->minstat && nodata)
- dist_stats->minstat = stat;
- if (nodata)
- dist_stats->sumstat += stat;
-*/
- }
- else if (sscanf(buf, "%ld %ld", &cat, &stat) == 2) {
- /* count stats */
- dist_stats->count++;
+ if (fgets(buf, sizeof(buf), fd) != NULL) {
+ /* WARNING!!!!!!
+ * this will be very wrong if type!=COUNT
+ * since the stat prodcued by r.stats will be a floating point value
+ * possibly less than 1 (shapiro)
+ */
+ if (sscanf(buf, "* %ld", &stat) == 1) {
+ dist_stats->null_stat = stat;
+ /*
+ if (stat > dist_stats->maxstat && nodata)
+ dist_stats->maxstat = stat;
+ if (stat < dist_stats->minstat && nodata)
+ dist_stats->minstat = stat;
+ if (nodata)
+ dist_stats->sumstat += stat;
+ */
+ }
+ else if (sscanf(buf, "%ld %ld", &cat, &stat) == 2) {
+ /* count stats */
+ dist_stats->count++;
- /* sum stats */
- dist_stats->sumstat += stat;
+ /* sum stats */
+ dist_stats->sumstat += stat;
- /* a max or a min stat? */
- if (first) {
- dist_stats->maxstat = stat;
- dist_stats->minstat = stat;
- dist_stats->maxcat = cat;
- dist_stats->mincat = cat;
- first = FALSE;
- }
- if (stat > dist_stats->maxstat)
- dist_stats->maxstat = stat;
- if (stat < dist_stats->minstat)
- dist_stats->minstat = stat;
+ /* a max or a min stat? */
+ if (first) {
+ dist_stats->maxstat = stat;
+ dist_stats->minstat = stat;
+ dist_stats->maxcat = cat;
+ dist_stats->mincat = cat;
+ first = FALSE;
+ }
+ if (stat > dist_stats->maxstat)
+ dist_stats->maxstat = stat;
+ if (stat < dist_stats->minstat)
+ dist_stats->minstat = stat;
- /* a max or a min cat? */
- if (cat > dist_stats->maxcat)
- dist_stats->maxcat = cat;
- if (cat < dist_stats->mincat)
- dist_stats->mincat = cat;
+ /* a max or a min cat? */
+ if (cat > dist_stats->maxcat)
+ dist_stats->maxcat = cat;
+ if (cat < dist_stats->mincat)
+ dist_stats->mincat = cat;
- /* put it in the list */
- if (dist_stats->ptr == NULL) {
- /* first in list */
- dist_stats->ptr = (struct stat_node *)
- G_malloc(sizeof(struct stat_node));
- dist_stats->ptr->cat = cat;
- dist_stats->ptr->stat = stat;
- dist_stats->ptr->next = NULL;
- ptr = dist_stats->ptr;
- }
- else {
- ptr->next = (struct stat_node *)
- G_malloc(sizeof(struct stat_node));
- ptr->next->cat = cat;
- ptr->next->stat = stat;
- ptr->next->next = NULL; /* mod: shapiro */
- ptr = ptr->next;
- }
- }
- }
- else
- done = TRUE;
+ /* put it in the list */
+ if (dist_stats->ptr == NULL) {
+ /* first in list */
+ dist_stats->ptr = (struct stat_node *)
+ G_malloc(sizeof(struct stat_node));
+ dist_stats->ptr->cat = cat;
+ dist_stats->ptr->stat = stat;
+ dist_stats->ptr->next = NULL;
+ ptr = dist_stats->ptr;
+ }
+ else {
+ ptr->next = (struct stat_node *)
+ G_malloc(sizeof(struct stat_node));
+ ptr->next->cat = cat;
+ ptr->next->stat = stat;
+ ptr->next->next = NULL; /* mod: shapiro */
+ ptr = ptr->next;
+ }
+ }
+ }
+ else
+ done = TRUE;
}
fclose(fd);
unlink(tempfile);
Modified: grass/branches/releasebranch_7_2/display/d.legend/histogram.c
===================================================================
--- grass/branches/releasebranch_7_2/display/d.legend/histogram.c 2016-07-27 11:18:55 UTC (rev 69036)
+++ grass/branches/releasebranch_7_2/display/d.legend/histogram.c 2016-07-27 18:05:07 UTC (rev 69037)
@@ -13,14 +13,14 @@
#include <grass/glocale.h>
#include "local_proto.h"
-void draw_histogram(const char *map_name, int x0, int y0, int width,
- int height, int color, int flip, int horiz,
- int map_type, int is_fp, struct FPRange render_range)
+double histogram(const char *map_name, int x0, int y0, int width,
+ int height, int color, int flip, int horiz, int map_type,
+ int is_fp, struct FPRange render_range, int drawh)
{
int i, nsteps, ystep;
long cell_count = 0;
- double max_width, width_mult, dx;
- double dy, y0_adjust; /* only needed for CELL maps */
+ double max_width, width_mult, dx, max;
+ double dy, y0_adjust; /* only needed for CELL maps */
struct stat_list dist_stats;
struct stat_node *ptr;
struct Range range;
@@ -31,83 +31,90 @@
double crop_min_perc = 0.0, crop_max_perc = 1.0, pad_min_perc = 0.0;
if (horiz) {
- max_width = height * 1.75;
- nsteps = width - 3;
+ max_width = height * 1.75;
+ nsteps = width - 3;
}
else {
- max_width = width * 1.75;
- nsteps = height - 3;
+ max_width = width * 1.75;
+ nsteps = height - 3;
}
+ /* reset return value max */
+ max = 0;
+
if (render_range.first_time) {
- /* user specified range, can be either larger
- or smaller than actual map's range */
+ /* user specified range, can be either larger
+ or smaller than actual map's range */
- if (is_fp) {
- Rast_read_fp_range(map_name, "", &fprange);
- Rast_get_fp_range_min_max(&fprange, &d_map_min, &d_map_max);
- map_min = (double)d_map_min;
- map_max = (double)d_map_max;
- }
- else {
- Rast_read_range(map_name, "", &range);
- Rast_get_range_min_max(&range, &c_map_min, &c_map_max);
- map_min = (double)c_map_min;
- map_max = (double)c_map_max;
- }
+ if (is_fp) {
+ Rast_read_fp_range(map_name, "", &fprange);
+ Rast_get_fp_range_min_max(&fprange, &d_map_min, &d_map_max);
+ map_min = (double)d_map_min;
+ map_max = (double)d_map_max;
+ }
+ else {
+ Rast_read_range(map_name, "", &range);
+ Rast_get_range_min_max(&range, &c_map_min, &c_map_max);
+ map_min = (double)c_map_min;
+ map_max = (double)c_map_max;
+ }
- map_range = map_max - map_min;
- user_range = render_range.max - render_range.min;
+ map_range = map_max - map_min;
+ user_range = render_range.max - render_range.min;
- if (horiz)
- nsteps = (int)(0.5 + (map_range * (width - 3) / user_range));
- else
- nsteps = (int)(0.5 + (map_range * (height - 3) / user_range));
+ if (horiz)
+ nsteps = (int)(0.5 + (map_range * (width - 3) / user_range));
+ else
+ nsteps = (int)(0.5 + (map_range * (height - 3) / user_range));
- G_debug(1, "number of steps for r.stats = %d, height-3=%d width-3=%d",
- nsteps, height - 3, width - 3);
+ G_debug(1,
+ "number of steps for r.stats = %d, height-3=%d width-3=%d",
+ nsteps, height - 3, width - 3);
- /* need to know the % of the MAP range where user range starts and stops.
- * note that MAP range can be fully inside user range, in which case
- * keep 0-100% aka 0,nsteps, i.e. the step number in the nsteps range */
+ /* need to know the % of the MAP range where user range starts and stops.
+ * note that MAP range can be fully inside user range, in which case
+ * keep 0-100% aka 0,nsteps, i.e. the step number in the nsteps range */
- if (render_range.min > map_min) {
- crop_min_perc = (render_range.min - map_min) / map_range;
- G_debug(3, "min: %.02f vs. %.02f (%.02f) ... %.02f%%",
- render_range.min, map_min, map_range, 100 * crop_min_perc);
- }
+ if (render_range.min > map_min) {
+ crop_min_perc = (render_range.min - map_min) / map_range;
+ G_debug(3, "min: %.02f vs. %.02f (%.02f) ... %.02f%%",
+ render_range.min, map_min, map_range,
+ 100 * crop_min_perc);
+ }
- if (render_range.max > map_max) {
- crop_max_perc = 1.0 - ((render_range.max - map_max) / user_range);
- G_debug(3, "max: %.02f vs. %.02f (%.02f) ... %.02f%%",
- map_max, render_range.max, map_range, 100 * crop_max_perc);
- }
+ if (render_range.max > map_max) {
+ crop_max_perc = 1.0 - ((render_range.max - map_max) / user_range);
+ G_debug(3, "max: %.02f vs. %.02f (%.02f) ... %.02f%%",
+ map_max, render_range.max, map_range,
+ 100 * crop_max_perc);
+ }
- if (render_range.min < map_min) {
- pad_min_perc = (map_min - render_range.min) / user_range;
- G_debug(3, "Min: %.02f vs. %.02f (%.02f) ... %.02f%%",
- map_min, render_range.min, user_range, 100 * pad_min_perc);
- }
+ if (render_range.min < map_min) {
+ pad_min_perc = (map_min - render_range.min) / user_range;
+ G_debug(3, "Min: %.02f vs. %.02f (%.02f) ... %.02f%%",
+ map_min, render_range.min, user_range,
+ 100 * pad_min_perc);
+ }
#ifdef amplify_gain
- /* proportion of nsteps to width, use as mult factor to boost the 1.75x
- when spread out over more nsteps than we are displaying */
- G_debug(0, "max_width was: %.2f (nsteps=%d)", max_width, nsteps);
+ /* proportion of nsteps to width, use as mult factor to boost the 1.75x
+ when spread out over more nsteps than we are displaying */
+ G_debug(0, "max_width was: %.2f (nsteps=%d)", max_width, nsteps);
- if (nsteps > ((horiz ? width : height) - 3.0))
- max_width *= nsteps / ((horiz ? width : height) - 3.0);
+ if (nsteps > ((horiz ? width : height) - 3.0))
+ max_width *= nsteps / ((horiz ? width : height) - 3.0);
- G_debug(0, "max_width now: %.2f", max_width);
+ G_debug(0, "max_width now: %.2f", max_width);
#endif
}
/* TODO */
if (!is_fp && render_range.first_time) {
- G_warning(_("Histogram constrained by range not yet implemented for "
- "categorical rasters"));
- return;
+ G_warning(_("Histogram constrained by range not yet implemented for "
+ "categorical rasters"));
+ return max;
}
@@ -115,139 +122,150 @@
get_stats(map_name, &dist_stats, nsteps, map_type);
width_mult = max_width / dist_stats.maxstat;
+ ptr = dist_stats.ptr;
- D_use_color(color);
- D_begin();
+ if (drawh) {
+ D_use_color(color);
+ D_begin();
- ptr = dist_stats.ptr;
+ if (!is_fp) {
+ dy = (nsteps + 3.0) / (1 + dist_stats.maxcat - dist_stats.mincat);
- if (!is_fp) {
- dy = (nsteps + 3.0) / (1 + dist_stats.maxcat - dist_stats.mincat);
+ if (flip)
+ dy *= -1;
- if (flip)
- dy *= -1;
+ if (dist_stats.mincat == 0)
+ y0_adjust = dy;
+ else
+ y0_adjust = 0;
- if (dist_stats.mincat == 0)
- y0_adjust = dy;
- else
- y0_adjust = 0;
-
- if (!flip) /* mmph */
- y0_adjust += 0.5;
+ if (!flip) /* mmph */
+ y0_adjust += 0.5;
+ }
}
- G_debug(3, "mincat=%ld maxcat=%ld", dist_stats.mincat, dist_stats.maxcat);
+ G_debug(3, "mincat=%ld maxcat=%ld", dist_stats.mincat,
+ dist_stats.maxcat);
for (i = dist_stats.mincat, ystep = 0; i <= dist_stats.maxcat; i++) {
- if (!ptr)
- break;
+ cell_count = 0;
+ if (!ptr)
+ break;
- /* jump out if user range cuts things shorter than the map's native range */
- if ((horiz && ystep > width - 4) || (!horiz && ystep > height - 4))
- break;
+ /* jump out if user range cuts things shorter than the map's native range */
+ if ((horiz && ystep > width - 4) || (!horiz && ystep > height - 4))
+ break;
- /* jump out if user range goes beyond max of map data */
- if (((double)ystep / ((horiz ? width : height) - 3.0)) > crop_max_perc)
- break;
-/* TODO if (!is_fp && i > render_range.max)
- break;
-*/
- /* haven't made it to the min of the user range yet */
- if (((double)i / nsteps) < crop_min_perc) {
- continue;
- }
+ /* jump out if user range goes beyond max of map data */
+ if (((double)ystep / ((horiz ? width : height) - 3.0)) >
+ crop_max_perc)
+ break;
+ /* TODO if (!is_fp && i > render_range.max)
+ break;
+ */
+ /* haven't made it to the min of the user range yet */
+ if (((double)i / nsteps) < crop_min_perc) {
+ continue;
+ }
- /* now it's ok advance the plotter position */
- ystep++;
+ /* now it's ok advance the plotter position */
+ ystep++;
- /* if user range is below the minimum real map value, we need to pad out the space */
- if (render_range.first_time && render_range.min < map_min) {
- if ( ((double)ystep / ((horiz ? width : height) - 3.0)) < pad_min_perc) {
- i--;
- continue;
- }
- }
+ /* if user range is below the minimum real map value, we need to pad out the space */
+ if (render_range.first_time && render_range.min < map_min) {
+ if (((double)ystep / ((horiz ? width : height) - 3.0)) <
+ pad_min_perc) {
+ i--;
+ continue;
+ }
+ }
- if (ptr->cat == i) { /* AH-HA!! found the stat */
- cell_count = ptr->stat;
+ if (ptr->cat == i) { /* AH-HA!! found the stat */
+ cell_count = ptr->stat;
- if (ptr->next != NULL)
- ptr = ptr->next;
- }
- else { /* we have to look for the stat */
+ if (ptr->next != NULL)
+ ptr = ptr->next;
+ }
+ else { /* we have to look for the stat */
- /* loop until we find it, or pass where it should be */
- while (ptr->cat < i && ptr->next != NULL)
- ptr = ptr->next;
- if (ptr->cat == i) { /* AH-HA!! found the stat */
- cell_count = ptr->stat;
+ /* loop until we find it, or pass where it should be */
+ while (ptr->cat < i && ptr->next != NULL)
+ ptr = ptr->next;
+ if (ptr->cat == i) { /* AH-HA!! found the stat */
+ cell_count = ptr->stat;
- if (ptr->next != NULL)
- ptr = ptr->next;
- }
- else /* stat cannot be found */
- G_debug(5, "No matching stat found, i=%d", i);
- }
+ if (ptr->next != NULL)
+ ptr = ptr->next;
+ }
+ else /* stat cannot be found */
+ G_debug(5, "No matching stat found, i=%d", i);
+ }
- G_debug(5, "i=%d ptr->cat=%ld cell_count=%ld", i, ptr->cat,
- cell_count);
+ G_debug(5, "i=%d ptr->cat=%ld cell_count=%ld", i, ptr->cat,
+ cell_count);
- if (!cell_count)
- continue;
+ if (!cell_count)
+ continue;
- dx = cell_count * width_mult;
+ dx = cell_count * width_mult;
- if (is_fp) {
- if (horiz) {
- if (flip)
- D_move_abs(x0 + width - ystep - 1, y0 - 1);
- else
- D_move_abs(x0 + ystep + 1, y0 - 1);
+ if (drawh) {
+ if (is_fp) {
+ if (horiz) {
+ if (flip)
+ D_move_abs(x0 + width - ystep - 1, y0 - 1);
+ else
+ D_move_abs(x0 + ystep + 1, y0 - 1);
- D_cont_rel(0, -dx);
- }
- else { /* vertical */
- if (flip)
- D_move_abs(x0 - 1, y0 - 1 + height - ystep);
- else
- D_move_abs(x0 - 1, y0 + 1 + ystep);
+ D_cont_rel(0, -dx);
+ }
+ else { /* vertical */
+ if (flip)
+ D_move_abs(x0 - 1, y0 - 1 + height - ystep);
+ else
+ D_move_abs(x0 - 1, y0 + 1 + ystep);
- D_cont_rel(-dx, 0);
- }
- }
- else { /* categorical */
+ D_cont_rel(-dx, 0);
+ }
+ }
+ else { /* categorical */
- if (horiz) {
- if (flip)
- D_box_abs(x0 + width + y0_adjust + ((i - 1) * dy),
- y0 - 1,
- x0 + width + y0_adjust + 1 + (i * dy),
- y0 - 1 - dx);
- else
- D_box_abs(x0 + y0_adjust + ((i - 1) * dy),
- y0 - 1,
- x0 - 1 + y0_adjust + (i * dy),
- y0 - 1 - dx);
- }
- else { /* vertical */
+ if (horiz) {
+ if (flip)
+ D_box_abs(x0 + width + y0_adjust + ((i - 2) * dy),
+ y0 - 1,
+ x0 + width + y0_adjust + 1 + ((i - 1) * dy),
+ y0 - 1 - dx);
+ else
+ D_box_abs(x0 + y0_adjust + ((i - 2) * dy),
+ y0 - 1,
+ x0 - 1 + y0_adjust + ((i - 1) * dy), y0 - 1 - dx);
+ }
+ else { /* vertical */
- if (flip)
- /* GRASS_EPSILON fudge around D_box_abs() weirdness + PNG driver */
- D_box_abs(x0 - 1 - GRASS_EPSILON * 10,
- y0 + height + y0_adjust + ((i - 1) * dy),
- x0 - 1 - dx,
- y0 + height + y0_adjust + 1 + (i * dy));
- else
- D_box_abs(x0 - 1 - GRASS_EPSILON * 10,
- y0 + y0_adjust + ((i - 1) * dy),
- x0 - 1 - dx,
- y0 + y0_adjust - 1 + (i * dy));
- }
- }
+ if (flip)
+ /* GRASS_EPSILON fudge around D_box_abs() weirdness + PNG driver */
+ D_box_abs(x0 - 1 - GRASS_EPSILON * 10,
+ y0 + height + y0_adjust + ((i - 2) * dy),
+ x0 - 1 - dx,
+ y0 + height + y0_adjust + 1 + ((i - 1) * dy));
+ else
+ D_box_abs(x0 - 1 - GRASS_EPSILON * 10,
+ y0 + y0_adjust + ((i - 2) * dy),
+ x0 - 1 - dx, y0 + y0_adjust - 1 + ((i - 1) * dy));
+ }
+ }
+ }
+ if (dx > max)
+ max = dx;
}
- D_close();
- D_end();
- D_stroke();
+ if (drawh) {
+ D_close();
+ D_end();
+ D_stroke();
+ }
+
+ return max;
}
Modified: grass/branches/releasebranch_7_2/display/d.legend/local_proto.h
===================================================================
--- grass/branches/releasebranch_7_2/display/d.legend/local_proto.h 2016-07-27 11:18:55 UTC (rev 69036)
+++ grass/branches/releasebranch_7_2/display/d.legend/local_proto.h 2016-07-27 18:05:07 UTC (rev 69037)
@@ -3,9 +3,9 @@
#define MAP_TYPE_RASTER2D 1
#define MAP_TYPE_RASTER3D 2
/* possibles for the future:
-#define MAP_TYPE_VECTOR 3
-#define MAP_TYPE_RULES 4
-*/
+ #define MAP_TYPE_VECTOR 3
+ #define MAP_TYPE_RULES 4
+ */
struct stat_node
{
@@ -29,9 +29,17 @@
/* histogram.c */
-void draw_histogram(const char *, int, int, int, int, int, int, int, int,
- int, struct FPRange);
+double histogram(const char *, int, int, int, int, int, int, int, int,
+ int, struct FPRange, int);
/* get_stats.c */
void get_stats(const char *, struct stat_list *, int, int);
void run_stats(const char *, int, const char *, int);
+
+/* draw.c */
+void draw(const char *, int, int, int, int, int, int, int, int, int, int, int,
+ int, struct Categories, struct Colors, double, double, double,
+ double, int, int, double, double, double *, int, int, int, double,
+ double, const char *, double *, double, int, int, struct Option *,
+ struct Option *, struct Option *, struct Option *, struct Option *,
+ struct Flag *, struct Flag *, int, int, int, char *);
Modified: grass/branches/releasebranch_7_2/display/d.legend/main.c
===================================================================
--- grass/branches/releasebranch_7_2/display/d.legend/main.c 2016-07-27 11:18:55 UTC (rev 69036)
+++ grass/branches/releasebranch_7_2/display/d.legend/main.c 2016-07-27 18:05:07 UTC (rev 69037)
@@ -15,6 +15,8 @@
* Markus Neteler
* Late 2002: Rewrite of much of the code:
* Hamish Bowman, Otago University, New Zealand
+ * Improvements (ticks, more label options, title):
+ * Adam Laza (part of GSoC 2016)
*
* COPYRIGHT: (c) 2002-2014 by The GRASS Development Team
*
@@ -37,47 +39,38 @@
int main(int argc, char **argv)
{
- char buff[512];
char *map_name;
int maptype;
- int black, white, color;
- int cats_num;
- int cur_dot_row;
- int do_cats;
- int dots_per_line;
- int i, j, k;
+ int color;
+ int i;
int thin, lines, steps;
int fp;
- double t, b, l, r;
- int hide_catnum, hide_catstr, hide_nodata, do_smooth;
- char *cstr;
- double x_box[5], y_box[5];
+ int label_indent;
+ int hide_catnum, hide_catstr, show_ticks, show_bg, hide_nodata, do_smooth;
struct Categories cats;
struct Colors colors;
struct GModule *module;
struct Option *opt_rast2d, *opt_rast3d, *opt_color, *opt_lines,
- *opt_thin, *opt_labelnum, *opt_at, *opt_use, *opt_range,
- *opt_font, *opt_path, *opt_charset, *opt_fontsize;
- struct Flag *hidestr, *hidenum, *hidenodata, *smooth, *flipit, *histo;
- struct Range range;
- struct FPRange fprange, render_range;
- CELL min_ind, max_ind;
- DCELL dmin, dmax, val;
- CELL min_colr, max_colr;
- DCELL min_dcolr, max_dcolr;
- int x0, x1, y0, y1, xyTemp;
+ *opt_thin, *opt_labelnum, *opt_at, *opt_use, *opt_range,
+ *opt_font, *opt_path, *opt_charset, *opt_fontsize, *opt_title,
+ *opt_ticks, *opt_tstep, *opt_brdcolor, *opt_bgcolor,
+ *opt_tit_fontsize, *opt_digits, *opt_units;
+ struct Flag *hidestr, *hidenum, *hidenodata, *smooth, *flipit, *histo,
+ *showtick, *showbg, *log_sc;
double X0, X1, Y0, Y1;
- int SigDigits;
- unsigned int MaxLabelLen;
- char DispFormat[5]; /* %.Xf\0 */
- int flip, horiz, UserRange;
+ int flip, UserRange;
double UserRangeMin, UserRangeMax, UserRangeTemp;
- double *catlist, maxCat;
- int catlistCount, use_catlist;
+ double *catlist;
+ int catlistCount, use_catlist, ticksCount;
double fontsize;
+ char *title;
char *units;
+ double *tick_values;
+ double t_step;
+ int colorb, colorbg;
+ double tit_fontsize;
+ int log_scale, digits;
-
/* Initialize the GIS calls */
G_gisinit(argv[0]);
@@ -86,8 +79,8 @@
G_add_keyword(_("cartography"));
G_add_keyword(_("legend"));
module->description =
- _("Displays a legend for a 2D or 3D raster map in the active frame "
- "of the graphics monitor.");
+ _("Displays a legend for a 2D or 3D raster map in the active frame "
+ "of the graphics monitor.");
opt_rast2d = G_define_standard_option(G_OPT_R_MAP);
opt_rast2d->key = "raster";
@@ -99,13 +92,29 @@
opt_rast3d->required = NO;
opt_rast3d->guisection = _("Input");
+ opt_title = G_define_option();
+ opt_title->key = "title";
+ opt_title->type = TYPE_STRING;
+ opt_title->required = NO;
+ opt_title->description = _("Legend title");
+ opt_title->guisection = _("Title");
+
+ opt_tit_fontsize = G_define_option();
+ opt_tit_fontsize->key = "title_fontsize";
+ opt_tit_fontsize->type = TYPE_DOUBLE;
+ opt_tit_fontsize->required = NO;
+ opt_tit_fontsize->options = "1-360";
+ opt_tit_fontsize->label = _("Title font size");
+ opt_tit_fontsize->description = _("Default: Same as fontsize");
+ opt_tit_fontsize->guisection = _("Title");
+
opt_lines = G_define_option();
opt_lines->key = "lines";
opt_lines->type = TYPE_INTEGER;
opt_lines->answer = "0";
opt_lines->options = "0-1000";
opt_lines->description =
- _("Number of text lines (useful for truncating long legends)");
+ _("Number of text lines (useful for truncating long legends)");
opt_lines->guisection = _("Advanced");
opt_thin = G_define_option();
@@ -115,46 +124,79 @@
opt_thin->answer = "1";
opt_thin->options = "1-1000";
opt_thin->description =
- _("Thinning factor (thin=10 gives cats 0,10,20...)");
+ _("Thinning factor (thin=10 gives cats 0,10,20...)");
opt_thin->guisection = _("Advanced");
+ opt_units = G_define_option();
+ opt_units->key = "units";
+ opt_units->type = TYPE_STRING;
+ opt_units->required = NO;
+ opt_units->description =
+ _("Units to display after labels (e.g. meters)");
+ opt_units->guisection = _("Advanced");
+
opt_labelnum = G_define_option();
opt_labelnum->key = "labelnum";
opt_labelnum->type = TYPE_INTEGER;
opt_labelnum->answer = "5";
opt_labelnum->options = "2-100";
opt_labelnum->description =
- _("Number of text labels for smooth gradient legend");
+ _("Number of text labels for smooth gradient legend");
opt_labelnum->guisection = _("Gradient");
+ opt_ticks = G_define_option();
+ opt_ticks->key = "label_values";
+ opt_ticks->type = TYPE_DOUBLE;
+ opt_ticks->required = NO;
+ opt_ticks->description = _("Specific values to draw ticks");
+ opt_ticks->required = NO;
+ opt_ticks->multiple = YES;
+ opt_ticks->guisection = _("Gradient");
+
+ opt_tstep = G_define_option();
+ opt_tstep->key = "label_step";
+ opt_tstep->type = TYPE_DOUBLE;
+ opt_tstep->required = NO;
+ opt_tstep->description = _("Display label every step");
+ opt_tstep->guisection = _("Gradient");
+
+ opt_digits = G_define_option();
+ opt_digits->key = "digits";
+ opt_digits->type = TYPE_INTEGER;
+ opt_digits->required = NO;
+ opt_digits->description = _("Number of digits after decimal point");
+ opt_digits->guisection = _("Advanced");
+ opt_digits->answer = NULL;
+ opt_digits->options = "0-6";
+
opt_at = G_define_option();
opt_at->key = "at";
opt_at->key_desc = "bottom,top,left,right";
- opt_at->type = TYPE_DOUBLE; /* needs to be TYPE_DOUBLE to get past options check */
+ opt_at->type = TYPE_DOUBLE; /* needs to be TYPE_DOUBLE to get past options check */
opt_at->required = NO;
opt_at->options = "0-100";
opt_at->label =
- _("Size and placement as percentage of screen coordinates "
- "(0,0 is lower left)");
+ _("Size and placement as percentage of screen coordinates "
+ "(0,0 is lower left)");
opt_at->description = opt_at->key_desc;
opt_at->answer = NULL;
opt_use = G_define_option();
opt_use->key = "use";
- opt_use->type = TYPE_DOUBLE; /* string as it is fed through the parser? */
+ opt_use->type = TYPE_DOUBLE; /* string as it is fed through the parser? */
opt_use->required = NO;
opt_use->description =
- _("List of discrete category numbers/values for legend");
+ _("List of discrete category numbers/values for legend");
opt_use->multiple = YES;
opt_use->guisection = _("Subset");
opt_range = G_define_option();
opt_range->key = "range";
opt_range->key_desc = "min,max";
- opt_range->type = TYPE_DOUBLE; /* should it be type_double or _string ?? */
+ opt_range->type = TYPE_DOUBLE; /* should it be type_double or _string ?? */
opt_range->required = NO;
opt_range->description =
- _("Use a subset of the map range for the legend (min,max)");
+ _("Use a subset of the map range for the legend (min,max)");
opt_range->guisection = _("Subset");
opt_color = G_define_standard_option(G_OPT_C);
@@ -189,9 +231,22 @@
opt_charset->type = TYPE_STRING;
opt_charset->required = NO;
opt_charset->description =
- _("Text encoding (only applicable to TrueType fonts)");
+ _("Text encoding (only applicable to TrueType fonts)");
opt_charset->guisection = _("Font settings");
+ opt_brdcolor = G_define_standard_option(G_OPT_CN);
+ opt_brdcolor->key = "border_color";
+ opt_brdcolor->answer = "black";
+ opt_brdcolor->label = _("Border color");
+ opt_brdcolor->guisection = _("Background");
+
+ opt_bgcolor = G_define_standard_option(G_OPT_CN);
+ opt_bgcolor->key = "bgcolor";
+ opt_bgcolor->answer = "white";
+ opt_bgcolor->label = _("Background color");
+ opt_bgcolor->guisection = _("Background");
+
+
hidestr = G_define_flag();
hidestr->key = 'v';
hidestr->description = _("Do not show category labels");
@@ -202,6 +257,11 @@
hidenum->description = _("Do not show category numbers");
hidenum->guisection = _("Advanced");
+ showtick = G_define_flag();
+ showtick->key = 't';
+ showtick->description = _("Draw legend ticks for labels");
+ showtick->guisection = _("Gradient");
+
hidenodata = G_define_flag();
hidenodata->key = 'n';
hidenodata->description = _("Skip categories with no label");
@@ -222,835 +282,210 @@
histo->description = _("Add histogram to smoothed legend");
histo->guisection = _("Gradient");
+ showbg = G_define_flag();
+ showbg->key = 'b';
+ showbg->description = _("Show background");
+ showbg->guisection = _("Background");
+ log_sc = G_define_flag();
+ log_sc->key = 'l';
+ log_sc->description = _("Use logarithmic scale");
+ log_sc->guisection = _("Advanced");
+
+ G_option_required(opt_rast2d, opt_rast3d, NULL);
+ G_option_exclusive(opt_rast2d, opt_rast3d, NULL);
+ G_option_exclusive(hidenum, opt_ticks, NULL);
+ G_option_exclusive(hidenum, opt_tstep, NULL);
+
/* Check command line */
if (G_parser(argc, argv))
- exit(EXIT_FAILURE);
+ exit(EXIT_FAILURE);
- /* FIXME: add GUI launching logic to G_parser() call */
- if ((opt_rast2d->answer && opt_rast3d->answer) ||
- !(opt_rast2d->answer || opt_rast3d->answer))
- G_fatal_error(_("Please specify a single map name. To launch GUI use d.legend --ui."));
-
if (opt_rast2d->answer) {
- map_name = opt_rast2d->answer;
- maptype = MAP_TYPE_RASTER2D;
+ map_name = opt_rast2d->answer;
+ maptype = MAP_TYPE_RASTER2D;
}
else {
- map_name = opt_rast3d->answer;
- maptype = MAP_TYPE_RASTER3D;
+ map_name = opt_rast3d->answer;
+ maptype = MAP_TYPE_RASTER3D;
}
- hide_catstr = hidestr->answer; /* note hide_catstr gets changed and re-read below */
+ if (opt_title->answer)
+ title = opt_title->answer;
+ else
+ title = "";
+
+ if (opt_units->answer) {
+ units = opt_units->answer;
+ }
+ else
+ units = "";
+
+ hide_catstr = hidestr->answer; /* note hide_catstr gets changed and re-read below */
hide_catnum = hidenum->answer;
+ show_ticks = showtick->answer;
hide_nodata = hidenodata->answer;
do_smooth = smooth->answer;
flip = flipit->answer;
+ show_bg = showbg->answer;
+ log_scale = log_sc->answer;
+ if (showtick->answer) {
+ label_indent = 12;
+ }
+ else
+ label_indent = 6;
+
+ if (opt_digits->answer != NULL)
+ sscanf(opt_digits->answer, "%d", &digits);
+ else
+ digits = -1;
+
color = D_parse_color(opt_color->answer, TRUE);
if (opt_lines->answer != NULL)
- sscanf(opt_lines->answer, "%d", &lines);
+ sscanf(opt_lines->answer, "%d", &lines);
thin = 1;
if (opt_thin->answer != NULL)
- sscanf(opt_thin->answer, "%d", &thin);
+ sscanf(opt_thin->answer, "%d", &thin);
if (!thin)
- thin = 1;
+ thin = 1;
if (opt_labelnum->answer != NULL)
- sscanf(opt_labelnum->answer, "%d", &steps);
+ sscanf(opt_labelnum->answer, "%d", &steps);
+ if ((opt_tstep->answer) || (opt_ticks->answer))
+ steps = 0;
+
+ if (opt_tstep->answer != NULL)
+ t_step = atof(opt_tstep->answer);
+
+ ticksCount = 0;
+ if (opt_ticks->answer != NULL) {
+ tick_values = (double *)G_calloc(100 + 1, sizeof(double));
+ for (i = 0; i < 100; i++) /* fill with dummy values */
+ tick_values[i] = 1.0 * (i + 1);
+ tick_values[i] = 0;
+
+ for (i = 0; (opt_ticks->answers[i] != NULL) && i < 100; i++)
+ tick_values[i] = atof(opt_ticks->answers[i]);
+ ticksCount = i;
+ }
+
catlistCount = 0;
- if (opt_use->answer != NULL) { /* should this be answerS ? */
- use_catlist = TRUE;
+ if (opt_use->answer != NULL) { /* should this be answerS ? */
+ use_catlist = TRUE;
- catlist = (double *)G_calloc(100 + 1, sizeof(double));
- for (i = 0; i < 100; i++) /* fill with dummy values */
- catlist[i] = 1.0 * (i + 1);
- catlist[i] = 0;
+ catlist = (double *)G_calloc(100 + 1, sizeof(double));
+ for (i = 0; i < 100; i++) /* fill with dummy values */
+ catlist[i] = 1.0 * (i + 1);
+ catlist[i] = 0;
- for (i = 0; (opt_use->answers[i] != NULL) && i < 100; i++)
- catlist[i] = atof(opt_use->answers[i]);
+ for (i = 0; (opt_use->answers[i] != NULL) && i < 100; i++)
+ catlist[i] = atof(opt_use->answers[i]);
- catlistCount = i;
+ catlistCount = i;
}
else
- use_catlist = FALSE;
+ use_catlist = FALSE;
UserRange = FALSE;
- if (opt_range->answer != NULL) { /* should this be answerS ? */
- sscanf(opt_range->answers[0], "%lf", &UserRangeMin);
- sscanf(opt_range->answers[1], "%lf", &UserRangeMax);
- UserRange = TRUE;
- if (UserRangeMin > UserRangeMax) {
- UserRangeTemp = UserRangeMax;
- UserRangeMax = UserRangeMin;
- UserRangeMin = UserRangeTemp;
- flip = !flip;
- }
+ if (opt_range->answer != NULL) { /* should this be answerS ? */
+ sscanf(opt_range->answers[0], "%lf", &UserRangeMin);
+ sscanf(opt_range->answers[1], "%lf", &UserRangeMax);
+ UserRange = TRUE;
+ if (UserRangeMin > UserRangeMax) {
+ UserRangeTemp = UserRangeMax;
+ UserRangeMax = UserRangeMin;
+ UserRangeMin = UserRangeTemp;
+ flip = !flip;
+ }
}
if (maptype == MAP_TYPE_RASTER2D) {
- if (Rast_read_colors(map_name, "", &colors) == -1)
- G_fatal_error(_("Color file for <%s> not available"), map_name);
+ if (Rast_read_colors(map_name, "", &colors) == -1)
+ G_fatal_error(_("Color file for <%s> not available"), map_name);
- fp = Rast_map_is_fp(map_name, "");
-
- Rast_read_cats(map_name, "", &cats);
+ fp = Rast_map_is_fp(map_name, "");
+
+ Rast_read_cats(map_name, "", &cats);
}
else {
- if (Rast3d_read_colors(map_name, "", &colors) == -1)
- G_fatal_error(_("Color file for <%s> not available"), map_name);
+ if (Rast3d_read_colors(map_name, "", &colors) == -1)
+ G_fatal_error(_("Color file for <%s> not available"), map_name);
- fp = TRUE; /* currently raster 3D is always floating point */
+ fp = TRUE; /* currently raster 3D is always floating point */
- Rast3d_read_cats(map_name, "", &cats);
+ Rast3d_read_cats(map_name, "", &cats);
}
if (fp && !use_catlist) {
- do_smooth = TRUE;
- /* fprintf(stderr, "FP map found - switching gradient legend on\n"); */
- flip = !flip;
+ do_smooth = TRUE;
+ /* fprintf(stderr, "FP map found - switching gradient legend on\n"); */
+ flip = !flip;
}
D_open_driver();
- white = D_translate_color(DEFAULT_FG_COLOR);
- black = D_translate_color(DEFAULT_BG_COLOR);
+ /* Parse and select background color */
+ colorb = D_parse_color(opt_brdcolor->answer, TRUE);
+ colorbg = D_parse_color(opt_bgcolor->answer, TRUE);
if (opt_font->answer)
- D_font(opt_font->answer);
+ D_font(opt_font->answer);
else if (opt_path->answer)
- D_font(opt_path->answer);
+ D_font(opt_path->answer);
if (opt_fontsize->answer != NULL)
- fontsize = atof(opt_fontsize->answer);
+ fontsize = atof(opt_fontsize->answer);
else
- fontsize = 12; /* dummy placeholder, should never be called */
+ fontsize = 12; /* dummy placeholder, should never be called */
if (opt_charset->answer)
- D_encoding(opt_charset->answer);
+ D_encoding(opt_charset->answer);
- /* Figure out where to put text */
- D_setup_unity(0);
- D_get_src(&t, &b, &l, &r);
+ if (opt_tit_fontsize->answer != NULL)
+ tit_fontsize = atof(opt_tit_fontsize->answer);
+ else
+ tit_fontsize = 0;
if (opt_at->answer != NULL) {
- sscanf(opt_at->answers[0], "%lf", &Y1);
- sscanf(opt_at->answers[1], "%lf", &Y0);
- sscanf(opt_at->answers[2], "%lf", &X0);
- sscanf(opt_at->answers[3], "%lf", &X1);
+ sscanf(opt_at->answers[0], "%lf", &Y1);
+ sscanf(opt_at->answers[1], "%lf", &Y0);
+ sscanf(opt_at->answers[2], "%lf", &X0);
+ sscanf(opt_at->answers[3], "%lf", &X1);
}
- else { /* default */
- Y1 = 12;
- Y0 = 88;
- X0 = 3;
- X1 = 7;
+ else { /* default */
+ Y1 = 12;
+ Y0 = 88;
+ X0 = 3;
+ X1 = 7;
- if (histo->answer) {
- X0 += 5;
- X1 += 5;
- }
+ if (histo->answer) {
+ X0 += 5;
+ X1 += 5;
+ }
}
- x0 = l + (int)((r - l) * X0 / 100.);
- x1 = l + (int)((r - l) * X1 / 100.);
- y0 = t + (int)((b - t) * (100. - Y0) / 100.); /* make lower left the origin */
- y1 = t + (int)((b - t) * (100. - Y1) / 100.);
+ if (show_bg)
+ draw(map_name, maptype, color, thin, lines, steps, fp, label_indent,
+ hide_catnum, hide_catstr, show_ticks, hide_nodata, do_smooth,
+ cats, colors, X0, X1, Y0, Y1, flip, UserRange, UserRangeMin,
+ UserRangeMax, catlist, catlistCount, use_catlist, ticksCount,
+ fontsize, tit_fontsize, title, tick_values, t_step, colorb,
+ colorbg, opt_use, opt_at, opt_fontsize, opt_tstep,
+ opt_range, histo, hidestr, log_scale, 0, digits, units);
- if (y0 > y1) { /* allow for variety in order of corner */
- flip = !flip; /* selection without broken output */
- xyTemp = y0;
- y0 = y1;
- y1 = xyTemp;
- }
- if (x0 > x1) {
- xyTemp = x0;
- x0 = x1;
- x1 = xyTemp;
- }
+ draw(map_name, maptype, color, thin, lines, steps, fp, label_indent,
+ hide_catnum, hide_catstr, show_ticks, hide_nodata, do_smooth, cats,
+ colors, X0, X1, Y0, Y1, flip, UserRange, UserRangeMin, UserRangeMax,
+ catlist, catlistCount, use_catlist, ticksCount, fontsize,
+ tit_fontsize, title, tick_values, t_step, colorb, colorbg, opt_use,
+ opt_at, opt_fontsize, opt_tstep, opt_range, histo,
+ hidestr, log_scale, 1, digits, units);
- if (x0 == x1)
- x1++; /* avoid 0 width boxes */
- if (y0 == y1)
- y1++;
-
- if ((x0 < l) || (x1 > r) || (y0 < t) || (y1 > b)) /* for mouse or at= 0- or 100+; needs to be after order check */
- G_warning(_("Legend box lies outside of frame. Text may not display properly."));
-
- horiz = (x1 - x0 > y1 - y0);
- if (horiz)
- G_message(_("Drawing horizontal legend as box width exceeds height"));
-
- if (!fp && horiz) /* better than nothing */
- do_smooth = TRUE;
-
-
- MaxLabelLen = 0; /* init variable */
-
- /* How many categories to show */
- if (!fp) {
- if (Rast_read_range(map_name, "", &range) == -1)
- G_fatal_error(_("Range information for <%s> not available (run r.support)"),
- map_name);
-
- Rast_get_range_min_max(&range, &min_ind, &max_ind);
- if (Rast_is_c_null_value(&min_ind))
- G_fatal_error(_("Input map contains no data"));
-
- Rast_get_c_color_range(&min_colr, &max_colr, &colors);
-
- if (UserRange) {
- if (min_ind < UserRangeMin)
- min_ind = (int)ceil(UserRangeMin);
- if (max_ind > UserRangeMax)
- max_ind = (int)floor(UserRangeMax);
- if (min_ind > UserRangeMin) {
- min_ind =
- UserRangeMin <
- min_colr ? min_colr : (int)ceil(UserRangeMin);
- G_warning(_("Requested range exceeds lower limit of actual data"));
- }
- if (max_ind < UserRangeMax) {
- max_ind =
- UserRangeMax >
- max_colr ? max_colr : (int)floor(UserRangeMax);
- G_warning(_("Requested range exceeds upper limit of actual data"));
- }
- }
-
- /* cats_num is total number of categories in raster */
- /* do_cats is total number of categories to be displayed */
- /* k is number of cats to be displayed after skipping unlabeled cats */
- /* lines is number of text lines/legend window */
-
- cats_num = max_ind - min_ind + 1;
-
- if (lines == 0)
- lines = cats_num;
-
- do_cats = cats_num > lines ? lines : cats_num;
-
- if (do_cats == cats_num)
- lines = (int)ceil((1.0 * lines) / thin);
-
- if (!use_catlist) {
- catlist = (double *)G_calloc(lines + 1, sizeof(double));
- catlistCount = lines;
- }
- /* see how many boxes there REALLY will be */
- maxCat = 0.0;
- for (i = min_ind, j = 1, k = 0; j <= do_cats && i <= max_ind;
- j++, i += thin) {
- if (!flip)
- cstr = Rast_get_c_cat(&i, &cats);
- else {
- CELL cat = max_ind - (i - min_ind);
- cstr = Rast_get_c_cat(&cat, &cats);
- }
-
- if (!use_catlist)
- catlist[j - 1] = (double)i;
-
- if (!cstr[0]) { /* no cat label found, skip str output */
- if (hide_nodata)
- continue;
- }
- else { /* ie has a label */
- if (!hide_catstr && (MaxLabelLen < strlen(cstr)))
- MaxLabelLen = strlen(cstr);
- }
-
- if (!hide_catnum)
- if (i > maxCat)
- maxCat = (double)i;
- k++; /* count of actual boxes drawn (hide_nodata option invaidates using j-1) */
- }
- lines = k;
-
- /* figure out how long the category + label will be */
- if (use_catlist) {
- MaxLabelLen = 0;
- maxCat = 0; /* reset */
- for (i = 0, k = 0; i < catlistCount; i++) {
- if ((catlist[i] < min_ind) || (catlist[i] > max_ind)) {
- G_fatal_error(_("use=%s out of range [%d,%d] (extend with range= ?)"),
- opt_use->answers[i], min_ind, max_ind);
- }
-
- cstr = Rast_get_d_cat(&catlist[i], &cats);
- if (!cstr[0]) { /* no cat label found, skip str output */
- if (hide_nodata)
- continue;
- }
- else { /* ie has a label */
- if (!hide_catstr && (MaxLabelLen < strlen(cstr)))
- MaxLabelLen = strlen(cstr);
- }
- if (!hide_catnum)
- if (catlist[i] > maxCat)
- maxCat = catlist[i];
- k++;
- }
- if (0 == k) /* nothing to draw */
- lines = 0;
- }
-
- if (MaxLabelLen > 0) { /* ie we've picked up at least one label */
- MaxLabelLen++; /* compensate for leading space */
- if (!hide_catnum)
- MaxLabelLen += 3; /* compensate for "%2d) " */
- }
- else {
- if (!hide_catnum)
- MaxLabelLen = 1;
- }
-
- /* compensate for categories >100 */
- if (!hide_catnum) {
- if (maxCat > 99)
- MaxLabelLen += (int)(log10(maxCat));
- }
-
- /* following covers both the above if(do_cats == cats_num) and k++ loop */
- if (lines < 1) {
- lines = 1; /* ward off the dpl floating point exception */
- G_fatal_error(_("Nothing to draw! (no categories with labels? out of range?)"));
- }
-
- /* Figure number of lines, number of pixles per line and text size */
- dots_per_line = ((y1 - y0) / lines);
-
- /* switch to a smooth legend for CELL maps with too many cats */
- /* an alternate solution is to set dots_per_line=1 */
- if ((dots_per_line == 0) && (do_smooth == FALSE)) {
- if (!use_catlist) {
- G_message(_("Forcing a smooth legend: too many categories for current window height"));
- do_smooth = TRUE;
- }
- }
-
- /* center really tiny legends */
- if (opt_at->answer == NULL) { /* if defualt scaling */
- if (!do_smooth && (dots_per_line < 4)) /* if so small that there's no box */
- if ((b - (dots_per_line * lines)) / (b * 1.0) > 0.15) /* if there's more than a 15% blank at the bottom */
- y0 = ((b - t) - (dots_per_line * lines)) / 2;
- }
-
- /* D_text_size(dots_per_line*4/5., dots_per_line*4/5.); redundant */
- /* if(Rast_is_c_null_value(&min_ind) && Rast_is_c_null_value(&max_ind))
- {
- min_ind = 1;
- max_ind = 0;
- } */
-
- if (horiz)
- sprintf(DispFormat, "%%d");
- else {
- if (maxCat > 0.0)
- sprintf(DispFormat, "%%%dd", (int)(log10(fabs(maxCat))) + 1);
- else
- sprintf(DispFormat, "%%2d");
- }
- }
- else { /* is fp */
- if (maptype == MAP_TYPE_RASTER2D) {
- if (Rast_read_fp_range(map_name, "", &fprange) == -1)
- G_fatal_error(_("Range information for <%s> not available"),
- map_name);
- }
- else {
- if (Rast3d_read_range(map_name, "", &fprange) == -1)
- G_fatal_error(_("Range information for <%s> not available"),
- map_name);
- }
-
- Rast_get_fp_range_min_max(&fprange, &dmin, &dmax);
- Rast_get_d_color_range(&min_dcolr, &max_dcolr, &colors);
-
- if (UserRange) {
- if (dmin < UserRangeMin)
- dmin = UserRangeMin;
- if (dmax > UserRangeMax)
- dmax = UserRangeMax;
- if (dmin > UserRangeMin) {
- dmin = UserRangeMin < min_dcolr ? min_dcolr : UserRangeMin;
- G_warning(_("Color range exceeds lower limit of actual data"));
- }
- if (dmax < UserRangeMax) {
- dmax = UserRangeMax > max_dcolr ? max_dcolr : UserRangeMax;
- G_warning(_("Color range exceeds upper limit of actual data"));
- }
- }
-
- if (use_catlist) {
- for (i = 0; i < catlistCount; i++) {
- if ((catlist[i] < dmin) || (catlist[i] > dmax)) {
- G_fatal_error(_("use=%s out of range [%.3f, %.3f] (extend with range= ?)"),
- opt_use->answers[i], dmin, dmax);
- }
- if (strlen(opt_use->answers[i]) > MaxLabelLen)
- MaxLabelLen = strlen(opt_use->answers[i]);
- }
- }
- do_cats = 0; /* if only to get rid of the compiler warning */
- cats_num = 0; /* if only to get rid of the compiler warning */
- /* determine how many significant digits to display based on range */
- if (0 == (dmax - dmin)) /* trap divide by 0 for single value rasters */
- sprintf(DispFormat, "%%f");
- else {
- SigDigits = (int)ceil(log10(fabs(25 / (dmax - dmin))));
- if (SigDigits < 0)
- SigDigits = 0;
- if (SigDigits < 7)
- sprintf(DispFormat, "%%.%df", SigDigits);
- else
- sprintf(DispFormat, "%%.2g"); /* eg 4.2e-9 */
- }
- }
-
- if (use_catlist) {
- cats_num = catlistCount;
- do_cats = catlistCount;
- lines = catlistCount;
- do_smooth = FALSE;
- }
-
-
- if (do_smooth) {
- int wleg, lleg, dx, dy;
- double txsiz;
- int ppl;
- int tcell;
- float ScaleFactor = 1.0;
-
- if (horiz) {
- lleg = x1 - x0;
- dx = 0;
- dy = y1 - y0;
- if (fp)
- flip = !flip; /* horiz floats look better not flipped by default */
- }
- else {
- lleg = y1 - y0;
- dy = 0;
- dx = x1 - x0;
- }
-
- /* Draw colors */
- for (k = 0; k < lleg; k++) {
- if (!fp) {
- if (!flip)
- tcell =
- min_ind + k * (double)(1 + max_ind - min_ind) / lleg;
- else
- tcell =
- (max_ind + 1) - k * (double)(1 + max_ind -
- min_ind) / lleg;
- D_color((CELL) tcell, &colors);
- }
- else {
- if (!flip)
- val = dmin + k * (dmax - dmin) / lleg;
- else
- val = dmax - k * (dmax - dmin) / lleg;
- D_d_color(val, &colors);
- }
-
- if (dx < dy)
- D_box_abs(x0 + k, y0, x0 + k + (dx ? -dx : 1),
- y0 - (dy ? -dy : 1));
- else
- D_box_abs(x0, y0 + k, x0 - (dx ? -dx : 1),
- y0 + k + (dy ? -dy : 1));
- }
-
- /* Format text */
- if (!fp) { /* cut down labelnum so they don't repeat */
- if (do_cats < steps)
- steps = do_cats;
- if (1 == steps)
- steps = 2; /* ward off the ppl floating point exception */
- }
-
- for (k = 0; k < steps; k++) {
- if (!fp) {
- if (!flip)
- tcell =
- min_ind + k * (double)(max_ind - min_ind) / (steps -
- 1);
- else
- tcell =
- max_ind - k * (double)(max_ind - min_ind) / (steps -
- 1);
-
- cstr = Rast_get_c_cat(&tcell, &cats);
-
- if (!cstr[0]) /* no cats found, disable str output */
- hide_catstr = 1;
- else
- hide_catstr = hidestr->answer;
-
- buff[0] = 0; /* blank string */
-
- if (!hide_catnum) { /* num */
- sprintf(buff, DispFormat, tcell);
- if (!hide_catstr) /* both */
- strcat(buff, ")");
- }
- if (!hide_catstr) /* str */
- sprintf(buff + strlen(buff), " %s", cstr);
- }
- else { /* ie FP map */
- if (hide_catnum)
- buff[0] = 0; /* no text */
- else {
- if (!flip)
- val = dmin + k * (dmax - dmin) / (steps - 1);
- else
- val = dmax - k * (dmax - dmin) / (steps - 1);
-
- sprintf(buff, DispFormat, val);
- }
- }
-
- /* this probably shouldn't happen mid-loop as text sizes
- might not end up being uniform, but it's a start */
- if (strlen(buff) > MaxLabelLen)
- MaxLabelLen = strlen(buff);
-
- /* Draw text */
- if (!horiz)
- txsiz = (y1 - y0) / 20;
- else
- txsiz = (x1 - x0) / 20;
-
- /* scale text to fit in window if position not manually set */
- /* usually not needed, except when frame is really narrow */
- if (opt_at->answer == NULL) { /* ie default scaling */
- ScaleFactor = ((r - x1) / ((MaxLabelLen + 1) * txsiz * 0.81)); /* ?? txsiz*.81=actual text width. */
- if (ScaleFactor < 1.0) {
- txsiz = txsiz * ScaleFactor;
- }
- }
-
- if (opt_fontsize->answer != NULL)
- txsiz = fontsize;
-
- if (txsiz < 0)
- txsiz = 0; /* keep it sane */
-
- D_text_size(txsiz, txsiz);
- D_use_color(color);
-
- ppl = (lleg) / (steps - 1);
-
- if (!horiz) {
- if (!k) /* first */
- D_pos_abs(x1 + 4, y0 + txsiz);
- else if (k == steps - 1) /* last */
- D_pos_abs(x1 + 4, y1);
- else
- D_pos_abs(x1 + 4, y0 + ppl * k + txsiz / 2);
- }
- else {
- /* text width is 0.81 of text height? so even though we set width
- to txsiz with D_text_size(), we still have to reduce.. hmmm */
- if (!k) /* first */
- D_pos_abs(x0 - (strlen(buff) * txsiz * .81 / 2),
- y1 + 4 + txsiz);
- else if (k == steps - 1) /* last */
- D_pos_abs(x1 - (strlen(buff) * txsiz * .81 / 2),
- y1 + 4 + txsiz);
- else
- D_pos_abs(x0 + ppl * k -
- (strlen(buff) * txsiz * .81 / 2),
- y1 + 4 + txsiz);
- }
-
- if (color)
- D_text(buff);
-
- } /* for */
-
- lleg = y1 - y0;
- wleg = x1 - x0;
-
- /* Black box */
- D_use_color(black);
- D_begin();
- D_move_abs(x0 + 1, y0 + 1);
- D_cont_rel(0, lleg - 2);
- D_cont_rel(wleg - 2, 0);
- D_cont_rel(0, 2 - lleg);
- D_close();
- D_end();
- D_stroke();
-
- /* White box */
- D_use_color(white);
- D_begin();
- D_move_abs(x0, y0);
- D_cont_rel(0, lleg);
- D_cont_rel(wleg, 0);
- D_cont_rel(0, -lleg);
- D_close();
- D_end();
- D_stroke();
-
-
- /* print units label, if present */
- if (maptype == MAP_TYPE_RASTER2D)
- units = Rast_read_units(map_name, "");
- else
- units = "";
-/* FIXME: does the raster3d really need to be opened to read the units?
- units = Rast3d_get_unit(map_fid); */
-
- if (!units)
- units = "";
-
- if(strlen(units)) {
- double x_pos, y_pos;
- int default_pos = TRUE;
-
- D_use_color(color);
- /* D_text_size() should be already set */
-
- if (horiz) {
- x_pos = (x0 + x1)/2. - (strlen(units) * txsiz * 0.81)/2;
- y_pos = y1 + (txsiz * 3);
- }
- else {
- x_pos = x1 - 4;
- if (default_pos)
- y_pos = y0 - (txsiz * 1.75);
- else
- y_pos = y1 + (txsiz * 2.75);
- }
-
- D_pos_abs(x_pos, y_pos);
- D_text(units);
- }
-
-
- /* display sidebar histogram, if requested */
- if (histo->answer) {
-
- render_range.min = (DCELL)(fp ? dmin : min_ind);
- render_range.max = (DCELL)(fp ? dmax : max_ind);
- /* reuse flag to indicate if user-specified or default ranging */
- render_range.first_time = opt_range->answer ? TRUE : FALSE;
-
- draw_histogram(map_name, x0, y0, wleg, lleg, color, flip, horiz,
- maptype, fp, render_range);
- }
-
- }
- else { /* non FP, no smoothing */
-
- int true_l, true_r;
- double txsiz;
- float ScaleFactor = 1.0;
-
- if (histo->answer)
- G_warning(_("Histogram plotting not implemented for categorical legends. "
- "Use the '-s' flag"));
-
- /* set legend box bounds */
- true_l = l;
- true_r = r; /* preserve window width */
- l = x0;
- t = y0;
- r = x1;
- b = y1;
-
- D_pos_abs(x0, y0);
-
- /* figure out box height */
- if (do_cats == cats_num)
- dots_per_line = (b - t) / (lines + 1); /* +1 line for the two 1/2s at top and bottom */
- else
- dots_per_line = (b - t) / (lines + 2); /* + another line for 'x of y categories' text */
-
- /* adjust text size */
- /* txsiz = (int)((y1-y0)/(1.5*(lines+5))); */
- txsiz = (y1 - y0) / (2.0 * lines);
-
- /* scale text to fit in window if position not manually set */
- if (opt_at->answer == NULL) { /* ie defualt scaling */
- ScaleFactor = ((true_r - true_l) / ((MaxLabelLen + 3) * txsiz * 0.81)); /* ?? txsiz*.81=actual text width. */
- if (ScaleFactor < 1.0) {
- txsiz = txsiz * ScaleFactor;
- dots_per_line = (int)floor(dots_per_line * ScaleFactor);
- }
- }
-
- if (dots_per_line < txsiz)
- txsiz = dots_per_line;
-
- if (opt_fontsize->answer != NULL)
- txsiz = fontsize;
-
- D_text_size(txsiz, txsiz);
-
-
- /* Set up box arrays */
- x_box[0] = 0;
- y_box[0] = 0;
- x_box[1] = 0;
- y_box[1] = (5 - dots_per_line);
- x_box[2] = (dots_per_line - 5);
- y_box[2] = 0;
- x_box[3] = 0;
- y_box[3] = (dots_per_line - 5);
- x_box[4] = (5 - dots_per_line);
- y_box[4] = 0;
-
-
- /* Draw away */
-
- /* if(ScaleFactor < 1.0) */
- /* cur_dot_row = ((b-t) - (dots_per_line*lines))/2; *//* this will center the legend */
- /* else */
- cur_dot_row = t + dots_per_line / 2;
-
- /* j = (do_cats == cats_num ? 1 : 2 ); */
-
- for (i = 0, k = 0; i < catlistCount; i++)
- /* for(i=min_ind, j=1, k=0; j<=do_cats && i<=max_ind; j++, i+=thin) */
- {
- if (!flip)
- cstr = Rast_get_d_cat(&catlist[i], &cats);
- else
- cstr = Rast_get_d_cat(&catlist[catlistCount - i - 1], &cats);
-
-
- if (!cstr[0]) { /* no cat label found, skip str output */
- hide_catstr = 1;
- if (hide_nodata)
- continue;
- }
- else
- hide_catstr = hidestr->answer;
-
- k++; /* count of actual boxes drawn (hide_nodata option invaidates using j-1) */
-
- /* White box */
- cur_dot_row += dots_per_line;
- D_use_color(white);
- D_begin();
- D_move_abs(l + 2, (cur_dot_row - 1));
- D_cont_rel(0, (3 - dots_per_line));
- D_cont_rel((dots_per_line - 3), 0);
- D_cont_rel(0, (dots_per_line - 3));
- D_close();
- D_end();
- D_stroke();
-
- /* Black box */
- D_use_color(black);
- D_begin();
- D_move_abs(l + 3, (cur_dot_row - 2));
- D_cont_rel(0, (5 - dots_per_line));
- D_cont_rel((dots_per_line - 5), 0);
- D_cont_rel(0, (dots_per_line - 5));
- D_close();
- D_end();
- D_stroke();
-
- /* Color solid box */
- if (!fp) {
- if (!flip)
- D_color((CELL) (int)catlist[i], &colors);
- else
- D_color((CELL) (int)catlist[catlistCount - i - 1],
- &colors);
- }
- else {
- if (!flip)
- D_d_color(catlist[i], &colors);
- else
- D_d_color(catlist[catlistCount - i - 1], &colors);
- }
-
- D_pos_abs(l + 3, (cur_dot_row - 2));
- D_polygon_rel(x_box, y_box, 5);
-
- /* Draw text */
- D_use_color(color);
-
- if (!fp) {
- /* nothing, box only */
- buff[0] = 0;
- if (!hide_catnum) { /* num */
- sprintf(buff, DispFormat, (int)catlist[i]);
- if (!flip)
- sprintf(buff, DispFormat, (int)catlist[i]);
- else
- sprintf(buff, DispFormat,
- (int)catlist[catlistCount - i - 1]);
- if (!hide_catstr) /* both */
- strcat(buff, ")");
- }
- if (!hide_catstr) /* str */
- sprintf(buff + strlen(buff), " %s", cstr);
- }
- else { /* is fp */
- if (!flip) {
- if (use_catlist)
- /* pass through format exactly as given by the user in
- the use= command line parameter (helps with log scale) */
- sprintf(buff, "%s", opt_use->answers[i]);
- else
- /* automatically generated/tuned decimal precision format */
- sprintf(buff, DispFormat, catlist[i]);
- }
- else {
- if(use_catlist)
- sprintf(buff, "%s", opt_use->answers[catlistCount - i - 1]);
- else
- sprintf(buff, DispFormat, catlist[catlistCount - i - 1]);
- }
- }
-
- D_pos_abs((l + 3 + dots_per_line), (cur_dot_row) - 3);
-
- if (color)
- D_text(buff);
- }
-
- if (0 == k)
- G_fatal_error(_("Nothing to draw! (no categories with labels?)")); /* "(..., out of range?)" */
-
-
- if (do_cats != cats_num) {
- cur_dot_row += dots_per_line;
- /* sprintf(buff, "%d of %d categories\n", (j-1), cats_num); */
-
- sprintf(buff, "%d of %d categories\n", k, cats_num);
-
- /* shrink text if it will run off the screen */
- MaxLabelLen = strlen(buff) + 4;
- ScaleFactor = ((true_r - true_l) / (MaxLabelLen * txsiz * 0.81)); /* ?? txsiz*.81=actual text width. */
- if (ScaleFactor < 1.0) {
- txsiz = txsiz * ScaleFactor;
-
- if (opt_fontsize->answer != NULL)
- txsiz = fontsize;
-
- D_text_size(txsiz, txsiz);
- }
- D_use_color(white);
- D_pos_abs((l + 3 + dots_per_line), (cur_dot_row));
- if (color)
- D_text(buff);
- }
- }
-
- D_save_command(G_recreate_command());
D_close_driver();
exit(EXIT_SUCCESS);
More information about the grass-commit
mailing list