web-dev-qa-db-fra.com

Comment comparer deux CLLocationCoordinate2D? (iPhone/iPad)

J'ai besoin d'un moyen de comparer deux CLLocationCoordinate2D, mais lorsque j'ai essayé d'utiliser ==, cela ne fonctionnerait pas. S'il vous plaît, quelqu'un peut-il m'aider avec le meilleur moyen de les comparer?

46
The Crazy Chimp

Soit l’approche générique pour comparer deux instances d’un type de structure donné:

memcmp(&cllc2d1, &second_cllc2d, sizeof(CLLocationCoordinate2D))

ou

cllc2d1.latitude == cllc2d2.latitude && cllc2d1.longitude == cllc2d2.longitude

devrait fonctionner, si vous voulez vraiment être sûr qu'ils sont exactement égaux. Cependant, étant donné que la latitude et la longitude sont définies comme des doubles, vous pouvez vraiment vouloir faire une comparaison "assez proche":

fabs(cllc2d1.latitude - cllc2d2.latitude) <= epsilon && fabs(cllc2d1.longitude - cllc2d2.longitude) <= epsilon

epsilon correspond au niveau d'erreur que vous souhaitez accepter.

57
Glenn

En tant que petit ajout à toutes ces réponses, il est assez pratique de définir la comparaison comme un préprocesseur:

#define CLCOORDINATES_EQUAL( coord1, coord2 ) (coord1.latitude == coord2.latitude && coord1.longitude == coord2.longitude)

ou avec epsilon:

#define CLCOORDINATE_EPSILON 0.005f
#define CLCOORDINATES_EQUAL2( coord1, coord2 ) (fabs(coord1.latitude - coord2.latitude) < CLCOORDINATE_EPSILON && fabs(coord1.longitude - coord2.longitude) < CLCOORDINATE_EPSILON)

Cela vous permet de faire une comparaison comme suit:

CLLocationCoordinate2D resultingCoordinate = ... a method call ...;
CLLocationCoordinate2D expectedCoordinate = CLLocationCoordinate2DMake(48.11, 11.12);

if(CLCOORDINATES_EQUAL( resultingCoordinate, expectedCoordinate)) {
    NSLog(@"equal");
} else {
    NSLog(@"not equal");
}

Une autre alternative consiste à utiliser une méthode en ligne, si vous n'aimez pas le pré-processeur.

33
Klaas

Une extension Swift:

import MapKit

extension CLLocationCoordinate2D: Equatable {}

public func ==(lhs: CLLocationCoordinate2D, rhs: CLLocationCoordinate2D) -> Bool {
    return (lhs.latitude == rhs.latitude && lhs.longitude == rhs.longitude)
}

[testé à partir de Xcode 7.3.1, Swift 2.2] [et présente toujours le danger intrinsèque de comparer les valeurs à virgule flottante, vous pouvez donc envisager d’utiliser epsilon comme indiqué dans les réponses précédentes]

17
leanne

Vous pouvez utiliser la méthode CLLocation class 'distanceFromLocation:. La valeur de retour est un CLLocationDistance , qui n'est en réalité qu'un double.

- (CLLocationDistance)distanceFromLocation:(const CLLocation *)location
12
Greg M. Krsak

Vous pouvez définir une fonction qui ressemble à celle de CoreLocation:

BOOL CLLocationCoordinateEqual(CLLocationCoordinate2D coordinate1, CLLocationCoordinate2D coordinate2) { return (fabs(coordinate1.latitude - coordinate2.latitude) <= DBL_EPSILON && fabs(coordinate1.longitude - coordinate2.longitude) <= DBL_EPSILON); }

8
Albert Schulz

Dans Swift 3, DBL_EPSILON est obsolète. Utilisez Double.ulpOfOne.

extension CLLocationCoordinate2D {
    func isEqual(_ coord: CLLocationCoordinate2D) -> Bool {
        return (fabs(self.latitude - coord.latitude) < .ulpOfOne) && (fabs(self.longitude - coord.longitude) < .ulpOfOne)
    }
}
6
Ryan
CLLocationCoordinate2D c1, c2;
if (c1.latitude == c2.latitude && c1.longitude == c2.longitude)
{
    // ...
}

Je ne plaisante pas. CLLocationCoordinate2D est une structure C et il n'existe pas de moyen facile de comparer les structures C, à part la comparaison des membres individuels.

2
joerick

CLLocationCoordinate2D est une structure C, vous devez donc comparer ses champs:

CLLocationCoordinate2D coord1, coord2;
if (coord1.latitude == coord2.latitude && coord1.longitude == coord2.longitude) {
    // coordinates are equal
}

Remarque, les champs CLLocationCoordinate2D sont double. Par conséquent, vous pouvez rencontrer les mêmes problèmes que pour toute autre comparaison à virgule flottante. Ainsi, je suggère d’arrondir un peu les valeurs, par exemple:

CLLocationCoordinate2D coord1, coord2;
if (round(coord1.latitude * 1000.0) == round(coord2.latitude * 1000.0)
    && round(coord1.longitude * 1000.0) == round(coord2.longitude * 1000.0)) {
    // coordinates are equal
}

Oui, le code est plus lent, mais cela peut vous aider à éviter les problèmes causés par la précision pas si parfaite des nombres en virgule flottante.

1
Aleksejs Mjaliks

Vous pouvez envelopper CLLocationCoordinate dans une NSValue en utilisant cette fonction + (NSValue *)valueWithMKCoordinate:(CLLocationCoordinate2D)coordinate

Et utilisez ensuite isEqualToValue pour comparer.

Citation tirée du document Apple concernant la fonction isEqualToValue:

La classe NSValue compare le type et le contenu de chaque objet de valeur pour déterminer l’égalité.

Réf. Apple doc de NSValue

1
Raymond

Nous pouvons convertir la latitude et la longitude en NSString et comparer les chaînes. 

+ (BOOL)isEqualWithCoordinate:(CLLocationCoordinate2D)location1 withAnotherCoordinate:(CLLocationCoordinate2D)location2{
NSString *locationString1 = [NSString stringWithFormat:@"%g, %g", location1.latitude, location1.longitude];
NSString *locationString2 = [NSString stringWithFormat:@"%g, %g", location2.latitude, location2.longitude];

if ([locationString1 isEqualToString:locationString2]) {
    return YES;
}else{
    return NO;
}

}

Puisque% g convertira le nombre décimal tronqué en 4 chiffres.

0
Saif