プログラム・コードはリスト4のようになります。

リスト4(UpDownModel.vb) 指のアップ・ダウンで円を拡大縮小するクラス

Imports System.ComponentModel
Imports Leap
Public Class UpDownModel

'  プロパティの値が変更されたことをクライアントに通知する、
'  INotifyPropertyChangedインターフェースをインプリメントしておく。
  Implements INotifyPropertyChanged
 
  Private ctlr As Controller
  Private listener As LeapListener
  
'  Newメソッド
'  各インスタンスを作成して、AddHandlerステートメントで、listenerオブジェクトの
'  LeapSwipeイベントに、SwipeActionベントハンドラ—を追加する。 
  Public Sub New()
    ctlr = New Controller
    listener = New LeapListener
    ctlr.AddListener(listener)
    AddHandler listener.LeapSwipe, AddressOf Me.SwipeAction
  End Sub

‘ EllipseHeightプロパティの定義
  Private myHeight As Double
 
  Public Property EllipseHeight As Double
    Get
      Return myHeight
    End Get
    Set(value As Double)
      myHeight = value
      OnPropertyChanged("EllipseHeight")
    End Set
  End Property

'  EllipseWidthプロパティの定義
  Private myWidth As Double
  Public Property EllipseWidth As Double
    Get
      Return myWidth
    End Get
    Set(value As Double)
      myWidth = value
      OnPropertyChanged("EllipseWidth")
    End Set
  End Property

'  UpとDownによってEllipseHeightとEllipseWidthの値を変化させるSwipeActionメソッドの処理
  Private Sub SwipeAction(ByVal sd As SwipeDirection)
    Select Case sd
      Case SwipeDirection.Up
        EllipseHeight += 10
        EllipseWidth += 10
 
        Exit Select
      Case SwipeDirection.Down
 
        EllipseHeight -= 10
        EllipseWidth -= 10
        Exit Select
    End Select
  End Sub

' プロパティの値が変更された時に、変更されたことをクライアントに通知する
'  PropertyChangedイベント。
  Public Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged

'  OnPropertyChangedメソッドの処理
'  RaseEventでプロパティ名で初期化されたPropertyChangedイベントを発生させる。
  Private Sub OnPropertyChanged(ByVal propertyName As String)
    RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
  End Sub
End Class

MainWindow.xaml内に[UpDownModel]を取り込む。

まず名前空間として「xmlns:local="clr-namespace:FingerRecognizeUpDown"」を定義します。

次にプロパティ要素内に「」と記述します。MainWindow.xaml内に「UpDownModel」クラスが取り込まれます。リスト5のコードのようになります。

※注意
プロパティ要素内に「」と記述すると、「」の下に波線が表示され、マウスカーソルを持っていくと、「指定されたファイルが見つかりません。」のエラーが表示されますが、実行には問題はないので、無視しても構いません。

リスト5(MainWindow.xaml) 「UpDownMode」を取り込んだMainWindow.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" 
  xmlns:local="clr-namespace:FingerRecognizeUpDown"
  Title="MainWindow" Height="768" Width="1366" >
  <Window.DataContext>
    <local:UpDownModel/>
  </Window.DataContext>
 ・・・・以下コード略・・・・
</Window>

プログラム・コード(MainWindow.xaml.vb)指の個数を表示させる処理

MainWindows.xaml.vbファイルを見ていきましょう(リスト6)。

新しいControllerクラスのインスタンスであるleapメンバー変数を宣言します。次に、インク・ストローク(=System.Windows.Ink名前空間のStrokeクラスで表現される、WPF上でのインクの線)の外観を指定する新しいDrawingAttributesクラス(System.Windows.Ink名前空間)のインスタンスである「touchIndicatorメンバー変数」を宣言します。

MainWindow_Loadedメソッドの処理

MainWindow_Loadedメソッド(=メイン・ウィンドウのLoadedイベントのハンドラー)では、MainWindowが読み込まれたときの処理を実装します。

