private void generateGraph(Voronoi voronoi)
    {
        points = new HashSet <Vector3>();
        nodes  = new HashSet <Node>();
        edges  = new List <NodeHalfEdge>();

        var edgesByStartPosition = new Dictionary <Vector3, List <NodeHalfEdge> >();
        var siteEdges            = new Dictionary <Vector2, List <LineSegment> >();

        foreach (var edge in voronoi.Edges())
        {
            if (edge.visible)
            {
                var p1      = edge.clippedEnds[Delaunay.LR.Side.LEFT];
                var p2      = edge.clippedEnds[Delaunay.LR.Side.RIGHT];
                var segment = new LineSegment(p1, p2);

                if (Vector2.Distance(p1.Value, p2.Value) < 0.001f)
                {
                    continue;
                }

                if (edge.leftSite != null)
                {
                    if (!siteEdges.ContainsKey(edge.leftSite.Coord))
                    {
                        siteEdges.Add(edge.leftSite.Coord, new List <LineSegment>());
                    }
                    siteEdges[edge.leftSite.Coord].Add(segment);
                }
                if (edge.rightSite != null)
                {
                    if (!siteEdges.ContainsKey(edge.rightSite.Coord))
                    {
                        siteEdges.Add(edge.rightSite.Coord, new List <LineSegment>());
                    }
                    siteEdges[edge.rightSite.Coord].Add(segment);
                }
            }
        }

        foreach (var site in voronoi.SiteCoords())
        {
            var boundries   = getBoundriesForSite(siteEdges, site);
            var center      = getPointWithElevation(site);
            var currentNode = new Node {
                centerPoint = center
            };
            nodes.Add(currentNode);

            NodeHalfEdge firstEdge    = null;
            NodeHalfEdge previousEdge = null;

            for (var i = 0; i < boundries.Count; i++)
            {
                var edge = boundries[i];

                var start = getPointWithElevation(edge.p0.Value);
                var end   = getPointWithElevation(edge.p1.Value);
                if (start == end)
                {
                    continue;
                }

                previousEdge = addEdge(edgesByStartPosition, previousEdge, start, end, currentNode);
                if (firstEdge == null)
                {
                    firstEdge = previousEdge;
                }
                if (currentNode.startEdge == null)
                {
                    currentNode.startEdge = previousEdge;
                }

                // figure out if the two edges meet, and if not then insert some more edges to close the polygon
                if (i < boundries.Count - 1)
                {
                    start = getPointWithElevation(edge.p1.Value);
                    end   = getPointWithElevation(boundries[i + 1].p0.Value);
                }
                else if (i == boundries.Count - 1)
                {
                    start = getPointWithElevation(edge.p1.Value);
                    end   = getPointWithElevation(boundries[0].p0.Value);
                }
                if (start != end)
                {
                    previousEdge = addEdge(edgesByStartPosition, previousEdge, previousEdge.destination, end, currentNode);
                }
            }
            // Connect up the end of the loop
            previousEdge.next  = firstEdge;
            firstEdge.previous = previousEdge;
        }

        connectOpposites(edgesByStartPosition);
    }
