IOS开发之MapKit定位国内不准的问题

最近做ios的开发,调用MapKit的时候碰到了定位不准的问题:当我做路线请求返回的时候,出发点明明输入的是我当前的位置,返回的结果却不在我的位置

其实,本质上不是Mapkit定位不准,而是采用的坐标系不同

在做MapKit开发的时候,细心的小伙伴们应该发现了地图的右下角标注了高德地图的字样,而看国外教程使用的时候就没有,这就导致了咱现在遇到的这个问题

国内 使用MapKit返回用户当前位置的经纬度 ,使用的坐标系是世界地理坐标WGS-84

而调用地图路线请求的时候,默认你传入的经纬度使用的坐标系是国测地理坐标GCJ-02

这就导致使用的时候,如果不进行坐标转换,就会导致返回的路线位置不正确

经过我的搜索,苹果官方也没有在MapKit中有坐标系转换这一功能,所以需要我们自行实现

swift代码如下

Swift 复制代码
//
//  CoordinateConverter.swift
//  demo
//
//  Created by hp on 2024/11/10.
//

import Foundation

class CoordinateConverter {
    // 常量参数
    private let a: Double = 6378245.0
    private let ee: Double = 0.00669342162296594323
    // GCJ-02 to WGS-84
    func gcj2Wgs(longitude: Double, latitude: Double) -> (Double, Double) {
        if(outOfChina(lon: longitude, lat: latitude)){
            return (longitude, latitude)
        }
        var dLat = transformLat(x: longitude - 105.0, y: latitude - 35.0)
        var dLon = transformLon(x: longitude - 105.0, y: latitude - 35.0)
        let radLat = latitude / 180.0 * .pi
        var magic = sin(radLat)
        magic = 1 - ee * magic * magic
        let sqrtMagic = sqrt(magic)
        dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * .pi)
        dLon = (dLon * 180.0) / (a / sqrtMagic * cos(radLat) * .pi)
        let mgLat = latitude + dLat
        let mgLon = longitude + dLon
        return (longitude * 2 - mgLon , latitude * 2 - mgLat)
    }
    // WGS-84 to GCJ-02
    func wgs2Gcj(longitude: Double, latitude: Double) -> (Double, Double) {
        if(outOfChina(lon: longitude, lat: latitude)){
            return (longitude, latitude)
        }
        var dLat = transformLat(x: longitude - 105.0, y: latitude - 35.0)
        var dLon = transformLon(x: longitude - 105.0, y: latitude - 35.0)
        let radLat = latitude / 180.0 * .pi
        var magic = sin(radLat)
        magic = 1 - ee * magic * magic
        let sqrtMagic = sqrt(magic)
        dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * .pi)
        dLon = (dLon * 180.0) / (a / sqrtMagic * cos(radLat) * .pi)
        let mgLat = latitude + dLat
        let mgLon = longitude + dLon
        return (mgLon, mgLat)
    }
    // 转换纬度
    private func transformLat(x: Double, y: Double) -> Double {
        var ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * sqrt(abs(x))
        ret += (20.0 * sin(6.0 * x * .pi) + 20.0 * sin(2.0 * x * .pi)) * 2.0 / 3.0
        ret += (20.0 * sin(y * .pi) + 40.0 * sin(y / 3.0 * .pi)) * 2.0 / 3.0
        ret += (160.0 * sin(y / 12.0 * .pi) + 320 * sin(y * .pi / 30.0)) * 2.0 / 3.0
        return ret
    }
    // 转换经度
    private func transformLon(x: Double, y: Double) -> Double {
        var ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * sqrt(abs(x))
        ret += (20.0 * sin(2.0 * x * .pi) + 20.0 * sin(x * .pi)) * 2.0 / 3.0
        ret += (20.0 * sin(x * .pi) + 40.0 * sin(x / 3.0 * .pi)) * 2.0 / 3.0
        ret += (150.0 * sin(x / 12.0 * .pi) + 300 * sin(x * .pi / 30.0)) * 2.0 / 3.0
        return ret
    }
    //判断是否在国内
    private func outOfChina(lon: Double, lat: Double)-> Bool{
        return !(lon > 73.66 && lon < 135.05 && lat > 3.86 && lat < 53.55)
    }
}

因为在国外是没有这个问题的,所以我添加了判断是否在国内的条件,保证所有用户都能正常使用

下面给大家看一下我调用时候的函数代码

Swift 复制代码
func fetchRoute() async{
    if let userLocation = locationManager.userLocation, let selectedPlacemark{
    //路线请求API
    let request = MKDirections.Request()
    //坐标转化
    let (wgsLon, wgsLat) = converter.wgs2Gcj(longitude: userLocation.coordinate.longitude, latitude: userLocation.coordinate.latitude)
    let wgsCoordinate = CLLocationCoordinate2D(latitude: wgsLat, longitude: wgsLon)
    //路线起点
    let sourcePlacemark = MKPlacemark(coordinate: wgsCoordinate)   
    let routeSource = MKMapItem(placemark: sourcePlacemark)
    //路线终点,这里我的selectedPlacemark已经在view里面赋值了,注意一下 
    let destinationPlacemark = MKPlacemark(coordinate:selectedPlacemark.coordinate)
    routeDestination = MKMapItem(placemark: destinationPlacemark)
    routeDestination?.name = selectedPlacemark.name
    request.source = routeSource
    request.destination = routeDestination
    //这个值是你使用的交通工具,我已经提前赋值了
    request.transportType = transportType
    //这个是返回路线指引,告诉你该怎么走
    let directions = MKDirections(request: request)
    let result = try? await directions.calculate()
    route = result?.routes.first
    //这个是返回预计多长时间
    travelInterval = route?.expectedTravelTime
    }
}

好了以上就是本博客的全部内容了,地图这块我之前用过百度地图,也碰到过这种事情,比较有经验,不然也不好解决这个问题。

学无止境,多学总是有用的!!!

相关推荐
for_ever_love__1 天前
UI学习:多界面传值的正向传值(属性传值)和反向传值(代理传值)
学习·ui·ios·objective-c
开心就好20251 天前
全面介绍iOS开发工具:Xcode、AppCode、CocoaPods、Fastlane和Git
后端·ios
懋学的前端攻城狮1 天前
数据持久化与缓存策略:在离线与在线间架起桥梁
ios·swift
~央千澈~1 天前
以cocos3.8.8开发的游戏为例商业实战项目举例cocos打包ios苹果安装包ipa完整详细教程-优雅草卓伊凡
ios
SameX1 天前
iOS 足迹 App 的成就系统,我推倒重做了一次——踩了3个坑之后
ios
SameX1 天前
我做了一个把专注计时变成「声音护照」的 iOS App,聊聊数据可视化和成长系统的设计思路
ios
SameX1 天前
我用 SpriteKit 给存钱罐装了个物理引擎
ios
开心就好20251 天前
Charles配置HTTP和HTTPS抓包完整指南
后端·ios
JarvanMo1 天前
7 个开源 iOS 应用,让你成为更好的开发者
前端·ios
白玉cfc1 天前
OC底层原理:alloc&init&new
c++·macos·ios·objective-c·xcode