예제 #1
0
        // If the number of points is less than the grainSize, the Run method
        // simply finds the lower hull by going through all points from right to
        // left, as described in the sequential convex hull algorithm.
        // Otherwise we split the points in two and find the lower hulls
        // concurrently.
        // Finally we merge the two lower hulls and return the lower hull.
        public override List <Point> Run()
        {
            int length = end - start + 1;

            if (length < grainSize)
            {
                List <Point> L = new List <Point>(length);

                int j = end;
                while (j > end - 2 && j >= start)
                {
                    L.Add(points[j]);
                    j--;
                }
                for (int i = end - 2; i >= start; i--)
                {
                    while (L.Count > 1 && STL.Turn(L[L.Count - 2], L[L.Count - 1], points[i]) <= 0)
                    {
                        L.RemoveAt(L.Count - 1);
                    }
                    L.Add(points[i]);
                }
                return(L);
            }
            else
            {
                int            middle = (length / 2) + start;
                List <Point>[] res    = Parallel.Gather(
                    new LowerHull(points, start, middle, grainSize),
                    new LowerHull(points, middle + 1, end, grainSize));

                return(MergeLowerHulls(res[0], res[1]));
            }
        }
예제 #2
0
        // Find the convex hull
        public List <Point> ConvexHull(List <Point> points)
        {
            int length = points.Count;

            if (length < 3)
            {
                return(points);
            }

            // Sort the points
            points.Sort();

            // Find upper hull
            List <Point> U = new List <Point>(length);

            U.Insert(0, points[0]);
            U.Insert(1, points[1]);
            for (int i = 2; i < length; i++)
            {
                while (U.Count > 1 && STL.Turn(U[U.Count - 2], U[U.Count - 1], points[i]) <= 0)
                {
                    U.RemoveAt(U.Count - 1);
                }
                U.Add(points[i]);
            }

            // Find lower hull
            List <Point> L = new List <Point>(length);

            L.Insert(0, points[length - 1]);
            L.Insert(1, points[length - 2]);
            for (int j = length - 3; j >= 0; j--)
            {
                while (L.Count > 1 && STL.Turn(L[L.Count - 2], L[L.Count - 1], points[j]) <= 0)
                {
                    L.RemoveAt(L.Count - 1);
                }
                L.Add(points[j]);
            }

            // Combine upper hull and lower hull
            U.RemoveAt(U.Count - 1);
            U.AddRange(L);
            U.RemoveAt(U.Count - 1);

            return(U);
        }
예제 #3
0
        // MergeLowerHulls merge two lower hulls in O(n) time.
        private List <Point> MergeLowerHulls(List <Point> P1, List <Point> P2)
        {
            int  lengthP1       = P1.Count;
            int  lengthP2       = P2.Count;
            int  currentP1Index = 0;
            int  currentP2Index = lengthP2 - 1;
            bool done           = false;

            while (!done)
            {
                done = true;
                if (currentP2Index > 0 && STL.Turn(P1[currentP1Index], P2[currentP2Index], P2[currentP2Index - 1]) > 0)
                {
                    done = false;
                    currentP2Index--;
                    while (currentP2Index > 0 && !LowerTangent(P1[currentP1Index], P2[currentP2Index], P2[currentP2Index - 1], P2[currentP2Index + 1]))
                    {
                        currentP2Index--;
                    }
                }

                if (currentP1Index < lengthP1 - 1 && STL.Turn(P2[currentP2Index], P1[currentP1Index], P1[currentP1Index + 1]) < 0)
                {
                    done = false;
                    currentP1Index++;
                    while (currentP1Index < lengthP1 - 1 && !LowerTangent(P2[currentP2Index], P1[currentP1Index], P1[currentP1Index + 1], P1[currentP1Index - 1]))
                    {
                        currentP1Index++;
                    }
                }
            }

            List <Point> L = new List <Point>();

            L.AddRange(P2.GetRange(0, currentP2Index + 1));
            L.AddRange(P1.GetRange(currentP1Index, lengthP1 - currentP1Index));
            return(L);
        }
예제 #4
0
        // If the number of points is less than the grainSize, the Run method
        // simply finds the upper hull by going through all points from left to
        // right, as described in the sequential convex hull algorithm.
        // Otherwise we split the points in two and find the upper hulls
        // concurrently.
        // Finally we merge the two upper hulls and return the upper hull.
        public override List <Point> Run()
        {
            int length = end - start + 1;

            if (length < grainSize)
            {
                List <Point> U = new List <Point>(length);

                int j = start;
                while (j < start + 2 && j <= end)
                {
                    U.Add(points[j]);
                    j++;
                }
                for (int i = start + 2; i <= end; i++)
                {
                    while (U.Count > 1 && STL.Turn(U[U.Count - 2], U[U.Count - 1], points[i]) <= 0)
                    {
                        U.RemoveAt(U.Count - 1);
                    }
                    U.Add(points[i]);
                }
                return(U);
            }
            else
            {
                int middle = (length / 2) + start;
                // The Parallel.Gather is similar to the Parallel.Run method. It runs the submitted
                // tasks concurrently, gather the result from each task and returns array containing
                // all results.
                List <Point>[] res = Parallel.Gather(
                    new UpperHull(points, start, middle, grainSize),
                    new UpperHull(points, middle + 1, end, grainSize));

                return(MergeUpperHulls(res[0], res[1]));
            }
        }
예제 #5
0
        // The main algorithm is fairly simple. We simply
        // sort the points and find the lower and upper hulls
        // concurrently. Finally we combine them and return
        // the points in the convex hull.
        public List <Point> ConvexHull(List <Point> points)
        {
            int length = points.Count;

            // Sort the points, see the STL class
            // for more information on the
            // parallel quicksort implementation.
            STL.QuickSort(points, 10);

            // Find Upper and Lower hull
            // The Parallel.Gather is similar to the Parallel.Run method. It runs the submitted
            // tasks concurrently, gather the result from each task and returns array containing
            // all results.
            List <Point>[] LU = Parallel.Gather(
                new UpperHull(points, 0, length - 1, 10),
                new LowerHull(points, 0, length - 1, 10));

            // Combine Upper and Lower hull
            LU[0].RemoveAt(LU[0].Count - 1);
            LU[0].AddRange(LU[1]);
            LU[0].RemoveAt(LU[0].Count - 1);

            return(LU[0]);
        }
예제 #6
0
 // Returns true if the tangent p0p1 is the lower tangent.
 // p0p1 is the tangent, p2 and p3 are the neighbors of p1.
 // p2 is the next point in the lower hull and p2 is the previous point.
 private bool LowerTangent(Point p0, Point p1, Point p2, Point p3)
 {
     return(!(STL.Turn(p0, p1, p2) < 0 && STL.Turn(p0, p1, p3) > 0));
 }