//
        // Is a quadrilateral convex? Assume no 3 points are colinear and the shape doesnt look like an hourglass
        //
        //A quadrilateral is a polygon with four edges (or sides) and four vertices or corners
        public static bool IsQuadrilateralConvex(MyVector2 a, MyVector2 b, MyVector2 c, MyVector2 d)
        {
            bool isConvex = false;

            //Convex if the convex hull includes all 4 points - will require just 4 determinant operations
            //In this case we dont kneed to know the order of the points, which is better
            //We could split it up into triangles, but still messy because of interior/exterior angles
            //Another version is if we know the edge between the triangles that form a quadrilateral
            //then we could measure the 4 angles of the edge, add them together (2 and 2) to get the interior angle
            //But it will still require 8 magnitude operations which is slow
            //From: https://stackoverflow.com/questions/2122305/convex-hull-of-4-points
            bool abc = Geometry.IsTriangleOrientedClockwise(a, b, c);
            bool abd = Geometry.IsTriangleOrientedClockwise(a, b, d);
            bool bcd = Geometry.IsTriangleOrientedClockwise(b, c, d);
            bool cad = Geometry.IsTriangleOrientedClockwise(c, a, d);

            if (abc && abd && bcd & !cad)
            {
                isConvex = true;
            }
            else if (abc && abd && !bcd & cad)
            {
                isConvex = true;
            }
            else if (abc && !abd && bcd & cad)
            {
                isConvex = true;
            }
            //The opposite sign, which makes everything inverted
            else if (!abc && !abd && !bcd & cad)
            {
                isConvex = true;
            }
            else if (!abc && !abd && bcd & !cad)
            {
                isConvex = true;
            }
            else if (!abc && abd && !bcd & !cad)
            {
                isConvex = true;
            }


            return(isConvex);
        }
        //
        // 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);
        }
        //We assume an edge is visible from a point if the triangle (formed by travering edges in the convex hull
        //of the existing triangulation) form a clockwise triangle with the point
        //https://stackoverflow.com/questions/8898255/check-whether-a-point-is-visible-from-a-face-of-a-2d-convex-hull
        private static HashSet <Triangle2> TriangulatePointsConvexHull(HashSet <MyVector2> points)
        {
            if (points.Count < 3)
            {
                Debug.Log("You need at least 3 points to form a triangle!");

                return(null);
            }


            //Step 0. Init the triangles we will return
            HashSet <Triangle2> triangles = new HashSet <Triangle2>();



            //Step 1. Sort the points
            List <MyVector2> sortedPoints = new List <MyVector2>(points);

            //OrderBy is always soring in ascending order - use OrderByDescending to get in the other order
            //sortedPoints = sortedPoints.OrderBy(n => n.x).ToList();

            //If we have colinear points we have to sort in both x and y
            sortedPoints = sortedPoints.OrderBy(n => n.x).ThenBy(n => n.y).ToList();



            //Step 2. Create the first triangle so we can start the algorithm because we need edges to look at
            //and see if they are visible

            //Pick the first two points in the sorted list - These are always a part of the first triangle
            MyVector2 p1 = sortedPoints[0];
            MyVector2 p2 = sortedPoints[1];

            //Remove them
            sortedPoints.RemoveAt(0);
            sortedPoints.RemoveAt(0);

            //The problem is the third point
            //If we have colinear points, then the third point in the sorted list is not always a valid point
            //to form a triangle because then it will be flat
            //So we have to look for a better point
            for (int i = 0; i < sortedPoints.Count; i++)
            {
                //We have found a non-colinear point
                LeftOnRight pointRelation = Geometry.IsPoint_Left_On_Right_OfVector(p1, p2, sortedPoints[i]);

                if (pointRelation == LeftOnRight.Left || pointRelation == LeftOnRight.Right)
                {
                    MyVector2 p3 = sortedPoints[i];

                    //Remove this point
                    sortedPoints.RemoveAt(i);

                    //Build the first triangle
                    Triangle2 newTriangle = new Triangle2(p1, p2, p3);

                    triangles.Add(newTriangle);

                    break;
                }
            }

            //If we have finished search and not found a triangle, that means that all points
            //are colinear and we cant form any triangles
            if (triangles.Count == 0)
            {
                Debug.Log("All points you want to triangulate a co-linear");

                return(null);
            }



            //Step 3. Add the other points one-by-one

            //For each point we add we have to calculate a convex hull of the previous points
            //An optimization is to not use all points in the triangulation
            //to calculate the hull because many of them might be inside of the hull
            //So we will use the previous points on the hull and add the point we added last iteration
            //to generate the new convex hull

            //First we need to init the convex hull
            HashSet <MyVector2> triangulatePoints = new HashSet <MyVector2>();

            foreach (Triangle2 t in triangles)
            {
                triangulatePoints.Add(t.p1);
                triangulatePoints.Add(t.p2);
                triangulatePoints.Add(t.p3);
            }

            //Calculate the first convex hull
            List <MyVector2> pointsOnHull = _ConvexHull.JarvisMarch(triangulatePoints);

            //Add the other points one-by-one
            foreach (MyVector2 pointToAdd in sortedPoints)
            {
                bool couldFormTriangle = false;

                //Loop through all edges in the convex hull
                for (int j = 0; j < pointsOnHull.Count; j++)
                {
                    MyVector2 hull_p1 = pointsOnHull[j];
                    MyVector2 hull_p2 = pointsOnHull[MathUtility.ClampListIndex(j + 1, pointsOnHull.Count)];

                    //First we have to check if the points are colinear, then we cant form a triangle
                    LeftOnRight pointRelation = Geometry.IsPoint_Left_On_Right_OfVector(hull_p1, hull_p2, pointToAdd);

                    if (pointRelation == LeftOnRight.On)
                    {
                        continue;
                    }

                    //If this triangle is clockwise, then we can see the edge
                    //so we should create a new triangle with this edge and the point
                    if (Geometry.IsTriangleOrientedClockwise(hull_p1, hull_p2, pointToAdd))
                    {
                        triangles.Add(new Triangle2(hull_p1, hull_p2, pointToAdd));

                        couldFormTriangle = true;
                    }
                }

                //Add the point to the list of points on the hull
                //Will re-generate the hull by using these points so dont worry that the
                //list is not valid anymore
                if (couldFormTriangle)
                {
                    pointsOnHull.Add(pointToAdd);

                    //Find the convex hull of the current triangulation
                    //It generates a counter-clockwise convex hull
                    pointsOnHull = _ConvexHull.JarvisMarch(new HashSet <MyVector2>(pointsOnHull));
                }
                else
                {
                    Debug.Log("This point could not form any triangles " + pointToAdd.x + " " + pointToAdd.y);
                }
            }



            return(triangles);
        }
