using System;
using System.Runtime.InteropServices;
using UnityEngine.XR.Hands.ProviderImplementation;
namespace UnityEngine.XR.Hands
{
///
/// Represents a joint of an .
///
///
/// The term "joint" should be taken loosely in this context. In addition to the
/// anatomical finger joints, the list of joints includes the fingertips, a point on the palm
/// and a point on the wrist. See for the full list of
/// joints.
///
/// Refer to [Hand data model](xref:xrhands-data-model) for a description of the joint locations
/// and the data they contain.
///
[StructLayout(LayoutKind.Sequential)]
public struct XRHandJoint : IEquatable
{
///
/// The ID of this joint.
///
/// The joint ID.
public XRHandJointID id => (XRHandJointID)(m_IdAndHandedness & ~k_IsRightHandBit);
///
/// Denotes which hand this joint is on.
///
/// Right or left.
public Handedness handedness => (m_IdAndHandedness & k_IsRightHandBit) != 0 ? Handedness.Right : Handedness.Left;
///
/// Represents which tracking data is valid.
///
/// A flag is set for each valid type of data. If the
/// The flag is set
/// when this joind ID isn't supported by the hand data provider.
public XRHandJointTrackingState trackingState => m_TrackingState;
///
/// Retrieves the joint's radius, if available.
///
///
/// Assigned the tracked radius of this joint, if successful.
/// Set to zero, if unsuccessful.
///
///
/// Returns if successful and the radius was
/// filled out with valid tracking data, returns
/// otherwise.
///
public bool TryGetRadius(out float radius)
{
if ((m_TrackingState & XRHandJointTrackingState.Radius) == XRHandJointTrackingState.None)
{
radius = 0.0f;
return false;
}
radius = m_Radius;
return true;
}
///
/// Retrieves the joint's pose, if available.
///
///
/// Assigned the tracked pose of this joint, if successful.
/// Set to , if unsuccessful.
///
///
/// Returns if successful and the joint pose was
/// filled out with valid tracking data, returns
/// otherwise.
///
///
/// Joint poses are relative to the real-world point chosen by the user's device.
///
/// To transform to world space so that the joint appears in the correct location
/// relative to the user, transform the pose based on the
/// [XROrigin](xref:Unity.XR.CoreUtils.XROrigin).
///
///
///
/// The following example illustrates how to transform a pose into world space using the
/// transform from the XROrigin object in a scene.
///
///
/// public Pose ToWorldPose(XRHandJoint joint, Transform origin)
/// {
/// Pose xrOriginPose = new Pose(origin.position, origin.rotation);
/// if (joint.TryGetPose(out Pose jointPose))
/// {
/// return jointPose.GetTransformedBy(xrOriginPose);
/// }
/// else
/// {
/// return Pose.identity;
/// }
/// }
///
///
public bool TryGetPose(out Pose pose)
{
if ((m_TrackingState & XRHandJointTrackingState.Pose) == XRHandJointTrackingState.None)
{
pose = Pose.identity;
return false;
}
pose = m_Pose;
return true;
}
///
/// Retrieves the joint's linear velocity vector, if available.
///
///
/// Assigned the tracked linear velocity of this joint, if successful.
/// Set to , if unsuccessful.
///
///
/// Returns if successful and the velocity was
/// filled out with valid tracking data, returns
/// otherwise.
///
///
/// To transform to world space so that the vector has the correct direction
/// relative to the user, rotate this by the rotation of the
/// [XROrigin](xref:Unity.XR.CoreUtils.XROrigin).
///
public bool TryGetLinearVelocity(out Vector3 linearVelocity)
{
if ((m_TrackingState & XRHandJointTrackingState.LinearVelocity) == XRHandJointTrackingState.None)
{
linearVelocity = Vector3.zero;
return false;
}
linearVelocity = m_LinearVelocity;
return true;
}
///
/// Retrieves the joint's angular velocity vector, if available
///
///
/// Assigned the tracked angular velocity of this joint, if successful.
/// Set to , if unsuccessful.
///
///
/// Returns if successful and the angular
/// velocity filled out with valid tracking data, returns
/// otherwise.
///
///
/// To transform to world space so that the vector has the correct direction
/// relative to the user, rotate this by the rotation of the
/// [XROrigin](xref:Unity.XR.CoreUtils.XROrigin).
///
public bool TryGetAngularVelocity(out Vector3 angularVelocity)
{
if ((m_TrackingState & XRHandJointTrackingState.AngularVelocity) == XRHandJointTrackingState.None)
{
angularVelocity = Vector3.zero;
return false;
}
angularVelocity = m_AngularVelocity;
return true;
}
///
/// Returns a string representation of the XRHandJoint.
///
///
/// String representation of the value.
///
public override string ToString()
{
return string.Format(
"[{0} {1}] Pose: {2} | Radius: {3} | Linear Velocity: {4} | Angular Velocity: {5} | Tracking State: {6}",
handedness, id, m_Pose.ToString("F4"), m_Radius.ToString("F4"), m_LinearVelocity.ToString("F4"), m_AngularVelocity.ToString("F4"), m_TrackingState);
}
///
/// Tests for equality.
///
/// The to compare against.
///
/// Returns if the underlying native pointers are
/// the same. Returns otherwise.
///
public bool Equals(XRHandJoint other)
{
return m_IdAndHandedness == other.m_IdAndHandedness &&
m_Pose == other.m_Pose &&
m_Radius == other.m_Radius &&
m_LinearVelocity == other.m_LinearVelocity &&
m_AngularVelocity == other.m_AngularVelocity &&
m_TrackingState == other.m_TrackingState;
}
///
/// Tests for equality.
///
/// An to compare against.
///
/// Returns if is an
/// and it compares equal to this one using
/// .
///
public override bool Equals(object obj) => obj is XRHandJoint other && Equals(other);
///
/// Computes a hash code from all fields of XRHandJoint.
///
/// Returns a hash code of this object.
public override int GetHashCode()
{
unchecked
{
int hash = m_IdAndHandedness.GetHashCode();
hash = hash * 486187739 + m_Pose.GetHashCode();
hash = hash * 486187739 + m_Radius.GetHashCode();
hash = hash * 486187739 + m_LinearVelocity.GetHashCode();
hash = hash * 486187739 + m_AngularVelocity.GetHashCode();
hash = hash * 486187739 + m_TrackingState.GetHashCode();
return hash;
}
}
///
/// Tests for equality. Same as .
///
/// The left-hand side of the comparison.
/// The right-hand side of the comparison.
/// Returns the same value as .
public static bool operator ==(XRHandJoint lhs, XRHandJoint rhs) => lhs.Equals(rhs);
///
/// Tests for inequality. Same as !
///
/// The left-hand side of the comparison.
/// The right-hand side of the comparison.
/// Returns the negation of .
public static bool operator !=(XRHandJoint lhs, XRHandJoint rhs) => !lhs.Equals(rhs);
internal int m_IdAndHandedness;
internal Pose m_Pose;
internal float m_Radius;
internal Vector3 m_LinearVelocity;
internal Vector3 m_AngularVelocity;
internal XRHandJointTrackingState m_TrackingState;
internal const int k_IsRightHandBit = 1 << 31;
}
}