[LeapMotion]Xcode, Objective-Cで開発

2013/07/29
Leap Motion」を手に入れたのでXcodeで試してみた。 LeapMotion

海外がお得

国内で買うと倍くらいしてしまうので、海外で買った方がお得で、意外と早く届きます(3日で届いた)。

セットアップ

https://www.leapmotion.com/setupから「Leap Motion Installer」をダウンロードして、インストールします。 非常にわかりやすいセットアップナビゲーションです。

アプリ管理は「AirSpace」

アプリ管理は「AirSpace」で行います。 https://airspace.leapmotion.com/にアクセスすると、iTunesStore、GooglePlayのようにアプリが購入できます。 フリーのソフトもあるので、ざっと試す事ができます。

開発環境

Leap Motionは、色々な言語に対応しているので自分の得意分野で開発かと思います。 (自分は XCode、Objective-Cで開発) SDKは、https://developer.leapmotion.com/downloads からダウンロードできます。 ダウンロードしたSDKは、自分の管理しやすいパスに配置します。 LeapMotion ※自分は「/Users/ユーザ/leap/LeapSDK/」にしました

XCode、Objective-Cで開発

Xcode、Objective-Cで開発するにはいくつか準備が必要です。 (1) libLeap.dylib (2) Leap、LeapMathヘッダファイル (3) LeapObjectiveC

プロジェクト作成

Cocoa Applicationでプロジェクト作成 LeapMotion ARCで作成してみる LeapMotion

Build Settingsの設定

「LeapSDK」のライブラリを利用するには、パスを通してやる必要があります。 まず、配置したLeapSDKのパス定義 LeapMotion ※「LEAPSDK_PATH」としました headerファイルのパス定義 LeapMotion $(LEAPSDK_PATH)/inclulde libraryファイルのパス定義 LeapMotion $(LEAPSDK_PATH)/lib

includeファイルの追加

「Leap.h」「LeapMath.h」「LeapObjectiveC.h」「LeapObjectiveC.mm」をプロジェクトにドラッグ&ドロップ LeapMotion LeapMotion

libLeap.dylib

「libLeap.dylib」をプロジェクトにドラッグ&ドロップ LeapMotion Build Phasesで、ファイルが追加されるのを確認 LeapMotion

DEMO

メインプログラムは「LeapSDK/samples/Sample.cpp」をそのまま記述しました。

LeapTest.h

#import <Foundation/Foundation.h>
#import "LeapObjectiveC.h"

@interface LeapTest : NSObject<LeapListener>

- (void)run;

@end
「LeapObjectiveC.h」を読み込んで、「LeapListener」で拡張

LeapTest.m

#import "LeapTest.h"

@implementation LeapTest
{
    LeapController *controller;
}

- (void)run
{
    controller = [[LeapController alloc] init];
    [controller addListener:self];
    NSLog(@"running");
}

- (void)onInit:(NSNotification *)notification
{
    NSLog(@"Initialized");
}

- (void)onConnect:(NSNotification *)notification
{
    NSLog(@"Connected");
    LeapController *aController = (LeapController *)[notification object];
    [aController enableGesture:LEAP_GESTURE_TYPE_CIRCLE enable:YES];
    [aController enableGesture:LEAP_GESTURE_TYPE_KEY_TAP enable:YES];
    [aController enableGesture:LEAP_GESTURE_TYPE_SCREEN_TAP enable:YES];
    [aController enableGesture:LEAP_GESTURE_TYPE_SWIPE enable:YES];
}

- (void)onDisconnect:(NSNotification *)notification
{
    //Note: not dispatched when running in a debugger.
    NSLog(@"Disconnected");
}

- (void)onExit:(NSNotification *)notification
{
    NSLog(@"Exited");
}

