Trouble with CLLocation method distanceFromLocation: Inaccurate results

后端 未结 4 1223
天命终不由人
天命终不由人 2020-12-15 11:16

I am trying to use the distanceFromLocation: method to calculate the total distance that I am walking with my iPhone in my hand. So far, I have been searching all over to h

相关标签:
4条回答
  • 2020-12-15 11:22

    You are not setting the accuracy of your location manager. Go through apple docs, it is something like accuracy = bestfornavigation. or something. That should drain battery like hell but is meant for this kind of purposes.

    edit: just remembered i had it at hand.

    // Create the Location Manager
    locationManager = [[CLLocationManager alloc] init];
    
    // Configure the Location Manager
    locationManager.delegate = self;
    locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
    
    0 讨论(0)
  • 2020-12-15 11:35
    CLLocationDistance distance = [secondLocation distanceFromLocation:firstLocation];  // distance is expressed in meters
    
    CLLocationDistance kilometers = distance / 1000.0;
    // or you can also use this..
    CLLocationDistance meters = distance;
    
    NSString *distanceString = [[NSString alloc] initWithFormat: @"%f", kilometers];
    
    flot totaldistancecovered = [distanceString floatValue];
    
    //Now,you can use this float value for addition...
    // distanceMoved  should be float type variable which is declare in .h file...
    
     distanceMoved = distanceMoved + totaldistancecovered ;
     theLabel.text = [NSString stringWithFormat: @"%f meters", distanceMoved];
    

    Hope this will help you..

    0 讨论(0)
  • 2020-12-15 11:38
    1. Filter out cached (old) location data,
    2. Filter out invalid location results (accuracy < 0),
    3. Set accuracy requirement set to kCLLocationAccuracyBest,
    4. Set a minimum distance filter, preferably at least 10 meters to filter out position noise.
    5. EDIT: Don't compute distance when the oldLocation is nil.

    There's more you could do but this should work provided you get a good enough horizonalAccuracy (<30m). You could filter out low accuracy results but then you'd have to keep track of the oldLocation yourself which is a bit more complicated.

    Add an NSLog (see below) so you can find out what's happening. If you still don't get good results post the output of the NSLog so we can see what's going on and help more.

    -(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
    {
        NSTimeInterval age = -[newLocation.timestamp timeIntervalSinceNow]; 
    
        if (age > 120) return;    // ignore old (cached) updates
    
        if (newLocation.horizontalAccuracy < 0) return;   // ignore invalid udpates
    
        // EDIT: need a valid oldLocation to be able to compute distance
        if (oldLocation == nil || oldLocation.horizontalAccuracy < 0) return; 
    
        CLLocationDistance distance = [newLocation distanceFromLocation: oldLocation];
    
        NSLog(@"%6.6f/%6.6f to %6.6f/%6.6f for %2.0fm, accuracy +/-%2.0fm",
            oldLocation.coordinate.latitude,
            oldLocation.coordinate.longitude,
            newLocation.coordinate.latitude,
            newLocation.coordinate.longitude, 
            distance,
            newLocation.horizontalAccuracy);
    
        distanceMoved += distance;
        theLabel.text = [NSString stringWithFormat: @"%f meters", distanceMoved];
    }
    
    - (void)viewDidLoad
    {
       locMan = [[CLLocationManager alloc] init];
       locMan.delegate = self;
       locMan.desiredAccuracy = kCLLocationAccuracyBest;
       locMan.distanceFilter = 10;
    
       [locMan startUpdatingLocation];
       isInitial = true;
       distanceMoved = 0.0;
       [super viewDidLoad];
    }
    

    EDIT for iOS6 if you wanted to do the same using didUpdateLocations: (since the above method is now deprecated) the simplest solution is to simply save each location in a property so that on the next update you have the previous location. Declare an property in the class to hold the oldLocation:

    @property (nonatomic, retain) CLLocation* oldLocation;
    

    Then in the delegate method you save each newLocation for use as the oldLocation for the next time the delegate method is called:

    -(void)locationManager:(CLLocationManager *)manager didUpdateToLocations:(NSArray *)locations
    {
        CLLocation* newLocation = [locations lastObject];
    
        NSTimeInterval age = -[newLocation.timestamp timeIntervalSinceNow]; 
    
        if (age > 120) return;    // ignore old (cached) updates
    
        if (newLocation.horizontalAccuracy < 0) return;   // ignore invalid udpates
    
        // EDIT: need a valid oldLocation to be able to compute distance
        if (self.oldLocation == nil || self.oldLocation.horizontalAccuracy < 0) {
            self.oldLocation = newLocation;
            return; 
        }
    
        CLLocationDistance distance = [newLocation distanceFromLocation: self.oldLocation];
    
        NSLog(@"%6.6f/%6.6f to %6.6f/%6.6f for %2.0fm, accuracy +/-%2.0fm",
            self.oldLocation.coordinate.latitude,
            self.oldLocation.coordinate.longitude,
            newLocation.coordinate.latitude,
            newLocation.coordinate.longitude, 
            distance,
            newLocation.horizontalAccuracy);
    
        distanceMoved += distance;
        theLabel.text = [NSString stringWithFormat: @"%f meters", distanceMoved];
    
        self.oldLocation = newLocation;    // save newLocation for next time
    }
    
    0 讨论(0)
  • 2020-12-15 11:40

    The first thing you should do is discharge the first update by checking the timestamp of the first update you receive from the location manager, it usually caches the last known position. Second remember the accuracy, the initial values that you'll get are always in a wide range.

    0 讨论(0)
提交回复
热议问题