123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494 |
- /*
- * r3.stats support functions
- *
- * Copyright (C) 2004-2014 by the GRASS Development Team
- * Author(s): Soeren Gebbert
- *
- * This program is free software under the GNU General Public
- * License (>=v2). Read the file COPYING that comes with GRASS
- * for details.
- *
- */
- #include <grass/gis.h>
- #include "local_proto.h"
- /* *************************************************************** */
- /* ***** 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 counts_only)
- {
- 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 if (counts_only) {
- for (i = 0; i < stats->nsteps; i++) {
- fprintf(stdout, "%d %ld\n",
- stats->table[i]->num, stats->table[i]->count);
- }
- fprintf(stdout, "* %ld\n", stats->null->count);
- }
- 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);
- }
- if (!counts_only) {
- 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;
- }
|