LocationTransform.swift 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. import Foundation
  2. /**
  3. * Struct transform coordinate between earth(WGS-84) and mars in china(GCJ-02).
  4. */
  5. public struct LocationTransform {
  6. static let EARTH_R: Double = 6378137.0
  7. static func isOutOfChina(lat: Double, lng: Double) -> Bool {
  8. if lng < 72.004 || lng > 137.8347 {
  9. return true
  10. }
  11. if lat < 0.8293 || lat > 55.8271 {
  12. return true
  13. }
  14. return false
  15. }
  16. static func transform(x: Double, y: Double) -> (lat: Double, lng: Double) {
  17. let xy = x * y
  18. let absX = sqrt(fabs(x))
  19. let xPi = x * M_PI
  20. let yPi = y * M_PI
  21. let d = 20.0 * sin(6.0 * xPi) + 20.0 * sin(2.0 * xPi)
  22. var lat = d
  23. var lng = d
  24. lat += 20.0 * sin(yPi) + 40.0 * sin(yPi / 3.0)
  25. lng += 20.0 * sin(xPi) + 40.0 * sin(xPi / 3.0)
  26. lat += 160.0 * sin(yPi / 12.0) + 320 * sin(yPi / 30.0)
  27. lng += 150.0 * sin(xPi / 12.0) + 300 * sin(xPi / 30.0)
  28. lat *= 2.0 / 3.0
  29. lng *= 2.0 / 3.0
  30. lat += -100 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * xy + 0.2 * absX
  31. lng += 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * xy + 0.1 * absX
  32. return (lat, lng)
  33. }
  34. static func delta(lat: Double, lng: Double) -> (dLat: Double, dLng: Double) {
  35. let ee = 0.00669342162296594323
  36. let radLat = lat / 180.0 * M_PI
  37. var magic = sin(radLat)
  38. magic = 1 - ee * magic * magic
  39. let sqrtMagic = sqrt(magic)
  40. var (dLat, dLng) = transform(x: lng - 105.0, y: lat - 35.0)
  41. dLat = (dLat * 180.0) / ((EARTH_R * (1 - ee)) / (magic * sqrtMagic) * M_PI)
  42. dLng = (dLng * 180.0) / (EARTH_R / sqrtMagic * cos(radLat) * M_PI)
  43. return (dLat, dLng)
  44. }
  45. /**
  46. * wgs2gcj convert WGS-84 coordinate(wgsLat, wgsLng) to GCJ-02 coordinate(gcjLat, gcjLng).
  47. */
  48. public static func wgs2gcj(wgsLat: Double, wgsLng: Double) -> (gcjLat: Double, gcjLng: Double) {
  49. if isOutOfChina(lat: wgsLat, lng: wgsLng) {
  50. return (wgsLat, wgsLng)
  51. }
  52. let (dLat, dLng) = delta(lat: wgsLat, lng: wgsLng)
  53. return (wgsLat + dLat, wgsLng + dLng)
  54. }
  55. /**
  56. * gcj2wgs convert GCJ-02 coordinate(gcjLat, gcjLng) to WGS-84 coordinate(wgsLat, wgsLng).
  57. * The output WGS-84 coordinate's accuracy is 1m to 2m. If you want more exactly result, use gcj2wgs_exact.
  58. */
  59. public static func gcj2wgs(gcjLat: Double, gcjLng: Double) -> (wgsLat: Double, wgsLng: Double) {
  60. if isOutOfChina(lat: gcjLat, lng: gcjLng) {
  61. return (gcjLat, gcjLng)
  62. }
  63. let (dLat, dLng) = delta(lat: gcjLat, lng: gcjLng)
  64. return (gcjLat - dLat, gcjLng - dLng)
  65. }
  66. /**
  67. * gcj2wgs_exact convert GCJ-02 coordinate(gcjLat, gcjLng) to WGS-84 coordinate(wgsLat, wgsLng).
  68. * The output WGS-84 coordinate's accuracy is less than 0.5m, but much slower than gcj2wgs.
  69. */
  70. public static func gcj2wgs_exact(gcjLat: Double, gcjLng: Double) -> (wgsLat: Double, wgsLng: Double) {
  71. let initDelta = 0.01, threshold = 0.000001
  72. var (dLat, dLng) = (initDelta, initDelta)
  73. var (mLat, mLng) = (gcjLat - dLat, gcjLng - dLng)
  74. var (pLat, pLng) = (gcjLat + dLat, gcjLng + dLng)
  75. var (wgsLat, wgsLng) = (gcjLat, gcjLng)
  76. for _ in 0 ..< 30 {
  77. (wgsLat, wgsLng) = ((mLat + pLat) / 2, (mLng + pLng) / 2)
  78. let (tmpLat, tmpLng) = wgs2gcj(wgsLat: wgsLat, wgsLng: wgsLng)
  79. (dLat, dLng) = (tmpLat - gcjLat, tmpLng - gcjLng)
  80. if (fabs(dLat) < threshold) && (fabs(dLng) < threshold) {
  81. return (wgsLat, wgsLng)
  82. }
  83. if dLat > 0 {
  84. pLat = wgsLat
  85. } else {
  86. mLat = wgsLat
  87. }
  88. if dLng > 0 {
  89. pLng = wgsLng
  90. } else {
  91. mLng = wgsLng
  92. }
  93. }
  94. return (wgsLat, wgsLng)
  95. }
  96. /**
  97. * Distance calculate the distance between point(latA, lngA) and point(latB, lngB), unit in meter.
  98. */
  99. public static func Distance(latA: Double, lngA: Double, latB: Double, lngB: Double) -> Double {
  100. let arcLatA = latA * M_PI / 180
  101. let arcLatB = latB * M_PI / 180
  102. let x = cos(arcLatA) * cos(arcLatB) * cos((lngA-lngB) * M_PI/180)
  103. let y = sin(arcLatA) * sin(arcLatB)
  104. var s = x + y
  105. if s > 1 {
  106. s = 1
  107. }
  108. if s < -1 {
  109. s = -1
  110. }
  111. let alpha = acos(s)
  112. let distance = alpha * EARTH_R
  113. return distance
  114. }
  115. }
  116. extension LocationTransform {
  117. public static func gcj2bd(gcjLat: Double, gcjLng: Double) -> (bdLat: Double, bdLng: Double) {
  118. if isOutOfChina(lat: gcjLat, lng: gcjLng) {
  119. return (gcjLat, gcjLng)
  120. }
  121. let x = gcjLng, y = gcjLat
  122. let z = sqrt(x * x + y * y) + 0.00002 * sin(y * M_PI)
  123. let theta = atan2(y, x) + 0.000003 * cos(x * M_PI)
  124. let bdLng = z * cos(theta) + 0.0065
  125. let bdLat = z * sin(theta) + 0.006
  126. return (bdLat, bdLng)
  127. }
  128. public static func bd2gcj(bdLat: Double, bdLng: Double) -> (gcjLat: Double, gcjLng: Double) {
  129. if isOutOfChina(lat: bdLat, lng: bdLng) {
  130. return (bdLat, bdLng)
  131. }
  132. let x = bdLng - 0.0065, y = bdLat - 0.006
  133. let z = sqrt(x * x + y * y) - 0.00002 * sin(y * M_PI)
  134. let theta = atan2(y, x) - 0.000003 * cos(x * M_PI)
  135. let gcjLng = z * cos(theta)
  136. let gcjLat = z * sin(theta)
  137. return (gcjLat, gcjLng)
  138. }
  139. public static func wgs2bd(wgsLat: Double, wgsLng: Double) -> (bdLat: Double, bdLng: Double) {
  140. let (gcjLat, gcjLng) = wgs2gcj(wgsLat: wgsLat, wgsLng: wgsLng)
  141. return gcj2bd(gcjLat: gcjLat, gcjLng: gcjLng)
  142. }
  143. public static func bd2wgs(bdLat: Double, bdLng: Double) -> (wgsLat: Double, wgsLng: Double) {
  144. let (gcjLat, gcjLng) = bd2gcj(bdLat: bdLat, bdLng: bdLng)
  145. return gcj2wgs(gcjLat: gcjLat, gcjLng: gcjLng)
  146. }
  147. }