range.c 15 KB

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