/// <summary>
        /// Equals method
        /// </summary>
        /// <returns>Returns true if not equivalent, otherwise false</returns>
        public bool Equals(FaceTrackInfo other)
        {
            if (this.TrackValid != other.TrackValid || this.FaceRect != other.FaceRect ||
                this.Rotation != other.Rotation || this.Translation != other.Translation)
            {
                return(false);
            }

            return(true);
        }
        /// <summary>
        /// Retrieve the transform matrix based on the input FaceTrackInfo
        /// Note: We find the one that has minimum rotation gap compared with input,
        /// and meanwhile lower than translation, rotation tolerance
        /// </summary>
        /// <param name="faceInfo">The input face tracking information used for searching.</param>
        /// <param name="resultMatrix">Output result transform matrix.</param>
        /// <returns>Whether successfully get the transform matrix</returns>
        public bool RetrieveTransformMatrix(FaceTrackInfo faceInfo, out Matrix4 resultMatrix)
        {
            bool retrieveSucceeded = false;

            resultMatrix = Matrix4.Identity;

            // Track the face tracking information is valid
            if (faceInfo.TrackValid)
            {
                List <int> candidateIndexes = new List <int>();

                // Get the candidates
                for (int i = 0; i < SavedFrameCount; i++)
                {
                    if (null != locationFrames[i])
                    {
                        double translationGap = GetDistance(faceInfo.Translation, locationFrames[i].FaceInfo.Translation);

                        // A valid candidate
                        if (translationGap < TranslationTolerance)
                        {
                            candidateIndexes.Add(i);
                        }
                    }
                }

                // Retrieve the best candidate and also lower than the tolerance
                double minimumRotationGap = double.MaxValue;
                int    retrieveIndex      = 0;
                foreach (var candidateIndex in candidateIndexes)
                {
                    double rotationGap = GetAbsoluteGap(faceInfo.Rotation, locationFrames[candidateIndex].FaceInfo.Rotation);
                    if (rotationGap < minimumRotationGap)
                    {
                        minimumRotationGap = rotationGap;

                        retrieveIndex = candidateIndex;
                    }
                }

                if (minimumRotationGap < RotationTolerance)
                {
                    retrieveSucceeded = true;
                    resultMatrix      = locationFrames[retrieveIndex].WorldToCameraTransform;
                }
            }

            return(retrieveSucceeded);
        }
        /// <summary>
        /// Update the relocation database
        /// </summary>
        /// <param name="faceInfo">The input face tracking information.</param>
        /// <param name="worldToCameraTransform">The corresponding transform matrix.</param>
        public void UpdateRelocation(FaceTrackInfo faceInfo, Matrix4 worldToCameraTransform)
        {
            processedFrames++;

            if (!faceInfo.TrackValid)
            {
                return;
            }

            // We save a frame in every SavingFrameInterval frames
            if (processedFrames >= SavingFrameInterval)
            {
                // Update the frame index
                savedFrameIndex = ++savedFrameIndex % SavedFrameCount;

                // Write input data to database
                locationFrames[savedFrameIndex] = new LocationFrame {
                    FaceInfo = faceInfo, WorldToCameraTransform = worldToCameraTransform
                };

                processedFrames = 0;
            }
        }