//
    // Visualz
    //

    //Show triangles
    private void ShowTriangles(HalfEdgeData2 triangles)
    {
        controller.ResetMultiColoredMeshes();

        List <Mesh> meshes = controller.GenerateTriangulationMesh(triangles, shouldUnNormalize: true);

        List <Material> materials = controller.GenerateRandomMaterials(meshes.Count);

        controller.multiColoredMeshes          = meshes;
        controller.multiColoredMeshesMaterials = materials;
    }
Пример #2
0
    //
    // Display stuff
    //

    //Show points
    private void ShowPoints(HashSet <MyVector2> points)
    {
        controller.ResetBlackMeshes();


        HashSet <Triangle2> triangles = new HashSet <Triangle2>();

        foreach (MyVector2 p in points)
        {
            MyVector2 point = controller.UnNormalize(p);

            HashSet <Triangle2> circleTriangles = _GenerateMesh.Circle(point, 0.1f, 10);

            triangles.UnionWith(circleTriangles);
        }


        //Will unnormalize
        List <Mesh> meshes = controller.GenerateTriangulationMesh(triangles, shouldUnNormalize: false);

        controller.blackMeshes = meshes;
    }
Пример #3
0
    //
    // For visualization when pressing Play button
    //

    private void Start()
    {
        GenerateTriangulation();


        //To access standardized methods for visualizations
        VisualizerController visualizerController = GetComponent <VisualizerController>();

        //Generate the meshes and materials once
        meshes = visualizerController.GenerateTriangulationMesh(triangulation, shouldUnNormalize: false);

        materials = visualizerController.GenerateRandomMaterials(meshes.Count);

        StartCoroutine(DisplayTriangleByTriangle(meshes));
    }
    public void StartVisualizer(HashSet <MyVector2> points, HalfEdgeData2 triangleData)
    {
        controller = GetComponent <VisualizerController>();

        //Step 1. Triangulate the points with some algorithm. The result is a convex triangulation
        HashSet <Triangle2> triangles = _TriangulatePoints.VisibleEdgesTriangulation(points);

        //HashSet<Triangle2> triangles = _TriangulatePoints.TriangleSplitting(points);

        //Step 2. Change the data structure from triangle to half-edge to make it easier to flip edges
        triangleData = _TransformBetweenDataStructures.Triangle2ToHalfEdge2(triangles, triangleData);

        //Generate the visual triangles
        controller.GenerateTriangulationMesh(triangleData);

        //Step 3. Flip edges until we have a delaunay triangulation
        StartCoroutine(FlipEdges(triangleData));
    }
    //
    // Visualize stuff
    //

    private void ShowAllPoints(HashSet <MyVector2> points)
    {
        HashSet <Triangle2> triangles = new HashSet <Triangle2>();

        foreach (MyVector2 p in points)
        {
            HashSet <Triangle2> tCircle = _GenerateMesh.Circle(controller.UnNormalize(p), 0.1f, 10);

            triangles.UnionWith(tCircle);
        }

        //To mesh
        List <Mesh> meshes = controller.GenerateTriangulationMesh(triangles, shouldUnNormalize: false);

        controller.ResetBlackMeshes();

        controller.blackMeshes = meshes;

        //Debug.Log(meshes.Count);
    }
    //Flip edges until we get a delaunay triangulation
    private IEnumerator FlipEdges(HalfEdgeData2 triangleData)
    {
        //The edges we want to flip
        HashSet <HalfEdge2> edges = triangleData.edges;

        //To avoid getting stuck in infinite loop
        int safety = 0;

        //Count how many edges we have flipped, which may be interesting to display
        int flippedEdges = 0;

        while (true)
        {
            safety += 1;

            if (safety > 100000)
            {
                Debug.Log("Stuck in endless loop when flipping edges to get a Delaunay triangulation");

                break;
            }

            bool hasFlippedEdge = false;

            //Search through all edges to see if we can flip an edge
            foreach (HalfEdge2 thisEdge in edges)
            {
                //Is this edge sharing an edge with another triangle, otherwise its a border, and then we cant flip the edge
                if (thisEdge.oppositeEdge == null)
                {
                    continue;
                }

                //The positions of the vertices belonging to the two triangles that we might flip
                //a-c should be the edge that we might flip
                MyVector2 a = thisEdge.v.position;
                MyVector2 b = thisEdge.nextEdge.v.position;
                MyVector2 c = thisEdge.nextEdge.nextEdge.v.position;
                MyVector2 d = thisEdge.oppositeEdge.nextEdge.v.position;

                //If we want to display the test circle
                //controller.GenerateDelaunayCircleMeshes(a, b, c, d);

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

                //Test if we should flip this edge
                if (DelaunayMethods.ShouldFlipEdge(a, b, c, d))
                {
                    flippedEdges += 1;

                    hasFlippedEdge = true;

                    HalfEdgeHelpMethods.FlipTriangleEdge(thisEdge);

                    controller.flipText.text = "Flipped edges: " + flippedEdges;

                    controller.GenerateTriangulationMesh(triangleData);

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

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

                break;
            }
        }

        //Remove the circle meshes so we see that we are finished
        controller.ClearBlackMeshes();

        yield return(null);
    }
    private IEnumerator RunVisualization(HashSet <MyVector2> points)
    {
        //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;
        //}



        //Show the triangulation
        controller.GenerateTriangulationMesh(triangles);

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



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

            controller.SetActivePoint(pointToAdd);

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


                    //Show the triangulation
                    controller.GenerateTriangulationMesh(triangles);

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

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



        yield return(null);
    }
Пример #8
0
    IEnumerator InsertPoints(HashSet <MyVector2> points, HalfEdgeData2 triangulationData, Triangle2 superTriangle)
    {
        //Visualize the first triangle
        controller.GenerateTriangulationMesh(triangulationData);

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


        //Step 4. Loop over each point we want to insert and do Steps 5-7

        //These are for display purposes only
        int missedPoints = 0;
        int flippedEdges = 0;

        foreach (MyVector2 p in points)
        {
            //Step 5. Insert the new point in the triangulation
            //Find the existing triangle the point is in
            HalfEdgeFace2 f = PointTriangulationIntersection.TriangulationWalk(p, null, triangulationData);

            //We couldnt find a triangle maybe because the point is not in the triangulation?
            if (f == null)
            {
                missedPoints += 1;
            }

            //Delete this triangle and form 3 new triangles by connecting p to each of the vertices in the old triangle
            HalfEdgeHelpMethods.SplitTriangleFaceAtPoint(f, p, triangulationData);


            //Visualize
            //Display the point as a black circle
            controller.GenerateCircleMesh(p, shouldResetAllMeshes: true);

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

            controller.GenerateTriangulationMesh(triangulationData);

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


            //Step 6. Initialize stack. Place all triangles which are adjacent to the edges opposite p on a LIFO stack
            //The report says we should place triangles, but it's easier to place edges with our data structure
            Stack <HalfEdge2> trianglesToInvestigate = new Stack <HalfEdge2>();

            AddTrianglesOppositePToStack(p, trianglesToInvestigate, triangulationData);


            //Step 7. Restore delaunay triangulation
            //While the stack is not empty
            int safety = 0;

            while (trianglesToInvestigate.Count > 0)
            {
                safety += 1;

                if (safety > 1000000)
                {
                    Debug.Log("Stuck in infinite loop when restoring delaunay in incremental sloan algorithm");

                    break;
                }

                //Step 7.1. Remove a triangle from the stack
                HalfEdge2 edgeToTest = trianglesToInvestigate.Pop();

                //Step 7.2. Do we need to flip this edge?
                //If p is outside or on the circumcircle for this triangle, we have a delaunay triangle and can return to next loop
                MyVector2 a = edgeToTest.v.position;
                MyVector2 b = edgeToTest.prevEdge.v.position;
                MyVector2 c = edgeToTest.nextEdge.v.position;

                //abc are here counter-clockwise
                if (DelaunayMethods.ShouldFlipEdgeStable(a, b, c, p))
                {
                    HalfEdgeHelpMethods.FlipTriangleEdge(edgeToTest);

                    //Step 7.3. Place any triangles which are now opposite p on the stack
                    AddTrianglesOppositePToStack(p, trianglesToInvestigate, triangulationData);

                    flippedEdges += 1;

                    //Visualize
                    controller.flipText.text = "Flipped edges: " + flippedEdges;

                    controller.GenerateTriangulationMesh(triangulationData);

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


        controller.ClearBlackMeshes();


        //Step 8. Delete the vertices belonging to the supertriangle
        StartCoroutine(RemoveSuperTriangle(superTriangle, triangulationData));

        yield return(null);
    }