2012-04-17 20 views

Odpowiedz

55

Albo ogólne podejście do porównywania dwóch wystąpień danego typu struct:

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

lub

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

powinny działać, jeśli naprawdę chcesz mieć pewność, że są dokładnie równe . Biorąc jednak pod uwagę, że szerokość i długość geograficzna są zdefiniowane jako deblu, można naprawdę chcą zrobić „wystarczająco blisko” porównania:

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

epsilon gdzie jest cokolwiek poziom błędu chcesz zaakceptować.

+4

Pierwszy z nich można uznać za szkicowy, ponieważ przyjmuje się, że struktura jest spakowana bez żadnych bajtów między elementami. – joerick

+0

Dobra uwaga. Jeśli wyzerujesz całą strukturę, gdy zostanie ona utworzona/przydzielona, ​​wówczas podejście memcmp jest bezpieczne nawet w przypadku niezapakowanych struktur, ale poza tym należy zachować ostrożność. – Glenn

+1

@ Glenn możesz naprawić abs do fabs i Shmidt

1
CLLocationCoordinate2D c1, c2; 
if (c1.latitude == c2.latitude && c1.longitude == c2.longitude) 
{ 
    // ... 
} 

Nie żartuję. CLLocationCoordinate2D jest strukturą C i nie ma łatwego sposobu porównywania struktur C, oprócz porównywania poszczególnych elementów.

1

CLLocationCoordinate2D jest struct C, a więc trzeba porównać swoje pola:

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

Uwaga, CLLocationCoordinate2D pola są double, w ten sposób, można uzyskać takie same problemy jak w przypadku każdego innego pływającą porównaniu pkt. Zatem proponuję wokół małe wartości bitowe, np .:

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 
} 

Tak, ten kod jest wolniejsza, ale może to pomóc uniknąć problemów powodowanych przez nie tak doskonałej precyzji liczb zmiennoprzecinkowych.

32

Jako mały Oprócz tych wszystkich odpowiedzi, to całkiem przydatny do porównania zdefiniowany jako preprocesor zdefiniować:

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

lub 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) 

Pozwala to zrobić porównanie w następujący sposób:

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

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

Inną alternatywą jest zastosowanie metody liniowej, jeśli robisz nie jak preprocesor.

+2

Nigdy nie porównuj liczb zmiennoprzecinkowych z '=='. Zobacz odpowiedzi, gdzie ludzie używają 'epsilon'. – DanSkeel

+0

@DanSkeel Zobacz moją zmienioną odpowiedź. Czasami masz przypadek użycia, w którym chcesz porównać dokładne współrzędne. Na przykład. jeśli źródłem współrzędnych jest baza danych miejsc i chcesz je tylko porównać. Wtedy nie ma potrzeby stosowania zakresu dla równego porównania. Możesz więc ponownie pomyśleć o swoim głosowaniu w dół. – Klaas

+1

Nie zrozumiałeś mojego punktu. Wyobraź sobie przypadek, gdy '1! = 0.99999999999' ... Jest to ogólna zasada dla każdego porównania zmiennoprzecinkowego. [Przeczytaj o] (http://floating-point-gui.de/errors/comparison/) to.Ta zasada jest stara jak komputer. – DanSkeel

10

Można użyć metody "distanceFromLocation: class CLLocation". Wartość zwracana to CLLocationDistance, która jest naprawdę tylko podwójna.

- (CLLocationDistance)distanceFromLocation:(const CLLocation *)location 
8

Można zdefiniować funkcję, która czuje się całkiem jak pochodzące z CoreLocation:

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

+0

przegłosowano, ponieważ jest to najbardziej konserwowalne rozwiązanie. IMO – mvanallen

+0

Dobre rozwiązanie. Oto pełna metoda dla nowej pszczoły. - (BOOL) compairLastSavedCoordinates: (CLLocationCoordinate2D) coordinate1 withNewCoordinates: (CLLocationCoordinate2D) coordinate2 { return (coordinate1.latitude == coordinate2.latitude) && (coordinate1.longitude == coordinate2.longitude); } – iLearner

+2

Nigdy nie porównuj liczb zmiennoprzecinkowych! Jeśli tak, to niewiarygodne. W praktyce większość porównań z rzeczywistych lokalizacji wygenerowanych przez różne źródła zwróci wartość "false" - nawet jeśli są one blisko siebie i mogą być uznane za "równe". – CouchDeveloper

1

można zawinąć CLLocationCoordinate do wiadomości NSValue użyciem tej funkcji + (NSValue *)valueWithMKCoordinate:(CLLocationCoordinate2D)coordinate

a następnie użyć isEqualToValue porównać .

Cytat firmy Apple DOC isEqualToValue funkcji:

Klasa NSValue porównuje rodzaj i zawartość każdego obiektu w celu ustalenia wartości równości.

Ref: Jabłko doc z NSValue

0

Możemy konwertować długość i szerokość geograficzną, aby NSString i zrobić ciąg porównania.

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

}

ponieważ% g przekształci obcina liczbę dziesiętną 4 cyfry.

12

Swift rozszerzenie:

import MapKit 

extension CLLocationCoordinate2D: Equatable {} 

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

[Testowany Xcode 7.3.1 Swift 2.2] [i, oczywiście, nadal ma wewnętrzną niebezpieczeństwo porównując zmiennoprzecinkowych, więc może chcesz rozważ użycie opcji epsilon, jak wspomniano we wcześniejszych odpowiedziach]

2

W Swift 3, DBL_EPSILON jest przestarzałe. Użyj Double.ulpOfOne.

extension CLLocationCoordinate2D { 
    func isEqual(_ coord: CLLocationCoordinate2D) -> Bool { 
     return (fabs(self.latitude - coord.latitude) < .ulpOfOne) && (fabs(self.longitude - coord.longitude) < .ulpOfOne) 
    } 
}