albers.c 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. #include <u.h>
  2. #include <libc.h>
  3. #include "map.h"
  4. /* For Albers formulas see Deetz and Adams "Elements of Map Projection", */
  5. /* USGS Special Publication No. 68, GPO 1921 */
  6. static double r0sq, r1sq, d2, n, den, sinb1, sinb2;
  7. static struct coord plat1, plat2;
  8. static southpole;
  9. static double num(double s)
  10. {
  11. if(d2==0)
  12. return(1);
  13. s = d2*s*s;
  14. return(1+s*(2./3+s*(3./5+s*(4./7+s*5./9))));
  15. }
  16. /* Albers projection for a spheroid, good only when N pole is fixed */
  17. static int
  18. Xspalbers(struct place *place, double *x, double *y)
  19. {
  20. double r = sqrt(r0sq-2*(1-d2)*place->nlat.s*num(place->nlat.s)/n);
  21. double t = n*place->wlon.l;
  22. *y = r*cos(t);
  23. *x = -r*sin(t);
  24. if(!southpole)
  25. *y = -*y;
  26. else
  27. *x = -*x;
  28. return(1);
  29. }
  30. /* lat1, lat2: std parallels; e2: squared eccentricity */
  31. static proj albinit(double lat1, double lat2, double e2)
  32. {
  33. double r1;
  34. double t;
  35. for(;;) {
  36. if(lat1 < -90)
  37. lat1 = -180 - lat1;
  38. if(lat2 > 90)
  39. lat2 = 180 - lat2;
  40. if(lat1 <= lat2)
  41. break;
  42. t = lat1; lat1 = lat2; lat2 = t;
  43. }
  44. if(lat2-lat1 < 1) {
  45. if(lat1 > 89)
  46. return(azequalarea());
  47. return(0);
  48. }
  49. if(fabs(lat2+lat1) < 1)
  50. return(cylequalarea(lat1));
  51. d2 = e2;
  52. den = num(1.);
  53. deg2rad(lat1,&plat1);
  54. deg2rad(lat2,&plat2);
  55. sinb1 = plat1.s*num(plat1.s)/den;
  56. sinb2 = plat2.s*num(plat2.s)/den;
  57. n = (plat1.c*plat1.c/(1-e2*plat1.s*plat1.s) -
  58. plat2.c*plat2.c/(1-e2*plat2.s*plat2.s)) /
  59. (2*(1-e2)*den*(sinb2-sinb1));
  60. r1 = plat1.c/(n*sqrt(1-e2*plat1.s*plat1.s));
  61. r1sq = r1*r1;
  62. r0sq = r1sq + 2*(1-e2)*den*sinb1/n;
  63. southpole = lat1<0 && plat2.c>plat1.c;
  64. return(Xspalbers);
  65. }
  66. proj
  67. sp_albers(double lat1, double lat2)
  68. {
  69. return(albinit(lat1,lat2,EC2));
  70. }
  71. proj
  72. albers(double lat1, double lat2)
  73. {
  74. return(albinit(lat1,lat2,0.));
  75. }
  76. static double scale = 1;
  77. static double twist = 0;
  78. void
  79. albscale(double x, double y, double lat, double lon)
  80. {
  81. struct place place;
  82. double alat, alon, x1,y1;
  83. scale = 1;
  84. twist = 0;
  85. invalb(x,y,&alat,&alon);
  86. twist = lon - alon;
  87. deg2rad(lat,&place.nlat);
  88. deg2rad(lon,&place.wlon);
  89. Xspalbers(&place,&x1,&y1);
  90. scale = sqrt((x1*x1+y1*y1)/(x*x+y*y));
  91. }
  92. void
  93. invalb(double x, double y, double *lat, double *lon)
  94. {
  95. int i;
  96. double sinb_den, sinp;
  97. x *= scale;
  98. y *= scale;
  99. *lon = atan2(-x,fabs(y))/(RAD*n) + twist;
  100. sinb_den = (r0sq - x*x - y*y)*n/(2*(1-d2));
  101. sinp = sinb_den;
  102. for(i=0; i<5; i++)
  103. sinp = sinb_den/num(sinp);
  104. *lat = asin(sinp)/RAD;
  105. }