omerc.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. var tsfnz = require('../common/tsfnz');
  2. var adjust_lon = require('../common/adjust_lon');
  3. var phi2z = require('../common/phi2z');
  4. var HALF_PI = Math.PI/2;
  5. var FORTPI = Math.PI/4;
  6. var EPSLN = 1.0e-10;
  7. /* Initialize the Oblique Mercator projection
  8. ------------------------------------------*/
  9. exports.init = function() {
  10. this.no_off = this.no_off || false;
  11. this.no_rot = this.no_rot || false;
  12. if (isNaN(this.k0)) {
  13. this.k0 = 1;
  14. }
  15. var sinlat = Math.sin(this.lat0);
  16. var coslat = Math.cos(this.lat0);
  17. var con = this.e * sinlat;
  18. this.bl = Math.sqrt(1 + this.es / (1 - this.es) * Math.pow(coslat, 4));
  19. this.al = this.a * this.bl * this.k0 * Math.sqrt(1 - this.es) / (1 - con * con);
  20. var t0 = tsfnz(this.e, this.lat0, sinlat);
  21. var dl = this.bl / coslat * Math.sqrt((1 - this.es) / (1 - con * con));
  22. if (dl * dl < 1) {
  23. dl = 1;
  24. }
  25. var fl;
  26. var gl;
  27. if (!isNaN(this.longc)) {
  28. //Central point and azimuth method
  29. if (this.lat0 >= 0) {
  30. fl = dl + Math.sqrt(dl * dl - 1);
  31. }
  32. else {
  33. fl = dl - Math.sqrt(dl * dl - 1);
  34. }
  35. this.el = fl * Math.pow(t0, this.bl);
  36. gl = 0.5 * (fl - 1 / fl);
  37. this.gamma0 = Math.asin(Math.sin(this.alpha) / dl);
  38. this.long0 = this.longc - Math.asin(gl * Math.tan(this.gamma0)) / this.bl;
  39. }
  40. else {
  41. //2 points method
  42. var t1 = tsfnz(this.e, this.lat1, Math.sin(this.lat1));
  43. var t2 = tsfnz(this.e, this.lat2, Math.sin(this.lat2));
  44. if (this.lat0 >= 0) {
  45. this.el = (dl + Math.sqrt(dl * dl - 1)) * Math.pow(t0, this.bl);
  46. }
  47. else {
  48. this.el = (dl - Math.sqrt(dl * dl - 1)) * Math.pow(t0, this.bl);
  49. }
  50. var hl = Math.pow(t1, this.bl);
  51. var ll = Math.pow(t2, this.bl);
  52. fl = this.el / hl;
  53. gl = 0.5 * (fl - 1 / fl);
  54. var jl = (this.el * this.el - ll * hl) / (this.el * this.el + ll * hl);
  55. var pl = (ll - hl) / (ll + hl);
  56. var dlon12 = adjust_lon(this.long1 - this.long2);
  57. this.long0 = 0.5 * (this.long1 + this.long2) - Math.atan(jl * Math.tan(0.5 * this.bl * (dlon12)) / pl) / this.bl;
  58. this.long0 = adjust_lon(this.long0);
  59. var dlon10 = adjust_lon(this.long1 - this.long0);
  60. this.gamma0 = Math.atan(Math.sin(this.bl * (dlon10)) / gl);
  61. this.alpha = Math.asin(dl * Math.sin(this.gamma0));
  62. }
  63. if (this.no_off) {
  64. this.uc = 0;
  65. }
  66. else {
  67. if (this.lat0 >= 0) {
  68. this.uc = this.al / this.bl * Math.atan2(Math.sqrt(dl * dl - 1), Math.cos(this.alpha));
  69. }
  70. else {
  71. this.uc = -1 * this.al / this.bl * Math.atan2(Math.sqrt(dl * dl - 1), Math.cos(this.alpha));
  72. }
  73. }
  74. };
  75. /* Oblique Mercator forward equations--mapping lat,long to x,y
  76. ----------------------------------------------------------*/
  77. exports.forward = function(p) {
  78. var lon = p.x;
  79. var lat = p.y;
  80. var dlon = adjust_lon(lon - this.long0);
  81. var us, vs;
  82. var con;
  83. if (Math.abs(Math.abs(lat) - HALF_PI) <= EPSLN) {
  84. if (lat > 0) {
  85. con = -1;
  86. }
  87. else {
  88. con = 1;
  89. }
  90. vs = this.al / this.bl * Math.log(Math.tan(FORTPI + con * this.gamma0 * 0.5));
  91. us = -1 * con * HALF_PI * this.al / this.bl;
  92. }
  93. else {
  94. var t = tsfnz(this.e, lat, Math.sin(lat));
  95. var ql = this.el / Math.pow(t, this.bl);
  96. var sl = 0.5 * (ql - 1 / ql);
  97. var tl = 0.5 * (ql + 1 / ql);
  98. var vl = Math.sin(this.bl * (dlon));
  99. var ul = (sl * Math.sin(this.gamma0) - vl * Math.cos(this.gamma0)) / tl;
  100. if (Math.abs(Math.abs(ul) - 1) <= EPSLN) {
  101. vs = Number.POSITIVE_INFINITY;
  102. }
  103. else {
  104. vs = 0.5 * this.al * Math.log((1 - ul) / (1 + ul)) / this.bl;
  105. }
  106. if (Math.abs(Math.cos(this.bl * (dlon))) <= EPSLN) {
  107. us = this.al * this.bl * (dlon);
  108. }
  109. else {
  110. us = this.al * Math.atan2(sl * Math.cos(this.gamma0) + vl * Math.sin(this.gamma0), Math.cos(this.bl * dlon)) / this.bl;
  111. }
  112. }
  113. if (this.no_rot) {
  114. p.x = this.x0 + us;
  115. p.y = this.y0 + vs;
  116. }
  117. else {
  118. us -= this.uc;
  119. p.x = this.x0 + vs * Math.cos(this.alpha) + us * Math.sin(this.alpha);
  120. p.y = this.y0 + us * Math.cos(this.alpha) - vs * Math.sin(this.alpha);
  121. }
  122. return p;
  123. };
  124. exports.inverse = function(p) {
  125. var us, vs;
  126. if (this.no_rot) {
  127. vs = p.y - this.y0;
  128. us = p.x - this.x0;
  129. }
  130. else {
  131. vs = (p.x - this.x0) * Math.cos(this.alpha) - (p.y - this.y0) * Math.sin(this.alpha);
  132. us = (p.y - this.y0) * Math.cos(this.alpha) + (p.x - this.x0) * Math.sin(this.alpha);
  133. us += this.uc;
  134. }
  135. var qp = Math.exp(-1 * this.bl * vs / this.al);
  136. var sp = 0.5 * (qp - 1 / qp);
  137. var tp = 0.5 * (qp + 1 / qp);
  138. var vp = Math.sin(this.bl * us / this.al);
  139. var up = (vp * Math.cos(this.gamma0) + sp * Math.sin(this.gamma0)) / tp;
  140. var ts = Math.pow(this.el / Math.sqrt((1 + up) / (1 - up)), 1 / this.bl);
  141. if (Math.abs(up - 1) < EPSLN) {
  142. p.x = this.long0;
  143. p.y = HALF_PI;
  144. }
  145. else if (Math.abs(up + 1) < EPSLN) {
  146. p.x = this.long0;
  147. p.y = -1 * HALF_PI;
  148. }
  149. else {
  150. p.y = phi2z(this.e, ts);
  151. p.x = adjust_lon(this.long0 - Math.atan2(sp * Math.cos(this.gamma0) - vp * Math.sin(this.gamma0), Math.cos(this.bl * us / this.al)) / this.bl);
  152. }
  153. return p;
  154. };
  155. exports.names = ["Hotine_Oblique_Mercator", "Hotine Oblique Mercator", "Hotine_Oblique_Mercator_Azimuth_Natural_Origin", "Hotine_Oblique_Mercator_Azimuth_Center", "omerc"];