/****************************************************************************** * 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 System; /// /// The LeapTransform class represents a transform in three dimensional space. /// /// Note that the LeapTransform class replaces the Leap.Matrix class. /// @since 3.1.2 /// public struct LeapTransform { /// /// Constructs a new transform from the specified translation and rotation. /// public LeapTransform(Vector3 translation, Quaternion rotation) : this(translation, rotation, Vector3.one) { } /// /// Constructs a new transform from the specified translation, rotation and scale. /// public LeapTransform(Vector3 translation, Quaternion rotation, Vector3 scale) : this() { this.scale = scale; // these are non-trival setters. this.translation = translation; this.rotation = rotation; // Calls validateBasis } /// /// Constructs a new Leap transform from a Unity Transform /// /// Unity Transform public LeapTransform(Transform t) : this() { this.scale = t.lossyScale; this.translation = t.position; this.rotation = t.rotation; } /// /// Transforms the specified position vector, applying translation, rotation and scale. /// public Vector3 TransformPoint(Vector3 point) { return _xBasisScaled * point.x + _yBasisScaled * point.y + _zBasisScaled * point.z + translation; } /// /// Transforms the specified direction vector, applying rotation only. /// public Vector3 TransformDirection(Vector3 direction) { return _xBasis * direction.x + _yBasis * direction.y + _zBasis * direction.z; } /// /// Transforms the specified velocity vector, applying rotation and scale. /// public Vector3 TransformVelocity(Vector3 velocity) { return _xBasisScaled * velocity.x + _yBasisScaled * velocity.y + _zBasisScaled * velocity.z; } /// /// Transforms the specified quaternion. /// Multiplies the quaternion representing the rotational part of this transform by the specified /// quaternion. /// /// **Important:** Modifying the basis vectors of this transform directly leaves the underlying quaternion in /// an indeterminate state. Neither this function nor the LeapTransform.rotation quaternion can be used after /// the basis vectors are set. /// public Quaternion TransformQuaternion(Quaternion rhs) { if (_quaternionDirty) throw new InvalidOperationException("Calling TransformQuaternion after Basis vectors have been modified."); if (_flip) { // Mirror the axis of rotation across the flip axis. rhs.x *= _flipAxes.x; rhs.y *= _flipAxes.y; rhs.z *= _flipAxes.z; } Quaternion t = _quaternion * rhs; return t; } /// /// Mirrors this transform's rotation and scale across the x-axis. Translation is not affected. /// @since 3.1.2 /// public void MirrorX() { _xBasis = -_xBasis; _xBasisScaled = -_xBasisScaled; _flip = true; _flipAxes.y = -_flipAxes.y; _flipAxes.z = -_flipAxes.z; } /// /// Mirrors this transform's rotation and scale across the z-axis. Translation is not affected. /// @since 3.1.2 /// public void MirrorZ() { _zBasis = -_zBasis; _zBasisScaled = -_zBasisScaled; _flip = true; _flipAxes.x = -_flipAxes.x; _flipAxes.y = -_flipAxes.y; } /// /// The x-basis of the transform. /// /// **Important:** Modifying the basis vectors of this transform directly leaves the underlying quaternion in /// an indeterminate state. Neither the TransformQuaternion() function nor the LeapTransform.rotation quaternion /// can be used after the basis vectors are set. /// /// @since 3.1.2 /// public Vector3 xBasis { get { return _xBasis; } set { _xBasis = value; _xBasisScaled = value * scale.x; _quaternionDirty = true; } } /// /// The y-basis of the transform. /// /// **Important:** Modifying the basis vectors of this transform directly leaves the underlying quaternion in /// an indeterminate state. Neither the TransformQuaternion() function nor the LeapTransform.rotation quaternion /// can be used after the basis vectors are set. /// /// @since 3.1.2 /// public Vector3 yBasis { get { return _yBasis; } set { _yBasis = value; _yBasisScaled = value * scale.y; _quaternionDirty = true; } } /// /// The z-basis of the transform. /// /// **Important:** Modifying the basis vectors of this transform directly leaves the underlying quaternion in /// an indeterminate state. Neither the TransformQuaternion() function nor the LeapTransform.rotation quaternion /// can be used after the basis vectors are set. /// /// @since 3.1.2 /// public Vector3 zBasis { get { return _zBasis; } set { _zBasis = value; _zBasisScaled = value * scale.z; _quaternionDirty = true; } } /// /// The translation component of the transform. /// @since 3.1.2 /// public Vector3 translation { get { return _translation; } set { _translation = value; } } /// /// The scale factors of the transform. /// Scale is kept separate from translation. /// @since 3.1.2 /// public Vector3 scale { get { return _scale; } set { _scale = value; _xBasisScaled = _xBasis * scale.x; _yBasisScaled = _yBasis * scale.y; _zBasisScaled = _zBasis * scale.z; } } /// /// The rotational component of the transform. /// /// **Important:** Modifying the basis vectors of this transform directly leaves the underlying quaternion in /// an indeterminate state. This rotation quaternion cannot be accessed after /// the basis vectors are modified directly. /// /// @since 3.1.2 /// public Quaternion rotation { get { if (_quaternionDirty) throw new InvalidOperationException("Requesting rotation after Basis vectors have been modified."); return _quaternion; } set { _quaternion = value; float d = value.x * value.x + value.y * value.y + value.z * value.z + value.w * value.w; float s = 2.0f / d; float xs = value.x * s, ys = value.y * s, zs = value.z * s; float wx = value.w * xs, wy = value.w * ys, wz = value.w * zs; float xx = value.x * xs, xy = value.x * ys, xz = value.x * zs; float yy = value.y * ys, yz = value.y * zs, zz = value.z * zs; _xBasis = new Vector3(1.0f - (yy + zz), xy + wz, xz - wy); _yBasis = new Vector3(xy - wz, 1.0f - (xx + zz), yz + wx); _zBasis = new Vector3(xz + wy, yz - wx, 1.0f - (xx + yy)); _xBasisScaled = _xBasis * scale.x; _yBasisScaled = _yBasis * scale.y; _zBasisScaled = _zBasis * scale.z; _quaternionDirty = false; _flip = false; _flipAxes = new Vector3(1.0f, 1.0f, 1.0f); } } /// /// The identity transform. /// @since 3.1.2 /// public static readonly LeapTransform Identity = new LeapTransform(Vector3.zero, Quaternion.identity, Vector3.one); private Vector3 _translation; private Vector3 _scale; private Quaternion _quaternion; private bool _quaternionDirty; private bool _flip; private Vector3 _flipAxes; private Vector3 _xBasis; private Vector3 _yBasis; private Vector3 _zBasis; private Vector3 _xBasisScaled; private Vector3 _yBasisScaled; private Vector3 _zBasisScaled; } }