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