我正在使用 MapKit 在地图上的两点之间绘制一条直线,并尝试在中心放置一个标记。当距离很小时,一切都很好,但是当距离更大时,中间的标记会偏离线。是否可以使其更准确?由于 PolyLine,我使用 MKMapView 的 UIViewRepresentable ,但我想在这种情况下这应该不重要。我正在复制 MapView 以防有人想要重现,但在我看来应该没问题。我居中只是一个例子,理想情况下,我想在线的任何部分放置一个标记。
struct ContentView: View {
let tfs = CLLocationCoordinate2D(latitude: 28.047477135170762, longitude: -16.572272806214418)
let london = CLLocationCoordinate2D(latitude: 51.507277135170762, longitude: 0.127672806214418)
private var lineCoordinates: [CLLocationCoordinate2D]
let middle: CLLocationCoordinate2D
init() {
self.lineCoordinates = [tfs, london]
middle = CLLocationCoordinate2D(latitude: (london.latitude + tfs.latitude) / 2, longitude: (london.longitude + tfs.longitude) / 2)
}
var body: some View {
MapView(
currentPosition: middle,
lineCoordinates: lineCoordinates
)
.edgesIgnoringSafeArea(.all)
}
}
struct MapView: UIViewRepresentable {
let currentPosition: CLLocationCoordinate2D
let lineCoordinates: [CLLocationCoordinate2D]
func makeUIView(context: Context) -> MKMapView {
let mapView = MKMapView()
mapView.delegate = context.coordinator
mapView.region = MKCoordinateRegion(coordinates: lineCoordinates)
let polyline = MKPolyline(coordinates: lineCoordinates, count: lineCoordinates.count)
mapView.addOverlay(polyline)
let annotation = MKPointAnnotation()
annotation.coordinate = currentPosition
annotation.title = "Current position"
mapView.addAnnotation(annotation)
return mapView
}
func updateUIView(_ view: MKMapView, context: Context) {}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
}
class Coordinator: NSObject, MKMapViewDelegate {
var parent: MapView
init(_ parent: MapView) {
self.parent = parent
}
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
if let routePolyline = overlay as? MKPolyline {
let renderer = MKPolylineRenderer(polyline: routePolyline)
renderer.strokeColor = UIColor.systemBlue
renderer.lineWidth = 10
return renderer
}
return MKOverlayRenderer()
}
}
extension MKCoordinateRegion {
init(coordinates: [CLLocationCoordinate2D], spanMultiplier: CLLocationDistance = 1.3) {
var topLeftCoord = CLLocationCoordinate2D(latitude: -90, longitude: 180)
var bottomRightCoord = CLLocationCoordinate2D(latitude: 90, longitude: -180)
for coordinate in coordinates {
topLeftCoord.longitude = min(topLeftCoord.longitude, coordinate.longitude)
topLeftCoord.latitude = max(topLeftCoord.latitude, coordinate.latitude)
bottomRightCoord.longitude = max(bottomRightCoord.longitude, coordinate.longitude)
bottomRightCoord.latitude = min(bottomRightCoord.latitude, coordinate.latitude)
}
let cent = CLLocationCoordinate2D.init(latitude: topLeftCoord.latitude - (topLeftCoord.latitude - bottomRightCoord.latitude) * 0.5, longitude: topLeftCoord.longitude + (bottomRightCoord.longitude - topLeftCoord.longitude) * 0.5)
let span = MKCoordinateSpan.init(latitudeDelta: abs(topLeftCoord.latitude - bottomRightCoord.latitude) * spanMultiplier, longitudeDelta: abs(bottomRightCoord.longitude - topLeftCoord.longitude) * spanMultiplier)
self.init(center: cent, span: span)
}
}
我想通了,其实我确实需要使用
MKGeodesicPolyline
,所以这条线会遵循地球的曲率来显示最短路径,但我计算线中间的方式也不正确
CLLocationCoordinate2D(latitude: (london.latitude + tfs.latitude) / 2, longitude: (london.longitude + tfs.longitude) / 2)
这仅适用于 2D 坐标空间,在计算地图上的距离或路径时不能在现实生活场景中使用。有一些高级公式可以做到这一点,但我最终只是通过这个gist获得了坐标内的点。我正在获取线条的坐标,并在想要放置标记时从这些点中进行选择。