画面のレイアウト(MainWindow.xaml)
画面のレイアウト(MainWindow.xaml)
デフォルトでGridコントロールが配置されているのをCanvasコントロールに変更します。その理由は、座標値が取得しやすいからです。しかし、今回は座標値を取得していないので、Gridでも問題はなのですが、この連載においては基本的にGridよりCanvasで統一することとします。
ツールボックスからEllipseコントロールを1個配置します。名前をEllipse1としておきます。この図ではわかりやすくするためにWidthとHeightに100を指定して円を表示していますが、実際にはWidthとHeightにはプロパティ名をバインドするため、円は点としてしか表示されません。
またLeap Motionのタッチ・ポイントを表示させるために、「paintCanvas」という名前のInkPresenterコントロールをCanvasコントロール上に配置します。このInkPresenterコントロールは、どのコントロールよりも一番手前に配置しておく必要があります。他のコントロールの後に配置すると、実行した場合に、タッチ・ポイントが表示されなくなりますので、注意してください。レイアウトは図7のようになります。
書き出されるXAMLをリスト1のように編集します。Ellipse1のHeightに[EllipseHeight]をバインドします。Widthに[EllipseWidth] をバインドします。これらの名称は、後で作成するクラス(UpDownModel.vb)内で定義したプロパティ名です。
ルートのCanvasコントロールの最後に
リスト1 (MainWindo.xaml)
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"
Title="MainWindow" Height="768" Width="1366">
<Canvas>
<Ellipse x:Name="Ellipse1" Fill="Crimson" HorizontalAlignment="Left" Height="{Binding EllipseHeight}" Stroke="Blue" StrokeThickness="5" VerticalAlignment="Top" Width="{Binding EllipseWidth}" Canvas.Left="357" Canvas.Top="200"/>
<InkPresenter Name="paintCanvas"/>
</Canvas>
</Window>
クラスの作成(SwipeDirection.vb)
では、次にクラスを作成します。ソリューション・エクスプローラー内のFingerRcognizeUpDownプロジェクトを選択して、マウスの右クリックで表示されるメニューから[追加]−[クラス]と選択します。表示される画面から[クラス]を選択し、「名前」に[SwipeDirection.vb] と指定して[追加]ボタンをタップします。
SwipeDirection.vbのプログラム・コード
Enum列挙体は、値を定義するための入れ物として使用する特殊なクラスです。列挙体が便利なのはプログラム中に入力候補が自動的に表示される点です。
SwipeDirection列挙体の中に、UpとDownという値を入れておきます(リスト2)。
リスト2(SwipeDirection.vb) 列挙体を記述したコード
Public Enum SwipeDirection
Up
Down
End Enum
クラスの作成(LeapListener.vb)
次に、SwipeDirection.vbを作成した方法で、LeapListener.vbクラスを作成します。
LeapListener.vbのプログラム・コード
Leap Motionを扱うための名前空間「Leap」をインポートします。
指の個数を格納するためのメンバー変数「Private fingersCount As Integer」を宣言します。
OnConnectコールバックメソッドの処理
コントローラーがLeap Motionセンサーと接続されたときに呼び出される、OnConnectコールバックメソッド内で、オブジェクトを動かす値を、10以上動かし、100mm/s以上の速度で動かします。デフォルトの値は150mm以上動かす、1000mm/s以上の速度で、というのが設定されています。
EnableGestureでGestureType.TYPESWIPEを有効にします。
TYPESWIPEは「指を伸ばした状態の手で直線を描く動作」を指します。ジェスチャーには4つのTypeがあります。詳細については「C#開発者から見たLeap Motion開発のファースト・インプレッション」を参照してください。今回は、この中からSwipeを使用します。
OnFrameコールバックメソッドの処理
次に、フレームのデータが更新されたときに呼び出されるOnFrameコールバックメソッドの処理です。
最新のフレームを取得し、1つ目の手を変数firstHandに格納します。
手に指があるかをチェックして、指がある場合は、全ジェスチャーを取得して、個別に処理を行います。
GestureTypeがTYPESWIPEであった場合は、スワイプの方向(Y座標)が0より大きかった場合は、指の個数(fingers)とスワイプの方向(SwipDirection.Up)を引数にしてSwipeActionメソッドを実行します。それ以外の場合は、指の個数(fingers)とスワイプの方向(SwipDirection.Down)を引数にして、SwipeActionメソッドを実行します。
次にSwipeEventデリゲート経由で、LeapSwipeメソッドを呼び出します。
SwipeActionメソッドでは、指が5つの場合は、SwipeDirectionのUpとDownで条件分岐を行い、RaiseEventでLeapSwipeイベントを発生させます。その際、引数にSwipeDirectionのUpとDownを指定します。
これらのコードはリスト3になります。
リスト3(LeapListener.vb) TYPESWIPEの処理を行うクラス
Imports Leap
Public Class LeapListener
Inherits Listener
Private fingersCount As Integer
' コントローラーがLeap Motionセンサーと接続されたときに呼び出される、
' OnConnectコールバックメソッド
' スワイプの動作を有効にする
Public Overrides Sub OnConnect(ctlr As Controller)
’ オブジェクトの移動距離(mm)と速度(mm/s)を指定
ctlr.Config.SetFloat("Gesture.Swipe.MinLength", 10)
ctlr.Config.SetFloat("Gesture.Swipe.MinVelocity", 100)
ctlr.Config.Save()
' EnableGestureでGestureType.TYPESWIPEを有効にする
ctlr.EnableGesture(Gesture.GestureType.TYPESWIPE)
End Sub
' フレームのデータが更新されたときに呼び出される
' OnFrameコールバックメソッドの処理
Public Overrides Sub OnFrame(ctlr As Controller)
Dim currentFrame As Frame = ctlr.Frame
If (Not currentFrame.Hands.Empty) Then
’ 最新のフレームを取得し、1つ目の手を変数firstHandに格納する。
Dim firstHand As Hand = currentFrame.Hands(0)
' 手に指があるかをチェックして、指がある場合は、
' 全ジェスチャーを取得して、個別に処理を行う。
Dim fingers As FingerList = firstHand.Fingers
If (Not fingers.Empty) Then
Dim gestures As GestureList = currentFrame.Gestures
For Each gst As Gesture In gestures
' GestureTypeがTYPESWIPEであった場合は、スワイプの方向で条件分岐を
’ 行う。
’ SwipeActionメソッドを実行する。
If gst.Type = Gesture.GestureType.TYPESWIPE Then
Dim swipe As New SwipeGesture(gst)
If (swipe.Direction.y > 0) Then
SwipeAction(fingers, SwipeDirection.Up)
Else
SwipeAction(fingers, SwipeDirection.Down)
End If
Exit For
End If
Next
End If
End If
End Sub
’ SwipeEventデリゲート経由で、LeapSwipeメソッドを呼び出す。
Public Delegate Sub SwipeEvent(ByVal sd As SwipeDirection)
Public Event LeapSwipe As SwipeEvent
' GestureTypeがTYPESWIPEであった場合は、スワイプの方向で条件分岐を
' 行うSwipeActionメソッドの処理。
Private Sub SwipeAction(ByVal fingers As FingerList, ByVal sd As SwipeDirection)
fingersCount = fingers.Count
If (fingersCount = 5) Then
Select Case sd
Case SwipeDirection.Up
’ RaiseEventでLeapSwipeイベントを発生させる。
RaiseEvent LeapSwipe(SwipeDirection.Up)
Exit Select
Case SwipeDirection.Down
' RaiseEventでLeapSwipeイベントを発生させる。
RaiseEvent LeapSwipe(SwipeDirection.Down)
Exit Select
End Select
End If
End Sub
End Class
クラスの作成(UpDownModel.vb)
次に、SwipeDirection.vbを作成した方法で、UpDownModel.vbクラスを作成します。
UpDownModel.vbのプログラム・コード
プロパティの値が変更されたことをクライアントに通知する、INotifyPropertyChangedインターフェースをインプリメントするために、System.ComponentModel名前空間をインポートしておきます。
Leap Motionを扱うためにLeap名前空間をインポートしておきます。
Controllerクラス型のメンバー変数ctlrを宣言します。
先ほど作成したLeapListenerクラス型のメンバー変数listenerを宣言します。
次に名前がNewであるメソッドを定義します。自動的にこれがコンストラクタになります。
Newメソッド内では以下の処理が行われます。
Controllerの新しいインスタンスctlrオブジェクトを作成します。新しいLeapListenerのインスタンスlistenerオブジェクトを作成します。AddListenerメソッドでctlrオブジェクトにlistenerオブジェクトを追加します。
AddHandlerステートメントで、listenerオブジェクトのLeapSwipeイベントに、SwipeActionイベントハンドラ—を追加します。
次に各プロパティを定義します。EllipseHeightとEllipseWidthプロパティを定義し、INotifyPropertyChangedインターフェースに各プロパティの名前を指定しておきます。
次はSwipeActionメソッドの処理です。
Enum列挙体で値を定義していた、SwipeDirectionの値で条件分岐を行います。Upの場合はEllipseHeightとEllipseWidthの値を10ずつ増加させ、Downの場合は、EllipseHeightとEllipseWidthの値を10ずつ減少させます。
プロパティの値が変更された時に、変更されたことをクライアントに通知するPropertyChangedイベントを定義します。
OnPropertyChangedメソッドで、プロパティ名で初期化されたPropertyChangedイベントを発生させます。

