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
    }
}

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

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

相关推荐
传奇开心果编程5 小时前
【SwiftUI提高练中学】第8课 网络层架构:拦截器、重试、缓存与离线优先
学习·macos·ui·ios·swiftui
传奇开心果编程12 小时前
【Compose Multiplatform 跨端开发学与练】第3课 布局与组件
android·windows·学习·ui·ios·kotlin·composer
tink13 小时前
告别 Xcode IDE:用 VS Code + SweetPad + XcodeGen 开发 iOS 应用的完整指南
ios·swiftui·xcode
传奇开心果编程14 小时前
【Compose Multiplatform 跨端开发学与练】第8课 资源管理与主题
android·windows·学习·ios·kotlin·web·composer
传奇开心果编程16 小时前
【Compose Multiplatform 跨端开发学与练】第9课 测试与调试
android·学习·macos·ios·kotlin·web·composer
传奇开心果编程16 小时前
【Compose Multiplatform 跨端开发学与练】第4课 导航与路由
android·windows·学习·ui·ios·kotlin·composer
黑科技iOS上架16 小时前
iOS隐私合规扫描工具
ios·审核
传奇开心果编程16 小时前
【Compose Multiplatform 跨端开发学与练】第6课 状态管理与架构
android·学习·ui·ios·架构·kotlin·composer
传奇开心果编程17 小时前
【Compose Multiplatform 跨端开发学与练】第2课 Compose 基础语法
android·windows·学习·ui·ios·kotlin·composer
可乐鸡翅yeah_17 小时前
hls.js 缓冲区参数 maxBufferLength、maxBufferSize 通俗讲解与业务调参
开发语言·javascript·ios·音视频·safari·m3u8