sample.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472
  1. /*!
  2. \file sample.c
  3. \brief GIS 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-2008 by the GRASS Development Team
  7. This program is free software under the
  8. GNU General Public License (>=v2).
  9. Read the file COPYING that comes with GRASS
  10. for details.
  11. \author James Darrell McCauley <darrell mccauley-usa.com>, http://mccauley-usa.com/
  12. \date 1994
  13. */
  14. #include <string.h>
  15. #include <unistd.h>
  16. #include <math.h>
  17. #include <grass/gis.h>
  18. #include <grass/glocale.h>
  19. /* prototypes */
  20. static double raster_sample_nearest(int fd,
  21. const struct Cell_head *window,
  22. struct Categories *cats,
  23. double north, double east, int usedesc);
  24. static double raster_sample_bilinear(int fd,
  25. const struct Cell_head *window,
  26. struct Categories *cats,
  27. double north, double east, int usedesc);
  28. static double raster_sample_cubic(int fd,
  29. const struct Cell_head *window,
  30. struct Categories *cats,
  31. double north, double east, int usedesc);
  32. static double scancatlabel(const char *);
  33. static void raster_row_error(const struct Cell_head *window, double north,
  34. double east);
  35. /*!
  36. * \brief Extract a cell value from raster map.
  37. *
  38. * Extract a cell value from raster map at given northing and easting
  39. * with a sampled 3x3 window using a specified interpolation method.
  40. *
  41. * \param fd file descriptor
  42. * \param window region settings
  43. * \param cats categories
  44. * \param north northing position
  45. * \param east easting position
  46. * \param usedesc flag to scan category label
  47. * \param itype interpolation method
  48. *
  49. * \return cell value at given position
  50. */
  51. double G_get_raster_sample(int fd,
  52. const struct Cell_head *window,
  53. struct Categories *cats,
  54. double north, double east,
  55. int usedesc, INTERP_TYPE itype)
  56. {
  57. double retval;
  58. switch (itype) {
  59. case NEAREST:
  60. retval =
  61. raster_sample_nearest(fd, window, cats, north, east, usedesc);
  62. break;
  63. case BILINEAR:
  64. retval =
  65. raster_sample_bilinear(fd, window, cats, north, east, usedesc);
  66. break;
  67. case CUBIC:
  68. retval = raster_sample_cubic(fd, window, cats, north, east, usedesc);
  69. break;
  70. default:
  71. G_fatal_error("G_get_raster_sample: %s",
  72. _("Unknown interpolation type"));
  73. }
  74. return retval;
  75. }
  76. static double raster_sample_nearest(int fd,
  77. const struct Cell_head *window,
  78. struct Categories *cats,
  79. double north, double east, int usedesc)
  80. {
  81. int row, col;
  82. double predicted;
  83. DCELL *maprow = G_allocate_d_raster_buf();
  84. /* convert northing and easting to row and col, resp */
  85. row = (int)G_northing_to_row(north, window);
  86. col = (int)G_easting_to_col(east, window);
  87. if (G_get_d_raster_row(fd, maprow, row) < 0)
  88. raster_row_error(window, north, east);
  89. if (G_is_d_null_value(&(maprow[col]))) {
  90. predicted = 0.0;
  91. }
  92. else if (usedesc) {
  93. char *buf = G_get_cat(maprow[col], cats);
  94. G_squeeze(buf);
  95. predicted = scancatlabel(buf);
  96. }
  97. else {
  98. predicted = maprow[col];
  99. }
  100. G_free(maprow);
  101. return predicted;
  102. }
  103. static double raster_sample_bilinear(int fd,
  104. const struct Cell_head *window,
  105. struct Categories *cats,
  106. double north, double east, int usedesc)
  107. {
  108. int i, row, col;
  109. double grid[2][2], tmp1, tmp2;
  110. DCELL *arow = G_allocate_d_raster_buf();
  111. DCELL *brow = G_allocate_d_raster_buf();
  112. /* convert northing and easting to row and col, resp */
  113. row = (int)G_northing_to_row(north, window);
  114. col = (int)G_easting_to_col(east, window);
  115. if (G_get_d_raster_row(fd, arow, row) < 0)
  116. raster_row_error(window, north, east);
  117. /*-
  118. * we need 2x2 pixels to do the interpolation. First we decide if we
  119. * need the previous or next map row
  120. */
  121. if (row == 0) {
  122. /* arow is at top, must get row below */
  123. if (G_get_d_raster_row(fd, brow, row + 1) < 0)
  124. raster_row_error(window, north, east);
  125. }
  126. else if (row + 1 == G_window_rows()) {
  127. /* amaprow is at bottom, get the one above it */
  128. /* brow = arow; */
  129. for (i = 0; i < G_window_cols(); ++i)
  130. brow[i] = arow[i];
  131. row--;
  132. if (G_get_d_raster_row(fd, arow, row) < 0)
  133. raster_row_error(window, north, east);
  134. }
  135. else if (north - G_row_to_northing((double)row + 0.5, window) > 0) {
  136. /* north is above a horizontal centerline going through arow */
  137. /* brow = arow; */
  138. for (i = 0; i < G_window_cols(); ++i)
  139. brow[i] = arow[i];
  140. row--;
  141. if (G_get_d_raster_row(fd, arow, row) < 0)
  142. raster_row_error(window, north, east);
  143. }
  144. else {
  145. /* north is below a horizontal centerline going through arow */
  146. if (G_get_d_raster_row(fd, brow, row + 1) < 0)
  147. raster_row_error(window, north, east);
  148. }
  149. /*-
  150. * next, we decide if we need the column to the right or left of the
  151. * current column using a procedure similar to above
  152. */
  153. if (col + 1 == G_window_cols())
  154. col--;
  155. else if (east - G_col_to_easting((double)col + 0.5, window) < 0)
  156. col--;
  157. /*-
  158. * now were ready to do bilinear interpolation over
  159. * arow[col], arow[col+1],
  160. * brow[col], brow[col+1]
  161. */
  162. if (usedesc) {
  163. char *buf;
  164. G_squeeze(buf = G_get_cat((int)arow[col], cats));
  165. grid[0][0] = scancatlabel(buf);
  166. G_squeeze(buf = G_get_cat((int)arow[col + 1], cats));
  167. grid[0][1] = scancatlabel(buf);
  168. G_squeeze(buf = G_get_cat((int)brow[col], cats));
  169. grid[1][0] = scancatlabel(buf);
  170. G_squeeze(buf = G_get_cat((int)brow[col + 1], cats));
  171. grid[1][1] = scancatlabel(buf);
  172. }
  173. else {
  174. grid[0][0] = (double)arow[col];
  175. grid[0][1] = (double)arow[col + 1];
  176. grid[1][0] = (double)brow[col];
  177. grid[1][1] = (double)brow[col + 1];
  178. }
  179. /* Treat NULL's as zero */
  180. if (G_is_d_null_value(&(arow[col])))
  181. grid[0][0] = 0.0;
  182. if (G_is_d_null_value(&(arow[col + 1])))
  183. grid[0][1] = 0.0;
  184. if (G_is_d_null_value(&(brow[col])))
  185. grid[1][0] = 0.0;
  186. if (G_is_d_null_value(&(brow[col + 1])))
  187. grid[1][1] = 0.0;
  188. east = fabs(G_col_to_easting((double)col, window) - east);
  189. while (east > window->ew_res)
  190. east -= window->ew_res;
  191. north = fabs(G_row_to_northing((double)row, window) - north);
  192. while (north > window->ns_res)
  193. north -= window->ns_res;
  194. /* we do two linear interpolations along the rows */
  195. tmp1 = G_interp_linear(east / window->ew_res, grid[0][0], grid[0][1]);
  196. tmp2 = G_interp_linear(east / window->ew_res, grid[1][0], grid[1][1]);
  197. G_debug(3, "DIAG: r=%d c=%d t1=%g t2=%g\te=%g n=%g",
  198. row, col, tmp1, tmp2, east, north);
  199. G_debug(3, "DIAG: %g %g\n %g %g",
  200. grid[0][0], grid[0][1], grid[1][0], grid[1][1]);
  201. /*-
  202. * Now we interpolate along a line parallel to columns
  203. * and passing through easting
  204. */
  205. G_free(arow);
  206. G_free(brow);
  207. return G_interp_linear(north / window->ns_res, tmp1, tmp2);
  208. }
  209. static double raster_sample_cubic(int fd,
  210. const struct Cell_head *window,
  211. struct Categories *cats,
  212. double north, double east, int usedesc)
  213. {
  214. int i, row, col;
  215. double grid[4][4], tmp[4];
  216. DCELL *arow = G_allocate_d_raster_buf();
  217. DCELL *brow = G_allocate_d_raster_buf();
  218. DCELL *crow = G_allocate_d_raster_buf();
  219. DCELL *drow = G_allocate_d_raster_buf();
  220. /* convert northing and easting to row and col, resp */
  221. row = G_northing_to_row(north, window);
  222. col = G_easting_to_col(east, window);
  223. if (G_get_d_raster_row(fd, arow, row) < 0)
  224. raster_row_error(window, north, east);
  225. /* we need 4x4 pixels to do the interpolation. */
  226. if (row == 0) {
  227. /* row containing sample is at top, must get three rows below */
  228. if (G_get_d_raster_row(fd, brow, row + 1) < 0)
  229. raster_row_error(window, north, east);
  230. if (G_get_d_raster_row(fd, crow, row + 2) < 0)
  231. raster_row_error(window, north, east);
  232. if (G_get_d_raster_row(fd, drow, row + 3) < 0)
  233. raster_row_error(window, north, east);
  234. }
  235. else if (row == 1) {
  236. /* must get row above and tow rows below */
  237. for (i = 0; i < G_window_cols(); ++i)
  238. brow[i] = arow[i];
  239. if (G_get_d_raster_row(fd, arow, row - 1) < 0)
  240. raster_row_error(window, north, east);
  241. if (G_get_d_raster_row(fd, crow, row + 1) < 0)
  242. raster_row_error(window, north, east);
  243. if (G_get_d_raster_row(fd, drow, row + 2) < 0)
  244. raster_row_error(window, north, east);
  245. row--;
  246. }
  247. else if (row + 1 == G_window_rows()) {
  248. /* arow is at bottom, get the three above it */
  249. for (i = 0; i < G_window_cols(); ++i)
  250. drow[i] = arow[i];
  251. if (G_get_d_raster_row(fd, arow, row - 3) < 0)
  252. raster_row_error(window, north, east);
  253. if (G_get_d_raster_row(fd, brow, row - 2) < 0)
  254. raster_row_error(window, north, east);
  255. if (G_get_d_raster_row(fd, crow, row - 1) < 0)
  256. raster_row_error(window, north, east);
  257. row -= 3;
  258. }
  259. else if (row + 2 == G_window_rows()) {
  260. /* arow is next to bottom, get the one below and two above it */
  261. for (i = 0; i < G_window_cols(); ++i)
  262. crow[i] = arow[i];
  263. if (G_get_d_raster_row(fd, arow, row - 2) < 0)
  264. raster_row_error(window, north, east);
  265. if (G_get_d_raster_row(fd, brow, row - 1) < 0)
  266. raster_row_error(window, north, east);
  267. if (G_get_d_raster_row(fd, drow, row + 1) < 0)
  268. raster_row_error(window, north, east);
  269. row -= 2;
  270. }
  271. else if (north - G_row_to_northing((double)row + 0.5, window) > 0) {
  272. /*
  273. * north is above a horizontal centerline going through arow. need two
  274. * above and one below
  275. */
  276. for (i = 0; i < G_window_cols(); ++i)
  277. crow[i] = arow[i];
  278. if (G_get_d_raster_row(fd, arow, row - 2) < 0)
  279. raster_row_error(window, north, east);
  280. if (G_get_d_raster_row(fd, brow, row - 1) < 0)
  281. raster_row_error(window, north, east);
  282. if (G_get_d_raster_row(fd, drow, row + 1) < 0)
  283. raster_row_error(window, north, east);
  284. row -= 2;
  285. }
  286. else {
  287. /*
  288. * north is below a horizontal centerline going through arow need one
  289. * above and two below
  290. */
  291. for (i = 0; i < G_window_cols(); ++i)
  292. brow[i] = arow[i];
  293. if (G_get_d_raster_row(fd, arow, row - 1) < 0)
  294. raster_row_error(window, north, east);
  295. if (G_get_d_raster_row(fd, crow, row + 1) < 0)
  296. raster_row_error(window, north, east);
  297. if (G_get_d_raster_row(fd, drow, row + 2) < 0)
  298. raster_row_error(window, north, east);
  299. row--;
  300. }
  301. /*
  302. * Next, we decide if we need columns to the right and/or left of the
  303. * current column using a procedure similar to above
  304. */
  305. if (col == 0 || col == 1)
  306. col = 0;
  307. else if (col + 1 == G_window_cols())
  308. col -= 3;
  309. else if (col + 2 == G_window_cols())
  310. col -= 2;
  311. else if (east - G_col_to_easting((double)col + 0.5, window) < 0)
  312. /* east is left of center */
  313. col -= 2;
  314. else
  315. col--;
  316. /*
  317. * now were ready to do cubic interpolation over
  318. * arow[col], arow[col+1], arow[col+2], arow[col+3],
  319. * brow[col], brow[col+1], brow[col+2], brow[col+3],
  320. * crow[col], crow[col+1], crow[col+2], crow[col+3],
  321. * drow[col], drow[col+1], drow[col+2], drow[col+3],
  322. */
  323. if (usedesc) {
  324. char *buf;
  325. for (i = 0; i < 4; ++i) {
  326. G_squeeze(buf = G_get_cat(arow[col + i], cats));
  327. grid[0][i] = scancatlabel(buf);
  328. G_squeeze(buf = G_get_cat(brow[col + i], cats));
  329. grid[1][i] = scancatlabel(buf);
  330. G_squeeze(buf = G_get_cat(crow[col + i], cats));
  331. grid[2][i] = scancatlabel(buf);
  332. G_squeeze(buf = G_get_cat(drow[col + i], cats));
  333. grid[3][i] = scancatlabel(buf);
  334. }
  335. }
  336. else {
  337. for (i = 0; i < 4; ++i) {
  338. grid[0][i] = (double)arow[col + i];
  339. grid[1][i] = (double)brow[col + i];
  340. grid[2][i] = (double)crow[col + i];
  341. grid[3][i] = (double)drow[col + i];
  342. }
  343. }
  344. /* Treat NULL cells as 0.0 */
  345. for (i = 0; i < 4; i++) {
  346. if (G_is_d_null_value(&(arow[col + i])))
  347. grid[0][i] = 0.0;
  348. if (G_is_d_null_value(&(brow[col + i])))
  349. grid[1][i] = 0.0;
  350. if (G_is_d_null_value(&(crow[col + i])))
  351. grid[2][i] = 0.0;
  352. if (G_is_d_null_value(&(drow[col + i])))
  353. grid[3][i] = 0.0;
  354. }
  355. /* this needs work here */
  356. east = fabs(G_col_to_easting((double)col + 1, window) - east);
  357. while (east > window->ew_res)
  358. east -= window->ew_res;
  359. east /= window->ew_res;
  360. north = fabs(G_row_to_northing((double)row + 1, window) - north);
  361. while (north > window->ns_res)
  362. north -= window->ns_res;
  363. north /= window->ns_res;
  364. /* we do four cubic convolutions along the rows */
  365. for (i = 0; i < 4; ++i)
  366. tmp[i] =
  367. G_interp_cubic(east, grid[i][0], grid[i][1], grid[i][2],
  368. grid[i][3]);
  369. G_debug(3,
  370. "raster_sample_cubic(): DIAG: (%d,%d) 1=%3.2g 2=%3.2g 3=%3.2g 4=%3.2g\te=%g n=%g",
  371. row, col, tmp[0], tmp[1], tmp[2], tmp[3], east, north);
  372. G_free(arow);
  373. G_free(brow);
  374. G_free(crow);
  375. G_free(drow);
  376. /* user horner's method again for the final interpolation */
  377. return G_interp_cubic(north, tmp[0], tmp[1], tmp[2], tmp[3]);
  378. }
  379. static double scancatlabel(const char *str)
  380. {
  381. double val;
  382. if (strcmp(str, "no data") != 0)
  383. sscanf(str, "%lf", &val);
  384. else {
  385. G_warning(_("\"no data\" label found; setting to zero"));
  386. val = 0.0;
  387. }
  388. return val;
  389. }
  390. static void raster_row_error(const struct Cell_head *window, double north,
  391. double east)
  392. {
  393. G_debug(3, "DIAG: \tRegion is: n=%g s=%g e=%g w=%g",
  394. window->north, window->south, window->east, window->west);
  395. G_debug(3, " \tData point is north=%g east=%g", north, east);
  396. G_fatal_error(_("Problem reading raster map"));
  397. }