Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

I want to find Qibla Direction (simple compass for direction) in Swift

All code works well but it does not give required result. The direction needle does not move to the perfect location. Sometimes it works, sometimes not.

func DegreesToRadians (value:Double) -> Double {
    return value * M_PI / 180.0
}

func RadiansToDegrees (value:Double) -> Double {
    return value * 180.0 / M_PI
}

class ViewController: UIViewController , CLLocationManagerDelegate {
    var needleAngle : Double?

    //Main Composs
    @IBOutlet weak var composs: UIImageView!

    //Needle Move with respect to compose
    @IBOutlet weak var needle: UIImageView!

    @IBOutlet weak var mapView: MKMapView!

    // Kabhalocation 
    var kabahLocation : CLLocation?
    var latitude  : Double?
    var longitude : Double?
    var distanceFromKabah : Double?

    let locationManger = CLLocationManager()

    override func viewDidLoad() {
        super.viewDidLoad()

        //KabhaLocation Hardcoded.
        kabahLocation = CLLocation(latitude: 21.42 , longitude: 39.83)

        //Delegate
        self.locationManger.delegate = self
        self.locationManger.desiredAccuracy = kCLLocationAccuracyBest
        if #available(iOS 8.0, *) {
            self.locationManger.requestAlwaysAuthorization()
        } else {
            // Fallback on earlier versions
        }

        self.locationManger.startUpdatingLocation()
        self.locationManger.startUpdatingHeading()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    // Mark: - LocationManger Delegate

    func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        let location = locations.last
 let center = CLLocationCoordinate2D(latitude: (location?.coordinate.latitude)!, longitude: (location?.coordinate.longitude)!)
        print("current location latitude \((location?.coordinate.latitude)!) and longitude \((location?.coordinate.longitude)!)")

        self.latitude = location?.coordinate.latitude
        self.longitude = location?.coordinate.longitude
//
//        self.latitude = 31.5497
//        self.longitude = 74.3436

        self.locationManger.startUpdatingLocation()

        needleAngle     = self.setLatLonForDistanceAndAngle(location!)
    }

    func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
        print("Error " + error.localizedDescription)
    }

    func setLatLonForDistanceAndAngle(userlocation: CLLocation) -> Double
    {
        let lat1 = DegreesToRadians(userlocation.coordinate.latitude)
        let lon1 = DegreesToRadians(userlocation.coordinate.longitude)
        let lat2 = DegreesToRadians(kabahLocation!.coordinate.latitude)
        let lon2 = DegreesToRadians(kabahLocation!.coordinate.longitude)

        distanceFromKabah = userlocation.distanceFromLocation(kabahLocation!)
        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*M_PI;
        }
//        print("Initial Bearing \(radiansBearing*180/M_PI)")

        let distanceFromKabahUnit  = 0.0

        return radiansBearing
    }

    func locationManager(manager: CLLocationManager, didUpdateHeading newHeading: CLHeading) {
        let needleDirection   = -newHeading.trueHeading;
        let compassDirection  = -newHeading.magneticHeading;

        self.needle.transform = CGAffineTransformMakeRotation(CGFloat(((Double(needleDirection) ) / 180.0) + needleAngle!))
        print("Needle \(CGAffineTransformMakeRotation(CGFloat(((Double(needleDirection) ) / 180.0) + needleAngle!)))")
        self.composs.transform = CGAffineTransformMakeRotation(CGFloat((Double(compassDirection) ) / 180.0))
        print("composs \(CGAffineTransformMakeRotation(CGFloat((Double(compassDirection) ) / 180.0)))")
    }

    override func viewDidAppear(animated: Bool) {
        needleAngle = 0.0
        self.locationManger.startUpdatingHeading()
        kabahLocation = CLLocation(latitude: 21.42 , longitude: 39.83)
        self.locationManger.delegate = self

    }

    override func viewDidDisappear(animated: Bool) {
        self.locationManger.delegate = nil
    }
like image 787
Muhammad Rizwan Anjum Avatar asked Sep 24 '16 11:09

Muhammad Rizwan Anjum


Video Answer


2 Answers

Actually what you are doing wrong here is making the compass rotate in didLocationChange method. Actually you need to have the rotation according to True north of Earth and for that you need to use didUpdateLocationHeader .This gives you the readings according to true north of Earth. I am posting my code below. You can also find a full working project on my github

import UIKit

import CoreLocation

