yoppa.org


immediate bitwave

多摩美 - “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

#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);
};

testApp.mm

#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){
}

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

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

testApp.h

#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);
};

testApp.mm

#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){
}

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

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

testApp.h

#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);
};

testApp.mm

#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){
}

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

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