方位角の求め方をソースコード付きで解説します。
iPhone/iPad/iPod等のARアプリでよく目にする仮想現実上に浮かぶポイントは、
何を元に浮かぶ位置を決定しているのでしょうか?
主に、現在いる位置から目的物に対する方角を算出し、iPhone/iPad/iPodの加速度センサーやコンパスにて
向いている方角を算出し、対象物に対する方位角と照らし合わせて
位置を決定しています。
今回は、そんなARアプリ開発に欠かせない『方位角』の取得方法について解説します。
ARアプリにおける方位角
そもそも、方位角とはどんなものなのでしょうか?
方位角とは、ある地点から、ある基準となる方角を0度とし、そこから目的地点への角度の事です。
例えば、北を基準とする場合、現在位置から北を向いている場合は0度。
現在地点から東にあるコンビニを見ると、コンビニの方位角は90度。
あくまで基準となる方角からの角度ですので、
例えば基準方角を自分が向いている方向とすると、自分が向いている方向から
対象物までの角度が分かります。
現在地点から東にコンビニがあり、自分が北を向いていればコンビニまでの方位角は90度。
南を向いていれば270度。といった角度が方位角です。
ARアプリでカメラを起動したとして、カメラの向いている方向を基準方向とすれば
目的地への方位角さえ分かればカメラ内の何処に看板を置けば目的地までの方向かがわかります。
加速度センサーとコンパスにて随時向いている方向を取得し、カメラ内に浮かせた看板の位置を更新すれば
カメラ内の指示に従って目的地の方向へと導く事も可能です。
北を基準とした二点間の緯度と経度を元に方位角を算出
Objective-C的な方位角の求め方は下記サイトのコードをサンプルコードとして表記させて頂きます。
iphonearkit
http://code.google.com/p/iphonearkit/source/browse/trunk/ARKitDemo/Classes/ARGeoCoordinate.m?r=2
上記サイトの様に、具体的に方位角を取得するメソッドを定義すると、下記の様になります。
//------------------------------------------------------------------------------ // 北を基準として二点間の緯度・経度を元に方位角を算出する //------------------------------------------------------------------------------ float CalculateAngle(float nLat1, float nLon1, float nLat2, float nLon2) { float longitudinalDifference = nLon2 - nLon1; float latitudinalDifference = nLat2 - nLat1; float azimuth = (M_PI * .5f) - atan(latitudinalDifference / longitudinalDifference); if (longitudinalDifference > 0) return( azimuth ); else if (longitudinalDifference < 0) return( azimuth + M_PI ); else if (latitudinalDifference < 0) return( M_PI ); return( 0.0f ); }
このメソッドをコピペでも十分に方位角を求める事が出来ます。
サンプルコードで見る方位角の利用方法
例えば、現在位置と目的地の北を基準とした方位角を取得し、
『自分が向いている方向との差を求めれば左右どちらに何度向いた方向に目的地がある』
といった事も求められるようになります。
下記にサンプルコードを示します
//------------------------------------------------------------------------------ // 北を基準として二点間の緯度・経度を元に方位角を算出する //------------------------------------------------------------------------------ float CalculateAngle(float nLat1, float nLon1, float nLat2, float nLon2) { float longitudinalDifference = nLon2 - nLon1; float latitudinalDifference = nLat2 - nLat1; float azimuth = (M_PI * .5f) - atan(latitudinalDifference / longitudinalDifference); if (longitudinalDifference > 0) return( azimuth ); else if (longitudinalDifference < 0) return( azimuth + M_PI ); else if (latitudinalDifference < 0) return( M_PI ); return( 0.0f ); } //------------------------------------------------------------------------------ // GPSイベント:方位の取得 //------------------------------------------------------------------------------ -(void)locationManager:(CLLocationManager*)manager didUpdateHeading:(CLHeading*)newHeading { // 方位角を求める double azimuth = CalculateAngle(self.nowLatitude, self.nowLongitude, target.latitude, target.longitude); // 現在向いている方位から方位角を引き、今向いている方向から対象物までの角度を算出する double target_azimuth = newHeading.trueHeading - azimuth; /* target_azimuthがマイナス値なら左方向、プラス値なら右方向に対象物があります。 自分が向いている方向を0度として考える事が出来ます。 */ } //------------------------------------------------------------------------------ // GPSイベント:座標取得成功 //------------------------------------------------------------------------------ -(void)locationManager:(CLLocationManager*)manager didUpdateToLocation:(CLLocation*)newLocation fromLocation:(CLLocation*)oldLocation { // 現在位置の緯度経度を格納する self.nowLatitude = [newLocation coordinate].latitude; self.nowLongitude = [newLocation coordinate].longitude; } //------------------------------------------------------------------------------ // viewの初回構築 //------------------------------------------------------------------------------ -(void)viewDidLoad { [super viewDidLoad]; // 現在位置の取得 self.locationManager = nil; self.locationManager = [[[CLLocationManager alloc] init] autorelease]; [self.locationManager setDelegate:self]; [self.locationManager setDesiredAccuracy:kCLLocationAccuracyBest]; // 測量の制度を「出来る限り正確」に設定 [self.locationManager setDistanceFilter:kCLDistanceFilterNone]; [self.locationManager startUpdatingLocation]; // 現在位置を取得する [self.locationManager startUpdatingHeading]; // コンパスの向きを取得 }
後はtarget_azimuthの値を使ってカメラに目的地の方向を示したり
地図を回転させつつ目的地の方向へ矢印を出したり
方位を使いこなせば、かなりアイデア次第で面白いアプリが作れるようになります。
また、先日エントリーしました『二点間の緯度、経度を元に距離を算出する方法』と合わせると
更に楽しいかも知れません。
方位角取得計算方法等、こういったアルゴリズムは理解するより覚えてしまった方が早いと思います。
サンプルコードも、どんどん改変して使って下さい。
今後も有益な情報を配信していきます。
// 現在向いている方位から方位角を引き、今向いている方向から対象物までの角度を算出する
返信削除double target_azimuth = newHeading.trueHeading - azimuth;
↑の件ですが、今向いている方向から対象物までの角度を算出すると書いてあるのですが、↓ではtarget_azimuthが向いている方向ですと書いてあります。
どちらが本当でしょうか?
/*
target_azimuthが向いている方向です。マイナス値なら左方向、プラス値なら右方向。
自分が向いている方向を0度として考える事が出来ます。
*/
宜しくお願いします。
お世話になります。
削除この度はご指摘頂きまして、誠に有難うございます。
// 現在向いている方位から方位角を引き、今向いている方向から対象物までの角度を算出する
こちらが正解です。
/*
target_azimuthが向いている方向です。マイナス値なら左方向、プラス値なら右方向。
自分が向いている方向を0度として考える事が出来ます。
*/
上記を下記の様に修正させて頂きました。
/*
target_azimuthがマイナス値なら左方向、プラス値なら右方向に対象物があります。
自分が向いている方向を0度として考える事が出来ます。
*/
他にも矛盾している点がありましたら、
お手数お掛けしますがコメント頂ければ幸いです。
何卒、よろしくお願い致します。
ご質問をさせて頂いた者です。
返信削除ご丁寧にご対応頂きましてありがとうございました。
より良い情報を提供する為、他にも何かお気づきの点が御座いましたら
削除どしどしコメント頂ければ幸いです。
今後ともよろしくお願いいたします。