【发布时间】:2012-04-29 06:13:06
【问题描述】:
我需要一种比较两个CLLocationCoordinate2D 的方法,但是当我尝试使用== 时它不起作用。请问有人能帮我找出比较它们的最佳方法吗?
【问题讨论】:
标签: core-location cllocation equatable
我需要一种比较两个CLLocationCoordinate2D 的方法,但是当我尝试使用== 时它不起作用。请问有人能帮我找出比较它们的最佳方法吗?
【问题讨论】:
标签: core-location cllocation equatable
Swift 5.3 方式
我创建了一个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
}
}
【讨论】:
您可以使用CLLocation 类的distanceFromLocation: 方法。返回值为CLLocationDistance,实际上只是一个double。
- (CLLocationDistance)distanceFromLocation:(const CLLocation *)location
【讨论】:
在 Swift 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)
}
}
【讨论】:
一个 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,如前面的答案中所述]
【讨论】:
您可以定义一个感觉很像来自 CoreLocation 的函数:
BOOL CLLocationCoordinateEqual(CLLocationCoordinate2D coordinate1, CLLocationCoordinate2D coordinate2)
{
return (fabs(coordinate1.latitude - coordinate2.latitude) <= DBL_EPSILON &&
fabs(coordinate1.longitude - coordinate2.longitude) <= DBL_EPSILON);
}
【讨论】:
false - 即使它们彼此非常接近并且可以被视为“相等”。
我们可以将纬度和经度转换为 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 位数字。
【讨论】:
您可以使用此函数+ (NSValue *)valueWithMKCoordinate:(CLLocationCoordinate2D)coordinate 将CLLocationCoordinate 包装成NSValue
然后使用isEqualToValue进行比较。
引用苹果文档isEqualToValue函数:
NSValue 类比较每个值对象的类型和内容以确定相等性。
参考:NSValue 的 Apple 文档
【讨论】:
比较任何给定结构类型的两个实例的通用方法:
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)
或使用 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)
这允许您进行如下比较:
CLLocationCoordinate2D resultingCoordinate = ... a method call ...;
CLLocationCoordinate2D expectedCoordinate = CLLocationCoordinate2DMake(48.11, 11.12);
if(CLCOORDINATES_EQUAL( resultingCoordinate, expectedCoordinate)) {
NSLog(@"equal");
} else {
NSLog(@"not equal");
}
如果您不喜欢预处理器,另一种选择是使用内联方法。
【讨论】:
== 进行比较。查看人们使用 epsilon 的答案。
1 != 0.99999999999 的情况......这是任何浮点比较的一般规则。 Read about它。这条规则就像计算机一样古老。
Double 值。 Double 值在计算机中很少准确。如果用户输入一个纬度,例如38.627003,则不能保证计算机将准确存储38.627003。最近一次将计算机的解释打印到小数点后 15 位的测试返回值38.627002716064453!现在,如果您将用户的响应检索并存储为 String,那么 结果将是准确的 - 但请记住 默认 是 Double。
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
}
是的,这个,代码比较慢,但这可以帮助您避免因浮点数精度不那么完美而导致的问题。
【讨论】:
CLLocationCoordinate2D c1, c2;
if (c1.latitude == c2.latitude && c1.longitude == c2.longitude)
{
// ...
}
我不是在开玩笑。 CLLocationCoordinate2D 是一个 C 结构,除了比较各个成员之外,没有简单的方法来比较 C 结构。
【讨论】: