/// <summary>
        /// Checks whether: 1) the vector to check is approximately in the plane created by the other vectors, where it is approximately in the plane if
        /// the angle between it and its projection in the plane is less than or equal to the allowable deviation in degrees, and 2) the vector to check's
        /// projection in the plane yields a vector that segments the interior angle of the angle between the other vectors. Returns the percentage of the angular
        /// distance between the first plane-defining vector and the second plane-defining vector that the vector to check has traveled
        /// </summary>
        /// <param name="vectorToCheck"></param>
        /// <param name="firstVector"></param>
        /// <param name="secondVector"></param>
        /// <returns>-1 if vector does satisfy requirements. -2 if there is a negligable (less than allowable deviation) angle between the first plane vector
        /// and the second plane vector</returns>
        public static UserPerformanceAnalysisInfo IsVectorOnPathInPlane(Vector3D vectorToCheck, Vector3D firstPlaneVector, Vector3D secondPlaneVector)
        {
            UserPerformanceAnalysisInfo result;
            double totalDisplacementToTravel = Vector3D.AngleBetween(firstPlaneVector, secondPlaneVector);
            //if (totalDisplacementToTravel <= SharedContent.AllowableDeviationInDegrees)
            //{
            //    result = new UserPerformanceAnalysisInfo(true);
            //}

            Vector3D normalToPlane = Vector3D.CrossProduct(firstPlaneVector, secondPlaneVector);
            normalToPlane.Normalize();
            Vector3D projectionOfInclIntoNormal = Vector3D.DotProduct(vectorToCheck, normalToPlane) * normalToPlane;
            Vector3D projectionOfInclIntoPlane = vectorToCheck - projectionOfInclIntoNormal;

            //Verifies that the deviation from the plane defined by the initial and final orientations is less than the allowable deviation
            if (Vector3D.AngleBetween(projectionOfInclIntoPlane, vectorToCheck) > SharedContent.GetAllowableDeviationInDegrees())
            {
                result = new UserPerformanceAnalysisInfo(true, String.Format("The deviation between the vector to check and the path between the two plane-defining vectors exceeds {0} degrees",
                    SharedContent.GetAllowableDeviationInDegrees()));
                return result;
            }

            //Verifies that this orientation instance falls between the initial and final orientations in the interior angle give or take the allowable deviation
            if ((Vector3D.AngleBetween(projectionOfInclIntoPlane, secondPlaneVector) > Vector3D.AngleBetween(secondPlaneVector, firstPlaneVector) &&
                Vector3D.AngleBetween(projectionOfInclIntoPlane, firstPlaneVector) > SharedContent.GetAllowableDeviationInDegrees()) ||
                (Vector3D.AngleBetween(projectionOfInclIntoPlane, firstPlaneVector) > Vector3D.AngleBetween(secondPlaneVector, firstPlaneVector) &&
                Vector3D.AngleBetween(projectionOfInclIntoPlane, secondPlaneVector) > SharedContent.GetAllowableDeviationInDegrees()))
            {
                result = new UserPerformanceAnalysisInfo(true, "The vector is not in the shortest path between the two plane-defining vectors");
                return result;
            }

            double currentDisplacementTraveled = Vector3D.AngleBetween(projectionOfInclIntoPlane, firstPlaneVector);

            return new UserPerformanceAnalysisInfo((int)(100 * (currentDisplacementTraveled / totalDisplacementToTravel)));
        }
