adj_cellhd.c 11 KB

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