iPhoneのプログラム

SATCHを用いたナビアプリ(3)その1

disp3.lua
local MLTPlugin = getMLTPluginManager()
local scene = getCurrentScene()
local camera = Camera(scene:getCurrentCamera())
local vidCap = VideoCapture(scene:getObjectByName("vidcap"))
local msg = Text2D(scene:getObjectByName("msg"))

-- 方向指示用
local boussole = Entity(scene:getObjectByName("Boussole"))
local fleche = Entity(scene:getObjectByName("Fleche"))
boussole:setVisible(false)
fleche:setVisible(false)

-- 色識別用
local mainView = RenderTarget(scene:getMainView())
local targetDirectory = getUserAppDataDirectory()
local targetJpg = targetDirectory .. "c1.jpg"
local camera_mode = 1

local componentInterface = getComponentInterface()

local err_ret = eOk
local trackingIndex = -1
local targetStatus = {-1, -1, -1}
local action = {"1104    found!", "2    found!", "1011    found!"}
local marker_no = {
1104, 2, 1011
}

local found_marker = -1
local dest = -1
local found = -1
local i=0
local mode = 1

local isCommand = nil
local command = nil

msg:setText(" ")

err_ret, trackingIndex = MLTPlugin:startTracking("tracker/tracker.xml", vidCap:getVidCapID(), camera)

repeat
	if (mode == 1) then

		if (found_marker < 0) then
			for i = 1,3 do
				err_ret, targetStatus[i] = MLTPlugin:getTargetStatus(trackingIndex, i-1)
			end

			found = -1
			for i = 1,3 do
				if (targetStatus[i] == 1) then
					found = i
					break
				end
			end

			if (found ~= -1) then
				msg:setText(action[found])
				found_marker = marker_no[found]
			else
				msg:setText(" ")
			end
		else
   			if componentInterface then
				componentInterface:executeAppFunc("setStartPosition", found_marker);
			end
			mode = 2
		end

	elseif (mode == 2) then
		msg:setText(" ")

		if componentInterface then
			isCommand, command = componentInterface:pullCommand()
			if isCommand then
				if command["CommandName"]=="sendGyro" then
					boussole:setVisible(true)
					fleche:setVisible(true)
					fleche:setOrientationEuler(0,command["arg1"],0,boussole)
					mode = 3;
				end
			end
		end

	elseif (mode == 3) then

		if componentInterface then
			isCommand, command = componentInterface:pullCommand()
			if isCommand then
				if command["CommandName"]=="sendGyro" then
					fleche:setOrientationEuler(0,command["arg1"],0,boussole)
				elseif command["CommandName"]=="prepareCamera" then
					boussole:setVisible(false)
					fleche:setVisible(false)
					camera_mode = 1
					mode = 4
				end
			end
		end

	elseif (mode == 4) then

		if camera_mode == 1 then
			if componentInterface then
				isCommand, command = componentInterface:pullCommand()
				if isCommand then
					if command["CommandName"]=="capture" then
						mainView:dump(targetJpg)
						camera_mode = 2
					end
				end
			end
		elseif camera_mode == 2 then
			if componentInterface then
				componentInterface:executeAppFunc("setCaptureFilename", targetJpg);
			end
			mode = 2
		end

	end

until coroutine.yield()
AppDelegate.h
#import <UIKit/UIKit.h>
#import <CoreMotion/CoreMotion.h>
#import "Spot.h"

// 前
#define NAVI_DIRECT_FORWARD         1

// 右斜め前
#define NAVI_DIRECT_RIGHT_FORWARD   2

// 右
#define NAVI_DIRECT_RIGHT           3

// 右斜め後ろ
#define NAVI_DIRECT_RIGHT_BACKWARD  4

// 後ろ
#define NAVI_DIRECT_BACKWARD        5

// 左斜め後ろ
#define NAVI_DIRECT_LEFT_BACKWARD   6

// 左
#define NAVI_DIRECT_LEFT            7

// 左斜め前
#define NAVI_DIRECT_LEFT_FORWARD    8

@class ViewController;

@interface AppDelegate : UIResponder <UIApplicationDelegate> {
    int numPath;
    int countPath;
    CMMotionManager *motionManager;
    CMAttitude *referenceAttitude;
    BOOL isCaptured;
    
    int curDirect;
}

@property (strong, nonatomic) UIWindow *window;

@property (strong, nonatomic) ViewController *viewController;

@property (strong, nonatomic) UINavigationController *navController;

