目錄:
- 一、問題出現(xiàn)場(chǎng)景
- 二、常見的計(jì)算里程方法
1、最土及常見的計(jì)算里程方法
2、初步優(yōu)化方案:
3、正確的判斷/解決飄的問題
4、更多關(guān)于解決隧道里定位會(huì)飄的問題
5、其他里程計(jì)算方法(后續(xù)補(bǔ)充) - 三、CLLocation詳解
前言
如果你的app不追求深度、精確度,請(qǐng)略過本文章。
一、問題出現(xiàn)場(chǎng)景
路測(cè),里程計(jì)算不準(zhǔn)確。WTF。。。什么場(chǎng)景會(huì)有這種需求???
答:如果你做的app是一款如滴滴司機(jī)端一樣,需要計(jì)算從接乘客上車到將乘客送達(dá),乘客下車的這段長(zhǎng)距離的里程值的時(shí)候,相信你就會(huì)有本文所要講的里程計(jì)算問題了。
二、常見的計(jì)算里程方法
1、最土及常見的計(jì)算里程方法
通過兩點(diǎn)位置,計(jì)算距離,累積相加得到最后的里程值。
- 會(huì)出現(xiàn)的問題:
定位飄了怎么辦?如海底隧道燈弱信號(hào)地方。
2、初步優(yōu)化方案:
加上定時(shí)器,通過定時(shí)器時(shí)間及兩點(diǎn)距離對(duì)該時(shí)間內(nèi)的時(shí)速做判斷,超過閾值,認(rèn)為當(dāng)前點(diǎn)無(wú)效,取下一個(gè)點(diǎn)跟上一個(gè)有效點(diǎn)比較。
- 會(huì)出現(xiàn)的問題:
判斷錯(cuò)誤,因?yàn)殡m然定時(shí)器的時(shí)間都是增加的,但是定位給出的位置,有可能是我們之前給的位置。即可能出現(xiàn)如下返回的位置信息:
<+24.50999425,+118.18279171> +/- 10.00m (speed 8.95 mps / course 158.55) @ 17/6/23 中國(guó)標(biāo)準(zhǔn)時(shí)間17:37:48
<+24.50958770,+118.18296699> +/- 10.00m (speed 9.96 mps / course 160.66) @ 17/6/23 中國(guó)標(biāo)準(zhǔn)時(shí)間17:37:53
<+24.50910223,+118.18314439> +/- 10.00m (speed 8.32 mps / course 166.99) @ 17/6/23 中國(guó)標(biāo)準(zhǔn)時(shí)間17:37:59
<+24.50317363,+118.18252758> +/- 10.00m (speed 10.28 mps / course 198.28) @ 17/6/23 中國(guó)標(biāo)準(zhǔn)時(shí)間17:39:04
<+24.50280620,+118.18241544> +/- 10.00m (speed 10.81 mps / course 189.49) @ 17/6/23 中國(guó)標(biāo)準(zhǔn)時(shí)間17:39:08
//>>>這里開始異常了(飄回了一個(gè)之前好久定位到的點(diǎn))
<+24.50958770,+118.18296699> +/- 10.00m (speed 9.96 mps / course 160.66) @ 17/6/23 中國(guó)標(biāo)準(zhǔn)時(shí)間17:37:53
<+24.50958770,+118.18296699> +/- 10.00m (speed 9.96 mps / course 160.66) @ 17/6/23 中國(guó)標(biāo)準(zhǔn)時(shí)間17:37:53
<+24.50958770,+118.18296699> +/- 10.00m (speed 9.96 mps / course 160.66) @ 17/6/23 中國(guó)標(biāo)準(zhǔn)時(shí)間17:37:53
<+24.50958770,+118.18296699> +/- 10.00m (speed 9.96 mps / course 160.66) @ 17/6/23 中國(guó)標(biāo)準(zhǔn)時(shí)間17:37:53
<+24.50958770,+118.18296699> +/- 10.00m (speed 9.96 mps / course 160.66) @ 17/6/23 中國(guó)標(biāo)準(zhǔn)時(shí)間17:37:53
//<<<這里結(jié)束異常了
<+24.50187348,+118.18212644> +/- 10.00m (speed 10.47 mps / course 197.23) @ 17/6/23 中國(guó)標(biāo)準(zhǔn)時(shí)間17:39:19
<+24.50145111,+118.18199236> +/- 10.00m (speed 9.20 mps / course 195.82) @ 17/6/23 中國(guó)標(biāo)準(zhǔn)時(shí)間17:39:24
仔細(xì)觀察數(shù)據(jù)會(huì)發(fā)現(xiàn):
定位飄回了一個(gè)之前好久定位到的點(diǎn).png
所以,通過兩點(diǎn)位置所得的距離,加上定時(shí)器時(shí)間間隔來(lái)判斷點(diǎn)是否有效的方法是錯(cuò)誤的。
那么問題來(lái)了,既然不能使用定時(shí)器的時(shí)間間隔,那兩點(diǎn)之間所用的時(shí)間怎么算?答應(yīng)該采用CLLocation里面的timestamp來(lái)計(jì)算時(shí)間差。
3、正確的判斷/解決飄的問題
從上我們知道,在隧道里由于定位會(huì)飄的問題,所以定位給出的位置,有可能是我們之前給的位置。所以我們不能采用自己約定的時(shí)間差(一般是計(jì)時(shí)器)來(lái)計(jì)算時(shí)速。
仔細(xì)觀察如下參考數(shù)據(jù):
上次計(jì)算地點(diǎn)為:<+24.52033493,+118.19203987> +/- 373.66m (speed -1.00 mps / course -1.00) @ 17/6/23 中國(guó)標(biāo)準(zhǔn)時(shí)間16:51:27
本次計(jì)算地點(diǎn)為:<+24.56114169,+118.22883818> +/- 2000.00m (speed -1.00 mps / course -1.00) @ 17/6/23 中國(guó)標(biāo)準(zhǔn)時(shí)間16:52:17
我們得出,其實(shí)每個(gè)定位點(diǎn)CLLocation是有帶該點(diǎn)的時(shí)間的。所以雖然計(jì)算兩點(diǎn)的時(shí)速的時(shí)候,不能采用自己的時(shí)間差,但是可以采用CLLocation里面的timestamp來(lái)計(jì)算時(shí)間差,這也才是正解。即:我們應(yīng)該判斷最新的位置的時(shí)間timestamp是不是比上次的timestamp大。否則,該點(diǎn)就是我們之前已經(jīng)獲取到的點(diǎn),而不是當(dāng)前時(shí)間的最新點(diǎn)。
4、更多關(guān)于解決隧道里定位會(huì)飄的問題
更完善的過濾方法可參考:iOS定位服務(wù),無(wú)效/不準(zhǔn)確位置的過濾
5、其他里程計(jì)算方法
后續(xù)補(bǔ)充,待完善。。。。。。
三、CLLocation詳解
CLLocation值修改?
CLLocationCoordinate2D chongQingCoordinate = CLLocationCoordinate2DMake(29.554941, 106.55329); //重慶市
CLLocation *chongQingLocation = [[CLLocation alloc] initWithLatitude:chongQingCoordinate.latitude longitude:chongQingCoordinate.longitude];
self.location = chongQingLocation;
其他基本知識(shí)
精確度設(shè)置
設(shè)置代理后,你還要設(shè)置需要的準(zhǔn)確度。就像我們剛剛說(shuō)的精確度越高越耗電。如果你只是要是應(yīng)用程序確定是哪個(gè)國(guó)家或是哪個(gè)州那么就不要設(shè)置很高的精確度。記住一點(diǎn)有時(shí)候你并不能得到你需要的精確度。
下面說(shuō)一個(gè)設(shè)置代理和設(shè)置精確度的例子:
locationManager.delegate = self;
locationManager.desiredAccuracy =kCLLocationAccuracyBest;
精確度使用的是一個(gè)double類型的常量。單位是米,所以如果你設(shè)置desiredAccuracy=10那么精確度就是10米,這就告訴 Location Manager盡可能達(dá)到10米的精確度。還可以設(shè)置為其他常量:
多久調(diào)用一次代理
默認(rèn)情況是這樣的,每當(dāng)位置改變時(shí)Location Manager就調(diào)用一次代理。
而通過設(shè)置distance filter可以實(shí)現(xiàn)當(dāng)位置改變超出一定范圍時(shí)Location Manager才調(diào)用相應(yīng)的代理方法。這樣可以達(dá)到省電的目的。
例如:locationManager.distanceFilter =1000.0f;
附設(shè)置默認(rèn)值的方法是:
locationManager.distanceFilter =kCLDistanceFilterNone;
Error Notifications
如果Core Location不能指定你當(dāng)前的位置,它將調(diào)用CLLocation的第二個(gè)代理方法:locationManager:didFailWithError:,最常見的是用戶取消使用定位信息。
獲取定位的信息
①獲取經(jīng)緯度
CLLocationDegrees latitude =theLocation.coordinate.latitude;
CLLocationDegrees longitude =theLocation.coordinate.longitude;
②獲取這個(gè)定位點(diǎn)是什么時(shí)間定到的
NSDate *timestamp = theLocation. timestamp;
CLLocation的另一個(gè)屬性timestamp用來(lái)告訴Location Manager是什么時(shí)候定位的。
③獲取海拔altitude
CLLocationDistance altitude = theLocation.altitude;
海拔值可能會(huì)有誤差。
@property(readonly, nonatomic) CLLocationAccuracy horizontalAccuracy;//水平的精確度(負(fù)數(shù)無(wú)效)
@property(readonly, nonatomic) CLLocationAccuracy verticalAccuracy; //垂直的精確度(負(fù)數(shù)無(wú)效)
所以每一個(gè)CLLocation對(duì)象都有一個(gè)叫verticalAccuracy的屬性來(lái)判斷精確度。其表示海拔數(shù)值可能會(huì)有verticalAccuracy大小的誤差,當(dāng)verticalAccuracy為負(fù)值時(shí),那是Core Location在通知你不能獲取海拔高度。
horizontalAccuracy屬性描述調(diào)整的中心點(diǎn)。horizontalAccuracy值越大越不精確。
計(jì)算兩點(diǎn)的距離
CLLocationDistance distance =[fromLocation getDistanceFrom:toLocation];
返回兩個(gè)時(shí)間段內(nèi)的距離,有時(shí)候它是不考慮海拔的,所以要自己計(jì)算距離。
CLLocation的其他屬性
//航向 、路徑 取值為:0.0 ~ 359.9 真北方向表示:0.0
@property(readonly, nonatomic) CLLocationDirection course ;
//速度 m/s
@property(readonly, nonatomic) CLLocationSpeed speed ;
//時(shí)間
@property(readonly, nonatomic, copy) NSDate *timestamp;
//顯示樓層的信息,如果當(dāng)?shù)刂С值脑?@property(readonly, nonatomic, copy) CLFloor *floor ;
//CLFloor中的一個(gè)屬性,顯示低第幾層樓
@property(readonly, nonatomic) NSInteger level;
//位置的描述,一般的對(duì)象都是可以調(diào)用這個(gè)屬性來(lái)顯示字符描述
@property (nonatomic, readonly, copy) NSString *description;
End
結(jié)束!
