//
        // Edge stuff
        //

        //Are two edges the same edge?
        private static bool AreTwoEdgesTheSame(MyVector2 e1_p1, MyVector2 e1_p2, MyVector2 e2_p1, MyVector2 e2_p2)
        {
            //Is e1_p1 part of this constraint?
            if ((e1_p1.Equals(e2_p1) || e1_p1.Equals(e2_p2)))
            {
                //Is e1_p2 part of this constraint?
                if ((e1_p2.Equals(e2_p1) || e1_p2.Equals(e2_p2)))
                {
                    return(true);
                }
            }

            return(false);
        }
Beispiel #2
0
 //Find the opposite edge to a vertex
 public Edge2 FindOppositeEdgeToVertex(MyVector2 p)
 {
     if (p.Equals(p1))
     {
         return(new Edge2(p2, p3));
     }
     else if (p.Equals(p2))
     {
         return(new Edge2(p3, p1));
     }
     else
     {
         return(new Edge2(p1, p2));
     }
 }
        //Get a list with unique edges
        //Currently we have two half-edges for each edge, making it time consuming
        //So this method is not always needed, but can be useful
        //But be careful because it takes time to generate this list as well, so measure that the algorithm is faster by using this list
        public HashSet <HalfEdge2> GetUniqueEdges()
        {
            HashSet <HalfEdge2> uniqueEdges = new HashSet <HalfEdge2>();

            foreach (HalfEdge2 e in edges)
            {
                MyVector2 p1 = e.v.position;
                MyVector2 p2 = e.prevEdge.v.position;

                bool isInList = false;

                //TODO: Put these in a lookup dictionary to improve performance
                foreach (HalfEdge2 eUnique in uniqueEdges)
                {
                    MyVector2 p1_test = eUnique.v.position;
                    MyVector2 p2_test = eUnique.prevEdge.v.position;

                    if ((p1.Equals(p1_test) && p2.Equals(p2_test)) || (p2.Equals(p1_test) && p1.Equals(p2_test)))
                    {
                        isInList = true;

                        break;
                    }
                }

                if (!isInList)
                {
                    uniqueEdges.Add(e);
                }
            }

            return(uniqueEdges);
        }
Beispiel #4
0
        //Get a list with unique edges
        //Currently we have two half-edges for each edge, making it time consuming
        //So this method is not always needed, but can be useful
        public List <HalfEdge2> GetUniqueEdges()
        {
            List <HalfEdge2> uniqueEdges = new List <HalfEdge2>();

            foreach (HalfEdge2 e in edges)
            {
                MyVector2 p1 = e.v.position;
                MyVector2 p2 = e.prevEdge.v.position;

                bool isInList = false;

                for (int j = 0; j < uniqueEdges.Count; j++)
                {
                    HalfEdge2 testEdge = uniqueEdges[j];

                    MyVector2 p1_test = testEdge.v.position;
                    MyVector2 p2_test = testEdge.prevEdge.v.position;

                    if ((p1.Equals(p1_test) && p2.Equals(p2_test)) || (p2.Equals(p1_test) && p1.Equals(p2_test)))
                    {
                        isInList = true;

                        break;
                    }
                }

                if (!isInList)
                {
                    uniqueEdges.Add(e);
                }
            }

            return(uniqueEdges);
        }
Beispiel #5
0
        //Is an edge crossing another edge?
        private static bool IsEdgeCrossingEdge(MyVector2 e1_p1, MyVector2 e1_p2, MyVector2 e2_p1, MyVector2 e2_p2)
        {
            //We will here run into floating point precision issues so we have to be careful
            //To solve that you can first check the end points
            //and modify the line-line intersection algorithm to include a small epsilon

            //First check if the edges are sharing a point, if so they are not crossing
            if (e1_p1.Equals(e2_p1) || e1_p1.Equals(e2_p2) || e1_p2.Equals(e2_p1) || e1_p2.Equals(e2_p2))
            {
                return(false);
            }

            //Then check if the lines are intersecting
            if (!_Intersections.LineLine(new Edge2(e1_p1, e1_p2), new Edge2(e2_p1, e2_p2), includeEndPoints: false))
            {
                return(false);
            }

            return(true);
        }
        //
        // Split triangle edge
        //
        //Split an edge at a point on the edge to form four new triangles, while removing two old
        //public static void SplitTriangleEdge(HalfEdge e, Vector3 splitPosition)
        //{

        //}



        //
        // Split triangle face
        //
        //Split a face (which we know is a triangle) at a point to create three new triangles while removing the old triangle
        //Could maybe make it more general so we can split a face, which consists of n edges
        public static void SplitTriangleFaceAtPoint(HalfEdgeFace2 f, MyVector2 splitPosition, HalfEdgeData2 data)
        {
            //The edges that belongs to this face
            HalfEdge2 e_1 = f.edge;
            HalfEdge2 e_2 = e_1.nextEdge;
            HalfEdge2 e_3 = e_2.nextEdge;

            //A list with new edges so we can connect the new edges with an edge on the opposite side
            HashSet <HalfEdge2> newEdges = new HashSet <HalfEdge2>();

            CreateNewFace(e_1, splitPosition, data, newEdges);
            CreateNewFace(e_2, splitPosition, data, newEdges);
            CreateNewFace(e_3, splitPosition, data, newEdges);

            //Debug.Log("New edges " + newEdges.Count);

            //Find the opposite connections
            foreach (HalfEdge2 e in newEdges)
            {
                //If we have already found a opposite
                if (e.oppositeEdge != null)
                {
                    continue;
                }

                MyVector2 eGoingTo   = e.v.position;
                MyVector2 eGoingFrom = e.prevEdge.v.position;

                foreach (HalfEdge2 eOpposite in newEdges)
                {
                    if (e == eOpposite || eOpposite.oppositeEdge != null)
                    {
                        continue;
                    }

                    MyVector2 eGoingTo_Other   = eOpposite.v.position;
                    MyVector2 eGoingFrom_Other = eOpposite.prevEdge.v.position;

                    if (eGoingTo.Equals(eGoingFrom_Other) && eGoingFrom.Equals(eGoingTo_Other))
                    {
                        e.oppositeEdge = eOpposite;
                        //Might as well connect it from the other way as well
                        eOpposite.oppositeEdge = e;

                        //Debug.Log("Found opposite");
                    }
                }
            }

            //Delete the old triangle
            DeleteTriangleFace(f, data, false);
        }
