【问题标题】:Trouble with CLLocation method distanceFromLocation: Inaccurate resultsCLLocation 方法 distanceFromLocation 的问题:结果不准确
【发布时间】:2012-04-28 09:54:58
【问题描述】:

我正在尝试使用 distanceFromLocation: 方法来计算我手里拿着 iPhone 行走的总距离。到目前为止,我一直在四处寻找以帮助纠正我的混乱、不准确和看似武断的结果。在这些代码 sn-ps 中,theLabel 只是我的应用程序界面中存在的标签对象,distanceMoved 是我试图存储我走过的总距离的变量,而 locMan 是在我的 @ 中声明的位置管理器接口文件。

- (void)viewDidLoad
{
   locMan = [[CLLocationManager alloc] init];
   locMan.delegate = self;
   [locMan startUpdatingLocation];
   isInitial = true;
   distanceMoved = 0.0;
   [super viewDidLoad];
}

-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
   distanceMoved += [newLocation distanceFromLocation: oldLocation];
   theLabel.text = [NSString stringWithFormat: @"%f meters", distanceMoved];
}

对于解决我在这里做错的任何帮助将不胜感激。谢谢!

【问题讨论】:

    标签: iphone objective-c core-location cllocation


    【解决方案1】:
    1. 过滤掉缓存的(旧的)位置数据,
    2. 过滤掉无效的定位结果(精度
    3. 将精度要求设置为kCLLocationAccuracyBest
    4. 设置最小距离过滤器,最好至少 10 米以过滤掉位置噪声。
    5. 编辑:当oldLocation 为零时,不要计算距离。

    您还可以做更多的事情,但只要您获得足够好的水平精度(

    添加一个 NSLog(见下文),以便您了解发生了什么。如果您仍然没有得到好的结果,请发布 NSLog 的输出,以便我们查看发生了什么并提供更多帮助。

    -(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
    {
        NSTimeInterval age = -[newLocation.timestamp timeIntervalSinceNow]; 
    
        if (age > 120) return;    // ignore old (cached) updates
    
        if (newLocation.horizontalAccuracy < 0) return;   // ignore invalid udpates
    
        // EDIT: need a valid oldLocation to be able to compute distance
        if (oldLocation == nil || oldLocation.horizontalAccuracy < 0) return; 
    
        CLLocationDistance distance = [newLocation distanceFromLocation: oldLocation];
    
        NSLog(@"%6.6f/%6.6f to %6.6f/%6.6f for %2.0fm, accuracy +/-%2.0fm",
            oldLocation.coordinate.latitude,
            oldLocation.coordinate.longitude,
            newLocation.coordinate.latitude,
            newLocation.coordinate.longitude, 
            distance,
            newLocation.horizontalAccuracy);
    
        distanceMoved += distance;
        theLabel.text = [NSString stringWithFormat: @"%f meters", distanceMoved];
    }
    
    - (void)viewDidLoad
    {
       locMan = [[CLLocationManager alloc] init];
       locMan.delegate = self;
       locMan.desiredAccuracy = kCLLocationAccuracyBest;
       locMan.distanceFilter = 10;
    
       [locMan startUpdatingLocation];
       isInitial = true;
       distanceMoved = 0.0;
       [super viewDidLoad];
    }
    

    EDIT for iOS6 如果您想使用didUpdateLocations: 执行相同操作(因为现在不推荐使用上述方法),最简单的解决方案是将每个位置保存在一个属性中,以便在下一个更新你有以前的位置。在类中声明一个属性来保存oldLocation

    @property (nonatomic, retain) CLLocation* oldLocation;
    

    然后在委托方法中保存每个newLocation 以用作下次调用委托方法时的oldLocation

    -(void)locationManager:(CLLocationManager *)manager didUpdateToLocations:(NSArray *)locations
    {
        CLLocation* newLocation = [locations lastObject];
    
        NSTimeInterval age = -[newLocation.timestamp timeIntervalSinceNow]; 
    
        if (age > 120) return;    // ignore old (cached) updates
    
        if (newLocation.horizontalAccuracy < 0) return;   // ignore invalid udpates
    
        // EDIT: need a valid oldLocation to be able to compute distance
        if (self.oldLocation == nil || self.oldLocation.horizontalAccuracy < 0) {
            self.oldLocation = newLocation;
            return; 
        }
    
        CLLocationDistance distance = [newLocation distanceFromLocation: self.oldLocation];
    
        NSLog(@"%6.6f/%6.6f to %6.6f/%6.6f for %2.0fm, accuracy +/-%2.0fm",
            self.oldLocation.coordinate.latitude,
            self.oldLocation.coordinate.longitude,
            newLocation.coordinate.latitude,
            newLocation.coordinate.longitude, 
            distance,
            newLocation.horizontalAccuracy);
    
        distanceMoved += distance;
        theLabel.text = [NSString stringWithFormat: @"%f meters", distanceMoved];
    
        self.oldLocation = newLocation;    // save newLocation for next time
    }
    

    【讨论】:

    • 我只是使用了这个确切的代码,但我将距离过滤器更改为 1。出于某种原因,我移动的距离从 -1 开始。这是我向前走了大约 2m 后的输出: 2012-04-17 17:58:05.341 LocationManagerTest2[422:707] 0.000000/0.000000 到 39.856110/-74.940113 for -1m,精度 +/-10m 2012-04-17 17 :58:10.248 LocationManagerTest2[422:707] 39.856110/-74.940113 to 39.856165/-74.940107 for 6m, 精度 +/-50m 2012-04-17 17:58:11.248 LocationManagerTest2[422:707] 39.856160/75/-79.942561/75/-2012-04-17 -74.940010 for 10m, accuracy +/-50m
    • 我之前也尝试过几次使用这段代码,我得到了一些看似准确的结果,但有些结果却很遥远
    • -1 距离是您的 oldLocation 为 0 的位置,这可能意味着 oldLocation 参数为零。您还需要为此添加一个检查(请参阅我上面的编辑)。当它报告horizo​​ntalAccuracy是50m时,你不能指望高精度!这意味着 GPS 没有足够好的信号,这意味着报告的位置可以在任何方向上偏离 50 米。
    • distanceFilter 1 太小了。当 GPS 报告它只有 50m 精度信号时,您不能指望 1m 精度。连10m都太乐观了。
    • 我更新了您编辑的代码。在尝试并走动了一下之后,该方法从未运行过,我也没有收到任何输出。只是为了澄清一下,if 语句之后出现的返回究竟是什么?
    【解决方案2】:

    您没有设置位置管理器的准确性。浏览苹果文档,它类似于accuracy = bestfornavigation。或者其他的东西。这应该会像地狱一样耗尽电池,但就是为了这种目的。

    编辑:只记得我手头有它。

    // Create the Location Manager
    locationManager = [[CLLocationManager alloc] init];
    
    // Configure the Location Manager
    locationManager.delegate = self;
    locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
    

    【讨论】:

    • 我尝试设置所有不同的常数以获得所需的精度,但仍然没有运气。现在,由于某种原因,我的应用程序将以 -1.00000 的距离开始,而不是 0.000000。问题可能出在我的核心位置框架或我的 iPhone 本身上吗?
    • NSlog 新旧位置,看看它们是如何变化的。然后告诉我,这样我就可以知道发生了什么。我和位置管理器一起工作了很多,我记得如果你没有正确配置它会做一些奇怪的事情
    • 纬度和经度坐标似乎是正确的,因为每次更新位置时,上次的新位置都会被存储为旧位置。出于某种原因,这两个位置之间的距离被计算为一个非常高的数字。
    【解决方案3】:
    CLLocationDistance distance = [secondLocation distanceFromLocation:firstLocation];  // distance is expressed in meters
    
    CLLocationDistance kilometers = distance / 1000.0;
    // or you can also use this..
    CLLocationDistance meters = distance;
    
    NSString *distanceString = [[NSString alloc] initWithFormat: @"%f", kilometers];
    
    flot totaldistancecovered = [distanceString floatValue];
    
    //Now,you can use this float value for addition...
    // distanceMoved  should be float type variable which is declare in .h file...
    
     distanceMoved = distanceMoved + totaldistancecovered ;
     theLabel.text = [NSString stringWithFormat: @"%f meters", distanceMoved];
    

    希望这会对你有所帮助..

    【讨论】:

    • CLLocationDistance 只是 double 的 typedef,因此没有理由将其转换为字符串然后再返回以进行数学运算。
    【解决方案4】:

    您应该做的第一件事是通过检查您从位置管理器收到的第一个更新的时间戳来释放第一个更新,它通常会缓存最后一个已知位置。其次要记住准确性,你得到的初始值总是在一个很大的范围内。

    【讨论】:

      猜你喜欢
      • 2014-04-10
      • 2011-07-09
      • 2017-02-08
      • 2013-01-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-07
      • 2011-07-10
      相关资源
      最近更新 更多