[GRASS-SVN] r71870 - in grass/trunk: include include/defs lib/raster

svn_grass at osgeo.org svn_grass at osgeo.org
Wed Nov 29 11:26:15 PST 2017


Author: mmetz
Date: 2017-11-29 11:26:15 -0800 (Wed, 29 Nov 2017)
New Revision: 71870

Modified:
   grass/trunk/include/defs/raster.h
   grass/trunk/include/raster.h
   grass/trunk/lib/raster/range.c
Log:
libraster: add raster statistics

Modified: grass/trunk/include/defs/raster.h
===================================================================
--- grass/trunk/include/defs/raster.h	2017-11-29 16:03:24 UTC (rev 71869)
+++ grass/trunk/include/defs/raster.h	2017-11-29 19:26:15 UTC (rev 71870)
@@ -528,6 +528,9 @@
 void Rast_init_fp_range(struct FPRange *);
 void Rast_get_fp_range_min_max(const struct FPRange *, DCELL *, DCELL *);
 
+int Rast_read_rstats(const char *, const char *, struct R_stats *);
+void Rast_write_rstats(const char *, const struct R_stats *);
+
 /* raster.c */
 int Rast_raster_cmp(const void *, const void *, RASTER_MAP_TYPE);
 void Rast_raster_cpy(void *, const void *, int, RASTER_MAP_TYPE);

Modified: grass/trunk/include/raster.h
===================================================================
--- grass/trunk/include/raster.h	2017-11-29 16:03:24 UTC (rev 71869)
+++ grass/trunk/include/raster.h	2017-11-29 19:26:15 UTC (rev 71870)
@@ -215,11 +215,19 @@
     } *list;
 };
 
+struct R_stats
+{
+    DCELL sum;
+    DCELL sumsq;
+    off_t count;
+};
+
 struct Range
 {
     CELL min;
     CELL max;
     int first_time;		/* whether or not range was updated */
+    struct R_stats rstats;
 };
 
 struct FPRange
@@ -227,6 +235,7 @@
     DCELL min;
     DCELL max;
     int first_time;		/* whether or not range was updated */
