123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724 |
- /*
- * r3.stats
- *
- * Copyright (C) 2004-2007 by the GRASS Development Team
- * Author(s): Soeren Gebbert
- *
- * Purpose: Generates volume statistics for raster3d maps.
- *
- * This program is free software under the GNU General Public
- * License (>=v2). Read the file COPYING that comes with GRASS
- * for details.
- *
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <math.h>
- #include <grass/gis.h>
- #include <grass/raster3d.h>
- #include <grass/glocale.h>
- #define COMPARE_PRECISION 0.000000001
- /*statistic table row struct */
- typedef struct
- {
- double min, max, vol, perc;
- int num, count;
- } stat_row;
- /*the statistic table struct */
- typedef struct
- {
- stat_row **table;
- stat_row *null;
- int sum_count, nsteps, equal;
- double sum_vol, sum_perc;
- } stat_table;
- /*the equal value struct */
- typedef struct
- {
- double val; /* the equal value */
- int count; /* the appearance count */
- } equal_val;
- /*an array of groups with equal values */
- typedef struct
- {
- equal_val **values;
- int count;
- } equal_val_array;
- /*prototypes */
- static equal_val_array *alloc_equal_val_array(int count);
- static void free_equal_val_array(equal_val_array * vals);
- static equal_val_array *add_equal_val_to_array(equal_val_array * array, double val);
- static int check_equal_value(equal_val_array * array, double val);
- static stat_table *create_stat_table(int nsteps, equal_val_array * values,
- double min, double max);
- static void free_stat_table(stat_table * stats);
- static void print_stat_table(stat_table * stats);
- static void update_stat_table(stat_table * stats, RASTER3D_Region * region);
- static void heapsort_eqvals(equal_val_array * data, int n);
- static void downheap_eqvals(equal_val_array * data, int n, int k);
- static void check_range_value(stat_table * stats, double value);
- static void tree_search_range(stat_table * stats, int left, int right,
- double value);
- /* *************************************************************** */
- /* ***** allocate equal_val_array structure ********************* */
- /* *************************************************************** */
- equal_val_array *alloc_equal_val_array(int count)
- {
- equal_val_array *p;
- int i;
- p = (equal_val_array *) G_calloc(1, sizeof(equal_val_array));
- p->count = count;
- p->values = (equal_val **) G_calloc(p->count, sizeof(equal_val *));
- for (i = 0; i < p->count; i++)
- p->values[i] = (equal_val *) G_calloc(1, sizeof(equal_val));
- return p;
- }
- /* *************************************************************** */
- /* ***** add an equal_val to the equal_val_array structure ******* */
- /* *************************************************************** */
- equal_val_array *add_equal_val_to_array(equal_val_array * array, double val)
- {
- equal_val_array *p = array;
- int count;
- if (p == NULL) {
- p = alloc_equal_val_array(1);
- p->values[0]->val = val;
- p->values[0]->count = 1;
- G_debug(5, "Create new equal_array with value %g\n", val);
- }
- else {
- /*increase the count */
- count = array->count;
- count++;
- /*new memory */
- p->values =
- (equal_val **) G_realloc(p->values, count * sizeof(equal_val *));
- p->values[count - 1] = (equal_val *) G_calloc(1, sizeof(equal_val));
- /*set the new value */
- p->values[count - 1]->val = val;
- p->values[count - 1]->count = 1;
- /*set the new counter */
- p->count = count;
- G_debug(5, "Add new value %g at position %i\n", val, p->count);
- }
- return p;
- }
- /* *************************************************************** */
- /* ***** check if a value exists in the equal_val_array ********* */
- /* *************************************************************** */
- int check_equal_value(equal_val_array * array, double val)
- {
- int i;
- /*search if the new value exists and increase the counter */
- if (array != NULL)
- for (i = 0; i < array->count; i++) {
- if (array->values[i]->val == val) {
- array->values[i]->count++;
- G_debug(5, "found value %g with count %i at pos %i\n", val,
- array->values[i]->count, i);
- return 1;
- }
- }
- /*if it does not exists, add it to the array */
- add_equal_val_to_array(array, val);
- /*return 1 if found, 0 otherwise */
- return 0;
- }
- /* *************************************************************** */
- /* ***** Release the memory of a equal_val_array structure ****** */
- /* *************************************************************** */
- void free_equal_val_array(equal_val_array * uvals)
- {
- int i;
- for (i = 0; i < uvals->count; i++) {
- G_free(uvals->values[i]);
- }
- G_free(uvals->values);
- G_free(uvals);
- uvals = NULL;
- return;
- }
- /* *************************************************************** */
- /* **** Create the structure which manages the statistical ******* */
- /* **** values for a value range or equal values **************** */
- /* *************************************************************** */
- stat_table *create_stat_table(int nsteps, equal_val_array * eqvals,
- double min, double max)
- {
- stat_table *p;
- int i;
- double step;
- /* Memory */
- p = (stat_table *) G_calloc(1, sizeof(stat_table));
- p->null = (stat_row *) G_calloc(nsteps, sizeof(stat_row));
- p->table = (stat_row **) G_calloc(nsteps, sizeof(stat_row *));
- for (i = 0; i < nsteps; i++)
- p->table[i] = (stat_row *) G_calloc(1, sizeof(stat_row));
- /* Some value initializing */
- p->null->min = 0;
- p->null->max = 0;
- p->null->vol = 0;
- p->null->perc = 0;
- p->null->count = 0;
- p->null->num = nsteps + 1;
- p->nsteps = nsteps;
- p->sum_count = 0;
- p->sum_vol = 0;
- p->sum_perc = 0;
- p->equal = 0;
- /*if no equal values are provided, calculate the range and the length of each step */
- if (!eqvals) {
- /*calculate the steplength */
- step = (max - min) / (nsteps);
- p->equal = 0;
- p->table[0]->min = min;
- p->table[0]->max = min + step;
- p->table[0]->num = 1;
- p->table[0]->count = 0;
- p->table[0]->vol = 0;
- p->table[0]->perc = 0;
- G_debug(3, "Step %i range min %.11lf max %.11lf\n", p->table[0]->num,
- p->table[0]->min, p->table[0]->max);
- for (i = 1; i < nsteps; i++) {
- p->table[i]->min = p->table[i - 1]->max;
- p->table[i]->max = p->table[i - 1]->max + step;
- p->table[i]->num = i + 1;
- p->table[i]->count = 0;
- p->table[i]->vol = 0;
- p->table[i]->perc = 0;
- G_debug(5, "Step %i range min %.11lf max %.11lf\n",
- p->table[i]->num, p->table[i]->min, p->table[i]->max);
- }
- /* the last value must be a bit larger */
- p->table[nsteps - 1]->max += COMPARE_PRECISION;
- }
- else { /* Create equal value statistic */
- p->equal = 1;
- for (i = 0; i < eqvals->count; i++) {
- p->table[i]->min = eqvals->values[i]->val; /* equal values have no range, set min and max to the same value */
- p->table[i]->max = eqvals->values[i]->val;
- p->table[i]->num = i + 1;
- p->table[i]->count = eqvals->values[i]->count; /* the appearance count for each equal value */
- p->table[i]->vol = 0;
- p->table[i]->perc = 0;
- G_debug(5, "Unique value %i = %g count %i\n", p->table[i]->num,
- p->table[i]->min, p->table[i]->count);
- }
- }
- return p;
- }
- /* *************************************************************** */
- /* ***** Release the memory of a stat_table structure ************ */
- /* *************************************************************** */
- void free_stat_table(stat_table * stats)
- {
- int i;
- for (i = 0; i < stats->nsteps; i++) {
- G_free(stats->table[i]);
- }
- G_free(stats->table);
- G_free(stats->null);
- G_free(stats);
- stats = NULL;
- return;
- }
- /* *************************************************************** */
- /* **** Compute the volume, percentage and sums ****************** */
- /* *************************************************************** */
- void update_stat_table(stat_table * stats, RASTER3D_Region * region)
- {
- int i;
- double vol = region->ns_res * region->ew_res * region->tb_res;
- int cellnum = region->rows * region->cols * region->depths;
- /*Calculate volume and percentage for each range or equal value and the sum stats */
- for (i = 0; i < stats->nsteps; i++) {
- stats->table[i]->vol = stats->table[i]->count * vol;
- stats->table[i]->perc =
- (double)(100.0 * (double)stats->table[i]->count /
- (double)cellnum);
- stats->sum_count += stats->table[i]->count;
- stats->sum_vol += stats->table[i]->vol;
- stats->sum_perc += stats->table[i]->perc;
- }
- /*calculate the null value stats */
- stats->null->vol = stats->null->count * vol;
- stats->null->perc =
- (double)(100.0 * (double)stats->null->count / (double)cellnum);
- return;
- }
- /* *************************************************************** */
- /* *************************************************************** */
- /* *************************************************************** */
- void print_stat_table(stat_table * stats)
- {
- int i;
- if (stats->equal) {
- /* 1234567 012345678901234567 0123456789012 0123456 0123456789 */
- fprintf(stdout,
- " num | value | volume | perc | cell count\n");
- for (i = 0; i < stats->nsteps; i++) {
- fprintf(stdout, "%7i %18.6lf %13.3lf %7.5lf %10i\n",
- stats->table[i]->num, stats->table[i]->min,
- stats->table[i]->vol, stats->table[i]->perc,
- stats->table[i]->count);
- }
- fprintf(stdout,
- "%7i * %13.3lf %7.5lf %10i\n",
- stats->null->num, stats->null->vol, stats->null->perc,
- stats->null->count);
- fprintf(stdout, "\nNumber of groups with equal values: %i",
- stats->nsteps);
- }
- else {
- /* 1234567 012345678901234567 012345678901234567 0123456789012 0123456 0123456789 */
- fprintf(stdout,
- " num | minimum <= value | value < maximum | volume | perc | cell count\n");
- for (i = 0; i < stats->nsteps; i++) {
- fprintf(stdout,
- "%7i %18.9lf %18.9lf %13.3lf %7.5lf %10i\n",
- stats->table[i]->num, stats->table[i]->min,
- stats->table[i]->max, stats->table[i]->vol,
- stats->table[i]->perc, stats->table[i]->count);
- }
- fprintf(stdout,
- "%7i * * %13.3lf %7.5lf %10i\n",
- stats->null->num, stats->null->vol, stats->null->perc,
- stats->null->count);
- }
- fprintf(stdout,
- "\nSum of non Null cells: \n\tVolume = %13.3lf \n\tPercentage = %7.3lf \n\tCell count = %i\n",
- stats->sum_vol, stats->sum_perc, stats->sum_count);
- fprintf(stdout,
- "\nSum of all cells: \n\tVolume = %13.3lf \n\tPercentage = %7.3lf \n\tCell count = %i\n",
- stats->sum_vol + stats->null->vol,
- stats->sum_perc + stats->null->perc,
- stats->sum_count + stats->null->count);
- return;
- }
- /* *************************************************************** */
- /* Make an entry in the statistic table based on range value check */
- /* *************************************************************** */
- void check_range_value(stat_table * stats, double value)
- {
- /* this is very expensive for large range arrays! */
- /*
- * int i;
- * for (i = 0; i < stats->nsteps; i++) {
- * if (value >= stats->table[i]->min && value < stats->table[i]->max) {
- * stats->table[i]->count++;
- * }
- * }
- */
- /* the much faster tree search is used */
- tree_search_range(stats, 0, stats->nsteps - 1, value);
- return;
- }
- /* *************************************************************** */
- /* tree search method developed by Soeren Gebbert *************** */
- /* *************************************************************** */
- /*
- * This is a divide and conquer tree search algorithm
- *
- * The algorithm counts how many values are located in each range.
- * It divides therefor the range array in smaller pices.
- *
- * e.g:
- * 0 1 2 3 4 5 6 7 8
- * [[0,1],[1,2],[2,3],[3,4],[4,5],[5,6],[6,7],[7,8],[8,9]]
- * / \
- * [[0,1],[1,2],[2,3],[3,4]] [[4,5],[5,6],[6,7],[7,8],[8,9]]
- * / \ / \
- * [[0,1],[1,2]] [[2,3],[3,4]] [[4,5],[5,6]] [[6,7],[7,8],[8,9]]
- * / \ / \ / \ / \
- * [[0,1]] [[1,2]] [[2,3]] [[3,4]] [[4,5]] [[5,6]] [[6,7]] [[7,8],[8,9]]
- * / \
- * [[7,8]] [[8,9]]
- *
- * Searching the value 5.5 will result in the follwoing steps:
- *
- * value 5.5 in range of
- * 1.) left array index = 0 - right array index = 8 -> range [0 - 9]
- * 2.) left array index = 4 - right array index = 8 -> range [4 - 9]
- * 3.) left array index = 4 - right array index = 5 -> range [4 - 6]
- * 4.) the value is located in range array 5 with a range of [5 - 6]
- * 5.) now increase the value range counter of range array with index 5
- *
- * */
- void tree_search_range(stat_table * stats, int left, int right, double value)
- {
- int size = right - left;
- G_debug(5,
- "Search value %g in array size %i left border index %i right border index %i\n",
- value, size, left, right);
- /*if left and right are equal */
- if (size == 0) {
- stats->table[left]->count++;
- return;
- }
- else if (size == 1) { /* if the size is one, check directly */
- if (value >= stats->table[left]->min &&
- value < stats->table[left]->max) {
- stats->table[left]->count++;
- }
- else if (value >= stats->table[right]->min &&
- value < stats->table[right]->max) {
- stats->table[right]->count++;
- }
- return;
- }
- else {
- if ((size % 2 == 0)) { /*even */
- /*left side */
- right = left + (size) / 2;
- if (value >= stats->table[left]->min &&
- value < stats->table[right]->max) {
- tree_search_range(stats, left, right, value);
- return;
- }
- /*right side */
- left += (size) / 2;
- right = left + (size) / 2;
- if (value >= stats->table[left]->min &&
- value < stats->table[right]->max) {
- tree_search_range(stats, left, right, value);
- return;
- }
- }
- else { /*odd */
- /*left side */
- right = left + (size - 1) / 2;
- if (value >= stats->table[left]->min &&
- value < stats->table[right]->max) {
- tree_search_range(stats, left, right, value);
- return;
- }
- /*right side */
- left += (size - 1) / 2;
- right = left + (size - 1) / 2 + 1; /*the right array is one col larger */
- if (value >= stats->table[left]->min &&
- value < stats->table[right]->max) {
- tree_search_range(stats, left, right, value);
- return;
- }
- }
- }
- return;
- }
- /* *************************************************************** */
- /* ****** heapsort for equal value arrays of size n ************** */
- /* ** Code based on heapsort from Sebastian Cyris **************** */
- /* *************************************************************** */
- void heapsort_eqvals(equal_val_array * e, int n)
- {
- int k;
- double t;
- int count = 0;
- --n;
- for (k = n / 2; k >= 0; k--)
- downheap_eqvals(e, n, k);
- while (n > 0) {
- t = e->values[0]->val;
- count = e->values[0]->count;
- e->values[0]->val = e->values[n]->val;
- e->values[0]->count = e->values[n]->count;
- e->values[n]->val = t;
- e->values[n]->count = count;
- downheap_eqvals(e, --n, 0);
- }
- return;
- }
- /* *************************************************************** */
- /* ** Code based on heapsort from Sebastian Cyris **************** */
- /* ** ************************************************************ */
- void downheap_eqvals(equal_val_array * e, int n, int k)
- {
- int j;
- double v;
- int count;
- v = e->values[k]->val;
- count = e->values[k]->count;
- while (k <= n / 2) {
- j = k + k;
- if (j < n && e->values[j]->val < e->values[j + 1]->val)
- j++;
- if (v >= e->values[j]->val)
- break;
- e->values[k]->val = e->values[j]->val;
- e->values[k]->count = e->values[j]->count;
- k = j;
- }
- e->values[k]->val = v;
- e->values[k]->count = count;
- return;
- }
- /* *************************************************************** */
- /* ** Main function ********************************************** */
- /* *************************************************************** */
- int main(int argc, char *argv[])
- {
- float val_f; /* for misc use */
- double val_d; /* for misc use */
- stat_table *stats = NULL;
- double min, max;
- equal_val_array *eqvals = NULL;
- unsigned int n = 0, nsteps;
- int map_type;
- char *infile = NULL;
- void *map = NULL;
- RASTER3D_Region region;
- unsigned int rows, cols, depths;
- unsigned int x, y, z;
- struct Option *inputfile, *steps;
- struct Flag *equal;
- struct GModule *module;
- G_gisinit(argv[0]);
- module = G_define_module();
- G_add_keyword(_("raster3d"));
- G_add_keyword(_("statistics"));
- module->description = _("Generates volume statistics for 3D raster maps.");
- /* Define the different options */
- inputfile = G_define_standard_option(G_OPT_R3_INPUT);
- steps = G_define_option();
- steps->key = "nsteps";
- steps->type = TYPE_INTEGER;
- steps->required = NO;
- steps->answer = "20";
- steps->description = _("Number of subranges to collect stats from");
- equal = G_define_flag();
- equal->key = 'e';
- equal->description =
- _("Calculate statistics based on equal value groups");
- if (G_parser(argc, argv))
- exit(EXIT_FAILURE);
- /*Set the defaults */
- Rast3d_init_defaults();
- /*get the current region */
- Rast3d_get_window(®ion);
- cols = region.cols;
- rows = region.rows;
- depths = region.depths;
- sscanf(steps->answer, "%i", &nsteps);
- /* break if the wrong number of subranges are given */
- if (nsteps <= 0)
- G_fatal_error(_("The number of subranges has to be equal or greater than 1"));
- infile = inputfile->answer;
- if (NULL == G_find_raster3d(infile, ""))
- Rast3d_fatal_error(_("3D raster map <%s> not found"), infile);
- map =
- Rast3d_open_cell_old(infile, G_find_raster3d(infile, ""), ®ion,
- RASTER3D_TILE_SAME_AS_FILE, RASTER3D_USE_CACHE_DEFAULT);
- if (map == NULL)
- Rast3d_fatal_error(_("Unable to open 3D raster map <%s>"), infile);
- map_type = Rast3d_tile_type_map(map);
- /* calculate statistics for groups of equal values */
- if ((equal->answer)) {
- /*search for equal values */
- eqvals = NULL;
- n = 0;
- for (z = 0; z < depths; z++) {
- G_percent(z, depths - 1, 10);
- for (y = 0; y < rows; y++) {
- for (x = 0; x < cols; x++) {
- if (map_type == FCELL_TYPE) {
- Rast3d_get_value(map, x, y, z, &val_f, map_type);
- if (!Rast3d_is_null_value_num(&val_f, map_type)) {
- /*the first entry */
- if (eqvals == NULL)
- eqvals =
- add_equal_val_to_array(eqvals,
- (double)val_f);
- else
- check_equal_value(eqvals, (double)val_f);
- n++; /*count non null cells */
- }
- }
- else if (map_type == DCELL_TYPE) {
- Rast3d_get_value(map, x, y, z, &val_d, map_type);
- if (!Rast3d_is_null_value_num(&val_d, map_type)) {
- /*the first entry */
- if (eqvals == NULL)
- eqvals =
- add_equal_val_to_array(eqvals, val_d);
- else
- check_equal_value(eqvals, val_d);
- n++; /*count non null cells */
- }
- }
- }
- }
- }
- if (eqvals) {
- /* sort the equal values array */
- G_message(_("Sort non-null values"));
- heapsort_eqvals(eqvals, eqvals->count);
- /* create the statistic table with equal values */
- stats = create_stat_table(eqvals->count, eqvals, 0, 0);
- /* compute the number of null values */
- stats->null->count = rows * cols * depths - n;
- free_equal_val_array(eqvals);
- }
- }
- else {
- /*create the statistic table based on value ranges */
- /* get the range of the map */
- Rast3d_range_load(map);
- Rast3d_range_min_max(map, &min, &max);
- stats = create_stat_table(nsteps, NULL, min, max);
- n = 0;
- for (z = 0; z < depths; z++) {
- G_percent(z, depths - 1, 10);
- for (y = 0; y < rows; y++) {
- for (x = 0; x < cols; x++) {
- if (map_type == FCELL_TYPE) {
- Rast3d_get_value(map, x, y, z, &val_f, map_type);
- if (!Rast3d_is_null_value_num(&val_f, map_type)) {
- check_range_value(stats, (double)val_f);
- n++;
- }
- }
- else if (map_type == DCELL_TYPE) {
- Rast3d_get_value(map, x, y, z, &val_d, map_type);
- if (!Rast3d_is_null_value_num(&val_d, map_type)) {
- check_range_value(stats, val_d);
- n++;
- }
- }
- }
- }
- }
- /* compute the number of null values */
- stats->null->count = rows * cols * depths - n;
- }
- if(stats) {
- /* Compute the volume and percentage */
- update_stat_table(stats, ®ion);
- /* Print the statistics to stdout */
- print_stat_table(stats);
- free_stat_table(stats);
- }
-
- exit(EXIT_SUCCESS);
- }
|