I'm trying to calculate distance between 2 coordinates. For this I do:
func setupLocationManager() {
if CLLocationManager.authorizationStatus() == .NotDetermined {
locationManager.requestWhenInUseAuthorization()
}
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingLocation()
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let latitude = locations.last?.coordinate.latitude
let longitude = locations.last?.coordinate.longitude
let myLocation = CLLocation(latitude: latitude!, longitude: longitude!)
let targetLocation = CLLocation(latitude: 41.4381022, longitude: 46.604910)
let distance = myLocation.distanceFromLocation(targetLocation)
print(distance)
}
I'm checking in Google Maps there are 13 km distance! But my app shows me 2-3 km!
How can I improve that?
Google maps gives you the route distance between two locations, CLLocation gives you the birds-eye distance between two locations.
From the documentation:
This method measures the distance between the two locations by tracing
a line between them that follows the curvature of the Earth. The
resulting arc is a smooth curve and does not take into account
specific altitude changes between the two locations.
Here is an example based on a working GPS app.
import CoreLocation
public class SwiftLocation: NSObject, CLLocationManagerDelegate {
private let locationManager = CLLocationManager()
private var latestCoord: CLLocationCoordinate2D
init(ignore:String) {
locationManager.requestAlwaysAuthorization()
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.distanceFilter = kCLDistanceFilterNone
locationManager.startUpdatingLocation()
latestCoord = locationManager.location!.coordinate
super.init()
locationManager.delegate = self
}
private func locationManager(manager: CLLocationManager, didUpdateToLocation newLocation: CLLocation, fromLocation oldLocation: CLLocation) {
latestCoord = manager.location!.coordinate
}
public func getLatest() -> CLLocationCoordinate2D {
return latestCoord
}
}
Related
I am making app where I need to get live coordinates of user and upload the newest coordinates every x minutes. I've been struggling with it for last few hours, and tried almost everything and checked all threads available and still don't have the answer.
Here is my code:
class LocationService: NSObject, ObservableObject, CLLocationManagerDelegate {
#Published var location: CLLocation?
#Published var locationManager = CLLocationManager()
init(searchCompleter: MKLocalSearchCompleter = MKLocalSearchCompleter()) {
super.init()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.distanceFilter = CLLocationDistanceMax
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
}
}
extension LocationService {
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.first else { return }
self.location = location
print(location.coordinate)
}
}
extension MKCoordinateRegion {
static func goldenGateRegion() -> MKCoordinateRegion {
MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 37.819527098978355, longitude: -122.47854602016669), latitudinalMeters: 10, longitudinalMeters: 10)
}
func getBinding() -> Binding<MKCoordinateRegion>? {
return Binding<MKCoordinateRegion>.constant(self)
}
}
I am calling this function on main view:
.onChange(of: locationService.location) { newValue in
print(newValue?.coordinate ?? "error")
}
And I am getting same coordinates for the whole time, (I picked driveway location option in simulator).
I want to save a set of latitude and longitude coordinates to Firebase, but whenever my app runs through this code it crashes!
let userID: String = (FIRAuth.auth()?.currentUser?.uid)!
let lat: Double = (locationManager.location?.coordinate.latitude)!
let lon: Double = (locationManager.location?.coordinate.longitude)!
self.ref.child("Location").child(userID).setValue(["Latitude": lat, "Longitude": lon])
Is there anyway I can fix this and save it properly and efficiently?
Make sure of two things :-
1.) your viewController inherits from CLLocationManagerDelegate and has its delegate set to self in viewDidLoad
2.) your info.plist has these keys added to them :-
NSLocationAlwaysUsageDescription --- I need Location
NSLocationWhenInUseUsageDescription --- I need Location
privacy - location usage description --- I need Location
class MapViewController: UIViewController , CLLocationManagerDelegate...{
...
..
let locationManager = CLLocationManager()
func viewDidLoad(){
super.viewDidLoad()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.distanceFilter = kCLDistanceFilterNone
locationManager.requestWhenInUseAuthorization()
locationManager.startMonitoringSignificantLocationChanges()
locationManager.startUpdatingLocation()
}
//Call these functions for updating the getting the values of current location
func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
if status == .AuthorizedWhenInUse {
print("authorised call came . . . . ")
mapView.myLocationEnabled = true
}
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let location = locations.first {
print("target position : = \(location.coordinate)")
print(locationManager.location!.coordinate.latitude)
mapView.camera = GMSCameraPosition(target: location.coordinate, zoom: 15, bearing: 0, viewingAngle: 0)
locationManager.stopUpdatingLocation()
self.FIRDatabase.database().reference().child("Location").child(FIRAuth.auth()!.currentUser!.uid).setValue(["Latitude": locationManager.location!.coordinate.latitude, "Longitude": locationManager.location!.coordinate.longitude])
}
}
}
I would like to know how to check if person is near some coordinates and then do something like say hello into console for testing. Right now I have already got user location and it is going to update every time person moves but how to know if he is near some coordinates or address? For example:
func sayHello(){
if mapView.userLocation.coordinate.latitude == 26{
print("Hello")
}
Code I've done already:
import UIKit
import MapKit
import CoreLocation
class ViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
#IBOutlet weak var mapView: MKMapView!
let locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.requestAlwaysAuthorization()
self.locationManager.startUpdatingLocation()
self.mapView.showsUserLocation = true
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation])
{
let location = locations.last
let center = CLLocationCoordinate2D(latitude: location!.coordinate.latitude, longitude: location!.coordinate.longitude)
let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01))
self.mapView.setRegion(region, animated: true)
self.locationManager.stopUpdatingLocation()
}
func locationManager(manager: CLLocationManager, didFailWithError error: NSError)
{
print("Errors: " + error.localizedDescription)
}
}
What I would do is every time you update the user's location, check the distance between your user's location and the address location(s) you have stored. If the user is within x meters, print "Hello".
Below is code I would use to get the distance between your user and the address. If you have an array of objects that contain your addresses and their coordinates you could loop through each address and print Hello for each address that is within x meters.
let userLocation:CLLocation = CLLocation(latitude: 10.000, longitude: 29.000)
let addressLocation:CLLocation = CLLocation(latitude: 15.000, longitude: 20.000)
let meters:CLLocationDistance = userLocation.distanceFromLocation(addressLocation)
Get the distance between two coordinates and match if its less than 5m than show print statement
CLLocation *locA = [[CLLocation alloc] initWithLatitude:lat1 longitude:long1];
CLLocation *locB = [[CLLocation alloc] initWithLatitude:lat2 longitude:long2];
CLLocationDistance distance = [locA distanceFromLocation:locB];
So I am trying to do 3 things.
Have a map which shows my location.
Map should be slightly slanted to give a 3d feel; same like when we scroll up and down with 2 fingers on apple map.
Use compass to rotate the map.
I have enabled userTrackingMode on the map and the map rotates with compass but if I set a MKMapCamera on the map the compass won't work.
Here is my code.
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
mapView.setUserTrackingMode(.FollowWithHeading, animated: true)
locationManager.startUpdatingLocation()
}
func locationManager(manager: CLLocationManager, didUpdateToLocation newLocation: CLLocation, fromLocation oldLocation: CLLocation) {
let userCordinate = CLLocationCoordinate2D(latitude: newLocation.coordinate.latitude, longitude: newLocation.coordinate.longitude)
let eyeCordinate = CLLocationCoordinate2D(latitude: newLocation.coordinate.latitude - 0.021078, longitude: newLocation.coordinate.longitude - 0.04078 )
let mapCamera = MKMapCamera(lookingAtCenterCoordinate: userCordinate, fromEyeCoordinate: eyeCordinate, eyeAltitude: 1400)
mapView.setCamera(mapCamera, animated: true)
print("Camera set")
}
What am I doing wrong here?
You have to update the heading of the camera with the compass. Here's something that I'm currently using:
func locationManager(_ manager: CLLocationManager, didUpdateHeading newHeading: CLHeading) {
self.mapView.camera.heading = newHeading.trueHeading
}
I am building a location based app. Is there anyway to make the location I am getting through CLLocationManager more accurate?
I need to make sure the accuracy is within 50 meters.
Here is my code so far:
func startSignificantChangeUpdates(){
if (locationManager.respondsToSelector(Selector("requestWhenInUseAuthorization"))) {
locationManager.requestWhenInUseAuthorization()
}else {
locationManager.startUpdatingLocation()
}
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
location = locationManager.location
}
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
if let newLocation = locations.last as? CLLocation {
//Lets not bother if the location is less than 500 meters
let oldLocation = location
location = newLocation
var distance = oldLocation?.distanceFromLocation(newLocation)
if distance > 500 {
NSNotificationCenter.defaultCenter().postNotificationName("location", object: self)
}
if distance > 50 {
NSNotificationCenter.defaultCenter().postNotificationName("imatlocation", object: self)
}
}
}
For accuracy of the returned location you need to check the horizontalAccuracy of the location, that will give you the radius of uncertainty for the location (in meters) you can then decide to act on or reject the location based on how accurate it is.
You can change your desired accuracy to use
kCLLocationAccuracyBest