@property (strong, nonatomic) NSMutableArray *spots;

@property (retain, nonatomic) Spot *startSpot;

@property (retain, nonatomic) Spot *destSpot;

@property (retain, nonatomic) NSArray *path1;

@property (retain, nonatomic) NSArray *path2;

- (void)gotoNaviMode;
- (void)stepNext;

@end

AppDelegate.mm
#import "AppDelegate.h"
#import "ViewController.h"
#import "Spot.h"
#import "URLLoader.h"
#import "NaviXMLParser.h"

@implementation AppDelegate

@synthesize window = _window;
@synthesize viewController = _viewController;
@synthesize navController = _navController;
@synthesize spots = _spots;

@synthesize startSpot;
@synthesize destSpot;

@synthesize path1;
@synthesize path2;

- (void)dealloc
{
    [_window release];
    [_viewController release];
    [_spots release];
    [super dealloc];
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
    // Override point for customization after application launch.
    numPath = 1;
    countPath = 0;
    curDirect = 1;

    Spot *s1 = [[Spot alloc] init];
    s1.spotID = @"1";
    s1.spotName = @"入り口(K2号館側)";

    Spot *s2 = [[Spot alloc] init];
    s2.spotID = @"2";
    s2.spotName = @"入り口(マクドナルド側)";
    
    Spot *s1101 = [[Spot alloc] init];
    s1101.spotID = @"1101";
    s1101.spotName = @"西村(広)教員室(1101)";

    Spot *s1102 = [[Spot alloc] init];
    s1102.spotID = @"1102";
    s1102.spotName = @"春日教員室(1102)";

    Spot *s1103 = [[Spot alloc] init];
    s1103.spotID = @"1103";
    s1103.spotName = @"共通教員室(1103)";

    Spot *s1104 = [[Spot alloc] init];
    s1104.spotID = @"1104";
    s1104.spotName = @"富川研究室・山内研究室(1104)";

    Spot *s1105 = [[Spot alloc] init];
    s1105.spotID = @"1105";
    s1105.spotName = @"富川教員室(1105)";

    Spot *s1106 = [[Spot alloc] init];
    s1106.spotID = @"1106";
    s1106.spotName = @"谷中教員室(1106)";

    Spot *s1107 = [[Spot alloc] init];
    s1107.spotID = @"1107";
    s1107.spotName = @"谷中研究室(1107)";

    Spot *s1108 = [[Spot alloc] init];
    s1108.spotID = @"1108";
    s1108.spotName = @"佐藤研究室・鈴木(浩)研究室(1108)";

    Spot *s1109 = [[Spot alloc] init];
    s1109.spotID = @"1109";
    s1109.spotName = @"佐藤教員室(1109)";

    self.spots = [[NSMutableArray alloc] 
                  initWithObjects:s1, s2, 
                  s1101, s1102, s1103, s1104, s1105,
                  s1106, s1107, s1108, s1109, nil];
    
    // ジャイロ関係
    motionManager = [[CMMotionManager alloc] init];
    motionManager.deviceMotionUpdateInterval = 1.0f/4.0f; // ジャイロのサンプリング間隔[s]    
    isCaptured = NO;
    referenceAttitude = nil;
    
    self.viewController = [[[ViewController alloc] initWithNibName:@"ViewController" bundle:nil] autorelease];
    self.navController = [[UINavigationController alloc] 
                          initWithRootViewController:self.viewController];
    self.window.rootViewController = self.navController;
    
    [self.window makeKeyAndVisible];
    return YES;
}