Example #2
0
        public override UserPerformanceAnalysisInfo IsInBetweenOrientations(BodyPartOrientation initialOrientation, BodyPartOrientation finalOrientation)
        {
            LimbOrientation initialLimbOrientation = (LimbOrientation)initialOrientation;
            LimbOrientation finalLimbOrientation = (LimbOrientation)finalOrientation;
            UserPerformanceAnalysisInfo[] limbComponentPerformanceInfo = new UserPerformanceAnalysisInfo[Enum.GetValues(typeof(LimbComponentID)).Length];

            //Upper limb
            UserPerformanceAnalysisInfo upperLimbInclinationInfo = BodyPartOrientation.IsVectorOnPathInPlane(this.calibratedUpperLimbInclination, initialLimbOrientation.calibratedUpperLimbInclination,
                finalLimbOrientation.calibratedUpperLimbInclination);
            if (upperLimbInclinationInfo.failed)
            {
                Console.WriteLine("Failed when checking upper limb inclination");
                return upperLimbInclinationInfo;
            }
            if (Vector3D.AngleBetween(initialLimbOrientation.upperLimbInclination, finalLimbOrientation.upperLimbInclination) <= SharedContent.GetAllowableDeviationInDegrees())
            {
                upperLimbInclinationInfo.negligableAction = true;
            }
            limbComponentPerformanceInfo[(int)LimbComponentID.UpperLimb] = upperLimbInclinationInfo;

            //Lower limb
            UserPerformanceAnalysisInfo lowerLimbInclinationInfo = BodyPartOrientation.IsVectorOnPathInPlane(this.calibratedLowerLimbInclination, initialLimbOrientation.calibratedLowerLimbInclination,
                finalLimbOrientation.calibratedLowerLimbInclination);
            if (lowerLimbInclinationInfo.failed)
            {
                Console.WriteLine("Failed when checking lower limb inclination");
                return lowerLimbInclinationInfo;
            }
            if (Vector3D.AngleBetween(initialLimbOrientation.lowerLimbInclination, finalLimbOrientation.lowerLimbInclination) <= SharedContent.GetAllowableDeviationInDegrees())
            {
                lowerLimbInclinationInfo.negligableAction = true;
            }
            limbComponentPerformanceInfo[(int)LimbComponentID.LowerLimb] = lowerLimbInclinationInfo;

            //Bend in limb
            if (this.calibratedBendInLimb < Math.Min(initialLimbOrientation.calibratedBendInLimb, finalLimbOrientation.calibratedBendInLimb) - SharedContent.GetAllowableDeviationInDegrees() ||
                this.calibratedBendInLimb > Math.Max(initialLimbOrientation.calibratedBendInLimb, finalLimbOrientation.calibratedBendInLimb) + SharedContent.GetAllowableDeviationInDegrees())
            {
                return new UserPerformanceAnalysisInfo(true, String.Format("The bend in the {0} is not in the range defined in the exercise step", Enum.GetName(typeof(SharedContent.BodyPartID), this.limbID)));
            }
            UserPerformanceAnalysisInfo bendInLimbInfo = new UserPerformanceAnalysisInfo(false);
            double currentChangeInBendInLimb = Math.Abs(this.calibratedBendInLimb - initialLimbOrientation.calibratedBendInLimb);
            double totalChangeInBendInLimb = Math.Abs(finalLimbOrientation.calibratedBendInLimb - initialLimbOrientation.calibratedBendInLimb);
            if (Math.Abs(finalLimbOrientation.bendInLimb - initialLimbOrientation.bendInLimb) <= SharedContent.GetAllowableDeviationInDegrees())
            {
                bendInLimbInfo.negligableAction = true;
            }
            else
            {
                bendInLimbInfo.percentComplete = (int)(100 * (currentChangeInBendInLimb / totalChangeInBendInLimb));
            }
            limbComponentPerformanceInfo[(int)LimbComponentID.BendInLimb] = bendInLimbInfo;

            if (bendInLimbInfo.negligableAction && upperLimbInclinationInfo.negligableAction && lowerLimbInclinationInfo.negligableAction)
            {
                return new UserPerformanceAnalysisInfo(true);
            }

            int maxPercent = int.MinValue, minPercent = int.MaxValue, maxPercentIndex = 0, minPercentIndex = 0, percentSum = 0, numPercents = 0;
            foreach (LimbComponentID limbComponentID in Enum.GetValues(typeof(LimbComponentID)))
            {
                if (!limbComponentPerformanceInfo[(int)limbComponentID].negligableAction)
                {
                    percentSum += limbComponentPerformanceInfo[(int)limbComponentID].percentComplete;
                    numPercents++;
                    if (limbComponentPerformanceInfo[(int)limbComponentID].percentComplete > maxPercent)
                    {
                        maxPercentIndex = (int)limbComponentID;
                        maxPercent = limbComponentPerformanceInfo[(int)limbComponentID].percentComplete;
                    }
                    if (limbComponentPerformanceInfo[(int)limbComponentID].percentComplete < minPercent)
                    {
                        minPercentIndex = (int)limbComponentID;
                        minPercent = limbComponentPerformanceInfo[(int)limbComponentID].percentComplete;
                    }
                }
            }

            if ((limbComponentPerformanceInfo[maxPercentIndex].percentComplete - limbComponentPerformanceInfo[minPercentIndex].percentComplete) > SharedContent.GetAllowableDeviationInPercent())
            {
                Console.WriteLine("Vector3D.AngleBetween(initialLimbOrientation.upperLimbInclination, finalLimbOrientation.upperLimbInclination) = {0}",
                    Vector3D.AngleBetween(initialLimbOrientation.upperLimbInclination, finalLimbOrientation.upperLimbInclination));
                Console.WriteLine("maxChange is for the {0} with {1} percent. minChange is for the {2} with {3} percent", Enum.GetName(typeof(LimbComponentID), (LimbComponentID)maxPercentIndex),
                    limbComponentPerformanceInfo[maxPercentIndex].percentComplete, Enum.GetName(typeof(LimbComponentID), (LimbComponentID)minPercentIndex), limbComponentPerformanceInfo[minPercentIndex].percentComplete);
                return new UserPerformanceAnalysisInfo(true, String.Format("The difference in the percentage completion of the movement for the {0} and {1} of the {2} exceeded the maximum allowable deviation of {3}",
                    Enum.GetName(typeof(LimbComponentID), (LimbComponentID)maxPercentIndex), Enum.GetName(typeof(LimbComponentID), (LimbComponentID)minPercentIndex),
                    Enum.GetName(typeof(SharedContent.BodyPartID), this.limbID), SharedContent.GetAllowableDeviationInPercent()));
            }
            else
            {
                return new UserPerformanceAnalysisInfo(percentSum / numPercents);
            }
        }
