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

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

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

相关推荐
zhlx28352 小时前
【免越狱】iOS砸壳 可下载AppStore任意版本 旧版本IPA下载
macos·ios·cocoa
XZHOUMIN13 小时前
网易博客旧文----编译用于IOS的zlib版本
ios
爱吃香菇的小白菜16 小时前
H5跳转App 判断App是否安装
前端·ios
二流小码农21 小时前
鸿蒙开发:ForEach中为什么键值生成函数很重要
android·ios·harmonyos
hxx2211 天前
iOS swift开发--- 加载PDF文件并显示内容
ios·pdf·swift
B.-1 天前
在 Flutter 应用中调用后端接口的方法
android·flutter·http·ios·https
️ 邪神1 天前
【Android、IOS、Flutter、鸿蒙、ReactNative 】约束布局
android·flutter·ios·鸿蒙·reactnative
️ 邪神2 天前
【Android、IOS、Flutter、鸿蒙、ReactNative 】文本点击事件
flutter·ios·鸿蒙·reactnative·anroid
️ 邪神2 天前
【Android、IOS、Flutter、鸿蒙、ReactNative 】文本Text显示
flutter·ios·鸿蒙·reactnative·anroid
袁代码2 天前
Swift 开发教程系列 - 第11章:内存管理和 ARC(Automatic Reference Counting)
开发语言·ios·swift·ios开发