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

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

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

相关推荐
叽哥4 小时前
Flutter Riverpod上手指南
android·flutter·ios
用户091 天前
SwiftUI Charts 函数绘图完全指南
ios·swiftui·swift
YungFan1 天前
iOS26适配指南之UIColor
ios·swift
权咚2 天前
阿权的开发经验小集
git·ios·xcode
用户092 天前
TipKit与CloudKit同步完全指南
ios·swift
法的空间2 天前
Flutter JsonToDart 支持 JsonSchema
android·flutter·ios
2501_915918412 天前
iOS 上架全流程指南 iOS 应用发布步骤、App Store 上架流程、uni-app 打包上传 ipa 与审核实战经验分享
android·ios·小程序·uni-app·cocoa·iphone·webview
00后程序员张2 天前
iOS App 混淆与加固对比 源码混淆与ipa文件混淆的区别、iOS代码保护与应用安全场景最佳实践
android·安全·ios·小程序·uni-app·iphone·webview
Magnetic_h3 天前
【iOS】设计模式复习
笔记·学习·ios·设计模式·objective-c·cocoa
00后程序员张3 天前
详细解析苹果iOS应用上架到App Store的完整步骤与指南
android·ios·小程序·https·uni-app·iphone·webview