do_proj.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. /**
  2. \file do_proj.c
  3. \brief GProj library - Functions for re-projecting point data
  4. \author Original Author unknown, probably Soil Conservation Service
  5. Eric Miller, Paul Kelly
  6. (C) 2003-2008 by the GRASS Development Team
  7. This program is free software under the GNU General Public
  8. License (>=v2). Read the file COPYING that comes with GRASS
  9. for details.
  10. **/
  11. #include <stdio.h>
  12. #include <string.h>
  13. #include <ctype.h>
  14. #include <grass/gis.h>
  15. #include <grass/gprojects.h>
  16. #include <grass/glocale.h>
  17. /* a couple defines to simplify reading the function */
  18. #define MULTIPLY_LOOP(x,y,c,m) \
  19. do {\
  20. int i; \
  21. for (i = 0; i < c; ++i) {\
  22. x[i] *= m; \
  23. y[i] *= m; \
  24. }\
  25. } while (0)
  26. #define DIVIDE_LOOP(x,y,c,m) \
  27. do {\
  28. int i; \
  29. for (i = 0; i < c; ++i) {\
  30. x[i] /= m; \
  31. y[i] /= m; \
  32. }\
  33. } while (0)
  34. static double METERS_in = 1.0, METERS_out = 1.0;
  35. /**
  36. * \brief Re-project a point between two co-ordinate systems
  37. *
  38. * This function takes pointers to two pj_info structures as arguments,
  39. * and projects a point between the co-ordinate systems represented by them.
  40. * The easting and northing of the point are contained in two pointers passed
  41. * to the function; these will be overwritten by the co-ordinates of the
  42. * re-projected point.
  43. *
  44. * \param x Pointer to a double containing easting or longitude
  45. * \param y Pointer to a double containing northing or latitude
  46. * \param info_in pointer to pj_info struct for input co-ordinate system
  47. * \param info_out pointer to pj_info struct for output co-ordinate system
  48. *
  49. * \return Return value from PROJ pj_transform() function
  50. **/
  51. int pj_do_proj(double *x, double *y,
  52. const struct pj_info *info_in, const struct pj_info *info_out)
  53. {
  54. int ok;
  55. double u, v;
  56. double h = 0.0;
  57. METERS_in = info_in->meters;
  58. METERS_out = info_out->meters;
  59. if (strncmp(info_in->proj, "ll", 2) == 0) {
  60. if (strncmp(info_out->proj, "ll", 2) == 0) {
  61. u = (*x) / RAD_TO_DEG;
  62. v = (*y) / RAD_TO_DEG;
  63. ok = pj_transform(info_in->pj, info_out->pj, 1, 0, &u, &v, &h);
  64. *x = u * RAD_TO_DEG;
  65. *y = v * RAD_TO_DEG;
  66. }
  67. else {
  68. u = (*x) / RAD_TO_DEG;
  69. v = (*y) / RAD_TO_DEG;
  70. ok = pj_transform(info_in->pj, info_out->pj, 1, 0, &u, &v, &h);
  71. *x = u / METERS_out;
  72. *y = v / METERS_out;
  73. }
  74. }
  75. else {
  76. if (strncmp(info_out->proj, "ll", 2) == 0) {
  77. u = *x * METERS_in;
  78. v = *y * METERS_in;
  79. ok = pj_transform(info_in->pj, info_out->pj, 1, 0, &u, &v, &h);
  80. *x = u * RAD_TO_DEG;
  81. *y = v * RAD_TO_DEG;
  82. }
  83. else {
  84. u = *x * METERS_in;
  85. v = *y * METERS_in;
  86. ok = pj_transform(info_in->pj, info_out->pj, 1, 0, &u, &v, &h);
  87. *x = u / METERS_out;
  88. *y = v / METERS_out;
  89. }
  90. }
  91. if (ok < 0) {
  92. G_warning(_("pj_transform() failed: %s"), pj_strerrno(ok));
  93. }
  94. return ok;
  95. }
  96. /**
  97. * \brief Re-project an array of points between two co-ordinate systems with
  98. * optional ellipsoidal height conversion
  99. *
  100. * This function takes pointers to two pj_info structures as arguments,
  101. * and projects an array of points between the co-ordinate systems
  102. * represented by them. Pointers to the three arrays of easting, northing,
  103. * and ellipsoidal height of the point (this one may be NULL) are passed
  104. * to the function; these will be overwritten by the co-ordinates of the
  105. * re-projected points.
  106. *
  107. * \param count Number of points in the arrays to be transformed
  108. * \param x Pointer to an array of type double containing easting or longitude
  109. * \param y Pointer to an array of type double containing northing or latitude
  110. * \param h Pointer to an array of type double containing ellipsoidal height.
  111. * May be null in which case a two-dimensional re-projection will be
  112. * done
  113. * \param info_in pointer to pj_info struct for input co-ordinate system
  114. * \param info_out pointer to pj_info struct for output co-ordinate system
  115. *
  116. * \return Return value from PROJ pj_transform() function
  117. **/
  118. int pj_do_transform(int count, double *x, double *y, double *h,
  119. const struct pj_info *info_in, const struct pj_info *info_out)
  120. {
  121. int ok;
  122. int has_h = 1;
  123. METERS_in = info_in->meters;
  124. METERS_out = info_out->meters;
  125. if (h == NULL) {
  126. int i;
  127. h = G_malloc(sizeof *h * count);
  128. /* they say memset is only guaranteed for chars ;-( */
  129. for (i = 0; i < count; ++i)
  130. h[i] = 0.0;
  131. has_h = 0;
  132. }
  133. if (strncmp(info_in->proj, "ll", 2) == 0) {
  134. if (strncmp(info_out->proj, "ll", 2) == 0) {
  135. DIVIDE_LOOP(x, y, count, RAD_TO_DEG);
  136. ok = pj_transform(info_in->pj, info_out->pj, count, 1, x, y, h);
  137. MULTIPLY_LOOP(x, y, count, RAD_TO_DEG);
  138. }
  139. else {
  140. DIVIDE_LOOP(x, y, count, RAD_TO_DEG);
  141. ok = pj_transform(info_in->pj, info_out->pj, count, 1, x, y, h);
  142. DIVIDE_LOOP(x, y, count, METERS_out);
  143. }
  144. }
  145. else {
  146. if (strncmp(info_out->proj, "ll", 2) == 0) {
  147. MULTIPLY_LOOP(x, y, count, METERS_in);
  148. ok = pj_transform(info_in->pj, info_out->pj, count, 1, x, y, h);
  149. MULTIPLY_LOOP(x, y, count, RAD_TO_DEG);
  150. }
  151. else {
  152. MULTIPLY_LOOP(x, y, count, METERS_in);
  153. ok = pj_transform(info_in->pj, info_out->pj, count, 1, x, y, h);
  154. DIVIDE_LOOP(x, y, count, METERS_out);
  155. }
  156. }
  157. if (!has_h)
  158. G_free(h);
  159. if (ok < 0) {
  160. G_warning(_("pj_transform() failed: %s"), pj_strerrno(ok));
  161. }
  162. return ok;
  163. }