如何在MKPolyLine上精准添加标记点(解决远距离偏移问题)
解决MapKit远距离两点路径标记点偏离问题
问题根源
直接对经纬度取平均值是平面坐标系的中点计算方式,但地球是球面,MKMapView绘制的PolyLine默认采用大圆航线(球面上两点的最短路径),平面中点不会落在这条球面上的路径上,远距离场景下偏差会非常明显。
解决方案
利用CoreLocation的球面坐标计算能力,实现两点间大圆路径的插值计算,精准获取路径上任意比例的位置点。
1. 添加球面坐标计算工具
import CoreLocation // 计算两点间大圆路径上指定比例的坐标点 func coordinateBetween(_ start: CLLocationCoordinate2D, _ end: CLLocationCoordinate2D, fraction: Double) -> CLLocationCoordinate2D { let startLoc = CLLocation(latitude: start.latitude, longitude: start.longitude) let endLoc = CLLocation(latitude: end.latitude, longitude: end.longitude) let distance = startLoc.distance(from: endLoc) let bearing = startLoc.bearing(to: endLoc) let moveDistance = distance * fraction return startLoc.coordinate(at: bearing, distance: moveDistance) } // CLLocation扩展:计算方位角和目标坐标 extension CLLocation { func bearing(to location: CLLocation) -> CLLocationDirection { let lat1 = self.coordinate.latitude.radians let lon1 = self.coordinate.longitude.radians let lat2 = location.coordinate.latitude.radians let lon2 = location.coordinate.longitude.radians let deltaLon = lon2 - lon1 let y = sin(deltaLon) * cos(lat2) let x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(deltaLon) return atan2(y, x).degrees } func coordinate(at bearing: CLLocationDirection, distance: CLLocationDistance) -> CLLocationCoordinate2D { let earthRadius = 6371000.0 // 地球半径(米) let bearingRadians = bearing.radians let lat1 = self.coordinate.latitude.radians let lon1 = self.coordinate.longitude.radians let lat2 = asin(sin(lat1) * cos(distance / earthRadius) + cos(lat1) * sin(distance / earthRadius) * cos(bearingRadians)) let lon2 = lon1 + atan2(sin(bearingRadians) * sin(distance / earthRadius) * cos(lat1), cos(distance / earthRadius) - sin(lat1) * sin(lat2)) return CLLocationCoordinate2D(latitude: lat2.degrees, longitude: lon2.degrees) } } // 角度与弧度转换扩展 extension BinaryFloatingPoint { var degrees: Self { self * 180 / .pi } var radians: Self { self * .pi / 180 } }
2. 修改中点计算逻辑
替换ContentView中原来的平面平均计算,改用球面插值:
init() { self.lineCoordinates = [tfs, london] // fraction为0.5时是中点,可设置0~1之间任意值获取路径上对应位置 middle = coordinateBetween(tfs, london, fraction: 0.5) }
效果说明
修改后,标记点会精准落在MKPolyLine的大圆航线上,无论两点距离远近都不会出现偏离。如果需要在路径任意位置添加标记,只需调整fraction参数(比如0.3表示从起点到终点的30%位置)。
内容的提问来源于stack exchange,提问作者Tamás Horváth
相关产品推荐
相关产品推荐

