//Try to add a voronoi edge. Not all edges have a neighboring triangle, and if it hasnt we cant add a voronoi edge
        private static void TryAddVoronoiEdgeFromTriangleEdge(HalfEdge e, Vector3 voronoiVertex, List <VoronoiEdge> allEdges)
        {
            //Ignore if this edge has no neighboring triangle
            if (e.oppositeEdge == null)
            {
                return;
            }

            //Calculate the circumcenter of the neighbor
            HalfEdge eNeighbor = e.oppositeEdge;

            Vector3 v1 = eNeighbor.v.position;
            Vector3 v2 = eNeighbor.nextEdge.v.position;
            Vector3 v3 = eNeighbor.nextEdge.nextEdge.v.position;

            //The .XZ() is an extension method that removes the y value of a vector3 so it becomes a vector2
            Vector2 center2D = CalculateCircleCenter(new Vector2(v1.x, v1.z), new Vector2(v2.x, v2.z), new Vector2(v3.x, v3.z));

            Vector3 voronoiVertexNeighbor = new Vector3(center2D.x, 0f, center2D.y);

            //Create a new voronoi edge between the voronoi vertices
            VoronoiEdge edge = new VoronoiEdge(voronoiVertex, voronoiVertexNeighbor, e.prevEdge.v.position);

            allEdges.Add(edge);
        }
        //Find the position in the list of all cells that includes this site
        //Returns -1 if no cell is found
        private static int TryFindCellPos(VoronoiEdge e, List <VoronoiCell> voronoiCells)
        {
            for (int i = 0; i < voronoiCells.Count; i++)
            {
                if (e.sitePos == voronoiCells[i].sitePos)
                {
                    return(i);
                }
            }

            return(-1);
        }
        public static List <VoronoiCell> GenerateVoronoiDiagram(List <Vector3> sites)
        {
            //First generate the delaunay triangulation
            List <Triangle> triangles = TriangulateByFlippingEdges(sites);


            //Generate the voronoi diagram

            //Step 1. For every delaunay edge, compute a voronoi edge
            //The voronoi edge is the edge connecting the circumcenters of two neighboring delaunay triangles
            List <VoronoiEdge> voronoiEdges = new List <VoronoiEdge>();

            for (int i = 0; i < triangles.Count; i++)
            {
                Triangle t = triangles[i];

                //Each triangle consists of these edges
                HalfEdge e1 = t.halfEdge;
                HalfEdge e2 = e1.nextEdge;
                HalfEdge e3 = e2.nextEdge;

                //Calculate the circumcenter for this triangle
                Vector3 v1 = e1.v.position;
                Vector3 v2 = e2.v.position;
                Vector3 v3 = e3.v.position;

                //The circumcenter is the center of a circle where the triangles corners is on the circumference of that circle
                //The .XZ() is an extension method that removes the y value of a vector3 so it becomes a vector2
                Vector2 center2D = CalculateCircleCenter(new Vector2(v1.x, v1.z), new Vector2(v2.x, v2.z), new Vector2(v3.x, v3.z));

                //The circumcenter is also known as a voronoi vertex, which is a position in the diagram where we are equally
                //close to the surrounding sites
                Vector3 voronoiVertex = new Vector3(center2D.x, 0f, center2D.y);

                TryAddVoronoiEdgeFromTriangleEdge(e1, voronoiVertex, voronoiEdges);
                TryAddVoronoiEdgeFromTriangleEdge(e2, voronoiVertex, voronoiEdges);
                TryAddVoronoiEdgeFromTriangleEdge(e3, voronoiVertex, voronoiEdges);
            }


            //Step 2. Find the voronoi cells where each cell is a list of all edges belonging to a site
            List <VoronoiCell> voronoiCells = new List <VoronoiCell>();

            for (int i = 0; i < voronoiEdges.Count; i++)
            {
                VoronoiEdge e = voronoiEdges[i];

                //Find the position in the list of all cells that includes this site
                int cellPos = TryFindCellPos(e, voronoiCells);

                //No cell was found so we need to create a new cell
                if (cellPos == -1)
                {
                    VoronoiCell newCell = new VoronoiCell(e.sitePos);

                    voronoiCells.Add(newCell);

                    newCell.edges.Add(e);
                }
                else
                {
                    voronoiCells[cellPos].edges.Add(e);
                }
            }


            return(voronoiCells);
        }
        private static void ClipDiagram(List <VoronoiCell> cells, float halfWidth)
        {
            //Remove the first 4 cells we added in the beginning because they are not needed anymore
            //cells.RemoveRange(0, 4);

            for (int i = 0; i < cells.Count; i++)
            {
                //We should move around the cell counter-clockwise so make sure all edges are oriented in that way
                List <VoronoiEdge> cellEdges = cells[i].edges;

                for (int j = cellEdges.Count - 1; j >= 0; j--)
                {
                    Vector3 edge_v1 = cellEdges[j].v1;
                    Vector3 edge_v2 = cellEdges[j].v2;

                    //Remove this edge if it is small
                    if ((edge_v1 - edge_v2).sqrMagnitude < 0.01f)
                    {
                        cellEdges.RemoveAt(j);

                        continue;
                    }

                    Vector3 edgeCenter = (edge_v1 + edge_v2) * 0.5f;

                    //Now we can make a line between the cell and the edge
                    Vector2 a = new Vector2(cells[i].sitePos.x, cells[i].sitePos.z);
                    Vector2 b = new Vector2(edgeCenter.x, edgeCenter.z);

                    //The point to the left of this line is coming after the other point if we are moving counter-clockwise
                    if (IsAPointLeftOfVector(a, b, new Vector2(edge_v1.x, edge_v1.z)) < 0f)
                    {
                        //Flip because we want to go from v1 to v2
                        cellEdges[j].v2 = edge_v1;
                        cellEdges[j].v1 = edge_v2;
                    }
                }

                //Connect the edges

                VoronoiEdge startEdge = cellEdges[0];

                cells[i].borderCoordinates.Add(startEdge.v2);

                Vector3 currentVertex = startEdge.v2;

                for (int j = 1; j < cellEdges.Count; j++)
                {
                    //Find the next edge
                    for (int k = 1; k < cellEdges.Count; k++)
                    {
                        Vector3 thisEdgeStart = cellEdges[k].v1;

                        if ((thisEdgeStart - currentVertex).sqrMagnitude < 0.01f)
                        {
                            cells[i].borderCoordinates.Add(cellEdges[k].v2);

                            currentVertex = cellEdges[k].v2;

                            break;
                        }
                    }
                }
            }

            List <Vector3> clipPolygon = new List <Vector3>();

            //The positions of the square border
            Vector3 TL = new Vector3(-halfWidth, 0f, halfWidth);
            Vector3 TR = new Vector3(halfWidth, 0f, halfWidth);
            Vector3 BR = new Vector3(halfWidth, 0f, -halfWidth);
            Vector3 BL = new Vector3(-halfWidth, 0f, -halfWidth);

            clipPolygon.Add(TL);
            clipPolygon.Add(BL);
            clipPolygon.Add(BR);
            clipPolygon.Add(TR);

            //Create the clipping planes
            List <Plane> clippingPlanes = new List <Plane>();

            for (int i = 0; i < clipPolygon.Count; i++)
            {
                int iPlusOne = ClampListIndex(i + 1, clipPolygon.Count);

                Vector3 v1 = clipPolygon[i];
                Vector3 v2 = clipPolygon[iPlusOne];

                //Doesnt have to be center but easier to debug
                Vector3 planePos = (v1 + v2) * 0.5f;

                Vector3 planeDir = v2 - v1;

                //Should point inwards
                Vector3 planeNormal = new Vector3(-planeDir.z, 0f, planeDir.x).normalized;

                clippingPlanes.Add(new Plane(planePos, planeNormal));
            }

            for (int i = 0; i < cells.Count; i++)
            {
                cells[i].borderCoordinates = ClipPolygon(cells[i].borderCoordinates, clippingPlanes);
            }
        }