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的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库来创建用于绘画的应用窗口。[例子这么简单,怎么玩运行啊]