adj_cellhd.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. /**
  2. * \file adj_cellhd.c
  3. *
  4. * \brief GIS Library - CELL header adjustment.
  5. *
  6. * (C) 2001-2008 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 GRASS GIS Development Team
  12. *
  13. * \date 1999-2008
  14. */
  15. #include <grass/gis.h>
  16. #include <grass/glocale.h>
  17. /**
  18. * \brief Adjust cell header.
  19. *
  20. * This function fills in missing parts of the input
  21. * cell header (or region). It also makes projection-specific adjustments. The
  22. * <b>cellhd</b> structure must have its <i>north, south, east, west</i>,
  23. * and <i>proj</i> fields set.
  24. *
  25. * If <b>row_flag</b> is true, then the north-south resolution is computed
  26. * from the number of <i>rows</i> in the <b>cellhd</b> structure. Otherwise the number of
  27. * <i>rows</i> is computed from the north-south resolution in the structure, similarly for
  28. * <b>col_flag</b> and the number of columns and the east-west resolution.
  29. *
  30. * <b>Note:</b> 3D values are not adjusted.
  31. *
  32. * \param[in,out] cellhd
  33. * \param[in] row_flag
  34. * \param[in] col_flag
  35. * \return NULL on success
  36. * \return Localized text string on error
  37. */
  38. 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
  146. * cell header (or region). It also makes projection-specific adjustments. The
  147. * <b>cellhd</b> structure must have its <i>north, south, east, west</i>,
  148. * and <i>proj</i> fields set.
  149. *
  150. * If <b>row_flag</b> is true, then the north-south resolution is computed
  151. * from the number of <i>rows</i> in the <b>cellhd</b> structure.
  152. * Otherwise the number of <i>rows</i> is computed from the north-south
  153. * resolution in the structure, similarly for <b>col_flag</b> and the
  154. * number of columns and the east-west resolution.
  155. *
  156. * If <b>depth_flag</b> is true, top-bottom resolution is calculated
  157. * from depths.
  158. * If <b>depth_flag</b> are false, number of depths is calculated from
  159. * top-bottom resolution.
  160. *
  161. * \param[in,out] cellhd
  162. * \param[in] row_flag
  163. * \param[in] col_flag
  164. * \param[in] depth_flag
  165. * \return NULL on success
  166. * \return Localized text string on error
  167. */
  168. char *G_adjust_Cell_head3(struct Cell_head *cellhd, int row_flag,
  169. int col_flag, int depth_flag)
  170. {
  171. if (!row_flag) {
  172. if (cellhd->ns_res <= 0)
  173. return (_("Illegal n-s resolution value"));
  174. if (cellhd->ns_res3 <= 0)
  175. return (_("Illegal n-s3 resolution value"));
  176. }
  177. else {
  178. if (cellhd->rows <= 0)
  179. return (_("Illegal row value"));
  180. if (cellhd->rows3 <= 0)
  181. return (_("Illegal row3 value"));
  182. }
  183. if (!col_flag) {
  184. if (cellhd->ew_res <= 0)
  185. return (_("Illegal e-w resolution value"));
  186. if (cellhd->ew_res3 <= 0)
  187. return (_("Illegal e-w3 resolution value"));
  188. }
  189. else {
  190. if (cellhd->cols <= 0)
  191. return (_("Illegal col value"));
  192. if (cellhd->cols3 <= 0)
  193. return (_("Illegal col3 value"));
  194. }
  195. if (!depth_flag) {
  196. if (cellhd->tb_res <= 0)
  197. return (_("Illegal t-b3 resolution value"));
  198. }
  199. else {
  200. if (cellhd->depths <= 0)
  201. return (_("Illegal depths value"));
  202. }
  203. /* for lat/lon, check north,south. force east larger than west */
  204. if (cellhd->proj == PROJECTION_LL) {
  205. double epsilon_ns, epsilon_ew;
  206. /* TODO: find good thresholds */
  207. epsilon_ns = 1. / cellhd->rows * 0.001;
  208. epsilon_ew = .000001; /* epsilon_ew calculation doesn't work due to cellhd->cols update/global wraparound below */
  209. G_debug(3, "G_adjust_Cell_head: epsilon_ns: %g, epsilon_ew: %g",
  210. epsilon_ns, epsilon_ew);
  211. /* TODO: once working, change below G_warning to G_debug */
  212. /* fix rounding problems if input map slightly exceeds the world definition -180 90 180 -90 */
  213. if (cellhd->north > 90.0) {
  214. if (((cellhd->north - 90.0) < epsilon_ns) &&
  215. ((cellhd->north - 90.0) > GRASS_EPSILON)) {
  216. G_warning(_("Fixing subtle input data rounding error of north boundary (%g>%g)"),
  217. cellhd->north - 90.0, epsilon_ns);
  218. cellhd->north = 90.0;
  219. }
  220. else
  221. return (_("Illegal latitude for North"));
  222. }
  223. if (cellhd->south < -90.0) {
  224. if (((cellhd->south + 90.0) < epsilon_ns) &&
  225. ((cellhd->south + 90.0) < GRASS_EPSILON)) {
  226. G_warning(_("Fixing subtle input data rounding error of south boundary (%g>%g)"),
  227. cellhd->south + 90.0, epsilon_ns);
  228. cellhd->south = -90.0;
  229. }
  230. else
  231. return (_("Illegal latitude for South"));
  232. }
  233. #if 0
  234. /* DISABLED: this breaks global wrap-around */
  235. G_debug(3,
  236. "G_adjust_Cell_head3() cellhd->west: %f, devi: %g, eps: %g",
  237. cellhd->west, cellhd->west + 180.0, epsilon_ew);
  238. if ((cellhd->west < -180.0) && ((cellhd->west + 180.0) < epsilon_ew)
  239. && ((cellhd->west + 180.0) < GRASS_EPSILON)) {
  240. G_warning(_("Fixing subtle input data rounding error of west boundary (%g>%g)"),
  241. cellhd->west + 180.0, epsilon_ew);
  242. cellhd->west = -180.0;
  243. }
  244. G_debug(3,
  245. "G_adjust_Cell_head3() cellhd->east: %f, devi: %g, eps: %g",
  246. cellhd->east, cellhd->east - 180.0, epsilon_ew);
  247. if ((cellhd->east > 180.0) && ((cellhd->east - 180.0) > epsilon_ew)
  248. && ((cellhd->east - 180.0) > GRASS_EPSILON)) {
  249. G_warning(_("Fixing subtle input data rounding error of east boundary (%g>%g)"),
  250. cellhd->east - 180.0, epsilon_ew);
  251. cellhd->east = 180.0;
  252. }
  253. #endif
  254. while (cellhd->east <= cellhd->west)
  255. cellhd->east += 360.0;
  256. }
  257. /* check the edge values */
  258. if (cellhd->north <= cellhd->south) {
  259. if (cellhd->proj == PROJECTION_LL)
  260. return (_("North must be north of South"));
  261. else
  262. return (_("North must be larger than South"));
  263. }
  264. if (cellhd->east <= cellhd->west)
  265. return (_("East must be larger than West"));
  266. if (cellhd->top <= cellhd->bottom)
  267. return (_("Top must be larger than Bottom"));
  268. /* compute rows and columns, if not set */
  269. if (!row_flag) {
  270. cellhd->rows =
  271. (cellhd->north - cellhd->south +
  272. cellhd->ns_res / 2.0) / cellhd->ns_res;
  273. if (cellhd->rows == 0)
  274. cellhd->rows = 1;
  275. cellhd->rows3 =
  276. (cellhd->north - cellhd->south +
  277. cellhd->ns_res3 / 2.0) / cellhd->ns_res3;
  278. if (cellhd->rows3 == 0)
  279. cellhd->rows3 = 1;
  280. }
  281. if (!col_flag) {
  282. cellhd->cols =
  283. (cellhd->east - cellhd->west +
  284. cellhd->ew_res / 2.0) / cellhd->ew_res;
  285. if (cellhd->cols == 0)
  286. cellhd->cols = 1;
  287. cellhd->cols3 =
  288. (cellhd->east - cellhd->west +
  289. cellhd->ew_res3 / 2.0) / cellhd->ew_res3;
  290. if (cellhd->cols3 == 0)
  291. cellhd->cols3 = 1;
  292. }
  293. if (!depth_flag) {
  294. cellhd->depths =
  295. (cellhd->top - cellhd->bottom +
  296. cellhd->tb_res / 2.0) / cellhd->tb_res;
  297. if (cellhd->depths == 0)
  298. cellhd->depths = 1;
  299. }
  300. if (cellhd->cols < 0 || cellhd->rows < 0 || cellhd->cols3 < 0 ||
  301. cellhd->rows3 < 0 || cellhd->depths < 0) {
  302. return (_("Invalid coordinates"));
  303. }
  304. /* (re)compute the resolutions */
  305. cellhd->ns_res = (cellhd->north - cellhd->south) / cellhd->rows;
  306. cellhd->ns_res3 = (cellhd->north - cellhd->south) / cellhd->rows3;
  307. cellhd->ew_res = (cellhd->east - cellhd->west) / cellhd->cols;
  308. cellhd->ew_res3 = (cellhd->east - cellhd->west) / cellhd->cols3;
  309. cellhd->tb_res = (cellhd->top - cellhd->bottom) / cellhd->depths;
  310. return NULL;
  311. }