bordwalk.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. /*
  2. * Function added to r.proj
  3. * GNU GPL by Morten Hulden <morten@untamo.net>, August 2000
  4. *
  5. * bordwalk.c - projects the border cell centers of a map or region
  6. * to check whether they are inside the borders of another map/region
  7. * in a different location, and adjusts the cell header so
  8. * only overlapping areas are included. The function is called by main,
  9. * first to project the output region into the input map and trim the
  10. * borders of this in order to get a smaller map, and faster and less hungry
  11. * memory allocation. Then main calls the function again, but reversed,
  12. * to project the input map on the output region, trimming this down to
  13. * the smallest possible rectangular region.
  14. *
  15. * Simply using corner and midpoints (original r.proj) will only work
  16. * between cylindrical projections. In other projections, though he input
  17. * map is always a rectangular area, the projected output can be of almost
  18. * any shape and its position can be rotated any way. It can even be a
  19. * discontinous area.
  20. *
  21. * In many projections, especially when large areas are displayed, the edges
  22. * of rectangular GRASS regions do not necessarily represent east, west, north
  23. * and south. Naming the region edges accordingly (as is regions and cellhd) can be
  24. * misleading. (Well, invite code readers/writers to make assumptions anyway. Don't
  25. * assume north is really direction north in this code ;)
  26. */
  27. #include <math.h>
  28. #include <stdio.h>
  29. #include <grass/gis.h>
  30. #include <grass/raster.h>
  31. #include <grass/gprojects.h>
  32. #include <grass/glocale.h>
  33. #include "r.proj.h"
  34. #ifdef MIN
  35. #undef MIN
  36. #endif
  37. #define MIN(a, b) (((a) < (b)) ? (a) : (b))
  38. #ifdef MAX
  39. #undef MAX
  40. #endif
  41. #define MAX(a, b) (((a) > (b)) ? (a) : (b))
  42. static void debug(const char *name, const struct Cell_head *hd)
  43. {
  44. G_debug(3, "%s: xmin: %f; xmax: %f; ymin: %f; ymax: %f",
  45. name, hd->west, hd->east, hd->south, hd->north);
  46. }
  47. static void update(struct Cell_head *to_hd, double hx, double hy)
  48. {
  49. to_hd->east = MAX(to_hd->east, hx);
  50. to_hd->west = MIN(to_hd->west, hx);
  51. to_hd->north = MAX(to_hd->north, hy);
  52. to_hd->south = MIN(to_hd->south, hy);
  53. }
  54. static void intersect(struct Cell_head *to_hd, const struct Cell_head *from_hd)
  55. {
  56. to_hd->east = MIN(to_hd->east, from_hd->east);
  57. to_hd->west = MAX(to_hd->west, from_hd->west);
  58. to_hd->north = MIN(to_hd->north, from_hd->north);
  59. to_hd->south = MAX(to_hd->south, from_hd->south);
  60. }
  61. static int inside(const struct Cell_head *ref_hd, double hx, double hy)
  62. {
  63. return
  64. (hx <= ref_hd->east) &&
  65. (hx >= ref_hd->west) &&
  66. (hy <= ref_hd->north) &&
  67. (hy >= ref_hd->south);
  68. }
  69. static void invert(struct Cell_head *cur_hd, const struct Cell_head *ref_hd,
  70. double epsilon)
  71. {
  72. cur_hd->east = ref_hd->west - epsilon;
  73. cur_hd->west = ref_hd->east + epsilon;
  74. cur_hd->north = ref_hd->south - epsilon;
  75. cur_hd->south = ref_hd->north + epsilon;
  76. }
  77. static void proj_update(const struct pj_info *from_pj, const struct pj_info *to_pj,
  78. struct Cell_head *to_hd, double hx, double hy)
  79. {
  80. if (pj_do_proj(&hx, &hy, from_pj, to_pj) < 0)
  81. return;
  82. update(to_hd, hx, hy);
  83. }
  84. void bordwalk1(const struct pj_info *from_pj, const struct pj_info *to_pj,
  85. const struct Cell_head *from_hd, struct Cell_head *to_hd)
  86. {
  87. double idx;
  88. /* Top */
  89. for (idx = from_hd->west + from_hd->ew_res / 2; idx < from_hd->east;
  90. idx += from_hd->ew_res)
  91. proj_update(from_pj, to_pj, to_hd, idx, from_hd->north - from_hd->ns_res / 2);
  92. debug("Top", to_hd);
  93. /* Right */
  94. for (idx = from_hd->north - from_hd->ns_res / 2; idx > from_hd->south;
  95. idx -= from_hd->ns_res)
  96. proj_update(from_pj, to_pj, to_hd, from_hd->east - from_hd->ew_res / 2, idx);
  97. debug("Right", to_hd);
  98. /* Bottom */
  99. for (idx = from_hd->east - from_hd->ew_res / 2; idx > from_hd->west;
  100. idx -= from_hd->ew_res)
  101. proj_update(from_pj, to_pj, to_hd, idx, from_hd->south + from_hd->ns_res / 2);
  102. debug("Bottom", to_hd);
  103. /* Left */
  104. for (idx = from_hd->south + from_hd->ns_res / 2; idx < from_hd->north;
  105. idx += from_hd->ns_res)
  106. proj_update(from_pj, to_pj, to_hd, from_hd->west + from_hd->ew_res / 2, idx);
  107. debug("Left", to_hd);
  108. }
  109. static int proj_inside(const struct pj_info *from_pj, const struct pj_info *to_pj,
  110. const struct Cell_head *ref_hd, double hx, double hy)
  111. {
  112. if (pj_do_proj(&hx, &hy, to_pj, from_pj) < 0)
  113. return 0;
  114. return inside(ref_hd, hx, hy);
  115. }
  116. static void reverse_check(const struct pj_info *from_pj, const struct pj_info *to_pj,
  117. const struct Cell_head *from_hd,
  118. const struct Cell_head *to_hd,
  119. struct Cell_head *cur_hd)
  120. {
  121. if (cur_hd->west > to_hd->west) {
  122. double hx = to_hd->west + to_hd->ew_res / 2;
  123. double hy = to_hd->south + (to_hd->north - to_hd->south) / 2;
  124. if (proj_inside(from_pj, to_pj, from_hd, hx, hy))
  125. cur_hd->west = hx;
  126. }
  127. if (cur_hd->east < to_hd->east) {
  128. double hx = to_hd->east - to_hd->ew_res / 2;
  129. double hy = to_hd->south + (to_hd->north - to_hd->south) / 2;
  130. if (proj_inside(from_pj, to_pj, from_hd, hx, hy))
  131. cur_hd->east = hx;
  132. }
  133. if (cur_hd->south > to_hd->south) {
  134. double hx = to_hd->west + (to_hd->east - to_hd->west) / 2;
  135. double hy = to_hd->south + to_hd->ns_res / 2;
  136. if (proj_inside(from_pj, to_pj, from_hd, hx, hy))
  137. cur_hd->south = hy;
  138. }
  139. if (cur_hd->north < to_hd->north) {
  140. double hx = to_hd->west + (to_hd->east - to_hd->west) / 2;
  141. double hy = to_hd->north - to_hd->ns_res / 2;
  142. if (proj_inside(from_pj, to_pj, from_hd, hx, hy))
  143. cur_hd->north = hy;
  144. }
  145. }
  146. static int outside(const struct Cell_head *cur_hd, const struct Cell_head *ref_hd)
  147. {
  148. return
  149. (cur_hd->west > ref_hd->east ) ||
  150. (cur_hd->east < ref_hd->west ) ||
  151. (cur_hd->south > ref_hd->north) ||
  152. (cur_hd->north < ref_hd->south);
  153. }
  154. static void snap_to_grid(struct Cell_head *cur_hd, const struct Cell_head *ref_hd)
  155. {
  156. int lidx = (int) floor(Rast_easting_to_col( cur_hd->west, ref_hd));
  157. int ridx = (int) floor(Rast_easting_to_col( cur_hd->east, ref_hd));
  158. int bidx = (int) floor(Rast_northing_to_row(cur_hd->south, ref_hd));
  159. int tidx = (int) floor(Rast_northing_to_row(cur_hd->north, ref_hd));
  160. cur_hd->west = Rast_col_to_easting( lidx + 0.0, ref_hd);
  161. cur_hd->east = Rast_col_to_easting( ridx + 1.0, ref_hd);
  162. cur_hd->south = Rast_row_to_northing(bidx + 1.0, ref_hd);
  163. cur_hd->north = Rast_row_to_northing(tidx + 0.0, ref_hd);
  164. }
  165. void bordwalk(const struct Cell_head *from_hd, struct Cell_head *to_hd,
  166. const struct pj_info *from_pj, const struct pj_info *to_pj)
  167. {
  168. struct Cell_head cur_hd;
  169. /* Set some (un)reasonable defaults before we walk the borders */
  170. invert(&cur_hd, to_hd, 1.0e-6);
  171. /* Start walking */
  172. bordwalk1(from_pj, to_pj, from_hd, &cur_hd);
  173. intersect(&cur_hd, to_hd);
  174. /* check some special cases by reversing the projection */
  175. reverse_check(from_pj, to_pj, from_hd, to_hd, &cur_hd);
  176. debug("Extra check", &cur_hd);
  177. /* if we still have some unresonable default minmax left, then abort */
  178. if (outside(&cur_hd, to_hd))
  179. G_fatal_error(_("Input raster map is outside current region"));
  180. intersect(&cur_hd, to_hd);
  181. /* adjust to edges */
  182. snap_to_grid(&cur_hd, to_hd);
  183. intersect(to_hd, &cur_hd);
  184. debug("Final check", to_hd);
  185. }
  186. void bordwalk2(const struct Cell_head *from_hd, struct Cell_head *to_hd,
  187. const struct pj_info *from_pj, const struct pj_info *to_pj)
  188. {
  189. bordwalk1(from_pj, to_pj, from_hd, to_hd);
  190. }