天天看點

Leap Motion觸摸仿真 概述 擷取觸摸地帶 擷取觸摸距離 擷取尖端的穩定坐标 從Leap Motion坐标系轉換到應用坐标系 觸點例子

Leap Motion翻譯系列文章http://52coding.com/leap-motion-official-doc-translation

觸摸仿真

Leap Motion的API提供了在你的應用中可以進行仿真的資訊。觸摸資訊是通過尖端類提供的。

概述

Leap 定義了一個自适應的觸摸平面,你可以将它與你應用中的二維元素美妙的結合在一起。這個平面粗糙的旋轉到與x-y平面平行,但是根據使用者的手指和手的位置動态調整。但使用者的手或者工具從前方到達平面,Leap會報告尖端物體是接近還是觸碰到這個虛拟的平面。API通過2個值彙報與平面相關的資訊:觸摸平面地帶和到觸摸平面的距離。

Leap Motion觸摸仿真 概述 擷取觸摸地帶 擷取觸摸距離 擷取尖端的穩定坐标 從Leap Motion坐标系轉換到應用坐标系 觸點例子

上圖:虛拟觸摸平面

觸摸地帶是識别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數值。使用了互動盒子類爸穩定的頂點位置被映射到應用視窗中。

Leap Motion觸摸仿真 概述 擷取觸摸地帶 擷取觸摸距離 擷取尖端的穩定坐标 從Leap Motion坐标系轉換到應用坐标系 觸點例子

上圖:觸摸點例子

#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庫來建立用于繪畫的應用視窗。[例子這麼簡單,怎麼玩運作啊]

繼續閱讀