inz-00/Assets/Scripts/GridGenerator/VoronoiGridGenerator.cs

76 lines
2.4 KiB
C#

using System.Collections.Generic;
using System.Linq;
using Assets.Common;
using Assets.PointDistribution;
using Assets.Voronoi;
namespace Assets.GridGenerator
{
public class VoronoiGridGenerator : IGridGenerator
{
public const string VoronoiSiteProperty = "VoronoiSite";
private readonly int _seed;
private readonly IPointDistribution _sampler;
public VoronoiGridGenerator(int seed, IPointDistribution sampler)
{
_seed = seed;
_sampler = sampler;
}
public Map CreateGrid(double width, double height)
{
Map result = new Map(_seed);
var points = GeneratePoints(width, height);
var generator = new VoronoiGenerator(points);
generator.Generate();
result.Boundaries = (Graph<Point>)generator.Voronoi.Clone();
result.Sites = generator.Delaunay.Morph(s =>
{
var site = new MapSite(s.Point, ClockwiseVertices(generator.Voronoi, s.Vertices)) { Edges = s.Edges };
site.Metadata.SetProperty(VoronoiSiteProperty, s);
return site;
});
foreach (var site in result.Sites.Vertices.Take(4))
site.IsOuter = true;
return result;
}
private List<Point> GeneratePoints(double width, double height)
{
var points = new List<Point>
{
new Point(-width / 8, height / 2 + 0.1f),
new Point(width * 1.125f, height / 2 - 0.1f),
new Point(width / 2 - 0.1f, -height / 8),
new Point(width / 2 + 0.1f, height * 1.125f)
};
points.AddRange(_sampler.Generate(width, height));
return points;
}
private IEnumerable<int> ClockwiseVertices(Graph<Point> graph, IEnumerable<int> vertices)
{
var enumerated = vertices as int[] ?? vertices.ToArray();
var center = PointUtils.Mean(enumerated.Select(n => graph[n]));
var reference = center + new Point(0, 1);
return enumerated
.Select(n => (Vertex: n, Point: graph[n]))
.Select(x => (Vertex: x.Vertex, Angle: PointUtils.AngleBetween(center, reference, x.Point)))
.OrderBy(x => x.Angle)
.Select(x => x.Vertex);
}
}
}