You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

mtu.cpp 12 kB

2 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. #ifndef __COORCONV_H__
  2. #define __COORCONV_H__
  3. #include <cmath>
  4. double pi = 3.14159265358979;
  5. /* Ellipsoid model constants (actual values here are for WGS84) */
  6. double sm_a = 6378137.0;
  7. double sm_b = 6356752.314;
  8. double sm_EccSquared = 6.69437999013e-03;
  9. double UTMScaleFactor = 0.9996;
  10. typedef struct tagUTMCorr
  11. {
  12. double x;
  13. double y;
  14. }UTMCoor;
  15. typedef struct tagWGS84Corr
  16. {
  17. double lat;
  18. double log;
  19. }WGS84Corr;
  20. /*
  21. * DegToRad
  22. *
  23. * Converts degrees to radians.
  24. *
  25. */
  26. inline double DegToRad (double deg)
  27. {
  28. return (deg / 180.0 * pi);
  29. }
  30. /*
  31. * RadToDeg
  32. *
  33. * Converts radians to degrees.
  34. *
  35. */
  36. inline double RadToDeg (double rad)
  37. {
  38. return (rad / pi * 180.0);
  39. }
  40. /*
  41. * ArcLengthOfMeridian
  42. *
  43. * Computes the ellipsoidal distance from the equator to a point at a
  44. * given latitude.
  45. *
  46. * Reference: Hoffmann-Wellenhof, B., Lichtenegger, H., and Collins, J.,
  47. * GPS: Theory and Practice, 3rd ed. New York: Springer-Verlag Wien, 1994.
  48. *
  49. * Inputs:
  50. * phi - Latitude of the point, in radians.
  51. *
  52. * Globals:
  53. * sm_a - Ellipsoid model major axis.
  54. * sm_b - Ellipsoid model minor axis.
  55. *
  56. * Returns:
  57. * The ellipsoidal distance of the point from the equator, in meters.
  58. *
  59. */
  60. double ArcLengthOfMeridian (double phi)
  61. {
  62. double alpha, beta, gamma, delta, epsilon, n;
  63. double result;
  64. /* Precalculate n */
  65. n = (sm_a - sm_b) / (sm_a + sm_b);
  66. /* Precalculate alpha */
  67. alpha = ((sm_a + sm_b) / 2.0) * (1.0 + (pow(n, 2.0) / 4.0) + (pow(n, 4.0) / 64.0));
  68. /* Precalculate beta */
  69. beta = (-3.0 * n / 2.0) + (9.0 * pow(n, 3.0) / 16.0) + (-3.0 * pow(n, 5.0) / 32.0);
  70. /* Precalculate gamma */
  71. gamma = (15.0 * pow(n, 2.0) / 16.0) + (-15.0 * pow(n, 4.0) / 32.0);
  72. /* Precalculate delta */
  73. delta = (-35.0 * pow(n, 3.0) / 48.0) + (105.0 * pow(n, 5.0) / 256.0);
  74. /* Precalculate epsilon */
  75. epsilon = (315.0 * pow(n, 4.0) / 512.0);
  76. /* Now calculate the sum of the series and return */
  77. result = alpha * (phi + (beta * sin(2.0 * phi)) + (gamma * sin(4.0 * phi)) + (delta * sin(6.0 * phi)) + (epsilon * sin(8.0 * phi)));
  78. return result;
  79. }
  80. /*
  81. * UTMCentralMeridian
  82. *
  83. * Determines the central meridian for the given UTM zone.
  84. *
  85. * Inputs:
  86. * zone - An integer value designating the UTM zone, range [1,60].
  87. *
  88. * Returns:
  89. * The central meridian for the given UTM zone, in radians, or zero
  90. * if the UTM zone parameter is outside the range [1,60].
  91. * Range of the central meridian is the radian equivalent of [-177,+177].
  92. *
  93. */
  94. inline double UTMCentralMeridian (int zone)
  95. {
  96. return DegToRad(-183.0 + (zone * 6.0));
  97. }
  98. /*
  99. * FootpointLatitude
  100. *
  101. * Computes the footpoint latitude for use in converting transverse
  102. * Mercator coordinates to ellipsoidal coordinates.
  103. *
  104. * Reference: Hoffmann-Wellenhof, B., Lichtenegger, H., and Collins, J.,
  105. * GPS: Theory and Practice, 3rd ed. New York: Springer-Verlag Wien, 1994.
  106. *
  107. * Inputs:
  108. * y - The UTM northing coordinate, in meters.
  109. *
  110. * Returns:
  111. * The footpoint latitude, in radians.
  112. *
  113. */
  114. double FootpointLatitude (double y)
  115. {
  116. double y_, alpha_, beta_, gamma_, delta_, epsilon_, n;
  117. double result;
  118. /* Precalculate n (Eq. 10.18) */
  119. n = (sm_a - sm_b) / (sm_a + sm_b);
  120. /* Precalculate alpha_ (Eq. 10.22) */
  121. /* (Same as alpha in Eq. 10.17) */
  122. alpha_ = ((sm_a + sm_b) / 2.0) * (1 + (pow(n, 2.0) / 4) + (pow(n, 4.0) / 64));
  123. /* Precalculate y_ (Eq. 10.23) */
  124. y_ = y / alpha_;
  125. /* Precalculate beta_ (Eq. 10.22) */
  126. beta_ = (3.0 * n / 2.0) + (-27.0 * pow(n, 3.0) / 32.0) + (269.0 * pow(n, 5.0) / 512.0);
  127. /* Precalculate gamma_ (Eq. 10.22) */
  128. gamma_ = (21.0 * pow(n, 2.0) / 16.0) + (-55.0 * pow(n, 4.0) / 32.0);
  129. /* Precalculate delta_ (Eq. 10.22) */
  130. delta_ = (151.0 * pow (n, 3.0) / 96.0) + (-417.0 * pow (n, 5.0) / 128.0);
  131. /* Precalculate epsilon_ (Eq. 10.22) */
  132. epsilon_ = (1097.0 * pow(n, 4.0) / 512.0);
  133. /* Now calculate the sum of the series (Eq. 10.21) */
  134. result = y_ + (beta_ * sin(2.0 * y_)) + (gamma_ * sin(4.0 * y_)) + (delta_ * sin(6.0 * y_)) + (epsilon_ * sin(8.0 * y_));
  135. return result;
  136. }
  137. /*
  138. * MapLatLonToXY
  139. *
  140. * Converts a latitude/longitude pair to x and y coordinates in the
  141. * Transverse Mercator projection. Note that Transverse Mercator is not
  142. * the same as UTM; a scale factor is required to convert between them.
  143. *
  144. * Reference: Hoffmann-Wellenhof, B., Lichtenegger, H., and Collins, J.,
  145. * GPS: Theory and Practice, 3rd ed. New York: Springer-Verlag Wien, 1994.
  146. *
  147. * Inputs:
  148. * phi - Latitude of the point, in radians.
  149. * lambda - Longitude of the point, in radians.
  150. * lambda0 - Longitude of the central meridian to be used, in radians.
  151. *
  152. * Outputs:
  153. * xy - A 2-element array containing the x and y coordinates
  154. * of the computed point.
  155. *
  156. * Returns:
  157. * The function does not return a value.
  158. *
  159. */
  160. void MapLatLonToXY (double phi, double lambda, double lambda0, UTMCoor &xy)
  161. {
  162. double N, nu2, ep2, t, t2, l;
  163. double l3coef, l4coef, l5coef, l6coef, l7coef, l8coef;
  164. double tmp;
  165. /* Precalculate ep2 */
  166. ep2 = (pow(sm_a, 2.0) - pow(sm_b, 2.0)) / pow(sm_b, 2.0);
  167. /* Precalculate nu2 */
  168. nu2 = ep2 * pow(cos(phi), 2.0);
  169. /* Precalculate N */
  170. N = pow(sm_a, 2.0) / (sm_b * sqrt(1 + nu2));
  171. /* Precalculate t */
  172. t = tan (phi);
  173. t2 = t * t;
  174. tmp = (t2 * t2 * t2) - pow (t, 6.0);
  175. /* Precalculate l */
  176. l = lambda - lambda0;
  177. /* Precalculate coefficients for l**n in the equations below
  178. so a normal human being can read the expressions for easting
  179. and northing
  180. -- l**1 and l**2 have coefficients of 1.0 */
  181. l3coef = 1.0 - t2 + nu2;
  182. l4coef = 5.0 - t2 + 9 * nu2 + 4.0 * (nu2 * nu2);
  183. l5coef = 5.0 - 18.0 * t2 + (t2 * t2) + 14.0 * nu2 - 58.0 * t2 * nu2;
  184. l6coef = 61.0 - 58.0 * t2 + (t2 * t2) + 270.0 * nu2 - 330.0 * t2 * nu2;
  185. l7coef = 61.0 - 479.0 * t2 + 179.0 * (t2 * t2) - (t2 * t2 * t2);
  186. l8coef = 1385.0 - 3111.0 * t2 + 543.0 * (t2 * t2) - (t2 * t2 * t2);
  187. /* Calculate easting (x) */
  188. xy.x = N * cos (phi) * l + (N / 6.0 * pow(cos(phi), 3.0) * l3coef * pow(l, 3.0))
  189. + (N / 120.0 * pow(cos(phi), 5.0) * l5coef * pow(l, 5.0))
  190. + (N / 5040.0 * pow(cos (phi), 7.0) * l7coef * pow(l, 7.0));
  191. /* Calculate northing (y) */
  192. xy.y = ArcLengthOfMeridian (phi)
  193. + (t / 2.0 * N * pow(cos(phi), 2.0) * pow(l, 2.0))
  194. + (t / 24.0 * N * pow(cos(phi), 4.0) * l4coef * pow(l, 4.0))
  195. + (t / 720.0 * N * pow(cos(phi), 6.0) * l6coef * pow(l, 6.0))
  196. + (t / 40320.0 * N * pow(cos(phi), 8.0) * l8coef * pow(l, 8.0));
  197. }
  198. /*
  199. * MapXYToLatLon
  200. *
  201. * Converts x and y coordinates in the Transverse Mercator projection to
  202. * a latitude/longitude pair. Note that Transverse Mercator is not
  203. * the same as UTM; a scale factor is required to convert between them.
  204. *
  205. * Reference: Hoffmann-Wellenhof, B., Lichtenegger, H., and Collins, J.,
  206. * GPS: Theory and Practice, 3rd ed. New York: Springer-Verlag Wien, 1994.
  207. *
  208. * Inputs:
  209. * x - The easting of the point, in meters.
  210. * y - The northing of the point, in meters.
  211. * lambda0 - Longitude of the central meridian to be used, in radians.
  212. *
  213. * Outputs:
  214. * philambda - A 2-element containing the latitude and longitude
  215. * in radians.
  216. *
  217. * Returns:
  218. * The function does not return a value.
  219. *
  220. * Remarks:
  221. * The local variables Nf, nuf2, tf, and tf2 serve the same purpose as
  222. * N, nu2, t, and t2 in MapLatLonToXY, but they are computed with respect
  223. * to the footpoint latitude phif.
  224. *
  225. * x1frac, x2frac, x2poly, x3poly, etc. are to enhance readability and
  226. * to optimize computations.
  227. *
  228. */
  229. void MapXYToLatLon (double x, double y, double lambda0, WGS84Corr &philambda)
  230. {
  231. double phif, Nf, Nfpow, nuf2, ep2, tf, tf2, tf4, cf;
  232. double x1frac, x2frac, x3frac, x4frac, x5frac, x6frac, x7frac, x8frac;
  233. double x2poly, x3poly, x4poly, x5poly, x6poly, x7poly, x8poly;
  234. /* Get the value of phif, the footpoint latitude. */
  235. phif = FootpointLatitude (y);
  236. /* Precalculate ep2 */
  237. ep2 = (pow(sm_a, 2.0) - pow(sm_b, 2.0)) / pow(sm_b, 2.0);
  238. /* Precalculate cos (phif) */
  239. cf = cos (phif);
  240. /* Precalculate nuf2 */
  241. nuf2 = ep2 * pow (cf, 2.0);
  242. /* Precalculate Nf and initialize Nfpow */
  243. Nf = pow(sm_a, 2.0) / (sm_b * sqrt(1 + nuf2));
  244. Nfpow = Nf;
  245. /* Precalculate tf */
  246. tf = tan (phif);
  247. tf2 = tf * tf;
  248. tf4 = tf2 * tf2;
  249. /* Precalculate fractional coefficients for x**n in the equations
  250. below to simplify the expressions for latitude and longitude. */
  251. x1frac = 1.0 / (Nfpow * cf);
  252. Nfpow *= Nf; /* now equals Nf**2) */
  253. x2frac = tf / (2.0 * Nfpow);
  254. Nfpow *= Nf; /* now equals Nf**3) */
  255. x3frac = 1.0 / (6.0 * Nfpow * cf);
  256. Nfpow *= Nf; /* now equals Nf**4) */
  257. x4frac = tf / (24.0 * Nfpow);
  258. Nfpow *= Nf; /* now equals Nf**5) */
  259. x5frac = 1.0 / (120.0 * Nfpow * cf);
  260. Nfpow *= Nf; /* now equals Nf**6) */
  261. x6frac = tf / (720.0 * Nfpow);
  262. Nfpow *= Nf; /* now equals Nf**7) */
  263. x7frac = 1.0 / (5040.0 * Nfpow * cf);
  264. Nfpow *= Nf; /* now equals Nf**8) */
  265. x8frac = tf / (40320.0 * Nfpow);
  266. /* Precalculate polynomial coefficients for x**n.
  267. -- x**1 does not have a polynomial coefficient. */
  268. x2poly = -1.0 - nuf2;
  269. x3poly = -1.0 - 2 * tf2 - nuf2;
  270. x4poly = 5.0 + 3.0 * tf2 + 6.0 * nuf2 - 6.0 * tf2 * nuf2 - 3.0 * (nuf2 *nuf2) - 9.0 * tf2 * (nuf2 * nuf2);
  271. x5poly = 5.0 + 28.0 * tf2 + 24.0 * tf4 + 6.0 * nuf2 + 8.0 * tf2 * nuf2;
  272. x6poly = -61.0 - 90.0 * tf2 - 45.0 * tf4 - 107.0 * nuf2 + 162.0 * tf2 * nuf2;
  273. x7poly = -61.0 - 662.0 * tf2 - 1320.0 * tf4 - 720.0 * (tf4 * tf2);
  274. x8poly = 1385.0 + 3633.0 * tf2 + 4095.0 * tf4 + 1575 * (tf4 * tf2);
  275. /* Calculate latitude */
  276. philambda.lat = phif + x2frac * x2poly * (x * x) + x4frac * x4poly * pow(x, 4.0) + x6frac * x6poly * pow(x, 6.0) + x8frac * x8poly * pow(x, 8.0);
  277. /* Calculate longitude */
  278. philambda.log = lambda0 + x1frac * x + x3frac * x3poly * pow(x, 3.0) + x5frac * x5poly * pow(x, 5.0) + x7frac * x7poly * pow(x, 7.0);
  279. }
  280. /*
  281. * LatLonToUTMXY
  282. *
  283. * Converts a latitude/longitude pair to x and y coordinates in the
  284. * Universal Transverse Mercator projection.
  285. *
  286. * Inputs:
  287. * lat - Latitude of the point, in radians.
  288. * lon - Longitude of the point, in radians.
  289. * zone - UTM zone to be used for calculating values for x and y.
  290. * If zone is less than 1 or greater than 60, the routine
  291. * will determine the appropriate zone from the value of lon.
  292. *
  293. * Outputs:
  294. * xy - A 2-element array where the UTM x and y values will be stored.
  295. *
  296. * Returns:
  297. * void
  298. *
  299. */
  300. void LatLonToUTMXY (double lat, double lon, int zone, UTMCoor &xy)
  301. {
  302. MapLatLonToXY (lat, lon, UTMCentralMeridian(zone), xy);
  303. /* Adjust easting and northing for UTM system. */
  304. xy.x = xy.x * UTMScaleFactor + 500000.0;
  305. xy.y = xy.y * UTMScaleFactor;
  306. if (xy.y < 0.0)
  307. xy.y += 10000000.0;
  308. }
  309. /*
  310. * UTMXYToLatLon
  311. *
  312. * Converts x and y coordinates in the Universal Transverse Mercator
  313. * projection to a latitude/longitude pair.
  314. *
  315. * Inputs:
  316. * x - The easting of the point, in meters.
  317. * y - The northing of the point, in meters.
  318. * zone - The UTM zone in which the point lies.
  319. * southhemi - True if the point is in the southern hemisphere;
  320. * false otherwise.
  321. *
  322. * Outputs:
  323. * latlon - A 2-element array containing the latitude and
  324. * longitude of the point, in radians.
  325. *
  326. * Returns:
  327. * The function does not return a value.
  328. *
  329. */
  330. void UTMXYToLatLon (double x, double y, int zone, bool southhemi, WGS84Corr &latlon)
  331. {
  332. double cmeridian;
  333. x -= 500000.0;
  334. x /= UTMScaleFactor;
  335. /* If in southern hemisphere, adjust y accordingly. */
  336. if (southhemi)
  337. y -= 10000000.0;
  338. y /= UTMScaleFactor;
  339. cmeridian = UTMCentralMeridian (zone);
  340. MapXYToLatLon (x, y, cmeridian, latlon);
  341. }
  342. #endif //__COORCONV_H__