Calculate bearing in MKMapView gives wrong value while crossing 180 meridian
Asked Answered
H

1

2

I need to draw lines to demonstrate transportation of goods on apple maps. To clarify start- and end-point, I draw a little arrowhead on the destination side.The arrowhead is drawn separately but it is reversed in one case.

>-->-->-->- 

instead of

<--<--<--<-

I am using MKMapView and MKPolyline to draw lines. I am using MKOverlay to add direction arrows. The steps I follow are,

  1. calculate bearing of

    Source : CLLocationCoordinate2D(latitude: -33.8392932, longitude: 151.21519799999999) Destination: CLLocationCoordinate2D(latitude: 39.645516999999998, longitude: -104.598724)

    using the following function

    open static func getDirectionOf( _ supplyLineWithCoordinates: [CLLocationCoordinate2D]) -> CGFloat {
    guard let sourceCoordniate = supplyLineWithCoordinates.first,
        let destinationCoordniate = supplyLineWithCoordinates.last  else {
            fatalError("Coordinates of supply line not found")
    }
    let sourcePoint: MKMapPoint = MKMapPointForCoordinate(sourceCoordniate)
    let destinationPoint: MKMapPoint = MKMapPointForCoordinate(destinationCoordniate)
    let x: Double = destinationPoint.x - sourcePoint.x
    let y: Double = destinationPoint.y - sourcePoint.y
    var arrowDirection = CGFloat(fmod(atan2(y, x), 360.0))
    if arrowDirection < 0.0 {
        arrowDirection += 2 * .pi
    }
    return arrowDirection 
    

    }

  2. Rotate the arrow image and add it as the map overlay. The directions are calculated correctly in most of the cases, however, when I select the line shown below the direction is displayed 180 opposite. It starts from Sydney, Australia and ends in Denver, US

enter image description here

When trying to display the region with this two locations in mapView.setVisibleMapRect these region is not displayed, mapview tries to display region starting from Sydney (Australia) to Denver(US) through Asia and Europe, while it should display the map area I have attached above. If you have suggestions for optimisation, feel free to mention it.

I think this might be the reason, the direction should be calculated along the red line but it being calculated along the green line. Both lines are drawn by connecting same location coordinates in map. Any known workaround for this?

enter image description here

Hofmannsthal answered 21/5, 2018 at 11:2 Comment(11)
This fmod(atan2(y, x), 360.0)) // in radians raises two questions for me: 1) the comment says radians, but 360.0 is obviously in degrees; 2) The expression looks as if it would return a value in the interval 0 to 360, but do you want -180 to 180 perhaps? Also, shouldn't the arrows go along with the line? In your example picture, they point somewhere else.Microgroove
Sorry, the comment saying in radians was wrong, I removed it. Since lines could be in any direction so 0 to 360 will be preferred. The arrows should go along the line, that's I bug I am seeking solution :) It is showing exact direction and goes along with the line in all other cases.Hofmannsthal
I would add debug printout showing the values of sourcePoint, destinationPoint, and arrowDirection.Microgroove
I tried printing values but I could not notice anything from it since it calculates right direction for all other MKPolylines. I have added more information to questionHofmannsthal
Looking closer at the values used for a calculation when something incorrect happens, is an important part of debugging. You must be able to notice something about how the wrong values are calculated.Microgroove
I found that this happens while Polyine crosses 180th meridian. This a problem with maps. Still looking for a solution.Hofmannsthal
Whereas I am still looking for data, so I can help you.Microgroove
Nice, but sourcePoint, destinationPoint (with x and y), and arrowDirection are the variables taking part in the calculation. Now SO suggests chat; I won't do that.Microgroove
gist.github.com/abin0992/ea1a49e02b4cbebbcfb9909faa69e0e8 The printed values are here. First 3 values are displayed correctly on mapview and the last bearing is the one calculated for the green polyline displayed on the image aboveHofmannsthal
I tried this answer. But now the arrows which were displayed correctly are showing wrong directions like thisHofmannsthal
The print values of coordinates and bearing for the above method gist.github.com/abin0992/04498b47c88c886d52b81943cfc996c6Hofmannsthal
H
0

I solved it in a dirty way by converting coordinate to CGPoint and then calculating bearing between Points.

let destinationPoint = mapView.convert(destination, toPointTo: nil)
let sourcePoint = mapView.convert(source, toPointTo: nil)

let bearing = atan2(sourcePoint.y - destinationPoint.y, sourcePoint.x - destinationPoint.x) - .pi

Caution: This calculation will go wrong when map is rotated

Hofmannsthal answered 30/5, 2018 at 11:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.