Leap Motionの日本語情報は非常に限られているので公式ドキュメントをざっくり日本語訳にしました。誤訳などあったらお知らせください。
本エントリはhttps://developer.leapmotion.com/documentation/Languages/CSharpandUnity/Guides/Leap_Touch_Emulation.htmlの日本語訳となります。
Touch Emulation
Leap Motion APIには、タッチエミュレーションを実装するために必要な情報を提供するPointableクラスがあります。
Topics:
- Overview
- Getting the Touch Zone
- Getting the Touch Distance
- Getting the Stabilized Position of a Pointable
- Converting from Leap Motion Coordinates to Application Coordinates
- TouchPoints Example
Overview
Leapはタッチを認識するための仮想平面を定義し、アプリケーションの 2D 要素との相互作用を調整することができます。仮想平面はほぼ x-y 平面と平行になっていて、指や手の位置を検出します。指やツールを前方に移動するとPointableオブジェクトはこの仮想平面と近い距離にあるか触れたかをタッチ面までの距離と共にレポートします。
タッチゾーンは、Leap Motionソフトウェアがタッチ画面の前後などの近くに指などがホバリングしている状態を考慮するかを指定します。ゾーンは「ホバリング」「タッチ」「なし」から構成されています。ゾーンの間の遷移はタッチの距離よりも遅れる傾向があります。この遅れはチャタリングのような繰り返しを検出しないようにするために使用されます。アプリケーション内でタッチ操作を実装する場合は、タッチゾーンを頻繁にチェックする必要はありません。
タッチの距離は、指などがホバリングまたはタッチゾーン内にある場合にのみ有効です。検出される値は+1~-1まで。ホバリングゾーンに指などがはいってくると+1.0を返し、タッチ面に近づくと0を返します。指などがタッチ面を突き抜けていくと-1の値になります。
マウスクリックやタッチ操作を判定するのにゾーンの値を使用できます。距離を使用して、さらにタッチ面への近さに基づいてUI要素の見た目を変化させるとよいでしょう。例えば、指はホバリングゾーンに入った時にコントロールの強調表示、近づいてきたらカーソルの変更をフィードバックします。
タッチエミュレーションAPIの一部として標準的な位置にあるPointableオブジェクトのゆっくりとした安定した位置を提供します。Leap Motionソフトウェアは、スムースフィルタを使って位置を安定化し、小さい領域(のようなボタンやリンク)にタッチしやすいような動きにします。このように動きを遅くしてタッチ距離が0の位置に触れやすくするために滑らかにするのは大きな意味を持ちます。
Getting the Touch Zone
タッチゾーンはPointableクラスの属性によって取得できます。ゾーンの列挙型は次の通りです。
- NONE ? 指などがタッチ面から離れている
- HOVERING ? 指などがホバリングゾーンに入り、まだタッチゾーンに入っていない
- TOUCHING ? 指などが仮想面にタッチした
次のコードスニペットは、一番手前の指がタッチゾーンに入ったかを取得する方法を示しています。
VB.NET
Dim _frame As Frame = leap.Frame()
Dim _pointable As Pointable = _frame.Pointables.Frontmost
Dim zone As Pointable.Zone = _pointable.TouchZone
C#
Frame frame = leap.Frame();
Pointable pointable = frame.Pointables.Frontmost;
Pointable.Zone zone = pointable.TouchZone;
Getting the Touch Distance
タッチ距離はPointableクラスのTouchDistance属性として取得できます。仮想面からの距離を+1~-1で表します。この値は実際の距離と一致しませんがタッチ面のどれくらい近くにいるかの判定に使用できます。
次のコードスニペットは、一番手前の指のタッチまでの距離を取得する方法を示しています。
VB.NET
Dim _frame As Frame = leap.Frame()
Dim _pointable As Pointable = _frame.Pointables.Frontmost
Dim distance As Single = _pointable.TouchDistance
C#
Frame frame = leap.Frame();
Pointable pointable = frame.Pointables.Frontmost;
float distance = pointable.TouchDistance;
Getting the Stabilized Position of a Pointable
ブレ防止フィルタをかけたあとの位置は、PointableクラスのStabilizedTipPosition属性で取得できます。 この位置は標準的なLeap Motion座標系で取得できますがフィルタリングとブレ防止を行ったあとの値になります。
次のコードスニペットは、一番手前の指のブレ防止フィルタをかけたときの位置を取得する方法を示しています。
VB.NET
Dim _frame As Frame = leap.Frame()
Dim _pointable As Pointable = _frame.Pointables.Frontmost
Dim stabilizedPosition As Vector = _pointable.StabilizedTipPosition
C#
Frame frame = leap.Frame();
Pointable pointable = frame.Pointables.Frontmost;
Vector stabilizedPosition = pointable.StabilizedTipPosition;
Converting from Leap Motion Coordinates to Application Coordinates
タッチ エミュレーションを実装するときは、アプリケーションのスクリーン空間にLeap Motion座標空間を割り当てる必要があります。このマッピングが容易にできるようにLeap Motion APIは、InteractionBoxクラスを提供します。InteractionBoxは、LeapMotion検出範囲で直線的な領域を表します。クラスはこの領域内での位置を範囲[0..1]座標を正規化する機能を提供します。位置を正規化し、アプリケーション座標のポイントを取得すると座標をスケールすることができます。
たとえば、変数windowWidthとwindowHeightで表されたクライアント領域のウィンドウがある場合、次のコードを使用してこのウィンドウ内のタッチ ポイントの2D座標を得ることができます。
VB.NET
Dim _frame As Frame = leap.Frame()
Dim _pointable As Pointable = _frame.Pointables.Frontmost
Dim stabilizedPosition As Vector = _pointable.StabilizedTipPosition
Dim iBox As InteractionBox = leap.Frame().InteractionBox
Dim normalizedPosition As Vector = iBox.NormalizePoint(stabilizedPosition)
Dim x As single = normalizedPosition.x * windowWidth
Dim y As float = windowHeight - normalizedPosition.y * windowHeight
C#
Frame frame = leap.Frame();
Finger finger = frame.Fingers.Frontmost;
Vector stabilizedPosition = finger.StabilizedTipPosition;
InteractionBox iBox = leap.Frame().InteractionBox;
Vector normalizedPosition = iBox.NormalizePoint(stabilizedPosition);
float x = normalizedPosition.x * windowWidth;
float y = windowHeight - normalizedPosition.y * windowHeight;
TouchPoints Example
VB.NET
Imports System.Collections.Generic
Imports System.Windows
Imports System.Windows.Input
Imports System.Windows.Media
Imports System.Windows.Shapes
Imports System.Windows.Ink
Imports Leap
Public Class MainWindow
Private leap As New Controller
Private windowWidth As Single = 1400
Private windowHeight As Single = 800
Private touchIndicator As New DrawingAttributes
Public Sub New()
' この呼び出しはデザイナーで必要です。
InitializeComponent()
' InitializeComponent() 呼び出しの後で初期化を追加します。
AddHandler CompositionTarget.Rendering, AddressOf Update
touchIndicator.Width = 20
touchIndicator.Height = 20
touchIndicator.StylusTip = StylusTip.Ellipse
End Sub
Private Sub Update(sender As Object, e As EventArgs)
paintCanvas.Strokes.Clear()
windowWidth = CType(Me.Width, Single)
windowHeight = CType(Me.Height, Single)
Dim _frame As Leap.Frame = leap.Frame()
Dim _interactionBox As InteractionBox = leap.Frame().InteractionBox
For Each _pointable As Pointable In leap.Frame().Pointables
Dim normalizedPosition As Leap.Vector = _interactionBox.NormalizePoint(_pointable.StabilizedTipPositioninte
Dim tx As Single = normalizedPosition.x * windowWidth
Dim ty As Single = windowHeight - normalizedPosition.y * windowHeight
Dim alpha As Integer = 255
If (_pointable.TouchDistance > 0 AndAlso _pointable.TouchZone <> Pointable.Zone.ZONENONE) Then alpha = 255 - CType(255 * _pointable.TouchDistance, Integer)
touchIndicator.Color = Color.FromArgb(CType(alpha, Byte), &H0, &HFF, &H0)
ElseIf (_pointable.TouchDistance <= 0) Then
alpha = -CType(255 * _pointable.TouchDistance, Integer)
touchIndicator.Color = Color.FromArgb(CType(alpha, Byte), &HFF, &H0, &H0)
Else
alpha = 50
touchIndicator.Color = Color.FromArgb(CType(alpha, Byte), &H0, &H0, &HFF)
End If
Dim touchPoint As 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
<window title="MainWindow" x:class="TouchPoints.MainWindow" width="525" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" height="350">
<grid>
<inkpresenter name="paintCanvas">
</inkpresenter>
</grid>
</window>
C#
using System.Collections.Generic;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Windows.Ink;
using Leap;
namespace TouchPoints
{
public partial class MainWindow : Window
{
Controller leap = new Controller();
float windowWidth = 1400;
float windowHeight = 800;
DrawingAttributes touchIndicator = new DrawingAttributes();
public MainWindow()
{
InitializeComponent();
CompositionTarget.Rendering += Update;
touchIndicator.Width = 20;
touchIndicator.Height = 20;
touchIndicator.StylusTip = StylusTip.Ellipse;
}
protected void Update(object sender, EventArgs e)
{
paintCanvas.Strokes.Clear();
windowWidth = (float)this.Width;
windowHeight = (float)this.Height;
Leap.Frame frame = leap.Frame();
InteractionBox interactionBox = leap.Frame().InteractionBox;
foreach(Pointable pointable in leap.Frame().Pointables)
{
Leap.Vector normalizedPosition = interactionBox.NormalizePoint(pointable.StabilizedTipPosition);
float tx = normalizedPosition.x * windowWidth;
float ty = windowHeight - normalizedPosition.y * windowHeight;
int alpha = 255;
if(pointable.TouchDistance > 0 && pointable.TouchZone != Pointable.Zone.ZONENONE)
{
alpha = 255 - (int)(255 * pointable.TouchDistance);
touchIndicator.Color = Color.FromArgb((byte)alpha, 0x0, 0xff, 0x0);
}
else if(pointable.TouchDistance <= 0)
{
alpha = -(int)(255 * pointable.TouchDistance);
touchIndicator.Color = Color.FromArgb((byte)alpha, 0xff, 0x0, 0x0);
}
else
{
alpha = 50;
touchIndicator.Color = Color.FromArgb((byte)alpha, 0x0, 0x0, 0xff);
}
StylusPoint touchPoint = new StylusPoint(tx, ty);
StylusPointCollection tips = new StylusPointCollection(new StylusPoint[] { touchPoint });
Stroke touchStroke = new Stroke(tips, touchIndicator);
paintCanvas.Strokes.Add(touchStroke);
}
}
}
}
<window title="MainWindow" x:class="TouchPoints.MainWindow" width="525" height="350" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<grid>
<inkpresenter name="paintCanvas">
</grid>
</window>
この例はVB.NET/C#によるWPFアプリケーションにおけるLeap Motionサンプルとなっています。
----
Copyright c 2012-2013 Leap Motion, Inc. All rights reserved.
Leap Motion proprietary and confidential. Not for distribution. Use subject to the terms of the Leap Motion SDK Agreement available at https://developer.leapmotion.com/sdk_agreement, or another agreement between Leap Motion and you, your company or other organization.