2012-04-17 15 views
9

Estoy intentando utilizar el distanceFromLocation: método para calcular la distancia total que estoy caminando con mi iPhone en la mano. Hasta ahora, he estado buscando por todas partes para ayudar a remediar mis resultados confusos, inexactos y aparentemente arbitrarios. En estos fragmentos de código, theLabel es sólo un objeto de etiqueta que está presente en la interfaz de mi aplicación, distanceMoved es la variable que estoy tratando de guardar la distancia total entré, y LOCMAN es un gerente de locación que se declara en mi archivo @interface .El problema con el método CLLocation distanceFromLocation: Los resultados inexactos

- (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]; 
} 

Cualquier ayuda para solucionar lo que estoy haciendo mal aquí sería muy apreciada. ¡Gracias!

Respuesta

13
  1. Filtrar cabo en caché (de edad) los datos de localización,
  2. a filtrar válido da como resultado la ubicación (precisión < 0),
  3. Conjunto requisito de precisión ajustado a kCLLocationAccuracyBest,
  4. establecer un filtro de distancia mínima, preferiblemente a al menos 10 metros para filtrar el ruido de posición.
  5. EDITAR: No calcule la distancia cuando el oldLocation es nula.

Hay más que podría hacer, pero esto debería funcionar siempre que obtenga una precisión horizonal suficiente (< 30m). Podrías filtrar los resultados de baja precisión, pero tendrías que hacer un seguimiento del oldLocation, que es un poco más complicado.

Añadir un NSLog (véase más adelante) para que pueda encontrar lo que está sucediendo. Si aún no obtiene buenos resultados, publique el resultado del NSLog para que podamos ver qué está sucediendo y obtener más ayuda.

-(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]; 
} 

EDITAR para iOS6 si quería hacer lo mismo usando didUpdateLocations: (ya que el método anterior se considera obsoleto) la solución más sencilla es simplemente guardar cada ubicación en una propiedad para que en la próxima actualización que tiene la ubicación anterior.Declarar una propiedad de la clase para mantener el oldLocation:

@property (nonatomic, retain) CLLocation* oldLocation; 

Luego, en el método delegado guardar cada newLocation para su uso como el oldLocation para la próxima vez que el método delegado se llama:

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

Acabo de utilizar este código exacto, pero cambié el filtro de distancia a 1. Por alguna razón, mi distancia movida comienza en -1. Aquí está mi salida después de caminar unos 2 m hacia adelante: 2012-04-17 17: 58: 05.341 LocationManagerTest2 [422: 707] 0.000000/0.000000 a 39.856110/-74.940113 para -1m, precisión +/- 10m 2012-04 -17 17: 58: 10.248 LocationManagerTest2 [422: 707] 39.856110/-74.940113 a 39.856165/-74.940107 para 6m, precisión +/- 50m 2012-04-17 17: 58: 11.248 LocationManagerTest2 [422: 707] 39.856165/- 74.940107 39.856223 a/-74.940010 de 10m, 50m precisión de +/- El distanceMoved salieron a alrededor de 15 m - demasiado – bnasty

+0

he intentado utilizar el código varias veces antes, así, y me dieron algunos resultados aparentemente precisos y algunos que estaban lejos de – bnasty

+0

la distancia -1 es donde su ubicación anterior era 0, lo que probablemente significa que el parámetro de ubicación anterior era nulo. Necesitarás agregar un cheque para eso también (mira mi edición arriba). No se puede esperar una alta precisión cuando se informa que la precisión es horizontal 50 m !!! Eso significa que el GPS no tiene una señal lo suficientemente buena, lo que significa que la posición reportada puede estar a 50 metros en cualquier dirección. – progrmr

0

No está ajustando la precisión de su gerente de locación. Consulte los documentos de apple, es algo así como accuracy = bestfornavigation. o algo. Eso debería agotar la batería como el infierno, pero está destinado a este tipo de propósitos.

edición: acabo de acordar que lo tenía a mano.

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

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

Probé estableciendo todas las constantes diferentes para la precisión deseada, pero todavía no hay suerte. Ahora, mi aplicación comenzará con la distancia modificada en -1.00000 por alguna razón en lugar de 0.000000. ¿Es posible que el problema se encuentre dentro de mi marco de Core Location o de mi iPhone? – bnasty

+0

NSlog la ubicación antigua y la nueva para ver cómo están cambiando. Entonces dime para que pueda tener una idea de lo que está pasando. He trabajado mucho con el administrador de la ubicación y recuerdo que si no se configura correctamente, hace cosas raras – Pochi

+0

Las coordenadas de latitud y longitud parecen ser correctas, ya que cada vez que se actualizan las ubicaciones, se está realizando la nueva ubicación desde la última vez almacenado como la ubicación anterior. Por alguna razón, la distancia entre las dos ubicaciones se calcula como un número extremadamente 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]; 

Hope esto le ayudará a ..

+0

'CLLocationDistance' es simplemente un typedef para' double', por lo que no hay razón para convertirlo en una cadena y luego de nuevo para hacer operaciones matemáticas. – pr1001

0

La primera cosa que debe hacer es descargar la primera actualización marcando la fecha y hora de la primera actualización que recibe del gestor de ubicación, por lo general cachés la última posición conocida. En segundo lugar, recuerde la precisión, los valores iniciales que obtendrá siempre se encuentran en un amplio rango.

Cuestiones relacionadas