yoppa.org


多摩美 - “iTamabi” – iPhoneアプリ開発プロジェクト 2010

openFrameworks for iPhone:MapKitを利用して地図を表示する

今日の内容

  • openFrameworks for iPhoneで、地図を表示する
  • 地図から緯度経度の情報をとりだしたり、地図上に図形を配置してみる
  • iTamabiアプリへ応用できるかも?

ofxiPhoneMapKit

  • ofxiPhoneMapKit – openFrameworksでMapKitを利用できるようにしたAddon
  • MapKitは、iPhone OS 3.0から追加された、地図の表示を扱う事ができるフレームワーク
  • MapKitを利用することで、iPhoneに付属の「マップ」アプリと同等の地図を利用することができる
  • ofxiPhoneMapKitは、最新のopenFrameworksのiPhone版であれば、既に利用できる形でインストールされている

ofxiPhoneMapKit の使用方法

  • ofxiPhoneMapKitクラスをインスタンス化する
  • あとは、そのインスタンスに様々なメソッド(関数、動作)を指定するだけで、地図に関する機能を付加していくことができる

opxiPhoneMapKit で使用可能なメソッド

  • open() – 地図を開く
  • close() – 地図を閉じる
  • void setCenter(double latitude, double longitude, bool animated = true); – 地図の中心位置を指定した緯度経度に移動する
  • void setSpan(double latitudeDelta, double longitudeDelta, bool animated = true); – 地図の表示範囲を角度で指定
  • void setSpanWithMeters(double metersLatitude, double metersLongitude, bool animated = true); – 地図の表示範囲を距離(メートル)で指定
  • void setRegion(double latitude, double longitude, double latitudeDelta, double longitudeDelta, bool animated = true); – 地図の中心位置の緯度経度と、表示範囲の角度を同時に指定
  • void setRegionWithMeters(double latitude, double longitude, double metersLatitude, double metersLongitude, bool animated = true); – 地図の中心位置の緯度経度と、表示範囲の距離を同時に指定
  • void setType(ofxiPhoneMapKitType type = OFXIPHONE_MAPKIT_MAP); – 地図の表示方法を指定する
    • 通常の地図:OFXIPHONE_MAPKIT_MAP
    • 衛星画像:OFXIPHONE_MAPKIT_SATELLITE
    • ハイブリット:OFXIPHONE_MAPKIT_HYRBID
  • void setShowUserLocation(bool b); – ユーザの位置を青い点で表示する
  • void setAllowUserInteraction(bool b); – 地図とのインタラクションの有効/無効の設定、有効にするとiPhoneのtouchイベント(testApp::touchXXXX)が無視される
  • void setAllowZoom(bool b); – ズームの有効/無効
  • void setAllowScroll(bool b); – 地図の移動の有効/無効
  • bool isUserOnScreen(); – ユーザの位置の表示がされているかどうかを調べる
  • ofxMapKitLocation getCenterLocation(); – 現在表示している地図の位置(緯度、経度)を調べる
  • ofPoint getScreenCoordinatesForLocation(double latitude, double longitude); – 地図上の位置(緯度、経度)を、画面の座標(ピクセル)に変換
  • ofxMapKitLocation getLocationForScreenCoordinates(float x, float y); – 画面の座標(ピクセル)を、地図上の位置(緯度、経度)に変換
  • ofRectangle getScreenRectForRegion(double latitude, double latitudeDelta, double longitudeDelta); – 地図上の位置(緯度、経度)と角度(°)から、四角形の領域を生成
  • ofRectangle getScreenRectForRegionWithMeters(double latitude, double longitude, double metersLatitude, double metersLongitude); – 地図上の位置(緯度、経度)と距離(メートル)から、四角形の領域を生成
  • bool isOpen(); – 現在地図が表示されているかどうかを調べる

ステップ1:地図を表示する

  • まず、ofxiPhoneMapkitを使用して、地図を表示してみる

testApp.h
[code language=”cpp”]
#pragma once

#include "ofMain.h"
#include "ofxiPhoneExtras.h"