예제 #2
0
    private void CreateFromVoronoi(Voronoi voronoi)
    {
        vertices = new Dictionary <Vector3, Vertex>();

        nodesByCenterPosition = new Dictionary <Vector3, Node>();
        var edgesByStartPosition = new Dictionary <Vector3, List <Edge> >();

        edges = new List <Edge>();

        plotBounds = voronoi.plotBounds;

        var bottomLeftSite  = voronoi.NearestSitePoint(plotBounds.xMin, plotBounds.yMin);
        var bottomRightSite = voronoi.NearestSitePoint(plotBounds.xMax, plotBounds.yMin);
        var topLeftSite     = voronoi.NearestSitePoint(plotBounds.xMin, plotBounds.yMax);
        var topRightSite    = voronoi.NearestSitePoint(plotBounds.xMax, plotBounds.yMax);

        var topLeft     = new Vector3(plotBounds.xMin, 0, plotBounds.yMax);
        var topRight    = new Vector3(plotBounds.xMax, 0, plotBounds.yMax);
        var bottomLeft  = new Vector3(plotBounds.xMin, 0, plotBounds.yMin);
        var bottomRight = new Vector3(plotBounds.xMax, 0, plotBounds.yMin);

        var siteEdges = new Dictionary <Vector2, List <LineSegment> >();

        var edgePointsRemoved = 0;

        foreach (var edge in voronoi.Edges())
        {
            if (!edge.visible)
            {
                continue;
            }

            var p1 = edge.clippedEnds[Delaunay.LR.Side.LEFT];
            var p2 = edge.clippedEnds[Delaunay.LR.Side.RIGHT];

            var segment = new LineSegment(p1, p2);

            if (Vector2.Distance(p1.Value, p2.Value) < 0.001f)
            {
                edgePointsRemoved++;
                continue;
            }

            if (edge.leftSite != null)
            {
                if (!siteEdges.ContainsKey(edge.leftSite.Coord))
                {
                    siteEdges.Add(edge.leftSite.Coord, new List <LineSegment>());
                }
                siteEdges[edge.leftSite.Coord].Add(segment);
            }

            if (edge.rightSite != null)
            {
                if (!siteEdges.ContainsKey(edge.rightSite.Coord))
                {
                    siteEdges.Add(edge.rightSite.Coord, new List <LineSegment>());
                }
                siteEdges[edge.rightSite.Coord].Add(segment);
            }
        }

        Debug.Assert(edgePointsRemoved == 0, string.Format("{0} edge points too close and have been removed", edgePointsRemoved));

        foreach (var site in voronoi.SiteCoords())
        {
            var boundries   = GetBoundriesForSite(siteEdges, site);
            var center      = ToVector3(site);
            var currentNode = new Node {
                centerPoint = center
            };

            nodesByCenterPosition.Add(center, currentNode);

            Edge firstEdge    = null;
            Edge previousEdge = null;

            for (var i = 0; i < boundries.Count; i++)
            {
                var edge = boundries[i];

                var start = ToVector3(edge.p0.Value);
                var end   = ToVector3(edge.p1.Value);
                if (start == end)
                {
                    continue;
                }

                previousEdge = AddEdge(edgesByStartPosition, previousEdge, start, end, currentNode);
                if (firstEdge == null)
                {
                    firstEdge = previousEdge;
                }
                if (currentNode.startEdge == null)
                {
                    currentNode.startEdge = previousEdge;
                }

                // We need to figure out if the two edges meet, and if not then
                // insert some more edges to close the polygon
                var insertEdges = false;
                if (i < boundries.Count - 1)
                {
                    start       = ToVector3(boundries[i + 0].p1.Value);
                    end         = ToVector3(boundries[i + 1].p0.Value);
                    insertEdges = start != end;
                }
                else if (i == boundries.Count - 1)
                {
                    start       = ToVector3(boundries[i].p1.Value);
                    end         = ToVector3(boundries[0].p0.Value);
                    insertEdges = start != end;
                }

                if (insertEdges)
                {
                    // Check which corners are within this node
                    var startIsTop    = start.z == voronoi.plotBounds.yMax;
                    var startIsBottom = start.z == voronoi.plotBounds.yMin;
                    var startIsLeft   = start.x == voronoi.plotBounds.xMin;
                    var startIsRight  = start.x == voronoi.plotBounds.xMax;

                    var hasTopLeft     = site == topLeftSite && !(startIsTop && startIsLeft);
                    var hasTopRight    = site == topRightSite && !(startIsTop && startIsRight);
                    var hasBottomLeft  = site == bottomLeftSite && !(startIsBottom && startIsLeft);
                    var hasBottomRight = site == bottomRightSite && !(startIsBottom && startIsRight);

                    if (startIsTop)
                    {
                        if (hasTopRight)
                        {
                            previousEdge = AddEdge(edgesByStartPosition, previousEdge, start, topRight, currentNode);
                        }
                        if (hasBottomRight)
                        {
                            previousEdge = AddEdge(edgesByStartPosition, previousEdge, previousEdge.destination.position, bottomRight, currentNode);
                        }
                        if (hasBottomLeft)
                        {
                            previousEdge = AddEdge(edgesByStartPosition, previousEdge, previousEdge.destination.position, bottomLeft, currentNode);
                        }
                        if (hasTopLeft)
                        {
                            previousEdge = AddEdge(edgesByStartPosition, previousEdge, previousEdge.destination.position, topLeft, currentNode);
                        }
                    }
                    else if (startIsRight)
                    {
                        if (hasBottomRight)
                        {
                            previousEdge = AddEdge(edgesByStartPosition, previousEdge, start, bottomRight, currentNode);
                        }
                        if (hasBottomLeft)
                        {
                            previousEdge = AddEdge(edgesByStartPosition, previousEdge, previousEdge.destination.position, bottomLeft, currentNode);
                        }
                        if (hasTopLeft)
                        {
                            previousEdge = AddEdge(edgesByStartPosition, previousEdge, previousEdge.destination.position, topLeft, currentNode);
                        }
                        if (hasTopRight)
                        {
                            previousEdge = AddEdge(edgesByStartPosition, previousEdge, previousEdge.destination.position, topRight, currentNode);
                        }
                    }
                    else if (startIsBottom)
                    {
                        if (hasBottomLeft)
                        {
                            previousEdge = AddEdge(edgesByStartPosition, previousEdge, start, bottomLeft, currentNode);
                        }
                        if (hasTopLeft)
                        {
                            previousEdge = AddEdge(edgesByStartPosition, previousEdge, previousEdge.destination.position, topLeft, currentNode);
                        }
                        if (hasTopRight)
                        {
                            previousEdge = AddEdge(edgesByStartPosition, previousEdge, previousEdge.destination.position, topRight, currentNode);
                        }
                        if (hasBottomRight)
                        {
                            previousEdge = AddEdge(edgesByStartPosition, previousEdge, previousEdge.destination.position, bottomRight, currentNode);
                        }
                    }
                    else if (startIsLeft)
                    {
                        if (hasTopLeft)
                        {
                            previousEdge = AddEdge(edgesByStartPosition, previousEdge, start, topLeft, currentNode);
                        }
                        if (hasTopRight)
                        {
                            previousEdge = AddEdge(edgesByStartPosition, previousEdge, previousEdge.destination.position, topRight, currentNode);
                        }
                        if (hasBottomRight)
                        {
                            previousEdge = AddEdge(edgesByStartPosition, previousEdge, previousEdge.destination.position, bottomRight, currentNode);
                        }
                        if (hasBottomLeft)
                        {
                            previousEdge = AddEdge(edgesByStartPosition, previousEdge, previousEdge.destination.position, bottomLeft, currentNode);
                        }
                    }

                    previousEdge = AddEdge(edgesByStartPosition, previousEdge, previousEdge.destination.position, end, currentNode);
                }
            }

            // Connect up the end of the loop
            previousEdge.next  = firstEdge;
            firstEdge.previous = previousEdge;

            AddLeavingEdge(firstEdge);
        }

        ConnectOpposites(edgesByStartPosition);
    }
