nzmg.js 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. import {SEC_TO_RAD} from '../constants/values';
  2. /*
  3. reference
  4. Department of Land and Survey Technical Circular 1973/32
  5. http://www.linz.govt.nz/docs/miscellaneous/nz-map-definition.pdf
  6. OSG Technical Report 4.1
  7. http://www.linz.govt.nz/docs/miscellaneous/nzmg.pdf
  8. */
  9. /**
  10. * iterations: Number of iterations to refine inverse transform.
  11. * 0 -> km accuracy
  12. * 1 -> m accuracy -- suitable for most mapping applications
  13. * 2 -> mm accuracy
  14. */
  15. export var iterations = 1;
  16. export function init() {
  17. this.A = [];
  18. this.A[1] = 0.6399175073;
  19. this.A[2] = -0.1358797613;
  20. this.A[3] = 0.063294409;
  21. this.A[4] = -0.02526853;
  22. this.A[5] = 0.0117879;
  23. this.A[6] = -0.0055161;
  24. this.A[7] = 0.0026906;
  25. this.A[8] = -0.001333;
  26. this.A[9] = 0.00067;
  27. this.A[10] = -0.00034;
  28. this.B_re = [];
  29. this.B_im = [];
  30. this.B_re[1] = 0.7557853228;
  31. this.B_im[1] = 0;
  32. this.B_re[2] = 0.249204646;
  33. this.B_im[2] = 0.003371507;
  34. this.B_re[3] = -0.001541739;
  35. this.B_im[3] = 0.041058560;
  36. this.B_re[4] = -0.10162907;
  37. this.B_im[4] = 0.01727609;
  38. this.B_re[5] = -0.26623489;
  39. this.B_im[5] = -0.36249218;
  40. this.B_re[6] = -0.6870983;
  41. this.B_im[6] = -1.1651967;
  42. this.C_re = [];
  43. this.C_im = [];
  44. this.C_re[1] = 1.3231270439;
  45. this.C_im[1] = 0;
  46. this.C_re[2] = -0.577245789;
  47. this.C_im[2] = -0.007809598;
  48. this.C_re[3] = 0.508307513;
  49. this.C_im[3] = -0.112208952;
  50. this.C_re[4] = -0.15094762;
  51. this.C_im[4] = 0.18200602;
  52. this.C_re[5] = 1.01418179;
  53. this.C_im[5] = 1.64497696;
  54. this.C_re[6] = 1.9660549;
  55. this.C_im[6] = 2.5127645;
  56. this.D = [];
  57. this.D[1] = 1.5627014243;
  58. this.D[2] = 0.5185406398;
  59. this.D[3] = -0.03333098;
  60. this.D[4] = -0.1052906;
  61. this.D[5] = -0.0368594;
  62. this.D[6] = 0.007317;
  63. this.D[7] = 0.01220;
  64. this.D[8] = 0.00394;
  65. this.D[9] = -0.0013;
  66. }
  67. /**
  68. New Zealand Map Grid Forward - long/lat to x/y
  69. long/lat in radians
  70. */
  71. export function forward(p) {
  72. var n;
  73. var lon = p.x;
  74. var lat = p.y;
  75. var delta_lat = lat - this.lat0;
  76. var delta_lon = lon - this.long0;
  77. // 1. Calculate d_phi and d_psi ... // and d_lambda
  78. // For this algorithm, delta_latitude is in seconds of arc x 10-5, so we need to scale to those units. Longitude is radians.
  79. var d_phi = delta_lat / SEC_TO_RAD * 1E-5;
  80. var d_lambda = delta_lon;
  81. var d_phi_n = 1; // d_phi^0
  82. var d_psi = 0;
  83. for (n = 1; n <= 10; n++) {
  84. d_phi_n = d_phi_n * d_phi;
  85. d_psi = d_psi + this.A[n] * d_phi_n;
  86. }
  87. // 2. Calculate theta
  88. var th_re = d_psi;
  89. var th_im = d_lambda;
  90. // 3. Calculate z
  91. var th_n_re = 1;
  92. var th_n_im = 0; // theta^0
  93. var th_n_re1;
  94. var th_n_im1;
  95. var z_re = 0;
  96. var z_im = 0;
  97. for (n = 1; n <= 6; n++) {
  98. th_n_re1 = th_n_re * th_re - th_n_im * th_im;
  99. th_n_im1 = th_n_im * th_re + th_n_re * th_im;
  100. th_n_re = th_n_re1;
  101. th_n_im = th_n_im1;
  102. z_re = z_re + this.B_re[n] * th_n_re - this.B_im[n] * th_n_im;
  103. z_im = z_im + this.B_im[n] * th_n_re + this.B_re[n] * th_n_im;
  104. }
  105. // 4. Calculate easting and northing
  106. p.x = (z_im * this.a) + this.x0;
  107. p.y = (z_re * this.a) + this.y0;
  108. return p;
  109. }
  110. /**
  111. New Zealand Map Grid Inverse - x/y to long/lat
  112. */
  113. export function inverse(p) {
  114. var n;
  115. var x = p.x;
  116. var y = p.y;
  117. var delta_x = x - this.x0;
  118. var delta_y = y - this.y0;
  119. // 1. Calculate z
  120. var z_re = delta_y / this.a;
  121. var z_im = delta_x / this.a;
  122. // 2a. Calculate theta - first approximation gives km accuracy
  123. var z_n_re = 1;
  124. var z_n_im = 0; // z^0
  125. var z_n_re1;
  126. var z_n_im1;
  127. var th_re = 0;
  128. var th_im = 0;
  129. for (n = 1; n <= 6; n++) {
  130. z_n_re1 = z_n_re * z_re - z_n_im * z_im;
  131. z_n_im1 = z_n_im * z_re + z_n_re * z_im;
  132. z_n_re = z_n_re1;
  133. z_n_im = z_n_im1;
  134. th_re = th_re + this.C_re[n] * z_n_re - this.C_im[n] * z_n_im;
  135. th_im = th_im + this.C_im[n] * z_n_re + this.C_re[n] * z_n_im;
  136. }
  137. // 2b. Iterate to refine the accuracy of the calculation
  138. // 0 iterations gives km accuracy
  139. // 1 iteration gives m accuracy -- good enough for most mapping applications
  140. // 2 iterations bives mm accuracy
  141. for (var i = 0; i < this.iterations; i++) {
  142. var th_n_re = th_re;
  143. var th_n_im = th_im;
  144. var th_n_re1;
  145. var th_n_im1;
  146. var num_re = z_re;
  147. var num_im = z_im;
  148. for (n = 2; n <= 6; n++) {
  149. th_n_re1 = th_n_re * th_re - th_n_im * th_im;
  150. th_n_im1 = th_n_im * th_re + th_n_re * th_im;
  151. th_n_re = th_n_re1;
  152. th_n_im = th_n_im1;
  153. num_re = num_re + (n - 1) * (this.B_re[n] * th_n_re - this.B_im[n] * th_n_im);
  154. num_im = num_im + (n - 1) * (this.B_im[n] * th_n_re + this.B_re[n] * th_n_im);
  155. }
  156. th_n_re = 1;
  157. th_n_im = 0;
  158. var den_re = this.B_re[1];
  159. var den_im = this.B_im[1];
  160. for (n = 2; n <= 6; n++) {
  161. th_n_re1 = th_n_re * th_re - th_n_im * th_im;
  162. th_n_im1 = th_n_im * th_re + th_n_re * th_im;
  163. th_n_re = th_n_re1;
  164. th_n_im = th_n_im1;
  165. den_re = den_re + n * (this.B_re[n] * th_n_re - this.B_im[n] * th_n_im);
  166. den_im = den_im + n * (this.B_im[n] * th_n_re + this.B_re[n] * th_n_im);
  167. }
  168. // Complex division
  169. var den2 = den_re * den_re + den_im * den_im;
  170. th_re = (num_re * den_re + num_im * den_im) / den2;
  171. th_im = (num_im * den_re - num_re * den_im) / den2;
  172. }
  173. // 3. Calculate d_phi ... // and d_lambda
  174. var d_psi = th_re;
  175. var d_lambda = th_im;
  176. var d_psi_n = 1; // d_psi^0
  177. var d_phi = 0;
  178. for (n = 1; n <= 9; n++) {
  179. d_psi_n = d_psi_n * d_psi;
  180. d_phi = d_phi + this.D[n] * d_psi_n;
  181. }
  182. // 4. Calculate latitude and longitude
  183. // d_phi is calcuated in second of arc * 10^-5, so we need to scale back to radians. d_lambda is in radians.
  184. var lat = this.lat0 + (d_phi * SEC_TO_RAD * 1E5);
  185. var lon = this.long0 + d_lambda;
  186. p.x = lon;
  187. p.y = lat;
  188. return p;
  189. }
  190. export var names = ["New_Zealand_Map_Grid", "nzmg"];
  191. export default {
  192. init: init,
  193. forward: forward,
  194. inverse: inverse,
  195. names: names
  196. };