方向関連のイベント
- ヘディング(heading)【iOS 4.0以降】
- 磁力センサーを利用して、「北」がどちらにあるかを計測します。単純に「北」と言っても、以下の二種類があり、どちらを示すかで方角が少し変わってきます。ヘディングでは両方を扱うことができます。詳細は「真北 - Wikipedia」「真北とは? | 用語集とGISの使い方 | 株式会社パスコ」などをご覧ください。
- 磁北(じほく/magnetic north): 地球の磁場上の北です。(普通の)コンパスなどを使った場合に示されるものとなります。デバイスに内蔵されている磁力センサーを使って磁北を求めることができます。
- 真北(しんぽく/true north): 普段の生活で良く使われる地図上の北です。北極点へと向かう線となります。磁北と真北はズレている為、現在地を元にしてそのズレを修正するものです。つまり、磁力センサーと現在地情報の両方が必要となります。
- コース(course)【iOS 2.2以降】
- 位置情報を利用して、どの方角へ移動しているかを計測します。前回の「CoreLocationサンプル1 - 現在位置の取得と領域観測 」で現在地情報を取得しましたが、その際に既に利用したプロパティで情報を取得できます。
標準アプリ「コンパス」でも「真北」と「磁北」を切り替えられます。
実装手順
- 「CoreLocation.framework」の追加
- 必要に応じて、<project-name>-Info.plistファイルにキー「location-services」「magnetometer」「gps」を追加する。
- ただし、現在位置の情報や磁力センサー、GPSが無くともアプリケーションが正常に動作する場合には追加すべきではありません。(UIRequiredDeviceCapabilitiesについての詳細は「iOSデバイス間の互換性まとめ」をご覧下さい。)
- ただし、現在位置の情報や磁力センサー、GPSが無くともアプリケーションが正常に動作する場合には追加すべきではありません。(UIRequiredDeviceCapabilitiesについての詳細は「iOSデバイス間の互換性まとめ」をご覧下さい。)
- ヘッダのインポート
#import <CoreLocation/CoreLocation.h>
- CLLocationManagerDelegateプロトコルの宣言
@interface ViewController : UIViewController <CLLocationManagerDelegate> @end
- (真北の情報が必要であれば)位置情報サービスの開始
- ヘディングイベントの開始
- ヘディングイベント情報の受け取り
- (不必要になったら)ヘディングイベント(と位置情報サービス)の停止
磁北の取得
- ヘディングイベントの開始
iOS 3.xにも対応させる必要がある場合はプロパティ【Deprecated in iOS 4.0】を使います。// プロパティではなくクラスメソッドです if ([CLLocationManager headingAvailable]) { // インスタンスを生成し、デリゲートの設定 _manager = [[CLLocationManager alloc] init]; _manager.delegate = self; _manager.headingFilter = kCLHeadingFilterNone; // 更新頻度 _manager.headingOrientation = CLDeviceOrientationPortrait; // 基準とする向き [_locationManager startUpdatingHeading]; }
// インスタンスの生成 _manager = [[CLLocationManager alloc] init]; if (_manager.headingAvailable || [CLLocationManager headingAvailable]) { // 必要な設定をして、ヘディングイベントの開始 }
- ヘディング情報の受け取り
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading { // ここで任意の処理 CLLocationDirection heading = newHeading.magneticHeading; }
- (不必要になったら)ヘディングイベントの停止
if ([CLLocationManager headingAvailable]) { [_manager stopUpdatingHeading]; }
真北の取得
- ヘディングイベントの開始
// 位置情報サービスの開始 if ([CLLocationManager locationServicesEnabled]) { _manager.desiredAccuracy = kCLLocationAccuracyBest; _manager.distanceFilter = kCLDistanceFilterNone; [_manager startUpdatingLocation]; } // ヘディングイベントの開始 if ([CLLocationManager headingAvailable]) { // プロパティではなくクラスメソッドです // インスタンスを生成し、デリゲートの設定 _manager = [[CLLocationManager alloc] init]; _manager.delegate = self; _manager.headingFilter = kCLHeadingFilterNone; _manager.headingOrientation = CLDeviceOrientationPortrait; [_locationManager startUpdatingHeading]; }
- ヘディングイベント情報の受け取り
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading { // ここで任意の処理 CLLocationDirection heading = newHeading.trueHeading; }
- (不必要になったら)ヘディングイベントと位置情報サービスの停止
if ([CLLocationManager headingAvailable]) { [_manager stopUpdatingHeading]; [_manager stopUpdatingLocation]; }
CLLocationManager
デバイスが機能を備えているかどうか
- ヘディングイベントを扱えるか【iOS 4.0以降】
iOS 3.xでも使いたい場合【Deprecated in iOS 4.0】+ (BOOL)headingAvailable __OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_4_0);
デバイスに、磁力センサーの機能があるかを確認する。【iOS 4.0以降】@property(readonly, nonatomic) BOOL locationServicesEnabled __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_NA,__MAC_NA,__IPHONE_2_0,__IPHONE_4_0);
ヘディングイベントの挙動を設定
- 次回の更新までの角度【iOS 3.0以降】
指定の角度動いたらヘディングイベントを生成する。単位は度数。kCLHeadingFilterNoneを指定すると、角度ではなく、動く度にイベントが通知されるようになります。デフォルトは1度です。@property(assign, nonatomic) CLLocationDegrees headingFilter __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_3_0); // 定義 typedef double CLLocationDegrees;
- デバイスで基準とする向き【iOS 4.0以降】
デバイスのどの向きが基準となるかを決める。例えば、ホームボタンを右にして横向きに持った状態で北を設定した場合は「CLDeviceOrientationLandscapeLeft」を指定します。デフォルトはCLDeviceOrientationPortrait。@property(assign, nonatomic) CLDeviceOrientation headingOrientation __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_4_0); // 定義 typedef enum { CLDeviceOrientationUnknown = 0, CLDeviceOrientationPortrait, CLDeviceOrientationPortraitUpsideDown, CLDeviceOrientationLandscapeLeft, CLDeviceOrientationLandscapeRight, CLDeviceOrientationFaceUp, CLDeviceOrientationFaceDown } CLDeviceOrientation;
イメージ 定数 説明 無しCLDeviceOrientationUnknown 無視される CLDeviceOrientationPortrait 画面上部を北とする CLDeviceOrientationPortraitUpsideDown 画面下部を北とする CLDeviceOrientationLandscapeLeft 画面右部を北とする CLDeviceOrientationLandscapeRight 画面左部を北とする 画面が表(上)CLDeviceOrientationFaceUp 無視される 画面が裏(下)CLDeviceOrientationFaceDown 無視される
利用開始
- ヘディングイベント【iOS 3.0以降】
- (void)startUpdatingHeading __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_3_0);
- キャリブレーション表示を隠す【iOS 3.0以降】
周りに磁力の強いものがあったりすると、正しく磁力センサーが働かなくなってしまう。その場合は下図のように、iOSが自動的に「8の字に振ってください」とのメッセージを表示するのだが、それを隠す。このメソッドを利用しなくても、キャリブレーションが成功すれば自動的に隠れます。(locationManagerShouldDisplayHeadingCalibrationを使わない場合に使用するのだろうが、使いどころが不明です)- (void)dismissHeadingCalibrationDisplay __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_3_0);
利用停止
- ヘディングイベント【iOS 3.0以降】
- (void)stopUpdatingHeading __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_3_0);
情報の取得
- ヘディング情報の取得【iOS 4.0以降】
最新のヘディング情報が格納されている。デリゲートを利用しない場合にも利用できる。@property(readonly, nonatomic) CLHeading *heading __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_4_0);
CLLocationManagerDelegate
情報の更新時
- ヘディング情報の更新時【iOS 3.0以降】
ヘディング情報が更新された際に呼ばれる。- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_3_0);
- キャリブレーション表示をするかどうか【iOS 3.0以降】
周りに磁力の強いものがあったりすると、正しく磁力センサーが働かなくなってしまう。その場合に、「8の字に振ってください」とのメッセージを表示するかどうかを返す。表示しないと磁力センサーの値がおかしいまま修正されません。- (BOOL)locationManagerShouldDisplayHeadingCalibration:(CLLocationManager *)manager __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_3_0);
デザイン的に表示してほしくない場合などにNOを返すと良いのか?(使いどころが不明です。)
CLHeading
ヘディング情報
- 磁北の角度【iOS 3.0以降】
磁北の角度を取得する。0.0から359.9の値で、0(北),90(東),180(南),270(西)となる。@property(readonly, nonatomic) CLLocationDirection magneticHeading; // 定義 typedef double CLLocationDirection;
- 真北の角度【iOS 3.0以降】
真北の角度を取得する。0.0から359.9の値で、0(北),90(東),180(南),270(西)となる。@property(readonly, nonatomic) CLLocationDirection trueHeading; // 定義 typedef double CLLocationDirection;
取得した情報の精度
- 精度【iOS 3.0以降】
磁北の方角と、計測された磁力から導き出した方角とのズレを角度で示す。値が小さいほど正確な磁北を示す。しかし、キャリブレーションが正しく行われていない場合など、負の値になる。@property(readonly, nonatomic) CLLocationDirection headingAccuracy; // 定義 typedef double CLLocationDirection;
- 計測された磁力の数値【iOS 3.0以降】
それぞれの方向の磁力センサーから得られた磁力をマイクロテスラで示す。-128から+128までの正規化された値になる。@property(readonly, nonatomic) CLHeadingComponentValue x; @property(readonly, nonatomic) CLHeadingComponentValue y; @property(readonly, nonatomic) CLHeadingComponentValue z;
サンプル
ソースコードはGitHubにて公開しています。iOS-SampleCodes/CoreLocationSample-HeadingRelated - GitHub
「設定 > 位置情報サービス >システムサービス > コンパスの調整」について
電池の持ちを良くするためとして、位置情報サービスのシステムサービスの全てをオフにしていました。ただ、「コンパスの調整」だけは意味が分からないままだったので、今回はこれが原因でハマりました。このスイッチの意味は、iPhoneのユーザーズガイドにも詳細な説明は書かれておらず、色々と調べても分からずに疑問だったのですが、磁力センサーを利用して方角の計測をするときに「磁北」だけではなく「真北」も自動的に計測するというもののようです。
- コンパスの調整「オン」
- 磁北だけではなく、真北も自動で計測する。その際「ステータスバーアイコン」も「オン」になっていれば、ステータスバーの右上に矢印を表示する。
- コンパスの調整「オフ」
- 磁北のみで、真北は"利用できない"。
つまり、「コンパスの調整」がオフのままだと、「真北」の利用が出来なくなります。その時の、標準アプリ「コンパス」の例です。真北の選択ができません。
今回のサンプルの場合は以下の通りです。コンパスの針に見立てた「^」が北を示します。ボタンを押すことで、磁北と真北とを切り替えることもできます。ですが、位置情報サービス(startUpdatingLocation)をオンにしても、真北の情報(trueHeading)を得られませんでした。
そこで、「コンパスの調整」を「オン」にすると真北が利用できるようになりました。
下図のように、アプリの標準位置情報サービスはまだオンになっていないのに、バックグラウンドで位置情報を取得し、真北を計算しています。この時表示されている矢印は「コンパスの調整」が自動的に位置情報を取得して真北を計算しているようです。それを表示するかしないかの判定が「ステータスバーアイコン」ということになります。
上の方で、真北を得るためには「startUpdatingLocation」と「startUpdatingHeading」の両方が必要だと書いたのですが、位置情報サービスを開始しても真北を得られないとなると、それは困ります。ご存知の方、ご教示いただけると幸いです。
「磁北」と「真北」の違い。若干、示す角度が異なっています。
iPod touch(第4世代)では、磁力センサーがないため、電子コンパスとして利用できません。
0 コメント:
コメントを投稿