2011年2月10日木曜日

iPhone CoreLocation から GPS情報を最適に利用し、Annotationする方法



CoreLocationManagerは、最初にGPSを取得する際、

「精度よりも、スピード」

を重視するようで、最初から精度を重視する人は(みんなそうだと思うけど)

下記のことをやったほうが良さそう

• 一つ前に取得したGPS情報のタイムスタンプが古い場合
→ newLocation.timestamp

• 精度の悪い情報の時
→ newlocation.horizotalAccuracyが指定した範囲より大きい


<手順>

•位置情報サービスを開始する
[locationManager startUpdatingLocation];

場合によってはこの前に、どのくらい移動したら、
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {

このメソッドを呼ぶかを指定する
locationManager.distanceFilter = "移動距離(m)";

取得し、上記メソッドが呼ばれた際に、
if (-[newLocation.timestamp timeIntervalSinceNow] > 5.0) return;

で前回取得した位置情報のタイムスタンプが古かったら処理をしない


指定した範囲を超えていたら処理をしない
if (newLocation.horizontalAccuracy > "指定した距離") return;




またAnnotationを使用しつつ、持続して、位置情報を取得し続けなければならないアプリの場合は、位置情報が移動したときに、その位置をもとにAnnotationする必要があるかと思います。


その際、問題なのがAnnotationを更新するタイミング。


今回は、下記のことを行った。

• 位置情報取得して、一つまえの緯度経度を覚えておき、その距離が指定した範囲外になったときに、アノテーションし直す。


if(newLocation.speed <= 2) {
moveMeters = 15.0f;
}
else if(newLocation.speed <= 5) {
}


大体、徒歩で、スピードは2前後、電車で、かっ飛ばしても20〜30くらいの数値
上の設定は、徒歩くらいのスピードで移動していたら、15m動いたら処理、

電車の場合は、1km動いたら処理といういうように設定した。

oldLocationとnewLocationの移動距離の計算は独自でやってみた。
下記ソース

- (id)initWithDistance:(CLLocationCoordinate2D)current {
currentLocation = current;
CGFloat lonCircle = CircleEarth;
oneLatMeter = lonCircle / 360;
CGFloat latCircle = cos(currentLocation.latitude / 180 * M_PI) * CircleEarth;
oneLonMeter = latCircle / 360;

return self;
}

- (void)setMoveLocation:(CLLocationCoordinate2D)move {
moveLocation = move; 
}

- (CGFloat)getLatitude:(CGFloat)latitude {

return oneLatMeter;
}

- (CGFloat)getLongitude:(CGFloat)latiude location:(CGFloat)longitude {
return oneLonMeter;
}

- (CGFloat)getLatMeter:(NSInteger)meter {
CGFloat latTime = meter / oneLatMeter;
return latTime;
}

- (CGFloat)getLonMeter:(NSInteger)meter {
CGFloat lonTime = meter / oneLonMeter;
return lonTime;
}


- (BOOL) checkMoveDistance:(CGFloat)checkMeters withDebug:(NSInteger)flag {
CGFloat latitude = (currentLocation.latitude - moveLocation.latitude);
CGFloat longitude = (currentLocation.longitude - moveLocation.longitude);
if(latitude < 0) {
latitude = latitude * (-1);
}
if(longitude < 0) {
longitude = longitude * (-1);
}
double distance = sqrt(pow(latitude * oneLatMeter,2) + pow(longitude * oneLonMeter, 2));
if(distance <= checkMeters) {
if(flag == 1) {
NSLog(@"メートル %fm, %fm => %fm ",latitude * oneLatMeter, longitude * oneLonMeter, distance);
}
return TRUE;
}
return FALSE;
}


例えば、coordinateと、startLocationの距離が、100メートル移動したかどうか調べる時

ConvertUnit *convertUnit = [[[ConvertUnit alloc]initWithDistance:coordinate]autorelease];


[convertUnit setMoveLocation:startLocation];



if([convertUnit checkMoveDistance:100.0f withDebug:0] == FALSE) {
  // 100.0fm以上移動しました
}
else {
   // 100.0fm以内の移動でした
}

この中で、もし指定した範囲以上、移動していたら、新しくAnnotationし直すなどの
処理をする

Annotationをし直す際は、一つ前にAnnotationしたデータをmapViewから削除しないと
Annotationの量がすごいことになるので、注意。



ほかにいい方法あったら誰か教えてください。





0 件のコメント:

コメントを投稿