/****************************************************************************** * Copyright (C) Ultraleap, Inc. 2011-2021. * * * * 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.Unity { public struct Movement { /// /// The linear velocity of this Movement. /// public Vector3 velocity; /// /// Angular velocity expressed as an angle-axis vector with angle equal to the length /// of the vector in degrees. /// public Vector3 angularVelocity; public static readonly Movement identity = new Movement(); public Movement inverse { get { return new Movement(-velocity, -angularVelocity); } } public static Movement operator *(Movement movement, float multiplier) { return new Movement(movement.velocity * multiplier, movement.angularVelocity * multiplier); } public static Movement operator /(Movement movement, float divisor) { return movement * (1f / divisor); } public Pose ToPose() { var angVelMag = angularVelocity.magnitude; return new Pose(velocity, Quaternion.AngleAxis(angVelMag, angularVelocity / angVelMag)); } public static Movement operator +(Movement movement0, Movement movement1) { return new Movement(movement0.velocity + movement1.velocity, movement0.angularVelocity + movement1.angularVelocity); } /// /// Constructs a linear Movement involving no rotation. /// public Movement(Vector3 velocity) { this.velocity = velocity; this.angularVelocity = Vector3.zero; } /// /// Constructs a Movement with a specified linear velocity and an angular velocity. /// public Movement(Vector3 velocity, Vector3 angularVelocity) { this.velocity = velocity; this.angularVelocity = angularVelocity; } /// /// Returns the Movement necessary to go from Pose p0 to Pose p1 in dt seconds. /// You can ignore the time parameter if you wish simply to store delta positions /// and angle-axis vector rotations. /// public Movement(Pose fromPose, Pose toPose, float dt = 1f) { Vector3 deltaPosition = toPose.position - fromPose.position; Quaternion deltaRotation = Quaternion.Inverse(fromPose.rotation) * toPose.rotation; this.velocity = deltaPosition / dt; this.angularVelocity = deltaRotation.ToAngleAxisVector() / dt; } #region Accelerations /// /// Discretely integrates this Movement's velocity by a linear acceleration over /// deltaTime. /// public void Integrate(Vector3 linearAcceleration, float deltaTime) { velocity += linearAcceleration * deltaTime; } /// /// Discretely integrates this Movement's velocity and angular velocity by both a /// linear acceleration term and an angular acceleration term and a deltaTime. /// public void Integrate(Vector3 linearAcceleration, Vector3 angularAcceleration, float deltaTime) { velocity += linearAcceleration * deltaTime; angularVelocity += angularAcceleration * deltaTime; } #endregion } public struct KinematicState { public Pose pose; public Movement movement; public KinematicState(Pose pose, Movement movement) { this.pose = pose; this.movement = movement; } public void Integrate(float deltaTime) { pose = pose.Integrated(movement, deltaTime); } public void Integrate(Vector3 linearAcceleration, float deltaTime) { movement.Integrate(linearAcceleration, deltaTime); pose = pose.Integrated(movement, deltaTime); } public void Integrate(Vector3 linearAcceleration, Vector3 angularAcceleration, float deltaTime) { movement.Integrate(linearAcceleration, angularAcceleration, deltaTime); pose = pose.Integrated(movement, deltaTime); } } public static class MovementExtensions { public static Pose Integrated(this Pose thisPose, Movement movement, float deltaTime) { thisPose.position = movement.velocity * deltaTime + thisPose.position; if (movement.angularVelocity.sqrMagnitude > 0.00001f) { var angVelMag = movement.angularVelocity.magnitude; thisPose.rotation = Quaternion.AngleAxis(angVelMag * deltaTime, movement.angularVelocity / angVelMag) * thisPose.rotation; } return thisPose; } } }