+    struct R_stats rstats;
 };
 
 struct FP_stats {

Modified: grass/trunk/lib/raster/range.c
===================================================================
--- grass/trunk/lib/raster/range.c	2017-11-29 16:03:24 UTC (rev 71869)
+++ grass/trunk/lib/raster/range.c	2017-11-29 19:26:15 UTC (rev 71870)
@@ -22,6 +22,8 @@
 #define DEFAULT_CELL_MIN 1
 #define DEFAULT_CELL_MAX 255
 
+static void init_rstats(struct R_stats *);
+
 /*!
    \brief Remove floating-point range
 
@@ -241,6 +243,104 @@
 }
 
 /*!
+ * \brief Read raster stats
+ *
+ * Read the stats file <i>stats</i>. This file is
+ * written in binary using XDR format.
+ *
+ * An empty stats file indicates that all cells are NULL. This
+ * is a valid case, and the result should be an initialized rstats
+ * struct with no defined stats.  If the stats file is missing
+ * this function will create a default stats with count = 0.
+ *
+ * \param name map name
+ * \param mapset mapset name
+ * \param rstats pointer to R_stats structure which holds raster stats
+ *
+ * \return 1 on success
+ * \return 2 stats is empty
+ * \return -1 on error or stats file does not exist
+ */
+int Rast_read_rstats(const char *name, const char *mapset,
+		       struct R_stats *rstats)
+{
+    int fd;
+    char xdr_buf[2][XDR_DOUBLE_NBYTES];
+    DCELL dcell1, dcell2;
+    unsigned char cc[8];
+    char nbytes;
+    int i;
+    off_t count;
+
+    Rast_init();
+    init_rstats(rstats);
+
+    fd = -1;
+
+    if (!G_find_file2_misc("cell_misc", "stats", name, mapset)) {
+	G_debug(1, "Stats file does not exist");
+	return -1;
+    }
+
+    fd = G_open_old_misc("cell_misc", "stats", name, mapset);
+    if (fd < 0) {
+	G_warning(_("Unable to read stats file for <%s>"),
+		  G_fully_qualified_name(name, mapset));
+	return -1;
+    }
+
+    if (read(fd, xdr_buf, sizeof(xdr_buf)) != sizeof(xdr_buf)) {
+	/* if the stats file exists, but empty file, meaning Nulls */
+	close(fd);
+	G_debug(1, "Empty stats file meaning Nulls for <%s>",
+		  G_fully_qualified_name(name, mapset));
+	return 2;
+    }
+
+    G_xdr_get_double(&dcell1, xdr_buf[0]);
+    G_xdr_get_double(&dcell2, xdr_buf[1]);
+
+    rstats->sum = dcell1;
+    rstats->sumsq = dcell2;
+
+    /* count; see cell_values_int() in get_row.c */
+    nbytes = 1;
+    if (read(fd, &nbytes, 1) != 1) {
+	/* if the stats file exists, but empty file, meaning Nulls */
+	close(fd);
+	G_debug(1, "Unable to read byte count in stats file for <%s>",
+		  G_fully_qualified_name(name, mapset));
+	return -1;
+    }
+
+    if (nbytes < 1 || nbytes > sizeof(off_t)) {
+	close(fd);
+	G_debug(1, "Invalid byte count in stats file for <%s>",
+		  G_fully_qualified_name(name, mapset));
+	return -1;
+    }
+    if (read(fd, cc, nbytes) != nbytes) {
+	/* incorrect number of bytes for count */
+	close(fd);
+	G_debug(1, "Unable to read count in stats file for <%s>",
+		  G_fully_qualified_name(name, mapset));
+	return -1;
+    }
+
+    count = 0;
+    /* copy byte by byte */
+    for (i = nbytes - 1; i >= 0; i--) {
+	count = (count << 8);
+	count = count + cc[i];
+    }
+    rstats->count = count;
+
+    close(fd);
+
+    return 1;
+}
+
+/*!
  * \brief Write raster range file
  *
  * This routine writes the range information for the raster map
@@ -259,6 +359,8 @@
 {
     FILE *fp;
 
+    Rast_write_rstats(name, &(range->rstats));
+
     if (Rast_map_type(name, G_mapset()) != CELL_TYPE) {
 	G_remove_misc("cell_misc", "range", name);	/* remove the old file with this name */
 	G_fatal_error(_("Unable to write range file for <%s>"), name);
@@ -294,6 +396,8 @@
 
     Rast_init();
 
+    Rast_write_rstats(name, &(range->rstats));
+
     fd = G_open_new_misc("cell_misc", "f_range", name);
     if (fd < 0) {
 	G_remove_misc("cell_misc", "f_range", name);
@@ -318,6 +422,73 @@
 }
 
 /*!
+ * \brief Write raster stats file
+ *
+ * Write the stats file <tt>stats</tt>. This file is
+ * written in binary using XDR format. If the count is < 1
+ * in <em>rstats</em>, an empty <tt>stats</tt> file is created.
+ *
+ * \param name map name
+ * \param rstats pointer to R_stats which holds stats info
+ */
+void Rast_write_rstats(const char *name, const struct R_stats *rstats)
+{
+    int fd;
+    char xdr_buf[2][XDR_DOUBLE_NBYTES];
+    unsigned char cc[8];
+    char nbytes;
+    int i;
+    off_t count;
+
+    Rast_init();
+
+    fd = G_open_new_misc("cell_misc", "stats", name);
+    if (fd < 0) {
+	G_remove_misc("cell_misc", "stats", name);
+	G_fatal_error(_("Unable to write stats file for <%s>"), name);
+    }
+
+    /* if count is zero, write empty file meaning Nulls */
+    if (rstats->count < 1) {
+	close(fd);
+	return;
+    }
+
+    G_xdr_put_double(xdr_buf[0], &rstats->sum);
+    G_xdr_put_double(xdr_buf[1], &rstats->sumsq);
+
+    if (write(fd, xdr_buf, sizeof(xdr_buf)) != sizeof(xdr_buf)) {
+	G_remove_misc("cell_misc", "stats", name);
+	G_fatal_error(_("Unable to write stats file for <%s>"), name);
+    }
+
+    /* count; see convert_int() in put_row.c */
+    count = rstats->count;
+    nbytes = 0;
+    /* copy byte by byte */
+    for (i = 0; i < sizeof(off_t); i++) {
+	cc[i] = count & 0xff;
+	count >>= 8;
+	if (cc[i])
+	    nbytes = i;
+    }
+    nbytes++;
+
+    /* number of bytes needed for count */
+    if (write(fd, &nbytes, 1) != 1) {
+	G_remove_misc("cell_misc", "stats", name);
+	G_fatal_error(_("Unable to write stats file for <%s>"), name);
+    }
+
+    if (write(fd, cc, nbytes) != nbytes) {
+	G_remove_misc("cell_misc", "stats", name);
+	G_fatal_error(_("Unable to write stats file for <%s>"), name);
+    }
+
+    close(fd);
+}
+
+/*!
  * \brief Update range structure (CELL)
  *
  * Compares the <i>cat</i> value with the minimum and maximum values
@@ -412,12 +583,21 @@
 	    range->first_time = 0;
 	    range->min = cat;
 	    range->max = cat;
+
+	    range->rstats.sum = cat;
+	    range->rstats.sumsq = (DCELL) cat * cat;
+	    range->rstats.count = 1;
+
 	    continue;
 	}
 	if (cat < range->min)
 	    range->min = cat;
 	if (cat > range->max)
 	    range->max = cat;
+
+	range->rstats.sum += cat;
+	range->rstats.sumsq += (DCELL) cat * cat;
+	range->rstats.count += 1;
     }
 }
 
@@ -461,12 +641,20 @@
 	    range->first_time = 0;
 	    range->min = val;
 	    range->max = val;
+
+	    range->rstats.sum = val;
+	    range->rstats.sumsq = val * val;
+	    range->rstats.count = 1;
 	}
 	else {
 	    if (val < range->min)
 		range->min = val;
 	    if (val > range->max)
 		range->max = val;
+
+	    range->rstats.sum += val;
+	    range->rstats.sumsq += val * val;
+	    range->rstats.count += 1;
 	}
 
 	rast = G_incr_void_ptr(rast, size);
@@ -489,6 +677,9 @@
 {
     Rast_set_c_null_value(&(range->min), 1);
     Rast_set_c_null_value(&(range->max), 1);
+
+    init_rstats(&range->rstats);
+
     range->first_time = 1;
 }
 
@@ -538,6 +729,9 @@
 {
     Rast_set_d_null_value(&(range->min), 1);
     Rast_set_d_null_value(&(range->max), 1);
+
+    init_rstats(&range->rstats);
+
     range->first_time = 1;
 }
 
@@ -572,3 +766,10 @@
 	    *max = range->max;
     }
 }
+
+static void init_rstats(struct R_stats *rstats)
+{
+    Rast_set_d_null_value(&(rstats->sum), 1);
+    Rast_set_d_null_value(&(rstats->sumsq), 1);
+    rstats->count = 0;
+}



More information about the grass-commit mailing list