- (void)onFrame:(NSNotification *)notification
{
    LeapController *aController = (LeapController *)[notification object];
    LeapFrame *frame = [aController frame:0];
    
    NSLog(@"Frame id: %lld, timestamp: %lld, hands: %ld, fingers: %ld, tools: %ld, gestures: %ld",
          [frame id], [frame timestamp], [[frame hands] count],
          [[frame fingers] count], [[frame tools] count], [[frame gestures:nil] count]);
    
    if ([[frame hands] count] != 0) {
        LeapHand *hand = [[frame hands] objectAtIndex:0];
        
        NSArray *fingers = [hand fingers];
        if ([fingers count] != 0) {
            LeapVector *avgPos = [[LeapVector alloc] init];
            for (int i = 0; i < [fingers count]; i++) {
                LeapFinger *finger = [fingers objectAtIndex:i];
                avgPos = [avgPos plus:[finger tipPosition]];
            }
            avgPos = [avgPos divide:[fingers count]];
            NSLog(@"Hand has %ld fingers, average finger tip position %@",
                  [fingers count], avgPos);
        }
        
        NSLog(@"Hand sphere radius: %f mm, palm position: %@",
              [hand sphereRadius], [hand palmPosition]);
        
        const LeapVector *normal = [hand palmNormal];
        const LeapVector *direction = [hand direction];
        
        NSLog(@"Hand pitch: %f degrees, roll: %f degrees, yaw: %f degrees\n",
              [direction pitch] * LEAP_RAD_TO_DEG,
              [normal roll] * LEAP_RAD_TO_DEG,
              [direction yaw] * LEAP_RAD_TO_DEG);
    }
    
    NSArray *gestures = [frame gestures:nil];
    for (int g = 0; g < [gestures count]; g++) {
        LeapGesture *gesture = [gestures objectAtIndex:g];
        switch (gesture.type) {
            case LEAP_GESTURE_TYPE_CIRCLE: {
                LeapCircleGesture *circleGesture = (LeapCircleGesture *)gesture;
                
                NSString *clockwiseness;
                if ([[[circleGesture pointable] direction] angleTo:[circleGesture normal]] <= LEAP_PI/4) {
                    clockwiseness = @"clockwise";
                } else {
                    clockwiseness = @"counterclockwise";
                }
                
                float sweptAngle = 0;
                if(circleGesture.state != LEAP_GESTURE_STATE_START) {
                    LeapCircleGesture *previousUpdate = (LeapCircleGesture *)[[aController frame:1] gesture:gesture.id];
                    sweptAngle = (circleGesture.progress - previousUpdate.progress) * 2 * LEAP_PI;
                }
                
                NSLog(@"Circle id: %d, %@, progress: %f, radius %f, angle: %f degrees %@",
                      circleGesture.id, [LeapTest stringForState:gesture.state],
                      circleGesture.progress, circleGesture.radius,
                      sweptAngle * LEAP_RAD_TO_DEG, clockwiseness);
                break;
            }
            case LEAP_GESTURE_TYPE_SWIPE: {
                LeapSwipeGesture *swipeGesture = (LeapSwipeGesture *)gesture;
                NSLog(@"Swipe id: %d, %@, position: %@, direction: %@, speed: %f",
                      swipeGesture.id, [LeapTest stringForState:swipeGesture.state],
                      swipeGesture.position, swipeGesture.direction, swipeGesture.speed);
                break;
            }
            case LEAP_GESTURE_TYPE_KEY_TAP: {
                LeapKeyTapGesture *keyTapGesture = (LeapKeyTapGesture *)gesture;
                NSLog(@"Key Tap id: %d, %@, position: %@, direction: %@",
                      keyTapGesture.id, [LeapTest stringForState:keyTapGesture.state],
                      keyTapGesture.position, keyTapGesture.direction);
                break;
            }
            case LEAP_GESTURE_TYPE_SCREEN_TAP: {
                LeapScreenTapGesture *screenTapGesture = (LeapScreenTapGesture *)gesture;
                NSLog(@"Screen Tap id: %d, %@, position: %@, direction: %@",
                      screenTapGesture.id, [LeapTest stringForState:screenTapGesture.state],
                      screenTapGesture.position, screenTapGesture.direction);
                break;
            }
            default:
                NSLog(@"Unknown gesture type");
                break;
        }
    }
    
    if (([[frame hands] count] > 0) || [[frame gestures:nil] count] > 0) {
        NSLog(@" ");
    }
}

