Swift 解决CLLocationManager获取定位在MKMapView显示不一致的问题

原因:定位坐标系不一致
解决方案:坐标转换

用法

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        
        if let location = locations.last {
            
            // 转换前
            let latitude = location.coordinate.latitude
            let longitude = location.coordinate.longitude

            // 转换后
            let point = LocationTransform.wgs2gcj(wgsLat: latitude, wgsLng: longitude)            
        }
    }

工具

import Foundation

/**
 *  Struct transform coordinate between earth(WGS-84) and mars in china(GCJ-02).
 */
public struct LocationTransform {

    static let EARTH_R: Double = 6378137.0

    static func isOutOfChina(lat: Double, lng: Double) -> Bool {

        if lng < 72.004 || lng > 137.8347 {
            return true
        }
        if lat < 0.8293 || lat > 55.8271 {
            return true
        }
        return false
    }

    static func transform(x: Double, y: Double) -> (lat: Double, lng: Double) {

        let xy = x * y
        let absX = sqrt(fabs(x))
        let xPi = x * Double.pi
        let yPi = y * Double.pi
        let d = 20.0 * sin(6.0 * xPi) + 20.0 * sin(2.0 * xPi)

        var lat = d
        var lng = d

        lat += 20.0 * sin(yPi) + 40.0 * sin(yPi / 3.0)
        lng += 20.0 * sin(xPi) + 40.0 * sin(xPi / 3.0)

        lat += 160.0 * sin(yPi / 12.0) + 320 * sin(yPi / 30.0)
        lng += 150.0 * sin(xPi / 12.0) + 300 * sin(xPi / 30.0)

        lat *= 2.0 / 3.0
        lng *= 2.0 / 3.0

        lat += -100 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * xy + 0.2 * absX
        lng += 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * xy + 0.1 * absX

        return (lat, lng)
    }

    static func delta(lat: Double, lng: Double) -> (dLat: Double,  dLng: Double) {
        let ee = 0.00669342162296594323
        let radLat = lat / 180.0 * Double.pi
        var magic = sin(radLat)
        magic = 1 - ee * magic * magic
        let sqrtMagic = sqrt(magic)
        var (dLat, dLng) = transform(x: lng - 105.0, y: lat - 35.0)
        dLat = (dLat * 180.0) / ((EARTH_R * (1 - ee)) / (magic * sqrtMagic) * Double.pi)
        dLng = (dLng * 180.0) / (EARTH_R / sqrtMagic * cos(radLat) * Double.pi)
        return (dLat, dLng)
    }

    /**
     *  wgs2gcj convert WGS-84 coordinate(wgsLat, wgsLng) to GCJ-02 coordinate(gcjLat, gcjLng).
     *  wgs2gcj 将 WGS-84 坐标(wgsLat,wgsLng)转换为 GCJ-02 坐标(gcjLat,gcjLng)。
     */
    public static func wgs2gcj(wgsLat: Double, wgsLng: Double) -> (gcjLat: Double, gcjLng: Double) {
        if isOutOfChina(lat: wgsLat, lng: wgsLng) {
            return (wgsLat, wgsLng)
        }
        let (dLat, dLng) = delta(lat: wgsLat, lng: wgsLng)
        return (wgsLat + dLat, wgsLng + dLng)
    }

    /**
     *  gcj2wgs convert GCJ-02 coordinate(gcjLat, gcjLng) to WGS-84 coordinate(wgsLat, wgsLng).
     *  The output WGS-84 coordinate's accuracy is 1m to 2m. If you want more exactly result, use gcj2wgs_exact.
     *   gcj2wgs 将 GCJ-02 坐标(gcjLat,gcjLng)转换为 WGS-84 坐标(wgsLat,wgsLng)。
     *   输出WGS-84坐标的精度为1m至2m。 如果您想要更准确的结果,请使用 gcj2wgs_exact。
     */
    public static func gcj2wgs(gcjLat: Double, gcjLng: Double) -> (wgsLat: Double, wgsLng: Double) {
        if isOutOfChina(lat: gcjLat, lng: gcjLng) {
            return (gcjLat, gcjLng)
        }
        let (dLat, dLng) = delta(lat: gcjLat, lng: gcjLng)
        return (gcjLat - dLat, gcjLng - dLng)
    }