예제 #3
0
        /**
         * Stupidly, Unity in 2D mode uses co-ords incompatible with Unity in 3D mode (xy instead of xz).
         *
         * So we have to provide a boolean to switch between the two modes!
         */
        public static VoronoiDiagram CreateDiagramFromVoronoiOutput(Voronoi voronoiGenerator, bool useUnity2DCoordsNot3D)
        {
            GameObject go           = new GameObject("New VoronoiMap");
            GameObject goCellHolder = new GameObject(_cellHolderName);

            goCellHolder.transform.parent = go.transform;
            GameObject goEdgeHolder = new GameObject(_edgeHolderName);

            goEdgeHolder.transform.parent = go.transform;
            GameObject goVertexHolder = new GameObject(_vertexHolderName);

            goVertexHolder.transform.parent = go.transform;

            VoronoiDiagram map = go.AddComponent <VoronoiDiagram>();

            System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
            watch.Reset();
            watch.Start();

            Dictionary <Site, VoronoiCell>          generatedCells    = new Dictionary <Site, VoronoiCell>();
            Dictionary <Vector2, VoronoiCellVertex> generatedVertices = new Dictionary <Vector2, VoronoiCellVertex>();

            int numEdgesCreated = 0;

            foreach (Edge edge in voronoiGenerator.Edges())
            {
                GameObject goEdge = new GameObject("Edge-#" + (numEdgesCreated++));
                goEdge.transform.parent = goEdgeHolder.transform;

                VoronoiCellEdge vEdge = goEdge.AddComponent <VoronoiCellEdge>();
                Debug.Log("Processing edge = " + edge + " with clippedEnds = " + (edge.clippedEnds == null ? "null" : "" + edge.clippedEnds.Count));
                if (!edge.visible)
                {
                    Debug.Log("...Voronoi algorithm generated a non-existent edge, skipping it...");
                    continue;
                }
                Vector2 clippedEndLeft  = (Vector2)edge.clippedEnds[Side.LEFT];
                Vector2 clippedEndRight = (Vector2)edge.clippedEnds[Side.RIGHT];
                vEdge.AddVertex(FetchVertexOrAddToObject(clippedEndLeft, generatedVertices, goVertexHolder, useUnity2DCoordsNot3D));
                vEdge.AddVertex(FetchVertexOrAddToObject(clippedEndRight, generatedVertices, goVertexHolder, useUnity2DCoordsNot3D));
                goEdge.transform.localPosition = (vEdge.edgeVertexA.transform.localPosition + vEdge.edgeVertexB.transform.localPosition) / 2.0f;

                Site[] bothSites = new Site[] { edge.leftSite, edge.rightSite };
                foreach (Site site in bothSites)
                {
                    /** Re-use or create the Cell */
                    VoronoiCell newCell = null; // C# is rubbish. Crashes if Dictionary lacks the key. Very bad design.
                    if (generatedCells.ContainsKey(site))
                    {
                        newCell = generatedCells[site];
                    }
                    GameObject goCell;

                    if (newCell == null)
                    {
                        goCell = new GameObject("Cell-#" + generatedCells.Count);
                        goCell.transform.parent        = goCellHolder.transform;
                        goCell.transform.localPosition = new Vector3(site.Coord.x, useUnity2DCoordsNot3D ? site.Coord.y : 0, useUnity2DCoordsNot3D ? 0 : site.Coord.y);
                        newCell = goCell.AddComponent <VoronoiCell>();
                        generatedCells.Add(site, newCell);
                    }
                    else
                    {
                        goCell = newCell.gameObject;
                    }

                    /** Now that cell is created, attach it to BOTH Vertex's on the new Edge
                     *        (so that later its easy for us to to find Cells-for-this-Vertex, and also:
                     *        for a Cell to "trace" around its edges, picking "next edge" from each Vertex
                     *        by looking at which edges from the vertex border this cell (by checking
                     *        that BOTH Vertex-ends of the edge are attached to this cell)
                     *
                     *        Also add the edge itself to the cell, and the cell to the edge.
                     */
                    vEdge.AddCellWithSideEffects(newCell);
                }
            }
            watch.Stop();

            return(map);
        }
