dist.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. #include <math.h>
  2. #include <grass/gis.h>
  3. #include "pi.h"
  4. /* distance from point to point along a geodesic
  5. * code from
  6. * Paul D. Thomas
  7. * "Spheroidal Geodesics, Reference Systems, and Local Geometry"
  8. * U.S. Naval Oceanographic Office, p. 162
  9. * Engineering Library 526.3 T36s
  10. */
  11. /* a corruption of geodist.c library module of GRASS, used to enhance
  12. execution efficiency of interpolation routine */
  13. static double boa;
  14. static double f;
  15. static double ff64;
  16. static double al;
  17. static double t1r, t2r;
  18. #define DIST_PARAMS struct dist_params
  19. DIST_PARAMS {
  20. short targetrow; /* interpolation row for which params apply */
  21. double t1, t2, t3, t4;
  22. };
  23. static DIST_PARAMS *lat_params, *nextcalc;
  24. /* must be called once to establish the ellipsoid */
  25. int G_begin_geodesic_distance_l(short nrows, double a, double e2)
  26. {
  27. int i;
  28. al = a;
  29. boa = sqrt(1 - e2);
  30. f = 1 - boa;
  31. ff64 = f * f / 64;
  32. /* initialize lat_params array and indicate no prior data storage */
  33. lat_params = (DIST_PARAMS *) G_calloc(nrows, sizeof(DIST_PARAMS));
  34. for (i = 0, nextcalc = lat_params; i < nrows; i++, nextcalc++)
  35. nextcalc->targetrow = -1;
  36. return 0;
  37. }
  38. double LL_set_geodesic_distance_lat(double lat)
  39. {
  40. return (atan(boa * tan(Radians(lat))));
  41. }
  42. double set_sdlmr(double lon_diff)
  43. {
  44. return (sin(Radians(lon_diff) / 2));
  45. }
  46. /* must be called first */
  47. int LL_set_geodesic_distance(double *rowlook, /* preprocessed latitude data by row */
  48. int unk, int data /* row (y) of interpolation target, data value */
  49. )
  50. {
  51. double stm, ctm, sdtm, cdtm;
  52. double tm, dtm;
  53. double temp;
  54. t1r = *(rowlook + unk);
  55. t2r = *(rowlook + data);
  56. tm = (t1r + t2r) / 2;
  57. dtm = (t2r - t1r) / 2;
  58. stm = sin(tm);
  59. ctm = cos(tm);
  60. sdtm = sin(dtm);
  61. cdtm = cos(dtm);
  62. nextcalc = lat_params + data;
  63. if (nextcalc->targetrow != unk) { /* reset latitude offset parameters */
  64. temp = stm * cdtm;
  65. nextcalc->t1 = temp * temp * 2;
  66. temp = sdtm * ctm;
  67. nextcalc->t2 = temp * temp * 2;
  68. nextcalc->t3 = sdtm * sdtm;
  69. nextcalc->t4 = cdtm * cdtm - stm * stm;
  70. nextcalc->targetrow = unk; /* parameterization tagged to row */
  71. }
  72. return 0;
  73. }
  74. double LL_geodesic_distance(double sdlmr)
  75. {
  76. double a, cd, d, e, q, sd, t, u, v, x, y;
  77. /* special case - shapiro */
  78. if (sdlmr == 0.0 && t1r == t2r)
  79. return 0.0;
  80. q = nextcalc->t3 + sdlmr * sdlmr * nextcalc->t4;
  81. /* special case - shapiro */
  82. if (q == 1.0)
  83. return PI * al;
  84. cd = 1 - 2 * q; /* ill-conditioned subtraction for small q */
  85. /* mod starts here */
  86. sd = 2 * sqrt(q - q * q); /* sd^2 = 1 - cd^2 */
  87. if (q != 0.0 && cd == 1.0) /* test for small q */
  88. t = 1.0;
  89. else if (sd == 0.0)
  90. t = 1.0;
  91. else
  92. t = acos(cd) / sd; /* don't know how to fix acos(1-2*q) yet */
  93. /* mod ends here */
  94. u = nextcalc->t1 / (1 - q);
  95. v = nextcalc->t2 / q;
  96. d = 4 * t * t;
  97. x = u + v;
  98. e = -2 * cd;
  99. y = u - v;
  100. a = -d * e;
  101. return (al * sd *
  102. (t - f / 4 * (t * x - y) +
  103. ff64 * (x * (a + (t - (a + e) / 2) * x) + y * (-2 * d + e * y)
  104. + d * x * y)
  105. )
  106. );
  107. }
  108. int free_dist_params(void)
  109. {
  110. G_free(lat_params);
  111. return 0;
  112. }