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

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

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

相关推荐
黑马源码库miui520861 小时前
JAVA国际版同城上门服务上门送水桶装水配送源码同城上门配送系统源码支持Android+IOS+H5
android·java·ios
2501_915921431 小时前
iPhone 定位功能测试时不越狱来修改手机位置的方法
android·ios·智能手机·小程序·uni-app·iphone·webview
spencer_tseng2 小时前
HTML5 - Android - IOS
android·ios·html·html5
90后的晨仔3 小时前
深入剖析 SDAnimatedImageView:如何优雅地在 iOS 中实现高性能动态图渲染
ios
游戏开发爱好者83 小时前
iOS 开发进阶,用 SniffMaster 实现 iPhone 抓包深度分析
android·ios·小程序·https·uni-app·iphone·webview
开心就好202516 小时前
本地执行 IPA 混淆 无需上传致云端且不修改工程的方案
后端·ios
报错小能手20 小时前
ios开发方向——对于实习开发的app(Robopocket)讲解
开发语言·学习·ios·swift
wechatbot88821 小时前
【企业通信】基于IPAD协议的企业微信群聊管理API:群操作功能接口设计与实现
java·ios·微信·企业微信·ipad
胖虎11 天前
我用一个 UITableView,干掉了 80% 复杂页面
ios·架构·cocoa·uitableview·ui布局
T1an-11 天前
最右IOS开发A卷笔试题3.31
c++·ios