    /**
     *  gcj2wgs_exact convert GCJ-02 coordinate(gcjLat, gcjLng) to WGS-84 coordinate(wgsLat, wgsLng).
     *  The output WGS-84 coordinate's accuracy is less than 0.5m, but much slower than gcj2wgs.
     *   gcj2wgs_exact 将 GCJ-02 坐标(gcjLat,gcjLng)转换为 WGS-84 坐标(wgsLat,wgsLng)。
     *   输出的WGS-84坐标精度小于0.5m,但比gcj2wgs慢很多。
     */
    public static func gcj2wgs_exact(gcjLat: Double, gcjLng: Double) -> (wgsLat: Double, wgsLng: Double) {
        let initDelta = 0.01, threshold = 0.000001
        var (dLat, dLng) = (initDelta, initDelta)
        var (mLat, mLng) = (gcjLat - dLat, gcjLng - dLng)
        var (pLat, pLng) = (gcjLat + dLat, gcjLng + dLng)
        var (wgsLat, wgsLng) = (gcjLat, gcjLng)
        for _ in 0 ..< 30 {
            (wgsLat, wgsLng) = ((mLat + pLat) / 2, (mLng + pLng) / 2)
            let (tmpLat, tmpLng) = wgs2gcj(wgsLat: wgsLat, wgsLng: wgsLng)
            (dLat, dLng) = (tmpLat - gcjLat, tmpLng - gcjLng)
            if (fabs(dLat) < threshold) && (fabs(dLng) < threshold) {
                return (wgsLat, wgsLng)
            }
            if dLat > 0 {
                pLat = wgsLat
            } else {
                mLat = wgsLat
            }
            if dLng > 0 {
                pLng = wgsLng
            } else {
                mLng = wgsLng
            }
        }
        return (wgsLat, wgsLng)
    }

    /**
     *  Distance calculate the distance between point(latA, lngA) and point(latB, lngB), unit in meter.
     *  距离计算点(latA,lngA)和点(latB,lngB)之间的距离,单位为米。
     */
    public static func Distance(latA: Double, lngA: Double, latB: Double, lngB: Double) -> Double {
        let arcLatA = latA * Double.pi / 180
        let arcLatB = latB * Double.pi / 180
        let x = cos(arcLatA) * cos(arcLatB) * cos((lngA-lngB) * Double.pi/180)
        let y = sin(arcLatA) * sin(arcLatB)
        var s = x + y
        if s > 1 {
            s = 1
        }
        if s < -1 {
            s = -1
        }
        let alpha = acos(s)
        let distance = alpha * EARTH_R
        return distance
    }
}

extension LocationTransform {

    public static func gcj2bd(gcjLat: Double, gcjLng: Double) -> (bdLat: Double, bdLng: Double) {
        if isOutOfChina(lat: gcjLat, lng: gcjLng) {
            return (gcjLat, gcjLng)
        }
        let x = gcjLng, y = gcjLat
        let z = sqrt(x * x + y * y) + 0.00002 * sin(y * Double.pi)
        let theta = atan2(y, x) + 0.000003 * cos(x * Double.pi)
        let bdLng = z * cos(theta) + 0.0065
        let bdLat = z * sin(theta) + 0.006
        return (bdLat, bdLng)
    }

    public static func bd2gcj(bdLat: Double, bdLng: Double) -> (gcjLat: Double, gcjLng: Double) {
        if isOutOfChina(lat: bdLat, lng: bdLng) {
            return (bdLat, bdLng)
        }
        let x = bdLng - 0.0065, y = bdLat - 0.006
        let z = sqrt(x * x + y * y) - 0.00002 * sin(y * Double.pi)
        let theta = atan2(y, x) - 0.000003 * cos(x * Double.pi)
        let gcjLng = z * cos(theta)
        let gcjLat = z * sin(theta)
        return (gcjLat, gcjLng)
    }

    public static func wgs2bd(wgsLat: Double, wgsLng: Double) -> (bdLat: Double, bdLng: Double) {
        let (gcjLat, gcjLng) = wgs2gcj(wgsLat: wgsLat, wgsLng: wgsLng)
        return gcj2bd(gcjLat: gcjLat, gcjLng: gcjLng)
    }

    public static func bd2wgs(bdLat: Double, bdLng: Double) -> (wgsLat: Double, wgsLng: Double) {
        let (gcjLat, gcjLng) = bd2gcj(bdLat: bdLat, bdLng: bdLng)
        return gcj2wgs(gcjLat: gcjLat, gcjLng: gcjLng)
    }
}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容