I need a way of comparing two CLLocationCoordinate2D
's however when I tried using ==
it wouldn't work. Please can someone help me out with the best way of comparing them?
Either the generic approach for comparing two instances of any given struct type:
memcmp(&cllc2d1, &second_cllc2d, sizeof(CLLocationCoordinate2D))
or
cllc2d1.latitude == cllc2d2.latitude && cllc2d1.longitude == cllc2d2.longitude
should work, if you really want to be sure they're exactly equal. However, given that latitude and longitude are defined as doubles, you might really want to do a "close enough" comparison:
fabs(cllc2d1.latitude - cllc2d2.latitude) <= epsilon && fabs(cllc2d1.longitude - cllc2d2.longitude) <= epsilon
where epsilon
is whatever level of error you want to accept.
As a small addition to all these answers, it's quite handy to have the comparison defined as a preprocessor define:
#define CLCOORDINATES_EQUAL( coord1, coord2 ) (coord1.latitude == coord2.latitude && coord1.longitude == coord2.longitude)
or with 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)
This allows you to do a comparison as follows:
CLLocationCoordinate2D resultingCoordinate = ... a method call ...;
CLLocationCoordinate2D expectedCoordinate = CLLocationCoordinate2DMake(48.11, 11.12);
if(CLCOORDINATES_EQUAL( resultingCoordinate, expectedCoordinate)) {
NSLog(@"equal");
} else {
NSLog(@"not equal");
}
Another alternative is to use an inline method, if you don't like the preprocessor.
==
. See answers where people use epsilon
. –
Cloe 1 != 0.99999999999
... It's general rule for any floating point comparison. Read about it. This rule is old as a computer. –
Cloe Double
values by default. Double
values are rarely exact in a computer. If the user enters a latitude, say, of 38.627003
, there's no guarantee that the computer will store exactly 38.627003
. A recent test printing a computer's interpretation to 15 decimal places returned a value of 38.627002716064453
! Now, if you retrieve and store the user's response as a String
, then the result would be exact - but remember the default is Double
. –
Scarf A Swift extension:
import MapKit
extension CLLocationCoordinate2D: Equatable {}
public func ==(lhs: CLLocationCoordinate2D, rhs: CLLocationCoordinate2D) -> Bool {
return (lhs.latitude == rhs.latitude && lhs.longitude == rhs.longitude)
}
[tested as of Xcode 7.3.1, Swift 2.2]
[and, of course, still has the intrinsic danger of comparing floating point values, so you might want to consider using epsilon
as mentioned in earlier answers]
You can use the CLLocation class' distanceFromLocation: method. The return value is a CLLocationDistance, which is really just a double.
- (CLLocationDistance)distanceFromLocation:(const CLLocation *)location
In Swift 3, DBL_EPSILON
is deprecated. Use Double.ulpOfOne
.
extension CLLocationCoordinate2D {
func isEqual(_ coord: CLLocationCoordinate2D) -> Bool {
return (fabs(self.latitude - coord.latitude) < .ulpOfOne) && (fabs(self.longitude - coord.longitude) < .ulpOfOne)
}
}
<= .ulpOfOne
instead of < .ulpOfOne
because anything less than ulpOfOne is in effect zero by definition. –
Blind You could define a function which feels pretty like coming from CoreLocation:
BOOL CLLocationCoordinateEqual(CLLocationCoordinate2D coordinate1, CLLocationCoordinate2D coordinate2)
{
return (fabs(coordinate1.latitude - coordinate2.latitude) <= DBL_EPSILON &&
fabs(coordinate1.longitude - coordinate2.longitude) <= DBL_EPSILON);
}
false
- even if they are pretty close to each other and can be considered "equal". –
Allegory CLLocationCoordinate2D c1, c2;
if (c1.latitude == c2.latitude && c1.longitude == c2.longitude)
{
// ...
}
I'm not kidding. CLLocationCoordinate2D is a C struct, and there's no easy way to compare C structs, apart from comparing the individual members.
CLLocationCoordinate2D
is a C struct, thus, you need to compare its fields:
CLLocationCoordinate2D coord1, coord2;
if (coord1.latitude == coord2.latitude && coord1.longitude == coord2.longitude) {
// coordinates are equal
}
Note, CLLocationCoordinate2D
fields are double
, thus, you may get the same issues like with any other floating point comparison. Thus, I suggest to round a little bit values, e.g.:
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
}
Yes, this, code is slower, but this may help you to avoid problems caused by not so perfect precision of floating point numbers.
You can wrap CLLocationCoordinate
into an NSValue
using this function + (NSValue *)valueWithMKCoordinate:(CLLocationCoordinate2D)coordinate
And then use isEqualToValue
to compare.
Quote from Apple doc of isEqualToValue
function:
The NSValue class compares the type and contents of each value object to determine equality.
Ref: Apple doc of NSValue
We can convert latitude and longitude to NSString and do a string compare.
+ (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;
}
}
Since %g will convert truncate decimal number to 4 digit.
You have to use some tolerance value to handle Double comparison, with trial and error I found that 0.01 is an acceptable value.
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
}
}
Swift 5.3 way
I've created a gist
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
}
}
© 2022 - 2024 — McMap. All rights reserved.