- (void)onFocusGained:(NSNotification *)notification
{
    NSLog(@"Focus Gained");
}

- (void)onFocusLost:(NSNotification *)notification
{
    NSLog(@"Focus Lost");
}

+ (NSString *)stringForState:(LeapGestureState)state
{
    switch (state) {
        case LEAP_GESTURE_STATE_INVALID:
            return @"STATE_INVALID";
        case LEAP_GESTURE_STATE_START:
            return @"STATE_START";
        case LEAP_GESTURE_STATE_UPDATE:
            return @"STATE_UPDATED";
        case LEAP_GESTURE_STATE_STOP:
            return @"STATE_STOP";
        default:
            return @"STATE_INVALID";
    }
}
@end
サイクルは以下の種類があり、NSNotificationで検知して処理するようです。 - (void)onInit:(NSNotification *)notification - (void)onConnect:(NSNotification *)notification - (void)onDisconnect:(NSNotification *)notification - (void)onExit:(NSNotification *)notification - (void)onFrame:(NSNotification *)notification - (void)onFocusGained:(NSNotification *)notification ジェスチャーはonFrame()で主に処理してやる必要がありますが、普通に書いてしまうと分岐の嵐になりそうですね。 最後に、AppDelegateでメインプログラムを処理します。 ※ARCで書いたので「LeapTest.h」は@classでなくimportにしています

AppDelegate.h

#import <Cocoa/Cocoa.h>
#import "LeapTest.h"

@interface AppDelegate : NSObject <NSApplicationDelegate>

@property (assign) IBOutlet NSWindow *window;
@property (nonatomic)LeapTest *leapTest;

@end

AppDelegate.m

#import "AppDelegate.h"

@implementation AppDelegate

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    _leapTest = [[LeapTest alloc]init];
    [_leapTest run];
}
@end
ビルドして動かすと、ジェスチャーとともにログが変化するのが確認できます。 LeapMotion と、とりあず動作確認程度ですが、ここからが大変そうですね。
AWS CLI と jq でインスタンス一覧を整形して表示
React と Laravel7 のプロジェクトを作成する
Homebrewインストール-2020年版
3直線で囲まれた範囲塗りつぶし
PuLP で線形最適化問題を解く
カスタムのペジネーションを作る
node-sass を使って sass をコンパイルする
Log ファサードでSQLログを分離して書き出す
いちから始める Docker - 複数のコンテナを使う - (2020年)
いちから始める Docker - docker-compose を使う - (2020年)
AWS ECR を使ってみる
Laravel7 でマルチ認証
Mac に AWS Client を設定する
Laravel 7 リリース
v-html でHTML表示する
Laravel で Vue コンポーネントを使う
Laravel で Nuxt.js を使ってみる(Docker環境)
いちから始める Docker -コンテナをビルド- (2020年)
いちから始める Docker -起動してみる- (2020年)
Mac で MySQL(8系)
composer で vendor がインストールできない
Eloquent の日付を Carbon で扱う
webpack 4 入門(npm編)
[Mac]容量を減らす
DIコンテナはじめ
freee SDKを Laravel で使ってみる
freee API を使ってみる
Segueを利用しない画面遷移
Xcode11.3 で XVim2 を利用する
Codable で JSONを読み込み
Webpack入門(yarn編)
MacからLaradock PostgreSQLで接続エラー
Dockerで不要なコンテナ・イメージを削除
Mac で Laradock の構築
yarn インストール&プロジェクト作成
Laravel 6.x 構築(Homestead編)
Composer インストール
nvm インストール
npm install が Mac でエラー
HTMLタグでカーソルが同時処理(ミラーリング)されてしまう
DI(依存性注入)
[Ubuntu]Let's Encryptで無料の証明書を利用する
[Apache]Apache2.4のアクセス制限が変更
[Ubuntu]rootのログインとsudo権限追加
タミヤ マイコンロボット工作セットをMacに接続してみた
pgAdimn4 でブラウザで開けなくなる
Java8 を HomebrewとjEnvで構築
Android Studio環境構築 2019
ロケールの再構築
vagrant グループに Apacheを追加