AddHandlerステートメントを使って、構成ツリーのオブジェクトがレンダリングされる直前に発生する「CompositionTarget.Renderingイベント」に対するイベント・ハンドラーとしてUpdateメソッドを指定します(※Updateメソッドの実装内容は後述)。

インク・ストロークの外観を表す、DrawingAttributesオブジェクトのインスタンス「touchIndicator」のWidthプロパティとHeightプロパティにそれぞれ「30」を指定します。スタイラスの形状を指定するStylusTipプロパティに「StylusTip.Ellipse」を指定して円形とします。Leap Motionの上で指をかざすと、かざした指の本数が5本で、30px(px=ピクセル)の円が表示されるようになります。

Updateメソッドの処理

次は、CompositionTarget.Renderingイベント・ハンドラーであるUpdateメソッドの処理です。

まず、上記のコードを実装した段階で、「Update」の位置に[エラー修正のオプション]というスマート・タグが表示されるので、そのタグのメニューから[’ ChangeBackgroundLeapMotion.MainWindow’ に ‘ Update’ のメソッド スタブを生成]をクリックすると、Updateメソッドのひな型が追加されます。次に、そのメソッド内を実装していきます。

「paintCanvas」という名前のInkPresenter内をクリアします。この処理を行っていないと、Updateメソッドは常に呼び出されているため、円を画面上で動かすと、円の軌跡が残ったまま表示されてしまいます。そのため、InkPresenter内をクリアする必要があります。

Leap Motionのフレームを表すFrame型(Leap名前空間)の変数「frame」を宣言します。InteractionBox型(Leap名前空間)の変数「interactionBox」を宣言し、そこにleap.Frame.InteractionBoxプロパティからInteractionBoxオブジェクトを取得します。InteractionBoxオブジェクトは、Leap Motionで認識できる可動範囲となります。InteractionBoxオブジェクトを使用することで、指やツール(=ペンなど)の位置を実際のディスプレイの座標系に変換できます。詳細な図については、「Leap Motionでのタッチ操作はどう開発するのか?」を参照してください。

Leap.Frame.Pointablesプロパティで得られるPointableListオブジェクト内を変数「Pointable」で反復処理しながら、1つずつPointableオブジェクトを処理し、それぞれのタッチ位置を取得していきます。

interactionBoxオブジェクトのNormalizePointメソッドに引数としてPointable.StabilizedTipPositionプロパティ値を渡し、ポインター上の位置を取得します。

変数「windowWidth」と「windowHeight」で表されたクライアント領域のウィンドウがある場合、

Dim tx As Double = normalizedPosition.x * windowWidth

Dim ty As Double = windowHeight - normalizedPosition.y * windowHeight

のコードで示す計算式を使用してこのウィンドウ内のタッチ・ポイントの2D座標を得ることができます。

最後に、

  Dim tips As New StylusPointCollection(New StylusPoint() {touchPoint})
  Dim touchStroke As New Stroke(tips, touchIndicator)
  paintCanvas.Strokes.Add(touchStroke)

と記述して、ディスプレイ上に円形のタッチ・ポイントを表示します。

実際のコードはリスト6になります。

リスト6(MainWindow.xaml.vb)

Imports Leap
Imports System.Windows.Ink
Class MainWindow
  Private leap As New Controller
  Private windowWidth As Double = 1366
  Private windowHeight As Double = 768
  Private touchIndicator As New DrawingAttributes

'  MainWindow_Loadedメソッドの処理
  Private Sub MainWindow_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
    AddHandler CompositionTarget.Rendering, AddressOf Update'  Updateメソッドをイベント・ハンドラーに追加する
    touchIndicator.Width = 30
    touchIndicator.Height = 30
    touchIndicator.StylusTip = StylusTip.Ellipse' スタイラスの形状を30pxの円形に指定する
  End Sub