- (void)applicationWillResignActive:(UIApplication *)application
{
    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
    // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}

- (void)applicationDidEnterBackground:(UIApplication *)application
{
    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 
    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}

- (void)applicationWillEnterForeground:(UIApplication *)application
{
    // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}

- (void)applicationWillTerminate:(UIApplication *)application
{
    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}

- (void)gotoNaviMode
{
    self.viewController.txtMsg.text = [NSString stringWithFormat:@"出発地:%@, 目的地:%@",
                                        startSpot.spotName, destSpot.spotName];
    
    NSString *url = [NSString 
        stringWithFormat:@"http://www.tosiyama.jp/personal/cgi/navitest8.cgi?start=%@&target=%@",
                     startSpot.spotID, destSpot.spotID];

    URLLoader *loader = [[[URLLoader alloc] init] autorelease];
    
    [[NSNotificationCenter defaultCenter] addObserver:self 
                                             selector:@selector(loadNaviDataDidEnd:) 
                                                 name:@"connectionDidFinishNotification"
                                               object:loader];
    
    [[NSNotificationCenter defaultCenter] addObserver:self 
                                             selector:@selector(loadNaviDataFailed:) 
                                                 name:@"connectionDidFailWithError" 
                                               object:loader];
    
    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
    [loader loadFromUrl:url method:@"GET"];
}
     
- (void)loadNaviDataDidEnd:(NSNotification *)notification
{
    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
    URLLoader *loader = (URLLoader *)[notification object];
    NSData *xmlData = loader.data;
    
    NaviXMLParser *parser = [[[NaviXMLParser alloc] init] autorelease];
    
    NSArray *naviData = [parser parseNaviData:xmlData];
    numPath = [naviData count];
    self.path1 = [naviData objectAtIndex:0];
    self.path2 = nil;
    if (numPath == 2) {
        self.path2 = [naviData objectAtIndex:1];
    }
    
    self.viewController.btnCorner.enabled = YES;
    [self stepNext];
    [self startGyro:NO];
}

- (int)adjustDirection:(int)dir prev:(int)prevDir
{
    int total = ((prevDir-1) + (dir-1)) % 8;
    return (total + 1);
}

- (void)stepNext
{
    if (countPath < [self.path1 count]) {
        
        int cmd = [[[self.path1 objectAtIndex:countPath] objectForKey:@"command"] intValue];
        NSString *msg = [[path1 objectAtIndex:countPath] objectForKey:@"msg"];
        
        if (curDirect == 0) {
            isCaptured = NO;
            curDirect = 1;
        }
        
        if (cmd > 10) {
            curDirect = [self adjustDirection:(cmd % 10) prev:curDirect];
        }
        else if (cmd == 0) {
            curDirect = 0;
            [motionManager stopDeviceMotionUpdates];
        }
        else if (cmd > 0) {
            curDirect = [self adjustDirection:cmd prev:curDirect];
        }

        if (msg != nil) {
            self.viewController.txtMsg.text = msg;
        }
        countPath++;
        if (countPath == [self.path1 count]) 
        {
            self.viewController.btnCorner.enabled = NO;
        }
    }
}

- (void)startGyro:(BOOL)restart
{
    // デバイスのハードウェアチェック
    if (!motionManager.deviceMotionAvailable)
    {
        NSLog(@"DeviceMotion is not available.");
        return;
    }
    
    isCaptured = restart;
    
    // モーションデータ更新時のハンドラを作成
    void (^handler)(CMDeviceMotion *, NSError *) = ^(CMDeviceMotion *motion, NSError *error)
    {
        if (isCaptured == NO) {
            referenceAttitude = [motion.attitude retain];
            isCaptured = YES;
        }
        else {
            // ジャイロデータの記録
            [self recordGyroData:motion];
        }
    };
    
    // モーションデータの測定を開始
    NSOperationQueue *queue = [NSOperationQueue currentQueue];
    [motionManager startDeviceMotionUpdatesToQueue:queue withHandler:handler];
}

- (void)recordGyroData:(CMDeviceMotion *)motion
{    
    CMAttitude *currentAttitude = motion.attitude;
    
    if (referenceAttitude != nil) {
        [currentAttitude multiplyByInverseOfAttitude: referenceAttitude];
    }
    
    // 角度を度数に変換
    float rollDegree = 180 * currentAttitude.roll / M_PI;
    NSNumber *direct = [self calcDirection:rollDegree mode:curDirect];
    
    NSString *_roll = [NSString stringWithFormat:@"%.4f", rollDegree];
    NSString *_roll2 = [NSString stringWithFormat:@"%.4f", [direct floatValue]];
    
    NSArray *para = [NSArray arrayWithObjects:_roll, _roll2, nil];
    NSLog(@"roll=%f, roll2=%f", rollDegree, [direct floatValue]);
    
    [direct release];
    [self.viewController enqueueCommand:@"sendGyro" args:para];
}

- (NSNumber *)calcDirection:(float)roll mode:(int)num
{
    float _direct = 0.0;
    switch (num) {
        case NAVI_DIRECT_FORWARD:
            _direct = roll;
            if (_direct <= 0) {
                _direct = -_direct;
            }
            else {
                _direct = 360.0 - _direct;
            }
            break;
            
        case NAVI_DIRECT_RIGHT:
            _direct = roll + 90.0;
            if (_direct <= 0) {
                _direct = -_direct;
            }
            else {
                _direct = 360.0 - _direct;
            }
            break;
            
        case NAVI_DIRECT_LEFT:
            _direct = roll - 90.0;
            if (_direct <= 0) {
                _direct = -_direct;
            }
            else {
                _direct = 360.0 - _direct;
            }
            break;
            
        case NAVI_DIRECT_BACKWARD:
            _direct = roll - 180;
            if (_direct <= 0) {
                _direct = -_direct;
            }
            else {
                _direct = 360.0 - _direct;
            }
            break;
            
        case NAVI_DIRECT_RIGHT_FORWARD:
            _direct = roll + 45.0;
            if (_direct <= 0) {
                _direct = -_direct;
            }
            else {
                _direct = 360.0 - _direct;
            }
            break;
            
        case NAVI_DIRECT_LEFT_FORWARD:
            _direct = roll - 45.0;
            if (_direct <= 0) {
                _direct = -_direct;
            }
            else {
                _direct = 360.0 - _direct;
            }
            break;
            
        case NAVI_DIRECT_RIGHT_BACKWARD:
            _direct = roll + 135.0;
            if (_direct <= 0) {
                _direct = -_direct;
            }
            else {
                _direct = 360.0 - _direct;
            }
            break;
            
        case NAVI_DIRECT_LEFT_BACKWARD:
            _direct = roll - 135.0;
            if (_direct <= 0) {
                _direct = -_direct;
            }
            else {
                _direct = 360.0 - _direct;
            }
            break;
            
    }
    
    NSNumber *direct = [[NSNumber alloc] initWithFloat:_direct];
    return direct;
}

- (void)loadNaviDataFailed:(NSNotification *)notification
{
    UIAlertView *alert = [[UIAlertView alloc]
                          initWithTitle:@"エラー" 
                          message:@"xmlデータの取得に失敗しました!" 
                          delegate:self 
                          cancelButtonTitle:@"閉じる" 
                          otherButtonTitles:nil];
    [alert show];
    [alert release];
}

@end

ViewController.h
#import <UIKit/UIKit.h>
#import "satchARViewer.h"
#import "Spot.h"

@interface ViewController : UIViewController {
    SatchARViewer *mPlayer;
}

@property (retain, nonatomic) IBOutlet UIButton *btnCorner;
@property (retain, nonatomic) IBOutlet UIView *mRender;
@property (retain, nonatomic) IBOutlet UITextView *txtMsg;

- (IBAction)pushCornerButton:(id)sender;

- (void)start;
- (void)stop;

- (void)enqueueCommand:(NSString *)commandName args:(NSArray *)args;

@end

ViewController.m
#import "AppDelegate.h"
#import "ViewController.h"
#import "DestController.h"

@interface ViewController ()

@end

@implementation ViewController
@synthesize btnCorner;
@synthesize mRender;
@synthesize txtMsg;

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.title = @"メイン画面";
    
    //メッセージのローカライズ
    [SatchARViewer        setDialogMessageLoading:@"ローディング..."];
    [SatchARViewer        setToastMessageNoNetworkConnection:@"ネットワークに接続されていません。"];
    [SatchARViewer        setToastMessageNetworkError:@"通信中にエラーが発生しました。"];
    [SatchARViewer        setToastMessageLicenceError:@"認証に失敗しました"];
    
    mPlayer = [[[SatchARViewer alloc] init] initialize:mRender];
    [self start];
    
    btnCorner.enabled = NO;
    txtMsg.text = @"出発地のマーカをかざしてください!";
	// Do any additional setup after loading the view, typically from a nib.
}

- (void)viewDidUnload
{
    [self setMRender:nil];
    [self setTxtMsg:nil];
    [self setTxtMsg:nil];
    [self setBtnCorner:nil];
    [super viewDidUnload];
    // Release any retained subviews of the main view.
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}

- (void)dealloc {
    if (mPlayer) {
        [mPlayer terminate];
        [mPlayer release];
        mPlayer = nil;
    }
    
    [mRender release];
    [txtMsg release];
    [txtMsg release];
    [btnCorner release];
    [super dealloc];
}

- (void)start
{
    if (mPlayer) {
        [mPlayer loadScenario:@"Nov1_iphone/Nov1.dpd"
                     callback:@selector(callback:)
                          obj:self];
    }
}


- (void)callback:(NSNumber*)num
{
    switch ([num intValue]) {
        case LOAD_SCENARIO_STATUS_COMPLETE:
            [mPlayer registerCommunicationCallback:@"setStartPosition" 
                                    callbackObject:self 
                                    callbackMethod:@"TI_SetStartPosNotification"];
            [[NSNotificationCenter defaultCenter] addObserver:self
                                                     selector:@selector(setStartPosition:) 
                                                         name:@"TI_SetStartPosNotification" 
                                                       object:nil];
            [mPlayer playScenario];
            break;
    }
}

- (void)stop
{
    if (mPlayer && ![mPlayer isScenarioPaused]) {
        [mPlayer pauseScenario];
    }    
}

- (IBAction)pushCornerButton:(id)sender 
{
    AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    [delegate stepNext];
}

- (void)setStartPosition:(NSNotification *)notification
{
    AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    
    NSDictionary* l_userInfo = [notification userInfo];
    NSString *s1 = (NSString *)[l_userInfo objectForKey:@"arg0"];
    
    NSUInteger idx = [delegate.spots indexOfObjectPassingTest:
                      ^BOOL(id obj, NSUInteger idx, BOOL *stop) {
                          Spot *cur_spot = (Spot *)obj;
                          return [cur_spot.spotID isEqualToString:s1];
                      }];
    delegate.startSpot = (Spot *)[delegate.spots objectAtIndex:idx];
    txtMsg.text = [NSString stringWithFormat:@"出発地:%@", delegate.startSpot.spotName];    
    
    DestController *dest = [[DestController alloc] init];
    [delegate.navController pushViewController:dest animated:YES];
}

- (void)enqueueCommand:(NSString *)commandName args:(NSArray *)args
{
    if (mPlayer) {
        [mPlayer enqueueCommand:commandName args:args];
    }
}
@end

URLLoader.h
#import <Foundation/Foundation.h>

@interface URLLoader : NSObject {
    NSURLConnection *connection;
    NSMutableData *data;
}

@property (retain, nonatomic) NSURLConnection *connection;
@property (retain, nonatomic) NSMutableData *data;

- (void)loadFromUrl:(NSString *)_url method:(NSString *)_method;

@end

URLLoader.m
#import "URLLoader.h"

@implementation URLLoader

@synthesize connection;
@synthesize data;

- (void)connection:(NSURLConnection *)conn
        didReceiveResponse:(NSURLResponse *)response {
    self.data = [NSMutableData data];
}

- (void)connection:(NSURLConnection *)conn
        didReceiveData:(NSData *)receiveData {
    [self.data appendData:receiveData];
}

- (void)connectionDidFinishLoading:(NSURLConnection *)conn {
    [[NSNotificationCenter defaultCenter]
        postNotificationName:@"connectionDidFinishNotification"
        object:self];
}

- (void)connection:(NSURLConnection *)conn
        didFailWithError:(NSError *)error {
    [[NSNotificationCenter defaultCenter]
     postNotificationName:@"connectionDidFailWithError"
     object:self];
}

- (void)loadFromUrl:(NSString *)_url method:(NSString *)_method {
    NSMutableURLRequest *req = [NSMutableURLRequest
requestWithURL:[NSURL URLWithString:_url]];
    [req setHTTPMethod:_method];
    self.connection = [NSURLConnection connectionWithRequest:req delegate:self];
}

- (void)dealloc {
    [connection release];
    [data release];
    [super dealloc];
}

@end

NaviXMLParser.h
#import <UIKit/UIKit.h>

@interface NaviXMLParser : NSObject <NSXMLParserDelegate> {
    NSMutableString *currentXpath;
    NSMutableArray *NaviData;
    NSMutableArray *PathData;
    NSMutableDictionary *currentGuide;
    NSMutableString *textNodeCharacters;
}

@property (retain , nonatomic) NSMutableString *currentXpath;
@property (retain , nonatomic) NSMutableArray *NaviData;
@property (retain , nonatomic) NSMutableArray *PathData;

@property (retain , nonatomic) NSMutableDictionary *currentGuide;
@property (retain , nonatomic) NSMutableString *textNodeCharacters;

- (NSArray *) parseNaviData: (NSData *) xmlData;

@end

NaviXMLParser.m
#import "NaviXMLParser.h"

@implementation NaviXMLParser

@synthesize currentXpath;
@synthesize NaviData;
@synthesize PathData;
@synthesize currentGuide;
@synthesize textNodeCharacters;

- (void)parserDidStartDocument:(NSXMLParser *)parser
{
    self.currentXpath = [[[NSMutableString alloc] init] autorelease];
    self.NaviData = [[[NSMutableArray alloc] init] autorelease];
}

- (void)parser:(NSXMLParser *)parser 
    didStartElement:(NSString *)elementName
    namespaceURI:(NSString *)namespaceURI 
    qualifiedName:(NSString *)qName 
    attributes:(NSDictionary *)attributeDict 
{
    [self.currentXpath appendString: elementName];
    [self.currentXpath appendString: @"/"];
    
    self.textNodeCharacters = [[[NSMutableString alloc] init] autorelease];
    
    if ([self.currentXpath isEqualToString: @"navi/path/"]) {
        self.PathData = [[[NSMutableArray alloc] init] autorelease];
    }
    else if ([self.currentXpath isEqualToString: @"navi/path/guide/"]) {
        self.currentGuide = [[[NSMutableDictionary alloc] init] autorelease];
    }
}

- (void)parser:(NSXMLParser *)parser 
    didEndElement:(NSString *)elementName 
    namespaceURI:(NSString *)namespaceURI 
    qualifiedName:(NSString *)qName 
{    
    NSString *textData = [self.textNodeCharacters stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
    
    if ([self.currentXpath isEqualToString: @"navi/path/"]) 
    {
        [self.NaviData addObject:self.PathData];
        self.PathData = nil;
    }
    else if ([self.currentXpath isEqualToString: @"navi/path/guide/"]) 
    {
        [self.PathData addObject:self.currentGuide];
        self.currentGuide = nil;        
    }
    else if ([self.currentXpath isEqualToString: @"navi/path/guide/command/"]) 
    {
        [self.currentGuide setValue:textData forKey:@"command"];
    }
    else if ([self.currentXpath isEqualToString: @"navi/path/guide/msg/"]) 
    {
        [self.currentGuide setValue:textData forKey:@"msg"];
    }
    
    int delLength = [elementName length] + 1;
    int delIndex = [self.currentXpath length] - delLength;
    
    [self.currentXpath deleteCharactersInRange:NSMakeRange(delIndex,delLength)];
}

- (void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string 
{
    [self.textNodeCharacters appendString:string];
}

- (NSArray *)parseNaviData:(NSData *)xmlData 
{
    NSXMLParser *parser = [[[NSXMLParser alloc] initWithData:xmlData] autorelease];
    [parser setDelegate:self];
    [parser parse];
    
    return self.NaviData;
}

- (void) dealloc 
{
    [currentXpath release];
    [NaviData release];
    [PathData release];
    [currentGuide release];
    [textNodeCharacters release];
    [super dealloc];
}

@end

Spot.h
#import <UIKit/UIKit.h>

@interface Spot : NSObject

@property (nonatomic, strong) NSString *spotID;
@property (nonatomic, strong) NSString *spotName;

@end

Spot.m
#import "Spot.h"

@implementation Spot

@synthesize spotID;
@synthesize spotName;

@end

DestController.h
#import <UIKit/UIKit.h>

@interface DestController : UIViewController <UITableViewDataSource, UITableViewDelegate> {
    NSMutableArray *spots;
}

@property (retain, nonatomic) IBOutlet UITableView *tableView;

@end

DestController.m
#import "AppDelegate.h"
#import "DestController.h"
#import "Spot.h"

@interface DestController ()

@end

@implementation DestController
@synthesize tableView;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.title = @"目的地の選択";
    
    AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    spots = delegate.spots;
    // Do any additional setup after loading the view from its nib.
}

- (void)viewDidUnload
{
    [self setTableView:nil];
    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}

- (void)dealloc {
    [tableView release];
    [super dealloc];
}

#pragma mark UITableViewDataSource Methods

- (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tv dequeueReusableCellWithIdentifier:@"cell"];
    if (nil == cell) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"];
    }
    
    Spot *thisSpot = [spots objectAtIndex:indexPath.row];
    cell.textLabel.text = thisSpot.spotName;
    return cell;
}

- (NSInteger)tableView:(UITableView *)tv numberOfRowsInSection:(NSInteger)section
{
    return [spots count];
}

#pragma mark UITableViewDelegate Methods

- (void)tableView:(UITableView *)tv didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    Spot *thisSpot = [spots objectAtIndex:indexPath.row];
    AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    delegate.destSpot = thisSpot;
    [delegate gotoNaviMode];
    
    [self dismissModalViewControllerAnimated:YES];
}
@end