[GRASS-SVN] r60093 - grass/trunk/display/d.legend
svn_grass at osgeo.org
svn_grass at osgeo.org
Sun May 4 23:07:16 PDT 2014
Author: hamish
Date: 2014-05-04 23:07:16 -0700 (Sun, 04 May 2014)
New Revision: 60093
Added:
grass/trunk/display/d.legend/get_stats.c
grass/trunk/display/d.legend/histogram.c
Modified:
grass/trunk/display/d.legend/
grass/trunk/display/d.legend/local_proto.h
grass/trunk/display/d.legend/main.c
Log:
add support for histogram sidebars (#1049)
Property changes on: grass/trunk/display/d.legend
___________________________________________________________________
Modified: svn:ignore
- OBJ.*
+ OBJ.*
*.tmp.html
Copied: grass/trunk/display/d.legend/get_stats.c (from rev 60092, grass/trunk/display/d.histogram/get_stats.c)
===================================================================
--- grass/trunk/display/d.legend/get_stats.c (rev 0)
+++ grass/trunk/display/d.legend/get_stats.c 2014-05-05 06:07:16 UTC (rev 60093)
@@ -0,0 +1,145 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <grass/gis.h>
+#include <grass/raster.h>
+#include <grass/spawn.h>
+#include "local_proto.h"
+
+
+void run_stats(const char *mapname, int nsteps, const char *tempfile)
+{
+ char buf[32];
+ const char *argv[12];
+ int argc = 0;
+
+ argv[argc++] = "r.stats";
+
+ argv[argc++] = "-r";
+ argv[argc++] = "-c";
+ argv[argc++] = mapname;
+
+ sprintf(buf, "nsteps=%d", nsteps);
+ argv[argc++] = buf;
+
+ argv[argc++] = SF_REDIRECT_FILE;
+ argv[argc++] = SF_STDOUT;
+ argv[argc++] = SF_MODE_OUT;
+ argv[argc++] = tempfile;
+
+ argv[argc++] = NULL;
+
+ if (G_vspawn_ex(argv[0], argv) != 0)
+ G_fatal_error("error running r.stats");
+}
+
+/* linked list of stats */
+void get_stats(const char *mapname, struct stat_list *dist_stats, int nsteps)
+{
+ 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 */
+ 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");
+ }
+*/
+ run_stats(mapname, nsteps, tempfile);
+
+ /* 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.");
+ }
+ dist_stats->ptr = NULL;
+ dist_stats->count = 0;
+ dist_stats->sumstat = 0;
+
+ 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++;
+
+ /* 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 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;
+ }
+ fclose(fd);
+ unlink(tempfile);
+}
Added: grass/trunk/display/d.legend/histogram.c
===================================================================
--- grass/trunk/display/d.legend/histogram.c (rev 0)
+++ grass/trunk/display/d.legend/histogram.c 2014-05-05 06:07:16 UTC (rev 60093)
@@ -0,0 +1,93 @@
+/* histogram.c:
+ * Draws a histogram along the left side of a smooth gradient legend
+ * (stats fetching code adapted from d.histogram)
+ *
+ * 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 <grass/gis.h>
+#include <grass/display.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 i, nsteps;
+ long cell_count;
+ double max_width, width_mult, dx;
+ struct stat_list dist_stats;
+ struct stat_node *ptr;
+
+ if (horiz) {
+ max_width = height * 1.75;
+ nsteps = width - 3;
+ }
+ else {
+ max_width = width * 1.75;
+ nsteps = height - 3;
+ }
+
+ /* get the distribution statistics */
+ get_stats(map_name, &dist_stats, nsteps);
+
+ width_mult = max_width / dist_stats.maxstat;
+
+ D_use_color(color);
+ D_begin();
+
+ ptr = dist_stats.ptr;
+ for (i = dist_stats.mincat; i <= dist_stats.maxcat; i++) {
+ if (!ptr)
+ break;
+
+ 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 */
+
+ /* 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(4, "No matching stat found, i=%d", i);
+ }
+
+ if (!cell_count)
+ continue;
+
+ dx = cell_count * width_mult;
+
+ if (horiz) {
+ if (flip)
+ D_move_abs(x0 + width - i - 1, y0 - 1);
+ else
+ D_move_abs(x0 + i + 1, y0 - 1);
+
+ D_cont_rel(0, -dx);
+ }
+ else { /* vertical */
+ if (flip)
+ D_move_abs(x0 - 1, y0 - 1 + height - i);
+ else
+ D_move_abs(x0 - 1, y0 + 1 + i);
+
+ D_cont_rel(-dx, 0);
+ }
+
+ }
+
+ D_close();
+ D_end();
+ D_stroke();
+}
Property changes on: grass/trunk/display/d.legend/histogram.c
___________________________________________________________________
Added: svn:mime-type
+ text/x-csrc
Added: svn:eol-style
+ native
Modified: grass/trunk/display/d.legend/local_proto.h
===================================================================
--- grass/trunk/display/d.legend/local_proto.h 2014-05-05 02:25:02 UTC (rev 60092)
+++ grass/trunk/display/d.legend/local_proto.h 2014-05-05 06:07:16 UTC (rev 60093)
@@ -0,0 +1,27 @@
+struct stat_node
+{
+ long int cat; /* cell-file category value */
+ long int stat; /* statistic: number of cells with that cat */
+ struct stat_node *next; /* pointer to next stat_node in list */
+};
+
+struct stat_list
+{
+ struct stat_node *ptr; /* pointer to first stat_node in list */
+ long int count, /* number of stat_nodes in list
+ (not counting null cells) */
+ null_stat, /* stats for null cell */
+ maxstat, /* max. statistic in list */
+ minstat, /* min. statistic in list */
+ sumstat, /* sum of all statistics in list */
+ maxcat, /* max. cell-file category value in list */
+ mincat; /* min. cell-file category value in list */
+};
+
+
+/* histogram.c */
+void draw_histogram(const char *, int, int, int, int, int, int, int);
+
+/* get_stats.c */
+void get_stats(const char *, struct stat_list *, int);
+void run_stats(const char *, int, const char *);
Modified: grass/trunk/display/d.legend/main.c
===================================================================
--- grass/trunk/display/d.legend/main.c 2014-05-05 02:25:02 UTC (rev 60092)
+++ grass/trunk/display/d.legend/main.c 2014-05-05 06:07:16 UTC (rev 60093)
@@ -60,7 +60,7 @@
struct Option *opt_input, *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;
+ struct Flag *hidestr, *hidenum, *hidenodata, *smooth, *flipit, *histo;
struct Range range;
struct FPRange fprange;
CELL min_ind, max_ind, null_cell;
@@ -111,7 +111,8 @@
opt_thin->required = NO;
opt_thin->answer = "1";
opt_thin->options = "1-1000";
- opt_thin->description = _("Thinning factor (thin=10 gives cats 0,10,20...)");
+ opt_thin->description =
+ _("Thinning factor (thin=10 gives cats 0,10,20...)");
opt_thin->guisection = _("Advanced");
opt_labelnum = G_define_option();
@@ -119,23 +120,25 @@
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");
+ opt_labelnum->description =
+ _("Number of text labels for smooth gradient legend");
opt_labelnum->guisection = _("Gradient");
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");
@@ -145,7 +148,7 @@
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)");
@@ -207,6 +210,12 @@
flipit->description = _("Flip legend");
flipit->guisection = _("Advanced");
+ histo = G_define_flag();
+ histo->key = 'd';
+ histo->description = _("Add histogram to smoothed legend");
+ histo->guisection = _("Advanced");
+
+
/* Check command line */
if (G_parser(argc, argv))
exit(EXIT_FAILURE);
@@ -220,11 +229,6 @@
do_smooth = smooth->answer;
flip = flipit->answer;
- if (opt_fontsize->answer != NULL)
- fontsize = atof(opt_fontsize->answer);
- else
- fontsize = 12; /* dummy placeholder, should never be called */
-
color = D_parse_color(opt_color->answer, TRUE);
if (opt_lines->answer != NULL)
@@ -298,6 +302,11 @@
else if (opt_path->answer)
D_font(opt_path->answer);
+ if (opt_fontsize->answer != NULL)
+ fontsize = atof(opt_fontsize->answer);
+ else
+ fontsize = 12; /* dummy placeholder, should never be called */
+
if (opt_charset->answer)
D_encoding(opt_charset->answer);
@@ -316,6 +325,11 @@
Y0 = 88;
X0 = 3;
X1 = 7;
+
+ if (histo->answer) {
+ X0 += 5;
+ X1 += 5;
+ }
}
x0 = l + (int)((r - l) * X0 / 100.);
@@ -755,6 +769,15 @@
D_end();
D_stroke();
+
+ if (histo->answer) {
+ if (opt_range->answer != NULL)
+ G_warning(_("Histogram constrained by range not yet implemented"));
+ else
+ draw_histogram(map_name, x0, y0, wleg, lleg, color, flip,
+ horiz);
+ }
+
}
else { /* non FP, no smoothing */
More information about the grass-commit
mailing list