/// <summary>
        /// Sets up the respective hand using the given parameters
        /// </summary>
        /// <param name="jointType"></param>
        /// <param name="instruction"></param>
        /// <param name="duration"></param>
        /// <param name="angularVelocity"></param>
        /// <param name="durationSet"></param>
        /// <param name="release"></param>
        private void SetupHand(MJointType jointType, MInstruction instruction, float duration, float angularVelocity, bool durationSet, bool release)
        {
            //Create a new hand container
            HandContainer hand = new HandContainer()
            {
                Type            = jointType,
                Instruction     = instruction,
                Release         = release,
                Duration        = duration,
                AngularVelocity = angularVelocity,
                HasDuration     = durationSet,
                Positioned      = false
            };

            HandContainer old = this.ActiveHands.Find(s => s.Type == jointType);

            if (old != null)
            {
                this.ActiveHands.Remove(old);
            }

            //Handle the hand pose (if defined)
            if (instruction.Properties.ContainsKey("HandPose"))
            {
                //Get the constraint id
                string constraintID = instruction.Properties["HandPose"];

                //Get the corresponding hand constraint
                MConstraint handConstraint = instruction.Constraints.Find(s => s.ID == constraintID);

                //Check if hand constraint is defined and assign as final posture
                if (handConstraint != null && handConstraint.PostureConstraint != null)
                {
                    hand.FinalPosture = handConstraint.PostureConstraint;
                }
            }

            //Add as active hand
            this.ActiveHands.Add(hand);
        }
        public override MSimulationResult DoStep(double time, MSimulationState simulationState)
        {
            //Create a new result
            MSimulationResult result = new MSimulationResult()
            {
                Events             = simulationState.Events ?? new List <MSimulationEvent>(),
                DrawingCalls       = new List <MDrawingCall>(),
                SceneManipulations = simulationState.SceneManipulations ?? new List <MSceneManipulation>(),
                Posture            = simulationState.Current,
                Constraints        = simulationState.Constraints ?? new List <MConstraint>()
            };

            //Cast to intermediate skeleton to get all functions
            IntermediateSkeleton iS = this.SkeletonAccess as IntermediateSkeleton;


            //Assign the approved posture of the last frame (proper finger rotations)
            this.SkeletonAccess.SetChannelData(simulationState.Initial);

            //First estimate the finger rotations
            //------------------------------------------------------------------------------------------------------------------

            //Handle each active hand
            for (int i = this.ActiveHands.Count - 1; i >= 0; i--)
            {
                //Get the current hand
                HandContainer hand = this.ActiveHands[i];

                if (hand.Release)
                {
                    //Use all finger joint if in release mode
                    foreach (MJointType jointType in fingerJoints)
                    {
                        //Get the current rotation of the finger
                        if (!hand.CurrentFingerRotations.ContainsKey(jointType))
                        {
                            hand.CurrentFingerRotations.Add(jointType, iS.GetLocalJointRotation(this.AvatarDescription.AvatarID, jointType));
                        }
                        else
                        {
                            hand.CurrentFingerRotations[jointType] = iS.GetLocalJointRotation(this.AvatarDescription.AvatarID, jointType);
                        }
                    }
                }

                else
                {
                    //Handle all joint constraints -> Use only the fingers that are constrained
                    foreach (MJointConstraint joint in hand.FinalPosture.JointConstraints)
                    {
                        //Skip if the joint is no finger joint
                        if (!this.IsFingerJoint(joint.JointType))
                        {
                            continue;
                        }

                        //Get the current rotation of the finger
                        if (!hand.CurrentFingerRotations.ContainsKey(joint.JointType))
                        {
                            hand.CurrentFingerRotations.Add(joint.JointType, iS.GetLocalJointRotation(this.AvatarDescription.AvatarID, joint.JointType));
                        }
                        else
                        {
                            hand.CurrentFingerRotations[joint.JointType] = iS.GetLocalJointRotation(this.AvatarDescription.AvatarID, joint.JointType);
                        }
                    }
                }
            }


            //Perform the blending
            //------------------------------------------------------------------------------------------------------------------

            //Assign the approved posture of the last frame (proper finger rotations)
            this.SkeletonAccess.SetChannelData(simulationState.Current);


            //Handle each active hand
            for (int i = this.ActiveHands.Count - 1; i >= 0; i--)
            {
                //Get the current hand
                HandContainer hand = this.ActiveHands[i];

                //Flag which indicates whether the fingers are positioned
                bool positioned = true;


                if (hand.Release)
                {
                    //If in release mode again use all joints being finger joints
                    foreach (MJointType jointType in fingerJoints)
                    {
                        //Get the current rotation of the finger
                        MQuaternion currentRotation = hand.CurrentFingerRotations[jointType];

                        //The current rotation is the result of the last frame
                        MQuaternion desiredRotation = iS.GetLocalJointRotation(this.AvatarDescription.AvatarID, jointType);

                        //The weight used for blending
                        double weight = 0;

                        //The angle between the current rotation and the desired one
                        double angle = MQuaternionExtensions.Angle(currentRotation, desiredRotation);


                        //Compute the weight based on the elapsed time if the duration is set
                        if (hand.HasDuration)
                        {
                            weight = hand.Elapsed / hand.Duration;
                        }

                        //By default use the angular velocity
                        else
                        {
                            //The max allowed angle in this frame
                            double maxAngle = time * hand.AngularVelocity;
                            weight = Math.Min(1, maxAngle / angle);
                        }

                        //Compute the new rotation
                        MQuaternion newRotation = MQuaternionExtensions.Slerp(currentRotation, desiredRotation, (float)weight);

                        //Set the local joint rotation of the intermediate skeleton
                        iS.SetLocalJointRotation(this.AvatarDescription.AvatarID, jointType, newRotation);

                        //Goal criteria
                        if (angle > 0.1f)
                        {
                            positioned = false;
                        }
                    }
                }

                else
                {
                    //Handle all joint constraints
                    foreach (MJointConstraint joint in hand.FinalPosture.JointConstraints)
                    {
                        //Skip if the joint is no finger joint
                        if (!this.IsFingerJoint(joint.JointType))
                        {
                            continue;
                        }

                        //Get the current rotation of the finger
                        MQuaternion currentRotation = hand.CurrentFingerRotations[joint.JointType];

                        //Get the desired rotation
                        MQuaternion desiredRotation = joint.GeometryConstraint.ParentToConstraint.Rotation;

                        //The weight used for blending
                        double weight = 0;

                        //The angle between the current rotation and the desired one
                        double angle = MQuaternionExtensions.Angle(currentRotation, desiredRotation);


                        //Compute the weight based on the elapsed time if the duration is set
                        if (hand.HasDuration)
                        {
                            weight = hand.Elapsed / hand.Duration;
                        }

                        //By default use the angular velocity
                        else
                        {
                            //The max allowed angle in this frame
                            double maxAngle = time * hand.AngularVelocity;
                            weight = Math.Min(1, maxAngle / angle);
                        }

                        //Compute the new rotation
                        MQuaternion newRotation = MQuaternionExtensions.Slerp(currentRotation, desiredRotation, (float)weight);

                        //Set the local joint rotation of the intermediate skeleton
                        iS.SetLocalJointRotation(this.AvatarDescription.AvatarID, joint.JointType, newRotation);

                        //Goal criteria
                        if (angle > 0.1f)
                        {
                            positioned = false;
                        }
                    }
                }

                //Provide event if positioned successfully
                if (positioned && !hand.Positioned)
                {
                    hand.Positioned = true;
                    result.Events.Add(new MSimulationEvent()
                    {
                        Name      = "MoveFingersMMU",
                        Type      = "FingersPositioned",
                        Reference = hand.Instruction.ID
                    });
                }


                //Increment the time
                hand.Elapsed += (float)time;
            }

            //Recompute the posture given the performed changes
            result.Posture = iS.RecomputeCurrentPostureValues(this.AvatarDescription.AvatarID);

            //Return the simulation result for the given frame
            return(result);
        }