Beispiel #7
0
        //Find a triangle which has an edge going from p1 to p2
        //private static HalfEdgeFace2 FindTriangleWithEdge(MyVector2 p1, MyVector2 p2, HalfEdgeData2 triangleData)
        //{
        //    HashSet<HalfEdge2> edges = triangleData.edges;

        //    foreach (HalfEdge2 e in edges)
        //    {
        //        //An edge is going TO a vertex
        //        MyVector2 e_p1 = e.prevEdge.v.position;
        //        MyVector2 e_p2 = e.v.position;

        //        if (e_p1.Equals(p1) && e_p2.Equals(p2))
        //        {
        //            return e.face;
        //        }
        //    }

        //    return null;
        //}



        //Find all half-edges that are constraint
        private static HashSet <HalfEdge2> FindAllConstraintEdges(List <MyVector2> constraints, HalfEdgeData2 triangleData)
        {
            HashSet <HalfEdge2> constrainEdges = new HashSet <HalfEdge2>();


            //Create a new set with all constrains, and as we discover new constraints, we delete constrains, which will make searching faster
            //A constraint can only exist once!
            HashSet <Edge2> constraintsEdges = new HashSet <Edge2>();

            for (int i = 0; i < constraints.Count; i++)
            {
                MyVector2 c_p1 = constraints[i];
                MyVector2 c_p2 = constraints[MathUtility.ClampListIndex(i + 1, constraints.Count)];

                constraintsEdges.Add(new Edge2(c_p1, c_p2));
            }


            //All edges we have to search
            HashSet <HalfEdge2> edges = triangleData.edges;

            foreach (HalfEdge2 e in edges)
            {
                //An edge is going TO a vertex
                MyVector2 e_p1 = e.prevEdge.v.position;
                MyVector2 e_p2 = e.v.position;

                //Is this edge a constraint?
                foreach (Edge2 c_edge in constraintsEdges)
                {
                    if (e_p1.Equals(c_edge.p1) && e_p2.Equals(c_edge.p2))
                    {
                        constrainEdges.Add(e);

                        constraintsEdges.Remove(c_edge);

                        //Move on to the next edge
                        break;
                    }
                }

                //We have found all constraint, so don't need to search anymore
                if (constraintsEdges.Count == 0)
                {
                    break;
                }
            }

            return(constrainEdges);
        }
Beispiel #8
0
        //Find a triangle which has an edge going from p1 to p2
        private static HalfEdgeFace2 FindTriangleWithEdge(MyVector2 p1, MyVector2 p2, HalfEdgeData2 triangleData)
        {
            HashSet <HalfEdge2> edges = triangleData.edges;

            foreach (HalfEdge2 e in edges)
            {
                //An edge is going TO a vertex
                MyVector2 e_p1 = e.prevEdge.v.position;
                MyVector2 e_p2 = e.v.position;

                if (e_p1.Equals(p1) && e_p2.Equals(p2))
                {
                    return(e.face);
                }
            }

            return(null);
        }
Beispiel #9
0
        //Find which position in the list a vertex has
        //If there are multiple, we want the last one
        public int GetLastListPos(MyVector2 pos)
        {
            List <MyVector2> vertices = polygon.vertices;

            int listPos = -1;

            for (int i = 0; i < vertices.Count; i++)
            {
                if (pos.Equals(vertices[i]))
                {
                    listPos = i;

                    //In some cases there are multiple of this vertices and we want the last one
                    //So we want stop searching after finding the first one
                    //break;
                }
            }

            return(listPos);
        }
        public static List <MyVector2> GenerateConvexHull(List <MyVector2> points)
        {
            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);

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

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

                    //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
                    }
                    //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!



            return(pointsOnConvexHull);
        }