예제 #4
0
        // Build graph data structure in 'edges', 'centers', 'corners',
        // based on information in the Voronoi results: point.neighbors
        // will be a list of neighboring points of the same type (corner
        // or center); point.edges will be a list of edges that include
        // that point. Each edge connects to four points: the Voronoi edge
        // edge.{v0,v1} and its dual Delaunay triangle edge edge.{d0,d1}.
        // For boundary polygons, the Delaunay edge will have one null
        // point, and the Voronoi edge may be null.
        private void BuildGraph()
        {
            Voronoi voronoi = new Voronoi(pointsCount, new Rect(0, 0, width, height), NUM_LLOYD_ITERATIONS);

            points = voronoi.GetPoints();
            // Workaround for Voronoi lib bug: we need to call region()
            // before Edges or neighboringSites are available
            foreach (var center in _centers)
            {
                voronoi.Region(center.point);
            }

            List <Delaunay.Edge> libedges = voronoi.Edges();

            Dictionary <Vector2, Center> centerLookup = new Dictionary <Vector2, Center>();

            // Build Center objects for each of the points, and a lookup map
            // to find those Center objects again as we build the graph
            foreach (var point in points)
            {
                Center p = new Center();
                p.index     = _centers.Count;
                p.point     = point;
                p.neighbors = new List <Center>();
                p.borders   = new List <DoubleEdge>();
                p.corners   = new List <Corner>();
                _centers.Add(p);
                centerLookup[point] = p;
            }

            Dictionary <int, List <Corner> > _cornerMap = new Dictionary <int, List <Corner> >();

            foreach (Delaunay.Edge libedge in libedges)
            {
                LineSegment dedge = libedge.DelaunayLine();
                LineSegment vedge = libedge.VoronoiEdge();

                // Fill the graph data. Make an Edge object corresponding to
                // the edge from the voronoi library.
                DoubleEdge edge = new DoubleEdge();
                edge.index = _edges.Count;
                edge.river = 0;
                if (vedge.p0 != null && vedge.p1 != null)
                {
                    edge.midpoint = Vector2.Lerp((Vector2)vedge.p0, (Vector2)vedge.p1, 0.5f);
                }

                // Edges point to corners. Edges point to centers.
                edge.v0 = MakeCorner(vedge.p0, _cornerMap);
                edge.v1 = MakeCorner(vedge.p1, _cornerMap);
                Center findCenter = null;
                if (centerLookup.TryGetValue((Vector2)dedge.p0, out findCenter))
                {
                    edge.d0 = findCenter;
                }
                else
                {
                    edge.d0 = null;
                }
                if (centerLookup.TryGetValue((Vector2)dedge.p1, out findCenter))
                {
                    edge.d1 = centerLookup[(Vector2)dedge.p1];
                }
                else
                {
                    edge.d1 = null;
                }

                // Centers point to edges. Corners point to edges.
                if (edge.d0 != null)
                {
                    edge.d0.borders.Add(edge);
                }
                if (edge.d1 != null)
                {
                    edge.d1.borders.Add(edge);
                }
                if (edge.v0 != null)
                {
                    edge.v0.protrudes.Add(edge);
                }
                if (edge.v1 != null)
                {
                    edge.v1.protrudes.Add(edge);
                }

                // Centers point to centers.
                if (edge.d0 != null && edge.d1 != null)
                {
                    AddToGenericList(edge.d0.neighbors, edge.d1);
                    AddToGenericList(edge.d1.neighbors, edge.d0);
                }

                // Corners point to corners
                if (edge.v0 != null && edge.v1 != null)
                {
                    AddToGenericList(edge.v0.adjacent, edge.v1);
                    AddToGenericList(edge.v1.adjacent, edge.v0);
                }

                // Centers point to corners
                if (edge.d0 != null)
                {
                    AddToGenericList(edge.d0.corners, edge.v0);
                    AddToGenericList(edge.d0.corners, edge.v1);
                }
                if (edge.d1 != null)
                {
                    AddToGenericList(edge.d1.corners, edge.v0);
                    AddToGenericList(edge.d1.corners, edge.v1);
                }

                // Corners point to centers
                if (edge.v0 != null)
                {
                    AddToGenericList(edge.v0.touches, edge.d0);
                    AddToGenericList(edge.v0.touches, edge.d1);
                }
                if (edge.v1 != null)
                {
                    AddToGenericList(edge.v1.touches, edge.d0);
                    AddToGenericList(edge.v1.touches, edge.d1);
                }
                _edges.Add(edge);
            }
        }
	public void buildGraph(List<Vector2> points, Voronoi voronoi) {
		Center p;
		Corner q; 
		Vector2 point;
		Vector2 other;
		List<Delaunay.Edge> libedges= voronoi.Edges();
		Dictionary<System.Nullable<Vector2>,Center> centerLookup = new Dictionary<System.Nullable<Vector2>,Center>();
		
		// Build Center objects for each of the points, and a lookup map
		// to find those Center objects again as we build the graph
		foreach ( Vector2 ppp in points) {
			System.Nullable<Vector2> pp = (System.Nullable<Vector2>) ppp;
			p = new Center();
			p.index = centers.Count;
			p.point = (Vector2) pp;
			p.neighbors = new List<Center>();
			p.borders = new List<Edge>();
			p.corners = new List<Corner>();
			centers.Add(p);
			centerLookup[pp] = p;
		}
		foreach ( Center po in centers) {
			voronoi.Region(po.point);
		}
		
		
		
		foreach (Delaunay.Edge libedge in libedges) {
			LineSegment dedge = libedge.DelaunayLine();
			LineSegment vedge = libedge.VoronoiEdge();
			
			// Fill the graph data. Make an Edge object corresponding to
			// the edge from the voronoi library.
			Edge edge = new Edge();
			edge.index = edges.Count;
			edge.river = 0;
			edges.Add(edge);
			edge.midpoint = null;
			if (vedge.p0!= null && vedge.p1 != null)
				edge.midpoint = Vector2.Lerp( (Vector2) vedge.p0, (Vector2) vedge.p1, 0.5f);

			
			// Edges point to corners. Edges point to centers. 
			edge.v0 = makeCorner(vedge.p0);
			edge.v1 = makeCorner(vedge.p1);
			edge.d0 = centerLookup[dedge.p0];
			edge.d1 = centerLookup[dedge.p1];
			
			// Centers point to edges. Corners point to edges.
			if (edge.d0 != null) { edge.d0.borders.Add(edge); }
			if (edge.d1 != null) { edge.d1.borders.Add(edge); }
			if (edge.v0 != null) { edge.v0.protrudes.Add(edge); }
			if (edge.v1 != null) { edge.v1.protrudes.Add(edge); }
			
			// Centers point to centers.
			if (edge.d0 != null && edge.d1 != null) {
				addToCenterList(edge.d0.neighbors, edge.d1);
				addToCenterList(edge.d1.neighbors, edge.d0);
			}
			
			// Corners point to corners
			if (edge.v0 != null && edge.v1 != null) {
				addToCornerList(edge.v0.adjacent, edge.v1);
				addToCornerList(edge.v1.adjacent, edge.v0);
			}
			
			// Centers point to corners
			if (edge.d0 != null) {
				addToCornerList(edge.d0.corners, edge.v0);
				addToCornerList(edge.d0.corners, edge.v1);
			}
			if (edge.d1 != null) {
				addToCornerList(edge.d1.corners, edge.v0);
				addToCornerList(edge.d1.corners, edge.v1);
			}
			
			// Corners point to centers
			if (edge.v0 != null) {
				addToCenterList(edge.v0.touches, edge.d0);
				addToCenterList(edge.v0.touches, edge.d1);
			}
			if (edge.v1 != null) {
				addToCenterList(edge.v1.touches, edge.d0);
				addToCenterList(edge.v1.touches, edge.d1);
			}
		}
	}