2012-04-17 13 views
9

Sto provando a utilizzare distanceFromLocation: metodo per calcolare la distanza totale che sto percorrendo con il mio iPhone in mano. Finora, ho cercato dappertutto per aiutare a rimediare ai miei risultati confusi, inaccurati e apparentemente arbitrari. In questi frammenti di codice, theLabel è solo un oggetto etichetta che è presente nell'interfaccia della mia app, distanceMoved è la variabile che sto cercando di memorizzare la distanza totale in cui sono entrato e locMan è un gestore di posizione dichiarato nel mio file @interface .Problemi con il metodo CLLocation distanceFromLocation: risultati imprecisi

- (void)viewDidLoad 
{ 
    locMan = [[CLLocationManager alloc] init]; 
    locMan.delegate = self; 
    [locMan startUpdatingLocation]; 
    isInitial = true; 
    distanceMoved = 0.0; 
    [super viewDidLoad]; 
} 

-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation 
{ 
    distanceMoved += [newLocation distanceFromLocation: oldLocation]; 
    theLabel.text = [NSString stringWithFormat: @"%f meters", distanceMoved]; 
} 

Qualsiasi aiuto per fissare quello che sto facendo male qui sarebbe molto apprezzato. Grazie!

risposta

13
  1. filtrare cache (vecchi) dati di posizione,
  2. filtrare validi spilli risultati (accuratezza < 0),
  3. Set requisito precisione impostato kCLLocationAccuracyBest,
  4. impostare un filtro distanza minima, preferibilmente almeno 10 metri per filtrare il rumore di posizione.
  5. MODIFICA: Non calcolare la distanza quando lo oldLocation è nullo.

C'è altro che si può fare, ma questo dovrebbe funzionare a condizione di avere una buona orizonalità orizzontale (< 30m). Puoi filtrare i risultati di bassa precisione, ma dovresti tenere traccia della vecchia posizione, che è un po 'più complicata.

Aggiungi un NSLog (vedi sotto) in modo da poter scoprire cosa sta succedendo. Se non ottieni ancora buoni risultati, pubblica l'output di NSLog in modo che possiamo vedere cosa sta succedendo e aiutare di più.

-(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 per iOS6 se si voleva fare lo stesso usando didUpdateLocations: (in quanto il metodo di cui sopra è ora sconsigliato) la soluzione più semplice è quello di salvare semplicemente ogni posizione in una proprietà in modo che il prossimo aggiornamento si dispone la posizione precedente.Dichiarare una proprietà nella classe per tenere la oldLocation:

@property (nonatomic, retain) CLLocation* oldLocation; 

Poi nel metodo delegato di salvare ogni newLocation per l'uso come oldLocation per la prossima volta il metodo delegato si chiama:

-(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

Ho appena usato questo codice esatto, ma ho modificato il filtro della distanza su 1. Per qualche ragione, la mia distanza spostata inizia a -1. Ecco la mia uscita dopo aver camminato a circa 2m avanti: 2012-04-17 17: 58: 05.341 LocationManagerTest2 [422: 707] 0,000000/0,000000 a 39,856110/-74,940113 per -1m, precisione +/- 10 m 2012-04 -17 17: 58: 10.248 LocationManagerTest2 [422: 707] 39.856110/-74.940113 a 39.856165/-74.940107 per 6m, precisione +/- 50m 2012-04-17 17: 58: 11.248 LocationManagerTest2 [422: 707] 39.856165/- 74.940107 a 39.856223/-74.940010 per 10m, precisione +/- 50m Il DistanceMoved è uscito a circa 15m - decisamente troppo – bnasty

+0

Ho provato a usare questo codice alcune volte prima e ho ottenuto risultati apparentemente accurati e alcuni erano lontani – bnasty

+0

la distanza -1 è dove la tua oldLocation era 0, il che probabilmente significa che il parametro oldLocation era nullo. Dovrai aggiungere anche un assegno (vedi la mia modifica sopra). Non puoi aspettarti un'elevata precisione quando segnala che l'accuratezza è 50m !!! Ciò significa che il GPS non ha un segnale abbastanza buono, significa che la posizione riportata può essere disattivata di 50 metri in qualsiasi direzione. – progrmr

0

Non si sta impostando la precisione del proprio gestore località. Passare attraverso Apple Docs, è qualcosa come accuratezza = bestfornavigation. o qualcosa. Quello dovrebbe scaricare la batteria come l'inferno ma è inteso per questo genere di scopi.

modifica: appena ricordato l'ho avuto a portata di mano.

// Create the Location Manager 
locationManager = [[CLLocationManager alloc] init]; 

// Configure the Location Manager 
locationManager.delegate = self; 
locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation; 
+0

ho provato impostando tutte le costanti differenti per la precisione desiderata, ma ancora senza fortuna. Ora, la mia app inizierà con distanceMoved a -1.00000 per qualche motivo anziché 0.000000. Il problema potrebbe risiedere nel mio framework Core Location o nel mio stesso iPhone? – bnasty

+0

NSlog il vecchio e il nuovo locaion per vedere come stanno cambiando. allora dimmi che posso avere un'idea di cosa sta succedendo. Ive ha lavorato molto con il responsabile della localizzazione e mi ricordo che se non lo configuri correttamente fa cose strane – Pochi

+0

Le coordinate di latitudine e longitudine sembrano essere corrette, poiché ogni volta che le posizioni vengono aggiornate, la nuova posizione dall'ultima volta viene memorizzato come la vecchia posizione. Per qualche motivo, la distanza tra le due posizioni viene calcolata come un numero estremamente alto. – bnasty

0
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]; 

Spero che questo vi aiuterà a ..

+0

'CLLocationDistance' è semplicemente un typedef per' double', quindi non c'è motivo di convertirlo in una stringa e poi di tornare indietro per fare matematica. – pr1001

0

La prima cosa da fare è scaricare il primo aggiornamento controllando il timestamp del primo aggiornamento si riceve dalla location manager, di solito memorizza nella cache l'ultima posizione nota. In secondo luogo, ricorda la precisione, i valori iniziali che otterrai sono sempre in una vasta gamma.

Problemi correlati