Example #3
0
        /// <summary>
        /// Determines whether this those is in between the initial and final poses provided, where it is assumed that a pose is in between two poses if and only if it occurs if
        /// the pose will occur while linearly transitioning from the first pose to the second pose (linearly = along the shortest path). Returns the average percent of the
        /// displacement between the initial and final poses that this pose has traveled
        /// </summary>
        /// <param name="initialPose"></param>
        /// <param name="finalPose"></param>
        /// <returns></returns>
        public UserPerformanceAnalysisInfo IsInBetweenPoses(Pose initialPose, Pose finalPose)
        {
            int maxChange = int.MinValue, minChange = int.MaxValue, percentSum = 0, numPercents = 0;
            SharedContent.BodyPartID maxChangeID = SharedContent.BodyPartID.Head, minChangeID = SharedContent.BodyPartID.Head;
            UserPerformanceAnalysisInfo result;

            foreach (SharedContent.BodyPartID bodyPartID in initialPose.bodyPartsOfInterest)
            {
                BodyPartOrientation bodyPartToCheck;
                this.poseBodyPartOrientations.TryGetValue(bodyPartID, out bodyPartToCheck);

                BodyPartOrientation initialBodyPart, finalBodyPart;
                initialPose.poseBodyPartOrientations.TryGetValue(bodyPartID, out initialBodyPart);
                finalPose.poseBodyPartOrientations.TryGetValue(bodyPartID, out finalBodyPart);

                result = bodyPartToCheck.IsInBetweenOrientations(initialBodyPart, finalBodyPart);
                if (result.failed)
                {
                    return result;
                }
                else if (!result.negligableAction)
                {
                    if (result.percentComplete < minChange)
                    {
                        minChange = result.percentComplete;
                        minChangeID = bodyPartID;
                    }
                    if (result.percentComplete > maxChange)
                    {
                        maxChange = result.percentComplete;
                        maxChangeID = bodyPartID;
                    }
                    percentSum += result.percentComplete;
                    numPercents++;
                }
            }

            if (numPercents == 0)
            {
                throw new Exception("In determining if pose is between two others, found that no non-negligable changes exist between the starting and ending poses");
            }

            if (maxChange - minChange > SharedContent.GetAllowableDeviationInPercent())
            {
                result = new UserPerformanceAnalysisInfo(true, String.Format("The difference in the percentage completion of the movement for {0} and {1} exceeded the maximum allowable deviation of {2}",
                    Enum.GetName(typeof(SharedContent.BodyPartID), maxChangeID), Enum.GetName(typeof(SharedContent.BodyPartID), minChangeID), SharedContent.GetAllowableDeviationInPercent()));
                return result;
            }
            else
            {
                result = new UserPerformanceAnalysisInfo(percentSum / numPercents);
                return result;
            }
        }
        public override UserPerformanceAnalysisInfo IsInBetweenOrientations(BodyPartOrientation initialOrientation, BodyPartOrientation finalOrientation)
        {
            TorsoOrientation initialTorsoOrientation = (TorsoOrientation)initialOrientation;
            TorsoOrientation finalTorsoOrientation = (TorsoOrientation)finalOrientation;

            //Compute inclination information
            UserPerformanceAnalysisInfo inclinationInfo = BodyPartOrientation.IsVectorOnPathInPlane(this.calibratedInclination, initialTorsoOrientation.calibratedInclination, finalTorsoOrientation.calibratedInclination);
            if (inclinationInfo.failed) return inclinationInfo;
            if (Vector3D.AngleBetween(initialTorsoOrientation.inclination, finalTorsoOrientation.inclination) <= SharedContent.GetAllowableDeviationInDegrees())
            {
                //The actual exercise has a negligable change in the torso inclination
                inclinationInfo.negligableAction = true;
            }

            //Compute rotation information
            if (this.calibratedRotation < Math.Min(initialTorsoOrientation.calibratedRotation, finalTorsoOrientation.calibratedRotation) - SharedContent.GetAllowableDeviationInDegrees() ||
                this.calibratedRotation > Math.Max(initialTorsoOrientation.calibratedRotation, finalTorsoOrientation.calibratedRotation) + SharedContent.GetAllowableDeviationInDegrees())
            {
                //The current rotation is not within the range specified by the initial and final orientations
                return new UserPerformanceAnalysisInfo(true, "User's torso rotation is not in the range defined by the exercise step");
            }

            UserPerformanceAnalysisInfo rotationInfo = new UserPerformanceAnalysisInfo(false);
            if (Math.Abs(finalTorsoOrientation.rotation - initialTorsoOrientation.rotation) <= SharedContent.GetAllowableDeviationInDegrees())
            {
                //The actual exercise has a negligable change in the torso rotation
                rotationInfo.negligableAction = true;
            }
            double currentRotationTraveled = Math.Abs(this.calibratedRotation - initialTorsoOrientation.calibratedRotation);
            double totalRotationToTravel = Math.Abs(finalTorsoOrientation.calibratedRotation - initialTorsoOrientation.calibratedRotation);
            rotationInfo.percentComplete = (int)(100 * (currentRotationTraveled / totalRotationToTravel));

            if (rotationInfo.negligableAction && inclinationInfo.negligableAction)
            {
                return new UserPerformanceAnalysisInfo(true);
            }
            else if (inclinationInfo.negligableAction)
            {
                return rotationInfo;
            }
            else if (rotationInfo.negligableAction)
            {
                return inclinationInfo;
            }
            else
            {
                if (Math.Abs(inclinationInfo.percentComplete - rotationInfo.percentComplete) > SharedContent.GetAllowableDeviationInPercent())
                {
                    return new UserPerformanceAnalysisInfo(true, String.Format("The difference in the percentage completion of the change in torso inclination and change in torso rotation exceeded the maximum allowable deviation of {0}",
                        SharedContent.GetAllowableDeviationInPercent()));
                }

                //Return the average percent complete
                return new UserPerformanceAnalysisInfo((int)((inclinationInfo.percentComplete + rotationInfo.percentComplete) / 2.0));
            }
        }