コード例 #1
0
    private IEnumerator RunAlgorithm(List <MyVector2> points)
    {
        //The list with points on the convex hull
        List <MyVector2> pointsOnConvexHull = new List <MyVector2>();


        //Step 0. Normalize the data to range [0, 1] or everything will break at larger sizes :(
        //Make sure the data is already normalized!!!



        //Step 1. Find the vertex with the smallest x coordinate
        //If several points have the same x coordinate, find the one with the smallest y
        MyVector2 startPos = points[0];

        for (int i = 1; i < points.Count; i++)
        {
            MyVector2 testPos = points[i];

            //Because of precision issues, we use a small value to test if they are the same
            if (testPos.x < startPos.x || ((Mathf.Abs(testPos.x - startPos.x) < MathUtility.EPSILON && testPos.y < startPos.y)))
            {
                startPos = points[i];
            }
        }

        //This vertex is always on the convex hull
        pointsOnConvexHull.Add(startPos);


        //VISUALIZE
        ShowHull(pointsOnConvexHull, null);

        yield return(new WaitForSeconds(controller.pauseTime));


        //But we can't remove it from the list of all points because we need it to stop the algorithm
        //points.Remove(startPos);



        //Step 2. Loop to find the other points on the hull
        MyVector2 previousPoint = pointsOnConvexHull[0];

        int counter = 0;

        while (true)
        {
            //We might have colinear points, so we need a list to save all points added this iteration
            List <MyVector2> pointsToAddToTheHull = new List <MyVector2>();


            //Pick next point randomly
            MyVector2 nextPoint = points[Random.Range(0, points.Count)];

            //If we are coming from the first point on the convex hull
            //then we are not allowed to pick it as next point, so we have to try again
            if (previousPoint.Equals(pointsOnConvexHull[0]) && nextPoint.Equals(pointsOnConvexHull[0]))
            {
                counter += 1;

                continue;
            }


            //VISUALIZE
            ShowHull(pointsOnConvexHull, new List <MyVector2>()
            {
                nextPoint
            });
            //ShowActivePoint(nextPoint);

            yield return(new WaitForSeconds(controller.pauseTime));

            //This point is assumed to be on the convex hull
            pointsToAddToTheHull.Add(nextPoint);


            //But this randomly selected point might not be the best next point, so we have to see if we can improve
            //by finding a point that is more to the right
            //We also have to check if this point has colinear points if it happens to be on the hull
            for (int i = 0; i < points.Count; i++)
            {
                MyVector2 testPoint = points[i];

                //Dont test the point we picked randomly
                //Or the point we are coming from which might happen when we move from the first point on the hull
                if (testPoint.Equals(nextPoint) || testPoint.Equals(previousPoint))
                {
                    continue;
                }


                //VISUALIZE
                //ShowHull(pointsOnConvexHull, new List<MyVector2>() { testPoint });
                ShowActivePoint(testPoint);

                yield return(new WaitForSeconds(controller.pauseTime));


                //Where is the test point in relation to the line between the point we are coming from
                //which we know is on the hull, and the point we think is on the hull
                LeftOnRight pointRelation = _Geometry.IsPoint_Left_On_Right_OfVector(previousPoint, nextPoint, testPoint);

                //The test point is on the line, so we have found a colinear point
                if (pointRelation == LeftOnRight.On)
                {
                    pointsToAddToTheHull.Add(testPoint);
                }
                //To the right = better point, so pick it as next point we want to test if it is on the hull
                else if (pointRelation == LeftOnRight.Right)
                {
                    nextPoint = testPoint;

                    //Clear colinear points because they belonged to the old point which was worse
                    pointsToAddToTheHull.Clear();

                    pointsToAddToTheHull.Add(nextPoint);

                    //We dont have to start over because the previous points weve gone through were worse


                    //VISUALIZE
                    ShowHull(pointsOnConvexHull, pointsToAddToTheHull);

                    yield return(new WaitForSeconds(controller.pauseTime));
                }
                //To the left = worse point so do nothing
            }



            //Sort this list, so we can add the colinear points in correct order
            pointsToAddToTheHull = pointsToAddToTheHull.OrderBy(n => MyVector2.SqrMagnitude(n - previousPoint)).ToList();

            pointsOnConvexHull.AddRange(pointsToAddToTheHull);

            //Remove the points that are now on the convex hull, which should speed up the algorithm
            //Or will it be slower because it also takes some time to remove points?
            for (int i = 0; i < pointsToAddToTheHull.Count; i++)
            {
                points.Remove(pointsToAddToTheHull[i]);
            }


            //The point we are coming from in the next iteration
            previousPoint = pointsOnConvexHull[pointsOnConvexHull.Count - 1];


            //Have we found the first point on the hull? If so we have completed the hull
            if (previousPoint.Equals(pointsOnConvexHull[0]))
            {
                //Then remove it because it is the same as the first point, and we want a convex hull with no duplicates
                pointsOnConvexHull.RemoveAt(pointsOnConvexHull.Count - 1);

                //Stop the loop!
                break;
            }


            //Safety
            if (counter > 100000)
            {
                Debug.Log("Stuck in endless loop when generating convex hull with jarvis march");

                break;
            }

            counter += 1;
        }



        //Dont forget to unnormalize the points!

        //VISUALIZE
        ShowHull(pointsOnConvexHull, new List <MyVector2>()
        {
            pointsOnConvexHull[0]
        });

        yield return(null);
    }