Compute location neighbours

This commit is contained in:
Kacper Donat 2019-08-17 14:08:41 +02:00
parent 8a9adbd28f
commit 8bfcb28a30
2 changed files with 81 additions and 37 deletions

View File

@ -1,31 +1,51 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using Assets.Voronoi;
using Random = System.Random;
namespace Assets.Map
{
public class LocationGenerator
{
private Graph<LocationSite> _graph;
private readonly Graph<LocationSite> _sites;
private readonly Graph<Location> _locations;
private readonly List<(int, Location)> _queue = new List<(int, Location)>();
private Random _random;
private readonly Dictionary<Location, List<int>> _blacklist = new Dictionary<Location, List<int>>();
private readonly Random _random;
public Graph<LocationSite> Sites => _sites;
public Graph<Location> Result => _locations;
public bool Done => _queue.Count == 0;
public Graph<LocationSite> Result => _graph;
private Dictionary<Location, List<int>> _blacklist = new Dictionary<Location, List<int>>();
public LocationGenerator(Graph<LocationSite> graph, Random random = null)
public LocationGenerator(List<Location> locations, Graph<Site> sites, Random random = null)
{
_graph = graph;
_sites = sites.Morph(s => new LocationSite(s));
_locations = new Graph<Location> { Vertices = new List<Location>(locations) };
_random = random ?? new Random();
}
public void Init(params (int, Location)[] start)
public void SetLocation(int vertex, Location location)
{
foreach (var (vertex, location) in start)
SetLocation(vertex, location);
_sites.Vertices[vertex].Location = location;
location.Sites.Add(_sites.Vertices[vertex]);
FixBoundaryPoints(vertex, location);
FixBoundaryEdges(vertex, location);
foreach (var neighbour in _sites.Neighbours(vertex))
if (_sites.Vertices[neighbour].Location == null)
_queue.Add((neighbour, location));
else if (location != _sites.Vertices[neighbour].Location)
_locations.AddEdge(
_locations.Vertices.IndexOf(location),
_locations.Vertices.IndexOf(_sites.Vertices[neighbour].Location)
);
}
private (int, Location) Dequeue()
@ -37,7 +57,7 @@ namespace Assets.Map
_queue.RemoveAt(index);
if (_graph.Vertices[pair.Item1].Location == null) return pair;
if (_sites.Vertices[pair.Item1].Location == null) return pair;
}
throw new Exception("No more elements.");
@ -56,23 +76,10 @@ namespace Assets.Map
}
}
private void SetLocation(int vertex, Location location)
{
_graph.Vertices[vertex].Location = location;
location.Sites.Add(_graph.Vertices[vertex]);
FixBoundaryPoints(vertex, location);
FixBoundaryEdges(vertex, location);
foreach (var neighbour in _graph.Neighbours(vertex))
if (_graph.Vertices[neighbour].Location == null)
_queue.Add((neighbour, location));
}
private void FixBoundaryPoints(int vertex, Location location)
{
var a = location.BoundaryPoints;
var b = _graph.Vertices[vertex].Site.Vertices;
var b = _sites.Vertices[vertex].Site.Vertices;
if (!_blacklist.ContainsKey(location)) _blacklist[location] = new List<int>();
_blacklist[location].AddRange(a.Intersect(b));
@ -83,7 +90,7 @@ namespace Assets.Map
private void FixBoundaryEdges(int vertex, Location location)
{
var a = location.BoundaryEdges;
var b = _graph.Vertices[vertex].Site.Edges;
var b = _sites.Vertices[vertex].Site.Edges;
location.BoundaryEdges = a.Union(b).Except(a.Intersect(b)).ToList();
}

View File

@ -24,6 +24,7 @@ namespace Assets
public bool displayHalfEdges = false;
public bool displayEdges = true;
public bool displayLocations = true;
public bool displayLocationCells = true;
public bool displayLocationEdges = true;
public bool displayLocationPoints = true;
}
@ -69,6 +70,7 @@ namespace Assets
public float radius = 8;
private double _directrix = 0.0f;
private Graph<(Point, Location)> _locationGraph;
void Start()
{
@ -94,6 +96,7 @@ namespace Assets
_voronoiGenerator = new VoronoiGenerator(_points.Select(x => new Point(x.x, x.y)).ToList());
_locationGenerator = null;
_locationGraph = null;
_locations = new List<Location>() { new Location() { Type = new LocationType() { color = Color.clear, name = "Ocean" } } };
_locations.AddRange(types.Select(type => new Location { Type = type }));
@ -118,19 +121,27 @@ namespace Assets
{
Stage = GenerationStage.Location;
_locationGenerator = new LocationGenerator(_voronoiGenerator.Delaunay.Morph(site => new LocationSite(site)), _random);
_locationGenerator.Init(
_locations.Select(location => (_random.Next(_voronoiGenerator.Delaunay.Vertices.Count), location))
.Concat(new List<int> { 0, 1, 2, 3 }.Select(i => (i, _locations[0]))) // borders should be water
.ToArray()
);
_locationGenerator = new LocationGenerator(_locations, _voronoiGenerator.Delaunay, _random);
var initial =
from location in _locations
select (_random.Next(_voronoiGenerator.Delaunay.Vertices.Count), location);
initial = initial.Concat(new List<int> { 0, 1, 2, 3 }.Select(i => (i, _locations[0])));
foreach (var (vertex, location) in initial)
_locationGenerator.SetLocation(vertex, location);
}
}
else if (Stage == GenerationStage.Location)
{
_locationGenerator.Step();
if (_locationGenerator.Done) Stage = GenerationStage.Done;
if (_locationGenerator.Done)
{
Stage = GenerationStage.Done;
RecalculateLocationGraph();
}
}
}
@ -208,15 +219,20 @@ namespace Assets
if (LocationGenerator == null) return;
if (debug.displayLocations)
if (debug.displayLocationCells)
{
foreach (var location in LocationGenerator.Result.Vertices.Where(l => l.Location != null && l.Location != _locations[0]))
foreach (var location in LocationGenerator.Sites.Vertices.Where(l => l.Location != null && l.Location != _locations[0]))
{
Gizmos.color = location.Location.Type.color;
Gizmos.DrawSphere(location.Site.Point.ToVector3(), 2);
}
}
if (debug.displayLocations && _locationGraph != null)
{
DisplayGraphEdges(_locationGraph.Morph(a => a.Item1));
}
if (debug.displayLocationPoints)
{
foreach (var location in _locations.Skip(1))
@ -270,6 +286,27 @@ namespace Assets
foreach (var (s, e) in edges) Gizmos.DrawLine(s, e);
}
private void RecalculateLocationGraph()
{
Point Mean(IEnumerable<Point> points)
{
var result = new Point(0, 0);
var i = 0;
foreach (var point in points)
{
result.x = (result.x * i + point.x) / (i + 1);
result.y = (result.y * i + point.y) / (i + 1);
i++;
}
return result;
}
_locationGraph = LocationGenerator.Result.Morph(location => (Mean(location.Sites.Select(s => s.Site.Point)), location));
}
}
}