IOS开发之MapKit定位国内不准的问题
最近做ios的开发,调用MapKit的时候碰到了定位不准的问题:当我做路线请求返回的时候,出发点明明输入的是我当前的位置,返回的结果却不在我的位置
其实,本质上不是Mapkit定位不准,而是采用的坐标系不同
在做MapKit开发的时候,细心的小伙伴们应该发现了地图的右下角标注了高德地图的字样,而看国外教程使用的时候就没有,这就导致了咱现在遇到的这个问题
在国内使用MapKit返回用户当前位置的经纬度,使用的坐标系是世界地理坐标WGS-84
而调用地图路线请求的时候,默认你传入的经纬度使用的坐标系是国测地理坐标GCJ-02
这就导致使用的时候,如果不进行坐标转换,就会导致返回的路线位置不正确
经过我的搜索,苹果官方也没有在MapKit中有坐标系转换这一功能,所以需要我们自行实现
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)
}
}
因为在国外是没有这个问题的,所以我添加了判断是否在国内的条件,保证所有用户都能正常使用
下面给大家看一下我调用时候的函数代码
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
}
}
好了以上就是本博客的全部内容了,地图这块我之前用过百度地图,也碰到过这种事情,比较有经验,不然也不好解决这个问题。
学无止境,多学总是有用的!!!