Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set custom distance Filter , is it possible in Swift?

Tags:

ios

swift

mapkit

I am new to Swift and i try with this one

How to set accuracy and distance filter when using MKMapView

Don't know why this code not working :

//start  mehtod out of scope
lazy var locationManager: CLLocationManager! = {
    let locationManager = CLLocationManager()


    //configeration for  user location access
    //The delegate object to receive update events.
    locationManager.delegate = self
    //The receiver does its best to achieve the requested accuracy
    //locationManager.desiredAccuracy = kCLLocationAccuracyBest
     self.locationManager.distanceFilter = 10.0
    //Requests permission to use location services while the app is in the foreground
    locationManager.requestWhenInUseAuthorization()
    //allow update notification when apps stay on background
    locationManager.allowsBackgroundLocationUpdates = true

    return locationManager
}() 

it is working fine when i seting :

locationManager.desiredAccuracy = kCLLocationAccuracyBest

So what am i want :

I want to get LAT and LONG after each 250 meter if user change her positioning then continuously 15 minutes call a method

 pushLocation(lat:double,long:double)
like image 266
cristan lika Avatar asked Feb 05 '23 13:02

cristan lika


2 Answers

Here's the code I'm using - all in Swift 3.0.

This setup of the locationManager will take care of the distance filtering and accuracy that you're after:

lazy var locationManager: CLLocationManager = {
    [unowned self] in
    var _locationManager = CLLocationManager()
    _locationManager.delegate = self
    _locationManager.desiredAccuracy = [Your Value For trackingAccuracy - see below]
    _locationManager.distanceFilter = [Your Value For the filter i.e., 250 for 250 meters]
    _locationManager.allowsBackgroundLocationUpdates = true
    _locationManager.pausesLocationUpdatesAutomatically = false 
    _locationManager.activityType = .fitness
    return _locationManager
    }()

The accuracy setting would be from the predefined set in location manager, e.g., kCLLocationAccuracyNearestTenMeters or kCLLocationAccuracyHundredMeters.

The option to allow background updates lets you get new points even if your app is not in the foreground. Turning off pauses automatically is necessary if the phone will stop moving from time to time - otherwise, it will automatically turn off capture if your user stops to rest for 5 minutes and won't turn it back on - you must reset these when you're done.

Authorization status should be dealt with in a separate check as follows so that you can request authorization if it's not already given:

    if CLLocationManager.authorizationStatus() != .authorizedAlways     // Check authorization for location tracking
    {
        locationManager.requestAlwaysAuthorization()                    // Will callbackdidChange... once user responds
    } else {
        locationManager.startUpdatingLocation()
    }

Since there's a delay in getting authorization, if you have to make the request you'll need to wait to request it to start updating locations until you hear back from the locationManager, which you can do as follows:

@nonobjc func locationManager(manager: CLLocationManager!, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
    switch status
    {
    case .authorizedAlways:
        locationManager.startUpdatingLocation()

    default:
        [Whatever you want to do - you can't get locations]
    }
}

I need .authorizedAlways, you may be able to get away with .authorizedWhenInUse depending on your use case.

I add an additional filter for accuracy based on checking the accuracy fields in the positions passed back to me by the locationManager. Note that there's separate horizontal and vertical accuracy values (confidence distance in meters); if you want to use the elevation value you need to pay attention to the second accuracy value as elevation is inherently less accurate in an iPhone.

I also check that the new point was captured after the previous point - out of sequence values come through sometimes and indicate "troubled" values. I've read that you may get accuracy values less than 0 to indicate problems, so you may want to check for that before using the position, though I haven't seen that issue. Here's the code:

// Called back by location manager - passes arrays of new CLLocation points captured. With distanceFilter set to 250, this will get called for a change of 250M.  You'll want to save the value for your timed pushLocation function.

// This function needs to be trim as it continues to be called when TrailHead is in the background and, if 
// we take too long we'll get killed by iOS.

var savePosition: CLLocationCoordinate2D?
private var latestTimeProcessed = Date()  // Initialize to ensure any point accepted received after initialization

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation])
{
    for location in locations {
        if latestTimeProcessed.compare(location.timeStamp) == .orderedAscending        // Out of seq indicates a locationManager problem - discard
            && location.horizontalAccuracy < [Whatever accuracy limit you want to use]    // Applying a user-selected quality filter
        {
            latestTimeProcessed = location.timeStamp      // Used to discard any earlier timestamped points returned by the location manager
            [PROCESS THE POSITION HERE - E.G.]

            savePosition = locations.last

        }
    }
}

As far as doing the push updates, I'd add a timer

private var myTimer: Timer? = nil  
private var longInterval = 900.0     // 900 seconds = 15 minutes

override func viewDidLoad()
{
    ....
        myTimer = Timer(timeInterval: timerInterval, target: myself, selector: #selector(myself.pushLocation), userInfo: nil, repeats: true)
        RunLoop.current.add(myTimer!, forMode: RunLoopMode.commonModes)
    ....
}

pushLocation(lat:double,long:double){
    [Use savePosition.latitude, savePosition.longitude]
}

Hope this helps...

like image 195
Ron Diel Avatar answered Mar 29 '23 17:03

Ron Diel


As per your question , you want to get LAT and LONG after each 250 meter ? So for this Here is Objective C Code : (Thanks to Link :https://stackoverflow.com/a/39996989/3400991)

First of All Call This method and store this New location and then you need to continuously find other lat and long when any (LAT , LONG) matches with this stored Location then it means you have travelled 250 meter :

Here is SWIFT3.0 Code :

func locationByMovingDistance(distanceMeters: Double, withBearing bearingDegrees: CLLocationDirection) -> CLLocation {
    let distanceRadians: Double = distanceMeters / (6372797.6)
        // earth radius in meters
    let bearingRadians: Double = bearingDegrees * M_PI / 180
    var lat1: Float = self.coordinate.latitude * M_PI / 180
    var lon1: Float = self.coordinate.longitude * M_PI / 180
    var lat2: Float = asin(sin(lat1) * cos(distanceRadians) + cos(lat1) * sin(distanceRadians) * cos(bearingRadians))
    var lon2: Float = lon1 + atan2(sin(bearingRadians) * sin(distanceRadians) * cos(lat1), cos(distanceRadians) - sin(lat1) * sin(lat2))
    return CLLocation(latitude: lat2 * 180 / M_PI, longitude: lon2 * 180 / M_PI)
}

Feel Free to post comment if you have any further issue. Hope it helps.

like image 27
Shobhakar Tiwari Avatar answered Mar 29 '23 18:03

Shobhakar Tiwari