Example #4
0
        //We assume an edge is visible from a point if the triangle (formed by travering edges in the convex hull
        //of the existing triangulation) form a clockwise triangle with the point
        //https://stackoverflow.com/questions/8898255/check-whether-a-point-is-visible-from-a-face-of-a-2d-convex-hull
        private static HashSet <Triangle2> TriangulatePointsConvexHull(HashSet <MyVector2> pointsHashset)
        {
            HashSet <Triangle2> triangles = new HashSet <Triangle2>();

            //The points we will add
            List <MyVector2> originalPoints = new List <MyVector2>(pointsHashset);


            //Step 1. Sort the points along x-axis
            //OrderBy is always soring in ascending order - use OrderByDescending to get in the other order
            //originalPoints = originalPoints.OrderBy(n => n.x).ThenBy(n => n.y).ToList();
            originalPoints = originalPoints.OrderBy(n => n.x).ToList();


            //Step 2. Create the first triangle so we can start the algorithm

            //Assumes the convex hull algorithm sorts in the same way in x and y directions as we do above
            MyVector2 p1Start = originalPoints[0];
            MyVector2 p2Start = originalPoints[1];
            MyVector2 p3Start = originalPoints[2];

            //Theese points for the first triangle
            Triangle2 newTriangle = new Triangle2(p1Start, p2Start, p3Start);

            triangles.Add(newTriangle);


            //All points that form the triangles
            HashSet <MyVector2> triangulatedPoints = new HashSet <MyVector2>();

            triangulatedPoints.Add(p1Start);
            triangulatedPoints.Add(p2Start);
            triangulatedPoints.Add(p3Start);


            //Step 3. Add the other points one-by-one
            //Add the other points one by one
            //Starts at 3 because we have already added 0,1,2
            for (int i = 3; i < originalPoints.Count; i++)
            {
                MyVector2 pointToAdd = originalPoints[i];

                //Find the convex hull of the current triangulation
                //It generates a counter-clockwise convex hull
                List <MyVector2> pointsOnHull = _ConvexHull.JarvisMarch(triangulatedPoints);

                if (pointsOnHull == null)
                {
                    Debug.Log("No points on hull when triangulating");

                    continue;
                }

                bool couldFormTriangle = false;

                //Loop through all edges in the convex hull
                for (int j = 0; j < pointsOnHull.Count; j++)
                {
                    MyVector2 p1 = pointsOnHull[j];
                    MyVector2 p2 = pointsOnHull[MathUtility.ClampListIndex(j + 1, pointsOnHull.Count)];

                    //If this triangle is clockwise, then we can see the edge
                    //so we should create a new triangle with this edge and the point
                    if (Geometry.IsTriangleOrientedClockwise(p1, p2, pointToAdd))
                    {
                        triangles.Add(new Triangle2(p1, p2, pointToAdd));

                        couldFormTriangle = true;
                    }
                }

                //Add the point to the list of all points in the current triangulation
                //if the point could form a triangle
                if (couldFormTriangle)
                {
                    triangulatedPoints.Add(pointToAdd);
                }
            }



            return(triangles);
        }