#include #include "global.h" /* hash definitions (these should be prime numbers) **************/ #define HASHSIZE 7307 #define HASHMOD 89 static CELL *values; static struct Node *node_pool; static int node_pool_count; static CELL *value_pool; static int value_pool_count; #define NODE_INCR 32 #define VALUE_INCR 32 static struct Node **sorted_list; struct Node { CELL *values; struct Node *left; struct Node *right; struct Node *list; long count; double area; } ; static struct Node **hashtable; static struct Node *node_list = NULL; static int node_count = 0, total_count = 0; int initialize_cell_stats (int n) { int i; /* record nilfes first */ nfiles = n; /* allocate a pool of value arrays */ value_pool_count = 0; allocate_values(); /* set Node pool to empty */ node_pool_count = 0; /* empty the has table */ hashtable = (struct Node **) G_malloc (HASHSIZE * sizeof(struct Node *)); for (i = 0; i < HASHSIZE; i++) hashtable[i] = NULL; return 0; } int allocate_values (void) { value_pool_count = VALUE_INCR; value_pool = (CELL *) G_calloc (nfiles * value_pool_count, sizeof(CELL)); values = value_pool; return 0; } struct Node * NewNode (double area) { struct Node *node; if (node_pool_count <= 0) node_pool = (struct Node *) G_calloc (node_pool_count = NODE_INCR, sizeof(struct Node)); node = &node_pool[--node_pool_count]; node->count = 1; node->area = area; node->values = values; if (--value_pool_count <= 0) allocate_values(); else values += nfiles; node->left = node->right = NULL; node->list = node_list; node_list = node; node_count++; return node; } int reset_null_vals (CELL *cell, int ncols) { while (ncols-- > 0) { if(G_is_c_null_value(&cell[ncols])) cell[ncols] = NULL_CELL; } return 0; } int update_cell_stats (CELL **cell, int ncols, double area) { register int i; register int hash; register struct Node *q,*p = NULL; register int dir = 0; while (ncols-- > 0) { /* copy this cell to an array, compute hash */ hash = values[0] = cell[0][ncols]; for (i = 1; i < nfiles; i++) hash = hash * HASHMOD + (values[i] = cell[i][ncols]); if (hash < 0) hash = -hash; hash %= HASHSIZE; /* look it up and update/insert */ if ((q = hashtable[hash]) == NULL) { hashtable[hash] = NewNode(area); } else { while(1) { for (i = 0; i < nfiles; i++) { if (values[i] < q->values[i]) { dir = -1; p = q->left; break; } if (values[i] > q->values[i]) { dir = 1; p = q->right; break; } } if (i == nfiles) /* match */ { q->count++; q->area += area; total_count++; break; } else if (p == NULL) { if (dir < 0) q->left = NewNode(area); else q->right = NewNode(area); break; } else q = p; } } } return 0; } int node_compare (const void *pp, const void *qq) { struct Node * const *p = pp, * const *q = qq; register int i, x; register const CELL *a, *b; a = (*p)->values; b = (*q)->values; for (i = nfiles; --i >= 0; ) if (x = (*a++ - *b++), x) return x; return 0; } int sort_cell_stats (void) { struct Node **q, *p; if (node_count <= 0) return 0; G_free(hashtable); /* make a bit more room */ sorted_list = (struct Node **) G_calloc (node_count, sizeof(struct Node *)); for (q = sorted_list, p = node_list; p; p = p->list) *q++ = p; qsort (sorted_list, node_count, sizeof(struct Node *), node_compare); return 0; } int print_node_count (void) { fprintf (stdout,"%d nodes\n", node_count); return 0; } int print_cell_stats (char *fmt, int with_percents, int with_counts, int with_areas, int with_labels, char *fs) { int i,n, nulls_found; struct Node *node; CELL tmp_cell, null_cell; DCELL dLow, dHigh; char str1[50], str2[50]; if(no_nulls) total_count -= sorted_list[node_count-1]->count; G_set_c_null_value(&null_cell, 1); if (node_count <= 0) { fprintf (stdout,"0"); for (i = 1; i < nfiles; i++) fprintf (stdout,"%s%s",fs, no_data_str); if (with_areas) fprintf (stdout,"%s0.0",fs); if (with_counts) fprintf (stdout,"%s0",fs); if (with_percents) fprintf (stdout,"%s0.00%%",fs); if (with_labels) fprintf (stdout,"%s%s", fs, G_get_cat (null_cell, &labels[i])); fprintf (stdout,"\n"); } else { for (n = 0; n < node_count; n++) { node = sorted_list[n]; if (no_nulls || no_nulls_all) { nulls_found = 0; for (i = 0; i < nfiles; i++) /* if (node->values[i] || (!raw && is_fp[i])) break; */ if(node->values[i] == NULL_CELL) nulls_found++; if (nulls_found == nfiles) continue; if(no_nulls && nulls_found) continue; } for (i = 0; i < nfiles; i++) { if (node->values[i] == NULL_CELL) { fprintf (stdout,"%s%s", i?fs:"", no_data_str); if (with_labels && !(raw && is_fp[i])) fprintf (stdout,"%s%s", fs, G_get_cat (null_cell, &labels[i])); } else if(raw || !is_fp[i] || as_int) { fprintf (stdout,"%s%ld", i?fs:"", (long) node->values[i]); if (with_labels && !is_fp[i]) fprintf (stdout,"%s%s", fs, G_get_cat ((CELL) node->values[i], &labels[i])); } else /* find out which floating point range to print */ { if(cat_ranges) G_quant_get_ith_rule (&labels[i].q, node->values[i], &dLow, &dHigh, &tmp_cell, &tmp_cell); else { dLow = (DMAX[i] - DMIN[i])/nsteps * (double) (node->values[i] - 1) + DMIN[i]; dHigh= (DMAX[i] - DMIN[i])/nsteps * (double) node->values[i] + DMIN[i]; } if(averaged) { /* print averaged values */ sprintf(str1, "%10f", (dLow+dHigh)/2.0); G_trim_decimal(str1); G_strip(str1); fprintf (stdout,"%s%s", i?fs:"", str1); } else { /* print intervals */ sprintf(str1, "%10f", dLow); sprintf(str2, "%10f", dHigh); G_trim_decimal(str1); G_trim_decimal(str2); G_strip(str1); G_strip(str2); fprintf (stdout,"%s%s-%s", i?fs:"", str1, str2); } if (with_labels) { if(cat_ranges) fprintf (stdout,"%s%s", fs, labels[i].labels[node->values[i]]); else fprintf (stdout,"%sfrom %s to %s", fs, G_get_d_raster_cat(&dLow, &labels[i]), G_get_d_raster_cat(&dHigh, &labels[i])); } } } if (with_areas) { fprintf (stdout,"%s", fs); fprintf (stdout,fmt, node->area); } if (with_counts) fprintf (stdout,"%s%ld", fs, (long) node->count); if (with_percents) fprintf (stdout,"%s%6.2f%%", fs, (double) 100*node->count/total_count); fprintf (stdout,"\n"); } } return 0; }