/// <summary>
 /// Returns the length of the source point.
 /// </summary>
 /// <returns>The length of the point.</returns>
 public static float length(PointFT point1)
 {
     return((float)Math.Sqrt(point1.X * point1.X + point1.Y * point1.Y));
 }
 /// <summary>
 /// Calculate the number of points you have to cross to go from one point to another.
 /// </summary>
 /// <param name="point1">Source point.</param>
 /// <param name="point2">Source point.</param>
 /// <returns>Returns the distance between the points.</returns>
 public static int distance(PointFT point1, PointFT point2)
 {
     return(Math.Abs(point1.X - point2.X) + Math.Abs(point1.Y - point2.Y));
 }
        private List <Hand> localizeHands(bool[][] valid)
        {
            int i, j, k;

            List <Hand> hands = new List <Hand>();

            List <PointFT> insidePoints  = new List <PointFT>();
            List <PointFT> contourPoints = new List <PointFT>();


            bool[][] contour = new bool[valid.Length][];
            for (i = 0; i < valid.Length; ++i)
            {
                contour[i] = new bool[valid[0].Length];
            }

            // Divide points in contour and inside points
            int count = 0;

            for (i = 1; i < valid.Length - 1; ++i)
            {
                for (j = 1; j < valid[i].Length - 1; ++j)
                {
                    if (valid[i][j])
                    {
                        // Count the number of valid adjacent points
                        count = this.numValidPixelAdjacent(ref i, ref j, ref valid);

                        if (count == 4) // Inside
                        {
                            insidePoints.Add(new PointFT(i, j));
                        }
                        else // Contour
                        {
                            contour[i][j] = true;
                            contourPoints.Add(new PointFT(i, j));
                        }
                    }
                }
            }

            // Create the sorted contour list, using the turtle algorithm
            for (i = 0; i < contourPoints.Count; ++i)
            {
                Hand hand = new Hand();

                // If it is a possible start point
                if (contour[contourPoints[i].X][contourPoints[i].Y])
                {
                    // Calculate the contour
                    hand.contour = CalculateFrontier(ref valid, contourPoints[i], ref contour);

                    // Check if the contour is big enough to be a hand
                    if (hand.contour.Count / (contourPoints.Count * 1.0f) > 0.20f &&
                        hand.contour.Count > settings.k)
                    {
                        // Calculate the container box
                        hand.calculateContainerBox(settings.containerBoxReduction);

                        // Add the hand to the list
                        hands.Add(hand);
                    }

                    // Don't look for more hands, if we reach the limit
                    if (hands.Count >= settings.maxTrackedHands)
                    {
                        break;
                    }
                }
            }

            // Allocate the inside points to the correct hand using its container box

            //List<int> belongingHands = new List<int>();
            for (i = 0; i < insidePoints.Count; ++i)
            {
                for (j = 0; j < hands.Count; ++j)
                {
                    if (hands[j].isPointInsideContainerBox(insidePoints[i]))
                    {
                        hands[j].inside.Add(insidePoints[i]);
                        //belongingHands.Add(j);
                    }
                }

                // A point can only belong to one hand, if not we don't take that point into account

                /*if (belongingHands.Count == 1)
                 * {
                 *  hands[belongingHands.ElementAt(0)].inside.Add(insidePoints[i]);
                 * }
                 * belongingHands.Clear();*/
            }

            // Find the center of the palm
            float min, max, distance = 0;

            for (i = 0; i < hands.Count; ++i)
            {
                max = float.MinValue;
                for (j = 0; j < hands[i].inside.Count; j += settings.findCenterInsideJump)
                {
                    min = float.MaxValue;
                    for (k = 0; k < hands[i].contour.Count; k += settings.findCenterInsideJump)
                    {
                        distance = PointFT.distanceEuclidean(hands[i].inside[j], hands[i].contour[k]);
                        if (!hands[i].isCircleInsideContainerBox(hands[i].inside[j], distance))
                        {
                            continue;
                        }
                        if (distance < min)
                        {
                            min = distance;
                        }
                        if (min < max)
                        {
                            break;
                        }
                    }

                    if (max < min && min != float.MaxValue)
                    {
                        max           = min;
                        hands[i].palm = hands[i].inside[j];
                    }
                }
            }

            // Find the fingertips
            PointFT p1, p2, p3, pAux, r1, r2;
            int     size;
            double  angle;
            int     jump;

            for (i = 0; i < hands.Count; ++i)
            {
                // Check if there is a point at the beginning to avoid checking the last ones of the list
                max  = hands[i].contour.Count;
                size = hands[i].contour.Count;
                jump = (int)(size * settings.fingertipFindJumpPerc);
                for (j = 0; j < settings.k; j += 1)
                {
                    p1 = hands[i].contour[(j - settings.k + size) % size];
                    p2 = hands[i].contour[j];
                    p3 = hands[i].contour[(j + settings.k) % size];
                    r1 = p1 - p2;
                    r2 = p3 - p2;

                    angle = PointFT.angle(r1, r2);

                    if (angle > 0 && angle < settings.theta)
                    {
                        pAux = p3 + ((p1 - p3) / 2);
                        if (PointFT.distanceEuclideanSquared(pAux, hands[i].palm) >
                            PointFT.distanceEuclideanSquared(hands[i].contour[j], hands[i].palm))
                        {
                            continue;
                        }

                        hands[i].fingertips.Add(hands[i].contour[j]);
                        max = hands[i].contour.Count + j - jump;
                        max = Math.Min(max, hands[i].contour.Count);
                        j  += jump;
                        break;
                    }
                }

                // Continue with the rest of the points
                for ( ; j < max; j += settings.findFingertipsJump)
                {
                    p1 = hands[i].contour[(j - settings.k + size) % size];
                    p2 = hands[i].contour[j];
                    p3 = hands[i].contour[(j + settings.k) % size];
                    r1 = p1 - p2;
                    r2 = p3 - p2;

                    angle = PointFT.angle(r1, r2);

                    if (angle > 0 && angle < settings.theta)
                    {
                        pAux = p3 + ((p1 - p3) / 2);
                        if (PointFT.distanceEuclideanSquared(pAux, hands[i].palm) >
                            PointFT.distanceEuclideanSquared(hands[i].contour[j], hands[i].palm))
                        {
                            continue;
                        }

                        hands[i].fingertips.Add(hands[i].contour[j]);
                        j += jump;
                    }
                }
            }

            return(hands);
        }