「Leap Motion」を手に入れたのでXcodeで試してみた。
国内で買うと倍くらいしてしまうので、海外で買った方がお得で、意外と早く届きます(3日で届いた)。
https://www.leapmotion.com/setupから「Leap Motion Installer」をダウンロードして、インストールします。 非常にわかりやすいセットアップナビゲーションです。
アプリ管理は「AirSpace」で行います。 https://airspace.leapmotion.com/にアクセスすると、iTunesStore、GooglePlayのようにアプリが購入できます。 フリーのソフトもあるので、ざっと試す事ができます。
Leap Motionは、色々な言語に対応しているので自分の得意分野で開発かと思います。 (自分は XCode、Objective-Cで開発)
SDKは、https://developer.leapmotion.com/downloads からダウンロードできます。
ダウンロードしたSDKは、自分の管理しやすいパスに配置します。 ※自分は「/Users/ユーザ/leap/LeapSDK/」にしました
Xcode、Objective-Cで開発するにはいくつか準備が必要です。
(1) libLeap.dylib (2) Leap、LeapMathヘッダファイル (3) LeapObjectiveC
Cocoa Applicationでプロジェクト作成
ARCで作成してみる
「LeapSDK」のライブラリを利用するには、パスを通してやる必要があります。
まず、配置したLeapSDKのパス定義 ※「LEAPSDK_PATH」としました
headerファイルのパス定義 $(LEAPSDK_PATH)/inclulde
libraryファイルのパス定義 $(LEAPSDK_PATH)/lib
「Leap.h」「LeapMath.h」「LeapObjectiveC.h」「LeapObjectiveC.mm」をプロジェクトにドラッグ&ドロップ
「libLeap.dylib」をプロジェクトにドラッグ&ドロップ
Build Phasesで、ファイルが追加されるのを確認
メインプログラムは「LeapSDK/samples/Sample.cpp」をそのまま記述しました。
#import
#import "LeapObjectiveC.h"
@interface LeapTest : NSObject
- (void)run;
@end
「LeapObjectiveC.h」を読み込んで、「LeapListener」で拡張
#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で検知して処理するようです。
ジェスチャーはonFrame()で主に処理してやる必要がありますが、普通に書いてしまうと分岐の嵐になりそうですね。
最後に、AppDelegateでメインプログラムを処理します。 ※ARCで書いたので「LeapTest.h」は@classでなくimportにしています
#import
#import "LeapTest.h"
@interface AppDelegate : NSObject
@property (assign) IBOutlet NSWindow *window;
@property (nonatomic)LeapTest *leapTest;
@end
#import "AppDelegate.h"
@implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
_leapTest = [[LeapTest alloc]init];
[_leapTest run];
}
@end
ビルドして動かすと、ジェスチャーとともにログが変化するのが確認できます。
と、とりあず動作確認程度ですが、ここからが大変そうですね。