3

enter image description here

I have a live tracking application, where I am tracking vehicles. I am getting vehicle position in every 10 seconds and moving vehicle car icon on map with animation like Uber, Ola.

My animation is running good but problem is on car MKAnnotation heading. How to change heading of car when every time my car position is changing?

I am using apple mapkit with swift and not having good knowledge of ObjectiveC.

MyViewConroller code is here

import UIKit
import Alamofire
import SwiftyJSON
import MapKit
import SwiftLoader

class LiveTrackingVC: UIViewController , MKMapViewDelegate{


    //Outlets
    @IBOutlet weak var deviceNameLAble:  UILabel!
    @IBOutlet weak var myNavigation:  UINavigationItem!
    @IBOutlet weak var mapView:  MKMapView!
    @IBOutlet weak var lbAddress:  UILabel!
    @IBOutlet weak var lbDistance:  UILabel!
    @IBOutlet weak var lbAssestSpeed:  UILabel!


    // Classes Objects
    let session = XSession()
    var assestID = String().self

    var lastPosition : CLLocationCoordinate2D?
    var livePosition : CLLocationCoordinate2D?


    var pointAnnotation   :  CarCustomeAnnotation!
    var pinAnnotationView : MKAnnotationView!
    let reuseIdentifier = "pin"


    var timer =  Timer()

    @IBAction func finish(_ sender: UIBarButtonItem) {

    self.dismiss(animated: true, completion: nil)
        self.timer.invalidate()
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        mapView.delegate = self
        pointAnnotation = CarCustomeAnnotation()
         liveAPI()
        timer.invalidate()
        timer = Timer.scheduledTimer(timeInterval: 5, target: self, selector: #selector(liveAPI), userInfo: nil, repeats: true)

        self.mapView.isRotateEnabled = false
    }


    /*
     Get live data from server
     with assest ID.
     */


    @objc func liveAPI() {
      //  print(self.session.getData(XConstant.webURL)+"/livestatus_new")
        MyCall().call(WithRequest: XSApi.liveTracking(assestID), AndSuccessHandler: {
            response in

            SwiftLoader.hide()
            let code = response?[API.SUCCESS].intValue
            if(code == API.OK)
            {

                // Here is getting vehcile latest location data
                self.handleLiveApi(listData: response![API.DATA].dictionaryValue)

            }

        })
          {(response, error) in

            print("Error")
        }
    }


       /*
       Live Tracking respone Handle
       */
    func handleLiveApi(listData : Dictionary<String, JSON>)
    {

        self.lbDistance.text = listData["mileAge"]?.stringValue
        let time = "".convertDateFormatter(date: (listData["DeviceTime"]?.stringValue)! )
        self.myNavigation.title    =  time
        self.deviceNameLAble.text  =  listData["DisplayName"]?.stringValue
        let speed                  =  (listData["Speed"]?.stringValue)!
        self.lbAssestSpeed.text    =  speed + " km/h"


        livePosition               =  CLLocationCoordinate2DMake(Double((listData["Latitude"]?.stringValue)!)!, Double((listData["Longitude"]?.stringValue)!)!)

        pointAnnotation.pinCustomImageName = "ic_car_map"
        if(lastPosition != nil )
        {
        pointAnnotation.courseDegrees = Double((lastPosition?.bearingToLocationDegrees(destinationLocation: livePosition!))!)
        }
         pinAnnotationView = MKAnnotationView(annotation: pointAnnotation, reuseIdentifier: reuseIdentifier)
        mapView.addAnnotation(pinAnnotationView.annotation!)
          if( lastPosition != nil)
        {

         pinAnnotationView.transform = CGAffineTransform(rotationAngle: CGFloat(pointAnnotation.courseDegrees))

         self.moveCar(self.livePosition!)

        }else{

            pointAnnotation.coordinate = livePosition!
           self.zoomMap(lat: (livePosition?.latitude)!,lng: (livePosition?.longitude)!)
        }

        lastPosition = livePosition



    }

    func zoomMap(lat:Double,lng:Double)  {

        let location = CLLocation(latitude: lat, longitude: lng)
        let coordinateRegion = MKCoordinateRegionMakeWithDistance(location.coordinate,
                                                                  1500 * 2.0, 1500 * 2.0)
        self.mapView.setRegion(coordinateRegion, animated: true)

    }



    //--------------------------------------------------
    //MARK:
    //MARK: - Custom Methods
    //--------------------------------------------------

    func degreesToRadians(degrees: Double) -> Double { return degrees * .pi / 180.0 }

    func radiansToDegrees(radians: Double) -> Double { return radians * 180.0 / .pi }

    func getHeadingForDirectionFromCoordinate (_ fromLoc : CLLocationCoordinate2D , toLoc : CLLocationCoordinate2D) -> Double {

        let  fLat = degreesToRadians(degrees: fromLoc.latitude)
        let  fLng = degreesToRadians(degrees: fromLoc.longitude)
        let  tLat = degreesToRadians(degrees: toLoc.latitude)
        let  tLng = degreesToRadians(degrees: toLoc.latitude)

        let degree = radiansToDegrees(radians: atan2(sin(tLng-fLng) * cos(tLat), cos(fLat)*sin(tLat)-sin(fLat)*cos(tLat)*cos(tLng-fLng)))
        if (degree >= 0) {
            return degree
        } else {
            return 360.0 + degree
        }
    }



    func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) ->
        MKAnnotationView? {
        var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: reuseIdentifier)
        if annotationView == nil {
            annotationView = MKAnnotationView(annotation: annotationView?.annotation, reuseIdentifier: reuseIdentifier)
            annotationView?.canShowCallout = false
        } else {
            annotationView?.annotation = annotation
            annotationView?.canShowCallout = false
        }
        annotationView?.image = UIImage.init(named:pointAnnotation.pinCustomImageName)




