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?
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
où epsilon
correspond au niveau d'erreur que vous souhaitez accepter.
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.
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]
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
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);
}
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)
}
}
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.
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.
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
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.