12
14
2011
iPhone用GPSナビに挑戦 #4
iPhone3GSのGPSは使い物になるのか?
前回Google Maps上に自分の位置を表示する簡単なアプリを作成してみましたが、まだCore Location フレームワークをどのようにコントロールすれば良いのか手探り状態と言ったところでしょうか.Core Location フレームワーク現在位置を取得するタイミングやその値〔精度)がバラバラでかなり手こずっています.
尤も私の使っているiPhoneは2世代前のiPhone3GSで、現在はSIMカードも抜いてありますので、3Gによる通信も出来ない状態です.私は普段ユピテルのASG-1というアウトドア用のGPSロガーを持ち歩いていますが、iPhone3GSのGPSの受信感度や精度に関してはかなり不安を抱いています.果たしてiPhone3GSはGPSナビとしてまともに使用できるのかどうか懐疑的です.Core Location フレームワークが返してくる精度情報(Accuracy)の数値を見ていると50〜150mなんて数値が出てきて驚いてしまいます.アウトドア用として販売されているGPSロガーやGPSナビの精度は水平で10m,垂直方向で20〜30m以内には収まっています.
iPhone内蔵のGPSの精度に期待できない場合は、BluetoothタイプのGPSロガーと連携させて、iPhoneを単なる地図表示デバイスとして使うという方法も考えなくてはならないかもしれません.最新のiPhone4SでGPSの性能を試してみたいところですが、慢性金欠病の私にはちょっと手が出せません.
iPhone用のGPSナビを作成する計画に少し暗雲が立ちこめてきましたが、とりあえず自分の勉強のため今後もGPSナビアプリ作りに挑戦してみたいと思います.
iOSのUIWebView上に電子国土WEBマップを表示してみる
iPhoneシミュレータ上で電子国土WEBマップを表示してみた
前回はGoogle Maps上に現在地を表示する簡単なアプリを作成してみましたが、今回はGoogle Mapsではなく本命の電子国土WEB地図を表示してみることにします.勿論電波の届かない場所で使うことが前提のGPSナビですので、電子国土WEB地図が表示できたところで現場では殆ど役に立ちませんが、電子国土の地図配信サーバから地図データを取得(キャッシュ)する場合の範囲選択などの場面で役に立つかもしれません.
Google Mapsに関しては大部分の方々が実際に使用したり、自分でマップアプリを開発したりしたことが有ると思いますので説明の必要はないでしょうが、国土地理院が提供している電子国土システムに関しては知らない人が殆どでしょう.正直なところ電子国土システムは使い勝手やAPIの整備状況、汎用性などはGoogle MapsやYahoo Japan Map などと較べると貧弱です.電子国土システムを用いたWEBアプリを開発しようとするとかなり苦労します.現在電子国土WEBマップシステムはオープンソースのフレームワークを用いて作り直しているところですが、APIそのものは前バージョンと互換性を持たせるため殆ど変更が無いようです.できればAPIもスクラッチビルドして欲しいところです.
電子国土を用いたWEBアプリの開発についての詳細は国土地理院の電子国土ポータルサイトからドキュメントを取得して目を通しておくと良いでしょう.
電子国土WEBマップをWEBブラウザ上に表示するには、Google Mapsのように直接地図を埋め込むことはできず、必ず “map” という名前のインラインフレーム <iframe> を用意しなければなりません.電子国土のWEBマップはこのインラインフレーム内にしか表示することができません.このインラインフレーム内に表示するHTMLコンテンツとして、国土地理院が用意している “webtis_map_obj.htm” というお決まりのHTMLファイルを指定しなければなりません.この”webtis_map_obj.htm”が関連する電子国土システムのJavascriptライブラリをWEBブラウザにロードし、環境を整えた後で ”app_main()” というユーザが用意した関数に制御を渡す仕組みになっています.
HTMLのサンプルは次の様なものになります.
“webtis_map_obj.htm” の内容は、
[sourcecode]
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>WebTIS_map V3</title>
<script>
function isGeckoWithPlugin() {
if(navigator.userAgent.indexOf(‘Firefox’) != -1) return false;
if(navigator.mimeTypes &&
navigator.mimeTypes[‘application/x-webtis’] &&
navigator.mimeTypes[‘application/x-webtis’].enabledPlugin) {
return true;
} else {
return false;
}
}
if(isGeckoWithPlugin()) {
// XPCOM
var url =
‘jar:’ + location.href.substring(0, location.href.lastIndexOf(‘/’)) +
‘/webtis_map.jar!/webtis_map_obj_ns.htm’;
document.location.href = url;
}
</script>
<script language="Javascript" src="http://portal2.cyberjapan.jp/sys/webtis.js" charset="Shift_JIS"></script>
<script language="Javascript" src="http://portal2.cyberjapan.jp/sys/affixture.js" charset="Shift_JIS"></script>
<script language="Javascript">createWebtisObjectVer3();</script>
<!–
/* デフォルトの設定では、このファイル(webtis_webtis_map_obj.htm)の置いてある場所にあるwebtis_map.jarファイルを読みに行きます。
webtis_map.jarファイルの場所を変更する場合は、21行目の記述を以下のように変更します。
‘jar:’ + ‘「ここを書き換えて下さい」’ +
の「ここを書き換えて下さい」の部分を、webtis_map.jarファイルのURLに書き換えてください。*/
//–>
</head>
</html>
[/sourcecode]
となっています.いちいちユーザ側でHTMLファイルを用意してその中にインラインフレームを作成するという面倒で融通のきかない変な仕様になっています.通常の静的なWEBページに組み込む場合には技術的な問題は生じないでしょうが、WordpressのプラグインのようにWEBアプリとしてモジュール化して使いこなしたいような場合には困りものです.
UIWebView を用いたWEBコンテンツの表示
iOSやMac OS X には UIWebViewというフレームワークが用意されており、ユーザが自分のアプリに簡単にWEBブラウザ機能を組み込むことができるようになっています.勿論UIWebViewはSafariで使われているコアと同じ物でWEBKitベースの最新のレンダリングエンジンです.
UIWebViewに関しての詳細は、 UIWebView Class Referenceを参照して下さい.
“ViewController.h”
[sourcecode]
//
// ViewController.h
// GetLocation
//
// Created by y2 on 12/9/11.
// Copyright (c) 2011 y2tech.net. All rights reserved.
//
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
//#import <MapKit/MapKit.h>
@interface ViewController : UIViewController <CLLocationManagerDelegate, UIApplicationDelegate> {
CLLocationManager *locationManager;
UIWebView *webView;
IBOutlet UILabel *locationText;
IBOutlet UILabel *accuracyText;
//IBOutlet MKMapView *googleMapView;
}
@property (nonatomic, retain) CLLocationManager *locationManager;
@property (retain, nonatomic) UILabel *locationText;
@property (retain, nonatomic) UILabel *accuracyText;
@property (nonatomic, retain) IBOutlet UIWebView *webView;
//@property (nonatomic, retain) IBOutlet MKMapView *googleMapView;
@end
[/sourcecode]
“ViewController.m”
[sourcecode]
//
// ViewController.m
// GetLocation
//
// Created by y2 on 12/9/11.
// Copyright (c) 2011 y2tech.net. All rights reserved.
//
#import "ViewController.h"
@implementation ViewController
@synthesize locationManager;
@synthesize locationText, accuracyText;
@synthesize webView;
//@synthesize latTextField, lonTextField, altTextField;
//@synthesize googleMapView;
– (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren’t in use.
}
#pragma mark – View lifecycle
– (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSString *path = [[NSBundle mainBundle] pathForResource:@"cjmapv3" ofType:@"html"];
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:path]]];
// Allocate a location manager instance and initialize it.
locationManager = [[CLLocationManager alloc] init];
// check to see if location service is available or not.
if ([CLLocationManager locationServicesEnabled]) {
locationManager.delegate = self;
// set accuracy and event filtering parameters
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
locationManager.distanceFilter = kCLDistanceFilterNone;
//locationManager.distanceFilter = 50.0f; // 50m
// start location service
[locationManager startUpdatingLocation];
} else {
NSString *msg = [[NSString alloc]
initWithString:@"Error : Location service is not available."];
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:@"Error"
message:msg
delegate:nil
cancelButtonTitle: @"Done"
otherButtonTitles:nil];
[alert show];
// [msg release]; // use Xcode4.2 ARC
// [alert release];
}
}
– (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
– (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
}
– (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
}
– (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
}
– (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
}
– (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
//================= Core Location Service Delegates ======================
– (void) locationManager: (CLLocationManager *) manager
didUpdateToLocation: (CLLocation *) newLocation
fromLocation: (CLLocation *) oldLocation {
NSString *latitude = [[NSString alloc] initWithFormat:@"%.6f", newLocation.coordinate.latitude];
NSString *longitude = [[NSString alloc] initWithFormat:@"%.6f", newLocation.coordinate.longitude];
NSString *altitude = [[NSString alloc] initWithFormat:@"%.0f", newLocation.altitude];
NSString *hAccuracy = [[NSString alloc] initWithFormat:@"%.0fm", newLocation.horizontalAccuracy];
NSString *vAccuracy = [[NSString alloc] initWithFormat:@"%.0fm", newLocation.verticalAccuracy];
NSString *location = [[NSString alloc] initWithFormat:@"Location: %@,%@ Alt: %@", latitude, longitude, altitude];
NSString *accuracy = [[NSString alloc] initWithFormat:@"Accuracy: H:%@, V:%@", hAccuracy, vAccuracy ];
//NSLog( @"Current Location latitude=%@, longitude=%@, altitude=%@", latitude, longitude, altitude );
locationText.text = location;
accuracyText.text = accuracy;
NSString *cjmapJSText = [[NSString alloc] initWithFormat:@"map.setMapCenter(%@, %@, 14000); map.redrawMap();", longitude, latitude ];
[webView stringByEvaluatingJavaScriptFromString: cjmapJSText];
}
– (void) locationManager: (CLLocationManager *) manager
didFailWithError: (NSError *) error {
NSString *msg = [[NSString alloc] initWithString:@"Error obtaining location"];
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:@"Error"
message: msg
delegate:nil
cancelButtonTitle: @"Done"
otherButtonTitles:nil];
[alert show];
// [msg release];
// [alert release];
}
@end
[/sourcecode]
電子国土にアクセスするためのHTMLリソースとして次の”cjmapv3.html” を用意し、バンドルリソースとしてアクセスできるようにプロジェクトに組み込みます.同様に”webtis_map_obj.htm”も組み込んでおきます.
バンドルリソースとしてHTMLファイルを組み込んでおく
“cjmapv3.html” [sourcecode] <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja"> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8" /> <title>Cyber Japan Map V3 Delegator</title> <style type="text/css"> body { border: none !important; margin: 0 !important; } </style> <script type="text/javascript"> // Kengamine, Mt. Fuji : 138°43’38.5" E (138.727361), 35°21’38.3" N (35.36063888) var lat=35.36063888; var lon=138.727361; var scale=9000; // dummy var width=320; var height=416; var args = getArguments(); if ( args.lat ) lat = parseFloat( args.lat ); if ( args.lon ) lon = parseFloat( args.lon ); if ( args.latlon ) { latlon = args.latlon.split( "," ); lat = parseFloat( latlon[0] ); lon = parseFloat( latlon[1] ); } if ( args.scale ) scale = parseInt( args.scale ); function app_main() { map.createScaleBar(); map.SelectFramework( "Mixed_L" ); map.setMouseMode( ‘pan2’ ); map.enableWheelZoom( true ); map.setMapCenter( lon, lat, scale ); map.openMap(); } function getArguments() { var args = new Object(); var query = location.search.substring( 1 ); var pairs = query.split( "&" ); for ( var i = 0; i < pairs.length; i++ ) { var pos = pairs[i].indexOf( "=" ); if ( pos == -1 ) continue; var argname = pairs[i].substring( 0, pos ); var value = pairs[i].substring( pos + 1 ); args[ argname ] = unescape( value ); } return( args ); } </script> </head> <body> <iframe name="map" id="map" src="./webtis_map_obj_v3.html" width="320" height="416" style="border: 0; margin : 0;"></iframe> <iframe name="message" src="" style="display:none" frameborder="0"></iframe> </body> </html> [/sourcecode]
iPhone3GS上で電子国土WEBマップを表示してみた
上記のプログラムはまだ試行錯誤段階で、実機で上記のプログラムを実行しても上手く地図を表示してくれない事の方が多いです.通常のWEBブラウザ上では問題有りませんが、iOS上では何故か地図の移動〔ドラッグ)やズームが上手くできません.
まだ UIWebViewの使い方が良く理解できていない部分が多く、頓珍漢なプログラムなので上手く動いていない部分が多いとは思いますが、通常のWEBアプリケーションのように 電子国土WEB地図をHTML(CSS) + Javascript の組み合わせで自由に制御するのは困難でしょう.
現実問題として電子国土地図をiPhone上でGPSナビとして利用するには、背景の地図データを一旦画像データとしてダウンロードして、iPhone上でWEBコンテンツとして表示するのではなく、単なる画像データとして表示するようにしないと使い物にならないでしょう.このような仕組みであれば地図の表示に電子国土のAPIを使わずに済むので、iOSのネイティブなアプリケーションとして自由にユーザインタフェースを組み込むことができます.
背景地図の滑らかなズームやスクロール、進行方向に応じた背景地図の回転などの機能を実現するにはWEBアプリでは不可能でしょう.
iOS上での電子国土WEBマップ(背景地図)の表示についてはまた別な機会に紹介したいと思います.