[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