class ViewController: UIViewController ,CLLocationManagerDelegate{

@IBOutlet weak var ivCompassBack: UIImageView!
@IBOutlet weak var ivCompassNeedle: UIImageView!

let latOfKabah = 21.4225
let lngOfKabah = 39.8262

var location: CLLocation?

let locationManager = CLLocationManager()


var bearingOfKabah = Double()

override func viewDidLoad() {

    super.viewDidLoad()
    initManager()

}


func initManager(){

    locationManager.requestAlwaysAuthorization()

    locationManager.requestWhenInUseAuthorization()

    if CLLocationManager.locationServicesEnabled() {

        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
        locationManager.startUpdatingLocation()
        locationManager.startUpdatingHeading()

    }
}

func locationManager(_ manager: CLLocationManager, didUpdateHeading heading: CLHeading) {


    let north = -1 * heading.magneticHeading * Double.pi/180

    let directionOfKabah = bearingOfKabah * Double.pi/180 + north

    ivCompassBack.transform =   CGAffineTransform(rotationAngle: CGFloat(north));

    ivCompassNeedle.transform =       CGAffineTransform(rotationAngle: CGFloat(directionOfKabah));


}

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {

    let newLocation = locations.last!

    location = newLocation

    bearingOfKabah = getBearingBetweenTwoPoints1(location!, latitudeOfKabah: self.latOfKabah, longitudeOfKabah: self.lngOfKabah) //calculating the bearing of KABAH
}


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


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

func getBearingBetweenTwoPoints1(_ point1 : CLLocation, latitudeOfKabah : Double , longitudeOfKabah :Double) -> Double {

    let lat1 = degreesToRadians(point1.coordinate.latitude)
    let lon1 = degreesToRadians(point1.coordinate.longitude)

    let lat2 = degreesToRadians(latitudeOfKabah);
    let lon2 = degreesToRadians(longitudeOfKabah);

    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 radiansToDegrees(radiansBearing)
}

}
like image 99
osama Avatar answered Sep 30 '22 03:09

osama


//
//  ViewController.swift
//  CurrentLocation
//
//  Created by Muhammad Rizwan Anjum on 26/8/16.
//  Copyright © 2016 Muhammad Rizwan Anjum. All rights reserved.
//

import UIKit
import MapKit
import CoreLocation

func DegreesToRadians (value:Double) -> Double {
    return value * M_PI / 180.0
}

func RadiansToDegrees (value:Double) -> Double {
    return value * 180.0 / M_PI
}

class ViewController: UIViewController , CLLocationManagerDelegate {

    var needleAngle : Double?

    @IBOutlet weak var composs: UIImageView!
    @IBOutlet weak var needle: UIImageView!
    @IBOutlet weak var mapView: MKMapView!
    var kabahLocation : CLLocation?
    var latitude  : Double?
    var longitude : Double?
    var distanceFromKabah : Double?

    let locationManger = CLLocationManager()

    override func viewDidLoad() {
        super.viewDidLoad()
        kabahLocation = CLLocation(latitude: 21.42 , longitude: 39.83)

        self.locationManger.delegate = self
        self.locationManger.desiredAccuracy = kCLLocationAccuracyBest
        if #available(iOS 8.0, *) {
            self.locationManger.requestAlwaysAuthorization()
        } else {
            // Fallback on earlier versions
        }

        self.locationManger.startUpdatingLocation()
        self.locationManger.startUpdatingHeading()

    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    // Mark: - LocationManger Delegate

    func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        let location = locations.last
//        let center = CLLocationCoordinate2D(latitude: (location?.coordinate.latitude)!, longitude: (location?.coordinate.longitude)!)
        print("current location latitude \((location?.coordinate.latitude)!) and longitude \((location?.coordinate.longitude)!)")

        self.latitude = location?.coordinate.latitude
        self.longitude = location?.coordinate.longitude
//
//        self.latitude = 31.5497
//        self.longitude = 74.3436
        self.locationManger.startUpdatingLocation()
        needleAngle     = self.setLatLonForDistanceAndAngle(location!)

    }
    func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
        print("Error " + error.localizedDescription)
    }

    func setLatLonForDistanceAndAngle(userlocation: CLLocation) -> Double
    {
        let lat1 = DegreesToRadians(userlocation.coordinate.latitude)
        let lon1 = DegreesToRadians(userlocation.coordinate.longitude)
        let lat2 = DegreesToRadians(kabahLocation!.coordinate.latitude)
        let lon2 = DegreesToRadians(kabahLocation!.coordinate.longitude)

        distanceFromKabah = userlocation.distanceFromLocation(kabahLocation!)
        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*M_PI;
        }
//        print("Initial Bearing \(radiansBearing*180/M_PI)")
        let distanceFromKabahUnit  = 0.0



        return radiansBearing

    }

    func locationManager(manager: CLLocationManager, didUpdateHeading newHeading: CLHeading) {

        let needleDirection   = -newHeading.trueHeading;
        let compassDirection  = -newHeading.magneticHeading;

//you Need to Multiply With M_PI

        self.needle.transform = CGAffineTransformMakeRotation(CGFloat(((Double(needleDirection) * M_PI) / 180.0) + needleAngle!))
        print("Needle \(CGAffineTransformMakeRotation(CGFloat(((Double(needleDirection) * M_PI) / 180.0) + needleAngle!)))")
        self.composs.transform = CGAffineTransformMakeRotation(CGFloat((Double(compassDirection) * M_PI) / 180.0))
        print("composs \(CGAffineTransformMakeRotation(CGFloat((Double(compassDirection) * M_PI) / 180.0)))")
    }

    override func viewDidAppear(animated: Bool) {
        needleAngle = 0.0
        self.locationManger.startUpdatingHeading()
        kabahLocation = CLLocation(latitude: 21.42 , longitude: 39.83)
        self.locationManger.delegate = self

    }
    override func viewDidDisappear(animated: Bool) {
        self.locationManger.delegate = nil
    }




}
like image 28
Rizwan anjum Avatar answered Sep 30 '22 02:09

Rizwan anjum