Beispiel #11
0
        //Find all triangles that share a specific constraint
        private static HashSet <HalfEdgeFace2> FindAllTrianglesBorderingTheConstraint(List <MyVector2> constraints, HalfEdgeData2 triangleData)
        {
            HashSet <HalfEdgeFace2> facesOnTheBorder = new HashSet <HalfEdgeFace2>();


            //Create a new set with all constrains, and as we discover new constraints, we delete constrains, which will make searching faster
            HashSet <Edge2> constraintsEdges = new HashSet <Edge2>();

            for (int i = 0; i < constraints.Count; i++)
            {
                MyVector2 c_p1 = constraints[i];
                MyVector2 c_p2 = constraints[MathUtility.ClampListIndex(i + 1, constraints.Count)];

                constraintsEdges.Add(new Edge2(c_p1, c_p2));
            }


            //Faster to search faces becase a triangle might have multiple constraints bordering it and we just need to find one
            HashSet <HalfEdgeFace2> faces = triangleData.faces;

            List <HalfEdge2> edges = new List <HalfEdge2>();

            foreach (HalfEdgeFace2 f in faces)
            {
                edges.Clear();

                edges.Add(f.edge);
                edges.Add(f.edge.nextEdge);
                edges.Add(f.edge.nextEdge.nextEdge);

                foreach (HalfEdge2 e in edges)
                {
                    //An edge is going TO a vertex
                    MyVector2 e_p1 = e.prevEdge.v.position;
                    MyVector2 e_p2 = e.v.position;

                    //Is this edge a constraint?
                    bool foundConstraint = false;

                    foreach (Edge2 c_edge in constraintsEdges)
                    {
                        if (e_p1.Equals(c_edge.p1) && e_p2.Equals(c_edge.p2))
                        {
                            facesOnTheBorder.Add(f);

                            constraintsEdges.Remove(c_edge);

                            foundConstraint = true;

                            break;
                        }
                    }

                    if (foundConstraint)
                    {
                        break;
                    }
                }

                if (constraintsEdges.Count == 0)
                {
                    break;
                }
            }

            return(facesOnTheBorder);
        }
Beispiel #12
0
        //
        // Try to restore the delaunay triangulation by flipping newly created edges
        //

        //This process is similar to when we created the original delaunay triangulation
        //This step can maybe be skipped if you just want a triangulation and Ive noticed its often not flipping any triangles
        private static void RestoreDelaunayTriangulation(MyVector2 c_p1, MyVector2 c_p2, List <HalfEdge2> newEdges)
        {
            int safety = 0;

            int flippedEdges = 0;

            //Repeat 4.1 - 4.3 until no further swaps take place
            while (true)
            {
                safety += 1;

                if (safety > 100000)
                {
                    Debug.Log("Stuck in endless loop when delaunay after fixing constrained edges");

                    break;
                }

                bool hasFlippedEdge = false;

                //Step 4.1. Loop over each edge in the list of newly created edges
                for (int j = 0; j < newEdges.Count; j++)
                {
                    HalfEdge2 e = newEdges[j];

                    //Step 4.2. Let the newly created edge be defined by the vertices
                    MyVector2 v_k = e.v.position;
                    MyVector2 v_l = e.prevEdge.v.position;

                    //If this edge is equal to the constrained edge, then skip to step 4.1
                    //because we are not allowed to flip the constrained edge
                    if ((v_k.Equals(c_p1) && v_l.Equals(c_p2)) || (v_l.Equals(c_p1) && v_k.Equals(c_p2)))
                    {
                        continue;
                    }

                    //Step 4.3. If the two triangles that share edge v_k and v_l don't satisfy the delaunay criterion,
                    //so that a vertex of one of the triangles is inside the circumcircle of the other triangle, flip the edge
                    //The third vertex of the triangle belonging to this edge
                    MyVector2 v_third_pos = e.nextEdge.v.position;
                    //The vertice belonging to the triangle on the opposite side of the edge and this vertex is not a part of the edge
                    MyVector2 v_opposite_pos = e.oppositeEdge.nextEdge.v.position;

                    //Test if we should flip this edge
                    if (DelaunayMethods.ShouldFlipEdge(v_l, v_k, v_third_pos, v_opposite_pos))
                    {
                        //Flip the edge
                        hasFlippedEdge = true;

                        HalfEdgeHelpMethods.FlipTriangleEdge(e);

                        flippedEdges += 1;
                    }
                }

                //We have searched through all edges and havent found an edge to flip, so we cant improve anymore
                if (!hasFlippedEdge)
                {
                    Debug.Log("Found a constrained delaunay triangulation in " + flippedEdges + " flips");

                    break;
                }
            }
        }