main.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724
  1. /*
  2. * r3.stats
  3. *
  4. * Copyright (C) 2004-2007 by the GRASS Development Team
  5. * Author(s): Soeren Gebbert
  6. *
  7. * Purpose: Generates volume statistics for raster3d maps.
  8. *
  9. * This program is free software under the GNU General Public
  10. * License (>=v2). Read the file COPYING that comes with GRASS
  11. * for details.
  12. *
  13. */
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <math.h>
  17. #include <grass/gis.h>
  18. #include <grass/raster3d.h>
  19. #include <grass/glocale.h>
  20. #define COMPARE_PRECISION 0.000000001
  21. /*statistic table row struct */
  22. typedef struct
  23. {
  24. double min, max, vol, perc;
  25. int num, count;
  26. } stat_row;
  27. /*the statistic table struct */
  28. typedef struct
  29. {
  30. stat_row **table;
  31. stat_row *null;
  32. int sum_count, nsteps, equal;
  33. double sum_vol, sum_perc;
  34. } stat_table;
  35. /*the equal value struct */
  36. typedef struct
  37. {
  38. double val; /* the equal value */
  39. int count; /* the appearance count */
  40. } equal_val;
  41. /*an array of groups with equal values */
  42. typedef struct
  43. {
  44. equal_val **values;
  45. int count;
  46. } equal_val_array;
  47. /*prototypes */
  48. static equal_val_array *alloc_equal_val_array(int count);
  49. static void free_equal_val_array(equal_val_array * vals);
  50. static equal_val_array *add_equal_val_to_array(equal_val_array * array, double val);
  51. static int check_equal_value(equal_val_array * array, double val);
  52. static stat_table *create_stat_table(int nsteps, equal_val_array * values,
  53. double min, double max);
  54. static void free_stat_table(stat_table * stats);
  55. static void print_stat_table(stat_table * stats);
  56. static void update_stat_table(stat_table * stats, RASTER3D_Region * region);
  57. static void heapsort_eqvals(equal_val_array * data, int n);
  58. static void downheap_eqvals(equal_val_array * data, int n, int k);
  59. static void check_range_value(stat_table * stats, double value);
  60. static void tree_search_range(stat_table * stats, int left, int right,
  61. double value);
  62. /* *************************************************************** */
  63. /* ***** allocate equal_val_array structure ********************* */
  64. /* *************************************************************** */
  65. equal_val_array *alloc_equal_val_array(int count)
  66. {
  67. equal_val_array *p;
  68. int i;
  69. p = (equal_val_array *) G_calloc(1, sizeof(equal_val_array));
  70. p->count = count;
  71. p->values = (equal_val **) G_calloc(p->count, sizeof(equal_val *));
  72. for (i = 0; i < p->count; i++)
  73. p->values[i] = (equal_val *) G_calloc(1, sizeof(equal_val));
  74. return p;
  75. }
  76. /* *************************************************************** */
  77. /* ***** add an equal_val to the equal_val_array structure ******* */
  78. /* *************************************************************** */
  79. equal_val_array *add_equal_val_to_array(equal_val_array * array, double val)
  80. {
  81. equal_val_array *p = array;
  82. int count;
  83. if (p == NULL) {
  84. p = alloc_equal_val_array(1);
  85. p->values[0]->val = val;
  86. p->values[0]->count = 1;
  87. G_debug(5, "Create new equal_array with value %g\n", val);
  88. }
  89. else {
  90. /*increase the count */
  91. count = array->count;
  92. count++;
  93. /*new memory */
  94. p->values =
  95. (equal_val **) G_realloc(p->values, count * sizeof(equal_val *));
  96. p->values[count - 1] = (equal_val *) G_calloc(1, sizeof(equal_val));
  97. /*set the new value */
  98. p->values[count - 1]->val = val;
  99. p->values[count - 1]->count = 1;
  100. /*set the new counter */
  101. p->count = count;
  102. G_debug(5, "Add new value %g at position %i\n", val, p->count);
  103. }
  104. return p;
  105. }
  106. /* *************************************************************** */
  107. /* ***** check if a value exists in the equal_val_array ********* */
  108. /* *************************************************************** */
  109. int check_equal_value(equal_val_array * array, double val)
  110. {
  111. int i;
  112. /*search if the new value exists and increase the counter */
  113. if (array != NULL)
  114. for (i = 0; i < array->count; i++) {
  115. if (array->values[i]->val == val) {
  116. array->values[i]->count++;
  117. G_debug(5, "found value %g with count %i at pos %i\n", val,
  118. array->values[i]->count, i);
  119. return 1;
  120. }
  121. }
  122. /*if it does not exists, add it to the array */
  123. add_equal_val_to_array(array, val);
  124. /*return 1 if found, 0 otherwise */
  125. return 0;
  126. }
  127. /* *************************************************************** */
  128. /* ***** Release the memory of a equal_val_array structure ****** */
  129. /* *************************************************************** */
  130. void free_equal_val_array(equal_val_array * uvals)
  131. {
  132. int i;
  133. for (i = 0; i < uvals->count; i++) {
  134. G_free(uvals->values[i]);
  135. }
  136. G_free(uvals->values);
  137. G_free(uvals);
  138. uvals = NULL;
  139. return;
  140. }
  141. /* *************************************************************** */
  142. /* **** Create the structure which manages the statistical ******* */
  143. /* **** values for a value range or equal values **************** */
  144. /* *************************************************************** */
  145. stat_table *create_stat_table(int nsteps, equal_val_array * eqvals,
  146. double min, double max)
  147. {
  148. stat_table *p;
  149. int i;
  150. double step;
  151. /* Memory */
  152. p = (stat_table *) G_calloc(1, sizeof(stat_table));
  153. p->null = (stat_row *) G_calloc(nsteps, sizeof(stat_row));
  154. p->table = (stat_row **) G_calloc(nsteps, sizeof(stat_row *));
  155. for (i = 0; i < nsteps; i++)
  156. p->table[i] = (stat_row *) G_calloc(1, sizeof(stat_row));
  157. /* Some value initializing */
  158. p->null->min = 0;
  159. p->null->max = 0;
  160. p->null->vol = 0;
  161. p->null->perc = 0;
  162. p->null->count = 0;
  163. p->null->num = nsteps + 1;
  164. p->nsteps = nsteps;
  165. p->sum_count = 0;
  166. p->sum_vol = 0;
  167. p->sum_perc = 0;
  168. p->equal = 0;
  169. /*if no equal values are provided, calculate the range and the length of each step */
  170. if (!eqvals) {
  171. /*calculate the steplength */
  172. step = (max - min) / (nsteps);
  173. p->equal = 0;
  174. p->table[0]->min = min;
  175. p->table[0]->max = min + step;
  176. p->table[0]->num = 1;
  177. p->table[0]->count = 0;
  178. p->table[0]->vol = 0;
  179. p->table[0]->perc = 0;
  180. G_debug(3, "Step %i range min %.11lf max %.11lf\n", p->table[0]->num,
  181. p->table[0]->min, p->table[0]->max);
  182. for (i = 1; i < nsteps; i++) {
  183. p->table[i]->min = p->table[i - 1]->max;
  184. p->table[i]->max = p->table[i - 1]->max + step;
  185. p->table[i]->num = i + 1;
  186. p->table[i]->count = 0;
  187. p->table[i]->vol = 0;
  188. p->table[i]->perc = 0;
  189. G_debug(5, "Step %i range min %.11lf max %.11lf\n",
  190. p->table[i]->num, p->table[i]->min, p->table[i]->max);
  191. }
  192. /* the last value must be a bit larger */
  193. p->table[nsteps - 1]->max += COMPARE_PRECISION;
  194. }
  195. else { /* Create equal value statistic */
  196. p->equal = 1;
  197. for (i = 0; i < eqvals->count; i++) {
  198. p->table[i]->min = eqvals->values[i]->val; /* equal values have no range, set min and max to the same value */
  199. p->table[i]->max = eqvals->values[i]->val;
  200. p->table[i]->num = i + 1;
  201. p->table[i]->count = eqvals->values[i]->count; /* the appearance count for each equal value */
  202. p->table[i]->vol = 0;
  203. p->table[i]->perc = 0;
  204. G_debug(5, "Unique value %i = %g count %i\n", p->table[i]->num,
  205. p->table[i]->min, p->table[i]->count);
  206. }
  207. }
  208. return p;
  209. }
  210. /* *************************************************************** */
  211. /* ***** Release the memory of a stat_table structure ************ */
  212. /* *************************************************************** */
  213. void free_stat_table(stat_table * stats)
  214. {
  215. int i;
  216. for (i = 0; i < stats->nsteps; i++) {
  217. G_free(stats->table[i]);
  218. }
  219. G_free(stats->table);
  220. G_free(stats->null);
  221. G_free(stats);
  222. stats = NULL;
  223. return;
  224. }
  225. /* *************************************************************** */
  226. /* **** Compute the volume, percentage and sums ****************** */
  227. /* *************************************************************** */
  228. void update_stat_table(stat_table * stats, RASTER3D_Region * region)
  229. {
  230. int i;
  231. double vol = region->ns_res * region->ew_res * region->tb_res;
  232. int cellnum = region->rows * region->cols * region->depths;
  233. /*Calculate volume and percentage for each range or equal value and the sum stats */
  234. for (i = 0; i < stats->nsteps; i++) {
  235. stats->table[i]->vol = stats->table[i]->count * vol;
  236. stats->table[i]->perc =
  237. (double)(100.0 * (double)stats->table[i]->count /
  238. (double)cellnum);
  239. stats->sum_count += stats->table[i]->count;
  240. stats->sum_vol += stats->table[i]->vol;
  241. stats->sum_perc += stats->table[i]->perc;
  242. }
  243. /*calculate the null value stats */
  244. stats->null->vol = stats->null->count * vol;
  245. stats->null->perc =
  246. (double)(100.0 * (double)stats->null->count / (double)cellnum);
  247. return;
  248. }
  249. /* *************************************************************** */
  250. /* *************************************************************** */
  251. /* *************************************************************** */
  252. void print_stat_table(stat_table * stats)
  253. {
  254. int i;
  255. if (stats->equal) {
  256. /* 1234567 012345678901234567 0123456789012 0123456 0123456789 */
  257. fprintf(stdout,
  258. " num | value | volume | perc | cell count\n");
  259. for (i = 0; i < stats->nsteps; i++) {
  260. fprintf(stdout, "%7i %18.6lf %13.3lf %7.5lf %10i\n",
  261. stats->table[i]->num, stats->table[i]->min,
  262. stats->table[i]->vol, stats->table[i]->perc,
  263. stats->table[i]->count);
  264. }
  265. fprintf(stdout,
  266. "%7i * %13.3lf %7.5lf %10i\n",
  267. stats->null->num, stats->null->vol, stats->null->perc,
  268. stats->null->count);
  269. fprintf(stdout, "\nNumber of groups with equal values: %i",
  270. stats->nsteps);
  271. }
  272. else {
  273. /* 1234567 012345678901234567 012345678901234567 0123456789012 0123456 0123456789 */
  274. fprintf(stdout,
  275. " num | minimum <= value | value < maximum | volume | perc | cell count\n");
  276. for (i = 0; i < stats->nsteps; i++) {
  277. fprintf(stdout,
  278. "%7i %18.9lf %18.9lf %13.3lf %7.5lf %10i\n",
  279. stats->table[i]->num, stats->table[i]->min,
  280. stats->table[i]->max, stats->table[i]->vol,
  281. stats->table[i]->perc, stats->table[i]->count);
  282. }
  283. fprintf(stdout,
  284. "%7i * * %13.3lf %7.5lf %10i\n",
  285. stats->null->num, stats->null->vol, stats->null->perc,
  286. stats->null->count);
  287. }
  288. fprintf(stdout,
  289. "\nSum of non Null cells: \n\tVolume = %13.3lf \n\tPercentage = %7.3lf \n\tCell count = %i\n",
  290. stats->sum_vol, stats->sum_perc, stats->sum_count);
  291. fprintf(stdout,
  292. "\nSum of all cells: \n\tVolume = %13.3lf \n\tPercentage = %7.3lf \n\tCell count = %i\n",
  293. stats->sum_vol + stats->null->vol,
  294. stats->sum_perc + stats->null->perc,
  295. stats->sum_count + stats->null->count);
  296. return;
  297. }
  298. /* *************************************************************** */
  299. /* Make an entry in the statistic table based on range value check */
  300. /* *************************************************************** */
  301. void check_range_value(stat_table * stats, double value)
  302. {
  303. /* this is very expensive for large range arrays! */
  304. /*
  305. * int i;
  306. * for (i = 0; i < stats->nsteps; i++) {
  307. * if (value >= stats->table[i]->min && value < stats->table[i]->max) {
  308. * stats->table[i]->count++;
  309. * }
  310. * }
  311. */
  312. /* the much faster tree search is used */
  313. tree_search_range(stats, 0, stats->nsteps - 1, value);
  314. return;
  315. }
  316. /* *************************************************************** */
  317. /* tree search method developed by Soeren Gebbert *************** */
  318. /* *************************************************************** */
  319. /*
  320. * This is a divide and conquer tree search algorithm
  321. *
  322. * The algorithm counts how many values are located in each range.
  323. * It divides therefor the range array in smaller pices.
  324. *
  325. * e.g:
  326. * 0 1 2 3 4 5 6 7 8
  327. * [[0,1],[1,2],[2,3],[3,4],[4,5],[5,6],[6,7],[7,8],[8,9]]
  328. * / \
  329. * [[0,1],[1,2],[2,3],[3,4]] [[4,5],[5,6],[6,7],[7,8],[8,9]]
  330. * / \ / \
  331. * [[0,1],[1,2]] [[2,3],[3,4]] [[4,5],[5,6]] [[6,7],[7,8],[8,9]]
  332. * / \ / \ / \ / \
  333. * [[0,1]] [[1,2]] [[2,3]] [[3,4]] [[4,5]] [[5,6]] [[6,7]] [[7,8],[8,9]]
  334. * / \
  335. * [[7,8]] [[8,9]]
  336. *
  337. * Searching the value 5.5 will result in the follwoing steps:
  338. *
  339. * value 5.5 in range of
  340. * 1.) left array index = 0 - right array index = 8 -> range [0 - 9]
  341. * 2.) left array index = 4 - right array index = 8 -> range [4 - 9]
  342. * 3.) left array index = 4 - right array index = 5 -> range [4 - 6]
  343. * 4.) the value is located in range array 5 with a range of [5 - 6]
  344. * 5.) now increase the value range counter of range array with index 5
  345. *
  346. * */
  347. void tree_search_range(stat_table * stats, int left, int right, double value)
  348. {
  349. int size = right - left;
  350. G_debug(5,
  351. "Search value %g in array size %i left border index %i right border index %i\n",
  352. value, size, left, right);
  353. /*if left and right are equal */
  354. if (size == 0) {
  355. stats->table[left]->count++;
  356. return;
  357. }
  358. else if (size == 1) { /* if the size is one, check directly */
  359. if (value >= stats->table[left]->min &&
  360. value < stats->table[left]->max) {
  361. stats->table[left]->count++;
  362. }
  363. else if (value >= stats->table[right]->min &&
  364. value < stats->table[right]->max) {
  365. stats->table[right]->count++;
  366. }
  367. return;
  368. }
  369. else {
  370. if ((size % 2 == 0)) { /*even */
  371. /*left side */
  372. right = left + (size) / 2;
  373. if (value >= stats->table[left]->min &&
  374. value < stats->table[right]->max) {
  375. tree_search_range(stats, left, right, value);
  376. return;
  377. }
  378. /*right side */
  379. left += (size) / 2;
  380. right = left + (size) / 2;
  381. if (value >= stats->table[left]->min &&
  382. value < stats->table[right]->max) {
  383. tree_search_range(stats, left, right, value);
  384. return;
  385. }
  386. }
  387. else { /*odd */
  388. /*left side */
  389. right = left + (size - 1) / 2;
  390. if (value >= stats->table[left]->min &&
  391. value < stats->table[right]->max) {
  392. tree_search_range(stats, left, right, value);
  393. return;
  394. }
  395. /*right side */
  396. left += (size - 1) / 2;
  397. right = left + (size - 1) / 2 + 1; /*the right array is one col larger */
  398. if (value >= stats->table[left]->min &&
  399. value < stats->table[right]->max) {
  400. tree_search_range(stats, left, right, value);
  401. return;
  402. }
  403. }
  404. }
  405. return;
  406. }
  407. /* *************************************************************** */
  408. /* ****** heapsort for equal value arrays of size n ************** */
  409. /* ** Code based on heapsort from Sebastian Cyris **************** */
  410. /* *************************************************************** */
  411. void heapsort_eqvals(equal_val_array * e, int n)
  412. {
  413. int k;
  414. double t;
  415. int count = 0;
  416. --n;
  417. for (k = n / 2; k >= 0; k--)
  418. downheap_eqvals(e, n, k);
  419. while (n > 0) {
  420. t = e->values[0]->val;
  421. count = e->values[0]->count;
  422. e->values[0]->val = e->values[n]->val;
  423. e->values[0]->count = e->values[n]->count;
  424. e->values[n]->val = t;
  425. e->values[n]->count = count;
  426. downheap_eqvals(e, --n, 0);
  427. }
  428. return;
  429. }
  430. /* *************************************************************** */
  431. /* ** Code based on heapsort from Sebastian Cyris **************** */
  432. /* ** ************************************************************ */
  433. void downheap_eqvals(equal_val_array * e, int n, int k)
  434. {
  435. int j;
  436. double v;
  437. int count;
  438. v = e->values[k]->val;
  439. count = e->values[k]->count;
  440. while (k <= n / 2) {
  441. j = k + k;
  442. if (j < n && e->values[j]->val < e->values[j + 1]->val)
  443. j++;
  444. if (v >= e->values[j]->val)
  445. break;
  446. e->values[k]->val = e->values[j]->val;
  447. e->values[k]->count = e->values[j]->count;
  448. k = j;
  449. }
  450. e->values[k]->val = v;
  451. e->values[k]->count = count;
  452. return;
  453. }
  454. /* *************************************************************** */
  455. /* ** Main function ********************************************** */
  456. /* *************************************************************** */
  457. int main(int argc, char *argv[])
  458. {
  459. float val_f; /* for misc use */
  460. double val_d; /* for misc use */
  461. stat_table *stats = NULL;
  462. double min, max;
  463. equal_val_array *eqvals = NULL;
  464. unsigned int n = 0, nsteps;
  465. int map_type;
  466. char *infile = NULL;
  467. void *map = NULL;
  468. RASTER3D_Region region;
  469. unsigned int rows, cols, depths;
  470. unsigned int x, y, z;
  471. struct Option *inputfile, *steps;
  472. struct Flag *equal;
  473. struct GModule *module;
  474. G_gisinit(argv[0]);
  475. module = G_define_module();
  476. G_add_keyword(_("raster3d"));
  477. G_add_keyword(_("statistics"));
  478. module->description = _("Generates volume statistics for 3D raster maps.");
  479. /* Define the different options */
  480. inputfile = G_define_standard_option(G_OPT_R3_INPUT);
  481. steps = G_define_option();
  482. steps->key = "nsteps";
  483. steps->type = TYPE_INTEGER;
  484. steps->required = NO;
  485. steps->answer = "20";
  486. steps->description = _("Number of subranges to collect stats from");
  487. equal = G_define_flag();
  488. equal->key = 'e';
  489. equal->description =
  490. _("Calculate statistics based on equal value groups");
  491. if (G_parser(argc, argv))
  492. exit(EXIT_FAILURE);
  493. /*Set the defaults */
  494. Rast3d_init_defaults();
  495. /*get the current region */
  496. Rast3d_get_window(&region);
  497. cols = region.cols;
  498. rows = region.rows;
  499. depths = region.depths;
  500. sscanf(steps->answer, "%i", &nsteps);
  501. /* break if the wrong number of subranges are given */
  502. if (nsteps <= 0)
  503. G_fatal_error(_("The number of subranges has to be equal or greater than 1"));
  504. infile = inputfile->answer;
  505. if (NULL == G_find_raster3d(infile, ""))
  506. Rast3d_fatal_error(_("3D raster map <%s> not found"), infile);
  507. map =
  508. Rast3d_open_cell_old(infile, G_find_raster3d(infile, ""), &region,
  509. RASTER3D_TILE_SAME_AS_FILE, RASTER3D_USE_CACHE_DEFAULT);
  510. if (map == NULL)
  511. Rast3d_fatal_error(_("Unable to open 3D raster map <%s>"), infile);
  512. map_type = Rast3d_tile_type_map(map);
  513. /* calculate statistics for groups of equal values */
  514. if ((equal->answer)) {
  515. /*search for equal values */
  516. eqvals = NULL;
  517. n = 0;
  518. for (z = 0; z < depths; z++) {
  519. G_percent(z, depths - 1, 10);
  520. for (y = 0; y < rows; y++) {
  521. for (x = 0; x < cols; x++) {
  522. if (map_type == FCELL_TYPE) {
  523. Rast3d_get_value(map, x, y, z, &val_f, map_type);
  524. if (!Rast3d_is_null_value_num(&val_f, map_type)) {
  525. /*the first entry */
  526. if (eqvals == NULL)
  527. eqvals =
  528. add_equal_val_to_array(eqvals,
  529. (double)val_f);
  530. else
  531. check_equal_value(eqvals, (double)val_f);
  532. n++; /*count non null cells */
  533. }
  534. }
  535. else if (map_type == DCELL_TYPE) {
  536. Rast3d_get_value(map, x, y, z, &val_d, map_type);
  537. if (!Rast3d_is_null_value_num(&val_d, map_type)) {
  538. /*the first entry */
  539. if (eqvals == NULL)
  540. eqvals =
  541. add_equal_val_to_array(eqvals, val_d);
  542. else
  543. check_equal_value(eqvals, val_d);
  544. n++; /*count non null cells */
  545. }
  546. }
  547. }
  548. }
  549. }
  550. if (eqvals) {
  551. /* sort the equal values array */
  552. G_message(_("Sort non-null values"));
  553. heapsort_eqvals(eqvals, eqvals->count);
  554. /* create the statistic table with equal values */
  555. stats = create_stat_table(eqvals->count, eqvals, 0, 0);
  556. /* compute the number of null values */
  557. stats->null->count = rows * cols * depths - n;
  558. free_equal_val_array(eqvals);
  559. }
  560. }
  561. else {
  562. /*create the statistic table based on value ranges */
  563. /* get the range of the map */
  564. Rast3d_range_load(map);
  565. Rast3d_range_min_max(map, &min, &max);
  566. stats = create_stat_table(nsteps, NULL, min, max);
  567. n = 0;
  568. for (z = 0; z < depths; z++) {
  569. G_percent(z, depths - 1, 10);
  570. for (y = 0; y < rows; y++) {
  571. for (x = 0; x < cols; x++) {
  572. if (map_type == FCELL_TYPE) {
  573. Rast3d_get_value(map, x, y, z, &val_f, map_type);
  574. if (!Rast3d_is_null_value_num(&val_f, map_type)) {
  575. check_range_value(stats, (double)val_f);
  576. n++;
  577. }
  578. }
  579. else if (map_type == DCELL_TYPE) {
  580. Rast3d_get_value(map, x, y, z, &val_d, map_type);
  581. if (!Rast3d_is_null_value_num(&val_d, map_type)) {
  582. check_range_value(stats, val_d);
  583. n++;
  584. }
  585. }
  586. }
  587. }
  588. }
  589. /* compute the number of null values */
  590. stats->null->count = rows * cols * depths - n;
  591. }
  592. if(stats) {
  593. /* Compute the volume and percentage */
  594. update_stat_table(stats, &region);
  595. /* Print the statistics to stdout */
  596. print_stat_table(stats);
  597. free_stat_table(stats);
  598. }
  599. exit(EXIT_SUCCESS);
  600. }