private static List <VoronoiSite> CalculateVoronoiGraph(Dictionary <Vector, VoronoiSite> points, int width, int height) { VoronoiGraph result = Fortune.ComputeVoronoiGraph(points.Keys.ToList()); foreach (VoronoiEdge edge in result.Edges) { VoronoiSite a = points[edge.LeftData]; VoronoiSite b = points[edge.RightData]; a.Neighbourgs.Add(b); b.Neighbourgs.Add(a); a.Edges.Add(edge); b.Edges.Add(edge); } foreach (VoronoiSite site in points.Values) { site.Reorder(width, height); } return(points.Values.ToList()); }
public void GenerateWater(List <VoronoiSite> sites) { NoiseGenerator.Frequency = 0.0005; foreach (VoronoiSite site in sites) { if ((site.IsOnBorder && RandomGenerator.GetDouble(0, 1) < 0.60) || (NoiseGenerator.Noise((int)site.VoronoiCenter[0], (int)site.VoronoiCenter[1]) + 1) * 127 < 125) { site.IsWater = true; } } Stack <VoronoiSite> processingStack = new Stack <VoronoiSite>(sites.Where(s => s.IsWater)); while (processingStack.Count > 0) { VoronoiSite site = processingStack.Pop(); if (!site.IsOnBorder && RandomGenerator.GetDouble(0, 1) < 0.50) { continue; } double threshold = site.IsOnBorder ? RandomGenerator.GetDouble(0, 0.85) : RandomGenerator.GetDouble(0, 0.67); foreach (VoronoiSite target in site.Neighbourgs) { if (target.IsWater) { continue; } if (RandomGenerator.GetDouble(0, 1) < threshold) { target.IsWater = true; if (!processingStack.Contains(target)) { processingStack.Push(target); } } } } //Remove single cell islands foreach (VoronoiSite island in sites.Where(p => !p.IsWater && p.Neighbourgs.All(i => i.IsWater))) { island.IsWater = true; } }
public void GenerateWater(List <VoronoiSite> sites) { Stack <VoronoiSite> processingStack = new Stack <VoronoiSite>(); foreach (VoronoiSite site in sites) { if (site.IsOnBorder || RandomGenerator.GetDouble(0, 80) < 1) { site.IsWater = true; processingStack.Push(site); } } while (processingStack.Count > 0) { if (RandomGenerator.GetDouble(0, 1) < 0.60) { continue; } VoronoiSite site = processingStack.Pop(); double threshold = RandomGenerator.GetDouble(0, 0.65); foreach (VoronoiSite target in site.Neighbourgs) { if (target.IsWater) { continue; } if (RandomGenerator.GetDouble(0, 1) < threshold) { target.IsWater = true; if (!processingStack.Contains(target)) { processingStack.Push(target); } } } } //Remove single cell islands foreach (VoronoiSite island in sites.Where(p => !p.IsWater && p.Neighbourgs.All(i => i.IsWater))) { island.IsWater = true; } }
public static List <VoronoiSite> Create(int width, int height, int pointCount, int relaxations, int seed) { RandomGenerator.ResetSeed(seed); Dictionary <Vector, VoronoiSite> points = new Dictionary <Vector, VoronoiSite>(pointCount); for (int i = 0; i < pointCount; i++) { Vector point = new Vector(RandomGenerator.Get(0, width), RandomGenerator.Get(0, height)); try { points.Add(point, new VoronoiSite(point)); } catch (ArgumentException) // In case two points are to close one from each other { i--; } } List <VoronoiSite> sites = CalculateVoronoiGraph(points, width, height); for (int i = 0; i < relaxations; i++) { Dictionary <Vector, VoronoiSite> newPoints = new Dictionary <Vector, VoronoiSite>(); foreach (VoronoiSite site in sites) { Vector newPoint = new Vector(site.VoronoiPoints.Average(p => p[0]), site.VoronoiPoints.Average(p => p[1])); newPoints.Add(newPoint, new VoronoiSite(newPoint)); } points = newPoints; sites = CalculateVoronoiGraph(points, width, height); } //Create water IWaterGenerator waterGenerator = new FloodFillWaterGenerator(); //waterGenerator = new PerlinWaterGenerator(); waterGenerator.GenerateWater(sites); //Associate water distance from shore and split the water in cluster (independant seas) while (true) { Stack <VoronoiSite> toBeProcessedSites = new Stack <VoronoiSite>(); VoronoiSite site = sites.FirstOrDefault(s => s.ShoreDistance == VoronoiSite.DefaultShoreDistance && s.Neighbourgs.Any(p => p.IsWater != s.IsWater)); if (site == null) { break; } site.ShoreDistance = 1; toBeProcessedSites.Push(site); Cluster cluster = new Cluster(); while (toBeProcessedSites.Count > 0) { VoronoiSite item = toBeProcessedSites.Pop(); item.Cluster = cluster; if (item.Neighbourgs.Any(s => item.IsWater != s.IsWater)) { item.ShoreDistance = 1; } foreach (VoronoiSite neighbourg in item.Neighbourgs) { if ((neighbourg.IsWater == item.IsWater) && neighbourg.ShoreDistance > item.ShoreDistance + 1) { neighbourg.ShoreDistance = item.ShoreDistance + 1; if (!toBeProcessedSites.Contains(neighbourg)) { toBeProcessedSites.Push(neighbourg); } } } } } DebugConsole.WriteLine("Land tiles : " + sites.Count(s => !s.IsWater) + " (" + string.Format("{0:P}", (float)sites.Count(s => !s.IsWater) / sites.Count) + ")"); DebugConsole.WriteLine("Water tiles : " + sites.Count(s => s.IsWater) + " (" + string.Format("{0:P}", (float)sites.Count(s => s.IsWater) / sites.Count) + ")"); return(sites); }