Как я могу сравнить два CLLocationCoordinate2D? (IPhone/ IPad)

Мне нужен способ сравнения двух CLLocationCoordinate2DОднако, когда я пытался использовать == это не сработает. Пожалуйста, может кто-нибудь помочь мне с лучшим способом их сравнения?

13 ответов

Решение

Либо общий подход для сравнения двух экземпляров любого данного типа структуры:

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

или же

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

должен работать, если вы действительно хотите быть уверены, что они абсолютно равны. Однако, учитывая, что широта и долгота определены как двойные значения, вы, возможно, захотите сделать "достаточно близкое" сравнение:

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

где epsilon какой уровень ошибки вы хотите принять.

Как небольшое дополнение ко всем этим ответам, очень удобно иметь сравнение, определенное как определение препроцессора:

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

или с эпсилоном:

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

Это позволяет сделать сравнение следующим образом:

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

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

Другой альтернативой является использование встроенного метода, если вам не нравится препроцессор.

Расширение Swift:

import MapKit

extension CLLocationCoordinate2D: Equatable {}

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

[проверено на Xcode 7.3.1, Swift 2.2] [и, конечно, все еще существует внутренняя опасность сравнения значений с плавающей запятой, поэтому вы можете рассмотреть возможность использования epsilon как упоминалось в предыдущих ответах]

Вы можете использовать класс CLLocation ' distanceFromLocation: метод. Возвращаемое значение - CLLocationDistance, которое на самом деле является просто двойным.

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

В Свифте 3 DBL_EPSILON устарела. использование Double.ulpOfOne,

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

Вы можете определить функцию, которая выглядит как CoreLocation:

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

Обновлено для Swift 5 на leanne ответа leanne.

import CoreLocation

extension CLLocationCoordinate2D: Equatable {
    static public func ==(lhs: Self, rhs: Self) -> Bool {
        return lhs.latitude == rhs.latitude && lhs.longitude == rhs.longitude
    }
}
CLLocationCoordinate2D c1, c2;
if (c1.latitude == c2.latitude && c1.longitude == c2.longitude)
{
    // ...
}

Я не шучу. CLLocationCoordinate2D является структурой C, и нет простого способа сравнить структуры C, кроме сравнения отдельных элементов.

CLLocationCoordinate2D является структурой C, поэтому вам нужно сравнить ее поля:

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

Заметка, CLLocationCoordinate2D поля doubleТаким образом, вы можете получить те же проблемы, что и при любом другом сравнении с плавающей запятой. Таким образом, я предлагаю немного округлить значения, например:

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
}

Да, этот код работает медленнее, но это может помочь вам избежать проблем, вызванных не столь совершенной точностью чисел с плавающей запятой.

Вы можете обернуть CLLocationCoordinate в NSValue используя эту функцию + (NSValue *)valueWithMKCoordinate:(CLLocationCoordinate2D)coordinate

А потом использовать isEqualToValue сравнивать.

Цитата из Apple, док isEqualToValue функция:

Класс NSValue сравнивает тип и содержимое каждого объекта значения для определения равенства.

Ссылка: Apple, док NSValue

Мы можем преобразовать широту и долготу в NSString и сравнить строки.

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

}

Так как%g преобразует усеченное десятичное число в 4 цифры.

Для обработки двойного сравнения необходимо использовать некоторое значение допуска. Методом проб и ошибок я обнаружил, что 0,01 является приемлемым значением.

      import MapKit

extension CLLocationCoordinate2D: Equatable {
  public static func == (lhs: CLLocationCoordinate2D, rhs: CLLocationCoordinate2D) -> Bool {
    let tolerance = 0.01
    return abs(lhs.latitude - rhs.latitude) < tolerance &&
    abs(lhs.longitude - rhs.longitude) < tolerance
  }
}

Свифт 5.3 способ

Я создал суть

      extension CLLocationCoordinate2D: Equatable {
    public static func == (lhs: CLLocationCoordinate2D, rhs: CLLocationCoordinate2D) -> Bool {
        let numbersAfterCommaAccuracy: Double = 4
        let ratio = numbersAfterCommaAccuracy * 10
        let isLatitudeEqual = ((lhs.latitude - rhs.latitude) * ratio).rounded(.down) == 0
        let isLongitudeEqual = ((lhs.latitude - rhs.latitude) * ratio).rounded(.down) == 0
        return isLatitudeEqual && isLongitudeEqual
    }
}
Другие вопросы по тегам