class testApp : public ofxiPhoneApp, ofxiPhoneMapKitListener {

public:
void setup();
void update();
void draw();
void exit();

void touchDown(ofTouchEventArgs &touch);
void touchMoved(ofTouchEventArgs &touch);
void touchUp(ofTouchEventArgs &touch);
void touchDoubleTap(ofTouchEventArgs &touch);

void lostFocus();
void gotFocus();
void gotMemoryWarning();
void deviceOrientationChanged(int newOrientation);

//ofxiPhoneMapKitをインスタンス化
//すべての地図に関する命令は、このオブジェクトを使用する
ofxiPhoneMapKit mapKit;

//地図に関するイベント
void regionWillChange(bool animated);
void regionDidChange(bool animated);
void willStartLoadingMap();
void didFinishLoadingMap();
void errorLoadingMap(string errorDescription);
};
[/code]

testApp.mm
[code language=”cpp”]
#include "testApp.h"

//表示する緯度と経度を定義(多摩美の場所)
#define LATITUDE 35.61129013687765
#define LONGITUDE 139.34929847717285

//————————————————————–
void testApp::setup(){
//iPhoneの基本設定
ofRegisterTouchEvents(this);
ofxAccelerometer.setup();
ofxiPhoneAlerts.addListener(this);
ofSetLogLevel(OF_LOG_VERBOSE);
ofEnableAlphaBlending();

//load font for displaying info
//font.loadFont("verdana.ttf", 12);

//MapViewを開く
mapKit.open();

//最初に表示する位置と、拡大率(200m x 200m)を設定
mapKit.setRegionWithMeters(LATITUDE, LONGITUDE, 200, 200);

//マップに関するイベントのリスナーを追加する
mapKit.addListener(this);

//ユーザの現在位置を表示(青い点で表示される)
mapKit.setShowUserLocation(true);

//マップの表示形式を設定
//通常の地図:OFXIPHONE_MAPKIT_MAP
//衛星画像:OFXIPHONE_MAPKIT_SATELLITE
//ハイブリット:OFXIPHONE_MAPKIT_HYRBID
mapKit.setType(OFXIPHONE_MAPKIT_MAP);
}

//————————————————————–
void testApp::update() {
}

//————————————————————–
void testApp::draw() {
}

void testApp::regionWillChange(bool animated) {
}

void testApp::regionDidChange(bool animated) {
}

void testApp::willStartLoadingMap() {
}

void testApp::didFinishLoadingMap() {
}

void testApp::errorLoadingMap(string errorDescription) {
}

//————————————————————–
void testApp::exit() {
}

//————————————————————–
void testApp::touchDown(ofTouchEventArgs &touch){
}

//————————————————————–
void testApp::touchMoved(ofTouchEventArgs &touch){
}

//————————————————————–
void testApp::touchUp(ofTouchEventArgs &touch){
}

//————————————————————–
void testApp::touchDoubleTap(ofTouchEventArgs &touch){
}

//————————————————————–
void testApp::lostFocus() {
}

//————————————————————–
void testApp::gotFocus() {
}

//————————————————————–
void testApp::gotMemoryWarning() {
}

//————————————————————–
void testApp::deviceOrientationChanged(int newOrientation){
}
[/code]

ステップ2:地図の中心の緯度経度を表示する

  • 地図の中心位置の緯度と経度を取得し、地図に重ねて表示する

testApp.h
[code language=”cpp”]
#pragma once

#include "ofMain.h"
#include "ofxiPhoneExtras.h"

class testApp : public ofxiPhoneApp, ofxiPhoneMapKitListener {

public:
void setup();
void update();
void draw();
void exit();

void touchDown(ofTouchEventArgs &touch);
void touchMoved(ofTouchEventArgs &touch);
void touchUp(ofTouchEventArgs &touch);
void touchDoubleTap(ofTouchEventArgs &touch);

void lostFocus();
void gotFocus();
void gotMemoryWarning();
void deviceOrientationChanged(int newOrientation);

//ofxiPhoneMapKitのインスタンス
//すべての地図に関する命令は、このオブジェクトを使用する
ofxiPhoneMapKit mapKit;

//ログ出力用文字列
string log;

//地図に関するイベント
void regionWillChange(bool animated);
void regionDidChange(bool animated);
void willStartLoadingMap();
void didFinishLoadingMap();
void errorLoadingMap(string errorDescription);
};
[/code]

testApp.mm
[code language=”cpp”]
#include "testApp.h"

//表示する緯度と経度を定義(多摩美の場所)
#define LATITUDE 35.61129013687765
#define LONGITUDE 139.34929847717285

