UNPKG

leapmotion-ts

Version:

TypeScript framework for Leap Motion.

1,044 lines (1,042 loc) 130 kB
var __extends = (this && this.__extends) || function(d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } __.prototype = b.prototype; d.prototype = new __(); }; define(["require", "exports"], function(require, exports) { /** * The EventDispatcher class provides strongly typed events. */ var EventDispatcher = (function() { function EventDispatcher() { this.listeners = []; } EventDispatcher.prototype.hasEventListener = function(type, listener) { var exists = false; for (var i = 0; i < this.listeners.length; i++) { if (this.listeners[i].type === type && this.listeners[i].listener === listener) { exists = true; break; } } return exists; }; EventDispatcher.prototype.addEventListener = function(typeStr, listenerFunction) { if (this.hasEventListener(typeStr, listenerFunction)) return; this.listeners.push({ type: typeStr, listener: listenerFunction }); }; EventDispatcher.prototype.removeEventListener = function(typeStr, listenerFunction) { for (var i = 0; i < this.listeners.length; i++) { if (this.listeners[i].type === typeStr && this.listeners[i].listener === listenerFunction) this.listeners.splice(i, 1); } }; EventDispatcher.prototype.dispatchEvent = function(event) { for (var i = 0; i < this.listeners.length; i++) { if (this.listeners[i].type === event.getType()) this.listeners[i].listener.call(this, event); } }; return EventDispatcher; })(); exports.EventDispatcher = EventDispatcher; var DefaultListener = (function(_super) { __extends(DefaultListener, _super); function DefaultListener() { _super.call(this); } DefaultListener.prototype.onConnect = function(controller) { controller.dispatchEvent(new LeapEvent(LeapEvent.LEAPMOTION_CONNECTED, this)); }; DefaultListener.prototype.onDisconnect = function(controller) { controller.dispatchEvent(new LeapEvent(LeapEvent.LEAPMOTION_DISCONNECTED, this)); }; DefaultListener.prototype.onExit = function(controller) { controller.dispatchEvent(new LeapEvent(LeapEvent.LEAPMOTION_EXIT, this)); }; DefaultListener.prototype.onFrame = function(controller, frame) { controller.dispatchEvent(new LeapEvent(LeapEvent.LEAPMOTION_FRAME, this, frame)); }; DefaultListener.prototype.onInit = function(controller) { controller.dispatchEvent(new LeapEvent(LeapEvent.LEAPMOTION_INIT, this)); }; return DefaultListener; })(EventDispatcher); exports.DefaultListener = DefaultListener; var LeapEvent = (function() { function LeapEvent(type, targetListener, frame) { if (frame === void 0) { frame = null; } this._type = type; this._target = targetListener; this.frame = frame; } LeapEvent.prototype.getTarget = function() { return this._target; }; LeapEvent.prototype.getType = function() { return this._type; }; LeapEvent.LEAPMOTION_INIT = "leapMotionInit"; LeapEvent.LEAPMOTION_CONNECTED = "leapMotionConnected"; LeapEvent.LEAPMOTION_DISCONNECTED = "leapMotionDisconnected"; LeapEvent.LEAPMOTION_EXIT = "leapMotionExit"; LeapEvent.LEAPMOTION_FRAME = "leapMotionFrame"; return LeapEvent; })(); exports.LeapEvent = LeapEvent; /** * LeapUtil is a collection of static utility functions. * */ var LeapUtil = (function() { function LeapUtil() {} /** * Convert an angle measure from radians to degrees. * * @param radians * @return The value, in degrees. * */ LeapUtil.toDegrees = function(radians) { return radians * 180 / Math.PI; }; /** * Determines if a value is equal to or less than 0.00001. * * @return True, if equal to or less than 0.00001; false otherwise. */ LeapUtil.isNearZero = function(value) { return Math.abs(value) <= LeapUtil.EPSILON; }; /** * Determines if all Vector3 components is equal to or less than 0.00001. * * @return True, if equal to or less than 0.00001; false otherwise. */ LeapUtil.vectorIsNearZero = function(inVector) { return this.isNearZero(inVector.x) && this.isNearZero(inVector.y) && this.isNearZero(inVector.z); }; /** * Create a new matrix with just the rotation block from the argument matrix */ LeapUtil.extractRotation = function(mtxTransform) { return new Matrix(mtxTransform.xBasis, mtxTransform.yBasis, mtxTransform.zBasis); }; /** * Returns a matrix representing the inverse rotation by simple transposition of the rotation block. */ LeapUtil.rotationInverse = function(mtxRot) { return new Matrix(new Vector3(mtxRot.xBasis.x, mtxRot.yBasis.x, mtxRot.zBasis.x), new Vector3(mtxRot.xBasis.y, mtxRot.yBasis.y, mtxRot.zBasis.y), new Vector3(mtxRot.xBasis.z, mtxRot.yBasis.z, mtxRot.zBasis.z)); }; /** * Returns a matrix that is the orthonormal inverse of the argument matrix. * This is only valid if the input matrix is orthonormal * (the basis vectors are mutually perpendicular and of length 1) */ LeapUtil.rigidInverse = function(mtxTransform) { var rigidInverse = this.rotationInverse(mtxTransform); rigidInverse.origin = rigidInverse.transformDirection(mtxTransform.origin.opposite()); return rigidInverse; }; LeapUtil.componentWiseMin = function(vLHS, vRHS) { return new Vector3(Math.min(vLHS.x, vRHS.x), Math.min(vLHS.y, vRHS.y), Math.min(vLHS.z, vRHS.z)); }; LeapUtil.componentWiseMax = function(vLHS, vRHS) { return new Vector3(Math.max(vLHS.x, vRHS.x), Math.max(vLHS.y, vRHS.y), Math.max(vLHS.z, vRHS.z)); }; LeapUtil.componentWiseScale = function(vLHS, vRHS) { return new Vector3(vLHS.x * vRHS.x, vLHS.y * vRHS.y, vLHS.z * vRHS.z); }; LeapUtil.componentWiseReciprocal = function(inVector) { return new Vector3(1.0 / inVector.x, 1.0 / inVector.y, 1.0 / inVector.z); }; LeapUtil.minComponent = function(inVector) { return Math.min(inVector.x, Math.min(inVector.y, inVector.z)); }; LeapUtil.maxComponent = function(inVector) { return Math.max(inVector.x, Math.max(inVector.y, inVector.z)); }; /** * Compute the polar/spherical heading of a vector direction in z/x plane */ LeapUtil.heading = function(inVector) { return Math.atan2(inVector.z, inVector.x); }; /** * Compute the spherical elevation of a vector direction in y above the z/x plane */ LeapUtil.elevation = function(inVector) { return Math.atan2(inVector.y, Math.sqrt(inVector.z * inVector.z + inVector.x * inVector.x)); }; /** * Set magnitude to 1 and bring heading to [-Pi,Pi], elevation into [-Pi/2, Pi/2] * * @param vSpherical The Vector3 to convert. * @return The normalized spherical Vector3. * */ LeapUtil.normalizeSpherical = function(vSpherical) { var fHeading = vSpherical.y; var fElevation = vSpherical.z; while (fElevation <= -Math.PI) fElevation += LeapUtil.TWO_PI; while (fElevation > Math.PI) fElevation -= LeapUtil.TWO_PI; if (Math.abs(fElevation) > LeapUtil.HALF_PI) { fHeading += Math.PI; fElevation = fElevation > 0 ? (Math.PI - fElevation) : -(Math.PI + fElevation); } while (fHeading <= -Math.PI) fHeading += LeapUtil.TWO_PI; while (fHeading > Math.PI) fHeading -= LeapUtil.TWO_PI; return new Vector3(1, fHeading, fElevation); }; /** * Convert from Cartesian (rectangular) coordinates to spherical coordinates * (magnitude, heading, elevation). * * @param vCartesian The Vector3 to convert. * @return The cartesian Vector3 converted to spherical. * */ LeapUtil.cartesianToSpherical = function(vCartesian) { return new Vector3(vCartesian.magnitude(), this.heading(vCartesian), this.elevation(vCartesian)); }; /** * Convert from spherical coordinates (magnitude, heading, elevation) to * Cartesian (rectangular) coordinates. * * @param vSpherical The Vector3 to convert. * @return The spherical Vector3 converted to cartesian. * */ LeapUtil.sphericalToCartesian = function(vSpherical) { var fMagnitude = vSpherical.x; var fCosHeading = Math.cos(vSpherical.y); var fSinHeading = Math.sin(vSpherical.y); var fCosElevation = Math.cos(vSpherical.z); var fSinElevation = Math.sin(vSpherical.z); return new Vector3(fCosHeading * fCosElevation * fMagnitude, fSinElevation * fMagnitude, fSinHeading * fCosElevation * fMagnitude); }; /** * Clamps a value between a minimum Number and maximum Number value. * * @param inVal The number to clamp. * @param minVal The minimum value. * @param maxVal The maximum value. * @return The value clamped between minVal and maxVal. * */ LeapUtil.clamp = function(inVal, minVal, maxVal) { return (inVal < minVal) ? minVal : ((inVal > maxVal) ? maxVal : inVal); }; /** * Linearly interpolates between two Numbers. * * @param a A number. * @param b A number. * @param coefficient The interpolation coefficient [0-1]. * @return The interpolated number. * */ LeapUtil.lerp = function(a, b, coefficient) { return a + ((b - a) * coefficient); }; /** * Linearly interpolates between two Vector3 objects. * * @param vec1 A Vector3 object. * @param vec2 A Vector3 object. * @param coefficient The interpolation coefficient [0-1]. * @return A new interpolated Vector3 object. * */ LeapUtil.lerpVector = function(vec1, vec2, coefficient) { return vec1.plus(vec2.minus(vec1).multiply(coefficient)); }; /** The constant pi as a single precision floating point number. */ LeapUtil.PI = 3.1415926536; /** * The constant ratio to convert an angle measure from degrees to radians. * Multiply a value in degrees by this constant to convert to radians. */ LeapUtil.DEG_TO_RAD = 0.0174532925; /** * The constant ratio to convert an angle measure from radians to degrees. * Multiply a value in radians by this constant to convert to degrees. */ LeapUtil.RAD_TO_DEG = 57.295779513; /** * Pi &#42; 2. */ LeapUtil.TWO_PI = Math.PI + Math.PI; /** * Pi &#42; 0.5. */ LeapUtil.HALF_PI = Math.PI * 0.5; /** * Represents the smallest positive single value greater than zero. */ LeapUtil.EPSILON = 0.00001; return LeapUtil; })(); exports.LeapUtil = LeapUtil; /** * The Controller class is your main interface to the Leap Motion Controller. * * <p>Create an instance of this Controller class to access frames of tracking * data and configuration information. Frame data can be polled at any time using * the <code>Controller::frame()</code> . Call <code>frame()</code> or <code>frame(0)</code> * to get the most recent frame. Set the history parameter to a positive integer * to access previous frames. A controller stores up to 60 frames in its frame history.</p> * * <p>Polling is an appropriate strategy for applications which already have an * intrinsic update loop, such as a game. You can also implement the Leap::Listener * interface to handle events as they occur. The Leap dispatches events to the listener * upon initialization and exiting, on connection changes, and when a new frame * of tracking data is available. When these events occur, the controller object * invokes the appropriate callback defined in the Listener interface.</p> * * <p>To access frames of tracking data as they become available:</p> * * <ul> * <li>Implement the Listener interface and override the <code>Listener::onFrame()</code> .</li> * <li>In your <code>Listener::onFrame()</code> , call the <code>Controller::frame()</code> to access the newest frame of tracking data.</li> * <li>To start receiving frames, create a Controller object and add event listeners to the <code>Controller::addEventListener()</code> .</li> * </ul> * * <p>When an instance of a Controller object has been initialized, * it calls the <code>Listener::onInit()</code> when the listener is ready for use. * When a connection is established between the controller and the Leap, * the controller calls the <code>Listener::onConnect()</code> . At this point, * your application will start receiving frames of data. The controller calls * the <code>Listener::onFrame()</code> each time a new frame is available. * If the controller loses its connection with the Leap software or * device for any reason, it calls the <code>Listener::onDisconnect()</code> . * If the listener is removed from the controller or the controller is destroyed, * it calls the <code>Listener::onExit()</code> . At that point, unless the listener * is added to another controller again, it will no longer receive frames of tracking data.</p> * * @author logotype * */ var Controller = (function(_super) { __extends(Controller, _super); /** * Constructs a Controller object. * @param host IP or hostname of the computer running the Leap software. * (currently only supported for socket connections). * */ function Controller(host) { var _this = this; if (host === void 0) { host = null; } _super.call(this); /** * @private * History of frame of tracking data from the Leap. */ this.frameHistory = []; /** * @private * Reports whether this Controller is connected to the Leap Motion Controller. */ this._isConnected = false; /** * @private * Reports whether gestures is enabled. */ this._isGesturesEnabled = false; this.listener = new DefaultListener(); if (!host) { this.connection = new WebSocket("ws://localhost:6437/v6.json"); } else { this.connection = new WebSocket("ws://" + host + ":6437/v6.json"); } this.listener.onInit(this); this.connection.onopen = function(event) { _this._isConnected = true; _this.listener.onConnect(_this); var focusedState = {}; focusedState.focused = true; _this.connection.send(JSON.stringify(focusedState)); }; this.connection.onclose = function(data) { _this._isConnected = false; _this.listener.onDisconnect(_this); }; this.connection.onmessage = function(data) { var i; var json; var currentFrame; var hand; var pointable; var gesture; var isTool; var length; var type; json = JSON.parse(data.data); currentFrame = new Frame(); currentFrame.controller = _this; // Hands if (typeof json.hands !== "undefined") { i = 0; length = json.hands.length; for (i = 0; i < length; i++) { hand = new Hand(); hand.frame = currentFrame; hand.direction = new Vector3(json.hands[i].direction[0], json.hands[i].direction[1], json.hands[i].direction[2]); hand.id = json.hands[i].id; hand.palmNormal = new Vector3(json.hands[i].palmNormal[0], json.hands[i].palmNormal[1], json.hands[i].palmNormal[2]); hand.palmPosition = new Vector3(json.hands[i].palmPosition[0], json.hands[i].palmPosition[1], json.hands[i].palmPosition[2]); hand.stabilizedPalmPosition = new Vector3(json.hands[i].stabilizedPalmPosition[0], json.hands[i].stabilizedPalmPosition[1], json.hands[i].stabilizedPalmPosition[2]); hand.palmVelocity = new Vector3(json.hands[i].palmPosition[0], json.hands[i].palmPosition[1], json.hands[i].palmPosition[2]); hand.rotation = new Matrix(new Vector3(json.hands[i].r[0][0], json.hands[i].r[0][1], json.hands[i].r[0][2]), new Vector3(json.hands[i].r[1][0], json.hands[i].r[1][1], json.hands[i].r[1][2]), new Vector3(json.hands[i].r[2][0], json.hands[i].r[2][1], json.hands[i].r[2][2])); hand.scaleFactorNumber = json.hands[i].s; hand.sphereCenter = new Vector3(json.hands[i].sphereCenter[0], json.hands[i].sphereCenter[1], json.hands[i].sphereCenter[2]); hand.sphereRadius = json.hands[i].sphereRadius; hand.timeVisible = json.hands[i].timeVisible; hand.translationVector = new Vector3(json.hands[i].t[0], json.hands[i].t[1], json.hands[i].t[2]); currentFrame.hands.push(hand); } } currentFrame.id = json.id; currentFrame.currentFramesPerSecond = json.currentFramesPerSecond; // InteractionBox if (typeof json.interactionBox !== "undefined") { currentFrame.interactionBox = new InteractionBox(); currentFrame.interactionBox.center = new Vector3(json.interactionBox.center[0], json.interactionBox.center[1], json.interactionBox.center[2]); currentFrame.interactionBox.width = json.interactionBox.size[0]; currentFrame.interactionBox.height = json.interactionBox.size[1]; currentFrame.interactionBox.depth = json.interactionBox.size[2]; } // Pointables if (typeof json.pointables !== "undefined") { i = 0; length = json.pointables.length; for (i = 0; i < length; i++) { isTool = json.pointables[i].tool; if (isTool) pointable = new Tool(); else pointable = new Finger(); pointable.frame = currentFrame; pointable.id = json.pointables[i].id; pointable.hand = Controller.getHandByID(currentFrame, json.pointables[i].handId); pointable.length = json.pointables[i].length; pointable.direction = new Vector3(json.pointables[i].direction[0], json.pointables[i].direction[1], json.pointables[i].direction[2]); pointable.tipPosition = new Vector3(json.pointables[i].tipPosition[0], json.pointables[i].tipPosition[1], json.pointables[i].tipPosition[2]); pointable.stabilizedTipPosition = new Vector3(json.pointables[i].stabilizedTipPosition[0], json.pointables[i].stabilizedTipPosition[1], json.pointables[i].stabilizedTipPosition[2]); pointable.tipVelocity = new Vector3(json.pointables[i].tipVelocity[0], json.pointables[i].tipVelocity[1], json.pointables[i].tipVelocity[2]); pointable.touchDistance = json.pointables[i].touchDistance; pointable.timeVisible = json.pointables[i].timeVisible; currentFrame.pointables.push(pointable); switch (json.pointables[i].touchZone) { case "hovering": pointable.touchZone = Zone.ZONE_HOVERING; break; case "touching": pointable.touchZone = Zone.ZONE_TOUCHING; break; default: pointable.touchZone = Zone.ZONE_NONE; break; } if (pointable.hand) pointable.hand.pointables.push(pointable); if (isTool) { pointable.isTool = true; pointable.isFinger = false; pointable.width = json.pointables[i].width; currentFrame.tools.push(pointable); if (pointable.hand) pointable.hand.tools.push(pointable); } else { pointable.isTool = false; pointable.isFinger = true; currentFrame.fingers.push(pointable); if (pointable.hand) pointable.hand.fingers.push(pointable); } } } // Gestures if (typeof json.gestures !== "undefined") { i = 0; length = json.gestures.length; for (i = 0; i < length; i++) { switch (json.gestures[i].type) { case "circle": gesture = new CircleGesture(); type = Type.TYPE_CIRCLE; var circle = gesture; circle.center = new Vector3(json.gestures[i].center[0], json.gestures[i].center[1], json.gestures[i].center[2]); circle.normal = new Vector3(json.gestures[i].normal[0], json.gestures[i].normal[1], json.gestures[i].normal[2]); circle.progress = json.gestures[i].progress; circle.radius = json.gestures[i].radius; break; case "swipe": gesture = new SwipeGesture(); type = Type.TYPE_SWIPE; var swipe = gesture; swipe.startPosition = new Vector3(json.gestures[i].startPosition[0], json.gestures[i].startPosition[1], json.gestures[i].startPosition[2]); swipe.position = new Vector3(json.gestures[i].position[0], json.gestures[i].position[1], json.gestures[i].position[2]); swipe.direction = new Vector3(json.gestures[i].direction[0], json.gestures[i].direction[1], json.gestures[i].direction[2]); swipe.speed = json.gestures[i].speed; break; case "screenTap": gesture = new ScreenTapGesture(); type = Type.TYPE_SCREEN_TAP; var screenTap = gesture; screenTap.position = new Vector3(json.gestures[i].position[0], json.gestures[i].position[1], json.gestures[i].position[2]); screenTap.direction = new Vector3(json.gestures[i].direction[0], json.gestures[i].direction[1], json.gestures[i].direction[2]); screenTap.progress = json.gestures[i].progress; break; case "keyTap": gesture = new KeyTapGesture(); type = Type.TYPE_KEY_TAP; var keyTap = gesture; keyTap.position = new Vector3(json.gestures[i].position[0], json.gestures[i].position[1], json.gestures[i].position[2]); keyTap.direction = new Vector3(json.gestures[i].direction[0], json.gestures[i].direction[1], json.gestures[i].direction[2]); keyTap.progress = json.gestures[i].progress; break; default: throw new Error("unkown gesture type"); } var j = 0; var lengthInner = 0; if (typeof json.gestures[i].handIds !== "undefined") { j = 0; lengthInner = json.gestures[i].handIds.length; for (j = 0; j < lengthInner; ++j) { var gestureHand = Controller.getHandByID(currentFrame, json.gestures[i].handIds[j]); gesture.hands.push(gestureHand); } } if (typeof json.gestures[i].pointableIds !== "undefined") { j = 0; lengthInner = json.gestures[i].pointableIds.length; for (j = 0; j < lengthInner; ++j) { var gesturePointable = Controller.getPointableByID(currentFrame, json.gestures[i].pointableIds[j]); if (gesturePointable) { gesture.pointables.push(gesturePointable); } } if (gesture instanceof CircleGesture && gesture.pointables.length > 0) { gesture.pointable = gesture.pointables[0]; } } gesture.frame = currentFrame; gesture.id = json.gestures[i].id; gesture.duration = json.gestures[i].duration; gesture.durationSeconds = gesture.duration / 1000000; switch (json.gestures[i].state) { case "start": gesture.state = State.STATE_START; break; case "update": gesture.state = State.STATE_UPDATE; break; case "stop": gesture.state = State.STATE_STOP; break; default: gesture.state = State.STATE_INVALID; } gesture.type = type; currentFrame._gestures.push(gesture); } } // Rotation (since last frame), interpolate for smoother motion if (json.r) currentFrame.rotation = new Matrix(new Vector3(json.r[0][0], json.r[0][1], json.r[0][2]), new Vector3(json.r[1][0], json.r[1][1], json.r[1][2]), new Vector3(json.r[2][0], json.r[2][1], json.r[2][2])); // Scale factor (since last frame), interpolate for smoother motion currentFrame.scaleFactorNumber = json.s; // Translation (since last frame), interpolate for smoother motion if (json.t) currentFrame.translationVector = new Vector3(json.t[0], json.t[1], json.t[2]); // Timestamp currentFrame.timestamp = json.timestamp; // Add frame to history if (_this.frameHistory.length > 59) _this.frameHistory.splice(59, 1); _this.frameHistory.unshift(_this.latestFrame); _this.latestFrame = currentFrame; _this.listener.onFrame(_this, _this.latestFrame); }; } /** * Finds a Hand object by ID. * * @param frame The Frame object in which the Hand contains * @param id The ID of the Hand object * @return The Hand object if found, otherwise null * */ Controller.getHandByID = function(frame, id) { var returnValue = null; var i = 0; for (i = 0; i < frame.hands.length; i++) { if (frame.hands[i].id === id) { returnValue = frame.hands[i]; break; } } return returnValue; }; /** * Finds a Pointable object by ID. * * @param frame The Frame object in which the Pointable contains * @param id The ID of the Pointable object * @return The Pointable object if found, otherwise null * */ Controller.getPointableByID = function(frame, id) { var returnValue = null; var i = 0; for (i = 0; i < frame.pointables.length; i++) { if (frame.pointables[i].id === id) { returnValue = frame.pointables[i]; break; } } return returnValue; }; /** * Returns a frame of tracking data from the Leap. * * <p>Use the optional history parameter to specify which frame to retrieve. * Call <code>frame()</code> or <code>frame(0)</code> to access the most recent frame; * call <code>frame(1)</code> to access the previous frame, and so on. If you use a history value * greater than the number of stored frames, then the controller returns * an invalid frame.</p> * * @param history The age of the frame to return, counting backwards from * the most recent frame (0) into the past and up to the maximum age (59). * * @return The specified frame; or, if no history parameter is specified, * the newest frame. If a frame is not available at the specified * history position, an invalid Frame is returned. * */ Controller.prototype.frame = function(history) { if (history === void 0) { history = 0; } if (history >= this.frameHistory.length) return Frame.invalid(); else return this.frameHistory[history]; }; /** * Update the object that receives direct updates from the Leap Motion Controller. * * <p>The default listener will make the controller dispatch flash events. * You can override this behaviour, by implementing the IListener interface * in your own classes, and use this method to set the listener to your * own implementation.</p> * * @param listener */ Controller.prototype.setListener = function(listener) { this.listener = listener; }; /** * Enables or disables reporting of a specified gesture type. * * <p>By default, all gesture types are disabled. When disabled, gestures of * the disabled type are never reported and will not appear in the frame * gesture list.</p> * * <p>As a performance optimization, only enable recognition for the types * of movements that you use in your application.</p> * * @param type The type of gesture to enable or disable. Must be a member of the Gesture::Type enumeration. * @param enable True, to enable the specified gesture type; False, to disable. * */ Controller.prototype.enableGesture = function(type, enable) { if (enable === void 0) { enable = true; } var enableObject = {}; if (enable) { this._isGesturesEnabled = true; enableObject.enableGestures = true; } else { this._isGesturesEnabled = false; enableObject.enableGestures = false; } this.connection.send(JSON.stringify(enableObject)); }; /** * Reports whether the specified gesture type is enabled. * * @param type The Gesture.TYPE parameter. * @return True, if the specified type is enabled; false, otherwise. * */ Controller.prototype.isGestureEnabled = function(type) { return this._isGesturesEnabled; }; /** * Reports whether this Controller is connected to the Leap Motion Controller. * * <p>When you first create a Controller object, <code>isConnected()</code> returns false. * After the controller finishes initializing and connects to * the Leap, <code>isConnected()</code> will return true.</p> * * <p>You can either handle the onConnect event using a event listener * or poll the <code>isConnected()</code> if you need to wait for your * application to be connected to the Leap before performing * some other operation.</p> * * @return True, if connected; false otherwise. * */ Controller.prototype.isConnected = function() { return this._isConnected; }; return Controller; })(EventDispatcher); exports.Controller = Controller; /** * The InteractionBox class represents a box-shaped region completely within * the field of view of the Leap Motion controller. * * <p>The interaction box is an axis-aligned rectangular prism and provides * normalized coordinates for hands, fingers, and tools within this box. * The InteractionBox class can make it easier to map positions in the * Leap Motion coordinate system to 2D or 3D coordinate systems used * for application drawing.</p> * * <p>The InteractionBox region is defined by a center and dimensions along the x, y, and z axes.</p> * * @author logotype * */ var InteractionBox = (function() { function InteractionBox() {} /** * Converts a position defined by normalized InteractionBox coordinates * into device coordinates in millimeters. * * This function performs the inverse of normalizePoint(). * * @param normalizedPosition The input position in InteractionBox coordinates. * @return The corresponding denormalized position in device coordinates. * */ InteractionBox.prototype.denormalizePoint = function(normalizedPosition) { var vec = Vector3.invalid(); vec.x = (normalizedPosition.x - 0.5) * this.width + this.center.x; vec.y = (normalizedPosition.y - 0.5) * this.height + this.center.y; vec.z = (normalizedPosition.z - 0.5) * this.depth + this.center.z; return vec; }; /** * Normalizes the coordinates of a point using the interaction box. * * <p>Coordinates from the Leap Motion frame of reference (millimeters) are * converted to a range of [0..1] such that the minimum value of the * InteractionBox maps to 0 and the maximum value of the InteractionBox maps to 1.</p> * * @param position The input position in device coordinates. * @param clamp Whether or not to limit the output value to the range [0,1] * when the input position is outside the InteractionBox. Defaults to true. * @return The normalized position. * */ InteractionBox.prototype.normalizePoint = function(position, clamp) { if (clamp === void 0) { clamp = true; } var vec = Vector3.invalid(); vec.x = ((position.x - this.center.x) / this.width) + 0.5; vec.y = ((position.y - this.center.y) / this.height) + 0.5; vec.z = ((position.z - this.center.z) / this.depth) + 0.5; if (clamp) { vec.x = Math.min(Math.max(vec.x, 0), 1); vec.y = Math.min(Math.max(vec.y, 0), 1); vec.z = Math.min(Math.max(vec.z, 0), 1); } return vec; }; /** * Reports whether this is a valid InteractionBox object. * @return True, if this InteractionBox object contains valid data. * */ InteractionBox.prototype.isValid = function() { return this.center.isValid() && this.width > 0 && this.height > 0 && this.depth > 0; }; /** * Compare InteractionBox object equality/inequality. * * <p>Two InteractionBox objects are equal if and only if both InteractionBox * objects represent the exact same InteractionBox and both InteractionBoxes are valid.</p> * * @param other * @return * */ InteractionBox.prototype.isEqualTo = function(other) { if (!this.isValid() || !other.isValid()) return false; if (!this.center.isEqualTo(other.center)) return false; if (this.depth != other.depth) return false; if (this.height != other.height) return false; if (this.width != other.width) return false; return true; }; /** * Returns an invalid InteractionBox object. * * <p>You can use the instance returned by this function in comparisons * testing whether a given InteractionBox instance is valid or invalid. * (You can also use the <code>InteractionBox.isValid()</code> function.)</p> * * @return The invalid InteractionBox instance. * */ InteractionBox.invalid = function() { return new InteractionBox(); }; /** * Writes a brief, human readable description of the InteractionBox object. * @return A description of the InteractionBox as a string. * */ InteractionBox.prototype.toString = function() { return "[InteractionBox depth:" + this.depth + " height:" + this.height + " width:" + this.width + "]"; }; return InteractionBox; })(); exports.InteractionBox = InteractionBox; /** * The Pointable class reports the physical characteristics of a detected finger or tool. * Both fingers and tools are classified as Pointable objects. Use the Pointable.isFinger * property to determine whether a Pointable object represents a finger. Use the * Pointable.isTool property to determine whether a Pointable object represents a tool. * The Leap classifies a detected entity as a tool when it is thinner, straighter, * and longer than a typical finger. * * <p>Note that Pointable objects can be invalid, which means that they do not contain valid * tracking data and do not correspond to a physical entity. Invalid Pointable objects * can be the result of asking for a Pointable object using an ID from an earlier frame * when no Pointable objects with that ID exist in the current frame. A Pointable object * created from the Pointable constructor is also invalid. Test for validity with * the <code>Pointable.isValid()</code> function.</p> * * @author logotype * */ /** * Defines the values for reporting the state of a Pointable object in relation to an adaptive touch plane. */ var Zone; (function(Zone) { /** * The Pointable object is too far from the plane to be considered hovering or touching. * * <p>Defines the values for reporting the state of a Pointable object in relation to an adaptive touch plane.</p> */ Zone[Zone["ZONE_NONE"] = 0] = "ZONE_NONE"; /** * The Pointable object is close to, but not touching the plane. * * <p>Defines the values for reporting the state of a Pointable object in relation to an adaptive touch plane.</p> */ Zone[Zone["ZONE_HOVERING"] = 1] = "ZONE_HOVERING"; /** * The Pointable has penetrated the plane. * * <p>Defines the values for reporting the state of a Pointable object in relation to an adaptive touch plane.</p> */ Zone[Zone["ZONE_TOUCHING"] = 2] = "ZONE_TOUCHING"; })(Zone || (Zone = {})); var Pointable = (function() { function Pointable() { /** * The current touch zone of this Pointable object. * * <p>The Leap Motion software computes the touch zone based on a * floating touch plane that adapts to the user's finger movement * and hand posture. The Leap Motion software interprets purposeful * movements toward this plane as potential touch points. * When a Pointable moves close to the adaptive touch plane, * it enters the "hovering" zone. When a Pointable reaches or * passes through the plane, it enters the "touching" zone.</p> * * <p>The possible states are present in the Zone enum of this class:</p> * * <code>Zone.NONE – The Pointable is outside the hovering zone. * Zone.HOVERING – The Pointable is close to, but not touching the touch plane. * Zone.TOUCHING – The Pointable has penetrated the touch plane.</code> * * <p>The touchDistance value provides a normalized indication of the * distance to the touch plane when the Pointable is in the hovering * or touching zones.</p> * */ this.touchZone = Zone.ZONE_NONE; /** * A value proportional to the distance between this Pointable * object and the adaptive touch plane. * * <p>The touch distance is a value in the range [-1, 1]. * The value 1.0 indicates the Pointable is at the far edge of * the hovering zone. The value 0 indicates the Pointable is * just entering the touching zone. A value of -1.0 indicates * the Pointable is firmly within the touching zone. * Values in between are proportional to the distance from the plane. * Thus, the touchDistance of 0.5 indicates that the Pointable * is halfway into the hovering zone.</p> * * <p>You can use the touchDistance value to modulate visual * feedback given to the user as their fingers close in on a * touch target, such as a button.</p> * */ this.touchDistance = 0; /** * The estimated length of the finger or tool in millimeters. * * <p>The reported length is the visible length of the finger or tool from * the hand to tip.</p> * * <p>If the length isn't known, then a value of 0 is returned.</p> */ this.length = 0; /** * The estimated width of the finger or tool in millimeters. * * <p>The reported width is the average width of the visible portion * of the finger or tool from the hand to the tip.</p> * * <p>If the width isn't known, then a value of 0 is returned.</p> */ this.width = 0; this.direction = Vector3.invalid(); this.tipPosition = Vector3.invalid(); this.tipVelocity = Vector3.invalid(); } /** * Reports whether this is a valid Pointable object. * @return True if <code>direction</code>, <code>tipPosition</code> and <code>tipVelocity</code> are true. */ Pointable.prototype.isValid = function() { var returnValue = false; if ((this.direction && this.direction.isValid()) && (this.tipPosition && this.tipPosition.isValid()) && (this.tipVelocity && this.tipVelocity.isValid())) returnValue = true; return returnValue; }; /** * Compare Pointable object equality/inequality. * * <p>Two Pointable objects are equal if and only if both Pointable * objects represent the exact same physical entities in * the same frame and both Pointable objects are valid.</p> * * @param other The Pointable to compare with. * @return True; if equal, False otherwise. * */ Pointable.prototype.isEqualTo = function(other) { if (!this.isValid() || !other.isValid()) return false; if (this.frame != other.frame) return false; if (this.hand != other.hand) return false; if (!this.direction.isEqualTo(other.direction)) return false; if (this.length != other.length) return false; if (this.width != other.width) return false; if (this.id != other.id) return false; if (!this.tipPosition.isEqualTo(other.tipPosition)) return false; if (!this.tipVelocity.isEqualTo(other.tipVelocity)) return false; if (this.isFinger != other.isFinger || this.isTool != other.isTool) return false; return true; }; /** * Returns an invalid Pointable object. * * <p>You can use the instance returned by this in * comparisons testing whether a given Pointable instance * is valid or invalid.<br/> * (You can also use the <code>Pointable.isValid()</code> function.)</p> * * @return The invalid Pointable instance. * */ Pointable.invalid = function() { return new Pointable(); }; /** * A string containing a brief, human readable description of the Pointable object. */ Pointable.prototype.toString = function() { return "[Pointable direction: " + this.direction + " tipPosition: " + this.tipPosition + " tipVelocity: " + this.tipVelocity + "]"; }; return Pointable; })(); exports.Pointable = Pointable; /** * The Gesture class represents a recognized movement by the user. * * <p>The Leap watches the activity within its field of view for certain movement * patterns typical of a user gesture or command. For example, a movement from * side to side with the hand can indicate a swipe gesture, while a finger poking * forward can indicate a screen tap gesture.</p> * * <p>When the Leap recognizes a gesture, it assigns an ID and adds a Gesture object * to the frame gesture list. For continuous gestures, which occur over many frames, * the Leap updates the gesture by adding a Gesture object having the same ID and * updated properties in each subsequent frame.</p> * * <p><strong>Important: Recognition for each type of gesture must be enabled using the * <code>Controller.enableGesture()</code> function; otherwise no gestures are recognized * or reported.</strong></p> * * <p>Subclasses of Gesture define the properties for the specific movement * patterns recognized by the Leap.</p> * * <p>The Gesture subclasses for include: * <pre> * CircleGesture – A circular movement by a finger. * SwipeGesture – A straight line movement by the hand with fingers extended. * ScreenTapGesture – A forward tapping movement by a finger. * KeyTapGesture – A downward tapping movement by a finger. * </pre> * </p> * * <p>Circle and swipe gestures are continuous and these objects can have a state * of start, update, and stop.</p> * * <p>The screen tap gesture is a discrete gesture. The Leap only creates a single * ScreenTa