range.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790
  1. /*!
  2. * \file lib/raster/range.c
  3. *
  4. * \brief Raster Library - Raster range file management
  5. *
  6. * (C) 2001-2009 GRASS Development Team
  7. *
  8. * This program is free software under the GNU General Public License
  9. * (>=v2). Read the file COPYING that comes with GRASS for details.
  10. *
  11. * \author Original author CERL
  12. */
  13. #include <unistd.h>
  14. #include <grass/raster.h>
  15. #include <grass/glocale.h>
  16. #include "R.h"
  17. #define DEFAULT_CELL_MIN 1
  18. #define DEFAULT_CELL_MAX 255
  19. static void init_rstats(struct R_stats *);
  20. /*!
  21. \brief Remove floating-point range
  22. Note: For internal use only.
  23. \param name map name
  24. */
  25. void Rast__remove_fp_range(const char *name)
  26. {
  27. G_remove_misc("cell_misc", "f_range", name);
  28. }
  29. /*!
  30. * \brief Construct default range
  31. *
  32. * Sets the integer range to [1,255]
  33. *
  34. * \param[out] r pointer to Range structure which holds range info
  35. */
  36. void Rast_construct_default_range(struct Range *range)
  37. {
  38. Rast_update_range(DEFAULT_CELL_MIN, range);
  39. Rast_update_range(DEFAULT_CELL_MAX, range);
  40. }
  41. /*!
  42. * \brief Read floating-point range
  43. *
  44. * Read the floating point range file <i>drange</i>. This file is
  45. * written in binary using XDR format.
  46. *
  47. * An empty range file indicates that the min, max are undefined. This
  48. * is a valid case, and the result should be an initialized range
  49. * struct with no defined min/max. If the range file is missing and
  50. * the map is a floating-point map, this function will create a
  51. * default range by calling G_construct_default_range().
  52. *
  53. * \param name map name
  54. * \param mapset mapset name
  55. * \param drange pointer to FPRange structure which holds fp range
  56. *
  57. * \return 1 on success
  58. * \return 2 range is empty
  59. * \return -1 on error
  60. */
  61. int Rast_read_fp_range(const char *name, const char *mapset,
  62. struct FPRange *drange)
  63. {
  64. struct Range range;
  65. int fd;
  66. char xdr_buf[2][XDR_DOUBLE_NBYTES];
  67. DCELL dcell1, dcell2;
  68. Rast_init();
  69. Rast_init_fp_range(drange);
  70. if (Rast_map_type(name, mapset) == CELL_TYPE) {
  71. /* if map is integer
  72. read integer range and convert it to double */
  73. if (Rast_read_range(name, mapset, &range) >= 0) {
  74. /* if the integer range is empty */
  75. if (range.first_time)
  76. return 2;
  77. Rast_update_fp_range((DCELL) range.min, drange);
  78. Rast_update_fp_range((DCELL) range.max, drange);
  79. return 1;
  80. }
  81. return -1;
  82. }
  83. fd = -1;
  84. if (G_find_file2_misc("cell_misc", "f_range", name, mapset)) {
  85. fd = G_open_old_misc("cell_misc", "f_range", name, mapset);
  86. if (fd < 0) {
  87. G_warning(_("Unable to read fp range file for <%s>"),
  88. G_fully_qualified_name(name, mapset));
  89. return -1;
  90. }
  91. if (read(fd, xdr_buf, sizeof(xdr_buf)) != sizeof(xdr_buf)) {
  92. /* if the f_range file exists, but empty file, meaning Nulls */
  93. close(fd);
  94. G_debug(1, "Empty fp range file meaning Nulls for <%s>",
  95. G_fully_qualified_name(name, mapset));
  96. return 2;
  97. }
  98. G_xdr_get_double(&dcell1, xdr_buf[0]);
  99. G_xdr_get_double(&dcell2, xdr_buf[1]);
  100. Rast_update_fp_range(dcell1, drange);
  101. Rast_update_fp_range(dcell2, drange);
  102. close(fd);
  103. }
  104. else {
  105. /* "f_range" file does not exist */
  106. G_warning(_("Missing fp range file for <%s> (run r.support -s)"),
  107. G_fully_qualified_name(name, mapset));
  108. return -1;
  109. }
  110. return 1;
  111. }
  112. /*!
  113. * \brief Read raster range (CELL)
  114. *
  115. * This routine reads the range information for the raster map
  116. * <i>name</i> in <i>mapset</i> into the <i>range</i> structure.
  117. *
  118. * A diagnostic message is printed and -1 is returned if there is an error
  119. * reading the range file. Otherwise, 0 is returned.
  120. *
  121. * Old range file (those with 4 numbers) should treat zeros in this
  122. * file as NULL-values. New range files (those with just 2 numbers)
  123. * should treat these numbers as real data (zeros are real data in
  124. * this case). An empty range file indicates that the min, max are
  125. * undefined. This is a valid case, and the result should be an
  126. * initialized range struct with no defined min/max. If the range file
  127. * is missing and the map is a floating-point map, this function will
  128. * create a default range by calling G_construct_default_range().
  129. *
  130. * \param name map name
  131. * \param mapset mapset name
  132. * \param[out] range pointer to Range structure which holds range info
  133. *
  134. * \return -1 on error
  135. * \return 1 on success
  136. * \return 2 if range is empty
  137. * \return 3 if raster map is floating-point, get range from quant rules
  138. */
  139. int Rast_read_range(const char *name, const char *mapset, struct Range *range)
  140. {
  141. FILE *fd;
  142. CELL x[4];
  143. char buf[200];
  144. int n, count;
  145. struct Quant quant;
  146. struct FPRange drange;
  147. Rast_init_range(range);
  148. fd = NULL;
  149. /* if map is not integer, read quant rules, and get limits */
  150. if (Rast_map_type(name, mapset) != CELL_TYPE) {
  151. DCELL dmin, dmax;
  152. if (Rast_read_quant(name, mapset, &quant) < 0) {
  153. G_warning(_("Unable to read quant rules for raster map <%s>"),
  154. G_fully_qualified_name(name, mapset));
  155. return -1;
  156. }
  157. if (Rast_quant_is_truncate(&quant) || Rast_quant_is_round(&quant)) {
  158. if (Rast_read_fp_range(name, mapset, &drange) >= 0) {
  159. Rast_get_fp_range_min_max(&drange, &dmin, &dmax);
  160. if (Rast_quant_is_truncate(&quant)) {
  161. x[0] = (CELL) dmin;
  162. x[1] = (CELL) dmax;
  163. }
  164. else { /* round */
  165. if (dmin > 0)
  166. x[0] = (CELL) (dmin + .5);
  167. else
  168. x[0] = (CELL) (dmin - .5);
  169. if (dmax > 0)
  170. x[1] = (CELL) (dmax + .5);
  171. else
  172. x[1] = (CELL) (dmax - .5);
  173. }
  174. }
  175. else
  176. return -1;
  177. }
  178. else
  179. Rast_quant_get_limits(&quant, &dmin, &dmax, &x[0], &x[1]);
  180. Rast_update_range(x[0], range);
  181. Rast_update_range(x[1], range);
  182. return 3;
  183. }
  184. if (G_find_file2_misc("cell_misc", "range", name, mapset)) {
  185. fd = G_fopen_old_misc("cell_misc", "range", name, mapset);
  186. if (!fd) {
  187. G_warning(_("Unable to read range file for <%s>"),
  188. G_fully_qualified_name(name, mapset));
  189. return -1;
  190. }
  191. /* if range file exists but empty */
  192. if (!fgets(buf, sizeof buf, fd)) {
  193. if (fd)
  194. fclose(fd);
  195. return 2;
  196. }
  197. x[0] = x[1] = x[2] = x[3] = 0;
  198. count = sscanf(buf, "%d%d%d%d", &x[0], &x[1], &x[2], &x[3]);
  199. /* if wrong format */
  200. if (count <= 0) {
  201. if (fd)
  202. fclose(fd);
  203. G_warning(_("Unable to read range file for <%s>"),
  204. G_fully_qualified_name(name, mapset));
  205. return -1;
  206. }
  207. for (n = 0; n < count; n++) {
  208. /* if count==4, the range file is old (4.1) and 0's in it
  209. have to be ignored */
  210. if (count < 4 || x[n])
  211. Rast_update_range((CELL) x[n], range);
  212. }
  213. fclose(fd);
  214. }
  215. else {
  216. /* "range" file does not exist */
  217. G_warning(_("Missing range file for <%s> (run r.support -s)"),
  218. G_fully_qualified_name(name, mapset));
  219. return -1;
  220. }
  221. return 1;
  222. }
  223. /*!
  224. * \brief Read raster stats
  225. *
  226. * Read the stats file <i>stats</i>. This file is
  227. * written in binary using XDR format.
  228. *
  229. * An empty stats file indicates that all cells are NULL. This
  230. * is a valid case, and the result should be an initialized rstats
  231. * struct with no defined stats. If the stats file is missing
  232. * this function will create a default stats with count = 0.
  233. *
  234. * \param name map name
  235. * \param mapset mapset name
  236. * \param rstats pointer to R_stats structure which holds raster stats
  237. *
  238. * \return 1 on success
  239. * \return 2 stats is empty
  240. * \return -1 on error or stats file does not exist
  241. */
  242. int Rast_read_rstats(const char *name, const char *mapset,
  243. struct R_stats *rstats)
  244. {
  245. int fd;
  246. char xdr_buf[2][XDR_DOUBLE_NBYTES];
  247. DCELL dcell1, dcell2;
  248. unsigned char cc[8];
  249. char nbytes;
  250. int i;
  251. grass_int64 count;
  252. Rast_init();
  253. init_rstats(rstats);
  254. fd = -1;
  255. if (!G_find_file2_misc("cell_misc", "stats", name, mapset)) {
  256. G_debug(1, "Stats file does not exist");
  257. return -1;
  258. }
  259. fd = G_open_old_misc("cell_misc", "stats", name, mapset);
  260. if (fd < 0) {
  261. G_warning(_("Unable to read stats file for <%s>"),
  262. G_fully_qualified_name(name, mapset));
  263. return -1;
  264. }
  265. if (read(fd, xdr_buf, sizeof(xdr_buf)) != sizeof(xdr_buf)) {
  266. /* if the stats file exists, but empty file, meaning Nulls */
  267. close(fd);
  268. G_debug(1, "Empty stats file meaning Nulls for <%s>",
  269. G_fully_qualified_name(name, mapset));
  270. return 2;
  271. }
  272. G_xdr_get_double(&dcell1, xdr_buf[0]);
  273. G_xdr_get_double(&dcell2, xdr_buf[1]);
  274. rstats->sum = dcell1;
  275. rstats->sumsq = dcell2;
  276. /* count; see cell_values_int() in get_row.c */
  277. nbytes = 1;
  278. if (read(fd, &nbytes, 1) != 1) {
  279. /* if the stats file exists, but empty file, meaning Nulls */
  280. close(fd);
  281. G_debug(1, "Unable to read byte count in stats file for <%s>",
  282. G_fully_qualified_name(name, mapset));
  283. return -1;
  284. }
  285. count = 0;
  286. if (nbytes == 0)
  287. return 1;
  288. if (nbytes < 1 || nbytes > sizeof(grass_int64)) {
  289. close(fd);
  290. G_debug(1, "Invalid byte count in stats file for <%s>",
  291. G_fully_qualified_name(name, mapset));
  292. return -1;
  293. }
  294. if (read(fd, cc, nbytes) != nbytes) {
  295. /* incorrect number of bytes for count */
  296. close(fd);
  297. G_debug(1, "Unable to read count in stats file for <%s>",
  298. G_fully_qualified_name(name, mapset));
  299. return -1;
  300. }
  301. /* copy byte by byte */
  302. for (i = nbytes - 1; i >= 0; i--) {
  303. count = (count << 8);
  304. count = count + cc[i];
  305. }
  306. rstats->count = count;
  307. close(fd);
  308. return 1;
  309. }
  310. /*!
  311. * \brief Write raster range file
  312. *
  313. * This routine writes the range information for the raster map
  314. * <i>name</i> in the current mapset from the <i>range</i> structure.
  315. * A diagnostic message is printed and -1 is returned if there is an
  316. * error writing the range file. Otherwise, 0 is returned.
  317. *
  318. * This routine only writes 2 numbers (min,max) to the range
  319. * file, instead of the 4 (pmin,pmax,nmin,nmax) previously written.
  320. * If there is no defined min,max, an empty file is written.
  321. *
  322. * \param name map name
  323. * \param range pointer to Range structure which holds range info
  324. */
  325. void Rast_write_range(const char *name, const struct Range *range)
  326. {
  327. FILE *fp;
  328. Rast_write_rstats(name, &(range->rstats));
  329. if (Rast_map_type(name, G_mapset()) != CELL_TYPE) {
  330. G_remove_misc("cell_misc", "range", name); /* remove the old file with this name */
  331. G_fatal_error(_("Unable to write range file for <%s>"), name);
  332. }
  333. fp = G_fopen_new_misc("cell_misc", "range", name);
  334. if (!fp) {
  335. G_remove_misc("cell_misc", "range", name); /* remove the old file with this name */
  336. G_fatal_error(_("Unable to write range file for <%s>"), name);
  337. }
  338. /* if range has been updated */
  339. if (!range->first_time)
  340. fprintf(fp, "%ld %ld\n", (long)range->min, (long)range->max);
  341. fclose(fp);
  342. }
  343. /*!
  344. * \brief Write raster range file (floating-point)
  345. *
  346. * Write the floating point range file <tt>f_range</tt>. This file is
  347. * written in binary using XDR format. If there is no defined min/max
  348. * in <em>range</em>, an empty <tt>f_range</tt> file is created.
  349. *
  350. * \param name map name
  351. * \param range pointer to FPRange which holds fp range info
  352. */
  353. void Rast_write_fp_range(const char *name, const struct FPRange *range)
  354. {
  355. int fd;
  356. char xdr_buf[2][XDR_DOUBLE_NBYTES];
  357. Rast_init();
  358. Rast_write_rstats(name, &(range->rstats));
  359. fd = G_open_new_misc("cell_misc", "f_range", name);
  360. if (fd < 0) {
  361. G_remove_misc("cell_misc", "f_range", name);
  362. G_fatal_error(_("Unable to write range file for <%s>"), name);
  363. }
  364. /* if range hasn't been updated, write empty file meaning Nulls */
  365. if (range->first_time) {
  366. close(fd);
  367. return;
  368. }
  369. G_xdr_put_double(xdr_buf[0], &range->min);
  370. G_xdr_put_double(xdr_buf[1], &range->max);
  371. if (write(fd, xdr_buf, sizeof(xdr_buf)) != sizeof(xdr_buf)) {
  372. G_remove_misc("cell_misc", "f_range", name);
  373. G_fatal_error(_("Unable to write range file for <%s>"), name);
  374. }
  375. close(fd);
  376. }
  377. /*!
  378. * \brief Write raster stats file
  379. *
  380. * Write the stats file <tt>stats</tt>. This file is
  381. * written in binary using XDR format. If the count is < 1
  382. * in <em>rstats</em>, an empty <tt>stats</tt> file is created.
  383. *
  384. * \param name map name
  385. * \param rstats pointer to R_stats which holds stats info
  386. */
  387. void Rast_write_rstats(const char *name, const struct R_stats *rstats)
  388. {
  389. int fd;
  390. char xdr_buf[2][XDR_DOUBLE_NBYTES];
  391. unsigned char cc[8];
  392. char nbytes;
  393. int i;
  394. grass_int64 count;
  395. Rast_init();
  396. fd = G_open_new_misc("cell_misc", "stats", name);
  397. if (fd < 0) {
  398. G_remove_misc("cell_misc", "stats", name);
  399. G_fatal_error(_("Unable to write stats file for <%s>"), name);
  400. }
  401. /* if count is zero, write empty file meaning Nulls */
  402. if (rstats->count < 1) {
  403. close(fd);
  404. return;
  405. }
  406. G_xdr_put_double(xdr_buf[0], &rstats->sum);
  407. G_xdr_put_double(xdr_buf[1], &rstats->sumsq);
  408. if (write(fd, xdr_buf, sizeof(xdr_buf)) != sizeof(xdr_buf)) {
  409. G_remove_misc("cell_misc", "stats", name);
  410. G_fatal_error(_("Unable to write stats file for <%s>"), name);
  411. }
  412. /* count; see convert_int() in put_row.c */
  413. count = rstats->count;
  414. nbytes = 0;
  415. /* copy byte by byte */
  416. for (i = 0; i < sizeof(grass_int64); i++) {
  417. cc[i] = count & 0xff;
  418. count >>= 8;
  419. if (cc[i])
  420. nbytes = i;
  421. }
  422. nbytes++;
  423. /* number of bytes needed for count */
  424. if (write(fd, &nbytes, 1) != 1) {
  425. G_remove_misc("cell_misc", "stats", name);
  426. G_fatal_error(_("Unable to write stats file for <%s>"), name);
  427. }
  428. if (nbytes > 0 && write(fd, cc, nbytes) != nbytes) {
  429. G_remove_misc("cell_misc", "stats", name);
  430. G_fatal_error(_("Unable to write stats file for <%s>"), name);
  431. }
  432. close(fd);
  433. }
  434. /*!
  435. * \brief Update range structure (CELL)
  436. *
  437. * Compares the <i>cat</i> value with the minimum and maximum values
  438. * in the <i>range</i> structure, modifying the range if <i>cat</i>
  439. * extends the range.
  440. *
  441. * NULL-values must be detected and ignored.
  442. *
  443. * \param cat raster value
  444. * \param range pointer to Range structure which holds range info
  445. */
  446. void Rast_update_range(CELL cat, struct Range *range)
  447. {
  448. if (!Rast_is_c_null_value(&cat)) {
  449. if (range->first_time) {
  450. range->first_time = 0;
  451. range->min = cat;
  452. range->max = cat;
  453. return;
  454. }
  455. if (cat < range->min)
  456. range->min = cat;
  457. if (cat > range->max)
  458. range->max = cat;
  459. }
  460. }
  461. /*!
  462. * \brief Update range structure (floating-point)
  463. *
  464. * Compares the <i>cat</i> value with the minimum and maximum values
  465. * in the <i>range</i> structure, modifying the range if <i>cat</i>
  466. * extends the range.
  467. *
  468. * NULL-values must be detected and ignored.
  469. *
  470. * \param val raster value
  471. * \param range pointer to Range structure which holds range info
  472. */
  473. void Rast_update_fp_range(DCELL val, struct FPRange *range)
  474. {
  475. if (!Rast_is_d_null_value(&val)) {
  476. if (range->first_time) {
  477. range->first_time = 0;
  478. range->min = val;
  479. range->max = val;
  480. return;
  481. }
  482. if (val < range->min)
  483. range->min = val;
  484. if (val > range->max)
  485. range->max = val;
  486. }
  487. }
  488. /*!
  489. * \brief Update range structure based on raster row (CELL)
  490. *
  491. * This routine updates the <i>range</i> data just like
  492. * Rast_update_range(), but for <i>n</i> values from the <i>cell</i>
  493. * array.
  494. *
  495. * \param cell raster values
  496. * \param n number of values
  497. * \param range pointer to Range structure which holds range info
  498. */
  499. void Rast_row_update_range(const CELL * cell, int n, struct Range *range)
  500. {
  501. Rast__row_update_range(cell, n, range, 0);
  502. }
  503. /*!
  504. * \brief Update range structure based on raster row
  505. *
  506. * Note: for internal use only.
  507. *
  508. * \param cell raster values
  509. * \param n number of values
  510. * \param range pointer to Range structure which holds range info
  511. * \param ignore_zeros ignore zeros
  512. */
  513. void Rast__row_update_range(const CELL * cell, int n,
  514. struct Range *range, int ignore_zeros)
  515. {
  516. CELL cat;
  517. while (n-- > 0) {
  518. cat = *cell++;
  519. if (Rast_is_c_null_value(&cat) || (ignore_zeros && !cat))
  520. continue;
  521. if (range->first_time) {
  522. range->first_time = 0;
  523. range->min = cat;
  524. range->max = cat;
  525. range->rstats.sum = cat;
  526. range->rstats.sumsq = (DCELL) cat * cat;
  527. range->rstats.count = 1;
  528. continue;
  529. }
  530. if (cat < range->min)
  531. range->min = cat;
  532. if (cat > range->max)
  533. range->max = cat;
  534. range->rstats.sum += cat;
  535. range->rstats.sumsq += (DCELL) cat * cat;
  536. range->rstats.count += 1;
  537. }
  538. }
  539. /*!
  540. * \brief Update range structure based on raster row (floating-point)
  541. *
  542. * This routine updates the <i>range</i> data just like
  543. * Rast_update_range(), but for <i>n</i> values from the <i>cell</i>
  544. * array.
  545. *
  546. * \param cell raster values
  547. * \param n number of values
  548. * \param range pointer to Range structure which holds range info
  549. * \param data_type raster type (CELL, FCELL, DCELL)
  550. */
  551. void Rast_row_update_fp_range(const void *rast, int n,
  552. struct FPRange *range,
  553. RASTER_MAP_TYPE data_type)
  554. {
  555. size_t size = Rast_cell_size(data_type);
  556. DCELL val = 0.0;
  557. while (n-- > 0) {
  558. switch (data_type) {
  559. case CELL_TYPE:
  560. val = (DCELL) * ((CELL *) rast);
  561. break;
  562. case FCELL_TYPE:
  563. val = (DCELL) * ((FCELL *) rast);
  564. break;
  565. case DCELL_TYPE:
  566. val = *((DCELL *) rast);
  567. break;
  568. }
  569. if (Rast_is_null_value(rast, data_type)) {
  570. rast = G_incr_void_ptr(rast, size);
  571. continue;
  572. }
  573. if (range->first_time) {
  574. range->first_time = 0;
  575. range->min = val;
  576. range->max = val;
  577. range->rstats.sum = val;
  578. range->rstats.sumsq = val * val;
  579. range->rstats.count = 1;
  580. }
  581. else {
  582. if (val < range->min)
  583. range->min = val;
  584. if (val > range->max)
  585. range->max = val;
  586. range->rstats.sum += val;
  587. range->rstats.sumsq += val * val;
  588. range->rstats.count += 1;
  589. }
  590. rast = G_incr_void_ptr(rast, size);
  591. }
  592. }
  593. /*!
  594. * \brief Initialize range structure
  595. *
  596. * Initializes the <i>range</i> structure for updates by
  597. * Rast_update_range() and Rast_row_update_range().
  598. *
  599. * Must set a flag in the range structure that indicates that no
  600. * min/max have been defined - probably a <tt>"first"</tt> boolean
  601. * flag.
  602. *
  603. * \param range pointer to Range structure which holds range info
  604. */
  605. void Rast_init_range(struct Range *range)
  606. {
  607. Rast_set_c_null_value(&(range->min), 1);
  608. Rast_set_c_null_value(&(range->max), 1);
  609. init_rstats(&range->rstats);
  610. range->first_time = 1;
  611. }
  612. /*!
  613. * \brief Get range min and max
  614. *
  615. * The minimum and maximum CELL values are extracted from the
  616. * <i>range</i> structure.
  617. *
  618. * If the range structure has no defined min/max (first!=0) there will
  619. * not be a valid range. In this case the min and max returned must be
  620. * the NULL-value.
  621. *
  622. * \param range pointer to Range structure which holds range info
  623. * \param[out] min minimum value
  624. * \param[out] max maximum value
  625. */
  626. void Rast_get_range_min_max(const struct Range *range, CELL * min, CELL * max)
  627. {
  628. if (range->first_time) {
  629. Rast_set_c_null_value(min, 1);
  630. Rast_set_c_null_value(max, 1);
  631. }
  632. else {
  633. if (Rast_is_c_null_value(&(range->min)))
  634. Rast_set_c_null_value(min, 1);
  635. else
  636. *min = range->min;
  637. if (Rast_is_c_null_value(&(range->max)))
  638. Rast_set_c_null_value(max, 1);
  639. else
  640. *max = range->max;
  641. }
  642. }
  643. /*!
  644. * \brief Initialize fp range
  645. *
  646. * Must set a flag in the range structure that indicates that no
  647. * min/max have been defined - probably a <tt>"first"</tt> boolean
  648. * flag.
  649. *
  650. * \param range pointer to FPRange which holds fp range info
  651. */
  652. void Rast_init_fp_range(struct FPRange *range)
  653. {
  654. Rast_set_d_null_value(&(range->min), 1);
  655. Rast_set_d_null_value(&(range->max), 1);
  656. init_rstats(&range->rstats);
  657. range->first_time = 1;
  658. }
  659. /*!
  660. * \brief Get minimum and maximum value from fp range
  661. *
  662. * Extract the min/max from the range structure <i>range</i>. If the
  663. * range structure has no defined min/max (first!=0) there will not be
  664. * a valid range. In this case the min and max returned must be the
  665. * NULL-value.
  666. *
  667. * \param range pointer to FPRange which holds fp range info
  668. * \param[out] min minimum value
  669. * \param[out] max maximum value
  670. */
  671. void Rast_get_fp_range_min_max(const struct FPRange *range,
  672. DCELL * min, DCELL * max)
  673. {
  674. if (range->first_time) {
  675. Rast_set_d_null_value(min, 1);
  676. Rast_set_d_null_value(max, 1);
  677. }
  678. else {
  679. if (Rast_is_d_null_value(&(range->min)))
  680. Rast_set_d_null_value(min, 1);
  681. else
  682. *min = range->min;
  683. if (Rast_is_d_null_value(&(range->max)))
  684. Rast_set_d_null_value(max, 1);
  685. else
  686. *max = range->max;
  687. }
  688. }
  689. static void init_rstats(struct R_stats *rstats)
  690. {
  691. Rast_set_d_null_value(&(rstats->sum), 1);
  692. Rast_set_d_null_value(&(rstats->sumsq), 1);
  693. rstats->count = 0;
  694. }