'  Updateメソッドの処理
  Private Sub Update(sender As Object, e As EventArgs)
    paintCanvas.Strokes.Clear()
    windowWidth = Me.Width
    windowHeight = Me.Height
 
    Dim frame As Leap.Frame = leap.Frame

'  Leap Motionで認識できる可動範囲を取得する
    Dim interactionBox As InteractionBox = leap.Frame.InteractionBox
    For Each Pointable As Pointable In leap.Frame.Pointables
      Dim normalizedPosition As Leap.Vector = interactionBox.NormalizePoint(Pointable.StabilizedTipPosition)
      Dim tx As Double = normalizedPosition.x * windowWidth
      Dim ty As Double = windowHeight - normalizedPosition.y * windowHeight
      Dim touchPoint As StylusPoint = New StylusPoint(tx, ty) '  ウィンドウ内のタッチ・ポイントの位置を取得する
 
      Dim tips As New StylusPointCollection(New StylusPoint() {touchPoint})
      Dim touchStroke As New Stroke(tips, touchIndicator)
      paintCanvas.Strokes.Add(touchStroke) '  ディスプレイ上にタッチ・ポイントを表示
    Next
  End Sub
End Class

これでVS2012のメニューから[デバッグ]−[デバッグ開始]と実行すると、5本の指のアップ・ダウンで円が拡大縮小表示されます。

リスト5を見ていただくとわかりますが、画面のWidthに1366、Heightに768と指定し、全画面表示にはしていません。

※注意
サンプルをダウンロードして動かす場合は、「LeapCSharp.NET4.0.dll」や「LeapCSharp.dll」、「Leap.dll」を読者の方自身のフォルダ内にあるDLLファイルに指定し直さなければ動かない可能性があるので、動かない場合は再指定してください。

Airspace Storeで配布中のアプリを少しだけ紹介

Leap Motionの有料、無料アプリを販売しているAirspace Storeがあります。
筆者は無料のアプリを2つほどダウンロードして試してみました。

まず、「Flocking」は下記の図のように、指の動きに合わせて魚群が移動する美しいアプリです。

Flockingの画面(クリックで拡大)

もう一つは「ESCAPE VELOCITY」というシューティングゲームです。筆者はゲームが苦手なため、全く操作ができませんでした(-_-;)

ESCAPE VELOCITYの画面(クリックで拡大)

人気記事トップ10

人気記事ランキングをもっと見る

企画広告も役立つ情報バッチリ! Sponsored

ClickHouse Cloudが実現した広告運用SaaS「ATOM」のデータ基盤革新、パフォーマンスを向上しながら、運用負荷とコストを削減 11月11日 6:20 AIで開発が加速する時代、品質保証はどう変わる? Tricentisが示すAIエージェント活用の実像 11月9日 6:45 悪用までの猶予が「1分」に迫るフロンティアAI時代に開発と本番を貫く脆弱性管理が必要 10月29日 8:30 欧州CRA対応とSBOM運用。AI生成コードのOSS混入問題の対策とは ――スニペット単位で検出する「FossID」「Insignary Clarity」によるSBOM運用 9月16日 6:40 PostgreSQLからTiDBへ、稼働中SaaSで進める段階的DB移行の実践と再設計への展望 9月7日 6:30 機能安全開発におけるGoogleTestの活用を支援!「Parasoft C/C++test CT」で実現する効率化&AI連携 4月14日 6:30 【CNDW2025】Grafanaが明かす「オブザーバビリティの哲学」ー最小限の労力で実用的なインサイトを得るには 1月23日 6:30 【CNDW2025】プロダクト急増に備える基盤刷新 ーウェルスナビがECSからEKSへの移行で得た知見とは 1月15日 6:30 【CNDW2025】250環境を5人で運用、構築時間は30分に ーKINTOテクノロジーズが語るインフラ基盤組織の作り方 2025年12月18日 6:30 新たな自動化で熱視線! AIエージェントの「推論能力」を支える2つのコンポーネントとは? 2025年11月28日 6:30