range.c 15 KB

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