        return annotationView
    }


    //Inert Animation Duration and Destination Coordinate which you are getting from server.
    func  moveCar(_ destinationCoordinate : CLLocationCoordinate2D) {
        UIView.animate(withDuration: 10, animations: {
            self.pointAnnotation.coordinate = destinationCoordinate


        }, completion: nil) }




}


public extension CLLocationCoordinate2D {
    func bearingToLocationRadian(_ destinationLocation: CLLocationCoordinate2D) -> CGFloat {




        let lat1 = self.latitude.degreesToRadians
        let lon1 = self.longitude.degreesToRadians

        let lat2 = destinationLocation.latitude.degreesToRadians
        let lon2 = destinationLocation.longitude.degreesToRadians

        let dLon = lon2 - lon1

        let y = sin(dLon) * cos(lat2)
        let x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(dLon)
        var radiansBearing = atan2(y, x)
        if(radiansBearing < 0.0)
        {
            radiansBearing += 2*Double.pi;
        }
        return CGFloat(radiansBearing)
    }

    func bearingToLocationDegrees(destinationLocation: CLLocationCoordinate2D) -> CGFloat {
        return CGFloat(Double(bearingToLocationRadian(destinationLocation)).radiansToDegrees)
    }
}

CarCustomeAnnotation

import UIKit import MapKit

class CarCustomeAnnotation: MKPointAnnotation
{
    var pinCustomImageName:String!
    var courseDegrees : Double! // Change The Value for Rotating Car Image Position
 } 
Deepak Ror
  • 2,084
  • 2
  • 20
  • 26
  • This is too much code to ask us to go through, but this is the approach that I proposed when someone had a similar question: https://stackoverflow.com/a/33464788/1271826. The basic idea is to have a `dynamic` "angle" property in the annotation, and have the annotation view "observe" that property, resulting in updating the angle of the annotation view automatically when the "angle" of the annotation changes. – Rob Jan 25 '18 at 06:39

0 Answers0