private void BuildGraph(IEnumerable <Vector2> points, Delaunay.Voronoi voronoi)
{
// 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.
var libedges = voronoi.Edges();
var 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)
{
var p = new Center {
index = centers.Count, point = point
};
centers.Add(p);
centerLookup[point] = p;
}
// Workaround for Voronoi lib bug: we need to call region()
// before Edges or neighboringSites are available
foreach (var p in centers)
{
voronoi.Region(p.point);
}
foreach (var libedge in libedges)
{
var dedge = libedge.DelaunayLine();
var vedge = libedge.VoronoiEdge();
// Fill the graph data. Make an Edge object corresponding to
// the edge from the voronoi library.
var edge = new Edge
{
index = edges.Count,
river = 0,
// Edges point to corners. Edges point to centers.
v0 = MakeCorner(vedge.p0),
v1 = MakeCorner(vedge.p1),
d0 = centerLookup[dedge.p0],
d1 = centerLookup[dedge.p1]
};
if (vedge.p0.HasValue && vedge.p1.HasValue)
{
edge.midpoint = Vector2Extensions.Interpolate(vedge.p0.Value, vedge.p1.Value, 0.5f);
}
edges.Add(edge);
// 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);
}
}
// TODO: use edges to determine these
var topLeft = centers.OrderBy(p => p.point.x + p.point.y).First();
AddCorner(topLeft, 0, 0);
var bottomRight = centers.OrderByDescending(p => p.point.x + p.point.y).First();
AddCorner(bottomRight, Width, Height);
var topRight = centers.OrderByDescending(p => Width - p.point.x + p.point.y).First();
AddCorner(topRight, 0, Height);
var bottomLeft = centers.OrderByDescending(p => p.point.x + Height - p.point.y).First();
AddCorner(bottomLeft, Width, 0);
// required for polygon fill
foreach (var center in centers)
{
center.corners.Sort(ClockwiseComparison(center));
}
}