Exemple #1
0
        //
        // Orient triangles so they have the correct orientation
        //
        public static HashSet <Triangle2> OrientTrianglesClockwise(HashSet <Triangle2> triangles)
        {
            //Convert to list or we will no be able to update the orientation
            List <Triangle2> trianglesList = new List <Triangle2>(triangles);

            for (int i = 0; i < trianglesList.Count; i++)
            {
                Triangle2 t = trianglesList[i];

                if (!_Geometry.IsTriangleOrientedClockwise(t.p1, t.p2, t.p3))
                {
                    t.ChangeOrientation();

                    trianglesList[i] = t;

                    //Debug.Log("Changed orientation");
                }
            }

            //Back to hashset
            triangles = new HashSet <Triangle2>(trianglesList);

            return(triangles);
        }
        //Used for debugging so we can see what's going on
        //public static List<MyVector2> GenerateConvexHull(List<MyVector2> originalPoints, bool includeColinearPoints, AABB normalizingbox, float dMax)


        public static List <MyVector2> GenerateConvexHull(List <MyVector2> originalPoints, bool includeColinearPoints)
        {
            List <MyVector2> pointsOnConvexHull = new List <MyVector2>();


            //Step 1.
            //Find the extreme points along each axis
            //This is similar to AABB but we need both x and y coordinates at each extreme point
            MyVector2 maxX = originalPoints[0];
            MyVector2 minX = originalPoints[0];
            MyVector2 maxY = originalPoints[0];
            MyVector2 minY = originalPoints[0];

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

                if (p.x > maxX.x)
                {
                    maxX = p;
                }
                if (p.x < minX.x)
                {
                    minX = p;
                }

                if (p.y > maxY.y)
                {
                    maxY = p;
                }
                if (p.y < minY.y)
                {
                    minY = p;
                }
            }


            //Step 2.
            //From the 4 extreme points, choose the pair that's furthest appart
            //These two are the first two points on the hull
            List <MyVector2> extremePoints = new List <MyVector2>()
            {
                maxX, minX, maxY, minY
            };

            //Just pick some points as start value
            MyVector2 p1 = maxX;
            MyVector2 p2 = minX;

            //Can use sqr because we are not interested in the exact distance
            float maxDistanceSqr = -Mathf.Infinity;

            //Loop through all points and compare them
            //TODO is comparing too many times: example maxX with maxY, and then maxY with maxX
            //https://stackoverflow.com/questions/12249051/unique-combinations-of-list
            for (int i = 0; i < extremePoints.Count; i++)
            {
                MyVector2 p1_test = extremePoints[i];

                for (int j = 0; j < extremePoints.Count; j++)
                {
                    //Dont compare the point with itself
                    if (i == j)
                    {
                        continue;
                    }

                    MyVector2 p2_test = extremePoints[j];

                    float distSqr = MyVector2.SqrDistance(p1_test, p2_test);

                    if (distSqr > maxDistanceSqr)
                    {
                        maxDistanceSqr = distSqr;

                        p1 = p1_test;
                        p2 = p2_test;
                    }
                }
            }

            //Convert the list to hashset to easier remove points which are on the hull or are inside of the hull
            HashSet <MyVector2> pointsToAdd = new HashSet <MyVector2>(originalPoints);

            //Remove the first 2 points on the hull
            pointsToAdd.Remove(p1);
            pointsToAdd.Remove(p2);


            //Step 3.
            //Find the third point on the hull, by finding the point which is the furthest
            //from the line between p1 and p2
            MyVector2 p3 = FindPointFurthestFromEdge(p1, p2, pointsToAdd);

            //Remove it from the points we want to add
            pointsToAdd.Remove(p3);


            //Step 4. Form the intitial triangle

            //Make sure the hull is oriented counter-clockwise
            Triangle2 tStart = new Triangle2(p1, p2, p3);

            if (_Geometry.IsTriangleOrientedClockwise(tStart.p1, tStart.p2, tStart.p3))
            {
                tStart.ChangeOrientation();
            }

            //New p1-p3
            p1 = tStart.p1;
            p2 = tStart.p2;
            p3 = tStart.p3;

            //pointsOnConvexHull.Add(p1);
            //pointsOnConvexHull.Add(p2);
            //pointsOnConvexHull.Add(p3);

            //Remove the points that we now know are within the hull triangle
            RemovePointsWithinTriangle(tStart, pointsToAdd);


            //Step 5.
            //Associate the rest of the points to their closest edge
            HashSet <MyVector2> edge_p1p2_points = new HashSet <MyVector2>();
            HashSet <MyVector2> edge_p2p3_points = new HashSet <MyVector2>();
            HashSet <MyVector2> edge_p3p1_points = new HashSet <MyVector2>();

            foreach (MyVector2 p in pointsToAdd)
            {
                //p1 p2
                LeftOnRight pointRelation1 = _Geometry.IsPoint_Left_On_Right_OfVector(p1, p2, p);

                if (pointRelation1 == LeftOnRight.On || pointRelation1 == LeftOnRight.Right)
                {
                    edge_p1p2_points.Add(p);

                    continue;
                }

                //p2 p3
                LeftOnRight pointRelation2 = _Geometry.IsPoint_Left_On_Right_OfVector(p2, p3, p);

                if (pointRelation2 == LeftOnRight.On || pointRelation2 == LeftOnRight.Right)
                {
                    edge_p2p3_points.Add(p);

                    continue;
                }

                //p3 p1
                //If the point hasnt been added yet, we know it belong to this edge
                edge_p3p1_points.Add(p);
            }


            //Step 6
            //For each edge, find the point furthest away and create a new triangle
            //and repeat the above steps by finding which points are inside of the hull
            //and which points are outside and belong to a new edge

            //Will automatically ignore the last point on this sub-hull to avoid doubles
            List <MyVector2> pointsOnHUll_p1p2 = CreateSubConvexHUll(p1, p2, edge_p1p2_points);

            List <MyVector2> pointsOnHUll_p2p3 = CreateSubConvexHUll(p2, p3, edge_p2p3_points);

            List <MyVector2> pointsOnHUll_p3p1 = CreateSubConvexHUll(p3, p1, edge_p3p1_points);


            //Create the final hull by combing the points
            pointsOnConvexHull.Clear();

            pointsOnConvexHull.AddRange(pointsOnHUll_p1p2);
            pointsOnConvexHull.AddRange(pointsOnHUll_p2p3);
            pointsOnConvexHull.AddRange(pointsOnHUll_p3p1);



            //Step 7. Add colinear points
            //I think the easiest way to add colinear points is to add them when the algorithm is finished
            if (includeColinearPoints)
            {
                pointsOnConvexHull = AddColinearPoints(pointsOnConvexHull, originalPoints);
            }


            //Debug.Log("Points on hull: " + pointsOnConvexHull.Count);


            return(pointsOnConvexHull);
        }