diff --git a/examples/leapOfFaith.js b/examples/leapOfFaith.js new file mode 100644 index 0000000000..6cd1a261eb --- /dev/null +++ b/examples/leapOfFaith.js @@ -0,0 +1,181 @@ +// +// leapOfFaith.js +// examples +// +// Created by Sam Cake on 6/22/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + + + + + +var jointList = MyAvatar.getJointNames(); +var jointMappings = "\n# Joint list start"; +for (var i = 0; i < jointList.length; i++) { + jointMappings = jointMappings + "\njointIndex = " + jointList[i] + " = " + i; +} +print(jointMappings + "\n# Joint list end"); + +function vec3ToString( v ) { + return ("(" + v.x +", " + v.y + ", " + v.z + ")" ); +} +function quatToString( q ) { + return ("(" + q.x +", " + q.y + ", " + q.z + ", " + q.w + ")" ); +} + +function printSpatialEvent( label, spatialEvent ) { + /* var dataString = label + " " + + vec3ToString( spatialEvent.locTranslation ) + " " + + quatToString( spatialEvent.locRotation ) + " " + + vec3ToString( spatialEvent.absTranslation ) + " " + + quatToString( spatialEvent.absRotation ); + // print( dataString ) + */; +} + +function avatarToWorld( apos ) { + + // apply offset ? + var offset = { x: 0, y: 0.5, z: -0.5 }; + var lpos = Vec3.sum(apos, offset); + + var wpos = Vec3.sum( MyAvatar.position , Vec3.multiplyQbyV(MyAvatar.orientation, lpos) ); + + return wpos; +} + +var jointParticles = []; +function updateJointParticle( joint, pos, look ) { + /* print( "debug 1" ); + var jointID = jointParticles[ joint ]; + if ( jointID == null ) { + print( "debug create " + joint ); +*/ + var ballProperties = { + position: pos, + velocity: { x: 0, y: 0, z: 0}, + gravity: { x: 0, y: 0, z: 0 }, + damping: 0, + radius : 0.005* look.r, + color: look.c, + lifetime: 0.05 + }; + jointParticles[ joint ] = Particles.addParticle(ballProperties); + /* } else { + print( "debug update " + joint ); + var prop = Particles.getParticleProperties( jointID ); + prop.position = pos; + prop.lifetime = 1.0; + Particles.editParticle( jointID, prop ); + }*/ +} + +function evalFingerBoneLook( isRightSide, finger, bone ) { + return { c: { red: (255 * ( 1 - isRightSide )), + green: 255 * ( ((bone - 1)) / 3 ), + blue: (255 * isRightSide) }, + r: (5 + (5 - (finger-1))) / 10.0 }; +} + +var leapJoints = [ + { n: "LeftHand", l: { c: { red: 255, green: 0, blue: 0 }, r: 3 } }, + + { n: "LeftHandThumb2", l: evalFingerBoneLook( 0, 1, 2) }, + { n: "LeftHandThumb3", l: evalFingerBoneLook( 0, 1, 3) }, + { n: "LeftHandThumb4", l: evalFingerBoneLook( 0, 1, 4) }, + + { n: "LeftHandIndex1", l: evalFingerBoneLook( 0, 2, 1) }, + { n: "LeftHandIndex2", l: evalFingerBoneLook( 0, 2, 2) }, + { n: "LeftHandIndex3", l: evalFingerBoneLook( 0, 2, 3) }, + { n: "LeftHandIndex4", l: evalFingerBoneLook( 0, 2, 4) }, + + { n: "LeftHandMiddle1", l: evalFingerBoneLook( 0, 3, 1) }, + { n: "LeftHandMiddle2", l: evalFingerBoneLook( 0, 3, 2) }, + { n: "LeftHandMiddle3", l: evalFingerBoneLook( 0, 3, 3) }, + { n: "LeftHandMiddle4", l: evalFingerBoneLook( 0, 3, 4) }, + + { n: "LeftHandRing1", l: evalFingerBoneLook( 0, 4, 1) }, + { n: "LeftHandRing2", l: evalFingerBoneLook( 0, 4, 2) }, + { n: "LeftHandRing3", l: evalFingerBoneLook( 0, 4, 3) }, + { n: "LeftHandRing4", l: evalFingerBoneLook( 0, 4, 4) }, + + { n: "LeftHandPinky1", l: evalFingerBoneLook( 0, 5, 1) }, + { n: "LeftHandPinky2", l: evalFingerBoneLook( 0, 5, 2) }, + { n: "LeftHandPinky3", l: evalFingerBoneLook( 0, 5, 3) }, + { n: "LeftHandPinky4", l: evalFingerBoneLook( 0, 5, 4) }, + + { n: "RightHand", l: { c: { red: 0, green: 0, blue: 255 }, r: 3 } }, + + { n: "RightHandThumb2", l: evalFingerBoneLook( 1, 1, 2) }, + { n: "RightHandThumb3", l: evalFingerBoneLook( 1, 1, 3) }, + { n: "RightHandThumb4", l: evalFingerBoneLook( 1, 1, 4) }, + + { n: "RightHandIndex1", l: evalFingerBoneLook( 1, 2, 1) }, + { n: "RightHandIndex2", l: evalFingerBoneLook( 1, 2, 2) }, + { n: "RightHandIndex3", l: evalFingerBoneLook( 1, 2, 3) }, + { n: "RightHandIndex4", l: evalFingerBoneLook( 1, 2, 4) }, + + { n: "RightHandMiddle1", l: evalFingerBoneLook( 1, 3, 1) }, + { n: "RightHandMiddle2", l: evalFingerBoneLook( 1, 3, 2) }, + { n: "RightHandMiddle3", l: evalFingerBoneLook( 1, 3, 3) }, + { n: "RightHandMiddle4", l: evalFingerBoneLook( 1, 3, 4) }, + + { n: "RightHandRing1", l: evalFingerBoneLook( 1, 4, 1) }, + { n: "RightHandRing2", l: evalFingerBoneLook( 1, 4, 2) }, + { n: "RightHandRing3", l: evalFingerBoneLook( 1, 4, 3) }, + { n: "RightHandRing4", l: evalFingerBoneLook( 1, 4, 4) }, + + { n: "RightHandPinky1", l: evalFingerBoneLook( 1, 5, 1) }, + { n: "RightHandPinky2", l: evalFingerBoneLook( 1, 5, 2) }, + { n: "RightHandPinky3", l: evalFingerBoneLook( 1, 5, 3) }, + { n: "RightHandPinky4", l: evalFingerBoneLook( 1, 5, 4) }, + + ]; + +function onSpatialEventHandler( jointName, look ) { + var _jointName = jointName; + var _look = look; + return (function( spatialEvent ) { + MyAvatar.setJointData(_jointName, spatialEvent.absRotation); + updateJointParticle(_jointName, avatarToWorld( spatialEvent.absTranslation ), _look ); + printSpatialEvent(_jointName, spatialEvent ); + }); +} + +var isPullingSpatialData = true; + +var jointControllers = []; +for ( i in leapJoints ) { + + print( leapJoints[i].n ); + var controller = Controller.createInputController( "Spatial", leapJoints[i].n ); + var handler = onSpatialEventHandler( leapJoints[i].n, leapJoints[i].l ); + jointControllers.push( { c: controller, h: handler } ); + + if ( ! isPullingSpatialData ) { + controller.spatialEvent.connect( handler ); + } +} + + +Script.update.connect(function(deltaTime) { + + if ( isPullingSpatialData ) + { + for ( i in jointControllers ) { + if ( jointControllers[i].c.isActive() ) { + var spatialEvent = { absTranslation: jointControllers[i].c.getAbsTranslation(), + absRotation: jointControllers[i].c.getAbsRotation() }; + jointControllers[i].h( spatialEvent ); + } + } + } + +}); + +Script.scriptEnding.connect(function() { +}); diff --git a/interface/external/leapmotion/include/Leap.h b/interface/external/leapmotion/include/Leap.h new file mode 100644 index 0000000000..11f5806384 --- /dev/null +++ b/interface/external/leapmotion/include/Leap.h @@ -0,0 +1,4792 @@ +/******************************************************************************\ +* Copyright (C) 2012-2014 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. * +\******************************************************************************/ + +#if !defined(__Leap_h__) +#define __Leap_h__ + +#include "LeapMath.h" +#include +#include + +// Define integer types for Visual Studio 2008 and earlier +#if defined(_MSC_VER) && (_MSC_VER < 1600) +typedef __int32 int32_t; +typedef __int64 int64_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int64 uint64_t; +#else +#include +#endif + +// Define Leap export macros +#if defined(_MSC_VER) // Visual C++ +#if LEAP_API_INTERNAL +#define LEAP_EXPORT +#elif LEAP_API_IMPLEMENTATION +#define LEAP_EXPORT __declspec(dllexport) +#else +#define LEAP_EXPORT __declspec(dllimport) +#endif +#define LEAP_EXPORT_CLASS +#define LEAP_EXPORT_PLUGIN __declspec(dllexport) +#elif !defined(SWIG) +#define LEAP_EXPORT __attribute__((visibility("default"))) +#define LEAP_EXPORT_CLASS __attribute__((visibility("default"))) +#define LEAP_EXPORT_PLUGIN __attribute__((visibility("default"))) +#else +#define LEAP_EXPORT +#define LEAP_EXPORT_CLASS +#define LEAP_EXPORT_PLUGIN +#endif + +namespace Leap { + + // Interface for internal use only + class LEAP_EXPORT_CLASS Interface { + public: + struct Implementation { + LEAP_EXPORT virtual ~Implementation() {} + }; + protected: + LEAP_EXPORT Interface(void* owner); + LEAP_EXPORT Interface(Implementation* reference, void* owner); + LEAP_EXPORT Interface(const Interface& rhs); + Interface(class SharedObject* object); + LEAP_EXPORT Interface& operator=(const Interface& rhs); + LEAP_EXPORT virtual ~Interface(); + template T* get() const { return static_cast(reference()); } + class SharedObject* m_object; + LEAP_EXPORT static void deleteCString(const char* cstr); + private: + LEAP_EXPORT Implementation* reference() const; + }; + + // Forward declarations for internal use only + class PointableImplementation; + class BoneImplementation; + class FingerImplementation; + class ToolImplementation; + class HandImplementation; + class GestureImplementation; + class ScreenImplementation; + class DeviceImplementation; + class InteractionBoxImplementation; + class FrameImplementation; + class ControllerImplementation; + template class ListBaseImplementation; + + // Forward declarations + class PointableList; + class FingerList; + class ToolList; + class HandList; + class GestureList; + class Hand; + class Gesture; + class Screen; + class InteractionBox; + class Frame; + class Listener; + + /** + * 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() + * function to determine whether a Pointable object represents a finger. Use the + * Pointable::isTool() function to determine whether a Pointable object represents a tool. + * The Leap Motion software classifies a detected entity as a tool when it is thinner, straighter, and longer + * than a typical finger. + * + * \include Pointable_Get_Basic.txt + * + * To provide touch emulation, the Leap Motion software associates a floating touch + * plane that adapts to the user's finger movement and hand posture. The Leap Motion + * interprets purposeful movements toward this plane as potential touch points. + * The Pointable class reports + * touch state with the touchZone and touchDistance values. + * + * 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 Pointable::isValid() function. + * + * @since 1.0 + */ + class Pointable : public Interface { + public: + + /** + * Defines the values for reporting the state of a Pointable object in relation to + * an adaptive touch plane. + * @since 1.0 + */ + enum Zone { + /** + * The Pointable object is too far from the plane to be + * considered hovering or touching. + * @since 1.0 + */ + ZONE_NONE = 0, + /** + * The Pointable object is close to, but not touching + * the plane. + * @since 1.0 + */ + ZONE_HOVERING = 1, + /** + * The Pointable has penetrated the plane. + * @since 1.0 + */ + ZONE_TOUCHING = 2, +#ifdef SWIGCSHARP + // deprecated + ZONENONE = ZONE_NONE, + ZONEHOVERING = ZONE_HOVERING, + ZONETOUCHING = ZONE_TOUCHING, +#endif + }; + + // For internal use only. + Pointable(PointableImplementation*); + // For internal use only. + Pointable(FingerImplementation*); + // For internal use only. + Pointable(ToolImplementation*); + + /** + * Constructs a Pointable object. + * + * An uninitialized pointable is considered invalid. + * Get valid Pointable objects from a Frame or a Hand object. + * + * \include Pointable_Pointable.txt + * + * @since 1.0 + */ + LEAP_EXPORT Pointable(); + + /** + * A unique ID assigned to this Pointable object, whose value remains the + * same across consecutive frames while the tracked finger or tool remains + * visible. If tracking is lost (for example, when a finger is occluded by + * another finger or when it is withdrawn from the Leap Motion Controller field of view), the + * Leap Motion software may assign a new ID when it detects the entity in a future frame. + * + * \include Pointable_id.txt + * + * Use the ID value with the Frame::pointable() function to find this + * Pointable object in future frames. + * + * IDs should be from 1 to 100 (inclusive). If more than 100 objects are tracked + * an IDs of -1 will be used until an ID in the defined range is available. + * + * @returns The ID assigned to this Pointable object. + * @since 1.0 + */ + LEAP_EXPORT int32_t id() const; + + /** + * The Frame associated with this Pointable object. + * + * \include Pointable_frame.txt + * + * @returns The associated Frame object, if available; otherwise, + * an invalid Frame object is returned. + * @since 1.0 + */ + LEAP_EXPORT Frame frame() const; + + /** + * The Hand associated with this finger or tool. + * + * \include Pointable_hand.txt + * + * @returns The associated Hand object, if available; otherwise, + * an invalid Hand object is returned. + * @since 1.0 + */ + LEAP_EXPORT Hand hand() const; + + /** + * The tip position in millimeters from the Leap Motion origin. + * + * \include Pointable_tipPosition.txt + * + * @returns The Vector containing the coordinates of the tip position. + * @since 1.0 + */ + LEAP_EXPORT Vector tipPosition() const; + + /** + * The rate of change of the tip position in millimeters/second. + * + * \include Pointable_tipVelocity.txt + * + * @returns The Vector containing the coordinates of the tip velocity. + * @since 1.0 + */ + LEAP_EXPORT Vector tipVelocity() const; + + /** + * The direction in which this finger or tool is pointing. + * + * \include Pointable_direction.txt + * + * The direction is expressed as a unit vector pointing in the same + * direction as the tip. + * + * \image html images/Leap_Finger_Model.png + * + * @returns The Vector pointing in the same direction as the tip of this + * Pointable object. + * @since 1.0 + */ + LEAP_EXPORT Vector direction() const; + + /** + * The estimated width of the finger or tool in millimeters. + * + * \include Pointable_width.txt + * + * The reported width is the average width of the visible portion of the + * finger or tool from the hand to the tip. If the width isn't known, + * then a value of 0 is returned. + * + * @returns The estimated width of this Pointable object. + * @since 1.0 + */ + LEAP_EXPORT float width() const; + + /** + * The estimated length of the finger or tool in millimeters. + * + * The reported length is the visible length of the finger or tool from the + * hand to tip. If the length isn't known, then a value of 0 is returned. + * + * \include Pointable_length.txt + * + * @returns The estimated length of this Pointable object. + * @since 1.0 + */ + LEAP_EXPORT float length() const; + + /** + * Whether or not this Pointable is believed to be a finger. + * Fingers are generally shorter, thicker, and less straight than tools. + * + * \include Pointable_Conversion.txt + * + * @returns True, if this Pointable is classified as a finger. + * @since 1.0 + */ + LEAP_EXPORT bool isFinger() const; + + /** + * Whether or not this Pointable is believed to be a tool. + * Tools are generally longer, thinner, and straighter than fingers. + * + * \include Pointable_Conversion.txt + * + * @returns True, if this Pointable is classified as a tool. + * @since 1.0 + */ + LEAP_EXPORT bool isTool() const; + + /** + * Whether or not this Pointable is in an extended posture. + * + * A finger is considered extended if it is extended straight from the hand as if + * pointing. A finger is not extended when it is bent down and curled towards the + * palm. Tools are always extended. + * + * \include Finger_isExtended.txt + * + * @returns True, if the pointable is extended. + * @since 2.0 + */ + LEAP_EXPORT bool isExtended() const; + + /** + * Reports whether this is a valid Pointable object. + * + * \include Pointable_isValid.txt + * + * @returns True, if this Pointable object contains valid tracking data. + * @since 1.0 + */ + LEAP_EXPORT bool isValid() const; + + /** + * The current touch zone of this Pointable object. + * + * 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. + * + * The possible states are present in the Zone enum of this class: + * + * * 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. + * + * The touchDistance value provides a normalized indication of the distance to + * the touch plane when the Pointable is in the hovering or touching zones. + * + * \include Pointable_touchZone.txt + * + * @returns The touch zone of this Pointable + * @since 1.0 + */ + LEAP_EXPORT Zone touchZone() const; + + /** + * A value proportional to the distance between this Pointable object and the + * adaptive touch plane. + * + * \image html images/Leap_Touch_Plane.png + * + * 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. + * + * \include Pointable_touchDistance.txt + * + * 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. + * + * @returns The normalized touch distance of this Pointable object. + * @since 1.0 + */ + LEAP_EXPORT float touchDistance() const; + + /** + * The stabilized tip position of this Pointable. + * + * Smoothing and stabilization is performed in order to make + * this value more suitable for interaction with 2D content. The stabilized + * position lags behind the tip position by a variable amount, depending + * primarily on the speed of movement. + * + * \include Pointable_stabilizedTipPosition.txt + * + * @returns A modified tip position of this Pointable object + * with some additional smoothing and stabilization applied. + * @since 1.0 + */ + LEAP_EXPORT Vector stabilizedTipPosition() const; + + /** + * The duration of time this Pointable has been visible to the Leap Motion Controller. + * + * \include Pointable_timeVisible.txt + * + * @returns The duration (in seconds) that this Pointable has been tracked. + * @since 1.0 + */ + LEAP_EXPORT float timeVisible() const; + + /** + * Returns an invalid Pointable object. + * + * You can use the instance returned by this function in comparisons testing + * whether a given Pointable instance is valid or invalid. (You can also use the + * Pointable::isValid() function.) + * + * \include Pointable_invalid.txt + * + * @returns The invalid Pointable instance. + * @since 1.0 + */ + LEAP_EXPORT static const Pointable& invalid(); + + /** + * Compare Pointable object equality. + * + * \include Pointable_operator_equals.txt + * + * 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. + * @since 1.0 + */ + LEAP_EXPORT bool operator==(const Pointable&) const; + + /** + * Compare Pointable object inequality. + * + * \include Pointable_operator_not_equal.txt + * + * 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. + * @since 1.0 + */ + LEAP_EXPORT bool operator!=(const Pointable&) const; + + /** + * Writes a brief, human readable description of the Pointable object to an output stream. + * + * \include Pointable_operator_stream.txt + * + * @since 1.0 + */ + LEAP_EXPORT friend std::ostream& operator<<(std::ostream&, const Pointable&); + + /** + * A string containing a brief, human readable description of the Pointable object. + * + * @returns A description of the Pointable object as a string. + * @since 1.0 + */ + std::string toString() const { + const char* cstr = toCString(); + std::string str(cstr); + deleteCString(cstr); + return str; + } + private: + LEAP_EXPORT const char* toCString() const; + }; + + /** + * The Bone class represents a tracked bone. + * + * All fingers contain 4 bones that make up the anatomy of the finger. + * Get valid Bone objects from a Finger object. + * + * Bones are ordered from base to tip, indexed from 0 to 3. Additionally, the + * bone's Type enum may be used to index a specific bone anatomically. + * + * \include Bone_iteration.txt + * + * The thumb does not have a base metacarpal bone and therefore contains a valid, + * zero length bone at that location. + * + * Note that Bone objects can be invalid, which means that they do not contain + * valid tracking data and do not correspond to a physical bone. Invalid Bone + * objects can be the result of asking for a Bone object from an invalid finger, + * indexing a bone out of range, or constructing a new bone. + * Test for validity with the Bone::isValid() function. + * @since 2.0 + */ + class Bone : public Interface { + public: + /** + * Enumerates the names of the bones. + * + * Members of this enumeration are returned by Bone::type() to identify a + * Bone object. + * @since 2.0 + */ + enum Type { + TYPE_METACARPAL = 0, /**< Bone connected to the wrist inside the palm */ + TYPE_PROXIMAL = 1, /**< Bone connecting to the palm */ + TYPE_INTERMEDIATE = 2, /**< Bone between the tip and the base*/ + TYPE_DISTAL = 3, /**< Bone at the tip of the finger */ + }; + + // For internal use only. + Bone(BoneImplementation*); + + /** + * Constructs an invalid Bone object. + * + * \include Bone_invalid.txt + * + * Get valid Bone objects from a Finger object. + * + * @since 2.0 + */ + LEAP_EXPORT Bone(); + + /** + * The base of the bone, closest to the wrist. + * + * In anatomical terms, this is the proximal end of the bone. + + * \include Bone_prevJoint.txt + * + * @returns The Vector containing the coordinates of the previous joint position. + * @since 2.0 + */ + LEAP_EXPORT Vector prevJoint() const; + + /** + * The end of the bone, closest to the finger tip. + * + * In anatomical terms, this is the distal end of the bone. + * + * \include Bone_nextJoint.txt + * + * @returns The Vector containing the coordinates of the next joint position. + * @since 2.0 + */ + LEAP_EXPORT Vector nextJoint() const; + + /** + * The midpoint of the bone. + * + * \include Bone_center.txt + * + * @returns The midpoint in the center of the bone. + * @since 2.0 + */ + LEAP_EXPORT Vector center() const; + + /** + * The normalized direction of the bone from base to tip. + * + * \include Bone_direction.txt + * + * @returns The normalized direction of the bone from base to tip. + * @since 2.0 + */ + LEAP_EXPORT Vector direction() const; + + /** + * The estimated length of the bone in millimeters. + * + * \include Bone_length.txt + * + * @returns The length of the bone in millimeters. + * @since 2.0 + */ + LEAP_EXPORT float length() const; + + /** + * The average width of the flesh around the bone in millimeters. + * + * \include Bone_width.txt + * + * @returns The width of the flesh around the bone in millimeters. + * @since 2.0 + */ + LEAP_EXPORT float width() const; + + /** + * The name of this bone. + * + * \include Bone_type.txt + * + * @returns The anatomical type of this bone as a member of the Bone::Type + * enumeration. + * @since 2.0 + */ + LEAP_EXPORT Type type() const; + + /** + * The orthonormal basis vectors for this Bone as a Matrix. + * + * Basis vectors specify the orientation of a bone. + * + * * xBasis. Perpendicular to the longitudinal axis of the + * bone; exits the sides of the finger. + * * yBasis or up vector. Perpendicular to the longitudinal + * axis of the bone; exits the top and bottom of the finger. More positive + * in the upward direction. + * * zBasis. Aligned with the longitudinal axis of the bone. + * More positive toward the base of the finger. + * + * The bases provided for the right hand use the right-hand rule; those for + * the left hand use the left-hand rule. Thus, the positive direction of the + * x-basis is to the right for the right hand and to the left for the left + * hand. You can change from right-hand to left-hand rule by multiplying the + * basis vectors by -1. + * + * You can use the basis vectors for such purposes as measuring complex + * finger poses and skeletal animation. + * + * Note that converting the basis vectors directly into a quaternion + * representation is not mathematically valid. If you use quaternions, + * create them from the derived rotation matrix not directly from the bases. + * + * \include Bone_basis.txt + * + * @returns The basis of the bone as a matrix. + * @since 2.0 + */ + LEAP_EXPORT Matrix basis() const; + + /** + * Reports whether this is a valid Bone object. + * + * \include Bone_isValid.txt + * + * @returns True, if this Bone object contains valid tracking data. + * @since 2.0 + */ + LEAP_EXPORT bool isValid() const; + + /** + * Returns an invalid Bone object. + * + * You can use the instance returned by this function in comparisons testing + * whether a given Bone instance is valid or invalid. (You can also use the + * Bone::isValid() function.) + * + * \include Bone_invalid.txt + * + * @returns The invalid Bone instance. + * @since 2.0 + */ + LEAP_EXPORT static const Bone& invalid(); + + /** + * Compare Bone object equality. + * + * Two Bone objects are equal if and only if both Bone objects represent the + * exact same physical bone in the same frame and both Bone objects are valid. + * @since 2.0 + */ + LEAP_EXPORT bool operator==(const Bone&) const; + + /** + * Compare Bone object inequality. + * + * Two Bone objects are equal if and only if both Bone objects represent the + * exact same physical bone in the same frame and both Bone objects are valid. + * @since 2.0 + */ + LEAP_EXPORT bool operator!=(const Bone&) const; + + /** + * Writes a brief, human readable description of the Bone object to an output stream. + * + * @since 2.0 + */ + LEAP_EXPORT friend std::ostream& operator<<(std::ostream&, const Bone&); + + /** + * A string containing a brief, human readable description of the Bone object. + * + * \include Bone_toString.txt + * + * @returns A description of the Bone object as a string. + * @since 2.0 + */ + std::string toString() const { + const char* cstr = toCString(); + std::string str(cstr); + deleteCString(cstr); + return str; + } + + private: + LEAP_EXPORT const char* toCString() const; + }; + + /** + * The Finger class represents a tracked finger. + * + * Fingers are Pointable objects that the Leap Motion software has classified as a finger. + * Get valid Finger objects from a Frame or a Hand object. + * + * Fingers may be permanently associated to a hand. In this case the angular order of the finger IDs + * will be invariant. As fingers move in and out of view it is possible for the guessed ID + * of a finger to be incorrect. Consequently, it may be necessary for finger IDs to be + * exchanged. All tracked properties, such as velocity, will remain continuous in the API. + * However, quantities that are derived from the API output (such as a history of positions) + * will be discontinuous unless they have a corresponding ID exchange. + * + * Note that Finger objects can be invalid, which means that they do not contain + * valid tracking data and do not correspond to a physical finger. Invalid Finger + * objects can be the result of asking for a Finger object using an ID from an + * earlier frame when no Finger objects with that ID exist in the current frame. + * A Finger object created from the Finger constructor is also invalid. + * Test for validity with the Finger::isValid() function. + * @since 1.0 + */ + class Finger : public Pointable { + public: + /** + * Deprecated as of version 2.0 + */ + enum Joint { + JOINT_MCP = 0, + JOINT_PIP = 1, + JOINT_DIP = 2, + JOINT_TIP = 3 + }; + + /** + * Enumerates the names of the fingers. + * + * Members of this enumeration are returned by Finger::type() to identify a + * Finger object. + * @since 2.0 + */ + enum Type { + TYPE_THUMB = 0, /**< The thumb */ + TYPE_INDEX = 1, /**< The index or fore-finger */ + TYPE_MIDDLE = 2, /**< The middle finger */ + TYPE_RING = 3, /**< The ring finger */ + TYPE_PINKY = 4 /**< The pinky or little finger */ + }; + + // For internal use only. + Finger(FingerImplementation*); + + /** + * Constructs a Finger object. + * + * An uninitialized finger is considered invalid. + * Get valid Finger objects from a Frame or a Hand object. + * @since 1.0 + */ + LEAP_EXPORT Finger(); + + /** + * If the specified Pointable object represents a finger, creates a copy + * of it as a Finger object; otherwise, creates an invalid Finger object. + * + * \include Finger_Finger.txt + * + * @since 1.0 + */ + LEAP_EXPORT explicit Finger(const Pointable&); + + /** + * Deprecated as of version 2.0 + * Use 'bone' method instead. + */ + LEAP_EXPORT Vector jointPosition(Joint jointIx) const; + + /** + * The bone at a given bone index on this finger. + * + * \include Bone_iteration.txt + * + * @param boneIx An index value from the Bone::Type enumeration identifying the + * bone of interest. + * @returns The Bone that has the specified bone type. + * @since 2.0 + */ + LEAP_EXPORT Bone bone(Bone::Type boneIx) const; + + /** + * The name of this finger. + * + * \include Finger_type.txt + * + * @returns The anatomical type of this finger as a member of the Finger::Type + * enumeration. + * @since 2.0 + */ + LEAP_EXPORT Type type() const; + + /** + * Returns an invalid Finger object. + * + * You can use the instance returned by this function in comparisons testing + * whether a given Finger instance is valid or invalid. (You can also use the + * Finger::isValid() function.) + * + * \include Finger_invalid.txt + * + * @returns The invalid Finger instance. + * @since 1.0 + */ + LEAP_EXPORT static const Finger& invalid(); + + /** + * A string containing a brief, human readable description of the Finger object. + * + * \include Finger_toString.txt + * + * @returns A description of the Finger object as a string. + * @since 1.0 + */ + std::string toString() const { + const char* cstr = toCString(); + std::string str(cstr); + deleteCString(cstr); + return str; + } + + private: + LEAP_EXPORT const char* toCString() const; + }; + + /** + * The Tool class represents a tracked tool. + * + * Tools are Pointable objects that the Leap Motion software has classified as a tool. + * Tools are longer, thinner, and straighter than a typical finger. + * Get valid Tool objects from a Frame or a Hand object. + * + * Tools may reference a hand, but unlike fingers they are not permanently associated. + * Instead, a tool can be transferred between hands while keeping the same ID. + * + * \image html images/Leap_Tool.png + * + * Note that Tool objects can be invalid, which means that they do not contain + * valid tracking data and do not correspond to a physical tool. Invalid Tool + * objects can be the result of asking for a Tool object using an ID from an + * earlier frame when no Tool objects with that ID exist in the current frame. + * A Tool object created from the Tool constructor is also invalid. + * Test for validity with the Tool::isValid() function. + * @since 1.0 + */ + class Tool : public Pointable { + public: + // For internal use only. + Tool(ToolImplementation*); + + /** + * Constructs a Tool object. + * + * An uninitialized tool is considered invalid. + * Get valid Tool objects from a Frame or a Hand object. + * + * \include Tool_Tool.txt + * + * @since 1.0 + */ + LEAP_EXPORT Tool(); + + /** + * If the specified Pointable object represents a tool, creates a copy + * of it as a Tool object; otherwise, creates an invalid Tool object. + * + * \include Tool_Tool_copy.txt + * + * @since 1.0 + */ + LEAP_EXPORT explicit Tool(const Pointable&); + + /** + * Returns an invalid Tool object. + * + * You can use the instance returned by this function in comparisons testing + * whether a given Tool instance is valid or invalid. (You can also use the + * Tool::isValid() function.) + * + * \include Tool_invalid.txt + * + * @returns The invalid Tool instance. + * @since 1.0 + */ + LEAP_EXPORT static const Tool& invalid(); + + /** + * A string containing a brief, human readable description of the Tool object. + * + * @returns A description of the Tool object as a string. + * @since 1.0 + */ + std::string toString() const { + const char* cstr = toCString(); + std::string str(cstr); + deleteCString(cstr); + return str; + } + + private: + LEAP_EXPORT const char* toCString() const; + }; + + /** + * The Hand class reports the physical characteristics of a detected hand. + * + * Hand tracking data includes a palm position and velocity; vectors for + * the palm normal and direction to the fingers; properties of a sphere fit + * to the hand; and lists of the attached fingers and tools. + * + * Get Hand objects from a Frame object: + * + * \include Hand_Get_First.txt + * + * Note that Hand objects can be invalid, which means that they do not contain + * valid tracking data and do not correspond to a physical entity. Invalid Hand + * objects can be the result of asking for a Hand object using an ID from an + * earlier frame when no Hand objects with that ID exist in the current frame. + * A Hand object created from the Hand constructor is also invalid. + * Test for validity with the Hand::isValid() function. + * @since 1.0 + */ + class Hand : public Interface { + public: + // For internal use only. + Hand(HandImplementation*); + + /** + * Constructs a Hand object. + * + * An uninitialized hand is considered invalid. + * Get valid Hand objects from a Frame object. + * + * \include Hand_Hand.txt + * + * @since 1.0 + */ + LEAP_EXPORT Hand(); + + /** + * A unique ID assigned to this Hand object, whose value remains the same + * across consecutive frames while the tracked hand remains visible. If + * tracking is lost (for example, when a hand is occluded by another hand + * or when it is withdrawn from or reaches the edge of the Leap Motion Controller field of view), + * the Leap Motion software may assign a new ID when it detects the hand in a future frame. + * + * Use the ID value with the Frame::hand() function to find this Hand object + * in future frames: + * + * \include Hand_Get_ID.txt + * + * @returns The ID of this hand. + * @since 1.0 + */ + LEAP_EXPORT int32_t id() const; + + /** + * The Frame associated with this Hand. + * + * \include Hand_frame.txt + * + * @returns The associated Frame object, if available; otherwise, + * an invalid Frame object is returned. + * @since 1.0 + */ + LEAP_EXPORT Frame frame() const; + + /** + * The list of Pointable objects (fingers and tools) detected in this frame + * that are associated with this hand, given in arbitrary order. The list + * will contain at least the 5 fingers. + * + * Use the Pointable::isFinger() function to determine whether or not an + * item in the list represents a finger. Use the Pointable::isTool() function + * to determine whether or not an item in the list represents a tool. + * You can also get only fingers using the Hand::fingers() function or + * only tools using the Hand::tools() function. + * + * Use PointableList::extended() to remove non-extended fingers from the list. + * + * \include Hand_Get_Fingers.txt + * + * @returns The PointableList containing all Pointable objects associated with this hand. + * @since 1.0 + */ + LEAP_EXPORT PointableList pointables() const; + + /** + * The Pointable object with the specified ID associated with this hand. + * + * Use the Hand::pointable() function to retrieve a Pointable object + * associated with this hand using an ID value obtained from a previous frame. + * This function always returns a Pointable object, but if no finger or tool + * with the specified ID is present, an invalid Pointable object is returned. + * + * \include Hand_Get_Pointable_ByID.txt + * + * Note that the ID values assigned to objects persist across frames, but only until + * tracking of that object is lost. If tracking of a finger or tool is lost and subsequently + * regained, the new Pointable object representing that finger or tool may have a + * different ID than that representing the finger or tool in an earlier frame. + * + * @param id The ID value of a Pointable object from a previous frame. + * @returns The Pointable object with the matching ID if one exists for this + * hand in this frame; otherwise, an invalid Pointable object is returned. + * @since 1.0 + */ + LEAP_EXPORT Pointable pointable(int32_t id) const; + + /** + * The list of Finger objects detected in this frame that are attached to + * this hand, given in order from thumb to pinky. The list cannot be empty. + * + * Use PointableList::extended() to remove non-extended fingers from the list. + * + * \include Hand_Get_Fingers.txt + * + * @returns The FingerList containing all Finger objects attached to this hand. + * @since 1.0 + */ + LEAP_EXPORT FingerList fingers() const; + + /** + * The Finger object with the specified ID attached to this hand. + * + * Use the Hand::finger() function to retrieve a Finger object attached to + * this hand using an ID value obtained from a previous frame. + * This function always returns a Finger object, but if no finger + * with the specified ID is present, an invalid Finger object is returned. + * + * \include Hand_finger.txt + * + * Note that ID values persist across frames, but only until tracking of a + * particular object is lost. If tracking of a finger is lost and subsequently + * regained, the new Finger object representing that finger may have a + * different ID than that representing the finger in an earlier frame. + * + * @param id The ID value of a Finger object from a previous frame. + * @returns The Finger object with the matching ID if one exists for this + * hand in this frame; otherwise, an invalid Finger object is returned. + * @since 1.0 + */ + LEAP_EXPORT Finger finger(int32_t id) const; + + /** + * The list of Tool objects detected in this frame that are held by this + * hand, given in arbitrary order. + * The list can be empty if no tools held by this hand are detected. + * + * \include Hand_tools.txt + * + * @returns The ToolList containing all Tool objects held by this hand. + * @since 1.0 + */ + LEAP_EXPORT ToolList tools() const; + + /** + * The Tool object with the specified ID held by this hand. + * + * Use the Hand::tool() function to retrieve a Tool object held by + * this hand using an ID value obtained from a previous frame. + * This function always returns a Tool object, but if no tool + * with the specified ID is present, an invalid Tool object is returned. + * + * \include Hand_tool.txt + * + * Note that ID values persist across frames, but only until tracking of a + * particular object is lost. If tracking of a tool is lost and subsequently + * regained, the new Tool object representing that tool may have a + * different ID than that representing the tool in an earlier frame. + * + * @param id The ID value of a Tool object from a previous frame. + * @returns The Tool object with the matching ID if one exists for this + * hand in this frame; otherwise, an invalid Tool object is returned. + * @since 1.0 + */ + LEAP_EXPORT Tool tool(int32_t id) const; + + /** + * The center position of the palm in millimeters from the Leap Motion Controller origin. + * + * \include Hand_palmPosition.txt + * + * @returns The Vector representing the coordinates of the palm position. + * @since 1.0 + */ + LEAP_EXPORT Vector palmPosition() const; + + /** + * The stabilized palm position of this Hand. + * + * Smoothing and stabilization is performed in order to make + * this value more suitable for interaction with 2D content. The stabilized + * position lags behind the palm position by a variable amount, depending + * primarily on the speed of movement. + * + * \include Hand_stabilizedPalmPosition.txt + * + * @returns A modified palm position of this Hand object + * with some additional smoothing and stabilization applied. + * @since 1.0 + */ + LEAP_EXPORT Vector stabilizedPalmPosition() const; + + /** + * The rate of change of the palm position in millimeters/second. + * + * \include Hand_palmVelocity.txt + * + * @returns The Vector representing the coordinates of the palm velocity. + * @since 1.0 + */ + LEAP_EXPORT Vector palmVelocity() const; + + /** + * The normal vector to the palm. If your hand is flat, this vector will + * point downward, or "out" of the front surface of your palm. + * + * \image html images/Leap_Palm_Vectors.png + * + * The direction is expressed as a unit vector pointing in the same + * direction as the palm normal (that is, a vector orthogonal to the palm). + * + * You can use the palm normal vector to compute the roll angle of the palm with + * respect to the horizontal plane: + * + * \include Hand_Get_Angles.txt + * + * @returns The Vector normal to the plane formed by the palm. + * @since 1.0 + */ + LEAP_EXPORT Vector palmNormal() const; + + /** + * The estimated width of the palm when the hand is in a flat position. + * + * \include Hand_palmWidth.txt + * + * @returns The width of the palm in millimeters + * @since 2.0 + */ + LEAP_EXPORT float palmWidth() const; + + /** + * The direction from the palm position toward the fingers. + * + * The direction is expressed as a unit vector pointing in the same + * direction as the directed line from the palm position to the fingers. + * + * You can use the palm direction vector to compute the pitch and yaw angles of the palm with + * respect to the horizontal plane: + * + * \include Hand_Get_Angles.txt + * + * @returns The Vector pointing from the palm position toward the fingers. + * @since 1.0 + */ + LEAP_EXPORT Vector direction() const; + + /** + * The orientation of the hand as a basis matrix. + * + * The basis is defined as follows: + * + * * xAxis: Positive in the direction of the pinky + * * yAxis: Positive above the hand + * * zAxis: Positive in the direction of the wrist + * + * Note: Since the left hand is a mirror of the right hand, the + * basis matrix will be left-handed for left hands. + * + * \include Hand_basis.txt + * + * @returns The basis of the hand as a matrix. + * @since 2.0 + */ + LEAP_EXPORT Matrix basis() const; + + /** + * The center of a sphere fit to the curvature of this hand. + * + * \include Hand_sphereCenter.txt + * + * This sphere is placed roughly as if the hand were holding a ball. + * + * \image html images/Leap_Hand_Ball.png + * + * @returns The Vector representing the center position of the sphere. + * @since 1.0 + */ + LEAP_EXPORT Vector sphereCenter() const; + + /** + * The radius of a sphere fit to the curvature of this hand. + * + * This sphere is placed roughly as if the hand were holding a ball. Thus the + * size of the sphere decreases as the fingers are curled into a fist. + * + * \include Hand_sphereRadius.txt + * + * @returns The radius of the sphere in millimeters. + * @since 1.0 + */ + LEAP_EXPORT float sphereRadius() const; + + /** + * The holding strength of a pinch hand pose. + * + * The strength is zero for an open hand, and blends to 1.0 when a pinching + * hand pose is recognized. Pinching can be done between the thumb + * and any other finger of the same hand. + * + * \include Hand_pinchStrength.txt + * + * @returns A float value in the [0..1] range representing the holding strength + * of the pinch pose. + * @since 2.0 + */ + LEAP_EXPORT float pinchStrength() const; + + /** + * The strength of a grab hand pose. + * + * The strength is zero for an open hand, and blends to 1.0 when a grabbing hand + * pose is recognized. + * + * \include Hand_grabStrength.txt + * + * @returns A float value in the [0..1] range representing the holding strength + * of the pose. + * @since 2.0 + */ + LEAP_EXPORT float grabStrength() const; + + /** + * The change of position of this hand between the current frame and + * the specified frame. + * + * The returned translation vector provides the magnitude and direction of + * the movement in millimeters. + * + * \include Hand_translation.txt + * + * If a corresponding Hand object is not found in sinceFrame, or if either + * this frame or sinceFrame are invalid Frame objects, then this method + * returns a zero vector. + * + * @param sinceFrame The starting frame for computing the translation. + * @returns A Vector representing the heuristically determined change in + * hand position between the current frame and that specified in the + * sinceFrame parameter. + * @since 1.0 + */ + LEAP_EXPORT Vector translation(const Frame& sinceFrame) const; + + /** + * The estimated probability that the hand motion between the current + * frame and the specified frame is intended to be a translating motion. + * + * \include Hand_translationProbability.txt + * + * If a corresponding Hand object is not found in sinceFrame, or if either + * this frame or sinceFrame are invalid Frame objects, then this method + * returns zero. + * + * @param sinceFrame The starting frame for computing the translation. + * @returns A value between 0 and 1 representing the estimated probability + * that the hand motion between the current frame and the specified frame + * is intended to be a translating motion. + * @since 1.0 + */ + LEAP_EXPORT float translationProbability(const Frame& sinceFrame) const; + + /** + * The axis of rotation derived from the change in orientation of this + * hand, and any associated fingers and tools, between the current frame + * and the specified frame. + * + * \include Hand_rotationAxis.txt + * + * The returned direction vector is normalized. + * + * If a corresponding Hand object is not found in sinceFrame, or if either + * this frame or sinceFrame are invalid Frame objects, then this method + * returns a zero vector. + * + * @param sinceFrame The starting frame for computing the relative rotation. + * @returns A normalized direction Vector representing the heuristically + * determined axis of rotational change of the hand between the current + * frame and that specified in the sinceFrame parameter. + * @since 1.0 + */ + LEAP_EXPORT Vector rotationAxis(const Frame& sinceFrame) const; + + /** + * The angle of rotation around the rotation axis derived from the change + * in orientation of this hand, and any associated fingers and tools, + * between the current frame and the specified frame. + * + * \include Hand_rotationAngle.txt + * + * The returned angle is expressed in radians measured clockwise around the + * rotation axis (using the right-hand rule) between the start and end frames. + * The value is always between 0 and pi radians (0 and 180 degrees). + * + * If a corresponding Hand object is not found in sinceFrame, or if either + * this frame or sinceFrame are invalid Frame objects, then the angle of + * rotation is zero. + * + * @param sinceFrame The starting frame for computing the relative rotation. + * @returns A positive value representing the heuristically determined + * rotational change of the hand between the current frame and that + * specified in the sinceFrame parameter. + * @since 1.0 + */ + LEAP_EXPORT float rotationAngle(const Frame& sinceFrame) const; + + /** + * The angle of rotation around the specified axis derived from the change + * in orientation of this hand, and any associated fingers and tools, + * between the current frame and the specified frame. + * + * \include Hand_rotationAngle_axis.txt + * + * The returned angle is expressed in radians measured clockwise around the + * rotation axis (using the right-hand rule) between the start and end frames. + * The value is always between -pi and pi radians (-180 and 180 degrees). + * + * If a corresponding Hand object is not found in sinceFrame, or if either + * this frame or sinceFrame are invalid Frame objects, then the angle of + * rotation is zero. + * + * @param sinceFrame The starting frame for computing the relative rotation. + * @param axis The axis to measure rotation around. + * @returns A value representing the heuristically determined rotational + * change of the hand between the current frame and that specified in the + * sinceFrame parameter around the specified axis. + * @since 1.0 + */ + LEAP_EXPORT float rotationAngle(const Frame& sinceFrame, const Vector& axis) const; + + /** + * The transform matrix expressing the rotation derived from the change + * in orientation of this hand, and any associated fingers and tools, + * between the current frame and the specified frame. + * + * \include Hand_rotationMatrix.txt + * + * If a corresponding Hand object is not found in sinceFrame, or if either + * this frame or sinceFrame are invalid Frame objects, then this method + * returns an identity matrix. + * + * @param sinceFrame The starting frame for computing the relative rotation. + * @returns A transformation Matrix representing the heuristically determined + * rotational change of the hand between the current frame and that specified + * in the sinceFrame parameter. + * @since 1.0 + */ + LEAP_EXPORT Matrix rotationMatrix(const Frame& sinceFrame) const; + + /** + * The estimated probability that the hand motion between the current + * frame and the specified frame is intended to be a rotating motion. + * + * \include Hand_rotationProbability.txt + * + * If a corresponding Hand object is not found in sinceFrame, or if either + * this frame or sinceFrame are invalid Frame objects, then this method + * returns zero. + * + * @param sinceFrame The starting frame for computing the relative rotation. + * @returns A value between 0 and 1 representing the estimated probability + * that the hand motion between the current frame and the specified frame + * is intended to be a rotating motion. + * @since 1.0 + */ + LEAP_EXPORT float rotationProbability(const Frame& sinceFrame) const; + + /** + * The scale factor derived from this hand's motion between the current frame + * and the specified frame. + * + * The scale factor is always positive. A value of 1.0 indicates no + * scaling took place. Values between 0.0 and 1.0 indicate contraction + * and values greater than 1.0 indicate expansion. + * + * \include Hand_scaleFactor.txt + * + * The Leap Motion software derives scaling from the relative inward or outward motion of + * a hand and its associated fingers and tools (independent of translation + * and rotation). + * + * If a corresponding Hand object is not found in sinceFrame, or if either + * this frame or sinceFrame are invalid Frame objects, then this method + * returns 1.0. + * + * @param sinceFrame The starting frame for computing the relative scaling. + * @returns A positive value representing the heuristically determined + * scaling change ratio of the hand between the current frame and that + * specified in the sinceFrame parameter. + * @since 1.0 + */ + LEAP_EXPORT float scaleFactor(const Frame& sinceFrame) const; + + /** + * The estimated probability that the hand motion between the current + * frame and the specified frame is intended to be a scaling motion. + * + * \include Hand_scaleProbability.txt + * + * If a corresponding Hand object is not found in sinceFrame, or if either + * this frame or sinceFrame are invalid Frame objects, then this method + * returns zero. + * + * @param sinceFrame The starting frame for computing the relative scaling. + * @returns A value between 0 and 1 representing the estimated probability + * that the hand motion between the current frame and the specified frame + * is intended to be a scaling motion. + * @since 1.0 + */ + LEAP_EXPORT float scaleProbability(const Frame& sinceFrame) const; + + /** + * The duration of time this Hand has been visible to the Leap Motion Controller. + * + * \include Hand_timeVisible.txt + * + * @returns The duration (in seconds) that this Hand has been tracked. + * @since 1.0 + */ + LEAP_EXPORT float timeVisible() const; + + /** + * How confident we are with a given hand pose. + * + * The confidence level ranges between 0.0 and 1.0 inclusive. + * + * \include Hand_confidence.txt + * + * @since 2.0 + */ + LEAP_EXPORT float confidence() const; + + /** + * Identifies whether this Hand is a left hand. + * + * \include Hand_isLeft.txt + * + * @returns True if the hand is identified as a left hand. + * @since 2.0 + */ + LEAP_EXPORT bool isLeft() const; + + /** + * Identifies whether this Hand is a right hand. + * + * \include Hand_isRight.txt + * + * @returns True if the hand is identified as a right hand. + * @since 2.0 + */ + LEAP_EXPORT bool isRight() const; + + /** + * Reports whether this is a valid Hand object. + * + * \include Hand_isValid.txt + * + * @returns True, if this Hand object contains valid tracking data. + * @since 1.0 + */ + LEAP_EXPORT bool isValid() const; + + /** + * Returns an invalid Hand object. + * + * \include Hand_invalid.txt + * + * You can use the instance returned by this function in comparisons testing + * whether a given Hand instance is valid or invalid. (You can also use the + * Hand::isValid() function.) + * + * @returns The invalid Hand instance. + * @since 1.0 + */ + LEAP_EXPORT static const Hand& invalid(); + + /** + * Compare Hand object equality. + * + * \include Hand_operator_equals.txt + * + * Two Hand objects are equal if and only if both Hand objects represent the + * exact same physical hand in the same frame and both Hand objects are valid. + * @since 1.0 + */ + LEAP_EXPORT bool operator==(const Hand&) const; + + /** + * Compare Hand object inequality. + * + * \include Hand_operator_not_equals.txt + * + * Two Hand objects are equal if and only if both Hand objects represent the + * exact same physical hand in the same frame and both Hand objects are valid. + * @since 1.0 + */ + LEAP_EXPORT bool operator!=(const Hand&) const; + + /** + * Writes a brief, human readable description of the Hand object to an output stream. + * + * \include Hand_operator_stream.txt + * + * @since 1.0 + */ + LEAP_EXPORT friend std::ostream& operator<<(std::ostream&, const Hand&); + + /** + * A string containing a brief, human readable description of the Hand object. + * + * @returns A description of the Hand as a string. + * @since 1.0 + */ + std::string toString() const { + const char* cstr = toCString(); + std::string str(cstr); + deleteCString(cstr); + return str; + } + + private: + LEAP_EXPORT const char* toCString() const; + }; + + /** + * The Gesture class represents a recognized movement by the user. + * + * The Leap Motion Controller 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. + * + * When the Leap Motion software 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 Motion software updates the gesture by adding + * a Gesture object having the same ID and updated properties in each + * subsequent frame. + * + * **Important:** Recognition for each type of gesture must be enabled using the + * Controller::enableGesture() function; otherwise **no gestures are recognized or + * reported**. + * + * \include Gesture_Feature_enable.txt + * + * Subclasses of Gesture define the properties for the specific movement patterns + * recognized by the Leap Motion software. + * + * The Gesture subclasses for include: + * + * * 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. + * + * Circle and swipe gestures are continuous and these objects can have a + * state of start, update, and stop. + * + * The screen tap gesture is a discrete gesture. The Leap Motion software only creates a single + * ScreenTapGesture object for each tap and it always has a stop state. + * + * Get valid Gesture instances from a Frame object. You can get a list of gestures + * with the Frame::gestures() method. You can get a list of gestures since a + * specified frame with the `Frame::gestures(const Frame&)` method. You can also + * use the `Frame::gesture()` method to find a gesture in the current frame using + * an ID value obtained in a previous frame. + * + * Gesture objects can be invalid. For example, when you get a gesture by ID + * using `Frame::gesture()`, and there is no gesture with that ID in the current + * frame, then `gesture()` returns an Invalid Gesture object (rather than a null + * value). Always check object validity in situations where a gesture might be + * invalid. + * + * The following keys can be used with the Config class to configure the gesture + * recognizer: + * + * \table + * ==================================== ========== ============= ======= + * Key string Value type Default value Units + * ==================================== ========== ============= ======= + * Gesture.Circle.MinRadius float 5.0 mm + * Gesture.Circle.MinArc float 1.5 * pi radians + * Gesture.Swipe.MinLength float 150 mm + * Gesture.Swipe.MinVelocity float 1000 mm/s + * Gesture.KeyTap.MinDownVelocity float 50 mm/s + * Gesture.KeyTap.HistorySeconds float 0.1 s + * Gesture.KeyTap.MinDistance float 3.0 mm + * Gesture.ScreenTap.MinForwardVelocity float 50 mm/s + * Gesture.ScreenTap.HistorySeconds float 0.1 s + * Gesture.ScreenTap.MinDistance float 5.0 mm + * ==================================== ========== ============= ======= + * \endtable + * + * @since 1.0 + */ + class Gesture : public Interface { + public: + // For internal use only. + Gesture(GestureImplementation*); + + /** + * The supported types of gestures. + * @since 1.0 + */ + enum Type { + /** + * An invalid type. + * @since 1.0 + */ + TYPE_INVALID = -1, + /** + * A straight line movement by the hand with fingers extended. + * @since 1.0 + */ + TYPE_SWIPE = 1, + /** + * A circular movement by a finger. + * @since 1.0 + */ + TYPE_CIRCLE = 4, + /** + * A forward tapping movement by a finger. + * @since 1.0 + */ + TYPE_SCREEN_TAP = 5, + /** + * A downward tapping movement by a finger. + * @since 1.0 + */ + TYPE_KEY_TAP = 6, +#ifdef SWIGCSHARP + // deprecated + TYPEINVALID = TYPE_INVALID, + TYPESWIPE = TYPE_SWIPE, + TYPECIRCLE = TYPE_CIRCLE, + TYPESCREENTAP = TYPE_SCREEN_TAP, + TYPEKEYTAP = TYPE_KEY_TAP, +#endif + }; + + /** + * The possible gesture states. + * @since 1.0 + */ + enum State { + /** + * An invalid state + * @since 1.0 + */ + STATE_INVALID = -1, + /** + * The gesture is starting. Just enough has happened to recognize it. + * @since 1.0 + */ + STATE_START = 1, + /** + * The gesture is in progress. (Note: not all gestures have updates). + * @since 1.0 + */ + STATE_UPDATE = 2, + /** + * The gesture has completed or stopped. + * @since 1.0 + */ + STATE_STOP = 3, +#ifdef SWIGCSHARP + // deprecated + STATEINVALID = STATE_INVALID, + STATESTART = STATE_START, + STATEUPDATE = STATE_UPDATE, + STATESTOP = STATE_STOP, +#endif + }; + + /** + * Constructs a new Gesture object. + * + * An uninitialized Gesture object is considered invalid. Get valid instances + * of the Gesture class, which will be one of the Gesture subclasses, from a + * Frame object. + * @since 1.0 + */ + LEAP_EXPORT Gesture(); + + /** + * Constructs a new copy of an Gesture object. + * + * \include Gesture_Gesture_copy.txt + * + * @since 1.0 + */ + LEAP_EXPORT Gesture(const Gesture& rhs); + + /** + * The gesture type. + * + * \include Gesture_type.txt + * + * @returns Gesture::Type A value from the Gesture::Type enumeration. + * @since 1.0 + */ + LEAP_EXPORT Type type() const; + + /** + * The gesture state. + * + * Recognized movements occur over time and have a beginning, a middle, + * and an end. The 'state()' attribute reports where in that sequence this + * Gesture object falls. + * + * \include Gesture_state.txt + * + * @returns Gesture::State A value from the Gesture::State enumeration. + * @since 1.0 + */ + LEAP_EXPORT State state() const; + + /** + * The gesture ID. + * + * All Gesture objects belonging to the same recognized movement share the + * same ID value. Use the ID value with the Frame::gesture() method to + * find updates related to this Gesture object in subsequent frames. + * + * \include Gesture_id.txt + * + * @returns int32_t the ID of this Gesture. + * @since 1.0 + */ + LEAP_EXPORT int32_t id() const; + + /** + * The elapsed duration of the recognized movement up to the + * frame containing this Gesture object, in microseconds. + * + * \include Gesture_duration.txt + * + * The duration reported for the first Gesture in the sequence (with the + * STATE_START state) will typically be a small positive number since + * the movement must progress far enough for the Leap Motion software to recognize it as + * an intentional gesture. + * + * @return int64_t the elapsed duration in microseconds. + * @since 1.0 + */ + LEAP_EXPORT int64_t duration() const; + + /** + * The elapsed duration in seconds. + * + * \include Gesture_durationSeconds.txt + * + * @see duration() + * @return float the elapsed duration in seconds. + * @since 1.0 + */ + LEAP_EXPORT float durationSeconds() const; + + /** + * The Frame containing this Gesture instance. + * + * \include Gesture_frame.txt + _ + * @return Frame The parent Frame object. + * @since 1.0 + */ + LEAP_EXPORT Frame frame() const; + + /** + * The list of hands associated with this Gesture, if any. + * + * \include Gesture_hands.txt + * + * If no hands are related to this gesture, the list is empty. + * + * @return HandList the list of related Hand objects. + * @since 1.0 + */ + LEAP_EXPORT HandList hands() const; + + /** + * The list of fingers and tools associated with this Gesture, if any. + * + * If no Pointable objects are related to this gesture, the list is empty. + * + * \include Gesture_pointables.txt + * + * @return PointableList the list of related Pointable objects. + * @since 1.0 + */ + LEAP_EXPORT PointableList pointables() const; + + /** + * Reports whether this Gesture instance represents a valid Gesture. + * + * An invalid Gesture object does not represent a snapshot of a recognized + * movement. Invalid Gesture objects are returned when a valid object cannot + * be provided. For example, when you get an gesture by ID + * using Frame::gesture(), and there is no gesture with that ID in the current + * frame, then gesture() returns an Invalid Gesture object (rather than a null + * value). Always check object validity in situations where an gesture might be + * invalid. + * + * \include Gesture_isValid.txt + * + * @returns bool True, if this is a valid Gesture instance; false, otherwise. + * @since 1.0 + */ + LEAP_EXPORT bool isValid() const; + + /** + * Compare Gesture object equality. + * + * \include Gesture_operator_equals.txt + * + * Two Gestures are equal if they represent the same snapshot of the same + * recognized movement. + * @since 1.0 + */ + LEAP_EXPORT bool operator==(const Gesture& rhs) const; + + /** + * Compare Gesture object inequality. + * + * \include Gesture_operator_not_equals.txt + * + * Two Gestures are equal only if they represent the same snapshot of the same + * recognized movement. + * @since 1.0 + */ + LEAP_EXPORT bool operator!=(const Gesture& rhs) const; + + /** + * A string containing a brief, human-readable description of this + * Gesture. + * + * \include Gesture_toString.txt + * + * @since 1.0 + */ + std::string toString() const { + const char* cstr = toCString(); + std::string str(cstr); + deleteCString(cstr); + return str; + } + + /** + * Returns an invalid Gesture object. + * + * You can use the instance returned by this function in comparisons testing + * whether a given Gesture instance is valid or invalid. (You can also use the + * Gesture::isValid() function.) + * + * \include Gesture_invalid.txt + * + * @returns The invalid Gesture instance. + * @since 1.0 + */ + LEAP_EXPORT static const Gesture& invalid(); + + private: + LEAP_EXPORT const char* toCString() const; + }; + + /** + * The SwipeGesture class represents a swiping motion of hand and a finger or tool. + * + * \image html images/Leap_Gesture_Swipe.png + * + * SwipeGesture objects are generated for each visible finger or tool on the + * swiping hand. Swipe gestures are continuous; a gesture object with the same + * ID value will appear in each frame while the gesture continues. + * + * **Important:** To use swipe gestures in your application, you must enable + * recognition of the swipe gesture. You can enable recognition with: + * + * \include Gesture_Swipe_Enable.txt + * + * You can set the minimum length and velocity required for a movement + * to be recognized as a swipe using the config attribute of a connected + * Controller object. Use the following keys to configure swipe recognition: + * + * \table + * ==================================== ========== ============= ======= + * Key string Value type Default value Units + * ==================================== ========== ============= ======= + * Gesture.Swipe.MinLength float 150 mm + * Gesture.Swipe.MinVelocity float 1000 mm/s + * ==================================== ========== ============= ======= + * \endtable + * + * The following example demonstrates how to set the swipe configuration + * parameters: + * + * \include Gesture_Swipe_Params.txt + * + * The Controller object must be connected to the Leap Motion service/daemon + * before setting the configuration parameters. + * + * @since 1.0 + */ + class SwipeGesture : public Gesture + { + public: + /** + * The swipe gesture type. + * + * \include SwipeGesture_classType.txt + * + * @returns Type The type value designating a swipe gesture. + * @since 1.0 + */ + static Type classType() { return TYPE_SWIPE; } + + LEAP_EXPORT SwipeGesture(); + + /** + * Constructs a SwipeGesture object from an instance of the Gesture class. + * + * \include SwipeGesture_SwipeGesture.txt + * + * @param rhs The Gesture instance to specialize. This Gesture instance must + * be a SwipeGesture object. + * @since 1.0 + */ + LEAP_EXPORT SwipeGesture(const Gesture& rhs); + + /** + * The position where the swipe began. + * + * \include SwipeGesture_startPosition.txt + * + * @returns Vector The starting position within the Leap Motion frame of + * reference, in mm. + * @since 1.0 + */ + LEAP_EXPORT Vector startPosition() const; + + /** + * The current position of the swipe. + * + * \include SwipeGesture_position.txt + * + * @returns Vector The current swipe position within the Leap Motion frame of + * reference, in mm. + * @since 1.0 + */ + LEAP_EXPORT Vector position() const; + + /** + * The unit direction vector parallel to the swipe motion. + * + * \include SwipeGesture_direction.txt + * + * You can compare the components of the vector to classify the swipe as + * appropriate for your application. For example, if you are using swipes + * for two dimensional scrolling, you can compare the x and y values to + * determine if the swipe is primarily horizontal or vertical. + * + * @returns Vector The unit direction vector representing the swipe + * motion. + * @since 1.0 + */ + LEAP_EXPORT Vector direction() const; + + /** + * The swipe speed in mm/second. + * + * \include SwipeGesture_speed.txt + * + * @returns float The speed of the finger performing the swipe gesture in + * millimeters per second. + * @since 1.0 + */ + LEAP_EXPORT float speed() const; + + /** + * The finger performing the swipe gesture. + * + * \include SwipeGesture_pointable.txt + * + * @returns Pointable A Pointable object representing the swiping finger. + * @since 1.0 + */ + LEAP_EXPORT Pointable pointable() const; + }; + + /** + * The CircleGesture classes represents a circular finger movement. + * + * A circle movement is recognized when the tip of a finger draws a circle + * within the Leap Motion Controller field of view. + * + * \image html images/Leap_Gesture_Circle.png + * + * **Important:** To use circle gestures in your application, you must enable + * recognition of the circle gesture. You can enable recognition with: + * + * \include Gesture_Circle_Enable.txt + * + * Circle gestures are continuous. The CircleGesture objects for the gesture have + * three possible states: + * + * * State::STATE_START -- The circle gesture has just started. The movement has + * progressed far enough for the recognizer to classify it as a circle. + * * State::STATE_UPDATE -- The circle gesture is continuing. + * * State::STATE_STOP -- The circle gesture is finished. + * + * You can set the minimum radius and minimum arc length required for a movement + * to be recognized as a circle using the config attribute of a connected + * Controller object. Use the following keys to configure circle recognition: + * + * \table + * ==================================== ========== ============= ======= + * Key string Value type Default value Units + * ==================================== ========== ============= ======= + * Gesture.Circle.MinRadius float 5.0 mm + * Gesture.Circle.MinArc float 1.5 * pi radians + * ==================================== ========== ============= ======= + * \endtable + * + * The following example demonstrates how to set the circle configuration + * parameters: + * + * \include Gesture_Circle_Params.txt + * + * The Controller object must be connected to the Leap Motion service/daemon + * before setting the configuration parameters. + * + * @since 1.0 + */ + class CircleGesture : public Gesture + { + public: + /** + * The circle gesture type. + * + * \include CircleGesture_classType.txt + * + * @returns Type The type value designating a circle gesture. + * @since 1.0 + */ + static Type classType() { return TYPE_CIRCLE; } + + /** + * Constructs a new CircleGesture object. + * + * An uninitialized CircleGesture object is considered invalid. Get valid instances + * of the CircleGesture class from a Frame object. + * @since 1.0 + */ + LEAP_EXPORT CircleGesture(); + + /** + * Constructs a CircleGesture object from an instance of the Gesture class. + * + * \include CircleGesture_CircleGesture.txt + * + * @param rhs The Gesture instance to specialize. This Gesture instance must + * be a CircleGesture object. + * @since 1.0 + */ + LEAP_EXPORT CircleGesture(const Gesture& rhs); + + /** + * The center point of the circle within the Leap Motion frame of reference. + * + * \include CircleGesture_center.txt + * @returns Vector The center of the circle in mm from the Leap Motion origin. + * @since 1.0 + */ + LEAP_EXPORT Vector center() const; + + /** + * Returns the normal vector for the circle being traced. + * + * If you draw the circle clockwise, the normal vector points in the same + * general direction as the pointable object drawing the circle. If you draw + * the circle counterclockwise, the normal points back toward the + * pointable. If the angle between the normal and the pointable object + * drawing the circle is less than 90 degrees, then the circle is clockwise. + * + * \include Gesture_Circle_Direction.txt + * + * @return Vector the normal vector for the circle being traced + * @since 1.0 + */ + LEAP_EXPORT Vector normal() const; + + /** + * The number of times the finger tip has traversed the circle. + * + * Progress is reported as a positive number of the number. For example, + * a progress value of .5 indicates that the finger has gone halfway + * around, while a value of 3 indicates that the finger has gone around + * the the circle three times. + * + * \include CircleGesture_progress.txt + * + * Progress starts where the circle gesture began. Since the circle + * must be partially formed before the Leap Motion software can recognize it, progress + * will be greater than zero when a circle gesture first appears in the + * frame. + * + * @returns float A positive number indicating the gesture progress. + * @since 1.0 + */ + LEAP_EXPORT float progress() const; + + /** + * The radius of the circle. + * + * \include CircleGesture_radius.txt + * + * @returns The circle radius in mm. + * @since 1.0 + */ + LEAP_EXPORT float radius() const; + + /** + * The finger performing the circle gesture. + * + * \include CircleGesture_pointable.txt + * + * @returns Pointable A Pointable object representing the circling finger. + * @since 1.0 + */ + LEAP_EXPORT Pointable pointable() const; + }; + + /** + * The ScreenTapGesture class represents a tapping gesture by a finger or tool. + * + * A screen tap gesture is recognized when the tip of a finger pokes forward + * and then springs back to approximately the original position, as if + * tapping a vertical screen. The tapping finger must pause briefly before beginning the tap. + * + * \image html images/Leap_Gesture_Tap2.png + * + * **Important:** To use screen tap gestures in your application, you must enable + * recognition of the screen tap gesture. You can enable recognition with: + * + * \include Gesture_ScreenTap_Enable.txt + * + * ScreenTap gestures are discrete. The ScreenTapGesture object representing a tap always + * has the state, STATE_STOP. Only one ScreenTapGesture object is created for each + * screen tap gesture recognized. + * + * You can set the minimum finger movement and velocity required for a movement + * to be recognized as a screen tap as well as adjust the detection window for + * evaluating the movement using the config attribute of a connected + * Controller object. Use the following keys to configure screen tap recognition: + * + * \table + * ==================================== ========== ============= ======= + * Key string Value type Default value Units + * ==================================== ========== ============= ======= + * Gesture.ScreenTap.MinForwardVelocity float 50 mm/s + * Gesture.ScreenTap.HistorySeconds float 0.1 s + * Gesture.ScreenTap.MinDistance float 5.0 mm + * ==================================== ========== ============= ======= + * \endtable + * + * The following example demonstrates how to set the screen tap configuration + * parameters: + * + * \include Gesture_ScreenTap_Params.txt + * + * The Controller object must be connected to the Leap Motion service/daemon + * before setting the configuration parameters. + * + * @since 1.0 + */ + class ScreenTapGesture : public Gesture + { + public: + /** + * The screen tap gesture type. + * + * \include ScreenTapGesture_classType.txt + * + * @returns Type The type value designating a screen tap gesture. + * @since 1.0 + */ + static Type classType() { return TYPE_SCREEN_TAP; } + + /** + * Constructs a new ScreenTapGesture object. + * + * An uninitialized ScreenTapGesture object is considered invalid. Get valid instances + * of the ScreenTapGesture class from a Frame object. + * @since 1.0 + */ + LEAP_EXPORT ScreenTapGesture(); + + /** + * Constructs a ScreenTapGesture object from an instance of the Gesture class. + * + * \include ScreenTapGesture_ScreenTapGesture.txt + * + * @param rhs The Gesture instance to specialize. This Gesture instance must + * be a ScreenTapGesture object. + * @since 1.0 + */ + LEAP_EXPORT ScreenTapGesture(const Gesture& rhs); + + /** + * The position where the screen tap is registered. + * + * \include ScreenTapGesture_position.txt + * + * @return Vector A Vector containing the coordinates of screen tap location. + * @since 1.0 + */ + LEAP_EXPORT Vector position() const; + + /** + * The direction of finger tip motion. + * + * \include ScreenTapGesture_direction.txt + * + * @returns Vector A unit direction vector. + * @since 1.0 + */ + LEAP_EXPORT Vector direction() const; + + /** + * The progress value is always 1.0 for a screen tap gesture. + * + * @returns float The value 1.0. + * @since 1.0 + */ + LEAP_EXPORT float progress() const; + + /** + * The finger performing the screen tap gesture. + * + * \include ScreenTapGesture_pointable.txt + * + * @returns Pointable A Pointable object representing the tapping finger. + * @since 1.0 + */ + LEAP_EXPORT Pointable pointable() const; + }; + + /** + * The KeyTapGesture class represents a tapping gesture by a finger or tool. + * + * A key tap gesture is recognized when the tip of a finger rotates down toward the + * palm and then springs back to approximately the original position, as if + * tapping. The tapping finger must pause briefly before beginning the tap. + * + * \image html images/Leap_Gesture_Tap.png + * + * **Important:** To use key tap gestures in your application, you must enable + * recognition of the key tap gesture. You can enable recognition with: + * + * \include Gesture_KeyTap_Enable.txt + * + * Key tap gestures are discrete. The KeyTapGesture object representing a tap always + * has the state, STATE_STOP. Only one KeyTapGesture object is created for each + * key tap gesture recognized. + * + * You can set the minimum finger movement and velocity required for a movement + * to be recognized as a key tap as well as adjust the detection window for + * evaluating the movement using the config attribute of a connected + * Controller object. Use the following configuration keys to configure key tap + * recognition: + * + * \table + * ==================================== ========== ============= ======= + * Key string Value type Default value Units + * ==================================== ========== ============= ======= + * Gesture.KeyTap.MinDownVelocity float 50 mm/s + * Gesture.KeyTap.HistorySeconds float 0.1 s + * Gesture.KeyTap.MinDistance float 3.0 mm + * ==================================== ========== ============= ======= + * \endtable + * + * The following example demonstrates how to set the key tap configuration + * parameters: + * + * \include Gesture_KeyTap_Params.txt + * + * The Controller object must be connected to the Leap Motion service/daemon + * before setting the configuration parameters. + * + * @since 1.0 + */ + class KeyTapGesture : public Gesture + { + public: + /** + * The key tap gesture type. + * + * \include KeyTapGesture_classType.txt + * + * @returns Type The type value designating a key tap gesture. + * @since 1.0 + */ + static Type classType() { return TYPE_KEY_TAP; } + + /** + * Constructs a new KeyTapGesture object. + * + * An uninitialized KeyTapGesture object is considered invalid. Get valid instances + * of the KeyTapGesture class from a Frame object. + * @since 1.0 + */ + LEAP_EXPORT KeyTapGesture(); + + /** + * Constructs a KeyTapGesture object from an instance of the Gesture class. + * + * \include KeyTapGesture_KeyTapGesture.txt + * + * @param rhs The Gesture instance to specialize. This Gesture instance must + * be a KeyTapGesture object. + * @since 1.0 + */ + LEAP_EXPORT KeyTapGesture(const Gesture& rhs); + + /** + * The position where the key tap is registered. + * + * \include KeyTapGesture_position.txt + * + * @return Vector A Vector containing the coordinates of tap location. + * @since 1.0 + */ + LEAP_EXPORT Vector position() const; + + /** + * The direction of finger tip motion. + * + * \include KeyTapGesture_direction.txt + * + * @returns Vector A unit direction vector if the finger tip is moving; + * otherwise, a zero-vector. + * @since 1.0 + */ + LEAP_EXPORT Vector direction() const; + + /** + * The progress value is always 1.0 for a key tap gesture. + * + * @returns float The value 1.0. + * @since 1.0 + */ + LEAP_EXPORT float progress() const; + + /** + * The finger performing the key tap gesture. + * + * \include KeyTapGesture_pointable.txt + * + * @returns Pointable A Pointable object representing the tapping finger. + * @since 1.0 + */ + LEAP_EXPORT Pointable pointable() const; + }; + + /* + * Deprecated as of version 1.2. + */ + class Screen : public Interface { + public: + // For internal use only. + Screen(ScreenImplementation*); + + LEAP_EXPORT Screen(); + + LEAP_EXPORT int32_t id() const; + + LEAP_EXPORT Vector intersect(const Pointable& pointable, bool normalize, float clampRatio = 1.0f) const; + + LEAP_EXPORT Vector intersect(const Vector& position, const Vector& direction, bool normalize, float clampRatio = 1.0f) const; + + LEAP_EXPORT Vector project(const Vector& position, bool normalize, float clampRatio = 1.0f) const; + + LEAP_EXPORT Vector horizontalAxis() const; + + LEAP_EXPORT Vector verticalAxis() const; + + LEAP_EXPORT Vector bottomLeftCorner() const; + + LEAP_EXPORT Vector normal() const; + + LEAP_EXPORT int widthPixels() const; + + LEAP_EXPORT int heightPixels() const; + + LEAP_EXPORT float distanceToPoint(const Vector& point) const; + + LEAP_EXPORT bool isValid() const; + + LEAP_EXPORT static const Screen& invalid(); + + LEAP_EXPORT bool operator==(const Screen&) const; + + LEAP_EXPORT bool operator!=(const Screen&) const; + + LEAP_EXPORT friend std::ostream& operator<<(std::ostream&, const Screen&); + + std::string toString() const { + const char* cstr = toCString(); + std::string str(cstr); + deleteCString(cstr); + return str; + } + + private: + LEAP_EXPORT const char* toCString() const; + }; + + /** + * The Device class represents a physically connected device. + * + * The Device class contains information related to a particular connected + * device such as field of view, device id, and calibrated positions. + * + * Note that Device objects can be invalid, which means that they do not contain + * valid device information and do not correspond to a physical device. + * Test for validity with the Device::isValid() function. + * @since 1.0 + */ + class Device : public Interface { + public: + + /** + * The available types of Leap Motion controllers. + * @since 1.2 + */ + enum Type + { + /** + * A standalone USB peripheral. The original Leap Motion controller device. + * @since 1.2 + */ + TYPE_PERIPHERAL = 1, + TYPE_LAPTOP, + /** + * A controller embedded in a laptop computer. + * @since 1.2 + */ + TYPE_KEYBOARD + }; + + // For internal use only. + Device(DeviceImplementation*); + + /** + * Constructs a Device object. + * + * An uninitialized device is considered invalid. + * Get valid Device objects from a DeviceList object obtained using the + * Controller::devices() method. + * + * \include Device_Device.txt + * + * @since 1.0 + */ + LEAP_EXPORT Device(); + + /** + * The angle of view along the x axis of this device. + * + * \image html images/Leap_horizontalViewAngle.png + * + * The Leap Motion controller scans a region in the shape of an inverted pyramid + * centered at the device's center and extending upwards. The horizontalViewAngle + * reports the view angle along the long dimension of the device. + * + * \include Device_horizontalViewAngle.txt + * + * @returns The horizontal angle of view in radians. + * @since 1.0 + */ + LEAP_EXPORT float horizontalViewAngle() const; + + /** + * The angle of view along the z axis of this device. + * + * \image html images/Leap_verticalViewAngle.png + * + * The Leap Motion controller scans a region in the shape of an inverted pyramid + * centered at the device's center and extending upwards. The verticalViewAngle + * reports the view angle along the short dimension of the device. + * + * \include Device_verticalViewAngle.txt + * + * @returns The vertical angle of view in radians. + * @since 1.0 + */ + LEAP_EXPORT float verticalViewAngle() const; + + /** + * The maximum reliable tracking range. + * + * The range reports the maximum recommended distance from the device center + * for which tracking is expected to be reliable. This distance is not a hard limit. + * Tracking may be still be functional above this distance or begin to degrade slightly + * before this distance depending on calibration and extreme environmental conditions. + * + * \include Device_range.txt + * + * @returns The recommended maximum range of the device in mm. + * @since 1.0 + */ + LEAP_EXPORT float range() const; + + /** + * The distance to the nearest edge of the Leap Motion controller's view volume. + * + * The view volume is an axis-aligned, inverted pyramid centered on the device origin + * and extending upward to the range limit. The walls of the pyramid are described + * by the horizontalViewAngle and verticalViewAngle and the roof by the range. + * This function estimates the distance between the specified input position and the + * nearest wall or roof of the view volume. + * + * \include Device_distanceToBoundary.txt + * + * @param position The point to use for the distance calculation. + * @returns The distance in millimeters from the input position to the nearest boundary. + * @since 1.0 + */ + LEAP_EXPORT float distanceToBoundary(const Vector& position) const; + + /** + * Reports whether this device is embedded in another computer or computer + * peripheral. + * + * @returns True, if this device is embedded in a laptop, keyboard, or other computer + * component; false, if this device is a standalone controller. + * @since 1.2 + */ + LEAP_EXPORT bool isEmbedded() const; + + /** + * Reports whether this device is streaming data to your application. + * + * Currently only one controller can provide data at a time. + * @since 1.2 + */ + LEAP_EXPORT bool isStreaming() const; + + /** + * The device type. + * + * Use the device type value in the (rare) circumstances that you + * have an application feature which relies on a particular type of device. + * Current types of device include the original Leap Motion peripheral, + * keyboard-embedded controllers, and laptop-embedded controllers. + * + * @returns The physical device type as a member of the DeviceType enumeration. + * @since 1.2 + */ + LEAP_EXPORT Type type() const; + + /** + * Reports whether this is a valid Device object. + * + * \include Device_isValid.txt + * + * @returns True, if this Device object contains valid data. + * @since 1.0 + */ + LEAP_EXPORT bool isValid() const; + + /** + * Returns an invalid Device object. + * + * You can use the instance returned by this function in comparisons testing + * whether a given Device instance is valid or invalid. (You can also use the + * Device::isValid() function.) + * + * \include Device_invalid.txt + * + * @returns The invalid Device instance. + * @since 1.0 + */ + LEAP_EXPORT static const Device& invalid(); + + /** + * Compare Device object equality. + * + * \include Device_operator_equals.txt + * + * Two Device objects are equal if and only if both Device objects represent the + * exact same Device and both Devices are valid. + * @since 1.0 + */ + LEAP_EXPORT bool operator==(const Device&) const; + + /** + * Compare Device object inequality. + * + * \include Device_operator_not_equals.txt + * + * Two Device objects are equal if and only if both Device objects represent the + * exact same Device and both Devices are valid. + * @since 1.0 + */ + LEAP_EXPORT bool operator!=(const Device&) const; + + /** + * Writes a brief, human readable description of the Device object. + * + * \include Device_operator_stream.txt + * + * @since 1.0 + */ + LEAP_EXPORT friend std::ostream& operator<<(std::ostream&, const Device&); + + /** + * A string containing a brief, human readable description of the Device object. + * + * @returns A description of the Device as a string. + * @since 1.0 + */ + std::string toString() const { + const char* cstr = toCString(); + std::string str(cstr); + deleteCString(cstr); + return str; + } + + private: + LEAP_EXPORT const char* toCString() const; + }; + + // For internal use only. + template + class ConstListIterator { + public: + ConstListIterator(const L& list, int index) : m_list(list), m_index(index) {} + + const T operator*() const { return m_list[m_index]; } + void operator++(int) {++m_index;} + const ConstListIterator& operator++() { ++m_index; return *this; } + bool operator!=(const ConstListIterator& rhs) const { return m_index != rhs.m_index; } + bool operator==(const ConstListIterator& rhs) const { return m_index == rhs.m_index; } + + typedef std::ptrdiff_t difference_type; + typedef T value_type; + typedef const T* pointer; + typedef const T& reference; + typedef std::forward_iterator_tag iterator_category; + + private: + const L& m_list; + int m_index; + }; + + /** + * The PointableList class represents a list of Pointable objects. + * + * Pointable objects include entities that can be pointed, such as fingers and tools. + * + * Get a PointableList object by calling Frame::pointables() or Hand::pointables(). + * + * \include PointableList_PointableList.txt + * + * @since 1.0 + */ + class PointableList : public Interface { + public: + // For internal use only. + PointableList(const ListBaseImplementation&); + + /** + * Constructs an empty list of pointable entities. + * @since 1.0 + */ + LEAP_EXPORT PointableList(); + + /** + * Returns the number of pointable entities in this list. + * + * \include PointableList_count.txt + * + * @returns The number of pointable entities in this list. + * @since 1.0 + */ + LEAP_EXPORT int count() const; + + /** + * Reports whether the list is empty. + * + * \include PointableList_isEmpty.txt + * + * @returns True, if the list has no members. + * @since 1.0 + */ + LEAP_EXPORT bool isEmpty() const; + + /** + * Access a list member by its position in the list. + * + * \include PointableList_operator_index.txt + * + * @param index The zero-based list position index. + * @returns The Pointable object at the specified index. + * @since 1.0 + */ + LEAP_EXPORT Pointable operator[](int index) const; + + /** + * Appends the members of the specified PointableList to this PointableList. + * @param other A PointableList object containing Pointable objects + * to append to the end of this PointableList. + * @since 1.0 + */ + LEAP_EXPORT PointableList& append(const PointableList& other); + + /** + * Appends the members of the specified FingerList to this PointableList. + * @param other A FingerList object containing Finger objects + * to append to the end of this PointableList. + * @since 1.0 + */ + LEAP_EXPORT PointableList& append(const FingerList& other); + + /** + * Appends the members of the specified ToolList to this PointableList. + * @param other A ToolList object containing Tool objects + * to append to the end of this PointableList. + * @since 1.0 + */ + LEAP_EXPORT PointableList& append(const ToolList& other); + + /** + * The member of the list that is farthest to the left within the standard + * Leap Motion frame of reference (i.e has the smallest X coordinate). + * + * \include PointableList_leftmost.txt + * + * @returns The leftmost pointable, or invalid if list is empty. + * @since 1.0 + */ + LEAP_EXPORT Pointable leftmost() const; + + /** + * The member of the list that is farthest to the right within the standard + * Leap Motion frame of reference (i.e has the largest X coordinate). + * + * \include PointableList_rightmost.txt + * + * @returns The rightmost pointable, or invalid if list is empty. + * @since 1.0 + */ + LEAP_EXPORT Pointable rightmost() const; + + + /** + * The member of the list that is farthest to the front within the standard + * Leap Motion frame of reference (i.e has the smallest Z coordinate). + * + * \include PointableList_frontmost.txt + * + * @returns The frontmost pointable, or invalid if list is empty. + * @since 1.0 + */ + LEAP_EXPORT Pointable frontmost() const; + + /** + * Returns a new list containing those members of the current list that are + * extended. This includes all tools and any fingers whose isExtended() function is true. + * + * @returns The list of tools and extended fingers from the current list. + * @since 2.0 + */ + LEAP_EXPORT PointableList& extended(); + + /** + * A C++ iterator type for PointableList objects. + * + * \include PointableList_iterator.txt + * + * @since 1.0 + */ + typedef ConstListIterator const_iterator; + + /** + * The C++ iterator set to the beginning of this PointableList. + * + * \include PointableList_begin.txt + * + * @since 1.0 + */ + LEAP_EXPORT const_iterator begin() const; + + /** + * The C++ iterator set to the end of this PointableList. + * + * \include PointableList_end.txt + * + * @since 1.0 + */ + LEAP_EXPORT const_iterator end() const; + }; + + /** + * The FingerList class represents a list of Finger objects. + * + * Get a FingerList object by calling Frame::fingers(). + * + * \include FingerList_FingerList.txt + * + * @since 1.0 + */ + class FingerList : public Interface { + public: + // For internal use only. + FingerList(const ListBaseImplementation&); + + /** + * Constructs an empty list of fingers. + * @since 1.0 + */ + LEAP_EXPORT FingerList(); + + /** + * Returns the number of fingers in this list. + * + * \include FingerList_count.txt + * + * @returns The number of fingers in this list. + * @since 1.0 + */ + LEAP_EXPORT int count() const; + + /** + * Reports whether the list is empty. + * + * \include FingerList_isEmpty.txt + * + * @returns True, if the list has no members. + * @since 1.0 + */ + LEAP_EXPORT bool isEmpty() const; + + /** + * Access a list member by its position in the list. + * + * \include FingerList_index.txt + * + * @param index The zero-based list position index. + * @returns The Finger object at the specified index. + * @since 1.0 + */ + LEAP_EXPORT Finger operator[](int index) const; + + /** + * Appends the members of the specified FingerList to this FingerList. + * @param other A FingerList object containing Finger objects + * to append to the end of this FingerList. + * @since 1.0 + */ + LEAP_EXPORT FingerList& append(const FingerList& other); + + /** + * The member of the list that is farthest to the left within the standard + * Leap Motion frame of reference (i.e has the smallest X coordinate). + * + * \include FingerList_leftmost.txt + * + * @returns The leftmost finger, or invalid if list is empty. + * @since 1.0 + */ + LEAP_EXPORT Finger leftmost() const; + + /** + * The member of the list that is farthest to the right within the standard + * Leap Motion frame of reference (i.e has the largest X coordinate). + * + * \include FingerList_rightmost.txt + * + * @returns The rightmost finger, or invalid if list is empty. + * @since 1.0 + */ + LEAP_EXPORT Finger rightmost() const; + + /** + * The member of the list that is farthest to the front within the standard + * Leap Motion frame of reference (i.e has the smallest Z coordinate). + * + * \include FingerList_frontmost.txt + * + * @returns The frontmost finger, or invalid if list is empty. + * @since 1.0 + */ + LEAP_EXPORT Finger frontmost() const; + + /** + * Returns a new list containing those fingers in the current list that are + * extended. + * + * \include FingerList_extended.txt + * + * @returns The list of extended fingers from the current list. + * @since 2.0 + */ + LEAP_EXPORT FingerList& extended(); + + /** + * Returns a list containing fingers from the current list of a given finger type by + * modifying the existing list. + * + * \include FingerList_fingerType.txt + * + * @returns The list of matching fingers from the current list. + * @since 2.0 + */ + LEAP_EXPORT FingerList& fingerType(Finger::Type type); + + /** + * A C++ iterator type for FingerList objects. + * + * \include FingerList_iterator.txt + * + * @since 1.0 + */ + typedef ConstListIterator const_iterator; + + /** + * The C++ iterator set to the beginning of this FingerList. + * + * \include FingerList_begin.txt + * + * @since 1.0 + */ + LEAP_EXPORT const_iterator begin() const; + + /** + * The C++ iterator set to the end of this FingerList. + * + * \include FingerList_end.txt + * + * @since 1.0 + */ + LEAP_EXPORT const_iterator end() const; + }; + + /** + * The ToolList class represents a list of Tool objects. + * + * Get a ToolList object by calling Frame::tools() or Hand::tools(). + * + * \include ToolList_ToolList.txt + * + * @since 1.0 + */ + class ToolList : public Interface { + public: + // For internal use only. + ToolList(const ListBaseImplementation&); + + /** + * Constructs an empty list of tools. + * @since 1.0 + */ + LEAP_EXPORT ToolList(); + + /** + * Returns the number of tools in this list. + * + * \include ToolList_count.txt + * + * @returns The number of tools in this list. + * @since 1.0 + */ + LEAP_EXPORT int count() const; + + /** + * Reports whether the list is empty. + * + * \include ToolList_isEmpty.txt + * + * @returns True, if the list has no members. + * @since 1.0 + */ + LEAP_EXPORT bool isEmpty() const; + + /** + * Access a list member by its position in the list. + * + * \include ToolList_operator_index.txt + * + * @param index The zero-based list position index. + * @returns The Tool object at the specified index. + * @since 1.0 + */ + LEAP_EXPORT Tool operator[](int index) const; + + /** + * Appends the members of the specified ToolList to this ToolList. + * @param other A ToolList object containing Tool objects + * to append to the end of this ToolList. + * @since 1.0 + */ + LEAP_EXPORT ToolList& append(const ToolList& other); + + /** + * The member of the list that is farthest to the left within the standard + * Leap Motion frame of reference (i.e has the smallest X coordinate). + * + * \include ToolList_leftmost.txt + * + * @returns The leftmost tool, or invalid if list is empty. + * @since 1.0 + */ + LEAP_EXPORT Tool leftmost() const; + + /** + * The member of the list that is farthest to the right within the standard + * Leap Motion frame of reference (i.e has the largest X coordinate). + * + * \include ToolList_rightmost.txt + * + * @returns The rightmost tool, or invalid if list is empty. + * @since 1.0 + */ + LEAP_EXPORT Tool rightmost() const; + + /** + * The member of the list that is farthest to the front within the standard + * Leap Motion frame of reference (i.e has the smallest Z coordinate). + * + * \include ToolList_frontmost.txt + * + * @returns The frontmost tool, or invalid if list is empty. + * @since 1.0 + */ + LEAP_EXPORT Tool frontmost() const; + + /** + * A C++ iterator type for ToolList objects. + * + * \include ToolList_iterator.txt + * + * @since 1.0 + */ + typedef ConstListIterator const_iterator; + + /** + * The C++ iterator set to the beginning of this ToolList. + * + * \include ToolList_begin.txt + * @since 1.0 + */ + LEAP_EXPORT const_iterator begin() const; + + /** + * The C++ iterator set to the end of this ToolList. + * + * \include ToolList_end.txt + * + * @since 1.0 + */ + LEAP_EXPORT const_iterator end() const; + }; + + /** + * The HandList class represents a list of Hand objects. + * + * Get a HandList object by calling Frame::hands(). + * + * \include HandList_HandList.txt + * + * @since 1.0 + */ + class HandList : public Interface { + public: + // For internal use only. + HandList(const ListBaseImplementation&); + + /** + * Constructs an empty list of hands. + * @since 1.0 + */ + LEAP_EXPORT HandList(); + + /** + * Returns the number of hands in this list. + * + * \include HandList_count.txt + * @returns The number of hands in this list. + * @since 1.0 + */ + LEAP_EXPORT int count() const; + + /** + * Reports whether the list is empty. + * + * \include HandList_isEmpty.txt + * + * @returns True, if the list has no members. + * @since 1.0 + */ + LEAP_EXPORT bool isEmpty() const; + + /** + * Access a list member by its position in the list. + * + * \include HandList_operator_index.txt + * + * @param index The zero-based list position index. + * @returns The Hand object at the specified index. + * @since 1.0 + */ + LEAP_EXPORT Hand operator[](int index) const; + + /** + * Appends the members of the specified HandList to this HandList. + * @param other A HandList object containing Hand objects + * to append to the end of this HandList. + */ + LEAP_EXPORT HandList& append(const HandList& other); + + /** + * The member of the list that is farthest to the left within the standard + * Leap Motion frame of reference (i.e has the smallest X coordinate). + * + * Note: to determine whether a hand is the left hand, use the Hand::isLeft() function. + * + * \include HandList_leftmost.txt + * + * @returns The leftmost hand, or invalid if list is empty. + * @since 1.0 + */ + LEAP_EXPORT Hand leftmost() const; + + /** + * The member of the list that is farthest to the right within the standard + * Leap Motion frame of reference (i.e has the largest X coordinate). + * + * Note: to determine whether a hand is the right hand, use the Hand::isRight() function. + * + * \include HandList_rightmost.txt + * + * @returns The rightmost hand, or invalid if list is empty. + * @since 1.0 + */ + LEAP_EXPORT Hand rightmost() const; + + /** + * The member of the list that is farthest to the front within the standard + * Leap Motion frame of reference (i.e has the smallest Z coordinate). + * + * \include HandList_frontmost.txt + * + * @returns The frontmost hand, or invalid if list is empty. + * @since 1.0 + */ + LEAP_EXPORT Hand frontmost() const; + + /** + * A C++ iterator type for this HandList objects. + * + * \include HandList_iterator.txt + * + * @since 1.0 + */ + typedef ConstListIterator const_iterator; + + /** + * The C++ iterator set to the beginning of this HandList. + * + * \include HandList_begin.txt + * + * @since 1.0 + */ + LEAP_EXPORT const_iterator begin() const; + + /** + * The C++ iterator set to the end of this HandList. + * + * \include HandList_end.txt + * + * @since 1.0 + */ + LEAP_EXPORT const_iterator end() const; + }; + + /** + * The GestureList class represents a list of Gesture objects. + * + * Get a GestureList object from a Frame object. + * @since 1.0 + */ + class GestureList : public Interface { + public: + // For internal use only. + GestureList(const ListBaseImplementation&); + + /** + * Constructs an empty gesture list. + * @since 1.0 + */ + LEAP_EXPORT GestureList(); + + /** + * The length of this list. + * + * \include GestureList_count.txt + * + * @returns The number of gestures in this list. + * @since 1.0 + */ + LEAP_EXPORT int count() const; + + /** + * Reports whether the list is empty. + * + * \include GestureList_isEmpty.txt + * + * @returns True, if the list has no members. + * @since 1.0 + */ + LEAP_EXPORT bool isEmpty() const; + + /** + * Access a list member by its position in the list. + * + * \include GestureList_operator_index.txt + * + * @param index The zero-based list position index. + * @returns The Gesture object at the specified index. + * @since 1.0 + */ + LEAP_EXPORT Gesture operator[](int index) const; + + /** + * Appends the members of the specified GestureList to this GestureList. + * @param other A GestureList object containing Gesture objects + * to append to the end of this GestureList. + * @since 1.0 + */ + LEAP_EXPORT GestureList& append(const GestureList& other); + + /** + * A C++ iterator type for GestureList objects. + * + * \include GestureList_iterator.txt + * @since 1.0 + */ + typedef ConstListIterator const_iterator; + + /** + * The C++ iterator set to the beginning of this GestureList. + * + * \include GestureList_begin.txt + * + * @since 1.0 + */ + LEAP_EXPORT const_iterator begin() const; + + /** + * The C++ iterator set to the end of this GestureList. + * + * \include GestureList_end.txt + * + * @since 1.0 + */ + LEAP_EXPORT const_iterator end() const; + }; + + /* + * Deprecated as of version 1.2. + */ + class ScreenList : public Interface { + public: + // For internal use only. + ScreenList(const ListBaseImplementation&); + + LEAP_EXPORT ScreenList(); + + LEAP_EXPORT int count() const; + + LEAP_EXPORT bool isEmpty() const; + + LEAP_EXPORT Screen operator[](int index) const; + + typedef ConstListIterator const_iterator; + + LEAP_EXPORT const_iterator begin() const; + + LEAP_EXPORT const_iterator end() const; + + LEAP_EXPORT Screen closestScreenHit(const Pointable& pointable) const; + + LEAP_EXPORT Screen closestScreenHit(const Vector& position, const Vector& direction) const; + + LEAP_EXPORT Screen closestScreen(const Vector& position) const; + }; + + /** + * The DeviceList class represents a list of Device objects. + * + * Get a DeviceList object by calling Controller::devices(). + * @since 1.0 + */ + class DeviceList : public Interface { + public: + // For internal use only. + DeviceList(const ListBaseImplementation&); + + /** + * Constructs an empty list of devices. + * @since 1.0 + */ + LEAP_EXPORT DeviceList(); + + /** + * Returns the number of devices in this list. + * @returns The number of devices in this list. + * @since 1.0 + */ + LEAP_EXPORT int count() const; + + /** + * Reports whether the list is empty. + * + * \include DeviceList_isEmpty.txt + * + * @returns True, if the list has no members. + * @since 1.0 + */ + LEAP_EXPORT bool isEmpty() const; + + /** + * Access a list member by its position in the list. + * @param index The zero-based list position index. + * @returns The Device object at the specified index. + * @since 1.0 + */ + LEAP_EXPORT Device operator[](int index) const; + + /** + * Appends the members of the specified DeviceList to this DeviceList. + * @param other A DeviceList object containing Device objects + * to append to the end of this DeviceList. + * @since 1.0 + */ + LEAP_EXPORT DeviceList& append(const DeviceList& other); + + /** + * A C++ iterator type for this DeviceList objects. + * @since 1.0 + */ + typedef ConstListIterator const_iterator; + + /** + * The C++ iterator set to the beginning of this DeviceList. + * @since 1.0 + */ + LEAP_EXPORT const_iterator begin() const; + + /** + * The C++ iterator set to the end of this DeviceList. + * @since 1.0 + */ + LEAP_EXPORT const_iterator end() const; + }; + + /** + * The InteractionBox class represents a box-shaped region completely + * within the field of view of the Leap Motion controller. + * + * 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. + * + * \image html images/Leap_InteractionBox.png + * + * The InteractionBox region is defined by a center and dimensions along the x, y, + * and z axes. + * + * Get an InteractionBox object from a Frame object. + * @since 1.0 + */ + class InteractionBox : public Interface { + public: + // For internal use only. + InteractionBox(InteractionBoxImplementation*); + + LEAP_EXPORT InteractionBox(); + + /** + * Normalizes the coordinates of a point using the interaction box. + * + * \include InteractionBox_normalizePoint.txt + * + * 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. + * + * @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. + * @returns The normalized position. + * @since 1.0 + */ + LEAP_EXPORT Vector normalizePoint(const Vector& position, bool clamp = true) const; + + /** + * Converts a position defined by normalized InteractionBox coordinates into device + * coordinates in millimeters. + * + * \include InteractionBox_denormalizePoint.txt + * + * This function performs the inverse of normalizePoint(). + * + * @param normalizedPosition The input position in InteractionBox coordinates. + * @returns The corresponding denormalized position in device coordinates. + * @since 1.0 + */ + LEAP_EXPORT Vector denormalizePoint(const Vector& normalizedPosition) const; + + /** + * The center of the InteractionBox in device coordinates (millimeters). This point + * is equidistant from all sides of the box. + * + * \include InteractionBox_center.txt + * + * @returns The InteractionBox center in device coordinates. + * @since 1.0 + */ + LEAP_EXPORT Vector center() const; + + /** + * The width of the InteractionBox in millimeters, measured along the x-axis. + * + * \include InteractionBox_width.txt + * + * @returns The InteractionBox width in millimeters. + * @since 1.0 + */ + LEAP_EXPORT float width() const; + + /** + * The height of the InteractionBox in millimeters, measured along the y-axis. + * + * \include InteractionBox_height.txt + * + * @returns The InteractionBox height in millimeters. + * @since 1.0 + */ + LEAP_EXPORT float height() const; + + /** + * The depth of the InteractionBox in millimeters, measured along the z-axis. + * + * \include InteractionBox_depth.txt + * + * @returns The InteractionBox depth in millimeters. + * @since 1.0 + */ + LEAP_EXPORT float depth() const; + + /** + * Reports whether this is a valid InteractionBox object. + * + * \include InteractionBox_isValid.txt + * + * @returns True, if this InteractionBox object contains valid data. + * @since 1.0 + */ + LEAP_EXPORT bool isValid() const; + + /** + * Returns an invalid InteractionBox object. + * + * 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 + * InteractionBox::isValid() function.) + * + * \include InteractionBox_invalid.txt + * + * @returns The invalid InteractionBox instance. + * @since 1.0 + */ + LEAP_EXPORT static const InteractionBox& invalid(); + + /** + * Compare InteractionBox object equality. + * + * \include InteractionBox_operator_equals.txt + * + * Two InteractionBox objects are equal if and only if both InteractionBox objects represent the + * exact same InteractionBox and both InteractionBoxes are valid. + * @since 1.0 + */ + LEAP_EXPORT bool operator==(const InteractionBox&) const; + + /** + * Compare InteractionBox object inequality. + * + * \include InteractionBox_operator_not_equals.txt + * + * Two InteractionBox objects are equal if and only if both InteractionBox objects represent the + * exact same InteractionBox and both InteractionBoxes are valid. + * @since 1.0 + */ + LEAP_EXPORT bool operator!=(const InteractionBox&) const; + + /** + * Writes a brief, human readable description of the InteractionBox object. + * + * \include InteractionBox_operator_stream.txt + * + * @since 1.0 + */ + LEAP_EXPORT friend std::ostream& operator<<(std::ostream&, const InteractionBox&); + + /** + * A string containing a brief, human readable description of the InteractionBox object. + * + * @returns A description of the InteractionBox as a string. + * @since 1.0 + */ + std::string toString() const { + const char* cstr = toCString(); + std::string str(cstr); + deleteCString(cstr); + return str; + } + + private: + LEAP_EXPORT const char* toCString() const; + }; + + /** + * The Frame class represents a set of hand and finger tracking data detected + * in a single frame. + * + * The Leap Motion software detects hands, fingers and tools within the tracking area, reporting + * their positions, orientations, gestures, and motions in frames at the Leap Motion frame rate. + * + * Access Frame objects through an instance of the Controller class: + * + * \include Controller_Frame_1.txt + * + * Implement a Listener subclass to receive a callback event when a new Frame is available. + * @since 1.0 + */ + class Frame : public Interface { + public: + // For internal use only. + Frame(FrameImplementation*); + + /** + * Constructs a Frame object. + * + * Frame instances created with this constructor are invalid. + * Get valid Frame objects by calling the Controller::frame() function. + * + * \include Frame_Frame.txt + * + * @since 1.0 + */ + LEAP_EXPORT Frame(); + + /** + * A unique ID for this Frame. + * + * Consecutive frames processed by the Leap Motion software have consecutive + * increasing values. You can use the frame ID to avoid processing the same + * Frame object twice: + * + * \include Frame_Duplicate.txt + * + * As well as to make sure that your application processes every frame: + * + * \include Frame_Skipped.txt + * + * @returns The frame ID. + * @since 1.0 + */ + LEAP_EXPORT int64_t id() const; + + /** + * The frame capture time in microseconds elapsed since the Leap started. + * + * \include Frame_timestamp.txt + * + * @returns The timestamp in microseconds. + * @since 1.0 + */ + LEAP_EXPORT int64_t timestamp() const; + + /** + * The list of Hand objects detected in this frame, given in arbitrary order. + * The list can be empty if no hands are detected. + * + * \include Frame_hands.txt + * + * @returns The HandList containing all Hand objects detected in this frame. + * @since 1.0 + */ + LEAP_EXPORT HandList hands() const; + + /** + * The Hand object with the specified ID in this frame. + * + * Use the Frame::hand() function to retrieve the Hand object from + * this frame using an ID value obtained from a previous frame. + * This function always returns a Hand object, but if no hand + * with the specified ID is present, an invalid Hand object is returned. + * + * \include Frame_hand.txt + * + * Note that ID values persist across frames, but only until tracking of a + * particular object is lost. If tracking of a hand is lost and subsequently + * regained, the new Hand object representing that physical hand may have + * a different ID than that representing the physical hand in an earlier frame. + * + * @param id The ID value of a Hand object from a previous frame. + * @returns The Hand object with the matching ID if one exists in this frame; + * otherwise, an invalid Hand object is returned. + * @since 1.0 + */ + LEAP_EXPORT Hand hand(int32_t id) const; + + /** + * The list of Pointable objects (fingers and tools) detected in this frame, + * given in arbitrary order. The list can be empty if no fingers or tools are detected. + * + * Use PointableList::extended() to remove non-extended fingers from the list. + * + * \include Frame_pointables.txt + * + * @returns The PointableList containing all Pointable objects detected in this frame. + * @since 1.0 + */ + LEAP_EXPORT PointableList pointables() const; + + /** + * The Pointable object with the specified ID in this frame. + * + * Use the Frame::pointable() function to retrieve the Pointable object from + * this frame using an ID value obtained from a previous frame. + * This function always returns a Pointable object, but if no finger or tool + * with the specified ID is present, an invalid Pointable object is returned. + * + * \include Frame_pointable.txt + * + * Note that ID values persist across frames, but only until tracking of a + * particular object is lost. If tracking of a finger or tool is lost and subsequently + * regained, the new Pointable object representing that finger or tool may have + * a different ID than that representing the finger or tool in an earlier frame. + * + * @param id The ID value of a Pointable object from a previous frame. + * @returns The Pointable object with the matching ID if one exists in this frame; + * otherwise, an invalid Pointable object is returned. + * @since 1.0 + */ + LEAP_EXPORT Pointable pointable(int32_t id) const; + + /** + * The list of Finger objects detected in this frame, given in arbitrary order. + * The list can be empty if no fingers are detected. + * + * Use PointableList::extended() to remove non-extended fingers from the list. + * + * \include Frame_fingers.txt + * + * @returns The FingerList containing all Finger objects detected in this frame. + * @since 1.0 + */ + LEAP_EXPORT FingerList fingers() const; + + /** + * The Finger object with the specified ID in this frame. + * + * Use the Frame::finger() function to retrieve the Finger object from + * this frame using an ID value obtained from a previous frame. + * This function always returns a Finger object, but if no finger + * with the specified ID is present, an invalid Finger object is returned. + * + * \include Frame_finger.txt + * + * Note that ID values persist across frames, but only until tracking of a + * particular object is lost. If tracking of a finger is lost and subsequently + * regained, the new Finger object representing that physical finger may have + * a different ID than that representing the finger in an earlier frame. + * + * @param id The ID value of a Finger object from a previous frame. + * @returns The Finger object with the matching ID if one exists in this frame; + * otherwise, an invalid Finger object is returned. + * @since 1.0 + */ + LEAP_EXPORT Finger finger(int32_t id) const; + + /** + * The list of Tool objects detected in this frame, given in arbitrary order. + * The list can be empty if no tools are detected. + * + * \include Frame_tools.txt + * + * @returns The ToolList containing all Tool objects detected in this frame. + * @since 1.0 + */ + LEAP_EXPORT ToolList tools() const; + + /** + * The Tool object with the specified ID in this frame. + * + * Use the Frame::tool() function to retrieve the Tool object from + * this frame using an ID value obtained from a previous frame. + * This function always returns a Tool object, but if no tool + * with the specified ID is present, an invalid Tool object is returned. + * + * \include Frame_tool.txt + * + * Note that ID values persist across frames, but only until tracking of a + * particular object is lost. If tracking of a tool is lost and subsequently + * regained, the new Tool object representing that tool may have a + * different ID than that representing the tool in an earlier frame. + * + * @param id The ID value of a Tool object from a previous frame. + * @returns The Tool object with the matching ID if one exists in this frame; + * otherwise, an invalid Tool object is returned. + * @since 1.0 + */ + LEAP_EXPORT Tool tool(int32_t id) const; + + /** + * The Gesture object with the specified ID in this frame. + * + * Use the Frame::gesture() function to return a Gesture object in this + * frame using an ID obtained in an earlier frame. The function always + * returns a Gesture object, but if there was no update for the gesture in + * this frame, then an invalid Gesture object is returned. + * + * \include Frame_gesture.txt + * + * All Gesture objects representing the same recognized movement share the + * same ID. + * @param id The ID of an Gesture object from a previous frame. + * @returns The Gesture object in the frame with the specified ID if one + * exists; Otherwise, an Invalid Gesture object. + * @since 1.0 + */ + LEAP_EXPORT Gesture gesture(int32_t id) const; + + /** + * The gestures recognized or continuing in this frame. + * + * \include Frame_gestures_now.txt + * + * Circle and swipe gestures are updated every frame. Tap gestures + * only appear in the list for a single frame. + * + * @return GestureList the list of gestures. + * @since 1.0 + */ + LEAP_EXPORT GestureList gestures() const; + + /** + * Returns a GestureList containing all gestures that have occurred since + * the specified frame. + * + * \include Frame_gestures_since.txt + * + * @param sinceFrame An earlier Frame object. The starting frame must + * still be in the frame history cache, which has a default length of + * 60 frames. + * @return GestureList The list of the Gesture objects that have occurred + * since the specified frame. + * @since 1.0 + */ + LEAP_EXPORT GestureList gestures(const Frame& sinceFrame) const; + + /** + * The change of position derived from the overall linear motion between + * the current frame and the specified frame. + * + * The returned translation vector provides the magnitude and direction of + * the movement in millimeters. + * + * \include Frame_translation.txt + * + * The Leap Motion software derives frame translation from the linear motion of + * all objects detected in the field of view. + * + * If either this frame or sinceFrame is an invalid Frame object, then this + * method returns a zero vector. + * + * @param sinceFrame The starting frame for computing the relative translation. + * @returns A Vector representing the heuristically determined change in + * position of all objects between the current frame and that specified + * in the sinceFrame parameter. + * @since 1.0 + */ + LEAP_EXPORT Vector translation(const Frame& sinceFrame) const; + + /** + * The estimated probability that the overall motion between the current + * frame and the specified frame is intended to be a translating motion. + * + * \include Frame_translationProbability.txt + * + * If either this frame or sinceFrame is an invalid Frame object, then this + * method returns zero. + * + * @param sinceFrame The starting frame for computing the translation. + * @returns A value between 0 and 1 representing the estimated probability + * that the overall motion between the current frame and the specified frame + * is intended to be a translating motion. + * @since 1.0 + */ + LEAP_EXPORT float translationProbability(const Frame& sinceFrame) const; + + /** + * The axis of rotation derived from the overall rotational motion between + * the current frame and the specified frame. + * + * The returned direction vector is normalized. + * + * \include Frame_rotationAxis.txt + * + * The Leap Motion software derives frame rotation from the relative change in position and + * orientation of all objects detected in the field of view. + * + * If either this frame or sinceFrame is an invalid Frame object, or if no + * rotation is detected between the two frames, a zero vector is returned. + * + * @param sinceFrame The starting frame for computing the relative rotation. + * @returns A normalized direction Vector representing the axis of the + * heuristically determined rotational change between the current frame + * and that specified in the sinceFrame parameter. + * @since 1.0 + */ + LEAP_EXPORT Vector rotationAxis(const Frame& sinceFrame) const; + + /** + * The angle of rotation around the rotation axis derived from the overall + * rotational motion between the current frame and the specified frame. + * + * The returned angle is expressed in radians measured clockwise around the + * rotation axis (using the right-hand rule) between the start and end frames. + * The value is always between 0 and pi radians (0 and 180 degrees). + * + * \include Frame_rotationAngle.txt + * + * The Leap Motion software derives frame rotation from the relative change in position and + * orientation of all objects detected in the field of view. + * + * If either this frame or sinceFrame is an invalid Frame object, then the + * angle of rotation is zero. + * + * @param sinceFrame The starting frame for computing the relative rotation. + * @returns A positive value containing the heuristically determined + * rotational change between the current frame and that specified in the + * sinceFrame parameter. + * @since 1.0 + */ + LEAP_EXPORT float rotationAngle(const Frame& sinceFrame) const; + + /** + * The angle of rotation around the specified axis derived from the overall + * rotational motion between the current frame and the specified frame. + * + * The returned angle is expressed in radians measured clockwise around the + * rotation axis (using the right-hand rule) between the start and end frames. + * The value is always between -pi and pi radians (-180 and 180 degrees). + * + * \include Frame_rotationAngle_axis.txt + * + * The Leap Motion software derives frame rotation from the relative change in position and + * orientation of all objects detected in the field of view. + * + * If either this frame or sinceFrame is an invalid Frame object, then the + * angle of rotation is zero. + * + * @param sinceFrame The starting frame for computing the relative rotation. + * @param axis The axis to measure rotation around. + * @returns A value containing the heuristically determined rotational + * change between the current frame and that specified in the sinceFrame + * parameter around the given axis. + * @since 1.0 + */ + LEAP_EXPORT float rotationAngle(const Frame& sinceFrame, const Vector& axis) const; + + /** + * The transform matrix expressing the rotation derived from the overall + * rotational motion between the current frame and the specified frame. + * + * \include Frame_rotationMatrix.txt + * + * The Leap Motion software derives frame rotation from the relative change in position and + * orientation of all objects detected in the field of view. + * + * If either this frame or sinceFrame is an invalid Frame object, then this + * method returns an identity matrix. + * + * @param sinceFrame The starting frame for computing the relative rotation. + * @returns A transformation Matrix containing the heuristically determined + * rotational change between the current frame and that specified in the + * sinceFrame parameter. + * @since 1.0 + */ + LEAP_EXPORT Matrix rotationMatrix(const Frame& sinceFrame) const; + + /** + * The estimated probability that the overall motion between the current + * frame and the specified frame is intended to be a rotating motion. + * + * \include Frame_rotationProbability.txt + * + * If either this frame or sinceFrame is an invalid Frame object, then this + * method returns zero. + * + * @param sinceFrame The starting frame for computing the relative rotation. + * @returns A value between 0 and 1 representing the estimated probability + * that the overall motion between the current frame and the specified frame + * is intended to be a rotating motion. + * @since 1.0 + */ + LEAP_EXPORT float rotationProbability(const Frame& sinceFrame) const; + + /** + * The scale factor derived from the overall motion between the current frame + * and the specified frame. + * + * The scale factor is always positive. A value of 1.0 indicates no + * scaling took place. Values between 0.0 and 1.0 indicate contraction + * and values greater than 1.0 indicate expansion. + * + * \include Frame_scaleFactor.txt + * + * The Leap Motion software derives scaling from the relative inward or outward motion of + * all objects detected in the field of view (independent of translation + * and rotation). + * + * If either this frame or sinceFrame is an invalid Frame object, then this + * method returns 1.0. + * + * @param sinceFrame The starting frame for computing the relative scaling. + * @returns A positive value representing the heuristically determined + * scaling change ratio between the current frame and that specified in the + * sinceFrame parameter. + * @since 1.0 + */ + LEAP_EXPORT float scaleFactor(const Frame& sinceFrame) const; + + /** + * The estimated probability that the overall motion between the current + * frame and the specified frame is intended to be a scaling motion. + * + * \include Frame_scaleProbability.txt + * + * If either this frame or sinceFrame is an invalid Frame object, then this + * method returns zero. + * + * @param sinceFrame The starting frame for computing the relative scaling. + * @returns A value between 0 and 1 representing the estimated probability + * that the overall motion between the current frame and the specified frame + * is intended to be a scaling motion. + * @since 1.0 + */ + LEAP_EXPORT float scaleProbability(const Frame& sinceFrame) const; + + /** + * The current InteractionBox for the frame. See the InteractionBox class + * documentation for more details on how this class should be used. + * + * \include Frame_interactionBox.txt + * + * @returns The current InteractionBox object. + * @since 1.0 + */ + LEAP_EXPORT InteractionBox interactionBox() const; + + /** + * The instantaneous framerate. + * + * The rate at which the Leap Motion software is providing frames of data + * (in frames per second). The framerate can fluctuate depending on available computing + * resources, activity within the device field of view, software tracking settings, + * and other factors. + * + * \include Frame_currentFramesPerSecond.txt + * + * @returns An estimate of frames per second of the Leap Motion Controller. + * @since 1.0 + */ + LEAP_EXPORT float currentFramesPerSecond() const; + + /** + * Reports whether this Frame instance is valid. + * + * A valid Frame is one generated by the Leap::Controller object that contains + * tracking data for all detected entities. An invalid Frame contains no + * actual tracking data, but you can call its functions without risk of a + * null pointer exception. The invalid Frame mechanism makes it more + * convenient to track individual data across the frame history. For example, + * you can invoke: + * + * \include Frame_Valid_Chain.txt + * + * for an arbitrary Frame history value, "n", without first checking whether + * frame(n) returned a null object. (You should still check that the + * returned Finger instance is valid.) + * + * @returns True, if this is a valid Frame object; false otherwise. + * @since 1.0 + */ + LEAP_EXPORT bool isValid() const; + + /** + * Returns an invalid Frame object. + * + * You can use the instance returned by this function in comparisons testing + * whether a given Frame instance is valid or invalid. (You can also use the + * Frame::isValid() function.) + * + * \include Frame_Invalid_Demo.txt + * + * @returns The invalid Frame instance. + * @since 1.0 + */ + LEAP_EXPORT static const Frame& invalid(); + + /** + * Compare Frame object equality. + * + * \include Frame_operator_equals.txt + * + * Two Frame objects are equal if and only if both Frame objects represent + * the exact same frame of tracking data and both Frame objects are valid. + * @since 1.0 + */ + LEAP_EXPORT bool operator==(const Frame&) const; + + /** + * Compare Frame object inequality. + * + * \include Frame_operator_not_equals.txt + * + * Two Frame objects are equal if and only if both Frame objects represent + * the exact same frame of tracking data and both Frame objects are valid. + * @since 1.0 + */ + LEAP_EXPORT bool operator!=(const Frame&) const; + + /** + * Writes a brief, human readable description of the Frame object to an output stream. + * + * \include Frame_operator_stream.txt + * + * @since 1.0 + */ + LEAP_EXPORT friend std::ostream& operator<<(std::ostream&, const Frame&); + + /** + * A string containing a brief, human readable description of the Frame object. + * + * @returns A description of the Frame as a string. + * @since 1.0 + */ + std::string toString() const { + const char* cstr = toCString(); + std::string str(cstr); + deleteCString(cstr); + return str; + } + + private: + LEAP_EXPORT const char* toCString() const; + }; + + /** + * The Config class provides access to Leap Motion system configuration information. + * + * You can get and set gesture configuration parameters using the Config object + * obtained from a connected Controller object. The key strings required to + * identify a configuration parameter include: + * + * \table + * ==================================== ========== ============= ======= + * Key string Value type Default value Units + * ==================================== ========== ============= ======= + * Gesture.Circle.MinRadius float 5.0 mm + * Gesture.Circle.MinArc float 1.5 * pi radians + * Gesture.Swipe.MinLength float 150 mm + * Gesture.Swipe.MinVelocity float 1000 mm/s + * Gesture.KeyTap.MinDownVelocity float 50 mm/s + * Gesture.KeyTap.HistorySeconds float 0.1 s + * Gesture.KeyTap.MinDistance float 3.0 mm + * Gesture.ScreenTap.MinForwardVelocity float 50 mm/s + * Gesture.ScreenTap.HistorySeconds float 0.1 s + * Gesture.ScreenTap.MinDistance float 5.0 mm + * ==================================== ========== ============= ======= + * \endtable + * + * After setting a configuration value, you must call the Config::save() method + * to commit the changes. You can save after the Controller has connected to + * the Leap Motion service/daemon. In other words, after the Controller + * has dispatched the serviceConnected or connected events or + * Controller::isConnected is true. The configuration value changes are + * not persistent; your application needs to set the values every time it runs. + * + * @see CircleGesture + * @see KeyTapGesture + * @see ScreenTapGesture + * @see SwipeGesture + * @since 1.0 + */ + class Config : public Interface { + public: + /** + * Constructs a Config object. + * Do not create your own Config objects. Get a Config object using + * the Controller::config() function. + * + * \include Config_Constructor.txt + * + * @since 1.0 + */ + LEAP_EXPORT Config(); + + /** + * Enumerates the possible data types for configuration values. + * + * The Config::type() function returns an item from the ValueType enumeration. + * @since 1.0 + */ + enum ValueType { + /** + * The data type is unknown. + * @since 1.0 + */ + TYPE_UNKNOWN = 0, + /** + * A boolean value. + * @since 1.0 + */ + TYPE_BOOLEAN = 1, + /** + * A 32-bit integer. + * @since 1.0 + */ + TYPE_INT32 = 2, + /** + * A floating-point number. + * @since 1.0 + */ + TYPE_FLOAT = 6, + /** + * A string of characters. + * @since 1.0 + */ + TYPE_STRING = 8, +#ifdef SWIGCSHARP + // deprecated + TYPEUNKNOWN = TYPE_UNKNOWN, + TYPEBOOLEAN = TYPE_BOOLEAN, + TYPEINT32 = TYPE_INT32, + TYPEFLOAT = TYPE_FLOAT, + TYPESTRING = TYPE_STRING, +#endif + }; + + /** + * Reports the natural data type for the value related to the specified key. + * + * \include Config_type.txt + * + * @param key The key for the looking up the value in the configuration dictionary. + * @returns The native data type of the value, that is, the type that does not + * require a data conversion. + * @since 1.0 + */ + ValueType type(const std::string& key) const { + return typeCString(key.c_str()); + } + + /** + * Gets the boolean representation for the specified key. + * + * \include Config_getBool.txt + * + * @since 1.0 + */ + bool getBool(const std::string& key) const { + return getBoolCString(key.c_str()); + } + + /** Sets the boolean representation for the specified key. + * + * \include Config_setBool.txt + * + * @returns true on success, false on failure. + * @since 1.0 + */ + bool setBool(const std::string& key, bool value) { + return setBoolCString(key.c_str(), value); + } + + /** + * Gets the 32-bit integer representation for the specified key. + * + * \include Config_getInt32.txt + * + * @since 1.0 + */ + int32_t getInt32(const std::string& key) const { + return getInt32CString(key.c_str()); + } + + /** Sets the 32-bit integer representation for the specified key. + * + * \include Config_setInt32.txt + * + * @returns true on success, false on failure. + * @since 1.0 + */ + bool setInt32(const std::string& key, int32_t value) { + return setInt32CString(key.c_str(), value); + } + + /** + * Gets the floating point representation for the specified key. + * + * \include Config_getFloat.txt + * + * @since 1.0 + */ + float getFloat(const std::string& key) const { + return getFloatCString(key.c_str()); + } + + /** Sets the floating point representation for the specified key. + * + * \include Config_setFloat.txt + * + * @returns true on success, false on failure. + * @since 1.0 + */ + bool setFloat(const std::string& key, float value) { + return setFloatCString(key.c_str(), value); + } + + /** + * Gets the string representation for the specified key. + * + * \include Config_getString.txt + * + * @since 1.0 + */ + std::string getString(const std::string& key) const { + const char* cstr = getStringCString(key.c_str()); + std::string str(cstr); + deleteCString(cstr); + return str; + } + + /** Sets the string representation for the specified key. + * + * \include Config_setString.txt + * + * @returns true on success, false on failure. + * @since 1.0 + */ + bool setString(const std::string& key, const std::string& value) { + return setStringCString(key.c_str(), value.c_str()); + } + + /** + * Saves the current state of the config. + * + * Call ``save()`` after making a set of configuration changes. The + * ``save()`` function transfers the configuration changes to the Leap Motion + * service. You can save after the Controller has connected to + * the Leap Motion service/daemon. In other words, after the Controller + * has dispatched the serviceConnected or connected events or + * Controller::isConnected is true. The configuration value changes are not persistent; your + * application must set the values every time it runs. + * + * \include Config_save.txt + * + * @returns true on success, false on failure. + * @since 1.0 + */ + LEAP_EXPORT bool save(); + private: + LEAP_EXPORT ValueType typeCString(const char* key) const; + LEAP_EXPORT bool getBoolCString(const char* key) const; + LEAP_EXPORT bool setBoolCString(const char* key, bool value); + LEAP_EXPORT int32_t getInt32CString(const char* key) const; + LEAP_EXPORT bool setInt32CString(const char* key, int32_t value); + LEAP_EXPORT float getFloatCString(const char* key) const; + LEAP_EXPORT bool setFloatCString(const char* key, float value); + LEAP_EXPORT const char* getStringCString(const char* key) const; + LEAP_EXPORT bool setStringCString(const char* key, const char* value); + }; + + /** + * The Controller class is your main interface to the Leap Motion Controller. + * + * 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 Controller::frame() function. Call frame() or frame(0) 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. + * + * Polling is an appropriate strategy for applications which already have an + * intrinsic update loop, such as a game. You can also add an instance of a + * subclass of Leap::Listener to the controller to handle events as they occur. + * The Controller dispatches events to the listener upon initialization and exiting, + * on connection changes, when the application gains and loses the OS input focus, + * and when a new frame of tracking data is available. + * When these events occur, the controller object invokes the appropriate + * callback function defined in your subclass of Listener. + * + * To access frames of tracking data as they become available: + * + * 1. Implement a subclass of the Listener class and override the + * Listener::onFrame() function. + * 2. In your Listener::onFrame() function, call the Controller::frame() + * function to access the newest frame of tracking data. + * 3. To start receiving frames, create a Controller object and add an instance + * of the Listener subclass to the Controller::addListener() function. + * + * When an instance of a Listener subclass is added to a Controller object, + * it calls the Listener::onInit() function when the listener is ready for use. + * When a connection is established between the controller and the Leap Motion software, + * the controller calls the Listener::onConnect() function. At this point, your + * application will start receiving frames of data. The controller calls the + * Listener::onFrame() function each time a new frame is available. If the + * controller loses its connection with the Leap Motion software or device for any + * reason, it calls the Listener::onDisconnect() function. If the listener is + * removed from the controller or the controller is destroyed, it calls the + * Listener::onExit() function. At that point, unless the listener is added to + * another controller again, it will no longer receive frames of tracking data. + * + * The Controller object is multithreaded and calls the Listener functions on + * its own thread, not on an application thread. + * @since 1.0 + */ + class Controller : public Interface { + public: + // For internal use only. + Controller(ControllerImplementation*); + + /** + * Constructs a Controller object. + * + * When creating a Controller object, you may optionally pass in a + * reference to an instance of a subclass of Leap::Listener. Alternatively, + * you may add a listener using the Controller::addListener() function. + * + * @since 1.0 + */ + LEAP_EXPORT Controller(); + LEAP_EXPORT virtual ~Controller(); + /** + * Constructs a Controller object. + * + * When creating a Controller object, you may optionally pass in a + * reference to an instance of a subclass of Leap::Listener. Alternatively, + * you may add a listener using the Controller::addListener() function. + * + * \include Controller_Controller.txt + * + * @param listener An instance of Leap::Listener implementing the callback + * functions for the Leap Motion events you want to handle in your application. + * @since 1.0 + */ + LEAP_EXPORT Controller(Listener& listener); + + /** + * Reports whether this Controller is connected to the Leap Motion service and + * the Leap Motion hardware is plugged in. + * + * When you first create a Controller object, isConnected() returns false. + * After the controller finishes initializing and connects to the Leap Motion + * software and if the Leap Motion hardware is plugged in, isConnected() returns true. + * + * You can either handle the onConnect event using a Listener instance or + * poll the isConnected() function if you need to wait for your + * application to be connected to the Leap Motion software before performing some other + * operation. + * + * \include Controller_isConnected.txt + * @returns True, if connected; false otherwise. + * @since 1.0 + */ + LEAP_EXPORT bool isConnected() const; + + /** + * Reports whether your application has a connection to the Leap Motion + * daemon/service. Can be true even if the Leap Motion hardware is not available. + * @since 1.2 + */ + LEAP_EXPORT bool isServiceConnected() const; + + /** + * Reports whether this application is the focused, foreground application. + * + * By default, your application only receives tracking information from + * the Leap Motion controller when it has the operating system input focus. + * To receive tracking data when your application is in the background, + * the background frames policy flag must be set. + * + * \include Controller_hasFocus.txt + * + * @returns True, if application has focus; false otherwise. + * + * @see Controller::setPolicyFlags() + * @since 1.0 + */ + LEAP_EXPORT bool hasFocus() const; + + /** + * The supported controller policies. + * + * Currently, the only supported policy is the background frames policy, + * which determines whether your application receives frames of tracking + * data when it is not the focused, foreground application. + * @since 1.0 + */ + enum PolicyFlag { + /** + * The default policy. + * @since 1.0 + */ + POLICY_DEFAULT = 0, + /** + * Receive background frames. + * @since 1.0 + */ + POLICY_BACKGROUND_FRAMES = (1 << 0), +#ifdef SWIGCSHARP + // deprecated + POLICYDEFAULT = POLICY_DEFAULT, + POLICYBACKGROUNDFRAMES = POLICY_BACKGROUND_FRAMES, +#endif + }; + + /** + * Gets the active policy settings. + * + * Use this function to determine the current policy state. + * Keep in mind that setting a policy flag is asynchronous, so changes are + * not effective immediately after calling setPolicyFlag(). In addition, a + * policy request can be declined by the user. You should always set the + * policy flags required by your application at startup and check that the + * policy change request was successful after an appropriate interval. + * + * If the controller object is not connected to the Leap Motion software, then the default + * policy state is returned. + * + * \include Controller_policyFlags.txt + * + * @returns The current policy flags. + * @since 1.0 + */ + LEAP_EXPORT PolicyFlag policyFlags() const; + + /** + * Requests a change in policy. + * + * A request to change a policy is subject to user approval and a policy + * can be changed by the user at any time (using the Leap Motion settings dialog). + * The desired policy flags must be set every time an application runs. + * + * Policy changes are completed asynchronously and, because they are subject + * to user approval, may not complete successfully. Call + * Controller::policyFlags() after a suitable interval to test whether + * the change was accepted. + * + * Currently, the background frames policy is the only policy supported. + * The background frames policy determines whether an application + * receives frames of tracking data while in the background. By + * default, the Leap Motion software only sends tracking data to the foreground application. + * Only applications that need this ability should request the background + * frames policy. + * + * At this time, you can use the Leap Motion Settings dialog to + * globally enable or disable the background frames policy. However, + * each application that needs tracking data while in the background + * must also set the policy flag using this function. + * + * This function can be called before the Controller object is connected, + * but the request will be sent to the Leap Motion software after the Controller connects. + * + * \include Controller_setPolicyFlags.txt + * + * @param flags A PolicyFlag value indicating the policies to request. + * @since 1.0 + */ + LEAP_EXPORT void setPolicyFlags(PolicyFlag flags) const; + + /** + * Adds a listener to this Controller. + * + * The Controller dispatches Leap Motion events to each associated listener. The + * order in which listener callback functions are invoked is arbitrary. If + * you pass a listener to the Controller's constructor function, it is + * automatically added to the list and can be removed with the + * Controller::removeListener() function. + * + * \include Controller_addListener.txt + * + * @param listener A subclass of Leap::Listener implementing the callback + * functions for the Leap Motion events you want to handle in your application. + * @returns Whether or not the listener was successfully added to the list + * of listeners. + * @since 1.0 + */ + LEAP_EXPORT bool addListener(Listener& listener); + + /** + * Remove a listener from the list of listeners that will receive Leap Motion + * events. A listener must be removed if its lifetime is shorter than the + * controller to which it is listening. + * + * \include Controller_removeListener.txt + * + * @param listener The listener to remove. + * @returns Whether or not the listener was successfully removed from the + * list of listeners. + * @since 1.0 + */ + LEAP_EXPORT bool removeListener(Listener& listener); + + /** + * Returns a frame of tracking data from the Leap Motion software. Use the optional + * history parameter to specify which frame to retrieve. Call frame() or + * frame(0) to access the most recent frame; call frame(1) 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. + * + * \include Controller_Frame_1.txt + * + * You can call this function in your Listener implementation to get frames at the + * Leap Motion frame rate: + * + * \include Controller_Listener_onFrame.txt + + * @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). + * @returns 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. + * @since 1.0 + */ + LEAP_EXPORT Frame frame(int history = 0) const; + + /** + * Returns a Config object, which you can use to query the Leap Motion system for + * configuration information. + * + * \include Controller_config.txt + * + * @returns The Controller's Config object. + * @since 1.0 + */ + LEAP_EXPORT Config config() const; + + /** + * The list of currently attached and recognized Leap Motion controller devices. + * + * The Device objects in the list describe information such as the range and + * tracking volume. + * + * \include Controller_devices.txt + * + * Currently, the Leap Motion Controller only allows a single active device at a time, + * however there may be multiple devices physically attached and listed here. Any active + * device(s) are guaranteed to be listed first, however order is not determined beyond that. + * + * @returns The list of Leap Motion controllers. + * @since 1.0 + */ + LEAP_EXPORT DeviceList devices() const; + + /* + * Deprecated as of version 1.2. + */ + LEAP_EXPORT ScreenList locatedScreens() const; + + /** + * Enables or disables reporting of a specified gesture type. + * + * 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. + * + * \include Controller_enableGesture.txt + * + * As a performance optimization, only enable recognition for the types + * of movements that you use in your application. + * + * @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. + * @see Controller::isGestureEnabled() + * @since 1.0 + */ + LEAP_EXPORT void enableGesture(Gesture::Type type, bool enable = true) const; + + /** + * Reports whether the specified gesture type is enabled. + * + * \include Controller_isGestureEnabled.txt + * + * @param type The type of gesture to check; a member of the Gesture::Type enumeration. + * @returns True, if the specified type is enabled; false, otherwise. + * @see Controller::enableGesture() + * @since 1.0 + */ + LEAP_EXPORT bool isGestureEnabled(Gesture::Type type) const; + }; + + /** + * The Listener class defines a set of callback functions that you can + * override in a subclass to respond to events dispatched by the Controller object. + * + * To handle Leap Motion events, create an instance of a Listener subclass and assign + * it to the Controller instance. The Controller calls the relevant Listener + * callback function when an event occurs, passing in a reference to itself. + * You do not have to implement callbacks for events you do not want to handle. + * + * The Controller object calls these Listener functions from a thread created + * by the Leap Motion library, not the thread used to create or set the Listener instance. + * @since 1.0 + */ + class Listener { + public: + /** + * Constructs a Listener object. + * @since 1.0 + */ + LEAP_EXPORT Listener() {} + + /** + * Destroys this Listener object. + */ + LEAP_EXPORT virtual ~Listener() {} + + /** + * Called once, when this Listener object is newly added to a Controller. + * + * \include Listener_onInit.txt + * + * @param controller The Controller object invoking this callback function. + * @since 1.0 + */ + LEAP_EXPORT virtual void onInit(const Controller&) {} + + /** + * Called when the Controller object connects to the Leap Motion software and + * the Leap Motion hardware device is plugged in, + * or when this Listener object is added to a Controller that is already connected. + * + * When this callback is invoked, Controller::isServiceConnected is true, + * Controller::devices() is not empty, and, for at least one of the Device objects in the list, + * Device::isStreaming() is true. + * + * \include Listener_onConnect.txt + * + * @param controller The Controller object invoking this callback function. + * @since 1.0 + */ + LEAP_EXPORT virtual void onConnect(const Controller&) {} + + /** + * Called when the Controller object disconnects from the Leap Motion software or + * the Leap Motion hardware is unplugged. + * The controller can disconnect when the Leap Motion device is unplugged, the + * user shuts the Leap Motion software down, or the Leap Motion software encounters an + * unrecoverable error. + * + * \include Listener_onDisconnect.txt + * + * Note: When you launch a Leap-enabled application in a debugger, the + * Leap Motion library does not disconnect from the application. This is to allow + * you to step through code without losing the connection because of time outs. + * + * @param controller The Controller object invoking this callback function. + * @since 1.0 + */ + LEAP_EXPORT virtual void onDisconnect(const Controller&) {} + + /** + * Called when this Listener object is removed from the Controller + * or the Controller instance is destroyed. + * + * \include Listener_onExit.txt + * + * @param controller The Controller object invoking this callback function. + * @since 1.0 + */ + LEAP_EXPORT virtual void onExit(const Controller&) {} + + /** + * Called when a new frame of hand and finger tracking data is available. + * Access the new frame data using the Controller::frame() function. + * + * \include Listener_onFrame.txt + * + * Note, the Controller skips any pending onFrame events while your + * onFrame handler executes. If your implementation takes too long to return, + * one or more frames can be skipped. The Controller still inserts the skipped + * frames into the frame history. You can access recent frames by setting + * the history parameter when calling the Controller::frame() function. + * You can determine if any pending onFrame events were skipped by comparing + * the ID of the most recent frame with the ID of the last received frame. + * + * @param controller The Controller object invoking this callback function. + * @since 1.0 + */ + LEAP_EXPORT virtual void onFrame(const Controller&) {} + + /** + * Called when this application becomes the foreground application. + * + * Only the foreground application receives tracking data from the Leap + * Motion Controller. This function is only called when the controller + * object is in a connected state. + * + * \include Listener_onFocusGained.txt + * + * @param controller The Controller object invoking this callback function. + * @since 1.0 + */ + LEAP_EXPORT virtual void onFocusGained(const Controller&) {} + + /** + * Called when this application loses the foreground focus. + * + * Only the foreground application receives tracking data from the Leap + * Motion Controller. This function is only called when the controller + * object is in a connected state. + * + * \include Listener_onFocusLost.txt + * + * @param controller The Controller object invoking this callback function. + * @since 1.0 + */ + LEAP_EXPORT virtual void onFocusLost(const Controller&) {} + + // onServiceConnect/onServiceDisconnect are for connection established/lost. + // in normal course of events onServiceConnect will get called once after onInit + // and onServiceDisconnect will not get called. disconnect notification only happens + // if service stops running or something else bad happens to disconnect controller from service. + /** + * Called when the Leap Motion daemon/service connects to your application Controller. + * + * @param controller The Controller object invoking this callback function. + * @since 1.2 + */ + LEAP_EXPORT virtual void onServiceConnect(const Controller&) {} + /** + * Called if the Leap Motion daemon/service disconnects from your application Controller. + * + * Normally, this callback is not invoked. It is only called if some external event + * or problem shuts down the service or otherwise interrupts the connection. + * + * @param controller The Controller object invoking this callback function. + * @since 1.2 + */ + LEAP_EXPORT virtual void onServiceDisconnect(const Controller&) {} + + /** + * Called when a Leap Motion controller plugged in, unplugged, or the device changes state. + * + * State changes include changes in frame rate and entering or leaving "robust" mode. + * Note that there is currently no way to query whether a device is in robust mode. + * You can use Frame::currentFramerate() to get the framerate. + * + * @param controller The Controller object invoking this callback function. + * @since 1.2 + */ + LEAP_EXPORT virtual void onDeviceChange(const Controller&) {} + }; +} + +#endif // __Leap_h__ diff --git a/interface/external/leapmotion/include/Leap.i b/interface/external/leapmotion/include/Leap.i new file mode 100644 index 0000000000..d0a39d8ed1 --- /dev/null +++ b/interface/external/leapmotion/include/Leap.i @@ -0,0 +1,787 @@ +################################################################################ +# 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. # +################################################################################ + +# usage: +# swig -c++ -python -o LeapPython.cpp -interface LeapPython Leap.i +# swig -c++ -java -o LeapJava.cpp -package com.leapmotion.leap -outdir com/leapmotion/leap Leap.i +# swig -c++ -csharp -o LeapCSharp.cpp -dllimport LeapCSharp -namespace Leap Leap.i + +%module(directors="1", threads="1") Leap +#pragma SWIG nowarn=325 + +%include "std_string.i" +%include "std_vector.i" +%include "stdint.i" +%include "attribute.i" + +################################################################################ +# Ignore constructors for internal use only # +################################################################################ + +%ignore Leap::Pointable::Pointable(PointableImplementation*); +%ignore Leap::Pointable::Pointable(FingerImplementation*); +%ignore Leap::Pointable::Pointable(ToolImplementation*); +%ignore Leap::Finger::Finger(FingerImplementation*); +%ignore Leap::Tool::Tool(ToolImplementation*); +%ignore Leap::Bone::Bone(BoneImplementation*); +%ignore Leap::Hand::Hand(HandImplementation*); +%ignore Leap::Gesture::Gesture(GestureImplementation*); +%ignore Leap::Screen::Screen(ScreenImplementation*); +%ignore Leap::Frame::Frame(FrameImplementation*); +%ignore Leap::Controller::Controller(ControllerImplementation*); +%ignore Leap::Device::Device(DeviceImplementation*); +%ignore Leap::InteractionBox::InteractionBox(InteractionBoxImplementation*); + +##################################################################################### +# Set Attributes (done after functions are uppercased, but before vars are lowered) # +##################################################################################### +#TODO: If possible, figure out how to auomatically make any C++ function +# that is const and takes no arguments be defined as a property in C# + +%define %constattrib( Class, Type, Name ) + %attribute( Class, Type, Name, Name ) +%enddef + +%define %staticattrib(Class, AttributeType, AttributeName) + %ignore Class::AttributeName(); + %ignore Class::AttributeName() const; + %immutable Class::AttributeName; + %extend Class { + AttributeType AttributeName; + } + %{ + #define %mangle(Class) ##_## AttributeName ## _get() Class::AttributeName() + %} +%enddef + +%define %leapattrib( Class, Type, Name ) + %attributeval(Class, Leap::Type, Name, Name) +%enddef + +#if SWIGCSHARP || SWIGPYTHON + +%rename(GestureType) Leap::Gesture::Type; +%rename(GestureState) Leap::Gesture::State; +%rename(FingerJoint) Leap::Finger::Joint; +%rename(FingerType) Leap::Finger::Type; +%rename(BoneType) Leap::Bone::Type; +%rename(DeviceType) Leap::Device::Type; + +#endif + +# Apply language specific caseing +#if SWIGCSHARP + +%rename("%(camelcase)s", %$not %$isenumitem) ""; + +#elif SWIGPYTHON + +%typemap(varout, noblock=1) SWIGTYPE & { + %set_varoutput(SWIG_NewPointerObj(%as_voidptr(&$1()), $descriptor, %newpointer_flags)); +} + +%rename("%(undercase)s", notregexmatch$name="^[A-Z0-9_]+$") ""; + +#endif + +#if SWIGCSHARP || SWIGPYTHON + +%constattrib( Leap::Pointable, int, id ); +%leapattrib( Leap::Pointable, Hand, hand ); +%leapattrib( Leap::Pointable, Vector, tipPosition ); +%leapattrib( Leap::Pointable, Vector, tipVelocity ); +%leapattrib( Leap::Pointable, Vector, direction ); +%constattrib( Leap::Pointable, float, width ); +%constattrib( Leap::Pointable, float, length ); +%constattrib( Leap::Pointable, bool, isTool ); +%constattrib( Leap::Pointable, bool, isFinger ); +%constattrib( Leap::Pointable, bool, isExtended ); +%constattrib( Leap::Pointable, bool, isValid ); +%constattrib( Leap::Pointable, Leap::Pointable::Zone, touchZone ) +%constattrib( Leap::Pointable, float, touchDistance ) +%leapattrib( Leap::Pointable, Vector, stabilizedTipPosition ) +%constattrib( Leap::Pointable, float, timeVisible ); +%leapattrib( Leap::Pointable, Frame, frame ); + +%leapattrib( Leap::Bone, Vector, prevJoint ); +%leapattrib( Leap::Bone, Vector, nextJoint ); +%leapattrib( Leap::Bone, Vector, center ); +%leapattrib( Leap::Bone, Vector, direction ); +%constattrib( Leap::Bone, float, length ); +%constattrib( Leap::Bone, float, width ); +%constattrib( Leap::Bone, Leap::Bone::Type, type ) +%leapattrib( Leap::Bone, Matrix, basis ) +%constattrib( Leap::Bone, bool, isValid ); + +%constattrib( Leap::Hand, int, id ); +%leapattrib( Leap::Hand, PointableList, pointables ); +%leapattrib( Leap::Hand, FingerList, fingers ); +%leapattrib( Leap::Hand, ToolList, tools ); +%leapattrib( Leap::Hand, Vector, palmPosition ); +%leapattrib( Leap::Hand, Vector, palmVelocity ); +%leapattrib( Leap::Hand, Vector, palmNormal ); +%leapattrib( Leap::Hand, Vector, direction ); +%leapattrib( Leap::Hand, Matrix, basis ) +%constattrib( Leap::Hand, bool, isValid ); +%leapattrib( Leap::Hand, Vector, sphereCenter ); +%constattrib( Leap::Hand, float, sphereRadius ); +%constattrib( Leap::Hand, float, grabStrength ); +%constattrib( Leap::Hand, float, pinchStrength ); +%constattrib( Leap::Hand, float, palmWidth ); +%leapattrib( Leap::Hand, Vector, stabilizedPalmPosition ) +%constattrib( Leap::Hand, float, timeVisible ); +%constattrib( Leap::Hand, float, confidence ); +%constattrib( Leap::Hand, bool, isLeft ); +%constattrib( Leap::Hand, bool, isRight ); +%leapattrib( Leap::Hand, Frame, frame ); + +%constattrib( Leap::Gesture, Leap::Gesture::Type, type ) +%constattrib( Leap::Gesture, Leap::Gesture::State, state ) +%constattrib( Leap::Gesture, int32_t, id ); +%constattrib( Leap::Gesture, int64_t, duration ); +%constattrib( Leap::Gesture, float, durationSeconds ); +%leapattrib( Leap::Gesture, Frame, frame ); +%leapattrib( Leap::Gesture, HandList, hands ); +%leapattrib( Leap::Gesture, PointableList, pointables ); +%constattrib( Leap::Gesture, bool, isValid ); +%leapattrib( Leap::CircleGesture, Vector, center ); +%leapattrib( Leap::CircleGesture, Vector, normal ); +%constattrib( Leap::CircleGesture, float, progress ); +%constattrib( Leap::CircleGesture, float, radius ); +%leapattrib( Leap::CircleGesture, Pointable, pointable ); +%leapattrib( Leap::SwipeGesture, Vector, startPosition ); +%leapattrib( Leap::SwipeGesture, Vector, position ); +%leapattrib( Leap::SwipeGesture, Vector, direction ); +%constattrib( Leap::SwipeGesture, float, speed ); +%leapattrib( Leap::SwipeGesture, Pointable, pointable ); +%leapattrib( Leap::ScreenTapGesture, Vector, position ); +%leapattrib( Leap::ScreenTapGesture, Vector, direction ); +%constattrib( Leap::ScreenTapGesture, float, progress ); +%leapattrib( Leap::ScreenTapGesture, Pointable, pointable ); +%leapattrib( Leap::KeyTapGesture, Vector, position ); +%leapattrib( Leap::KeyTapGesture, Vector, direction ); +%constattrib( Leap::KeyTapGesture, float, progress ); +%leapattrib( Leap::KeyTapGesture, Pointable, pointable ); + +# Count is made a const attribute in C# but renamed to __len__ in Python +#if SWIGCSHARP +%constattrib( Leap::PointableList, int, count ); +%constattrib( Leap::FingerList, int, count ); +%constattrib( Leap::ToolList, int, count ); +%constattrib( Leap::HandList, int, count ); +%constattrib( Leap::GestureList, int, count ); +%constattrib( Leap::ScreenList, int, count ); +%constattrib( Leap::DeviceList, int, count ); +#endif + +%constattrib( Leap::PointableList, bool, isEmpty ); +%constattrib( Leap::FingerList, bool, isEmpty ); +%constattrib( Leap::ToolList, bool, isEmpty ); +%constattrib( Leap::HandList, bool, isEmpty ); +%constattrib( Leap::GestureList, bool, isEmpty ); +%constattrib( Leap::ScreenList, bool, isEmpty ); +%constattrib( Leap::DeviceList, bool, isEmpty ); + +%leapattrib( Leap::PointableList, Pointable, leftmost ); +%leapattrib( Leap::PointableList, Pointable, rightmost ); +%leapattrib( Leap::PointableList, Pointable, frontmost ); +%leapattrib( Leap::FingerList, Finger, leftmost ); +%leapattrib( Leap::FingerList, Finger, rightmost ); +%leapattrib( Leap::FingerList, Finger, frontmost ); +%leapattrib( Leap::ToolList, Tool, leftmost ); +%leapattrib( Leap::ToolList, Tool, rightmost ); +%leapattrib( Leap::ToolList, Tool, frontmost ); +%leapattrib( Leap::HandList, Hand, leftmost ); +%leapattrib( Leap::HandList, Hand, rightmost ); +%leapattrib( Leap::HandList, Hand, frontmost ); + +%constattrib( Leap::Frame, int64_t, id ); +%constattrib( Leap::Frame, int64_t, timestamp ); +%constattrib( Leap::Frame, float, currentFramesPerSecond ); +%leapattrib( Leap::Frame, PointableList, pointables ); +%leapattrib( Leap::Frame, FingerList, fingers ); +%leapattrib( Leap::Frame, ToolList, tools ); +%leapattrib( Leap::Frame, HandList, hands ); +%constattrib( Leap::Frame, bool, isValid ); +%leapattrib( Leap::Frame, InteractionBox, interactionBox ); + +%constattrib( Leap::Screen, int32_t, id ); +%leapattrib( Leap::Screen, Vector, horizontalAxis ); +%leapattrib( Leap::Screen, Vector, verticalAxis ); +%leapattrib( Leap::Screen, Vector, bottomLeftCorner ); +%constattrib( Leap::Screen, int, widthPixels ); +%constattrib( Leap::Screen, int, heightPixels ); +%constattrib( Leap::Screen, bool, isValid ); + +%constattrib( Leap::Device, float, horizontalViewAngle ); +%constattrib( Leap::Device, float, verticalViewAngle ); +%constattrib( Leap::Device, float, range ); +%constattrib( Leap::Device, bool, isValid ); +%constattrib( Leap::Device, bool, isEmbedded ); +%constattrib( Leap::Device, bool, isStreaming ); +%constattrib( Leap::Device, Leap::Device::Type, type ); + +%leapattrib( Leap::InteractionBox, Vector, center ); +%constattrib( Leap::InteractionBox, float, width ); +%constattrib( Leap::InteractionBox, float, height ); +%constattrib( Leap::InteractionBox, float, depth ); +%constattrib( Leap::InteractionBox, bool, isValid ); + +#if SWIGCSHARP +%csmethodmodifiers Leap::Finger::invalid "public new"; +%csmethodmodifiers Leap::Tool::invalid "public new"; +#endif +%staticattrib( Leap::Pointable, static const Pointable&, invalid); +%staticattrib( Leap::Finger, static const Finger&, invalid); +%staticattrib( Leap::Tool, static const Tool&, invalid); +%staticattrib( Leap::Bone, static const Bone&, invalid); +%staticattrib( Leap::Hand, static const Hand&, invalid); +%staticattrib( Leap::Gesture, static const Gesture&, invalid); +%staticattrib( Leap::Screen, static const Screen&, invalid ); +%staticattrib( Leap::Device, static const Device&, invalid ); +%staticattrib( Leap::InteractionBox, static const InteractionBox&, invalid ); +%staticattrib( Leap::Frame, static const Frame&, invalid); + +%constattrib( Leap::Vector, float, magnitude ); +%constattrib( Leap::Vector, float, magnitudeSquared ); +%constattrib( Leap::Vector, float, pitch ); +%constattrib( Leap::Vector, float, roll ); +%constattrib( Leap::Vector, float, yaw ); +%leapattrib( Leap::Vector, Vector, normalized ); + +%constattrib( Leap::Controller, bool, isConnected ); +%constattrib( Leap::Controller, bool, hasFocus ); +%constattrib( Leap::Controller, Controller::PolicyFlag, policyFlags ); +%leapattrib( Leap::Controller, Config, config ); +%leapattrib( Leap::Controller, ScreenList, locatedScreens ); +%leapattrib( Leap::Controller, DeviceList, devices ); + +%staticattrib( Leap::Vector, static const Vector&, zero ); +%staticattrib( Leap::Vector, static const Vector&, xAxis ); +%staticattrib( Leap::Vector, static const Vector&, yAxis ); +%staticattrib( Leap::Vector, static const Vector&, zAxis ); +%staticattrib( Leap::Vector, static const Vector&, forward ); +%staticattrib( Leap::Vector, static const Vector&, backward ); +%staticattrib( Leap::Vector, static const Vector&, left ); +%staticattrib( Leap::Vector, static const Vector&, right ); +%staticattrib( Leap::Vector, static const Vector&, up ); +%staticattrib( Leap::Vector, static const Vector&, down ); + +%staticattrib( Leap::Matrix, static const Matrix&, identity ); + +#endif + +#if SWIGCSHARP + +%rename("%(lowercamelcase)s", %$isvariable) ""; +%ignore Leap::DEG_TO_RAD; +%ignore Leap::RAD_TO_DEG; +%ignore Leap::PI; + +SWIG_CSBODY_PROXY(public, public, SWIGTYPE) + +#elif SWIGPYTHON + +%rename("%(camelcase)s", %$isclass) ""; +%rename("%(camelcase)s", %$isconstructor) ""; + +#elif SWIGJAVA + +%ignore Leap::DEG_TO_RAD; +%ignore Leap::RAD_TO_DEG; +%ignore Leap::PI; + +# Use proper Java enums +%include "enums.swg" +%javaconst(1); + +SWIG_JAVABODY_PROXY(public, public, SWIGTYPE) + +#endif + +# Ignore C++ streaming operator +%ignore operator<<; +# Ignore C++ equal operator +%ignore operator=; + +#if SWIGPYTHON +%begin %{ +#if defined(_WIN32) && defined(_DEBUG) +// Workaround for obscure STL template error +#include +// Workaround for non-existent Python debug library +#define _TMP_DEBUG _DEBUG +#undef _DEBUG +#include +#define _DEBUG _TMP_DEBUG +#undef _TMP_DEBUG +#endif +#if defined(__APPLE__) +#pragma GCC diagnostic ignored "-Wself-assign" +#endif +%} +#endif + +#if SWIGCSHARP || SWIGJAVA +%begin %{ +#if defined(_WIN32) +#include +// When dynamically loading the Leap C# DLL, set the DLL search path to look in +// the same the directory. This will allow loading the Leap.dll. Create the +// Leap C# DLL with the /DELAYLOAD:Leap.dll link option. +extern "C" BOOL WINAPI DllMain( + _In_ HINSTANCE hinstDLL, + _In_ DWORD fdwReason, + _In_ LPVOID lpvReserved) +{ + if (lpvReserved == 0) { + static TCHAR lpPrevPathName[1024]; + static BOOL restore = FALSE; + + if (fdwReason == DLL_PROCESS_ATTACH) { + TCHAR lpPathName[1024]; + int len; + + len = GetDllDirectory(static_cast(sizeof(lpPrevPathName) - 1), + lpPrevPathName); + if (len < 0 && len >= sizeof(lpPrevPathName)) { + len = 0; + } + lpPrevPathName[len] = '\0'; + len = static_cast(GetModuleFileName(static_cast(hinstDLL), + lpPathName, static_cast(sizeof(lpPathName)))); + if (len > 0 && len < sizeof(lpPathName)) { + for (int i = len; i >= 0; i--) { + if (lpPathName[i] == '\\' || lpPathName[i] == '/') { + lpPathName[i] = '\0'; + restore = SetDllDirectory(lpPathName); + break; + } + } + } + } else if (fdwReason == DLL_PROCESS_DETACH) { + if (restore && lpPrevPathName[0] != '\0') { + SetDllDirectory(lpPrevPathName); + restore = FALSE; + } + } + } + return TRUE; +} +#endif +%} +#endif + +%typemap(csin, pre=" lock(arg0) {", post=" $csinput.Dispose();\n }") const Leap::Controller& "Controller.getCPtr($csinput)" + +%header %{ +#define SWIG +#include "Leap.h" +%} + +%feature("director") Leap::Listener; +#if SWIGPYTHON +%feature("director:except") { + if ($error != NULL) { + PyErr_Print(); + } +} +#endif + +%pragma(java) jniclasscode=%{ + static { + try { + System.loadLibrary("LeapJava"); + } catch (UnsatisfiedLinkError e) { + System.err.println("Native code library failed to load. \n" + e); + System.exit(1); + } + } +%} + +################################################################################ +# Operator overloading # +################################################################################ + +#if SWIGCSHARP + +%ignore *::operator+=; +%ignore *::operator-=; +%ignore *::operator*=; +%ignore *::operator/=; +%ignore *::operator!=; +%ignore Leap::Vector::toFloatPointer; +%ignore Leap::Matrix::toArray3x3; +%ignore Leap::Matrix::toArray4x4; +%ignore Leap::FloatArray; + +%rename(Equals) *::operator ==; +%rename(_operator_add) *::operator +; +%rename(_operator_sub) *::operator -; +%rename(_operator_mul) *::operator *; +%rename(_operator_div) *::operator /; +%rename(_operator_get) *::operator []; +%rename(_operator_to_float) *::operator const float*; +%csmethodmodifiers *::operator + "private"; +%csmethodmodifiers *::operator - "private"; +%csmethodmodifiers *::operator * "private"; +%csmethodmodifiers *::operator / "private"; +%csmethodmodifiers *::operator [] "private"; +%csmethodmodifiers *::operator const float* "private"; + +%typemap(cscode) Leap::Vector +%{ + /** Add vectors component-wise. */ + public static Vector operator + (Vector v1, Vector v2) { + return v1._operator_add(v2); + } + /** Subtract vectors component-wise. */ + public static Vector operator - (Vector v1, Vector v2) { + return v1._operator_sub(v2); + } + /** Multiply vector by a scalar. */ + public static Vector operator * (Vector v1, float scalar) { + return v1._operator_mul(scalar); + } + /** Multiply vector by a scalar on the left-hand side. */ + public static Vector operator * (float scalar, Vector v1) { + return v1._operator_mul(scalar); + } + /** Divide vector by a scalar. */ + public static Vector operator / (Vector v1, float scalar) { + return v1._operator_div(scalar); + } + /** Negate a vector. */ + public static Vector operator - (Vector v1) { + return v1._operator_sub(); + } + /** Convert this vector to an array of three float values: [x,y,z]. */ + public float[] ToFloatArray() { + return new float[] {x, y, z}; + } +%} +%typemap(cscode) Leap::Matrix +%{ + /** Multiply two matrices. */ + public static Matrix operator * (Matrix m1, Matrix m2) { + return m1._operator_mul(m2); + } + /** Copy this matrix to the specified array of 9 float values in row-major order. */ + public float[] ToArray3x3(float[] output) { + output[0] = xBasis.x; output[1] = xBasis.y; output[2] = xBasis.z; + output[3] = yBasis.x; output[4] = yBasis.y; output[5] = yBasis.z; + output[6] = zBasis.x; output[7] = zBasis.y; output[8] = zBasis.z; + return output; + } + /** Copy this matrix to the specified array containing 9 double values in row-major order. */ + public double[] ToArray3x3(double[] output) { + output[0] = xBasis.x; output[1] = xBasis.y; output[2] = xBasis.z; + output[3] = yBasis.x; output[4] = yBasis.y; output[5] = yBasis.z; + output[6] = zBasis.x; output[7] = zBasis.y; output[8] = zBasis.z; + return output; + } + /** Convert this matrix to an array containing 9 float values in row-major order. */ + public float[] ToArray3x3() { + return ToArray3x3(new float[9]); + } + /** Copy this matrix to the specified array of 16 float values in row-major order. */ + public float[] ToArray4x4(float[] output) { + output[0] = xBasis.x; output[1] = xBasis.y; output[2] = xBasis.z; output[3] = 0.0f; + output[4] = yBasis.x; output[5] = yBasis.y; output[6] = yBasis.z; output[7] = 0.0f; + output[8] = zBasis.x; output[9] = zBasis.y; output[10] = zBasis.z; output[11] = 0.0f; + output[12] = origin.x; output[13] = origin.y; output[14] = origin.z; output[15] = 1.0f; + return output; + } + /** Copy this matrix to the specified array of 16 double values in row-major order. */ + public double[] ToArray4x4(double[] output) { + output[0] = xBasis.x; output[1] = xBasis.y; output[2] = xBasis.z; output[3] = 0.0f; + output[4] = yBasis.x; output[5] = yBasis.y; output[6] = yBasis.z; output[7] = 0.0f; + output[8] = zBasis.x; output[9] = zBasis.y; output[10] = zBasis.z; output[11] = 0.0f; + output[12] = origin.x; output[13] = origin.y; output[14] = origin.z; output[15] = 1.0f; + return output; + } + /** Convert this matrix to an array containing 16 float values in row-major order. */ + public float[] ToArray4x4() { + return ToArray4x4(new float[16]); + } +%} + +#elif SWIGJAVA + +%ignore *::operator+=; +%ignore *::operator-=; +%ignore *::operator*=; +%ignore *::operator/=; +%ignore *::operator!=; +%ignore Leap::Vector::toFloatPointer; +%ignore Leap::Matrix::toArray3x3; +%ignore Leap::Matrix::toArray4x4; +%ignore Leap::FloatArray; + +%rename(plus) *::operator+; +%rename(minus) *::operator-; +%rename(opposite) *::operator-() const; +%rename(times) *::operator*; +%rename(divide) *::operator/; +%rename(get) *::operator []; +%rename(equals) *::operator==; + +%typemap(javacode) Leap::Vector +%{ + public float[] toFloatArray() { + return new float[] {getX(), getY(), getZ()}; + } +%} +%typemap(javacode) Leap::Matrix +%{ + public float[] toArray3x3(float[] output) { + output[0] = getXBasis().getX(); output[1] = getXBasis().getY(); output[2] = getXBasis().getZ(); + output[3] = getYBasis().getX(); output[4] = getYBasis().getY(); output[5] = getYBasis().getZ(); + output[6] = getZBasis().getX(); output[7] = getZBasis().getY(); output[8] = getZBasis().getZ(); + return output; + } + public double[] toArray3x3(double[] output) { + output[0] = getXBasis().getX(); output[1] = getXBasis().getY(); output[2] = getXBasis().getZ(); + output[3] = getYBasis().getX(); output[4] = getYBasis().getY(); output[5] = getYBasis().getZ(); + output[6] = getZBasis().getX(); output[7] = getZBasis().getY(); output[8] = getZBasis().getZ(); + return output; + } + public float[] toArray3x3() { + return toArray3x3(new float[9]); + } + public float[] toArray4x4(float[] output) { + output[0] = getXBasis().getX(); output[1] = getXBasis().getY(); output[2] = getXBasis().getZ(); output[3] = 0.0f; + output[4] = getYBasis().getX(); output[5] = getYBasis().getY(); output[6] = getYBasis().getZ(); output[7] = 0.0f; + output[8] = getZBasis().getX(); output[9] = getZBasis().getY(); output[10] = getZBasis().getZ(); output[11] = 0.0f; + output[12] = getOrigin().getX(); output[13] = getOrigin().getY(); output[14] = getOrigin().getZ(); output[15] = 1.0f; + return output; + } + public double[] toArray4x4(double[] output) { + output[0] = getXBasis().getX(); output[1] = getXBasis().getY(); output[2] = getXBasis().getZ(); output[3] = 0.0f; + output[4] = getYBasis().getX(); output[5] = getYBasis().getY(); output[6] = getYBasis().getZ(); output[7] = 0.0f; + output[8] = getZBasis().getX(); output[9] = getZBasis().getY(); output[10] = getZBasis().getZ(); output[11] = 0.0f; + output[12] = getOrigin().getX(); output[13] = getOrigin().getY(); output[14] = getOrigin().getZ(); output[15] = 1.0f; + return output; + } + public float[] toArray4x4() { + return toArray4x4(new float[16]); + } +%} + +#elif SWIGPYTHON + +%ignore Leap::Interface::operator=; +%ignore Leap::ConstListIterator::operator++; +%ignore Leap::Vector::toFloatPointer; +%ignore Leap::Matrix::toArray3x3; +%ignore Leap::Matrix::toArray4x4; +%ignore Leap::FloatArray; + +%rename(__getitem__) *::operator []; + +%extend Leap::Vector { +%pythoncode { + def to_float_array(self): return [self.x, self.y, self.z] + def to_tuple(self): return (self.x, self.y, self.z) +%}} +%extend Leap::Matrix { +%pythoncode { + def to_array_3x3(self, output = None): + if output is None: + output = [0]*9 + output[0], output[1], output[2] = self.x_basis.x, self.x_basis.y, self.x_basis.z + output[3], output[4], output[5] = self.y_basis.x, self.y_basis.y, self.y_basis.z + output[6], output[7], output[8] = self.z_basis.x, self.z_basis.y, self.z_basis.z + return output + def to_array_4x4(self, output = None): + if output is None: + output = [0]*16 + output[0], output[1], output[2], output[3] = self.x_basis.x, self.x_basis.y, self.x_basis.z, 0.0 + output[4], output[5], output[6], output[7] = self.y_basis.x, self.y_basis.y, self.y_basis.z, 0.0 + output[8], output[9], output[10], output[11] = self.z_basis.x, self.z_basis.y, self.z_basis.z, 0.0 + output[12], output[13], output[14], output[15] = self.origin.x, self.origin.y, self.origin.z, 1.0 + return output +%}} + +#endif + +################################################################################ +# List Helpers # +################################################################################ + +#if SWIGCSHARP + +%define %leap_iterator_helper(BaseType) +%typemap(csinterfaces_derived) Leap::BaseType##List "System.Collections.Generic.IEnumerable" +%typemap(cscode) Leap::BaseType##List +%{ + private class BaseType##List##Enumerator : System.Collections.Generic.IEnumerator { + private BaseType##List _list; + private int _index; + public BaseType##List##Enumerator(BaseType##List list) { + _list = list; + _index = -1; + } + public void Reset() { + _index = -1; + } + public BaseType Current { + get { + return _list._operator_get(_index); + } + } + object System.Collections.IEnumerator.Current { + get { + return this.Current; + } + } + public bool MoveNext() { + _index++; + return (_index < _list.Count); + } + public void Dispose() { + //No cleanup needed + } + } + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { + return this.GetEnumerator(); + } + public System.Collections.Generic.IEnumerator GetEnumerator() { + return new BaseType##List##Enumerator(this); + } + public BaseType this[int index] { + get { return _operator_get(index); } + } +%} +%enddef + +#elif SWIGJAVA + +%define %leap_iterator_helper(BaseType) +%typemap(javainterfaces) Leap::BaseType##List "Iterable" +%typemap(javacode) Leap::BaseType##List +%{ + public class BaseType##ListIterator implements java.util.Iterator { + int index = 0; + @Override public boolean hasNext() { + return index < count(); + } + @Override public BaseType next() { + return get(index++); + } + @Override public void remove() { + } + } + @Override public java.util.Iterator iterator() { + return new BaseType##ListIterator(); + } +%} +%enddef + +#elif SWIGPYTHON + +%define %leap_iterator_helper(BaseType) +%rename(__len__) Leap::BaseType##List::count; +%extend Leap::BaseType##List { +%pythoncode { + def __iter__(self): + _pos = 0 + while _pos < len(self): + yield self[_pos] + _pos += 1 +%}} +%enddef + +#else + +%define %leap_iterator_helper(BaseType) +%enddef + +#endif + +%define %leap_list_helper(BaseType) +%ignore Leap::BaseType##List::BaseType##List(const ListBaseImplementation&); +%ignore Leap::BaseType##List::const_iterator; +%ignore Leap::BaseType##List::begin() const; +%ignore Leap::BaseType##List::end() const; +%leap_iterator_helper(BaseType) +%enddef + +%leap_list_helper(Pointable); +%leap_list_helper(Finger); +%leap_list_helper(Tool); +%leap_list_helper(Gesture); +%leap_list_helper(Hand); +%leap_list_helper(Screen); +%leap_list_helper(Device); + +################################################################################ +# Config Helpers # +################################################################################ + +#if SWIGPYTHON + +// Use dynamic typing to get or set any type of config value with one function +%extend Leap::Config { +%pythoncode { + def get(self, *args): + type = LeapPython.Config_type(self, *args) + if type == LeapPython.Config_TYPE_BOOLEAN: + return LeapPython.Config_get_bool(self, *args) + elif type == LeapPython.Config_TYPE_INT32: + return LeapPython.Config_get_int_32(self, *args) + elif type == LeapPython.Config_TYPE_FLOAT: + return LeapPython.Config_get_float(self, *args) + elif type == LeapPython.Config_TYPE_STRING: + return LeapPython.Config_get_string(self, *args) + return None + def set(self, *args): + type = LeapPython.Config_type(self, *args[:-1]) # Do not pass value through + if type == LeapPython.Config_TYPE_BOOLEAN: + return LeapPython.Config_set_bool(self, *args) + elif type == LeapPython.Config_TYPE_INT32: + return LeapPython.Config_set_int_32(self, *args) + elif type == LeapPython.Config_TYPE_FLOAT: + return LeapPython.Config_set_float(self, *args) + elif type == LeapPython.Config_TYPE_STRING: + return LeapPython.Config_set_string(self, *args) + return False +%}} +// Ignore methods that are unnecessary due to get and set functions defined above +%feature("shadow") Leap::Config::type(const std::string& key) const %{%} +%feature("shadow") Leap::Config::getBool(const std::string& key) const %{%} +%feature("shadow") Leap::Config::setBool(const std::string& key, bool value) %{%} +%feature("shadow") Leap::Config::getInt32(const std::string& key) const %{%} +%feature("shadow") Leap::Config::setInt32(const std::string& key, int32_t value) %{%} +%feature("shadow") Leap::Config::getFloat(const std::string& key) const %{%} +%feature("shadow") Leap::Config::setFloat(const std::string& key, float value) %{%} +%feature("shadow") Leap::Config::getString(const std::string& key) const %{%} +%feature("shadow") Leap::Config::setString(const std::string& key, const std::string& value) %{%} + +#endif + +################################################################################ +# ToString methods # +################################################################################ + +#if SWIGCSHARP + +%csmethodmodifiers *::toString "public override"; + +#elif SWIGJAVA + +%javamethodmodifiers *::toString "@Override public"; + +#elif SWIGPYTHON + +%rename(__str__) *::toString; + +#endif + +%include "LeapMath.h" +%include "Leap.h" diff --git a/interface/external/leapmotion/include/LeapMath.h b/interface/external/leapmotion/include/LeapMath.h new file mode 100644 index 0000000000..7837b6021a --- /dev/null +++ b/interface/external/leapmotion/include/LeapMath.h @@ -0,0 +1,1050 @@ +/******************************************************************************\ +* 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. * +\******************************************************************************/ + +#if !defined(__LeapMath_h__) +#define __LeapMath_h__ + +#include +#include +#include +#include +#include + +namespace Leap { + +/** + * The constant pi as a single precision floating point number. + * @since 1.0 + */ +static const float PI = 3.1415926536f; +/** + * The constant ratio to convert an angle measure from degrees to radians. + * Multiply a value in degrees by this constant to convert to radians. + * @since 1.0 + */ +static const float DEG_TO_RAD = 0.0174532925f; +/** + * The constant ratio to convert an angle measure from radians to degrees. + * Multiply a value in radians by this constant to convert to degrees. + * @since 1.0 + */ +static const float RAD_TO_DEG = 57.295779513f; + +/** +* The difference between 1 and the least value greater than 1 that is +* representable as a float. +* @since 2.0 +*/ +static const float EPSILON = 1.192092896e-07f; + +/** + * The Vector struct represents a three-component mathematical vector or point + * such as a direction or position in three-dimensional space. + * + * The Leap Motion software employs a right-handed Cartesian coordinate system. + * Values given are in units of real-world millimeters. The origin is centered + * at the center of the Leap Motion Controller. The x- and z-axes lie in the horizontal + * plane, with the x-axis running parallel to the long edge of the device. + * The y-axis is vertical, with positive values increasing upwards (in contrast + * to the downward orientation of most computer graphics coordinate systems). + * The z-axis has positive values increasing away from the computer screen. + * + * \image html images/Leap_Axes.png + * @since 1.0 + */ +struct Vector { + /** + * Creates a new Vector with all components set to zero. + * @since 1.0 + */ + Vector() : + x(0), y(0), z(0) {} + + /** + * Creates a new Vector with the specified component values. + * + * \include Vector_Constructor_1.txt + * @since 1.0 + */ + Vector(float _x, float _y, float _z) : + x(_x), y(_y), z(_z) {} + + /** + * Copies the specified Vector. + * + * \include Vector_Constructor_2.txt + * @since 1.0 + */ + Vector(const Vector& vector) : + x(vector.x), y(vector.y), z(vector.z) {} + + /** + * The zero vector: (0, 0, 0) + * + * \include Vector_Zero.txt + * @since 1.0 + */ + static const Vector& zero() { + static Vector s_zero(0, 0, 0); + return s_zero; + } + + /** + * The x-axis unit vector: (1, 0, 0) + * + * \include Vector_XAxis.txt + * @since 1.0 + */ + static const Vector& xAxis() { + static Vector s_xAxis(1, 0, 0); + return s_xAxis; + } + /** + * The y-axis unit vector: (0, 1, 0) + * + * \include Vector_YAxis.txt + * @since 1.0 + */ + static const Vector& yAxis() { + static Vector s_yAxis(0, 1, 0); + return s_yAxis; + } + /** + * The z-axis unit vector: (0, 0, 1) + * + * \include Vector_ZAxis.txt + * @since 1.0 + */ + static const Vector& zAxis() { + static Vector s_zAxis(0, 0, 1); + return s_zAxis; + } + + /** + * The unit vector pointing left along the negative x-axis: (-1, 0, 0) + * + * \include Vector_Left.txt + * @since 1.0 + */ + static const Vector& left() { + static Vector s_left(-1, 0, 0); + return s_left; + } + /** + * The unit vector pointing right along the positive x-axis: (1, 0, 0) + * + * \include Vector_Right.txt + * @since 1.0 + */ + static const Vector& right() { + return xAxis(); + } + /** + * The unit vector pointing down along the negative y-axis: (0, -1, 0) + * + * \include Vector_Down.txt + * @since 1.0 + */ + static const Vector& down() { + static Vector s_down(0, -1, 0); + return s_down; + } + /** + * The unit vector pointing up along the positive y-axis: (0, 1, 0) + * + * \include Vector_Up.txt + * @since 1.0 + */ + static const Vector& up() { + return yAxis(); + } + /** + * The unit vector pointing forward along the negative z-axis: (0, 0, -1) + * + * \include Vector_Forward.txt + * @since 1.0 + */ + static const Vector& forward() { + static Vector s_forward(0, 0, -1); + return s_forward; + } + /** + * The unit vector pointing backward along the positive z-axis: (0, 0, 1) + * + * \include Vector_Backward.txt + * @since 1.0 + */ + static const Vector& backward() { + return zAxis(); + } + + /** + * The magnitude, or length, of this vector. + * + * The magnitude is the L2 norm, or Euclidean distance between the origin and + * the point represented by the (x, y, z) components of this Vector object. + * + * \include Vector_Magnitude.txt + * + * @returns The length of this vector. + * @since 1.0 + */ + float magnitude() const { + return std::sqrt(x*x + y*y + z*z); + } + + /** + * The square of the magnitude, or length, of this vector. + * + * \include Vector_Magnitude_Squared.txt + * + * @returns The square of the length of this vector. + * @since 1.0 + */ + float magnitudeSquared() const { + return x*x + y*y + z*z; + } + + /** + * The distance between the point represented by this Vector + * object and a point represented by the specified Vector object. + * + * \include Vector_DistanceTo.txt + * + * @param other A Vector object. + * @returns The distance from this point to the specified point. + * @since 1.0 + */ + float distanceTo(const Vector& other) const { + return std::sqrt((x - other.x)*(x - other.x) + + (y - other.y)*(y - other.y) + + (z - other.z)*(z - other.z)); + } + + /** + * The angle between this vector and the specified vector in radians. + * + * The angle is measured in the plane formed by the two vectors. The + * angle returned is always the smaller of the two conjugate angles. + * Thus A.angleTo(B) == B.angleTo(A) and is always a positive + * value less than or equal to pi radians (180 degrees). + * + * If either vector has zero length, then this function returns zero. + * + * \image html images/Math_AngleTo.png + * + * \include Vector_AngleTo.txt + * + * @param other A Vector object. + * @returns The angle between this vector and the specified vector in radians. + * @since 1.0 + */ + float angleTo(const Vector& other) const { + float denom = this->magnitudeSquared() * other.magnitudeSquared(); + if (denom <= EPSILON) { + return 0.0f; + } + float val = this->dot(other) / std::sqrt(denom); + if (val >= 1.0f) { + return 0.0f; + } else if (val <= -1.0f) { + return PI; + } + return std::acos(val); + } + + /** + * The pitch angle in radians. + * + * Pitch is the angle between the negative z-axis and the projection of + * the vector onto the y-z plane. In other words, pitch represents rotation + * around the x-axis. + * If the vector points upward, the returned angle is between 0 and pi radians + * (180 degrees); if it points downward, the angle is between 0 and -pi radians. + * + * \image html images/Math_Pitch_Angle.png + * + * \include Vector_Pitch.txt + * + * @returns The angle of this vector above or below the horizon (x-z plane). + * @since 1.0 + */ + float pitch() const { + return std::atan2(y, -z); + } + + /** + * The yaw angle in radians. + * + * Yaw is the angle between the negative z-axis and the projection of + * the vector onto the x-z plane. In other words, yaw represents rotation + * around the y-axis. If the vector points to the right of the negative z-axis, + * then the returned angle is between 0 and pi radians (180 degrees); + * if it points to the left, the angle is between 0 and -pi radians. + * + * \image html images/Math_Yaw_Angle.png + * + * \include Vector_Yaw.txt + * + * @returns The angle of this vector to the right or left of the negative z-axis. + * @since 1.0 + */ + float yaw() const { + return std::atan2(x, -z); + } + + /** + * The roll angle in radians. + * + * Roll is the angle between the y-axis and the projection of + * the vector onto the x-y plane. In other words, roll represents rotation + * around the z-axis. If the vector points to the left of the y-axis, + * then the returned angle is between 0 and pi radians (180 degrees); + * if it points to the right, the angle is between 0 and -pi radians. + * + * \image html images/Math_Roll_Angle.png + * + * Use this function to get roll angle of the plane to which this vector is a + * normal. For example, if this vector represents the normal to the palm, + * then this function returns the tilt or roll of the palm plane compared + * to the horizontal (x-z) plane. + * + * \include Vector_Roll.txt + * + * @returns The angle of this vector to the right or left of the y-axis. + * @since 1.0 + */ + float roll() const { + return std::atan2(x, -y); + } + + /** + * The dot product of this vector with another vector. + * + * The dot product is the magnitude of the projection of this vector + * onto the specified vector. + * + * \image html images/Math_Dot.png + * + * \include Vector_Dot.txt + * + * @param other A Vector object. + * @returns The dot product of this vector and the specified vector. + * @since 1.0 + */ + float dot(const Vector& other) const { + return (x * other.x) + (y * other.y) + (z * other.z); + } + + /** + * The cross product of this vector and the specified vector. + * + * The cross product is a vector orthogonal to both original vectors. + * It has a magnitude equal to the area of a parallelogram having the + * two vectors as sides. The direction of the returned vector is + * determined by the right-hand rule. Thus A.cross(B) == -B.cross(A). + * + * \image html images/Math_Cross.png + * + * \include Vector_Cross.txt + * + * @param other A Vector object. + * @returns The cross product of this vector and the specified vector. + * @since 1.0 + */ + Vector cross(const Vector& other) const { + return Vector((y * other.z) - (z * other.y), + (z * other.x) - (x * other.z), + (x * other.y) - (y * other.x)); + } + + /** + * A normalized copy of this vector. + * + * A normalized vector has the same direction as the original vector, + * but with a length of one. + * + * \include Vector_Normalized.txt + * + * @returns A Vector object with a length of one, pointing in the same + * direction as this Vector object. + * @since 1.0 + */ + Vector normalized() const { + float denom = this->magnitudeSquared(); + if (denom <= EPSILON) { + return Vector::zero(); + } + denom = 1.0f / std::sqrt(denom); + return Vector(x * denom, y * denom, z * denom); + } + + /** + * A copy of this vector pointing in the opposite direction. + * + * \include Vector_Negate.txt + * + * @returns A Vector object with all components negated. + * @since 1.0 + */ + Vector operator-() const { + return Vector(-x, -y, -z); + } + + /** + * Add vectors component-wise. + * + * \include Vector_Plus.txt + * @since 1.0 + */ + Vector operator+(const Vector& other) const { + return Vector(x + other.x, y + other.y, z + other.z); + } + + /** + * Subtract vectors component-wise. + * + * \include Vector_Minus.txt + * @since 1.0 + */ + Vector operator-(const Vector& other) const { + return Vector(x - other.x, y - other.y, z - other.z); + } + + /** + * Multiply vector by a scalar. + * + * \include Vector_Times.txt + * @since 1.0 + */ + Vector operator*(float scalar) const { + return Vector(x * scalar, y * scalar, z * scalar); + } + + /** + * Divide vector by a scalar. + * + * \include Vector_Divide.txt + * @since 1.0 + */ + Vector operator/(float scalar) const { + return Vector(x / scalar, y / scalar, z / scalar); + } + +#if !defined(SWIG) + /** + * Multiply vector by a scalar on the left-hand side (C++ only). + * + * \include Vector_Left_Times.txt + * @since 1.0 + */ + friend Vector operator*(float scalar, const Vector& vector) { + return Vector(vector.x * scalar, vector.y * scalar, vector.z * scalar); + } +#endif + + /** + * Add vectors component-wise and assign the sum. + * @since 1.0 + */ + Vector& operator+=(const Vector& other) { + x += other.x; + y += other.y; + z += other.z; + return *this; + } + + /** + * Subtract vectors component-wise and assign the difference. + * @since 1.0 + */ + Vector& operator-=(const Vector& other) { + x -= other.x; + y -= other.y; + z -= other.z; + return *this; + } + + /** + * Multiply vector by a scalar and assign the product. + * @since 1.0 + */ + Vector& operator*=(float scalar) { + x *= scalar; + y *= scalar; + z *= scalar; + return *this; + } + + /** + * Divide vector by a scalar and assign the quotient. + * @since 1.0 + */ + Vector& operator/=(float scalar) { + x /= scalar; + y /= scalar; + z /= scalar; + return *this; + } + + /** + * Returns a string containing this vector in a human readable format: (x, y, z). + * @since 1.0 + */ + std::string toString() const { + std::stringstream result; + result << "(" << x << ", " << y << ", " << z << ")"; + return result.str(); + } + /** + * Writes the vector to the output stream using a human readable format: (x, y, z). + * @since 1.0 + */ + friend std::ostream& operator<<(std::ostream& out, const Vector& vector) { + return out << vector.toString(); + } + + /** + * Compare Vector equality component-wise. + * + * \include Vector_Equals.txt + * @since 1.0 + */ + bool operator==(const Vector& other) const { + return x == other.x && y == other.y && z == other.z; + } + /** + * Compare Vector inequality component-wise. + * + * \include Vector_NotEqual.txt + * @since 1.0 + */ + bool operator!=(const Vector& other) const { + return x != other.x || y != other.y || z != other.z; + } + + /** + * Returns true if all of the vector's components are finite. If any + * component is NaN or infinite, then this returns false. + * + * \include Vector_IsValid.txt + * @since 1.0 + */ + bool isValid() const { + return (x <= FLT_MAX && x >= -FLT_MAX) && + (y <= FLT_MAX && y >= -FLT_MAX) && + (z <= FLT_MAX && z >= -FLT_MAX); + } + + /** + * Index vector components numerically. + * Index 0 is x, index 1 is y, and index 2 is z. + * @returns The x, y, or z component of this Vector, if the specified index + * value is at least 0 and at most 2; otherwise, returns zero. + * + * \include Vector_Index.txt + * @since 1.0 + */ + float operator[](unsigned int index) const { + return index < 3 ? (&x)[index] : 0.0f; + } + + /** + * Cast the vector to a float array. + * + * \include Vector_ToFloatPointer.txt + * @since 1.0 + */ + const float* toFloatPointer() const { + return &x; /* Note: Assumes x, y, z are aligned in memory. */ + } + + /** + * Convert a Leap::Vector to another 3-component Vector type. + * + * The specified type must define a constructor that takes the x, y, and z + * components as separate parameters. + * @since 1.0 + */ + template + const Vector3Type toVector3() const { + return Vector3Type(x, y, z); + } + + /** + * Convert a Leap::Vector to another 4-component Vector type. + * + * The specified type must define a constructor that takes the x, y, z, and w + * components as separate parameters. (The homogeneous coordinate, w, is set + * to zero by default, but you should typically set it to one for vectors + * representing a position.) + * @since 1.0 + */ + template + const Vector4Type toVector4(float w=0.0f) const { + return Vector4Type(x, y, z, w); + } + + /** + * The horizontal component. + * @since 1.0 + */ + float x; + /** + * The vertical component. + * @since 1.0 + */ + float y; + /** + * The depth component. + * @since 1.0 + */ + float z; +}; + + +/** + * The FloatArray struct is used to allow the returning of native float arrays + * without requiring dynamic memory allocation. It represents a matrix + * with a size up to 4x4. + * @since 1.0 + */ +struct FloatArray { + /** + * Access the elements of the float array exactly like a native array. + * @since 1.0 + */ + float& operator[] (unsigned int index) { + return m_array[index]; + } + + /** + * Use the Float Array anywhere a float pointer can be used. + * @since 1.0 + */ + operator float* () { + return m_array; + } + + /** + * Use the Float Array anywhere a const float pointer can be used. + * @since 1.0 + */ + operator const float* () const { + return m_array; + } + + /** + * An array containing up to 16 entries of the matrix. + * @since 1.0 + */ + float m_array[16]; +}; + +/** + * The Matrix struct represents a transformation matrix. + * + * To use this struct to transform a Vector, construct a matrix containing the + * desired transformation and then use the Matrix::transformPoint() or + * Matrix::transformDirection() functions to apply the transform. + * + * Transforms can be combined by multiplying two or more transform matrices using + * the * operator. + * @since 1.0 + */ +struct Matrix +{ + /** + * Constructs an identity transformation matrix. + * + * \include Matrix_Matrix.txt + * + * @since 1.0 + */ + Matrix() : + xBasis(1, 0, 0), + yBasis(0, 1, 0), + zBasis(0, 0, 1), + origin(0, 0, 0) { + } + + /** + * Constructs a copy of the specified Matrix object. + * + * \include Matrix_Matrix_copy.txt + * + * @since 1.0 + */ + Matrix(const Matrix& other) : + xBasis(other.xBasis), + yBasis(other.yBasis), + zBasis(other.zBasis), + origin(other.origin) { + } + + /** + * Constructs a transformation matrix from the specified basis vectors. + * + * \include Matrix_Matrix_basis.txt + * + * @param _xBasis A Vector specifying rotation and scale factors for the x-axis. + * @param _yBasis A Vector specifying rotation and scale factors for the y-axis. + * @param _zBasis A Vector specifying rotation and scale factors for the z-axis. + * @since 1.0 + */ + Matrix(const Vector& _xBasis, const Vector& _yBasis, const Vector& _zBasis) : + xBasis(_xBasis), + yBasis(_yBasis), + zBasis(_zBasis), + origin(0, 0, 0) { + } + + /** + * Constructs a transformation matrix from the specified basis and translation vectors. + * + * \include Matrix_Matrix_basis_origin.txt + * + * @param _xBasis A Vector specifying rotation and scale factors for the x-axis. + * @param _yBasis A Vector specifying rotation and scale factors for the y-axis. + * @param _zBasis A Vector specifying rotation and scale factors for the z-axis. + * @param _origin A Vector specifying translation factors on all three axes. + * @since 1.0 + */ + Matrix(const Vector& _xBasis, const Vector& _yBasis, const Vector& _zBasis, const Vector& _origin) : + xBasis(_xBasis), + yBasis(_yBasis), + zBasis(_zBasis), + origin(_origin) { + } + + /** + * Constructs a transformation matrix specifying a rotation around the specified vector. + * + * \include Matrix_Matrix_rotation.txt + * + * @param axis A Vector specifying the axis of rotation. + * @param angleRadians The amount of rotation in radians. + * @since 1.0 + */ + Matrix(const Vector& axis, float angleRadians) : + origin(0, 0, 0) { + setRotation(axis, angleRadians); + } + + /** + * Constructs a transformation matrix specifying a rotation around the specified vector + * and a translation by the specified vector. + * + * \include Matrix_Matrix_rotation_translation.txt + * + * @param axis A Vector specifying the axis of rotation. + * @param angleRadians The angle of rotation in radians. + * @param translation A Vector representing the translation part of the transform. + * @since 1.0 + */ + Matrix(const Vector& axis, float angleRadians, const Vector& translation) + : origin(translation) { + setRotation(axis, angleRadians); + } + + /** + * Returns the identity matrix specifying no translation, rotation, and scale. + * + * \include Matrix_identity.txt + * + * @returns The identity matrix. + * @since 1.0 + */ + static const Matrix& identity() { + static Matrix s_identity; + return s_identity; + } + + /** + * Sets this transformation matrix to represent a rotation around the specified vector. + * + * \include Matrix_setRotation.txt + * + * This function erases any previous rotation and scale transforms applied + * to this matrix, but does not affect translation. + * + * @param axis A Vector specifying the axis of rotation. + * @param angleRadians The amount of rotation in radians. + * @since 1.0 + */ + void setRotation(const Vector& axis, float angleRadians) { + const Vector n = axis.normalized(); + const float s = std::sin(angleRadians); + const float c = std::cos(angleRadians); + const float C = (1-c); + + xBasis = Vector(n[0]*n[0]*C + c, n[0]*n[1]*C - n[2]*s, n[0]*n[2]*C + n[1]*s); + yBasis = Vector(n[1]*n[0]*C + n[2]*s, n[1]*n[1]*C + c, n[1]*n[2]*C - n[0]*s); + zBasis = Vector(n[2]*n[0]*C - n[1]*s, n[2]*n[1]*C + n[0]*s, n[2]*n[2]*C + c ); + } + + /** + * Transforms a vector with this matrix by transforming its rotation, + * scale, and translation. + * + * \include Matrix_transformPoint.txt + * + * Translation is applied after rotation and scale. + * + * @param in The Vector to transform. + * @returns A new Vector representing the transformed original. + * @since 1.0 + */ + Vector transformPoint(const Vector& in) const { + return xBasis*in.x + yBasis*in.y + zBasis*in.z + origin; + } + + /** + * Transforms a vector with this matrix by transforming its rotation and + * scale only. + * + * \include Matrix_transformDirection.txt + * + * @param in The Vector to transform. + * @returns A new Vector representing the transformed original. + * @since 1.0 + */ + Vector transformDirection(const Vector& in) const { + return xBasis*in.x + yBasis*in.y + zBasis*in.z; + } + + /** + * Performs a matrix inverse if the matrix consists entirely of rigid + * transformations (translations and rotations). If the matrix is not rigid, + * this operation will not represent an inverse. + * + * \include Matrix_rigidInverse.txt + * + * Note that all matrices that are directly returned by the API are rigid. + * + * @returns The rigid inverse of the matrix. + * @since 1.0 + */ + Matrix rigidInverse() const { + Matrix rotInverse = Matrix(Vector(xBasis[0], yBasis[0], zBasis[0]), + Vector(xBasis[1], yBasis[1], zBasis[1]), + Vector(xBasis[2], yBasis[2], zBasis[2])); + rotInverse.origin = rotInverse.transformDirection( -origin ); + return rotInverse; + } + + /** + * Multiply transform matrices. + * + * Combines two transformations into a single equivalent transformation. + * + * \include Matrix_operator_times.txt + * + * @param other A Matrix to multiply on the right hand side. + * @returns A new Matrix representing the transformation equivalent to + * applying the other transformation followed by this transformation. + * @since 1.0 + */ + Matrix operator*(const Matrix& other) const { + return Matrix(transformDirection(other.xBasis), + transformDirection(other.yBasis), + transformDirection(other.zBasis), + transformPoint(other.origin)); + } + + /** + * Multiply transform matrices and assign the product. + * + * \include Matrix_operator_times_equal.txt + * + * @since 1.0 + */ + Matrix& operator*=(const Matrix& other) { + return (*this) = (*this) * other; + } + + /** + * Compare Matrix equality component-wise. + * + * \include Matrix_operator_equals.txt + * + * @since 1.0 + */ + bool operator==(const Matrix& other) const { + return xBasis == other.xBasis && + yBasis == other.yBasis && + zBasis == other.zBasis && + origin == other.origin; + } + /** + * Compare Matrix inequality component-wise. + * + * \include Matrix_operator_not_equals.txt + * + * @since 1.0 + */ + bool operator!=(const Matrix& other) const { + return xBasis != other.xBasis || + yBasis != other.yBasis || + zBasis != other.zBasis || + origin != other.origin; + } + + /** + * Convert a Leap::Matrix object to another 3x3 matrix type. + * + * The new type must define a constructor function that takes each matrix + * element as a parameter in row-major order. + * + * Translation factors are discarded. + * @since 1.0 + */ + template + const Matrix3x3Type toMatrix3x3() const { + return Matrix3x3Type(xBasis.x, xBasis.y, xBasis.z, + yBasis.x, yBasis.y, yBasis.z, + zBasis.x, zBasis.y, zBasis.z); + } + + /** + * Convert a Leap::Matrix object to another 4x4 matrix type. + * + * The new type must define a constructor function that takes each matrix + * element as a parameter in row-major order. + * @since 1.0 + */ + template + const Matrix4x4Type toMatrix4x4() const { + return Matrix4x4Type(xBasis.x, xBasis.y, xBasis.z, 0.0f, + yBasis.x, yBasis.y, yBasis.z, 0.0f, + zBasis.x, zBasis.y, zBasis.z, 0.0f, + origin.x, origin.y, origin.z, 1.0f); + } + + /** + * Writes the 3x3 Matrix object to a 9 element row-major float or + * double array. + * + * Translation factors are discarded. + * + * Returns a pointer to the same data. + * @since 1.0 + */ + template + T* toArray3x3(T* output) const { + output[0] = xBasis.x; output[1] = xBasis.y; output[2] = xBasis.z; + output[3] = yBasis.x; output[4] = yBasis.y; output[5] = yBasis.z; + output[6] = zBasis.x; output[7] = zBasis.y; output[8] = zBasis.z; + return output; + } + + /** + * Convert a 3x3 Matrix object to a 9 element row-major float array. + * + * Translation factors are discarded. + * + * \include Matrix_toArray3x3.txt + * + * Returns a FloatArray struct to avoid dynamic memory allocation. + * @since 1.0 + */ + FloatArray toArray3x3() const { + FloatArray output; + toArray3x3((float*)output); + return output; + } + + /** + * Writes the 4x4 Matrix object to a 16 element row-major float + * or double array. + * + * Returns a pointer to the same data. + * @since 1.0 + */ + template + T* toArray4x4(T* output) const { + output[0] = xBasis.x; output[1] = xBasis.y; output[2] = xBasis.z; output[3] = 0.0f; + output[4] = yBasis.x; output[5] = yBasis.y; output[6] = yBasis.z; output[7] = 0.0f; + output[8] = zBasis.x; output[9] = zBasis.y; output[10] = zBasis.z; output[11] = 0.0f; + output[12] = origin.x; output[13] = origin.y; output[14] = origin.z; output[15] = 1.0f; + return output; + } + + /** + * Convert a 4x4 Matrix object to a 16 element row-major float array. + * + * \include Matrix_toArray4x4.txt + * + * Returns a FloatArray struct to avoid dynamic memory allocation. + * @since 1.0 + */ + FloatArray toArray4x4() const { + FloatArray output; + toArray4x4((float*)output); + return output; + } + + /** + * Write the matrix to a string in a human readable format. + * @since 1.0 + */ + std::string toString() const { + std::stringstream result; + result << "xBasis:" << xBasis.toString() << " yBasis:" << yBasis.toString() + << " zBasis:" << zBasis.toString() << " origin:" << origin.toString(); + return result.str(); + } + + /** + * Write the matrix to an output stream in a human readable format. + * + * \include Matrix_operator_stream.txt + * + * @since 1.0 + */ + friend std::ostream& operator<<(std::ostream& out, const Matrix& matrix) { + return out << matrix.toString(); + } + + /** + * The basis vector for the x-axis. + * + * \include Matrix_xBasis.txt + * + * @since 1.0 + */ + Vector xBasis; + /** + * The basis vector for the y-axis. + * + * \include Matrix_yBasis.txt + * + * @since 1.0 + */ + Vector yBasis; + /** + * The basis vector for the z-axis. + * + * \include Matrix_zBasis.txt + * + * @since 1.0 + */ + Vector zBasis; + /** + * The translation factors for all three axes. + * + * \include Matrix_origin.txt + * + * @since 1.0 + */ + Vector origin; +}; + +}; // namespace Leap + +#endif // __LeapMath_h__ diff --git a/interface/external/leapmotion/lib/x64/Leap.dll b/interface/external/leapmotion/lib/x64/Leap.dll new file mode 100644 index 0000000000..9ece351675 Binary files /dev/null and b/interface/external/leapmotion/lib/x64/Leap.dll differ diff --git a/interface/external/leapmotion/lib/x64/Leap.lib b/interface/external/leapmotion/lib/x64/Leap.lib new file mode 100644 index 0000000000..59342b2f23 Binary files /dev/null and b/interface/external/leapmotion/lib/x64/Leap.lib differ diff --git a/interface/external/leapmotion/lib/x64/Leapd.dll b/interface/external/leapmotion/lib/x64/Leapd.dll new file mode 100644 index 0000000000..81341c165c Binary files /dev/null and b/interface/external/leapmotion/lib/x64/Leapd.dll differ diff --git a/interface/external/leapmotion/lib/x64/Leapd.lib b/interface/external/leapmotion/lib/x64/Leapd.lib new file mode 100644 index 0000000000..de00e7fa82 Binary files /dev/null and b/interface/external/leapmotion/lib/x64/Leapd.lib differ diff --git a/interface/external/leapmotion/lib/x64/msvcp120.dll b/interface/external/leapmotion/lib/x64/msvcp120.dll new file mode 100644 index 0000000000..4ea1efa734 Binary files /dev/null and b/interface/external/leapmotion/lib/x64/msvcp120.dll differ diff --git a/interface/external/leapmotion/lib/x64/msvcp120d.dll b/interface/external/leapmotion/lib/x64/msvcp120d.dll new file mode 100644 index 0000000000..db33cac88a Binary files /dev/null and b/interface/external/leapmotion/lib/x64/msvcp120d.dll differ diff --git a/interface/external/leapmotion/lib/x64/msvcr120.dll b/interface/external/leapmotion/lib/x64/msvcr120.dll new file mode 100644 index 0000000000..d711c92232 Binary files /dev/null and b/interface/external/leapmotion/lib/x64/msvcr120.dll differ diff --git a/interface/external/leapmotion/lib/x64/msvcr120d.dll b/interface/external/leapmotion/lib/x64/msvcr120d.dll new file mode 100644 index 0000000000..e744909f49 Binary files /dev/null and b/interface/external/leapmotion/lib/x64/msvcr120d.dll differ diff --git a/interface/external/leapmotion/lib/x86/Leap.dll b/interface/external/leapmotion/lib/x86/Leap.dll new file mode 100644 index 0000000000..6afaf21d2c Binary files /dev/null and b/interface/external/leapmotion/lib/x86/Leap.dll differ diff --git a/interface/external/leapmotion/lib/x86/Leap.lib b/interface/external/leapmotion/lib/x86/Leap.lib new file mode 100644 index 0000000000..ae10e4e2d4 Binary files /dev/null and b/interface/external/leapmotion/lib/x86/Leap.lib differ diff --git a/interface/external/leapmotion/lib/x86/msvcp120.dll b/interface/external/leapmotion/lib/x86/msvcp120.dll new file mode 100644 index 0000000000..a237d2d778 Binary files /dev/null and b/interface/external/leapmotion/lib/x86/msvcp120.dll differ diff --git a/interface/external/leapmotion/lib/x86/msvcr120.dll b/interface/external/leapmotion/lib/x86/msvcr120.dll new file mode 100644 index 0000000000..8c36149a65 Binary files /dev/null and b/interface/external/leapmotion/lib/x86/msvcr120.dll differ diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 3cfec3190e..fdc515e7bb 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -86,6 +86,8 @@ #include "ui/Stats.h" #include "ui/TextRenderer.h" +#include "devices/Leapmotion.h" + using namespace std; // Starfield information @@ -1653,6 +1655,10 @@ void Application::init() { _faceplus.init(); _visage.init(); + Leapmotion* leap = new Leapmotion(); + int index = DeviceTracker::registerDevice( "Leapmotion", leap ); + // _leapmotion.init(); + // fire off an immediate domain-server check in now that settings are loaded NodeList::getInstance()->sendDomainServerCheckIn(); @@ -1990,6 +1996,9 @@ void Application::update(float deltaTime) { updateLOD(); updateMouseRay(); // check what's under the mouse and update the mouse voxel + + DeviceTracker::updateAll(); + updateFaceshift(); updateVisage(); @@ -2003,6 +2012,7 @@ void Application::update(float deltaTime) { _sixenseManager.update(deltaTime); _joystickManager.update(); _prioVR.update(deltaTime); + } { @@ -2010,6 +2020,10 @@ void Application::update(float deltaTime) { updateMyAvatar(deltaTime); // Sample hardware, update view frustum if needed, and send avatar data to mixer/nodes } + + // Dispatch input events + _controllerScriptingInterface.updateInputControllers(); + updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process... { @@ -3104,6 +3118,7 @@ void Application::resetSensors() { } _prioVR.reset(); + //_leapmotion.reset(); QCursor::setPos(_mouseX, _mouseY); _myAvatar->reset(); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index a14152aa04..049d9ac302 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -286,6 +286,35 @@ void MyAvatar::updateFromTrackers(float deltaTime) { -MAX_LEAN, MAX_LEAN)); head->setLeanForward(glm::clamp(glm::degrees(atanf(relativePosition.z * _leanScale / TORSO_LENGTH)), -MAX_LEAN, MAX_LEAN)); + + // Hand Tracker ? + { +/* HandTracker* tracker = Application::getInstance()->getActiveHandTracker(); + if (tracker) { + Hand* hand = getHand(); + if ( hand ) { + int numPalms = hand->getNumPalms(); + numPalms = (numPalms < 2 ? numPalms: 2 ); // stick to 2 palms for now + for ( int palmNum = 0; palmNum < numPalms; palmNum++ ) { + PalmData* palmData = &(hand->getPalms()[ palmNum ]); + + int handSide = HandTracker::SIDE_LEFT + palmNum; + + if ( tracker->isPalmActive( HandTracker::Side( handSide ) ) ) { + palmData->setRawPosition( tracker->getPalmTranslation( HandTracker::Side( handSide ) ) ); + palmData->setRawRotation( tracker->getPalmRotation( HandTracker::Side( handSide ) ) ); + palmData->setActive( true ); + + palmData->setSixenseID( ( (handSide == HandTracker::SIDE_LEFT) ? LEFT_HAND_INDEX : RIGHT_HAND_INDEX ) ); + } else { + palmData->setActive( false ); + palmData->setSixenseID( -1 ); + } + } + } + } + */ + } } void MyAvatar::moveWithLean() { diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 1b1b2e032b..12a9bd52e8 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -66,7 +66,7 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) { hand->getLeftRightPalmIndices(leftPalmIndex, rightPalmIndex); const float HAND_RESTORATION_RATE = 0.25f; - if (leftPalmIndex == -1) { + if ( (leftPalmIndex == -1) && ( rightPalmIndex == -1) ) { // NO palm active // palms are not yet set, use mouse if (_owningAvatar->getHandState() == HAND_STATE_NULL) { restoreRightHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY); @@ -77,10 +77,15 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) { } restoreLeftHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY); - } else if (leftPalmIndex == rightPalmIndex) { + } else if ( (leftPalmIndex == -1) && ( rightPalmIndex != -1)) { // Just right hand active + // right hand only + applyPalmData(geometry.rightHandJointIndex, hand->getPalms()[rightPalmIndex]); + restoreLeftHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY); + + } else if ( (leftPalmIndex != -1) && ( rightPalmIndex == -1) ) { // Just left hand active // right hand only applyPalmData(geometry.rightHandJointIndex, hand->getPalms()[leftPalmIndex]); - restoreLeftHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY); + restoreRightHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY); } else { applyPalmData(geometry.leftHandJointIndex, hand->getPalms()[leftPalmIndex]); diff --git a/interface/src/devices/DeviceTracker.cpp b/interface/src/devices/DeviceTracker.cpp new file mode 100644 index 0000000000..66a1a1cf76 --- /dev/null +++ b/interface/src/devices/DeviceTracker.cpp @@ -0,0 +1,91 @@ +// +// DeviceTracker.cpp +// interface/src/devices +// +// Created by Sam Cake on 6/20/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "DeviceTracker.h" + +// The singleton managing the connected devices +DeviceTracker::Singleton DeviceTracker::Singleton::_singleton; + +int DeviceTracker::init() +{ + + return Singleton::get()->_devicesMap.size(); +} +int DeviceTracker::getNumDevices() +{ + return Singleton::get()->_devicesMap.size(); +} + +int DeviceTracker::getDeviceIndex( const Name& name ) +{ + auto deviceIt = Singleton::get()->_devicesMap.find( name ); + if ( deviceIt != Singleton::get()->_devicesMap.end() ) + return (*deviceIt).second; + else + return -1; +} + +DeviceTracker* DeviceTracker::getDevice( const Name& name ) +{ + return getDevice( getDeviceIndex( name ) ); +} + +DeviceTracker* DeviceTracker::getDevice( int deviceNum ) +{ + if ( (deviceNum >= 0) && ( deviceNum < Singleton::get()->_devicesVector.size() ) ) { + return Singleton::get()->_devicesVector[ deviceNum ]; + } else { + return NULL; + } +} + +int DeviceTracker::registerDevice( const Name& name, DeviceTracker* device ) +{ + if ( !device ) + return -1; + int index = getDeviceIndex( name ); + if ( index >= 0 ) { + // early exit because device name already taken + return -2; + } else { + index = Singleton::get()->_devicesVector.size(); + Singleton::get()->_devicesMap.insert( SingletonData::Map::value_type( name, index ) ); + Singleton::get()->_devicesVector.push_back( device ); + return index; + } +} + +void DeviceTracker::updateAll() +{ + for ( auto deviceIt = Singleton::get()->_devicesVector.begin(); deviceIt != Singleton::get()->_devicesVector.end(); deviceIt++ ) { + if ( (*deviceIt) ) + (*deviceIt)->update(); + } +} + +// Core features of the Device Tracker + +DeviceTracker::DeviceTracker() +{ +} + +DeviceTracker::~DeviceTracker() +{ +} + +bool DeviceTracker::isConnected() const +{ + return false; +} + +void DeviceTracker::update() +{ +} diff --git a/interface/src/devices/DeviceTracker.h b/interface/src/devices/DeviceTracker.h new file mode 100644 index 0000000000..e7e2d287dd --- /dev/null +++ b/interface/src/devices/DeviceTracker.h @@ -0,0 +1,91 @@ +// +// DeviceTracker.h +// interface/src/devices +// +// Created by Sam Cake on 6/20/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_DeviceTracker_h +#define hifi_DeviceTracker_h + +#include +#include + +//-------------------------------------------------------------------------------------- +// Singleton template class +//-------------------------------------------------------------------------------------- +template < class T > +class TemplateSingleton +{ + static TemplateSingleton< T > _singleton; + T* _one; + +public: + + static T* get() + { + if ( !_singleton._one ) { + _singleton._one = new T(); + } + return _singleton._one; + } + + TemplateSingleton() : + _one(0) + { + } + ~TemplateSingleton() + { + if ( _one ) { + delete _one; + _one = 0; + } + } +}; + +/// Base class for device trackers. +class DeviceTracker : public QObject { + Q_OBJECT +public: + + typedef std::string Name; + typedef qint64 Stamp; + + // Singleton interface to register and query the Devices currently connected + + static int init(); + static int getNumDevices(); + static int getDeviceIndex( const Name& name ); + static DeviceTracker* getDevice( int deviceNum ); + static DeviceTracker* getDevice( const Name& name ); + + /// Update all the devices calling for their update() function + static void updateAll(); + + static int registerDevice( const Name& name, DeviceTracker* tracker ); + + // DeviceTracker interface + virtual bool isConnected() const; + virtual void update(); + +protected: + DeviceTracker(); + virtual ~DeviceTracker(); + +private: + + struct SingletonData + { + typedef std::map< Name, int > Map; + typedef std::vector< DeviceTracker* > Vector; + Map _devicesMap; + Vector _devicesVector; + }; + typedef TemplateSingleton< SingletonData > Singleton; +}; + +#endif // hifi_DeviceTracker_h diff --git a/interface/src/devices/HandTracker.cpp b/interface/src/devices/HandTracker.cpp new file mode 100644 index 0000000000..4d3e65fd04 --- /dev/null +++ b/interface/src/devices/HandTracker.cpp @@ -0,0 +1,16 @@ +// +// HandTracker.cpp +// interface/src/devices +// +// Created by Sam Cake on 6/10/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "HandTracker.h" + +HandTracker::HandTracker() { +} + diff --git a/interface/src/devices/HandTracker.h b/interface/src/devices/HandTracker.h new file mode 100644 index 0000000000..7dc26236da --- /dev/null +++ b/interface/src/devices/HandTracker.h @@ -0,0 +1,58 @@ +// +// HandTracker.h +// interface/src/devices +// +// Created by Sam Cake on 6/10/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_HandTracker_h +#define hifi_HandTracker_h + +#include +#include + +#include +#include + +/// Base class for face trackers (Faceshift, Visage, Faceplus). +class HandTracker { + +public: + + struct PalmData + { + glm::vec3 _translation; + glm::quat _rotation; + int _lastUpdate; + + PalmData() : + _translation(), + _rotation(), + _lastUpdate(0) + {} + }; + + enum Side + { + SIDE_LEFT =0, + SIDE_RIGHT, + SIDE_NUMSIDES, // Not a valid Side, the number of sides + }; + + HandTracker(); + + const glm::vec3& getPalmTranslation(Side side) const { return _palms[side]._translation; } + const glm::quat& getPalmRotation(Side side) const { return _palms[side]._rotation; } + bool isPalmActive(Side side) const { return _palms[side]._lastUpdate == 0; } + +protected: + + PalmData _palms[SIDE_NUMSIDES]; + +}; + +#endif // hifi_HandTracker_h diff --git a/interface/src/devices/LeapMotionManager.cpp b/interface/src/devices/Leapmotion.cpp similarity index 53% rename from interface/src/devices/LeapMotionManager.cpp rename to interface/src/devices/Leapmotion.cpp index 5b5e724b1e..267b4c5602 100644 --- a/interface/src/devices/LeapMotionManager.cpp +++ b/interface/src/devices/Leapmotion.cpp @@ -1,5 +1,5 @@ // -// LeapMotionManager.cpp +// Leapmotion.cpp // interface/src/devices // // Created by Sam Cake on 6/2/2014 @@ -15,56 +15,56 @@ #include #include "Application.h" -#include "LeapMotionManager.h" +#include "Leapmotion.h" #include "ui/TextRenderer.h" #ifdef HAVE_LEAPMOTION -LeapMotionManager::SampleListener::SampleListener() : ::Leap::Listener() +Leapmotion::SampleListener::SampleListener() : ::Leap::Listener() { // std::cout << __FUNCTION__ << std::endl; } -LeapMotionManager::SampleListener::~SampleListener() +Leapmotion::SampleListener::~SampleListener() { // std::cout << __FUNCTION__ << std::endl; } -void LeapMotionManager::SampleListener::onConnect(const ::Leap::Controller &) +void Leapmotion::SampleListener::onConnect(const ::Leap::Controller &) { // std::cout << __FUNCTION__ << std::endl; } -void LeapMotionManager::SampleListener::onDisconnect(const ::Leap::Controller &) +void Leapmotion::SampleListener::onDisconnect(const ::Leap::Controller &) { // std::cout << __FUNCTION__ << std::endl; } -void LeapMotionManager::SampleListener::onExit(const ::Leap::Controller &) +void Leapmotion::SampleListener::onExit(const ::Leap::Controller &) { // std::cout << __FUNCTION__ << std::endl; } -void LeapMotionManager::SampleListener::onFocusGained(const ::Leap::Controller &) +void Leapmotion::SampleListener::onFocusGained(const ::Leap::Controller &) { // std::cout << __FUNCTION__ << std::endl; } -void LeapMotionManager::SampleListener::onFocusLost(const ::Leap::Controller &) +void Leapmotion::SampleListener::onFocusLost(const ::Leap::Controller &) { // std::cout << __FUNCTION__ << std::endl; } -void LeapMotionManager::SampleListener::onFrame(const ::Leap::Controller &) +void Leapmotion::SampleListener::onFrame(const ::Leap::Controller &) { // std::cout << __FUNCTION__ << std::endl; } -void LeapMotionManager::SampleListener::onInit(const ::Leap::Controller &) +void Leapmotion::SampleListener::onInit(const ::Leap::Controller &) { // std::cout << __FUNCTION__ << std::endl; } -void LeapMotionManager::SampleListener::onServiceConnect(const ::Leap::Controller &) +void Leapmotion::SampleListener::onServiceConnect(const ::Leap::Controller &) { // std::cout << __FUNCTION__ << std::endl; } -void LeapMotionManager::SampleListener::onServiceDisconnect(const ::Leap::Controller &) +void Leapmotion::SampleListener::onServiceDisconnect(const ::Leap::Controller &) { // std::cout << __FUNCTION__ << std::endl; } @@ -177,55 +177,109 @@ const float LEAP_Y = 0.3f; // meters const float LEAP_Z = 0.3f; // meters #endif -LeapMotionManager::LeapMotionManager() { +const int FINGER_NUM_JOINTS = 4; +const int HAND_NUM_JOINTS = FINGER_NUM_JOINTS*5+1; + +Leapmotion::Leapmotion() : + MotionTracker(), + _enabled(false), + _active(false) +{ #ifdef HAVE_LEAPMOTION // Have the sample listener receive events from the controller _controller.addListener(_listener); - // By default we assume the _neckBase (in orb frame) is as high above the orb - // as the "torso" is below it. - _leapBasePos = glm::vec3(0, -LEAP_Y, LEAP_Z); - - glm::vec3 xAxis(1.f, 0.f, 0.f); - glm::vec3 yAxis(0.f, 1.f, 0.f); - glm::vec3 zAxis = glm::normalize(glm::cross(xAxis, yAxis)); - xAxis = glm::normalize(glm::cross(yAxis, zAxis)); - _leapBaseOri = glm::inverse(glm::quat_cast(glm::mat3(xAxis, yAxis, zAxis))); + reset(); #endif + + // Create the Leapmotion joint hierarchy + { + std::vector< Semantic > hands; + hands.push_back( "Left" ); + hands.push_back( "Right" ); + + std::vector< Semantic > fingers; + fingers.push_back( "Thumb" ); + fingers.push_back( "Index" ); + fingers.push_back( "Middle" ); + fingers.push_back( "Ring" ); + fingers.push_back( "Pinky" ); + + std::vector< Semantic > fingerBones; +/* fingerBones.push_back( "Metacarpal" ); + fingerBones.push_back( "Proximal" ); + fingerBones.push_back( "Intermediate" ); + fingerBones.push_back( "Distal" ); +*/ + fingerBones.push_back( "1" ); + fingerBones.push_back( "2" ); + fingerBones.push_back( "3" ); + fingerBones.push_back( "4" ); + + std::vector< Index > palms; + for ( int h = 0; h < hands.size(); h++ ) { + Index rootJoint = addJoint( hands[h] + "Hand", 0 ); + palms.push_back( rootJoint ); + + for ( int f = 0; f < fingers.size(); f++ ) { + for ( int b = 0; b < fingerBones.size(); b++ ) { + rootJoint = addJoint( hands[h] + "Hand" + fingers[f] + fingerBones[b], rootJoint ); + } + } + } + } } -LeapMotionManager::~LeapMotionManager() { +Leapmotion::~Leapmotion() { #ifdef HAVE_LEAPMOTION // Remove the sample listener when done _controller.removeListener(_listener); #endif } -const int HEAD_ROTATION_INDEX = 0; -glm::vec3 LeapMotionManager::getHandPos( unsigned int handNb ) const -{ - if ( handNb < _hands.size() ) - { - return _hands[ handNb ]; - } - else - return glm::vec3(0.f); +void Leapmotion::init() { + // connect(Application::getInstance()->getFaceshift(), SIGNAL(connectionStateChanged()), SLOT(updateEnabled())); + updateEnabled(); } -void LeapMotionManager::update(float deltaTime) { #ifdef HAVE_LEAPMOTION +glm::quat quatFromLeapBase( float sideSign, const Leap::Matrix& basis ) { - if ( !_controller.isConnected() ) + glm::vec3 xAxis = glm::normalize( sideSign * glm::vec3( basis.xBasis.x, basis.xBasis.y, basis.xBasis.z) ); + glm::vec3 yAxis = glm::normalize( glm::vec3( basis.yBasis.x, basis.yBasis.y, basis.yBasis.z) ); + glm::vec3 zAxis = glm::normalize( glm::vec3( basis.zBasis.x, basis.zBasis.y, basis.zBasis.z) ); + + glm::quat orientation = /* glm::inverse*/ (glm::quat_cast(glm::mat3(xAxis, yAxis, zAxis))); + + return orientation; +} + +glm::vec3 vec3FromLeapVector( const Leap::Vector& vec ) { + return glm::vec3( vec.x * METERS_PER_MILLIMETER, vec.y * METERS_PER_MILLIMETER, vec.z * METERS_PER_MILLIMETER ); +} + +#endif + +void Leapmotion::update() { +#ifdef HAVE_LEAPMOTION + _active = _controller.isConnected(); + if (!_active) { return; + } + // go through all the joints and increment their counter since last update + for ( auto jointIt = _jointsArray.begin(); jointIt != _jointsArray.end(); jointIt++ ) { + (*jointIt).tickNewFrame(); + } + + float deltaTime = 0.001f; // Get the most recent frame and report some basic information const Leap::Frame frame = _controller.frame(); static _int64 lastFrame = -1; - _hands.clear(); _int64 newFrameNb = frame.id(); if ( (lastFrame >= newFrameNb) ) @@ -233,135 +287,64 @@ void LeapMotionManager::update(float deltaTime) { glm::vec3 delta(0.f); glm::quat handOri; - if (!frame.hands().isEmpty()) - { - // Get the first hand - const Leap::Hand hand = frame.hands()[0]; - Leap::Vector lp = hand.palmPosition(); - glm::vec3 p(lp.x * METERS_PER_MILLIMETER, lp.y * METERS_PER_MILLIMETER, lp.z * METERS_PER_MILLIMETER ); + if ( !frame.hands().isEmpty() ) { + for ( int handNum = 0; handNum < frame.hands().count(); handNum++ ) { + // Get the first hand + const Leap::Hand hand = frame.hands()[handNum]; + int side = ( hand.isRight() ? -1 : 1 ); + Index handIndex = 1 + ((1 - side)/2) * HAND_NUM_JOINTS; - Leap::Vector n = hand.palmNormal(); - glm::vec3 xAxis(n.x, n.y, n.z); - glm::vec3 yAxis(0.f, 1.f, 0.f); - glm::vec3 zAxis = glm::normalize(glm::cross(xAxis, yAxis)); - xAxis = glm::normalize(glm::cross(yAxis, zAxis)); - handOri = glm::inverse(glm::quat_cast(glm::mat3(xAxis, yAxis, zAxis))); + glm::vec3 pos = vec3FromLeapVector(hand.palmPosition()); + glm::quat ori = quatFromLeapBase(float(side), hand.basis() ); - _hands.push_back( p ); + JointTracker* palmJoint = editJointTracker( handIndex ); + palmJoint->editLocFrame().setTranslation( pos ); + palmJoint->editLocFrame().setRotation( ori ); + palmJoint->editAbsFrame().setTranslation( pos ); + palmJoint->editAbsFrame().setRotation( ori ); + palmJoint->activeFrame(); + + // Transform the measured position into body frame. + glm::vec3 neck = _leapBasePos; + // Zeroing y component of the "neck" effectively raises the measured position a little bit. + //neck.y = 0.f; + pos = _leapBaseOri * (pos - neck); - //Leap::Vector dp = hand.translation( _controller.frame( lastFrame ) ); - Leap::Vector dp = hand.palmVelocity(); - delta = glm::vec3( dp.x * METERS_PER_MILLIMETER, dp.y * METERS_PER_MILLIMETER, dp.z * METERS_PER_MILLIMETER); + // Check if the hand has any fingers + const Leap::FingerList fingers = hand.fingers(); + if (!fingers.isEmpty()) { + // For every fingers in the list + for (int i = 0; i < fingers.count(); ++i) { + // Reset the parent joint to the palmJoint for every finger traversal + JointTracker* parentJointTracker = palmJoint; + + // surprisingly, Leap::Finger::Type start at 0 for thumb a until 4 for the pinky + Index fingerIndex = handIndex + 1 + Index(fingers[i].type()) * FINGER_NUM_JOINTS; + + // let's update the finger's joints + for ( int b = 0; b < FINGER_NUM_JOINTS; b++ ) { + Leap::Bone::Type type = Leap::Bone::Type(b + Leap::Bone::TYPE_METACARPAL); + Leap::Bone bone = fingers[i].bone( type ); + JointTracker* ljointTracker = editJointTracker( fingerIndex + b ); + if ( bone.isValid() ) { + Leap::Vector bp = bone.nextJoint(); + + ljointTracker->editAbsFrame().setTranslation( vec3FromLeapVector( bp ) ); + ljointTracker->editAbsFrame().setRotation(quatFromLeapBase( float(side), bone.basis() ) ); + ljointTracker->updateLocFromAbsTransform( parentJointTracker ); + ljointTracker->activeFrame(); + } + parentJointTracker = ljointTracker; + } + } + } + } } + lastFrame = newFrameNb; - MyAvatar* avatar = Application::getInstance()->getAvatar(); - Hand* hand = avatar->getHand(); -// for ( int h = 0; h < frame.hands().count(); h++ ) - if ( _hands.size() ) - { - - // Set palm position and normal based on Hydra position/orientation - - // Either find a palm matching the sixense controller, or make a new one - PalmData* palm; - bool foundHand = false; - for (size_t j = 0; j < hand->getNumPalms(); j++) { - if (hand->getPalms()[j].getSixenseID() == 28) { - palm = &(hand->getPalms()[j]); - foundHand = true; - } - } - if (!foundHand) { - PalmData newPalm(hand); - hand->getPalms().push_back(newPalm); - palm = &(hand->getPalms()[hand->getNumPalms() - 1]); - palm->setSixenseID(28); - qDebug("Found new LeapMotion hand, ID %i", 28); - } - - palm->setActive(true); - - // Read controller buttons and joystick into the hand - //palm->setControllerButtons(data->buttons); - //palm->setTrigger(data->trigger); - //palm->setJoystick(data->joystick_x, data->joystick_y); - - glm::vec3 position(_hands[0]); - - // Transform the measured position into body frame. - glm::vec3 neck = _leapBasePos; - // Zeroing y component of the "neck" effectively raises the measured position a little bit. - //neck.y = 0.f; - position = _leapBaseOri * (position - neck); - - // Rotation of Palm - glm::quat rotation(handOri[3], -handOri[0], handOri[1], -handOri[2]); - rotation = glm::angleAxis(PI, glm::vec3(0.f, 1.f, 0.f)) * _leapBaseOri * rotation; - - // Compute current velocity from position change - glm::vec3 rawVelocity; - if (deltaTime > 0.f) { - // rawVelocity = (position - palm->getRawPosition()) / deltaTime; - rawVelocity = delta / deltaTime; - } else { - rawVelocity = glm::vec3(0.0f); - } - palm->setRawVelocity(rawVelocity); // meters/sec - - // Use a velocity sensitive filter to damp small motions and preserve large ones with - // no latency. - float velocityFilter = glm::clamp(1.0f - glm::length(rawVelocity), 0.0f, 1.0f); - palm->setRawPosition(palm->getRawPosition() * velocityFilter + position * (1.0f - velocityFilter)); - palm->setRawRotation(safeMix(palm->getRawRotation(), rotation, 1.0f - velocityFilter)); - - // use the velocity to determine whether there's any movement (if the hand isn't new) - /* const float MOVEMENT_DISTANCE_THRESHOLD = 0.003f; - _amountMoved += rawVelocity * deltaTime; - if (glm::length(_amountMoved) > MOVEMENT_DISTANCE_THRESHOLD && foundHand) { - _lastMovement = usecTimestampNow(); - _amountMoved = glm::vec3(0.0f); - }*/ - - // Store the one fingertip in the palm structure so we can track velocity - /* const float FINGER_LENGTH = 0.3f; // meters - const glm::vec3 FINGER_VECTOR(0.0f, 0.0f, FINGER_LENGTH); - const glm::vec3 newTipPosition = position + rotation * FINGER_VECTOR; - glm::vec3 oldTipPosition = palm->getTipRawPosition(); - if (deltaTime > 0.f) { - palm->setTipVelocity((newTipPosition - oldTipPosition) / deltaTime); - } else { - palm->setTipVelocity(glm::vec3(0.f)); - } - palm->setTipPosition(newTipPosition);*/ - } - else - { - // Either find a palm matching the sixense controller, or make a new one - PalmData* palm; - bool foundHand = false; - for (size_t j = 0; j < hand->getNumPalms(); j++) { - if (hand->getPalms()[j].getSixenseID() == 28) { - palm = &(hand->getPalms()[j]); - foundHand = true; - } - } - if (foundHand) { - palm->setRawPosition(palm->getRawPosition()); - palm->setRawRotation(palm->getRawRotation()); - palm->setActive(false); - } - } - - - /* if (numActiveControllers == 2) { - updateCalibration(controllers); - } - */ - - // } if ( false ) { @@ -411,31 +394,29 @@ void LeapMotionManager::update(float deltaTime) { #endif } -void LeapMotionManager::reset() { -#ifdef HAVE_LEAPMOTION - if (!_controller.isConnected()) { - return; - } - /* connect(Application::getInstance(), SIGNAL(renderingOverlay()), SLOT(renderCalibrationCountdown())); - _calibrationCountdownStarted = QDateTime::currentDateTime(); - */ -#endif +void Leapmotion::reset() { + // By default we assume the _neckBase (in orb frame) is as high above the orb + // as the "torso" is below it. + _leapBasePos = glm::vec3(0, -LEAP_Y, LEAP_Z); + + glm::vec3 xAxis(1.f, 0.f, 0.f); + glm::vec3 yAxis(0.f, 1.f, 0.f); + glm::vec3 zAxis = glm::normalize(glm::cross(xAxis, yAxis)); + xAxis = glm::normalize(glm::cross(yAxis, zAxis)); + _leapBaseOri = glm::inverse(glm::quat_cast(glm::mat3(xAxis, yAxis, zAxis))); } -void LeapMotionManager::renderCalibrationCountdown() { +void Leapmotion::updateEnabled() { + /* setEnabled(Menu::getInstance()->isOptionChecked(MenuOption::Visage) && + !Menu::getInstance()->isOptionChecked(MenuOption::Faceplus) && + !(Menu::getInstance()->isOptionChecked(MenuOption::Faceshift) && + Application::getInstance()->getFaceshift()->isConnectedOrConnecting()));*/ +} + +void Leapmotion::setEnabled(bool enabled) { #ifdef HAVE_LEAPMOTION - /* const int COUNTDOWN_SECONDS = 3; - int secondsRemaining = COUNTDOWN_SECONDS - _calibrationCountdownStarted.secsTo(QDateTime::currentDateTime()); - if (secondsRemaining == 0) { - yei_tareSensors(_skeletalDevice); - Application::getInstance()->disconnect(this); + if (_enabled == enabled) { return; } - static TextRenderer textRenderer(MONO_FONT_FAMILY, 18, QFont::Bold, false, TextRenderer::OUTLINE_EFFECT, 2); - QByteArray text = "Assume T-Pose in " + QByteArray::number(secondsRemaining) + "..."; - textRenderer.draw((Application::getInstance()->getGLWidget()->width() - textRenderer.computeWidth(text.constData())) / 2, - Application::getInstance()->getGLWidget()->height() / 2, - text); - */ -#endif +#endif } diff --git a/interface/src/devices/LeapMotionManager.h b/interface/src/devices/Leapmotion.h similarity index 54% rename from interface/src/devices/LeapMotionManager.h rename to interface/src/devices/Leapmotion.h index 2aaddc555e..8ae7ed71a4 100644 --- a/interface/src/devices/LeapMotionManager.h +++ b/interface/src/devices/Leapmotion.h @@ -1,5 +1,5 @@ // -// LeapMotionManager.h +// Leapmotion.h // interface/src/devices // // Created by Sam Cake on 6/2/2014 @@ -9,46 +9,37 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#ifndef hifi_LeapMotionManager_h -#define hifi_LeapMotionManager_h +#ifndef hifi_Leapmotion_h +#define hifi_Leapmotion_h #include -#include -#include -#include +#include "HandTracker.h" +#include "MotionTracker.h" #ifdef HAVE_LEAPMOTION #include -/*extern "C" { -#include -}*/ #endif -/// Handles interaction with the LeapMotionManager skeleton tracking suit. -class LeapMotionManager : public QObject { +/// Handles interaction with the Leapmotion skeleton tracking suit. +class Leapmotion : public MotionTracker { Q_OBJECT public: + + Leapmotion(); + virtual ~Leapmotion(); + + void init(); + + bool isActive() const { return _active; } - LeapMotionManager(); - virtual ~LeapMotionManager(); - - bool isActive() const { return !_hands.isEmpty(); } - - int nbHands() const { return _hands.size(); } - - glm::vec3 getHandPos( unsigned int handNb ) const; - - const QVector& getHumanIKJointIndices() const { return _humanIKJointIndices; } - const QVector& getJointRotations() const { return _jointRotations; } - - void update(float deltaTime); + void update(); void reset(); -private slots: +public slots: - void renderCalibrationCountdown(); + void updateEnabled(); private: #ifdef HAVE_LEAPMOTION @@ -76,13 +67,11 @@ private: #endif glm::vec3 _leapBasePos; glm::quat _leapBaseOri; - QVector _hands; - QVector _humanIKJointIndices; - QVector _jointRotations; - QVector _lastJointRotations; - - QDateTime _calibrationCountdownStarted; + void setEnabled(bool enabled); + + bool _enabled; + bool _active; }; -#endif // hifi_LeapMotionManager_h +#endif // hifi_Leapmotion_h diff --git a/interface/src/devices/MotionTracker.cpp b/interface/src/devices/MotionTracker.cpp new file mode 100644 index 0000000000..2e60d5c175 --- /dev/null +++ b/interface/src/devices/MotionTracker.cpp @@ -0,0 +1,200 @@ +// +// MotionTracker.cpp +// interface/src/devices +// +// Created by Sam Cake on 6/20/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "MotionTracker.h" + + +//-------------------------------------------------------------------------------------- +// glm::mult( mat43, mat43 ) just the composition of the 2 matrices assuming they are in fact mat44 with the last raw = { 0, 0, 0, 1 } +//-------------------------------------------------------------------------------------- +namespace glm { + mat4x3 mult( const mat4& lhs, const mat4x3& rhs ) { + vec3 lrx( lhs[0].x, lhs[1].x, lhs[2].x ); + vec3 lry( lhs[0].y, lhs[1].y, lhs[2].y ); + vec3 lrz( lhs[0].z, lhs[1].z, lhs[2].z ); + return mat4x3( + dot( lrx, rhs[0] ), + dot( lry, rhs[0] ), + dot( lrz, rhs[0] ), + + dot( lrx, rhs[1] ), + dot( lry, rhs[1] ), + dot( lrz, rhs[1] ), + + dot( lrx, rhs[2] ), + dot( lry, rhs[2] ), + dot( lrz, rhs[2] ), + + dot( lrx, rhs[3] ) + lhs[3].x, + dot( lry, rhs[3] ) + lhs[3].y, + dot( lrz, rhs[3] ) + lhs[3].z + ); + } + mat4x3 mult( const mat4x3& lhs, const mat4x3& rhs ) { + vec3 lrx( lhs[0].x, lhs[1].x, lhs[2].x ); + vec3 lry( lhs[0].y, lhs[1].y, lhs[2].y ); + vec3 lrz( lhs[0].z, lhs[1].z, lhs[2].z ); + return mat4x3( + dot( lrx, rhs[0] ), + dot( lry, rhs[0] ), + dot( lrz, rhs[0] ), + + dot( lrx, rhs[1] ), + dot( lry, rhs[1] ), + dot( lrz, rhs[1] ), + + dot( lrx, rhs[2] ), + dot( lry, rhs[2] ), + dot( lrz, rhs[2] ), + + dot( lrx, rhs[3] ) + lhs[3].x, + dot( lry, rhs[3] ) + lhs[3].y, + dot( lrz, rhs[3] ) + lhs[3].z + ); + } +} + +//-------------------------------------------------------------------------------------- +// MotionTracker +//-------------------------------------------------------------------------------------- +MotionTracker::MotionTracker() : + DeviceTracker() +{ + _jointsArray.resize(1); + _jointsMap.insert( JointTracker::map::value_type( Semantic( "Root" ), 0 ) ); +} + +MotionTracker::~MotionTracker() +{ +} + +bool MotionTracker::isConnected() const +{ + return false; +} + +MotionTracker::Index MotionTracker::addJoint( const Semantic& semantic, Index parent ) +{ + // Check the parent + if ( int(parent) < 0 ) + return INVALID_PARENT; + + // Check that the semantic is not already in use + Index foundIndex = findJointIndex( semantic ); + if ( int(foundIndex) >= 0 ) + return INVALID_SEMANTIC; + + // All good then allocate the joint + Index newIndex = _jointsArray.size(); + _jointsArray.push_back( JointTracker( semantic, parent ) ); + _jointsMap.insert( JointTracker::map::value_type( semantic, newIndex ) ); + + return newIndex; +} + +MotionTracker::Index MotionTracker::findJointIndex( const Semantic& semantic ) const +{ + auto jointIt = _jointsMap.find( semantic ); + if ( jointIt != _jointsMap.end() ) + return (*jointIt).second; + return INVALID_SEMANTIC; +} + +void MotionTracker::updateAllAbsTransform() +{ + _jointsArray[0].updateAbsFromLocTransform( 0 ); + + // Because we know the hierarchy is stored from root down the branches let's just traverse and update + for ( Index i = 1; i < _jointsArray.size(); i++ ) { + JointTracker* joint = _jointsArray.data() + i; + joint->updateAbsFromLocTransform( _jointsArray.data() + joint->getParent() ); + } +} + +//-------------------------------------------------------------------------------------- +// MotionTracker::JointTracker +//-------------------------------------------------------------------------------------- + +MotionTracker::JointTracker::JointTracker() : + _locFrame(), + _absFrame(), + _semantic(""), + _parent(INVALID_PARENT), + _lastUpdate(0) +{ +} + +MotionTracker::JointTracker::JointTracker( const Semantic& semantic, Index parent ) : + _semantic( semantic ), + _parent( parent ), + _lastUpdate( 0 ) +{ +} + +MotionTracker::JointTracker::JointTracker( const JointTracker& tracker ) : + _locFrame( tracker._locFrame ), + _absFrame( tracker._absFrame ), + _semantic( tracker._semantic ), + _parent( tracker._parent ), + _lastUpdate( tracker._lastUpdate ) +{ +} +void MotionTracker::JointTracker::updateAbsFromLocTransform(const JointTracker* parentJoint) +{ + if ( parentJoint ) { + editAbsFrame()._transform = glm::mult( parentJoint->getAbsFrame()._transform, getLocFrame()._transform ); + } else { + editAbsFrame()._transform = getLocFrame()._transform; + } +} + +void MotionTracker::JointTracker::updateLocFromAbsTransform(const JointTracker* parentJoint) +{ + if ( parentJoint ) { + glm::mat4 ip = glm::inverse( glm::mat4( parentJoint->getAbsFrame()._transform ) ); + editLocFrame()._transform = glm::mult( ip, getAbsFrame()._transform ); + } else { + editLocFrame()._transform = getAbsFrame()._transform; + } +} + +//-------------------------------------------------------------------------------------- +// MotionTracker::Frame +//-------------------------------------------------------------------------------------- + +MotionTracker::Frame::Frame() : + _transform() +{ +} + +void MotionTracker::Frame::setRotation( const glm::quat& rotation ) +{ + glm::mat3x3 rot = glm::mat3_cast( rotation ); + _transform[0] = rot[0]; + _transform[1] = rot[1]; + _transform[2] = rot[2]; +} + +void MotionTracker::Frame::getRotation( glm::quat& rotation ) const +{ + rotation = glm::quat_cast( glm::mat3( _transform[0], _transform[1], _transform[2] ) ); +} + +void MotionTracker::Frame::setTranslation( const glm::vec3& translation ) +{ + _transform[3] = translation; +} + +void MotionTracker::Frame::getTranslation( glm::vec3& translation ) const +{ + translation = _transform[3]; +} + diff --git a/interface/src/devices/MotionTracker.h b/interface/src/devices/MotionTracker.h new file mode 100644 index 0000000000..f9aa91677b --- /dev/null +++ b/interface/src/devices/MotionTracker.h @@ -0,0 +1,130 @@ +// +// MotionTracker.h +// interface/src/devices +// +// Created by Sam Cake on 6/20/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_MotionTracker_h +#define hifi_MotionTracker_h + +#include "DeviceTracker.h" + +#include + +#include +#include +#include + +/// Base class for device trackers. +class MotionTracker : public DeviceTracker { + Q_OBJECT +public: + + class Frame + { + public: + Frame(); + + glm::mat4x3 _transform; + + void setRotation( const glm::quat& rotation ); + void getRotation( glm::quat& rotation ) const; + + void setTranslation( const glm::vec3& translation ); + void getTranslation( glm::vec3& translation ) const; + }; + + typedef std::string Semantic; + typedef unsigned int Index; + + static const Index INVALID_SEMANTIC = -1; + static const Index INVALID_PARENT = -2; + + + class JointTracker + { + public: + typedef std::vector< JointTracker > vector; + typedef std::map< Semantic, Index > map; + + JointTracker(); + JointTracker( const JointTracker& tracker ); + JointTracker( const Semantic& semantic, Index parent ); + + const Frame& getLocFrame() const { return _locFrame; } + Frame& editLocFrame() { return _locFrame; } + void setLocFrame( const Frame& frame ) { editLocFrame() = frame; } + + const Frame& getAbsFrame() const { return _absFrame; } + Frame& editAbsFrame() { return _absFrame; } + void setAbsFrame( const Frame& frame ) { editAbsFrame() = frame; } + + const Semantic& getSemantic() const { return _semantic; } + const Index& getParent() const { return _parent; } + + bool isActive() const { return (_lastUpdate <= 0); } + void tickNewFrame() { _lastUpdate++; } + void activeFrame() { _lastUpdate = 0; } + + /// Update the loc/abs transform for this joint from the current abs/loc value and the specified parent joint abs frame + void updateLocFromAbsTransform(const JointTracker* parentJoint); + void updateAbsFromLocTransform(const JointTracker* parentJoint); + + protected: + Frame _locFrame; + Frame _absFrame; + Semantic _semantic; + Index _parent; + int _lastUpdate; + }; + + + virtual bool isConnected() const; + + Index numJointTrackers() const { return _jointsArray.size(); } + + + + /// Access a Joint from it's index. + /// Index 0 is always the "Root". + /// if the index is Invalid then returns NULL. + const JointTracker* getJointTracker( Index index ) const { return ( int(index) < _jointsArray.size() ? _jointsArray.data() + index : NULL ); } + JointTracker* editJointTracker( Index index ) { return ( int(index) < _jointsArray.size() ? _jointsArray.data() + index : NULL ); } + + /// From a semantic, find the Index of the Joint. + /// \return the index of the mapped Joint or INVALID_SEMANTIC if the semantic is not knowned. + Index findJointIndex( const Semantic& semantic ) const; + +protected: + MotionTracker(); + virtual ~MotionTracker(); + + JointTracker::vector _jointsArray; + JointTracker::map _jointsMap; + + /// Adding joint is only done from the specialized Motion Tracker, hence this function is protected. + /// The hierarchy of joints must be created from the top down to the branches. + /// The "Root" node is at index 0 and exists at creation of the Motion Tracker. + /// + /// \param semantic A joint is defined by it's semantic, the unique name mapping to it + /// \param parent The parent's index, the parent must be valid and correspond to a Joint that has been previously created + /// + /// \return The Index of the newly created Joint. + /// Valid if everything went well. + /// INVALID_SEMANTIC if the semantic is already in use + /// INVALID_PARENT if the parent is not valid + Index addJoint( const Semantic& semantic, Index parent ); + + /// Update the absolute transform stack traversing the hierarchy from the root down the branches + /// This is a generic way to update all the Joint's absFrame by combining the locFrame going down the hierarchy branch. + void updateAllAbsTransform(); +}; + + + +#endif // hifi_MotionTracker_h diff --git a/interface/src/scripting/ControllerScriptingInterface.cpp b/interface/src/scripting/ControllerScriptingInterface.cpp index 34c1cc2f1c..44f39b1684 100644 --- a/interface/src/scripting/ControllerScriptingInterface.cpp +++ b/interface/src/scripting/ControllerScriptingInterface.cpp @@ -13,6 +13,7 @@ #include "Application.h" #include "devices/SixenseManager.h" #include "ControllerScriptingInterface.h" +#include "devices/MotionTracker.h" ControllerScriptingInterface::ControllerScriptingInterface() : _mouseCaptured(false), @@ -258,3 +259,73 @@ glm::vec2 ControllerScriptingInterface::getViewportDimensions() const { QGLWidget* widget = Application::getInstance()->getGLWidget(); return glm::vec2(widget->width(), widget->height()); } + +AbstractInputController* ControllerScriptingInterface::createInputController( const QString& category, const QString& tracker ) +{ + // This is where we retreive the Device Tracker category and then the sub tracker within it + auto icIt = _inputControllers.find( 0 ); + if ( icIt != _inputControllers.end() ) { + return (*icIt).second; + } else { + + // Look for matching category + int categoryID = 0; + MotionTracker* motionTracker = dynamic_cast< MotionTracker* > ( DeviceTracker::getDevice( categoryID ) ); + if ( motionTracker ) + { + int trackerID = motionTracker->findJointIndex( tracker.toStdString() ); + if ( trackerID > 0 ) + { + AbstractInputController* inputController = new InputController(categoryID,trackerID, this ); + + _inputControllers.insert( InputControllerMap::value_type( inputController->getKey(), inputController ) ); + + return inputController; + } + } + return 0; + } +} + +void ControllerScriptingInterface::updateInputControllers() +{ + for ( auto it = _inputControllers.begin(); it != _inputControllers.end(); it++ ) { + (*it).second->update(); + } + +} + + +InputController::InputController(int deviceTrackerId, int subTrackerId, QObject* parent) : + AbstractInputController(), + _deviceTrackerId( deviceTrackerId ), + _subTrackerId( subTrackerId ) +{ +} + +void InputController::update() +{ + _isActive = false; + + MotionTracker* motionTracker = dynamic_cast< MotionTracker*> ( DeviceTracker::getDevice( _deviceTrackerId ) ); + if ( motionTracker ) { + if ( _subTrackerId < motionTracker->numJointTrackers() ) { + const MotionTracker::JointTracker* joint = motionTracker->getJointTracker( _subTrackerId ); + + if ( joint->isActive() ) { + joint->getAbsFrame().getTranslation( _eventCache.absTranslation ); + joint->getAbsFrame().getRotation( _eventCache.absRotation ); + joint->getLocFrame().getTranslation( _eventCache.locTranslation ); + joint->getLocFrame().getRotation( _eventCache.locRotation ); + + _isActive = true; + emit spatialEvent(_eventCache); + } + } + } +} + + +InputController::Key InputController::getKey() const { + return (_deviceTrackerId * 10000) + _subTrackerId; +} diff --git a/interface/src/scripting/ControllerScriptingInterface.h b/interface/src/scripting/ControllerScriptingInterface.h index c5d805dca5..6d3613f16a 100644 --- a/interface/src/scripting/ControllerScriptingInterface.h +++ b/interface/src/scripting/ControllerScriptingInterface.h @@ -17,6 +17,38 @@ #include class PalmData; + +class InputController : public AbstractInputController { + Q_OBJECT + +public: + InputController(int deviceTrackerId, int subTrackerId, QObject* parent = NULL); + + virtual void update(); + virtual Key getKey() const; + +public slots: + + virtual bool isActive() const { return _isActive; } + virtual glm::vec3 getAbsTranslation() const { return _eventCache.absTranslation; } + virtual glm::quat getAbsRotation() const { return _eventCache.absRotation; } + virtual glm::vec3 getLocTranslation() const { return _eventCache.locTranslation; } + virtual glm::quat getLocRotation() const { return _eventCache.locRotation; } + +private: + + int _deviceTrackerId; + int _subTrackerId; + + // cache for the spatial + SpatialEvent _eventCache; + bool _isActive; + + +signals: +}; + + /// handles scripting of input controller commands from JS class ControllerScriptingInterface : public AbstractControllerScriptingInterface { Q_OBJECT @@ -43,6 +75,10 @@ public: bool isWheelCaptured() const { return _wheelCaptured; } bool isJoystickCaptured(int joystickIndex) const; + void updateInputControllers(); + + void releaseInputController( AbstractInputController* input ); + public slots: virtual bool isPrimaryButtonPressed() const; virtual glm::vec2 getPrimaryJoystickPosition() const; @@ -78,6 +114,8 @@ public slots: virtual glm::vec2 getViewportDimensions() const; + virtual AbstractInputController* createInputController( const QString& category, const QString& tracker ); + private: const PalmData* getPrimaryPalm() const; const PalmData* getPalm(int palmIndex) const; @@ -89,6 +127,9 @@ private: bool _wheelCaptured; QMultiMap _capturedKeys; QSet _capturedJoysticks; + + typedef std::map< AbstractInputController::Key, AbstractInputController* > InputControllerMap; + InputControllerMap _inputControllers; }; const int NUMBER_OF_SPATIALCONTROLS_PER_PALM = 2; // the hand and the tip @@ -98,4 +139,5 @@ const int NUMBER_OF_BUTTONS_PER_PALM = 6; const int PALM_SPATIALCONTROL = 0; const int TIP_SPATIALCONTROL = 1; + #endif // hifi_ControllerScriptingInterface_h diff --git a/libraries/script-engine/src/AbstractControllerScriptingInterface.h b/libraries/script-engine/src/AbstractControllerScriptingInterface.h index 677ca27e04..1f58e5f5c9 100644 --- a/libraries/script-engine/src/AbstractControllerScriptingInterface.h +++ b/libraries/script-engine/src/AbstractControllerScriptingInterface.h @@ -19,6 +19,28 @@ #include "EventTypes.h" +class AbstractInputController : public QObject { + Q_OBJECT + +public: + typedef unsigned int Key; + + virtual void update() = 0; + + virtual Key getKey() const = 0; + +public slots: + + virtual bool isActive() const = 0; + virtual glm::vec3 getAbsTranslation() const = 0; + virtual glm::quat getAbsRotation() const = 0; + virtual glm::vec3 getLocTranslation() const = 0; + virtual glm::quat getLocRotation() const = 0; + +signals: + void spatialEvent(const SpatialEvent& event); + +}; /// handles scripting of input controller commands from JS class AbstractControllerScriptingInterface : public QObject { @@ -60,6 +82,9 @@ public slots: virtual glm::vec2 getViewportDimensions() const = 0; + + virtual AbstractInputController* createInputController( const QString& category, const QString& tracker ) = 0; + signals: void keyPressEvent(const KeyEvent& event); void keyReleaseEvent(const KeyEvent& event); diff --git a/libraries/script-engine/src/EventTypes.cpp b/libraries/script-engine/src/EventTypes.cpp index e785f53c19..3bd6303d02 100644 --- a/libraries/script-engine/src/EventTypes.cpp +++ b/libraries/script-engine/src/EventTypes.cpp @@ -19,6 +19,7 @@ void registerEventTypes(QScriptEngine* engine) { qScriptRegisterMetaType(engine, mouseEventToScriptValue, mouseEventFromScriptValue); qScriptRegisterMetaType(engine, touchEventToScriptValue, touchEventFromScriptValue); qScriptRegisterMetaType(engine, wheelEventToScriptValue, wheelEventFromScriptValue); + qScriptRegisterMetaType(engine, spatialEventToScriptValue, spatialEventFromScriptValue); } KeyEvent::KeyEvent() : @@ -600,3 +601,34 @@ void wheelEventFromScriptValue(const QScriptValue& object, WheelEvent& event) { } + +SpatialEvent::SpatialEvent() : + locTranslation(0.0f), + locRotation(), + absTranslation(0.0f), + absRotation() +{ +}; + +SpatialEvent::SpatialEvent(const SpatialEvent& event) { + locTranslation = event.locTranslation; + locRotation = event.locRotation; + absTranslation = event.absTranslation; + absRotation = event.absRotation; +} + + +QScriptValue spatialEventToScriptValue(QScriptEngine* engine, const SpatialEvent& event) { + QScriptValue obj = engine->newObject(); + + obj.setProperty("locTranslation", vec3toScriptValue(engine, event.locTranslation) ); + obj.setProperty("locRotation", quatToScriptValue(engine, event.locRotation) ); + obj.setProperty("absTranslation", vec3toScriptValue(engine, event.absTranslation) ); + obj.setProperty("absRotation", quatToScriptValue(engine, event.absRotation) ); + + return obj; +} + +void spatialEventFromScriptValue(const QScriptValue& object,SpatialEvent& event) { + // nothing for now... +} diff --git a/libraries/script-engine/src/EventTypes.h b/libraries/script-engine/src/EventTypes.h index 6994225fd7..ed7aabc3c9 100644 --- a/libraries/script-engine/src/EventTypes.h +++ b/libraries/script-engine/src/EventTypes.h @@ -13,6 +13,7 @@ #define hifi_EventTypes_h #include +#include #include @@ -107,10 +108,25 @@ public: bool isAlt; }; +class SpatialEvent { +public: + SpatialEvent(); + SpatialEvent(const SpatialEvent& other); + + glm::vec3 locTranslation; + glm::quat locRotation; + glm::vec3 absTranslation; + glm::quat absRotation; + +private: +}; + + Q_DECLARE_METATYPE(KeyEvent) Q_DECLARE_METATYPE(MouseEvent) Q_DECLARE_METATYPE(TouchEvent) Q_DECLARE_METATYPE(WheelEvent) +Q_DECLARE_METATYPE(SpatialEvent) void registerEventTypes(QScriptEngine* engine); @@ -126,4 +142,7 @@ void touchEventFromScriptValue(const QScriptValue& object, TouchEvent& event); QScriptValue wheelEventToScriptValue(QScriptEngine* engine, const WheelEvent& event); void wheelEventFromScriptValue(const QScriptValue& object, WheelEvent& event); +QScriptValue spatialEventToScriptValue(QScriptEngine* engine, const SpatialEvent& event); +void spatialEventFromScriptValue(const QScriptValue& object, SpatialEvent& event); + #endif // hifi_EventTypes_h diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index a4aae61248..85515edcb9 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -67,6 +67,14 @@ void injectorFromScriptValue(const QScriptValue &object, AudioInjector* &out) { out = qobject_cast(object.toQObject()); } +QScriptValue injectorToScriptValue_InputController(QScriptEngine *engine, AbstractInputController* const &in) { + return engine->newQObject(in); +} + +void injectorFromScriptValue_InputController(const QScriptValue &object, AbstractInputController* &out) { + out = qobject_cast(object.toQObject()); +} + ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNameString, AbstractControllerScriptingInterface* controllerScriptingInterface) : @@ -248,6 +256,7 @@ void ScriptEngine::init() { _engine.globalObject().setProperty("LocalVoxels", localVoxelsValue); qScriptRegisterMetaType(&_engine, injectorToScriptValue, injectorFromScriptValue); + qScriptRegisterMetaType( &_engine, injectorToScriptValue_InputController, injectorFromScriptValue_InputController); registerGlobalObject("Script", this); registerGlobalObject("Audio", &_audioScriptingInterface);