// // 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); }