0
votes

I am integrating Mapbox iOS SDK into my app. Right now I am stuck at a point where I want to achieve car tracking feature like Uber app.

I used to have that feature with Google Maps SDK but I cant make it work with Mapbox SDK.

I am adding MGLPointAnnotation object to add it on map and want to move it from point A to point B with animation.

I am doing it using

UIView.animate(withDuration: TimeInterval(duration), animations: {
    // Update annotation coordinate to be the destination coordinate
    point.coordinate = newCoordinate
}, completion: nil)

But for MGLPointAnnotation I can't change its image because when there's a turn I want to rotate the image(Annotation).

If I use MGLAnnotationView object I can change the image but I cant change its coordinate because its readonly.

What should I do here to achieve that functionality?

1
As I know point changes its position animated by default, you need to rotate image of your marker - Alexandr Kolesnik
Changing the position is not a problem. I want to rotate marker's image after its added on map view, which I can't do it when I am using MGLPointAnnotation object. - Paras Gorasiya
I think you need marker.rotation property - Alexandr Kolesnik
The annotation might not be a UIView object but a layer instead. Try CATransition begin and commit instead. - Robin
@AlexandrKolesnik Can you elaborate? - Paras Gorasiya

1 Answers

0
votes

Several years ago I wrote smth similar, I used GoggleMaps, look through the code, maybe it will be helpful, I really don't remember what are all that numbers in angle counting

    extension Double {

    var degrees: Double {
        return self * 180.0 / Double.pi
    }

}


extension CLLocationCoordinate2D {

    func angleToPosition(position : CLLocationCoordinate2D) -> CLLocationDegrees {
        let bearingRadians = atan2(Double(position.latitude - latitude), Double(position.longitude - longitude))
        var bearingDegrees = bearingRadians.degrees
        //        print("\(bearingDegrees)")
        var roundDegrees = 360.0
        if bearingDegrees < 0 {
            if bearingDegrees > -90 {
                roundDegrees = 350
            }
            if bearingDegrees < -90 && bearingDegrees > -180 {
                roundDegrees = 370
            }
            bearingDegrees += roundDegrees
            return 360 - bearingDegrees
        }
        roundDegrees = bearingDegrees < 90 ? 350 : 360
        if bearingDegrees > 90 && bearingDegrees < 180 {
            roundDegrees = 370
        }
        UserDefaults.standard.set(bearingDegrees, forKey: "bearingDegrees")
        return roundDegrees - bearingDegrees
    }

    func duration(toDestination destination: CLLocationCoordinate2D, withSpeed speed : Double) -> Double {
        let distance = GMSGeometryDistance(self, destination)
        return distance / (speed * (1000 / 3600))
    }

}

And this is the func which do the rotation, you can use it as soon as you receive new coordinates, or call it in for loop if you have certain polyline

func animateCarDrive(info: [String: Any]) {
    let speed = info["speed"] as? Double ?? 40 // if your car's speed is changeable
    let position = info["position"] as? CLLocationCoordinate2D // new point position
    let duration = marker.position.duration(toDestination: position, withSpeed: speed)
    marker.rotation = marker.position.angleToPosition(position: position)
    CATransaction.begin()
    CATransaction.setAnimationDuration(duration)
    marker.position = position
    CATransaction.commit()
}