adj_cellhd.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. /*!
  2. * \file gis/adj_cellhd.c
  3. *
  4. * \brief GIS Library - CELL header adjustment.
  5. *
  6. * (C) 2001-2009 by the 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 <grass/gis.h>
  14. #include <grass/glocale.h>
  15. /*!
  16. * \brief Adjust cell header.
  17. *
  18. * This function fills in missing parts of the input cell header (or
  19. * region). It also makes projection-specific adjustments. The
  20. * <i>cellhd</i> structure must have its <i>north, south, east,
  21. * west</i>, and <i>proj</i> fields set.
  22. *
  23. * If <i>row_flag</i> is true, then the north-south resolution is
  24. * computed from the number of <i>rows</i> in the <i>cellhd</i>
  25. * structure. Otherwise the number of <i>rows</i> is computed from the
  26. * north-south resolution in the structure, similarly for
  27. * <i>col_flag</i> and the number of columns and the east-west
  28. * resolution.
  29. *
  30. * <b>Note:</b> 3D values are not adjusted.
  31. *
  32. * \param[in,out] cellhd pointer to Cell_head structure
  33. * \param row_flag compute n-s resolution
  34. * \param col_flag compute e-w resolution
  35. */
  36. void G_adjust_Cell_head(struct Cell_head *cellhd, int row_flag, int col_flag)
  37. {
  38. if (!row_flag) {
  39. if (cellhd->ns_res <= 0)
  40. G_fatal_error(_("Illegal n-s resolution value"));
  41. }
  42. else {
  43. if (cellhd->rows <= 0)
  44. G_fatal_error(_("Illegal row value"));
  45. }
  46. if (!col_flag) {
  47. if (cellhd->ew_res <= 0)
  48. G_fatal_error(_("Illegal e-w resolution value"));
  49. }
  50. else {
  51. if (cellhd->cols <= 0)
  52. G_fatal_error(_("Illegal col value"));
  53. }
  54. /* for lat/lon, check north,south. force east larger than west */
  55. if (cellhd->proj == PROJECTION_LL) {
  56. double epsilon_ns, epsilon_ew;
  57. /* TODO: find good thresholds */
  58. epsilon_ns = 1. / cellhd->rows * 0.001;
  59. epsilon_ew = .000001; /* epsilon_ew calculation doesn't work due to cellhd->cols update/global wraparound below */
  60. G_debug(3, "G_adjust_Cell_head: epsilon_ns: %g, epsilon_ew: %g",
  61. epsilon_ns, epsilon_ew);
  62. /* TODO: once working, change below G_warning to G_debug */
  63. /* fix rounding problems if input map slightly exceeds the world definition -180 90 180 -90 */
  64. if (cellhd->north > 90.0) {
  65. if (((cellhd->north - 90.0) < epsilon_ns) &&
  66. ((cellhd->north - 90.0) > GRASS_EPSILON)) {
  67. G_warning(_("Fixing subtle input data rounding error of north boundary (%g>%g)"),
  68. cellhd->north - 90.0, epsilon_ns);
  69. cellhd->north = 90.0;
  70. }
  71. else
  72. G_fatal_error(_("Illegal latitude for North"));
  73. }
  74. if (cellhd->south < -90.0) {
  75. if (((cellhd->south + 90.0) < epsilon_ns) &&
  76. ((cellhd->south + 90.0) < GRASS_EPSILON)) {
  77. G_warning(_("Fixing subtle input data rounding error of south boundary (%g>%g)"),
  78. cellhd->south + 90.0, epsilon_ns);
  79. cellhd->south = -90.0;
  80. }
  81. else
  82. G_fatal_error(_("Illegal latitude for South"));
  83. }
  84. #if 0
  85. /* DISABLED: this breaks global wrap-around */
  86. G_debug(3,
  87. "G_adjust_Cell_head() cellhd->west: %f, devi: %g, eps: %g",
  88. cellhd->west, cellhd->west + 180.0, epsilon_ew);
  89. if ((cellhd->west < -180.0) && ((cellhd->west + 180.0) < epsilon_ew)
  90. && ((cellhd->west + 180.0) < GRASS_EPSILON)) {
  91. G_warning(_("Fixing subtle input data rounding error of west boundary (%g>%g)"),
  92. cellhd->west + 180.0, epsilon_ew);
  93. cellhd->west = -180.0;
  94. }
  95. G_debug(3,
  96. "G_adjust_Cell_head() cellhd->east: %f, devi: %g, eps: %g",
  97. cellhd->east, cellhd->east - 180.0, epsilon_ew);
  98. if ((cellhd->east > 180.0) && ((cellhd->east - 180.0) > epsilon_ew)
  99. && ((cellhd->east - 180.0) > GRASS_EPSILON)) {
  100. G_warning(_("Fixing subtle input data rounding error of east boundary (%g>%g)"),
  101. cellhd->east - 180.0, epsilon_ew);
  102. cellhd->east = 180.0;
  103. }
  104. #endif
  105. while (cellhd->east <= cellhd->west)
  106. cellhd->east += 360.0;
  107. }
  108. /* check the edge values */
  109. if (cellhd->north <= cellhd->south) {
  110. if (cellhd->proj == PROJECTION_LL)
  111. G_fatal_error(_("North must be north of South"));
  112. else
  113. G_fatal_error(_("North must be larger than South"));
  114. }
  115. if (cellhd->east <= cellhd->west)
  116. G_fatal_error(_("East must be larger than West"));
  117. /* compute rows and columns, if not set */
  118. if (!row_flag) {
  119. cellhd->rows =
  120. (cellhd->north - cellhd->south +
  121. cellhd->ns_res / 2.0) / cellhd->ns_res;
  122. if (cellhd->rows == 0)
  123. cellhd->rows = 1;
  124. }
  125. if (!col_flag) {
  126. cellhd->cols =
  127. (cellhd->east - cellhd->west +
  128. cellhd->ew_res / 2.0) / cellhd->ew_res;
  129. if (cellhd->cols == 0)
  130. cellhd->cols = 1;
  131. }
  132. if (cellhd->cols < 0 || cellhd->rows < 0) {
  133. G_fatal_error(_("Invalid coordinates"));
  134. }
  135. /* (re)compute the resolutions */
  136. cellhd->ns_res = (cellhd->north - cellhd->south) / cellhd->rows;
  137. cellhd->ew_res = (cellhd->east - cellhd->west) / cellhd->cols;
  138. }
  139. /*!
  140. * \brief Adjust cell header for 3D values.
  141. *
  142. * This function fills in missing parts of the input cell header (or
  143. * region). It also makes projection-specific adjustments. The
  144. * <i>cellhd</i> structure must have its <i>north, south, east,
  145. * west</i>, and <i>proj</i> fields set.
  146. *
  147. * If <i>row_flag</i> is true, then the north-south resolution is computed
  148. * from the number of <i>rows</i> in the <i>cellhd</i> structure.
  149. * Otherwise the number of <i>rows</i> is computed from the north-south
  150. * resolution in the structure, similarly for <i>col_flag</i> and the
  151. * number of columns and the east-west resolution.
  152. *
  153. * If <i>depth_flag</i> is true, top-bottom resolution is calculated
  154. * from depths.
  155. * If <i>depth_flag</i> are false, number of depths is calculated from
  156. * top-bottom resolution.
  157. *
  158. * \warning This function can cause segmentation fault without any warning
  159. * when it is called with Cell_head top and bottom set to zero.
  160. *
  161. * \param[in,out] cellhd pointer to Cell_head structure
  162. * \param row_flag compute n-s resolution
  163. * \param col_flag compute e-w resolution
  164. * \param depth_flag compute t-b resolution
  165. */
  166. void G_adjust_Cell_head3(struct Cell_head *cellhd, int row_flag,
  167. int col_flag, int depth_flag)
  168. {
  169. if (!row_flag) {
  170. if (cellhd->ns_res <= 0)
  171. G_fatal_error(_("Illegal n-s resolution value"));
  172. if (cellhd->ns_res3 <= 0)
  173. G_fatal_error(_("Illegal n-s3 resolution value"));
  174. }
  175. else {
  176. if (cellhd->rows <= 0)
  177. G_fatal_error(_("Illegal row value"));
  178. if (cellhd->rows3 <= 0)
  179. G_fatal_error(_("Illegal row3 value"));
  180. }
  181. if (!col_flag) {
  182. if (cellhd->ew_res <= 0)
  183. G_fatal_error(_("Illegal e-w resolution value"));
  184. if (cellhd->ew_res3 <= 0)
  185. G_fatal_error(_("Illegal e-w3 resolution value"));
  186. }
  187. else {
  188. if (cellhd->cols <= 0)
  189. G_fatal_error(_("Illegal col value"));
  190. if (cellhd->cols3 <= 0)
  191. G_fatal_error(_("Illegal col3 value"));
  192. }
  193. if (!depth_flag) {
  194. if (cellhd->tb_res <= 0)
  195. G_fatal_error(_("Illegal t-b3 resolution value"));
  196. }
  197. else {
  198. if (cellhd->depths <= 0)
  199. G_fatal_error(_("Illegal depths value"));
  200. }
  201. /* for lat/lon, check north,south. force east larger than west */
  202. if (cellhd->proj == PROJECTION_LL) {
  203. double epsilon_ns, epsilon_ew;
  204. /* TODO: find good thresholds */
  205. epsilon_ns = 1. / cellhd->rows * 0.001;
  206. epsilon_ew = .000001; /* epsilon_ew calculation doesn't work due to cellhd->cols update/global wraparound below */
  207. G_debug(3, "G_adjust_Cell_head: epsilon_ns: %g, epsilon_ew: %g",
  208. epsilon_ns, epsilon_ew);
  209. /* TODO: once working, change below G_warning to G_debug */
  210. /* fix rounding problems if input map slightly exceeds the world definition -180 90 180 -90 */
  211. if (cellhd->north > 90.0) {
  212. if (((cellhd->north - 90.0) < epsilon_ns) &&
  213. ((cellhd->north - 90.0) > GRASS_EPSILON)) {
  214. G_warning(_("Fixing subtle input data rounding error of north boundary (%g>%g)"),
  215. cellhd->north - 90.0, epsilon_ns);
  216. cellhd->north = 90.0;
  217. }
  218. else
  219. G_fatal_error(_("Illegal latitude for North"));
  220. }
  221. if (cellhd->south < -90.0) {
  222. if (((cellhd->south + 90.0) < epsilon_ns) &&
  223. ((cellhd->south + 90.0) < GRASS_EPSILON)) {
  224. G_warning(_("Fixing subtle input data rounding error of south boundary (%g>%g)"),
  225. cellhd->south + 90.0, epsilon_ns);
  226. cellhd->south = -90.0;
  227. }
  228. else
  229. G_fatal_error(_("Illegal latitude for South"));
  230. }
  231. #if 0
  232. /* DISABLED: this breaks global wrap-around */
  233. G_debug(3,
  234. "G_adjust_Cell_head3() cellhd->west: %f, devi: %g, eps: %g",
  235. cellhd->west, cellhd->west + 180.0, epsilon_ew);
  236. if ((cellhd->west < -180.0) && ((cellhd->west + 180.0) < epsilon_ew)
  237. && ((cellhd->west + 180.0) < GRASS_EPSILON)) {
  238. G_warning(_("Fixing subtle input data rounding error of west boundary (%g>%g)"),
  239. cellhd->west + 180.0, epsilon_ew);
  240. cellhd->west = -180.0;
  241. }
  242. G_debug(3,
  243. "G_adjust_Cell_head3() cellhd->east: %f, devi: %g, eps: %g",
  244. cellhd->east, cellhd->east - 180.0, epsilon_ew);
  245. if ((cellhd->east > 180.0) && ((cellhd->east - 180.0) > epsilon_ew)
  246. && ((cellhd->east - 180.0) > GRASS_EPSILON)) {
  247. G_warning(_("Fixing subtle input data rounding error of east boundary (%g>%g)"),
  248. cellhd->east - 180.0, epsilon_ew);
  249. cellhd->east = 180.0;
  250. }
  251. #endif
  252. while (cellhd->east <= cellhd->west)
  253. cellhd->east += 360.0;
  254. }
  255. /* check the edge values */
  256. if (cellhd->north <= cellhd->south) {
  257. if (cellhd->proj == PROJECTION_LL)
  258. G_fatal_error(_("North must be north of South"));
  259. else
  260. G_fatal_error(_("North must be larger than South"));
  261. }
  262. if (cellhd->east <= cellhd->west)
  263. G_fatal_error(_("East must be larger than West"));
  264. if (cellhd->top <= cellhd->bottom)
  265. G_fatal_error(_("Top must be larger than Bottom"));
  266. /* compute rows and columns, if not set */
  267. if (!row_flag) {
  268. cellhd->rows =
  269. (cellhd->north - cellhd->south +
  270. cellhd->ns_res / 2.0) / cellhd->ns_res;
  271. if (cellhd->rows == 0)
  272. cellhd->rows = 1;
  273. cellhd->rows3 =
  274. (cellhd->north - cellhd->south +
  275. cellhd->ns_res3 / 2.0) / cellhd->ns_res3;
  276. if (cellhd->rows3 == 0)
  277. cellhd->rows3 = 1;
  278. }
  279. if (!col_flag) {
  280. cellhd->cols =
  281. (cellhd->east - cellhd->west +
  282. cellhd->ew_res / 2.0) / cellhd->ew_res;
  283. if (cellhd->cols == 0)
  284. cellhd->cols = 1;
  285. cellhd->cols3 =
  286. (cellhd->east - cellhd->west +
  287. cellhd->ew_res3 / 2.0) / cellhd->ew_res3;
  288. if (cellhd->cols3 == 0)
  289. cellhd->cols3 = 1;
  290. }
  291. if (!depth_flag) {
  292. cellhd->depths =
  293. (cellhd->top - cellhd->bottom +
  294. cellhd->tb_res / 2.0) / cellhd->tb_res;
  295. if (cellhd->depths == 0)
  296. cellhd->depths = 1;
  297. }
  298. if (cellhd->cols < 0 || cellhd->rows < 0 || cellhd->cols3 < 0 ||
  299. cellhd->rows3 < 0 || cellhd->depths < 0) {
  300. G_fatal_error(_("Invalid coordinates"));
  301. }
  302. /* (re)compute the resolutions */
  303. cellhd->ns_res = (cellhd->north - cellhd->south) / cellhd->rows;
  304. cellhd->ns_res3 = (cellhd->north - cellhd->south) / cellhd->rows3;
  305. cellhd->ew_res = (cellhd->east - cellhd->west) / cellhd->cols;
  306. cellhd->ew_res3 = (cellhd->east - cellhd->west) / cellhd->cols3;
  307. cellhd->tb_res = (cellhd->top - cellhd->bottom) / cellhd->depths;
  308. }