//Remove the supertriangle
    IEnumerator RemoveSuperTriangle(Triangle2 superTriangle, HalfEdgeData2 triangulationData)
    {
        //The super triangle doesnt exists anymore because we have split it into many new triangles
        //But we can use its vertices to figure out which new triangles (or faces belonging to the triangle)
        //we should delete

        HashSet <HalfEdgeFace2> triangleFacesToDelete = new HashSet <HalfEdgeFace2>();

        //Loop through all vertices belongin to the triangulation
        foreach (HalfEdgeVertex2 v in triangulationData.vertices)
        {
            //If the face attached to this vertex already exists in the list of faces we want to delete
            //Then dont add it again
            if (triangleFacesToDelete.Contains(v.edge.face))
            {
                continue;
            }

            MyVector2 v1 = v.position;

            //Is this vertex in the triangulation a vertex in the super triangle?
            if (v1.Equals(superTriangle.p1) || v1.Equals(superTriangle.p2) || v1.Equals(superTriangle.p3))
            {
                triangleFacesToDelete.Add(v.edge.face);
            }
        }

        //Debug.Log("Triangles to delete: " + trianglesToDelete.Count);

        //Delete the new triangles with vertices attached to the super triangle
        foreach (HalfEdgeFace2 f in triangleFacesToDelete)
        {
            HalfEdgeHelpMethods.DeleteTriangleFace(f, triangulationData, shouldSetOppositeToNull: true);


            //VISUALZ
            ShowTriangles(triangulationData);

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


        //VISUALZ - show the colored mesh when its finished
        controller.shouldDisplayColoredMesh = true;

        yield return(null);
    }
Exemple #2
0
    //Is an edge between p1 and p2 a constraint?
    //private static bool IsEdgeAConstraint(MyVector2 p1, MyVector2 p2, List<MyVector2> constraints)
    //{
    //    for (int i = 0; i < constraints.Count; i++)
    //    {
    //        MyVector2 c_p1 = constraints[i];
    //        MyVector2 c_p2 = constraints[MathUtility.ClampListIndex(i + 1, constraints.Count)];

    //        if (AreTwoEdgesTheSame(p1, p2, c_p1, c_p2))
    //        {
    //            return true;
    //        }
    //    }

    //    return false;
    //}



    //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);
    }
Exemple #3
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);
    }
Exemple #4
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 IEnumerator RestoreDelaunayTriangulation(MyVector2 c_p1, MyVector2 c_p2, List <HalfEdge2> newEdges, HalfEdgeData2 triangleData, Normalizer2 normalizer)
    {
        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;


                    //
                    // PAUSE AND VISUALIZE
                    //

                    visualizeController.DisplayMeshMain(triangleData, normalizer);

                    yield return(new WaitForSeconds(0.5f));
                }
            }

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