//————————————————————–
void testApp::setup(){
//iPhoneの基本設定
ofRegisterTouchEvents(this);
ofxAccelerometer.setup();
ofxiPhoneAlerts.addListener(this);
ofSetLogLevel(OF_LOG_VERBOSE);
ofEnableAlphaBlending();

//load font for displaying info
//font.loadFont("verdana.ttf", 12);

//MapViewを開く
mapKit.open();

//最初に表示する位置と、拡大率(1000km x 1000km)を設定
mapKit.setRegionWithMeters(LATITUDE, LONGITUDE, 200, 200);

//マップに関するイベントのリスナーを追加する
mapKit.addListener(this);

//ユーザの現在位置を表示(青い点で表示される)
mapKit.setShowUserLocation(true);

//マップの表示形式を設定
//通常の地図:OFXIPHONE_MAPKIT_MAP
//衛星画像:OFXIPHONE_MAPKIT_SATELLITE
//ハイブリット:OFXIPHONE_MAPKIT_HYRBID
mapKit.setType(OFXIPHONE_MAPKIT_MAP);

//OpenGLの表示を前面に
ofxiPhoneSendGLViewToFront();
//OpenGLの透明度を有効に
ofxiPhoneSetGLViewTransparent(true);
//OpenGLの表示部分のインタラクションを無しに
ofxiPhoneSetGLViewUserInteraction(false);
}

//————————————————————–
void testApp::update() {
if(mapKit.isOpen()) {
//現在の中心の緯度と経度を表示
ofxMapKitLocation centerLocation = mapKit.getCenterLocation();
log = "latitude:"+ofToString(centerLocation.latitude,5)+", longitude:"+ofToString(centerLocation.longitude,5);
}
}

//————————————————————–
void testApp::draw() {
if(mapKit.isOpen()) {
ofFill();
ofSetColor(0, 0, 0, 200);
ofRect(0, 0, ofGetWidth(), 20);
ofSetColor(255, 255, 255);
ofDrawBitmapString(log, 10, 10);

//中心位置に円を表示
ofNoFill();
ofSetLineWidth(2);
ofSetColor(255, 0, 0);
ofCircle(ofGetWidth()/2, ofGetHeight()/2, 5);
}
}

void testApp::regionWillChange(bool animated) {

}

void testApp::regionDidChange(bool animated) {

}

void testApp::willStartLoadingMap() {

}

void testApp::didFinishLoadingMap() {

}

void testApp::errorLoadingMap(string errorDescription) {

}

//————————————————————–
void testApp::exit() {
}

//————————————————————–
void testApp::touchDown(ofTouchEventArgs &touch){
}

//————————————————————–
void testApp::touchMoved(ofTouchEventArgs &touch){
}

//————————————————————–
void testApp::touchUp(ofTouchEventArgs &touch){
}

//————————————————————–
void testApp::touchDoubleTap(ofTouchEventArgs &touch){
}

//————————————————————–
void testApp::lostFocus() {
}

//————————————————————–
void testApp::gotFocus() {
}

//————————————————————–
void testApp::gotMemoryWarning() {
}

//————————————————————–
void testApp::deviceOrientationChanged(int newOrientation){
}
[/code]

ステップ3:地図上に図形を配置する

  • 緯度と経度を指定して、地図の上に図形を描いて配置していく
  • 地図を拡大/縮小したり、位置を移動しても、地図上の点の位置がずれていないところに注目

testApp.h
[code language=”cpp”]
#pragma once

#include "ofMain.h"
#include "ofxiPhoneExtras.h"

class testApp : public ofxiPhoneApp, ofxiPhoneMapKitListener {

public:
void setup();
void update();
void draw();
void exit();

void touchDown(ofTouchEventArgs &touch);
void touchMoved(ofTouchEventArgs &touch);
void touchUp(ofTouchEventArgs &touch);
void touchDoubleTap(ofTouchEventArgs &touch);

void lostFocus();
void gotFocus();
void gotMemoryWarning();
void deviceOrientationChanged(int newOrientation);

//ofxiPhoneMapKitのインスタンス
//すべての地図に関する命令は、このオブジェクトを使用する
ofxiPhoneMapKit mapKit;

//ログ出力用文字列
string log;

//緯度、経度で位置を指定するための配列
ofxMapKitLocation mapLoc[9];

//地図に関するイベント
void regionWillChange(bool animated);
void regionDidChange(bool animated);
void willStartLoadingMap();
void didFinishLoadingMap();
void errorLoadingMap(string errorDescription);
};
[/code]

testApp.mm
[code language=”cpp”]
#include "testApp.h"

//表示する緯度と経度を定義(多摩美の場所)
#define LATITUDE 35.61127
#define LONGITUDE 139.34983

