range.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604
  1. /*!
  2. * \file 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 <rpc/types.h> /* need this for sgi */
  15. #include <rpc/xdr.h>
  16. #include <grass/raster.h>
  17. #include <grass/glocale.h>
  18. #include "R.h"
  19. #define DEFAULT_CELL_MIN 1
  20. #define DEFAULT_CELL_MAX 255
  21. /*!
  22. \brief Remove floating-point range
  23. Note: For internal use only.
  24. \param name map name
  25. */
  26. void Rast__remove_fp_range(const char *name)
  27. {
  28. G_remove_misc("cell_misc", "f_range", name);
  29. }
  30. /*!
  31. * \brief Construct default range
  32. *
  33. * Sets the integer range to [1,255]
  34. *
  35. * \param[out] r pointer to Range structure which holds range info
  36. */
  37. void Rast_construct_default_range(struct Range *range)
  38. {
  39. Rast_update_range(DEFAULT_CELL_MIN, range);
  40. Rast_update_range(DEFAULT_CELL_MAX, range);
  41. }
  42. /*!
  43. * \brief Read floating-point range
  44. *
  45. * Read the floating point range file <i>drange</i>. This file is
  46. * written in binary using XDR format.
  47. *
  48. * An empty range file indicates that the min, max are undefined. This
  49. * is a valid case, and the result should be an initialized range
  50. * struct with no defined min/max. If the range file is missing and
  51. * the map is a floating-point map, this function will create a
  52. * default range by calling G_construct_default_range().
  53. *
  54. * \param name map name
  55. * \param mapset mapset name
  56. * \param drange pointer to FPRange structure which holds fp range
  57. *
  58. * \return 1 on success
  59. * \return 2 range is empty
  60. * \return -1 on error
  61. */
  62. int Rast_read_fp_range(const char *name, const char *mapset,
  63. struct FPRange *drange)
  64. {
  65. struct Range range;
  66. int fd;
  67. char xdr_buf[100];
  68. DCELL dcell1, dcell2;
  69. XDR xdr_str;
  70. Rast_init_fp_range(drange);
  71. if (Rast_map_type(name, mapset) == CELL_TYPE) {
  72. /* if map is integer
  73. read integer range and convert it to double */
  74. if (Rast_read_range(name, mapset, &range) >= 0) {
  75. /* if the integer range is empty */
  76. if (range.first_time)
  77. return 2;
  78. Rast_update_fp_range((DCELL) range.min, drange);
  79. Rast_update_fp_range((DCELL) range.max, drange);
  80. return 1;
  81. }
  82. return -1;
  83. }
  84. fd = -1;
  85. if (G_find_file2_misc("cell_misc", "f_range", name, mapset)) {
  86. fd = G_open_old_misc("cell_misc", "f_range", name, mapset);
  87. if (fd < 0) {
  88. G_warning(_("Unable to read fp range file for <%s@%s>"),
  89. name, mapset);
  90. return -1;
  91. }
  92. if (read(fd, xdr_buf, 2 * XDR_DOUBLE_NBYTES) != 2 * XDR_DOUBLE_NBYTES)
  93. return 2;
  94. xdrmem_create(&xdr_str, xdr_buf, (u_int) XDR_DOUBLE_NBYTES * 2,
  95. XDR_DECODE);
  96. /* if the f_range file exists, but empty */
  97. if (!xdr_double(&xdr_str, &dcell1) || !xdr_double(&xdr_str, &dcell2)) {
  98. if (fd)
  99. close(fd);
  100. G_warning(_("Unable to read fp range file for <%s@%s>"),
  101. name, mapset);
  102. return -1;
  103. }
  104. Rast_update_fp_range(dcell1, drange);
  105. Rast_update_fp_range(dcell2, drange);
  106. close(fd);
  107. }
  108. return 1;
  109. }
  110. /*!
  111. * \brief Read raster range (CELL)
  112. *
  113. * This routine reads the range information for the raster map
  114. * <i>name</i> in <i>mapset</i> into the <i>range</i> structure.
  115. *
  116. * A diagnostic message is printed and -1 is returned if there is an error
  117. * reading the range file. Otherwise, 0 is returned.
  118. *
  119. * Old range file (those with 4 numbers) should treat zeros in this
  120. * file as NULL-values. New range files (those with just 2 numbers)
  121. * should treat these numbers as real data (zeros are real data in
  122. * this case). An empty range file indicates that the min, max are
  123. * undefined. This is a valid case, and the result should be an
  124. * initialized range struct with no defined min/max. If the range file
  125. * is missing and the map is a floating-point map, this function will
  126. * create a default range by calling G_construct_default_range().
  127. *
  128. * \param name map name
  129. * \param mapset mapset name
  130. * \param range pointer to Range structure which holds range info
  131. *
  132. * \return -1 on error
  133. * \return 1 on success
  134. * \return 2 if range is empty
  135. * \return 3 if raster map is floating-point, get range from quant rules
  136. */
  137. int Rast_read_range(const char *name, const char *mapset, struct Range *range)
  138. {
  139. FILE *fd;
  140. CELL x[4];
  141. char buf[200];
  142. int n, count;
  143. struct Quant quant;
  144. struct FPRange drange;
  145. Rast_init_range(range);
  146. fd = NULL;
  147. /* if map is not integer, read quant rules, and get limits */
  148. if (Rast_map_type(name, mapset) != CELL_TYPE) {
  149. DCELL dmin, dmax;
  150. if (Rast_read_quant(name, mapset, &quant) < 0) {
  151. G_warning(_("Unable to read quant rules for raster map <%s@%s>"),
  152. name, mapset);
  153. return -1;
  154. }
  155. if (Rast_quant_is_truncate(&quant) || Rast_quant_is_round(&quant)) {
  156. if (Rast_read_fp_range(name, mapset, &drange) >= 0) {
  157. Rast_get_fp_range_min_max(&drange, &dmin, &dmax);
  158. if (Rast_quant_is_truncate(&quant)) {
  159. x[0] = (CELL) dmin;
  160. x[1] = (CELL) dmax;
  161. }
  162. else { /* round */
  163. if (dmin > 0)
  164. x[0] = (CELL) (dmin + .5);
  165. else
  166. x[0] = (CELL) (dmin - .5);
  167. if (dmax > 0)
  168. x[1] = (CELL) (dmax + .5);
  169. else
  170. x[1] = (CELL) (dmax - .5);
  171. }
  172. }
  173. else
  174. return -1;
  175. }
  176. else
  177. Rast_quant_get_limits(&quant, &dmin, &dmax, &x[0], &x[1]);
  178. Rast_update_range(x[0], range);
  179. Rast_update_range(x[1], range);
  180. return 3;
  181. }
  182. if (G_find_file2_misc("cell_misc", "range", name, mapset)) {
  183. fd = G_fopen_old_misc("cell_misc", "range", name, mapset);
  184. if (!fd) {
  185. G_warning(_("Unable to read range file for <%s@%s>"),
  186. name, mapset);
  187. return -1;
  188. }
  189. /* if range file exists but empty */
  190. if (!fgets(buf, sizeof buf, fd))
  191. return 2;
  192. x[0] = x[1] = x[2] = x[3] = 0;
  193. count = sscanf(buf, "%d%d%d%d", &x[0], &x[1], &x[2], &x[3]);
  194. /* if wrong format */
  195. if (count <= 0) {
  196. if (fd)
  197. fclose(fd);
  198. G_warning(_("Unable to read range file for <%s@%s>"),
  199. name, mapset);
  200. return -1;
  201. }
  202. for (n = 0; n < count; n++) {
  203. /* if count==4, the range file is old (4.1) and 0's in it
  204. have to be ignored */
  205. if (count < 4 || x[n])
  206. Rast_update_range((CELL) x[n], range);
  207. }
  208. fclose(fd);
  209. }
  210. return 1;
  211. }
  212. /*!
  213. * \brief Write raster range file
  214. *
  215. * This routine writes the range information for the raster map
  216. * <i>name</i> in the current mapset from the <i>range</i> structure.
  217. * A diagnostic message is printed and -1 is returned if there is an
  218. * error writing the range file. Otherwise, 0 is returned.
  219. *
  220. * This routine only writes 2 numbers (min,max) to the range
  221. * file, instead of the 4 (pmin,pmax,nmin,nmax) previously written.
  222. * If there is no defined min,max, an empty file is written.
  223. *
  224. * \param name map name
  225. * \param range pointer to Range structure which holds range info
  226. *
  227. * \return -1 on error (or raster map is floating-point)
  228. * \return 0 on success
  229. */
  230. int Rast_write_range(const char *name, const struct Range *range)
  231. {
  232. FILE *fd;
  233. if (Rast_map_type(name, G_mapset()) != CELL_TYPE) {
  234. G_remove_misc("cell_misc", "range", name); /* remove the old file with this name */
  235. G_warning(_("Unable to write range file for <%s>"),
  236. name);
  237. return -1;
  238. }
  239. fd = G_fopen_new_misc("cell_misc", "range", name);
  240. if (!fd) {
  241. G_remove_misc("cell_misc", "range", name); /* remove the old file with this name */
  242. G_warning(_("Unable to write range file for <%s>"),
  243. name);
  244. return -1;
  245. }
  246. /* if range hasn't been updated */
  247. if (range->first_time) {
  248. fclose(fd);
  249. return 0;
  250. }
  251. fprintf(fd, "%ld %ld\n", (long)range->min, (long)range->max);
  252. fclose(fd);
  253. return 0;
  254. }
  255. /*!
  256. * \brief Write raster range file (floating-point)
  257. *
  258. * Write the floating point range file <tt>f_range</tt>. This file is
  259. * written in binary using XDR format. If there is no defined min/max
  260. * in <em>range</em>, an empty <tt>f_range</tt> file is created.
  261. *
  262. * \param name map name
  263. * \param range pointer to FPRange which holds fp range info
  264. *
  265. * \return 0 on success
  266. * \return -1 on error
  267. */
  268. int Rast_write_fp_range(const char *name, const struct FPRange *range)
  269. {
  270. int fd;
  271. char xdr_buf[100];
  272. XDR xdr_str;
  273. fd = G_open_new_misc("cell_misc", "f_range", name);
  274. if (fd < 0) {
  275. G_remove_misc("cell_misc", "f_range", name);
  276. G_warning(_("Unable to write range file for <%s>"),
  277. name);
  278. return -1;
  279. }
  280. /* if range hasn't been updated, write empty file meaning Nulls */
  281. if (range->first_time) {
  282. close(fd);
  283. return 0;
  284. }
  285. xdrmem_create(&xdr_str, xdr_buf, (u_int) XDR_DOUBLE_NBYTES * 2,
  286. XDR_ENCODE);
  287. if (!xdr_double(&xdr_str, (double *)&(range->min))) {
  288. G_remove_misc("cell_misc", "f_range", name);
  289. G_warning(_("Unable to write range file for <%s>"),
  290. name);
  291. return -1;
  292. }
  293. if (!xdr_double(&xdr_str, (double *)&(range->max))) {
  294. G_remove_misc("cell_misc", "f_range", name);
  295. G_warning(_("Unable to write range file for <%s>"),
  296. name);
  297. return -1;
  298. }
  299. write(fd, xdr_buf, XDR_DOUBLE_NBYTES * 2);
  300. close(fd);
  301. return 0;
  302. }
  303. /*!
  304. * \brief Update range structure (CELL)
  305. *
  306. * Compares the <i>cat</i> value with the minimum and maximum values
  307. * in the <i>range</i> structure, modifying the range if <i>cat</i>
  308. * extends the range.
  309. *
  310. * NULL-values must be detected and ignored.
  311. *
  312. * \param cat raster value
  313. * \param range pointer to Range structure which holds range info
  314. */
  315. void Rast_update_range(CELL cat, struct Range *range)
  316. {
  317. if (!Rast_is_c_null_value(&cat)) {
  318. if (range->first_time) {
  319. range->first_time = 0;
  320. range->min = cat;
  321. range->max = cat;
  322. return;
  323. }
  324. if (cat < range->min)
  325. range->min = cat;
  326. if (cat > range->max)
  327. range->max = cat;
  328. }
  329. }
  330. /*!
  331. * \brief Update range structure (floating-point)
  332. *
  333. * Compares the <i>cat</i> value with the minimum and maximum values
  334. * in the <i>range</i> structure, modifying the range if <i>cat</i>
  335. * extends the range.
  336. *
  337. * NULL-values must be detected and ignored.
  338. *
  339. * \param val raster value
  340. * \param range pointer to Range structure which holds range info
  341. */
  342. void Rast_update_fp_range(DCELL val, struct FPRange *range)
  343. {
  344. if (!Rast_is_d_null_value(&val)) {
  345. if (range->first_time) {
  346. range->first_time = 0;
  347. range->min = val;
  348. range->max = val;
  349. return;
  350. }
  351. if (val < range->min)
  352. range->min = val;
  353. if (val > range->max)
  354. range->max = val;
  355. }
  356. }
  357. /*!
  358. * \brief Update range structure based on raster row (CELL)
  359. *
  360. * This routine updates the <i>range</i> data just like
  361. * Rast_update_range(), but for <i>n</i> values from the <i>cell</i>
  362. * array.
  363. *
  364. * \param cell raster values
  365. * \param n number of values
  366. * \param range pointer to Range structure which holds range info
  367. */
  368. void Rast_row_update_range(const CELL *cell, int n, struct Range *range)
  369. {
  370. Rast__row_update_range(cell, n, range, 0);
  371. }
  372. /*!
  373. * \brief Update range structure based on raster row
  374. *
  375. * Note: for internal use only.
  376. *
  377. * \param cell raster values
  378. * \param n number of values
  379. * \param range pointer to Range structure which holds range info
  380. * \param ignore_zeros ignore zeros
  381. */
  382. void Rast__row_update_range(const CELL *cell, int n,
  383. struct Range *range, int ignore_zeros)
  384. {
  385. CELL cat;
  386. while (n-- > 0) {
  387. cat = *cell++;
  388. if (Rast_is_c_null_value(&cat) || (ignore_zeros && !cat))
  389. continue;
  390. if (range->first_time) {
  391. range->first_time = 0;
  392. range->min = cat;
  393. range->max = cat;
  394. continue;
  395. }
  396. if (cat < range->min)
  397. range->min = cat;
  398. if (cat > range->max)
  399. range->max = cat;
  400. }
  401. }
  402. /*!
  403. * \brief Update range structure based on raster row (floating-point)
  404. *
  405. * This routine updates the <i>range</i> data just like
  406. * Rast_update_range(), but for <i>n</i> values from the <i>cell</i>
  407. * array.
  408. *
  409. * \param cell raster values
  410. * \param n number of values
  411. * \param range pointer to Range structure which holds range info
  412. * \param data_type raster type (CELL, FCELL, DCELL)
  413. */
  414. void Rast_row_update_fp_range(const void *rast, int n,
  415. struct FPRange *range, RASTER_MAP_TYPE data_type)
  416. {
  417. DCELL val = 0L;
  418. while (n-- > 0) {
  419. switch (data_type) {
  420. case CELL_TYPE:
  421. val = (DCELL) * ((CELL *) rast);
  422. break;
  423. case FCELL_TYPE:
  424. val = (DCELL) * ((FCELL *) rast);
  425. break;
  426. case DCELL_TYPE:
  427. val = *((DCELL *) rast);
  428. break;
  429. }
  430. if (Rast_is_null_value(rast, data_type)) {
  431. rast = G_incr_void_ptr(rast, Rast_cell_size(data_type));
  432. continue;
  433. }
  434. if (range->first_time) {
  435. range->first_time = 0;
  436. range->min = val;
  437. range->max = val;
  438. }
  439. else {
  440. if (val < range->min)
  441. range->min = val;
  442. if (val > range->max)
  443. range->max = val;
  444. }
  445. rast = G_incr_void_ptr(rast, Rast_cell_size(data_type));
  446. }
  447. }
  448. /*!
  449. * \brief Initialize range structure
  450. *
  451. * Initializes the <i>range</i> structure for updates by
  452. * Rast_update_range() and Rast_row_update_range().
  453. *
  454. * Must set a flag in the range structure that indicates that no
  455. * min/max have been defined - probably a <tt>"first"</tt> boolean
  456. * flag.
  457. *
  458. * \param range pointer to Range structure which holds range info
  459. */
  460. void Rast_init_range(struct Range *range)
  461. {
  462. Rast_set_c_null_value(&(range->min), 1);
  463. Rast_set_c_null_value(&(range->max), 1);
  464. range->first_time = 1;
  465. }
  466. /*!
  467. * \brief Get range min and max
  468. *
  469. * The mininum and maximum CELL values are extracted from the
  470. * <i>range</i> structure.
  471. *
  472. * If the range structure has no defined min/max (first!=0) there will
  473. * not be a valid range. In this case the min and max returned must be
  474. * the NULL-value.
  475. *
  476. * \param range pointer to Range structure which holds range info
  477. * \param[out] min minimum value
  478. * \param[out] max maximum value
  479. */
  480. void Rast_get_range_min_max(const struct Range *range, CELL * min, CELL * max)
  481. {
  482. if (range->first_time) {
  483. Rast_set_c_null_value(min, 1);
  484. Rast_set_c_null_value(max, 1);
  485. }
  486. else {
  487. if (Rast_is_c_null_value(&(range->min)))
  488. Rast_set_c_null_value(min, 1);
  489. else
  490. *min = range->min;
  491. if (Rast_is_c_null_value(&(range->max)))
  492. Rast_set_c_null_value(max, 1);
  493. else
  494. *max = range->max;
  495. }
  496. }
  497. /*!
  498. * \brief Initialize fp range
  499. *
  500. * Must set a flag in the range structure that indicates that no
  501. * min/max have been defined - probably a <tt>"first"</tt> boolean
  502. * flag.
  503. *
  504. * \param range pointer to FPRange which holds fp range info
  505. */
  506. void Rast_init_fp_range(struct FPRange *range)
  507. {
  508. Rast_set_d_null_value(&(range->min), 1);
  509. Rast_set_d_null_value(&(range->max), 1);
  510. range->first_time = 1;
  511. }
  512. /*!
  513. * \brief Get minumum and maximum value from fp range
  514. *
  515. * Extract the min/max from the range structure <i>range</i>. If the
  516. * range structure has no defined min/max (first!=0) there will not be
  517. * a valid range. In this case the min and max returned must be the
  518. * NULL-value.
  519. *
  520. * \param range pointer to FPRange which holds fp range info
  521. * \param[out] min minimum value
  522. * \param[out] max maximum value
  523. */
  524. void Rast_get_fp_range_min_max(const struct FPRange *range,
  525. DCELL *min, DCELL *max)
  526. {
  527. if (range->first_time) {
  528. Rast_set_d_null_value(min, 1);
  529. Rast_set_d_null_value(max, 1);
  530. }
  531. else {
  532. if (Rast_is_d_null_value(&(range->min)))
  533. Rast_set_d_null_value(min, 1);
  534. else
  535. *min = range->min;
  536. if (Rast_is_d_null_value(&(range->max)))
  537. Rast_set_d_null_value(max, 1);
  538. else
  539. *max = range->max;
  540. }
  541. }