/****************************************************************************** * Copyright (C) Ultraleap, Inc. 2011-2024. * * * * Use subject to the terms of the Apache License 2.0 available at * * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * * between Ultraleap and you, your company or other organization. * ******************************************************************************/ using UnityEngine; namespace Leap { using LeapInternal; using System; /// /// The Device class represents a physically connected device. /// /// The Device class contains information related to a particular connected /// device such as device id, field of view relative to the device, /// and the position and orientation of the device in relative coordinates. /// /// The position and orientation describe the alignment of the device relative to the user. /// The alignment relative to the user is only descriptive. Aligning devices to users /// provides consistency in the parameters that describe user interactions. /// /// 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. /// @since 1.0 /// public class Device : IEquatable { /// /// Constructs a default Device object. /// /// Get valid Device objects from a DeviceList object obtained using the /// Controller.Devices() method. /// /// @since 1.0 /// public Device() { } public Device(IntPtr deviceHandle, IntPtr internalHandle, float horizontalViewAngle, float verticalViewAngle, float range, float baseline, DeviceType type, bool isStreaming, uint status, string serialNumber, uint deviceID) { Handle = deviceHandle; HorizontalViewAngle = horizontalViewAngle; VerticalViewAngle = verticalViewAngle; Range = range; Baseline = baseline; Type = type; IsStreaming = isStreaming; SerialNumber = serialNumber; DeviceID = deviceID; UpdateStatus((eLeapDeviceStatus)status); } public Device(IntPtr deviceHandle, IntPtr internalHandle, float horizontalViewAngle, float verticalViewAngle, float range, float baseline, DeviceType type, bool isStreaming, uint status, string serialNumber) : this(deviceHandle, internalHandle, horizontalViewAngle, verticalViewAngle, range, baseline, type, isStreaming, status, serialNumber, 0) { } /// /// For internal use only. /// public void Update( float horizontalViewAngle, float verticalViewAngle, float range, float baseline, uint status, string serialNumber) { HorizontalViewAngle = horizontalViewAngle; VerticalViewAngle = verticalViewAngle; Range = range; Baseline = baseline; SerialNumber = serialNumber; UpdateStatus((eLeapDeviceStatus)status); } /// /// For internal use only. /// public void Update(Device updatedDevice) { HorizontalViewAngle = updatedDevice.HorizontalViewAngle; VerticalViewAngle = updatedDevice.VerticalViewAngle; Range = updatedDevice.Range; Baseline = updatedDevice.Baseline; IsStreaming = updatedDevice.IsStreaming; SerialNumber = updatedDevice.SerialNumber; } /// /// Updates the status fields by parsing the uint given by the event /// internal void UpdateStatus(eLeapDeviceStatus status) { if ((status & eLeapDeviceStatus.eLeapDeviceStatus_Streaming) == eLeapDeviceStatus.eLeapDeviceStatus_Streaming) IsStreaming = true; else IsStreaming = false; if ((status & eLeapDeviceStatus.eLeapDeviceStatus_LowResource) == eLeapDeviceStatus.eLeapDeviceStatus_LowResource) IsLowResource = true; else IsLowResource = false; } /// /// For internal use only. /// public IntPtr Handle { get; private set; } [Obsolete("Use LeapC.SetLeapPause instead")] public bool SetPaused(bool pause) { return false; } /// /// Compare Device object equality. /// /// 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 /// public bool Equals(Device other) { return SerialNumber == other.SerialNumber; } /// /// A string containing a brief, human readable description of the Device object. /// @since 1.0 /// public override string ToString() { return "Device serial# " + this.SerialNumber; } /// /// The angle in radians of view along the x axis of this device. /// /// 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. /// /// @since 1.0 /// public float HorizontalViewAngle { get; private set; } /// /// The angle in radians of view along the z axis of this device. /// /// 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. /// /// @since 1.0 /// public float VerticalViewAngle { get; private set; } /// /// The maximum reliable tracking range from the center of this device. /// /// 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. /// /// @since 1.0 /// public float Range { get; private set; } /// /// The distance in mm between the center points of the stereo sensors. /// /// The baseline value, together with the maximum resolution, influence the /// maximum range. /// /// @since 2.2.5 /// public float Baseline { get; private set; } /// /// Reports whether this device is streaming data to your application. /// /// Currently only one controller can provide data at a time. /// @since 1.2 /// public bool IsStreaming { get; internal set; } /// /// 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. /// /// @since 1.2 /// public DeviceType Type { get; private set; } /// /// An alphanumeric serial number unique to each device. /// /// Consumer device serial numbers consist of 2 letters followed by 11 digits. /// /// When using multiple devices, the serial number provides an unambiguous /// identifier for each device. /// @since 2.2.2 /// public string SerialNumber { get; private set; } /// /// Reports the ID assoicated with the device /// public uint DeviceID { get; private set; } private bool poseSet = false; private Pose devicePose = Pose.identity; /// /// The transform to world coordinates from 3D Leap coordinates. /// public Pose DevicePose { get { if (poseSet) // Assumes the devicePose never changes and so, uses the cached pose. { return devicePose; } bool deviceTransformAvailable = LeapC.GetDeviceTransformAvailable(Handle); if (!deviceTransformAvailable) { devicePose = Pose.identity; poseSet = true; return Pose.identity; } float[] data = new float[16]; eLeapRS result = LeapC.GetDeviceTransform(Handle, data); if (result != eLeapRS.eLeapRS_Success || data == null) { devicePose = Pose.identity; poseSet = true; return Pose.identity; } // Using the LEAP->OPENXR device transform matrix // Unitys matrices are generated as 4 columns: Matrix4x4 deviceTransform = new Matrix4x4( new Vector4(data[0], data[1], data[2], data[3]), new Vector4(data[4], data[5], data[6], data[7]), new Vector4(data[8], data[9], data[10], data[11]), new Vector4(data[12], data[13], data[14], data[15])); // An example of the expected matrix if it were 8cm forward from the head origin // Unitys matrices are generated as 4 columns: //Matrix4x4 deviceTransform = new Matrix4x4( // new Vector4(-0.001f, 0, 0, 0), // new Vector4(0, 0, -0.001f, 0), // new Vector4(0, -0.001f, 0, 0), // new Vector4(0, 0, -0.08f, 1)); if (deviceTransform == Matrix4x4.identity) { devicePose = Pose.identity; poseSet = true; return Pose.identity; } Matrix4x4 openXRToUnity = new Matrix4x4( new Vector4(1f, 0, 0, 0), new Vector4(0, 1f, 0, 0), new Vector4(0, 0, -1f, 0), new Vector4(0, 0, 0, 1)); deviceTransform = openXRToUnity * deviceTransform; Vector3 outputPos = deviceTransform.GetPosition(); //Quaternion outputRot = deviceTransform.rotation; // Note: the matrices we receive are not rotatrion matrices. This produces unexpected results devicePose = new Pose(outputPos, Quaternion.identity); poseSet = true; return devicePose; } } /// /// Returns the internal status field of the current device /// protected uint GetDeviceStatus() { eLeapRS result; LEAP_DEVICE_INFO deviceInfo = new LEAP_DEVICE_INFO(); deviceInfo.serial = IntPtr.Zero; deviceInfo.size = (uint)System.Runtime.InteropServices.Marshal.SizeOf(deviceInfo); result = LeapC.GetDeviceInfo(Handle, ref deviceInfo); if (result != eLeapRS.eLeapRS_Success) return 0; uint status = deviceInfo.status; System.Runtime.InteropServices.Marshal.FreeCoTaskMem(deviceInfo.serial); return status; } /// /// The software has detected a possible smudge on the translucent cover /// over the Leap Motion cameras. /// @since 3.0 /// [Obsolete("IsSmudged is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")] public bool IsSmudged { get; internal set; } /// /// The software has entered low-resource mode /// @since 3.0 /// public bool IsLowResource { get; internal set; } /// /// The software has detected excessive IR illumination, which may interfere /// with tracking. If robust mode is enabled, the system will enter robust mode when /// isLightingBad() is true. /// @since 3.0 /// [Obsolete("IsLightingBad is not used in Ultraleap's Tracking Service 5.X+. This will be removed in the next Major release")] public bool IsLightingBad { get; internal set; } /// /// The available types of Leap Motion controllers. /// public enum DeviceType { TYPE_INVALID = -1, /// /// A standalone USB peripheral. The original Leap Motion controller device. /// @since 1.2 /// TYPE_PERIPHERAL = (int)eLeapDeviceType.eLeapDeviceType_Peripheral, /// /// Internal research product codename "Dragonfly". /// TYPE_DRAGONFLY = (int)eLeapDeviceType.eLeapDeviceType_Dragonfly, /// /// Internal research product codename "Nightcrawler". /// TYPE_NIGHTCRAWLER = (int)eLeapDeviceType.eLeapDeviceType_Nightcrawler, /// /// Research product codename "Rigel". /// TYPE_RIGEL = (int)eLeapDeviceType.eLeapDevicePID_Rigel, /// /// The Ultraleap Stereo IR 170 (SIR170) hand tracking module. /// TYPE_SIR170 = (int)eLeapDeviceType.eLeapDevicePID_SIR170, /// /// The Ultraleap 3Di hand tracking camera. /// TYPE_3DI = (int)eLeapDeviceType.eLeapDevicePID_3Di, /// /// The Ultraleap Leap Motion Controller 2 hand tracking camera. /// TYPE_LMC2 = (int)eLeapDeviceType.eLeapDevicePID_LMC2 } } }