Leap Motion翻譯系列文章http://52coding.com/leap-motion-official-doc-translation
觸摸仿真
Leap Motion的API提供了在你的應用中可以進行仿真的資訊。觸摸資訊是通過尖端類提供的。
概述
Leap 定義了一個自适應的觸摸平面,你可以将它與你應用中的二維元素美妙的結合在一起。這個平面粗糙的旋轉到與x-y平面平行,但是根據使用者的手指和手的位置動态調整。但使用者的手或者工具從前方到達平面,Leap會報告尖端物體是接近還是觸碰到這個虛拟的平面。API通過2個值彙報與平面相關的資訊:觸摸平面地帶和到觸摸平面的距離。
上圖:虛拟觸摸平面
觸摸地帶是識别Leap Motion軟體是否把尖端當作懸浮在觸摸平面,是穿透觸摸平面還是相對于螢幕較遠(或者指向錯誤的方向)。地帶包含“懸浮”、“觸摸”和“無”。觸摸地帶的轉換根據觸摸距離變換有一定滞後。這個滞後用于避免突然和反複的變換。如果你在應用中使用這個觸摸互動,你可能不需要經常考慮地帶。
隻有當尖端在懸浮和觸摸地帶,觸摸距離才是有效的。這個距離是歸一到[-1,+1]的數值。當一個尖端物體第一次進入懸浮地帶,此時觸摸距離為+1,而當距離不斷減少到0,意味着尖端物體接近觸摸平面。但尖端物體穿入平面,距離變為0。因為尖端物體繼續往觸摸地帶推進,距離不斷靠近但不會超過-1(永遠趨向于-1)。
你可以使用地帶數值,根據懸浮還是觸摸來決定何時更新界面元素。你還可以使用距離,根據是否靠近平面進一步改變界面元素[一個粗,一個細]。例如,當手指在控制體上并且在懸浮地帶,你可以讓控制體高亮顯示,并且依據使用者到底多接近控制體的距離,改變光标形态。
作為觸摸仿真API的一部分,Leap Motion為尖端物體,提供了一個額外的相對于标準坐标的穩定坐标。Leap Motion軟體使用自适應濾波器來穩定這個位置,可以平滑和降低運動,最終使得它在螢幕上小區域内(例如按鈕和連結)更容易地與使用者互動。但運動緩慢是平滑效果也越強,這樣使用者可以調整距離并且更容易的觸碰到特定的點[這個效果很贊,和人們在現實世界操作一樣]。
擷取觸摸地帶
觸摸地帶通過尖端類的touchZone屬性描述。這些地帶都是使用枚舉類型辨別的,一共有下面三個狀态:
#NONE --- 尖端距離觸摸螢幕太遠,大于考慮它觸摸的距離。又或者它指向反方向的使用者(也就是物體預設在使用者正面前,使用者手指着自己是一種不合适的操作)
#HOVERING --- 尖端物體的頂端已經到達懸浮地帶,但不被認為觸摸。
#TOUCHING --- 尖端到達了虛拟平面内。
下面的代碼片段說明如何取回最前面手指的地帶辨別:
Leap::Frame frame = leap.frame();
Leap::Pointable pointable = frame.pointables().frontmost();
Leap::Pointable::Zone zone = pointable.touchZone();
擷取觸摸距離
觸摸距離是通過尖端類的touchDistance屬性描述的。這個距離範圍是+1到-1,對應了手指移向和穿過虛拟觸摸平面。這個距離沒有實體意義,但卻是Leap Motion軟體認為的到底有多靠近觸碰。
下面的代碼段說明如何取出最前端手指的觸摸距離:
Leap::Frame frame = leap.frame();
Leap::Pointable pointable = frame.pointables().frontmost();
float distance = pointable.touchDistance();
擷取尖端的穩定坐标
穩定坐标是尖端類的stabilizedTipPosition屬性描述的。這個位置根據标準Leap Motion坐标系統參照得出的,但是具有一個上下文相關大量資料的濾波器,是以很穩定。
下面的代碼片段描述了如何得到最前端手指的穩定位置:
Leap::Frame frame = leap.frame();
Leap::Pointable pointable = frame.pointables().frontmost();
Leap::Vector stabilizedPosition = pointable.stabilizedTipPosition();
從Leap Motion坐标系轉換到應用坐标系
但使用觸摸仿真時,你必須把Leap Motion的坐标空間轉化到應用的螢幕空間。為了使得這個操作更簡單,Leap Motion的API提供了一個互動箱子類[互動盒子類](IneractionBox)。這個互動箱子類描述Leap Motion視野中的線性物體運動。這個類提供了一個把物體範圍中的坐标歸一化到[0,1]範圍内。你可以歸一化一個距離,并且根據應用尺寸,把結果坐标進行縮放,來擷取一個在應用中的坐标。
例如,如果你在客戶區域中有個具有windowWidth和windowHeight兩個度量的視窗,你可以使用以下代碼,取得在視窗中觸摸點的二維像素坐标:
Leap::Frame frame = leap.frame();
Leap::Finger finger = frame.fingers().frontmost();
Leap::Vector stabilizedPosition = finger.stabilizedTipPosition();
Leap::InteractionBox iBox = leap.frame().interactionBox();
Leap::Vector normalizedPosition = iBox.normalizePoint(stabilizedPosition);
float x = normalizedPosition.x * windowWidth;
float y = windowHeight - normalizedPosition.y * windowHeight;
觸點例子
下面的例子使用觸摸仿真的API,來顯示所有在應用視窗下,檢測到的尖端物體。這個例子使用了觸摸地帶來設定點的顔色,使用觸摸距離來設定alpha數值。使用了互動盒子類爸穩定的頂點位置被映射到應用視窗中。
上圖:觸摸點例子
#include "cinder/app/AppNative.h"
#include "cinder/gl/gl.h"
#include "Leap.h"
#include "LeapMath.h"
using namespace ci;
using namespace ci::app;
using namespace std;
class TouchPointsApp : public AppNative {
public:
void setup();
void draw();
private:
int windowWidth = 800;
int windowHeight = 800;
Leap::Controller leap;
};
void TouchPointsApp::setup()
{
this->setWindowSize(windowWidth, windowHeight);
this->setFrameRate(120);
gl::enableAlphaBlending();
}
void TouchPointsApp::draw()
{
gl::clear( Color( .97, .93, .79 ) );
Leap::PointableList pointables = leap.frame().pointables();
Leap::InteractionBox iBox = leap.frame().interactionBox();
for( int p = 0; p < pointables.count(); p++ )
{
Leap::Pointable pointable = pointables[p];
Leap::Vector normalizedPosition = iBox.normalizePoint(pointable.stabilizedTipPosition());
float x = normalizedPosition.x * windowWidth;
float y = windowHeight - normalizedPosition.y * windowHeight;
if(pointable.touchDistance() > 0 && pointable.touchZone() != Leap::Pointable::Zone::ZONE_NONE)
{
gl::color(0, 1, 0, 1 - pointable.touchDistance());
}
else if(pointable.touchDistance() <= 0)
{
gl::color(1, 0, 0, -pointable.touchDistance());
}
else
{
gl::color(0, 0, 1, .05);
}
gl::drawSolidCircle(Vec2f(x,y), 40);
}
}
CINDER_APP_NATIVE( TouchPointsApp, RendererGl )
這個例子使用了Cinder庫來建立用于繪畫的應用視窗。[例子這麼簡單,怎麼玩運作啊]