geos.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. import hypot from '../common/hypot';
  2. export function init() {
  3. this.flip_axis = (this.sweep === 'x' ? 1 : 0);
  4. this.h = Number(this.h);
  5. this.radius_g_1 = this.h / this.a;
  6. if (this.radius_g_1 <= 0 || this.radius_g_1 > 1e10) {
  7. throw new Error();
  8. }
  9. this.radius_g = 1.0 + this.radius_g_1;
  10. this.C = this.radius_g * this.radius_g - 1.0;
  11. if (this.es !== 0.0) {
  12. var one_es = 1.0 - this.es;
  13. var rone_es = 1 / one_es;
  14. this.radius_p = Math.sqrt(one_es);
  15. this.radius_p2 = one_es;
  16. this.radius_p_inv2 = rone_es;
  17. this.shape = 'ellipse'; // Use as a condition in the forward and inverse functions.
  18. } else {
  19. this.radius_p = 1.0;
  20. this.radius_p2 = 1.0;
  21. this.radius_p_inv2 = 1.0;
  22. this.shape = 'sphere'; // Use as a condition in the forward and inverse functions.
  23. }
  24. if (!this.title) {
  25. this.title = "Geostationary Satellite View";
  26. }
  27. }
  28. function forward(p) {
  29. var lon = p.x;
  30. var lat = p.y;
  31. var tmp, v_x, v_y, v_z;
  32. lon = lon - this.long0;
  33. if (this.shape === 'ellipse') {
  34. lat = Math.atan(this.radius_p2 * Math.tan(lat));
  35. var r = this.radius_p / hypot(this.radius_p * Math.cos(lat), Math.sin(lat));
  36. v_x = r * Math.cos(lon) * Math.cos(lat);
  37. v_y = r * Math.sin(lon) * Math.cos(lat);
  38. v_z = r * Math.sin(lat);
  39. if (((this.radius_g - v_x) * v_x - v_y * v_y - v_z * v_z * this.radius_p_inv2) < 0.0) {
  40. p.x = Number.NaN;
  41. p.y = Number.NaN;
  42. return p;
  43. }
  44. tmp = this.radius_g - v_x;
  45. if (this.flip_axis) {
  46. p.x = this.radius_g_1 * Math.atan(v_y / hypot(v_z, tmp));
  47. p.y = this.radius_g_1 * Math.atan(v_z / tmp);
  48. } else {
  49. p.x = this.radius_g_1 * Math.atan(v_y / tmp);
  50. p.y = this.radius_g_1 * Math.atan(v_z / hypot(v_y, tmp));
  51. }
  52. } else if (this.shape === 'sphere') {
  53. tmp = Math.cos(lat);
  54. v_x = Math.cos(lon) * tmp;
  55. v_y = Math.sin(lon) * tmp;
  56. v_z = Math.sin(lat);
  57. tmp = this.radius_g - v_x;
  58. if (this.flip_axis) {
  59. p.x = this.radius_g_1 * Math.atan(v_y / hypot(v_z, tmp));
  60. p.y = this.radius_g_1 * Math.atan(v_z / tmp);
  61. } else {
  62. p.x = this.radius_g_1 * Math.atan(v_y / tmp);
  63. p.y = this.radius_g_1 * Math.atan(v_z / hypot(v_y, tmp));
  64. }
  65. }
  66. p.x = p.x * this.a;
  67. p.y = p.y * this.a;
  68. return p;
  69. }
  70. function inverse(p) {
  71. var v_x = -1.0;
  72. var v_y = 0.0;
  73. var v_z = 0.0;
  74. var a, b, det, k;
  75. p.x = p.x / this.a;
  76. p.y = p.y / this.a;
  77. if (this.shape === 'ellipse') {
  78. if (this.flip_axis) {
  79. v_z = Math.tan(p.y / this.radius_g_1);
  80. v_y = Math.tan(p.x / this.radius_g_1) * hypot(1.0, v_z);
  81. } else {
  82. v_y = Math.tan(p.x / this.radius_g_1);
  83. v_z = Math.tan(p.y / this.radius_g_1) * hypot(1.0, v_y);
  84. }
  85. var v_zp = v_z / this.radius_p;
  86. a = v_y * v_y + v_zp * v_zp + v_x * v_x;
  87. b = 2 * this.radius_g * v_x;
  88. det = (b * b) - 4 * a * this.C;
  89. if (det < 0.0) {
  90. p.x = Number.NaN;
  91. p.y = Number.NaN;
  92. return p;
  93. }
  94. k = (-b - Math.sqrt(det)) / (2.0 * a);
  95. v_x = this.radius_g + k * v_x;
  96. v_y *= k;
  97. v_z *= k;
  98. p.x = Math.atan2(v_y, v_x);
  99. p.y = Math.atan(v_z * Math.cos(p.x) / v_x);
  100. p.y = Math.atan(this.radius_p_inv2 * Math.tan(p.y));
  101. } else if (this.shape === 'sphere') {
  102. if (this.flip_axis) {
  103. v_z = Math.tan(p.y / this.radius_g_1);
  104. v_y = Math.tan(p.x / this.radius_g_1) * Math.sqrt(1.0 + v_z * v_z);
  105. } else {
  106. v_y = Math.tan(p.x / this.radius_g_1);
  107. v_z = Math.tan(p.y / this.radius_g_1) * Math.sqrt(1.0 + v_y * v_y);
  108. }
  109. a = v_y * v_y + v_z * v_z + v_x * v_x;
  110. b = 2 * this.radius_g * v_x;
  111. det = (b * b) - 4 * a * this.C;
  112. if (det < 0.0) {
  113. p.x = Number.NaN;
  114. p.y = Number.NaN;
  115. return p;
  116. }
  117. k = (-b - Math.sqrt(det)) / (2.0 * a);
  118. v_x = this.radius_g + k * v_x;
  119. v_y *= k;
  120. v_z *= k;
  121. p.x = Math.atan2(v_y, v_x);
  122. p.y = Math.atan(v_z * Math.cos(p.x) / v_x);
  123. }
  124. p.x = p.x + this.long0;
  125. return p;
  126. }
  127. export var names = ["Geostationary Satellite View", "Geostationary_Satellite", "geos"];
  128. export default {
  129. init: init,
  130. forward: forward,
  131. inverse: inverse,
  132. names: names,
  133. };