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;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using UnityEngine; using Assets.Voronoi;
using Random = System.Random; using Random = System.Random;
namespace Assets.Map namespace Assets.Map
{ {
public class LocationGenerator 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 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 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(); _random = random ?? new Random();
} }
public void Init(params (int, Location)[] start) public void SetLocation(int vertex, Location location)
{ {
foreach (var (vertex, location) in start) _sites.Vertices[vertex].Location = location;
SetLocation(vertex, 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() private (int, Location) Dequeue()
@ -37,7 +57,7 @@ namespace Assets.Map
_queue.RemoveAt(index); _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."); 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) private void FixBoundaryPoints(int vertex, Location location)
{ {
var a = location.BoundaryPoints; 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>(); if (!_blacklist.ContainsKey(location)) _blacklist[location] = new List<int>();
_blacklist[location].AddRange(a.Intersect(b)); _blacklist[location].AddRange(a.Intersect(b));
@ -83,7 +90,7 @@ namespace Assets.Map
private void FixBoundaryEdges(int vertex, Location location) private void FixBoundaryEdges(int vertex, Location location)
{ {
var a = location.BoundaryEdges; 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(); location.BoundaryEdges = a.Union(b).Except(a.Intersect(b)).ToList();
} }

View File

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