sample.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. /*!
  2. \file raster/sample.c
  3. \brief Raster library - Sampling methods (extract a cell value from
  4. raster map)
  5. 1/2006: moved to libgis from v.sample/v.drape for clone removal
  6. (C) 2001-2009 by the GRASS Development Team
  7. This program is free software under the GNU General Public License
  8. (>=v2). Read the file COPYING that comes with GRASS for details.
  9. \author James Darrell McCauley <darrell mccauley-usa.com>, http://mccauley-usa.com/
  10. */
  11. #include <string.h>
  12. #include <unistd.h>
  13. #include <math.h>
  14. #include <grass/gis.h>
  15. #include <grass/raster.h>
  16. #include <grass/glocale.h>
  17. /* prototypes */
  18. static double scancatlabel(const char *);
  19. static void raster_row_error(const struct Cell_head *window, double north,
  20. double east);
  21. /*!
  22. * \brief Extract a cell value from raster map.
  23. *
  24. * Extract a cell value from raster map at given northing and easting
  25. * with a sampled 3x3 window using a specified interpolation method.
  26. *
  27. * - NEAREST neighbor interpolation
  28. * - BILINEAR bilinear interpolation
  29. * - CUBIC cubic interpolation
  30. *
  31. * \param fd file descriptor
  32. * \param window region settings
  33. * \param cats categories
  34. * \param north northing position
  35. * \param east easting position
  36. * \param usedesc flag to scan category label
  37. * \param itype interpolation method
  38. *
  39. * \return cell value at given position
  40. */
  41. DCELL Rast_get_raster_sample(int fd,
  42. const struct Cell_head *window,
  43. struct Categories *cats,
  44. double north, double east,
  45. int usedesc, INTERP_TYPE itype)
  46. {
  47. double retval;
  48. switch (itype) {
  49. case NEAREST:
  50. retval = Rast_get_raster_sample_nearest(fd, window, cats, north, east, usedesc);
  51. break;
  52. case BILINEAR:
  53. retval = Rast_get_raster_sample_bilinear(fd, window, cats, north, east, usedesc);
  54. break;
  55. case CUBIC:
  56. retval = Rast_get_raster_sample_cubic(fd, window, cats, north, east, usedesc);
  57. break;
  58. default:
  59. G_fatal_error("Rast_get_raster_sample: %s",
  60. _("Unknown interpolation type"));
  61. }
  62. return retval;
  63. }
  64. /*!
  65. * \brief Extract a cell value from raster map (neighbor interpolation)
  66. *
  67. * Extract a cell value from raster map at given northing and easting
  68. * with a sampled 3x3 window using a neighbor interpolation.
  69. *
  70. * \param fd file descriptor
  71. * \param window region settings
  72. * \param cats categories
  73. * \param north northing position
  74. * \param east easting position
  75. * \param usedesc flag to scan category label
  76. *
  77. * \return cell value at given position
  78. */
  79. DCELL Rast_get_raster_sample_nearest(int fd,
  80. const struct Cell_head *window,
  81. struct Categories *cats,
  82. double north, double east, int usedesc)
  83. {
  84. int row, col;
  85. DCELL result;
  86. DCELL *maprow = Rast_allocate_d_buf();
  87. /* convert northing and easting to row and col, resp */
  88. row = (int)floor(G_northing_to_row(north, window));
  89. col = (int)floor(G_easting_to_col(east, window));
  90. if (row < 0 || row >= G_window_rows() ||
  91. col < 0 || col >= G_window_cols()) {
  92. Rast_set_d_null_value(&result, 1);
  93. goto done;
  94. }
  95. if (Rast_get_d_raster_row(fd, maprow, row) < 0)
  96. raster_row_error(window, north, east);
  97. if (Rast_is_d_null_value(&maprow[col])) {
  98. Rast_set_d_null_value(&result, 1);
  99. goto done;
  100. }
  101. if (usedesc) {
  102. char *buf = Rast_get_cat(maprow[col], cats);
  103. G_squeeze(buf);
  104. result = scancatlabel(buf);
  105. }
  106. else
  107. result = maprow[col];
  108. done:
  109. G_free(maprow);
  110. return result;
  111. }
  112. /*!
  113. * \brief Extract a cell value from raster map (bilinear interpolation).
  114. *
  115. * Extract a cell value from raster map at given northing and easting
  116. * with a sampled 3x3 window using a bilinear interpolation.
  117. *
  118. * \param fd file descriptor
  119. * \param window region settings
  120. * \param cats categories
  121. * \param north northing position
  122. * \param east easting position
  123. * \param usedesc flag to scan category label
  124. *
  125. * \return cell value at given position
  126. */
  127. DCELL Rast_get_raster_sample_bilinear(int fd,
  128. const struct Cell_head *window,
  129. struct Categories *cats,
  130. double north, double east, int usedesc)
  131. {
  132. int row, col;
  133. double grid[2][2];
  134. DCELL *arow = Rast_allocate_d_buf();
  135. DCELL *brow = Rast_allocate_d_buf();
  136. double frow, fcol, trow, tcol;
  137. DCELL result;
  138. frow = G_northing_to_row(north, window);
  139. fcol = G_easting_to_col(east, window);
  140. /* convert northing and easting to row and col, resp */
  141. row = (int)floor(frow - 0.5);
  142. col = (int)floor(fcol - 0.5);
  143. trow = frow - row - 0.5;
  144. tcol = fcol - col - 0.5;
  145. if (row < 0 || row + 1 >= G_window_rows() ||
  146. col < 0 || col + 1 >= G_window_cols()) {
  147. Rast_set_d_null_value(&result, 1);
  148. goto done;
  149. }
  150. if (Rast_get_d_raster_row(fd, arow, row) < 0)
  151. raster_row_error(window, north, east);
  152. if (Rast_get_d_raster_row(fd, brow, row + 1) < 0)
  153. raster_row_error(window, north, east);
  154. if (Rast_is_d_null_value(&arow[col]) || Rast_is_d_null_value(&arow[col + 1]) ||
  155. Rast_is_d_null_value(&brow[col]) || Rast_is_d_null_value(&brow[col + 1])) {
  156. Rast_set_d_null_value(&result, 1);
  157. goto done;
  158. }
  159. /*-
  160. * now were ready to do bilinear interpolation over
  161. * arow[col], arow[col+1],
  162. * brow[col], brow[col+1]
  163. */
  164. if (usedesc) {
  165. char *buf;
  166. G_squeeze(buf = Rast_get_cat((int)arow[col], cats));
  167. grid[0][0] = scancatlabel(buf);
  168. G_squeeze(buf = Rast_get_cat((int)arow[col + 1], cats));
  169. grid[0][1] = scancatlabel(buf);
  170. G_squeeze(buf = Rast_get_cat((int)brow[col], cats));
  171. grid[1][0] = scancatlabel(buf);
  172. G_squeeze(buf = Rast_get_cat((int)brow[col + 1], cats));
  173. grid[1][1] = scancatlabel(buf);
  174. }
  175. else {
  176. grid[0][0] = arow[col];
  177. grid[0][1] = arow[col + 1];
  178. grid[1][0] = brow[col];
  179. grid[1][1] = brow[col + 1];
  180. }
  181. result = Rast_interp_bilinear(tcol, trow,
  182. grid[0][0], grid[0][1], grid[1][0], grid[1][1]);
  183. done:
  184. G_free(arow);
  185. G_free(brow);
  186. return result;
  187. }
  188. /*!
  189. * \brief Extract a cell value from raster map (cubic interpolation).
  190. *
  191. * Extract a cell value from raster map at given northing and easting
  192. * with a sampled 3x3 window using a cubic interpolation.
  193. *
  194. * \param fd file descriptor
  195. * \param window region settings
  196. * \param cats categories
  197. * \param north northing position
  198. * \param east easting position
  199. * \param usedesc flag to scan category label
  200. *
  201. * \return cell value at given position
  202. */
  203. DCELL Rast_get_raster_sample_cubic(int fd,
  204. const struct Cell_head *window,
  205. struct Categories *cats,
  206. double north, double east, int usedesc)
  207. {
  208. int i, j, row, col;
  209. double grid[4][4];
  210. DCELL *rows[4];
  211. double frow, fcol, trow, tcol;
  212. DCELL result;
  213. for (i = 0; i < 4; i++)
  214. rows[i] = Rast_allocate_d_buf();
  215. frow = G_northing_to_row(north, window);
  216. fcol = G_easting_to_col(east, window);
  217. /* convert northing and easting to row and col, resp */
  218. row = (int)floor(frow - 1.5);
  219. col = (int)floor(fcol - 1.5);
  220. trow = frow - row - 1.5;
  221. tcol = fcol - col - 1.5;
  222. if (row < 0 || row + 3 >= G_window_rows() ||
  223. col < 0 || col + 3 >= G_window_cols()) {
  224. Rast_set_d_null_value(&result, 1);
  225. goto done;
  226. }
  227. for (i = 0; i < 4; i++)
  228. if (Rast_get_d_raster_row(fd, rows[i], row + i) < 0)
  229. raster_row_error(window, north, east);
  230. for (i = 0; i < 4; i++)
  231. for (j = 0; j < 4; j++)
  232. if (Rast_is_d_null_value(&rows[i][col + j])) {
  233. Rast_set_d_null_value(&result, 1);
  234. goto done;
  235. }
  236. /*
  237. * now were ready to do cubic interpolation over
  238. * arow[col], arow[col+1], arow[col+2], arow[col+3],
  239. * brow[col], brow[col+1], brow[col+2], brow[col+3],
  240. * crow[col], crow[col+1], crow[col+2], crow[col+3],
  241. * drow[col], drow[col+1], drow[col+2], drow[col+3],
  242. */
  243. if (usedesc) {
  244. char *buf;
  245. for (i = 0; i < 4; i++) {
  246. for (j = 0; j < 4; j++) {
  247. G_squeeze(buf = Rast_get_cat(rows[i][col + j], cats));
  248. grid[i][j] = scancatlabel(buf);
  249. }
  250. }
  251. }
  252. else {
  253. for (i = 0; i < 4; i++)
  254. for (j = 0; j < 4; j++)
  255. grid[i][j] = rows[i][col + j];
  256. }
  257. result = Rast_interp_bicubic(tcol, trow,
  258. grid[0][0], grid[0][1], grid[0][2], grid[0][3],
  259. grid[1][0], grid[1][1], grid[1][2], grid[1][3],
  260. grid[2][0], grid[2][1], grid[2][2], grid[2][3],
  261. grid[3][0], grid[3][1], grid[3][2], grid[3][3]);
  262. done:
  263. for (i = 0; i < 4; i++)
  264. G_free(rows[i]);
  265. return result;
  266. }
  267. static double scancatlabel(const char *str)
  268. {
  269. double val;
  270. if (strcmp(str, "no data") != 0)
  271. sscanf(str, "%lf", &val);
  272. else {
  273. G_warning(_("\"no data\" label found; setting to zero"));
  274. val = 0.0;
  275. }
  276. return val;
  277. }
  278. static void raster_row_error(const struct Cell_head *window, double north,
  279. double east)
  280. {
  281. G_debug(3, "DIAG: \tRegion is: n=%g s=%g e=%g w=%g",
  282. window->north, window->south, window->east, window->west);
  283. G_debug(3, " \tData point is north=%g east=%g", north, east);
  284. G_fatal_error(_("Problem reading raster map"));
  285. }