//————————————————————–
void testApp::setup(){
//iPhoneの基本設定
ofRegisterTouchEvents(this);
ofxAccelerometer.setup();
ofxiPhoneAlerts.addListener(this);
ofSetLogLevel(OF_LOG_VERBOSE);
ofEnableAlphaBlending();

//緯度、経度で位置を指定
mapLoc[0].latitude = 35.61045;
mapLoc[0].longitude = 139.35108;

mapLoc[1].latitude = 35.61090;
mapLoc[1].longitude = 139.35029;

mapLoc[2].latitude = 35.61124;
mapLoc[2].longitude = 139.34923;

mapLoc[3].latitude = 35.61139;
mapLoc[3].longitude = 139.35041;

mapLoc[4].latitude = 35.61207;
mapLoc[4].longitude = 139.35048;

mapLoc[5].latitude = 35.61185;
mapLoc[5].longitude = 139.34979;

mapLoc[6].latitude = 35.61153;
mapLoc[6].longitude = 139.35120;

mapLoc[7].latitude = 35.61222;
mapLoc[7].longitude = 139.34878;

mapLoc[8].latitude = 35.61150;
mapLoc[8].longitude = 139.34828;

//MapViewを開く
mapKit.open();

//最初に表示する位置と、拡大率(300m x 300m)を設定
mapKit.setRegionWithMeters(LATITUDE, LONGITUDE, 300, 300);

//マップに関するイベントのリスナーを追加する
mapKit.addListener(this);

//ユーザの現在位置を表示(青い点で表示される)
mapKit.setShowUserLocation(true);

//マップの表示形式を設定
//通常の地図:OFXIPHONE_MAPKIT_MAP
//衛星画像:OFXIPHONE_MAPKIT_SATELLITE
//ハイブリット:OFXIPHONE_MAPKIT_HYRBID
mapKit.setType(OFXIPHONE_MAPKIT_MAP);

//OpenGLの表示を前面に
ofxiPhoneSendGLViewToFront();
//OpenGLの透明度を有効に
ofxiPhoneSetGLViewTransparent(true);
//OpenGLの表示部分のインタラクションを無しに
ofxiPhoneSetGLViewUserInteraction(false);
}

//————————————————————–
void testApp::update() {
if(mapKit.isOpen()) {
//現在の中心の緯度と経度を表示
ofxMapKitLocation centerLocation = mapKit.getCenterLocation();
log = "latitude:"+ofToString(centerLocation.latitude,5)+", longitude:"+ofToString(centerLocation.longitude,5);
}
}

//————————————————————–
void testApp::draw() {
if(mapKit.isOpen()) {
ofFill();
ofSetColor(0, 0, 0, 200);
ofRect(0, 0, ofGetWidth(), 20);
ofSetColor(255, 255, 255);
ofDrawBitmapString(log, 10, 10);

//中心位置に赤い円を表示
ofNoFill();
ofSetLineWidth(2);
ofSetColor(255, 0, 0);
ofCircle(ofGetWidth()/2, ofGetHeight()/2, 5);

//位置を指定した場所に青い円を表示
ofFill();
ofSetColor(0, 0, 255);
for (int i=0; i<9; i++) {
ofPoint loc = mapKit.getScreenCoordinatesForLocation(mapLoc[i].latitude, mapLoc[i].longitude);
ofCircle(loc.x, loc.y, 5);
}
}
}

void testApp::regionWillChange(bool animated) {

}

void testApp::regionDidChange(bool animated) {

}

void testApp::willStartLoadingMap() {

}

void testApp::didFinishLoadingMap() {

}

void testApp::errorLoadingMap(string errorDescription) {

}

//————————————————————–
void testApp::exit() {
}

//————————————————————–
void testApp::touchDown(ofTouchEventArgs &touch){
}

//————————————————————–
void testApp::touchMoved(ofTouchEventArgs &touch){
}

//————————————————————–
void testApp::touchUp(ofTouchEventArgs &touch){
}

//————————————————————–
void testApp::touchDoubleTap(ofTouchEventArgs &touch){
}

//————————————————————–
void testApp::lostFocus() {
}

//————————————————————–
void testApp::gotFocus() {
}

//————————————————————–
void testApp::gotMemoryWarning() {
}

//————————————————————–
void testApp::deviceOrientationChanged(int newOrientation){
}
[/code]

サンプルファイルのダウンロード

今日の授業の全てのサンプルファイルは、以下のリンクよりダウンロードしてください