datumUtils.js 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. 'use strict';
  2. import {PJD_3PARAM, PJD_7PARAM, HALF_PI} from './constants/values';
  3. export function compareDatums(source, dest) {
  4. if (source.datum_type !== dest.datum_type) {
  5. return false; // false, datums are not equal
  6. } else if (source.a !== dest.a || Math.abs(source.es - dest.es) > 0.000000000050) {
  7. // the tolerance for es is to ensure that GRS80 and WGS84
  8. // are considered identical
  9. return false;
  10. } else if (source.datum_type === PJD_3PARAM) {
  11. return (source.datum_params[0] === dest.datum_params[0] && source.datum_params[1] === dest.datum_params[1] && source.datum_params[2] === dest.datum_params[2]);
  12. } else if (source.datum_type === PJD_7PARAM) {
  13. return (source.datum_params[0] === dest.datum_params[0] && source.datum_params[1] === dest.datum_params[1] && source.datum_params[2] === dest.datum_params[2] && source.datum_params[3] === dest.datum_params[3] && source.datum_params[4] === dest.datum_params[4] && source.datum_params[5] === dest.datum_params[5] && source.datum_params[6] === dest.datum_params[6]);
  14. } else {
  15. return true; // datums are equal
  16. }
  17. } // cs_compare_datums()
  18. /*
  19. * The function Convert_Geodetic_To_Geocentric converts geodetic coordinates
  20. * (latitude, longitude, and height) to geocentric coordinates (X, Y, Z),
  21. * according to the current ellipsoid parameters.
  22. *
  23. * Latitude : Geodetic latitude in radians (input)
  24. * Longitude : Geodetic longitude in radians (input)
  25. * Height : Geodetic height, in meters (input)
  26. * X : Calculated Geocentric X coordinate, in meters (output)
  27. * Y : Calculated Geocentric Y coordinate, in meters (output)
  28. * Z : Calculated Geocentric Z coordinate, in meters (output)
  29. *
  30. */
  31. export function geodeticToGeocentric(p, es, a) {
  32. var Longitude = p.x;
  33. var Latitude = p.y;
  34. var Height = p.z ? p.z : 0; //Z value not always supplied
  35. var Rn; /* Earth radius at location */
  36. var Sin_Lat; /* Math.sin(Latitude) */
  37. var Sin2_Lat; /* Square of Math.sin(Latitude) */
  38. var Cos_Lat; /* Math.cos(Latitude) */
  39. /*
  40. ** Don't blow up if Latitude is just a little out of the value
  41. ** range as it may just be a rounding issue. Also removed longitude
  42. ** test, it should be wrapped by Math.cos() and Math.sin(). NFW for PROJ.4, Sep/2001.
  43. */
  44. if (Latitude < -HALF_PI && Latitude > -1.001 * HALF_PI) {
  45. Latitude = -HALF_PI;
  46. } else if (Latitude > HALF_PI && Latitude < 1.001 * HALF_PI) {
  47. Latitude = HALF_PI;
  48. } else if (Latitude < -HALF_PI) {
  49. /* Latitude out of range */
  50. //..reportError('geocent:lat out of range:' + Latitude);
  51. return { x: -Infinity, y: -Infinity, z: p.z };
  52. } else if (Latitude > HALF_PI) {
  53. /* Latitude out of range */
  54. return { x: Infinity, y: Infinity, z: p.z };
  55. }
  56. if (Longitude > Math.PI) {
  57. Longitude -= (2 * Math.PI);
  58. }
  59. Sin_Lat = Math.sin(Latitude);
  60. Cos_Lat = Math.cos(Latitude);
  61. Sin2_Lat = Sin_Lat * Sin_Lat;
  62. Rn = a / (Math.sqrt(1.0e0 - es * Sin2_Lat));
  63. return {
  64. x: (Rn + Height) * Cos_Lat * Math.cos(Longitude),
  65. y: (Rn + Height) * Cos_Lat * Math.sin(Longitude),
  66. z: ((Rn * (1 - es)) + Height) * Sin_Lat
  67. };
  68. } // cs_geodetic_to_geocentric()
  69. export function geocentricToGeodetic(p, es, a, b) {
  70. /* local defintions and variables */
  71. /* end-criterium of loop, accuracy of sin(Latitude) */
  72. var genau = 1e-12;
  73. var genau2 = (genau * genau);
  74. var maxiter = 30;
  75. var P; /* distance between semi-minor axis and location */
  76. var RR; /* distance between center and location */
  77. var CT; /* sin of geocentric latitude */
  78. var ST; /* cos of geocentric latitude */
  79. var RX;
  80. var RK;
  81. var RN; /* Earth radius at location */
  82. var CPHI0; /* cos of start or old geodetic latitude in iterations */
  83. var SPHI0; /* sin of start or old geodetic latitude in iterations */
  84. var CPHI; /* cos of searched geodetic latitude */
  85. var SPHI; /* sin of searched geodetic latitude */
  86. var SDPHI; /* end-criterium: addition-theorem of sin(Latitude(iter)-Latitude(iter-1)) */
  87. var iter; /* # of continous iteration, max. 30 is always enough (s.a.) */
  88. var X = p.x;
  89. var Y = p.y;
  90. var Z = p.z ? p.z : 0.0; //Z value not always supplied
  91. var Longitude;
  92. var Latitude;
  93. var Height;
  94. P = Math.sqrt(X * X + Y * Y);
  95. RR = Math.sqrt(X * X + Y * Y + Z * Z);
  96. /* special cases for latitude and longitude */
  97. if (P / a < genau) {
  98. /* special case, if P=0. (X=0., Y=0.) */
  99. Longitude = 0.0;
  100. /* if (X,Y,Z)=(0.,0.,0.) then Height becomes semi-minor axis
  101. * of ellipsoid (=center of mass), Latitude becomes PI/2 */
  102. if (RR / a < genau) {
  103. Latitude = HALF_PI;
  104. Height = -b;
  105. return {
  106. x: p.x,
  107. y: p.y,
  108. z: p.z
  109. };
  110. }
  111. } else {
  112. /* ellipsoidal (geodetic) longitude
  113. * interval: -PI < Longitude <= +PI */
  114. Longitude = Math.atan2(Y, X);
  115. }
  116. /* --------------------------------------------------------------
  117. * Following iterative algorithm was developped by
  118. * "Institut for Erdmessung", University of Hannover, July 1988.
  119. * Internet: www.ife.uni-hannover.de
  120. * Iterative computation of CPHI,SPHI and Height.
  121. * Iteration of CPHI and SPHI to 10**-12 radian resp.
  122. * 2*10**-7 arcsec.
  123. * --------------------------------------------------------------
  124. */
  125. CT = Z / RR;
  126. ST = P / RR;
  127. RX = 1.0 / Math.sqrt(1.0 - es * (2.0 - es) * ST * ST);
  128. CPHI0 = ST * (1.0 - es) * RX;
  129. SPHI0 = CT * RX;
  130. iter = 0;
  131. /* loop to find sin(Latitude) resp. Latitude
  132. * until |sin(Latitude(iter)-Latitude(iter-1))| < genau */
  133. do {
  134. iter++;
  135. RN = a / Math.sqrt(1.0 - es * SPHI0 * SPHI0);
  136. /* ellipsoidal (geodetic) height */
  137. Height = P * CPHI0 + Z * SPHI0 - RN * (1.0 - es * SPHI0 * SPHI0);
  138. RK = es * RN / (RN + Height);
  139. RX = 1.0 / Math.sqrt(1.0 - RK * (2.0 - RK) * ST * ST);
  140. CPHI = ST * (1.0 - RK) * RX;
  141. SPHI = CT * RX;
  142. SDPHI = SPHI * CPHI0 - CPHI * SPHI0;
  143. CPHI0 = CPHI;
  144. SPHI0 = SPHI;
  145. }
  146. while (SDPHI * SDPHI > genau2 && iter < maxiter);
  147. /* ellipsoidal (geodetic) latitude */
  148. Latitude = Math.atan(SPHI / Math.abs(CPHI));
  149. return {
  150. x: Longitude,
  151. y: Latitude,
  152. z: Height
  153. };
  154. } // cs_geocentric_to_geodetic()
  155. /****************************************************************/
  156. // pj_geocentic_to_wgs84( p )
  157. // p = point to transform in geocentric coordinates (x,y,z)
  158. /** point object, nothing fancy, just allows values to be
  159. passed back and forth by reference rather than by value.
  160. Other point classes may be used as long as they have
  161. x and y properties, which will get modified in the transform method.
  162. */
  163. export function geocentricToWgs84(p, datum_type, datum_params) {
  164. if (datum_type === PJD_3PARAM) {
  165. // if( x[io] === HUGE_VAL )
  166. // continue;
  167. return {
  168. x: p.x + datum_params[0],
  169. y: p.y + datum_params[1],
  170. z: p.z + datum_params[2],
  171. };
  172. } else if (datum_type === PJD_7PARAM) {
  173. var Dx_BF = datum_params[0];
  174. var Dy_BF = datum_params[1];
  175. var Dz_BF = datum_params[2];
  176. var Rx_BF = datum_params[3];
  177. var Ry_BF = datum_params[4];
  178. var Rz_BF = datum_params[5];
  179. var M_BF = datum_params[6];
  180. // if( x[io] === HUGE_VAL )
  181. // continue;
  182. return {
  183. x: M_BF * (p.x - Rz_BF * p.y + Ry_BF * p.z) + Dx_BF,
  184. y: M_BF * (Rz_BF * p.x + p.y - Rx_BF * p.z) + Dy_BF,
  185. z: M_BF * (-Ry_BF * p.x + Rx_BF * p.y + p.z) + Dz_BF
  186. };
  187. }
  188. } // cs_geocentric_to_wgs84
  189. /****************************************************************/
  190. // pj_geocentic_from_wgs84()
  191. // coordinate system definition,
  192. // point to transform in geocentric coordinates (x,y,z)
  193. export function geocentricFromWgs84(p, datum_type, datum_params) {
  194. if (datum_type === PJD_3PARAM) {
  195. //if( x[io] === HUGE_VAL )
  196. // continue;
  197. return {
  198. x: p.x - datum_params[0],
  199. y: p.y - datum_params[1],
  200. z: p.z - datum_params[2],
  201. };
  202. } else if (datum_type === PJD_7PARAM) {
  203. var Dx_BF = datum_params[0];
  204. var Dy_BF = datum_params[1];
  205. var Dz_BF = datum_params[2];
  206. var Rx_BF = datum_params[3];
  207. var Ry_BF = datum_params[4];
  208. var Rz_BF = datum_params[5];
  209. var M_BF = datum_params[6];
  210. var x_tmp = (p.x - Dx_BF) / M_BF;
  211. var y_tmp = (p.y - Dy_BF) / M_BF;
  212. var z_tmp = (p.z - Dz_BF) / M_BF;
  213. //if( x[io] === HUGE_VAL )
  214. // continue;
  215. return {
  216. x: x_tmp + Rz_BF * y_tmp - Ry_BF * z_tmp,
  217. y: -Rz_BF * x_tmp + y_tmp + Rx_BF * z_tmp,
  218. z: Ry_BF * x_tmp - Rx_BF * y_tmp + z_tmp
  219. };
  220. } //cs_geocentric_from_wgs84()
  221. }