Add information about cell voronoi vertices

This commit is contained in:
Kacper Donat 2019-08-15 20:22:18 +02:00
parent 5e8cb736ac
commit 945b639dbd
24 changed files with 253 additions and 225 deletions

3
Assets/Common.meta Normal file
View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9d3e07b4c54b4298817166f19d224de7
timeCreated: 1564324091

View File

@ -1,7 +1,6 @@
using System;
using UnityEngine;
namespace Assets.Voronoi
namespace Assets.Common
{
public class Point
{
@ -19,9 +18,4 @@ namespace Assets.Voronoi
return Math.Sqrt(Math.Pow(a.x - b.x, 2) + Math.Pow(a.y - b.y, 2));
}
}
public class VoronoiGraph
{
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a6e558709286422ba155d8132b36242c
timeCreated: 1564324127

View File

@ -0,0 +1,12 @@
using UnityEngine;
namespace Assets.Common
{
public static class UnityPointExtensions
{
public static Vector3 ToVector3(this Point p)
{
return new Vector3((float)p.x, (float)p.y);
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: db7eb0dc4b174fc5a40dd6871366b5ea
timeCreated: 1564324236

View File

@ -14,6 +14,8 @@ namespace Editor
{
GraphGenerator generator = (GraphGenerator)target;
GUILayout.Label($"Stage: {generator.Stage}");
DrawDefaultInspector();
if (GUILayout.Button("Reset")) {
@ -50,10 +52,10 @@ namespace Editor
{
GraphGenerator generator = (GraphGenerator)target;
if (generator.generator != null)
if (generator.VoronoiGenerator != null)
{
var moved = Handles.PositionHandle(generator.transform.position + Vector3.up * (float)generator.generator.Line.Directrix, Quaternion.identity);
generator.generator.Line.Directrix = moved.y;
var moved = Handles.PositionHandle(generator.transform.position + Vector3.up * (float)generator.VoronoiGenerator.Line.Directrix, Quaternion.identity);
generator.VoronoiGenerator.Line.Directrix = moved.y;
}
}
}

View File

@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
@ -17,5 +18,20 @@ namespace Assets.Map
{
return Edges.Where(x => x.Item1 == a || x.Item2 == a);
}
public Graph<U> Morph<U>(Func<T, U> morph)
{
var result = new Graph<U>() { Edges = Edges };
result.Vertices.AddRange(Vertices.Select(morph));
return result;
}
public IEnumerable<int> Neighbours(int vertex)
{
foreach (var (a, b) in this.EdgesOf(vertex))
yield return a == vertex ? b : a;
}
}
}

17
Assets/Map/Location.cs Normal file
View File

@ -0,0 +1,17 @@
using Assets.Common;
using Assets.Voronoi;
using UnityEngine;
namespace Assets.Map
{
public class Location
{
public readonly Point Center;
public Color Type;
public Location(Point center)
{
Center = center;
}
}
}

View File

@ -0,0 +1,62 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Random = System.Random;
namespace Assets.Map
{
public class LocationGenerator
{
private Graph<Location> _graph;
private readonly List<(int, Color)> _queue = new List<(int, Color)>();
private Random _random;
public bool Done => _queue.Count == 0;
public Graph<Location> Result => _graph;
public LocationGenerator(Graph<Location> graph, Random random = null)
{
_graph = graph;
_random = random ?? new Random();
}
public void Init(params (int, Color)[] start)
{
foreach (var pair in start)
_queue.Add(pair);
}
private (int, Color) Dequeue()
{
while (_queue.Count > 0)
{
var index = _random.Next(_queue.Count);
var pair = _queue[index];
_queue.RemoveAt(index);
if (_graph.Vertices[pair.Item1].Type == Color.clear) return pair;
}
throw new Exception("No more elements.");
}
public void Step()
{
try
{
var (vertex, color) = Dequeue();
_graph.Vertices[vertex].Type = color;
foreach (var neighbour in _graph.Neighbours(vertex))
if (_graph.Vertices[neighbour].Type == Color.clear)
_queue.Add((neighbour, color));
}
catch (Exception ex)
{
}
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7a2d1705444344bfa99efc3c210db6f4
timeCreated: 1564324021

View File

@ -5,6 +5,6 @@ namespace Assets.Map
[Serializable]
public class Map
{
public readonly Graph<Section> Sections = new Graph<Section>();
public readonly Graph<Location> Sections = new Graph<Location>();
}
}

View File

@ -1,8 +0,0 @@
namespace Assets.Map
{
public class Section
{
public double x;
public double y;
}
}

View File

@ -248,14 +248,20 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 06dfaa94f8713f12fbe207b61b694c90, type: 3}
m_Name:
m_EditorClassIdentifier:
seed: 150
size: {x: 100, y: 100}
seed: 500
size: {x: 200, y: 200}
debug:
enabled: 1
displayPoints: 1
displayBeachLine: 1
displayParabolas: 0
displayVertices: 0
displayNeighbours: 0
displayLabels: 0
displayHalfEdges: 0
displayEdges: 1
displayLocations: 1
radius: 8
--- !u!33 &528199734
MeshFilter:
m_ObjectHideFlags: 0

View File

@ -1,61 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
[RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))]
public class CircleGenerator : MonoBehaviour
{
[Range(1, 200)]
public int NodeCount = 3;
public int Details = 150;
public float Radius = 20.0f;
[Range(0, 1)]
public float AngleVariation = 0.5f;
public float RadiusVariation = 2f;
private Random random = new Random();
private float RandomCoefficient(float multiplier) => 2 * (Random.value - 0.5f) * multiplier;
public void Generate()
{
Vector3 center = new Vector3(0, 0, 0);
Mesh mesh = new Mesh();
var maxAngleVariation = AngleVariation * Mathf.PI * 2 / Details;
var vertices = new List<Vector3>();
for (int i = 0; i < Details; i++)
{
var angle = i * Mathf.PI * 2 / Details + RandomCoefficient(maxAngleVariation);
var radius = Radius + RandomCoefficient(RadiusVariation);
Vector3 direction = new Vector3(Mathf.Sin(angle), 0, Mathf.Cos(angle));
vertices.Add(direction * radius);
}
var triangles = new List<int>();
for (int i = 0; i < Details - 2; i++)
{
triangles.Add(0);
triangles.Add(i);
triangles.Add(i + 1);
}
var normals = new List<Vector3>();
for (int i = 0; i < Details; i++)
{
normals.Add(-Vector3.forward);
}
mesh.vertices = vertices.ToArray();
mesh.triangles = triangles.ToArray();
mesh.normals = normals.ToArray();
var mf = GetComponent<MeshFilter>();
mf.mesh = mesh;
}
}

View File

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 3229222b4f08ca4759cc1561d71992c0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Assets.Common;
using Assets.Generators;
using Assets.Map;
using Assets.Voronoi;
@ -22,26 +23,51 @@ namespace Assets
public bool displayLabels = false;
public bool displayHalfEdges = false;
public bool displayEdges = true;
public bool displayLocations = true;
}
[Serializable]
public class Section
{
public string name;
public Color color;
}
public enum GenerationStage
{
Start,
Voronoi,
Location,
Done
};
[RequireComponent(typeof(MeshRenderer), typeof(MeshFilter)), ExecuteInEditMode]
public class GraphGenerator : MonoBehaviour
{
MeshFilter _filter;
private PoissonDiskSampler _sampler;
IList<Vector3> _points = new List<Vector3>();
List<Vector3> _points = new List<Vector3>();
public List<Section> sections = new List<Section>();
public VoronoiGenerator generator;
private VoronoiGenerator _voronoiGenerator;
private LocationGenerator _locationGenerator;
public VoronoiGenerator VoronoiGenerator => _voronoiGenerator;
public LocationGenerator LocationGenerator => _locationGenerator;
public int seed = Environment.TickCount;
public Vector2 size = new Vector2();
public GraphGeneratorDebug debug;
public GenerationStage Stage { get; internal set; } = GenerationStage.Start;
[Range(2.0f, 64.0f)]
public float radius = 8;
private double _directrix = 0.0f;
private Random _random;
private Dictionary<Vector3, Color> _colors;
private Graph<Location> _locations;
void Start()
{
@ -50,108 +76,113 @@ namespace Assets
Reset();
}
public Vector3 RandomPoint()
{
return _points[_random.Next(_points.Count)];
}
public void Reset()
{
_colors = new Dictionary<Vector3, Color>();
_random = new System.Random(seed);
_sampler = new PoissonDiskSampler(radius);
_sampler.Generator = _random;
_points = new List<Vector3>(_sampler.Generate(size.x, size.y));
_points = new List<Vector3>();
_points.Add(new Vector3(0, -0.1f));
_points.Add(new Vector3(size.x, 0.1f));
_points.Add(new Vector3(size.x, size.y - 0.1f));
_points.Add(new Vector3(0, size.y + 0.1f));
_points.AddRange(_sampler.Generate(size.x, size.y));
for (int i = 0; i < 10; i++)
{
_colors[RandomPoint()] = Color.yellow;
}
// points = new List<Vector3>()
// {
// new Vector3(15.7f, 5.9f),
// new Vector3(37.9f, 10.3f),
// new Vector3(24.6f, 18.1f),
// new Vector3(53.5f, 8.0f),
// };
generator = new VoronoiGenerator(_points.Select(x => new Point(x.x, x.y)).ToList());
Stage = GenerationStage.Voronoi;
_voronoiGenerator = new VoronoiGenerator(_points.Select(x => new Point(x.x, x.y)).ToList());
_locationGenerator = null;
}
public void Generate()
{
generator.Generate();
while (Stage != GenerationStage.Done)
{
Step();
}
}
public void Step()
{
generator.Step();
_directrix = generator.Line.Directrix;
if (Stage == GenerationStage.Voronoi)
{
_voronoiGenerator.Step();
_directrix = _voronoiGenerator.Line.Directrix;
if (_voronoiGenerator.Done)
{
Stage = GenerationStage.Location;
_locationGenerator = new LocationGenerator(_voronoiGenerator.Delaunay.Morph(p => new Location(p)), _random);
_locationGenerator.Init(
sections.Select(section => (_random.Next(_voronoiGenerator.Delaunay.Vertices.Count), section.color))
.Concat(new List<(int, Color)> { (0, Color.white), (1, Color.white), (2, Color.white), (3, Color.white)})
.ToArray()
);
}
}
else if (Stage == GenerationStage.Location)
{
_locationGenerator.Step();
if (_locationGenerator.Done) Stage = GenerationStage.Done;
}
}
void OnDrawGizmos()
{
if (!debug.enabled) return;
if (!debug.enabled || _voronoiGenerator == null) return;
if (debug.displayPoints)
{
foreach (var point in _points)
{
Gizmos.color = _colors.ContainsKey(point) ? _colors[point] : Color.white;
Gizmos.DrawSphere(point, 1);
}
Gizmos.color = Color.white;
DisplayGraphVertices(_voronoiGenerator.Delaunay);
}
if (generator is null) return;
if (debug.displayNeighbours)
{
Gizmos.color = Color.yellow;
DisplayGraphEdges(generator.Delaunay);
DisplayGraphEdges(_voronoiGenerator.Delaunay);
}
if (debug.displayVertices)
{
Gizmos.color = Color.blue;
DisplayGraphVertices(generator.Voronoi);
DisplayGraphVertices(_voronoiGenerator.Voronoi);
}
if (debug.displayHalfEdges)
{
Gizmos.color = Color.green;
foreach (var edge in generator.HalfEdges)
foreach (var edge in _voronoiGenerator.HalfEdges)
{
var vecStart = new Vector3((float)edge.Start.x, (float)edge.Start.y);
var vecEnd = new Vector3((float)edge.End.x, (float)edge.End.y);
Gizmos.DrawLine(vecStart, vecEnd);
Gizmos.DrawLine(edge.Start.ToVector3(), edge.End.ToVector3());
}
}
if (debug.displayEdges)
{
Gizmos.color = Color.white;
DisplayGraphEdges(generator.Voronoi);
DisplayGraphEdges(_voronoiGenerator.Voronoi);
}
Gizmos.color = Color.red;
Gizmos.DrawLine(new Vector3(0, (float)generator.Line.Directrix), new Vector3(size.x, (float)generator.Line.Directrix));
Gizmos.DrawLine(new Vector3(0, (float)_voronoiGenerator.Line.Directrix), new Vector3(size.x, (float)_voronoiGenerator.Line.Directrix));
Gizmos.color = Color.blue;
Vector3 start;
if (debug.displayParabolas)
{
foreach (var parabola in generator.Line.Parabolas)
foreach (var parabola in _voronoiGenerator.Line.Parabolas)
{
start = new Vector3(-size.x, (float)generator.Line.EvalParabola(parabola.Site.Point, -size.x));
start = new Vector3(-size.x, (float)_voronoiGenerator.Line.EvalParabola(parabola.Site.Point, -size.x));
for (var x = -size.x + 0.1f; x < size.x * 2; x += 0.1f)
{
var point = new Vector3(x, (float)generator.Line.EvalParabola(parabola.Site.Point, x));
var point = new Vector3(x, (float)_voronoiGenerator.Line.EvalParabola(parabola.Site.Point, x));
Gizmos.DrawLine(start, point);
start = point;
@ -162,33 +193,43 @@ namespace Assets
if (debug.displayBeachLine)
{
Gizmos.color = Color.white;
start = new Vector3(-size.x, (float)generator.Line.Eval(-size.x));
start = new Vector3(-size.x, (float)_voronoiGenerator.Line.Eval(-size.x));
for (var x = -size.x + 0.1f; x < size.x * 2; x += 0.1f)
{
var point = new Vector3(x, (float)generator.Line.Eval(x));
var point = new Vector3(x, (float)_voronoiGenerator.Line.Eval(x));
Gizmos.DrawLine(start, point);
start = point;
}
}
if (debug.displayLocations && LocationGenerator != null)
{
foreach (var location in LocationGenerator.Result.Vertices.Where(l => l.Type != Color.white))
{
Gizmos.color = location.Type;
Gizmos.DrawSphere(location.Center.ToVector3(), 2);
}
}
}
public void Rewind(float y)
{
while (generator.Line.Directrix < y && !generator.Done)
while (_voronoiGenerator.Line.Directrix < y && !_voronoiGenerator.Done)
{
generator.Step();
_voronoiGenerator.Step();
}
}
private void DisplayGraphVertices(Graph<Point> graph)
{
var vertices = graph.Vertices.Select(p => new Vector3((float) p.x, (float) p.y));
foreach (var v in vertices)
var vertices = graph.Vertices.Select(p => p.ToVector3());
var offset = Vector3.right;
foreach (var (v, i) in vertices.Select((x, i) => (x, i)))
{
Gizmos.DrawSphere(v, 1);
if (debug.displayLabels) Handles.Label(v, $"({v.x:F2}, {v.y:F2})");
if (debug.displayLabels) Handles.Label(v + offset, $"{i}");
}
}
@ -196,9 +237,10 @@ namespace Assets
{
var edges = graph.Edges
.Select(edge => (graph.Vertices[edge.Item1], graph.Vertices[edge.Item2]))
.Select(edge => (new Vector3((float)edge.Item1.x, (float)edge.Item1.y), new Vector3((float)edge.Item2.x, (float)edge.Item2.y)));
.Select(edge => (edge.Item1.ToVector3(), edge.Item2.ToVector3()));
foreach (var (s, e) in edges) Gizmos.DrawLine(s, e);
}
}
}

View File

@ -1,57 +0,0 @@
using System;
using Generators;
using UnityEngine;
public class MapRenderer : MonoBehaviour
{
public Renderer mapRenderer;
public IGenerator generator;
public Vector2 Offset;
public float Scale;
[Range(0, 1)]
public float Decay;
[Range(0, 4)]
public float Lacunarity;
[Range(0, 1)]
public float Threshold;
public void DrawMap(int width, int height)
{
var texture = new Texture2D(width, height);
var colors = new Color[width * height];
var position = new Vector2(0.0f, 0.0f);
generator = new PerlinNoiseGenerator {
Scale = Scale,
Offset = Offset,
Decay = Decay,
Lacunarity = Lacunarity
};
generator = new IslandGenerator(generator) {
Threshold = Threshold
};
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
position.x = x - width / 2;
position.y = y - height / 2;
colors[y * width + x] = Color.Lerp(Color.black, Color.white, (float)generator.GetValue(position));
}
}
texture.SetPixels(colors);
texture.Apply();
mapRenderer.sharedMaterial.mainTexture = texture;
mapRenderer.transform.localScale = new Vector3(width / 100.0f, 1, height / 100.0f);
}
}

View File

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 56488ae21f3a5526189eba26fc16d0c3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using Assets.Common;
using static System.Math;
namespace Assets.Voronoi

View File

@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.Linq;
using Assets.Common;
using Assets.Map;
using Priority_Queue;
@ -32,6 +33,7 @@ namespace Assets.Voronoi
{
public Point Point { get; internal set; }
public int Index { get; internal set; }
public ISet<int> Vertices { get; internal set; } = new HashSet<int>();
public Site(Point point, int index)
{
@ -129,28 +131,36 @@ namespace Assets.Voronoi
Voronoi.Vertices.Add(@event.vertex);
var index = Voronoi.Vertices.Count - 1;
node.Value.LeftEdge.End = @event.vertex;
node.Value.LeftEdge.EndVertex = Voronoi.Vertices.Count - 1;
node.Value.LeftEdge.EndVertex = index;
node.Value.RightEdge.End = @event.vertex;
node.Value.RightEdge.EndVertex = Voronoi.Vertices.Count - 1;
node.Value.RightEdge.EndVertex = index;
HalfEdges.Add(node.Value.LeftEdge);
HalfEdges.Add(node.Value.RightEdge);
node.Value.Site.Vertices.Add(index);
previous?.Value.Site.Vertices.Add(index);
next?.Value.Site.Vertices.Add(index);
if (node.Value.LeftEdge.IsComplete)
{
var (a, b) = node.Value.LeftEdge.Edge;
Voronoi.AddEdge(a, b);
}
if (node.Value.RightEdge.IsComplete)
{
var (a, b) = node.Value.RightEdge.Edge;
Voronoi.AddEdge(a, b);
}
var newEdge = new HalfEdge() { Start = @event.vertex, StartVertex = Voronoi.Vertices.Count - 1 };
var newEdge = new HalfEdge() { Start = @event.vertex, StartVertex = index };
node.Previous.Value.RightEdge = newEdge;
node.Next.Value.LeftEdge = newEdge;

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 9e306028c37441f7abf011f8429ffcef
timeCreated: 1563289564

View File

@ -3,7 +3,7 @@
--- !u!30 &1
GraphicsSettings:
m_ObjectHideFlags: 0
serializedVersion: 12
serializedVersion: 13
m_Deferred:
m_Mode: 1
m_Shader: {fileID: 69, guid: 0000000000000000f000000000000000, type: 0}
@ -31,6 +31,9 @@ GraphicsSettings:
m_AlwaysIncludedShaders:
- {fileID: 10753, guid: 0000000000000000f000000000000000, type: 0}
- {fileID: 10770, guid: 0000000000000000f000000000000000, type: 0}
- {fileID: 16000, guid: 0000000000000000f000000000000000, type: 0}
- {fileID: 16001, guid: 0000000000000000f000000000000000, type: 0}
- {fileID: 17000, guid: 0000000000000000f000000000000000, type: 0}
m_PreloadedShaders: []
m_SpritesDefaultMaterial: {fileID: 10754, guid: 0000000000000000f000000000000000,
type: 0}
@ -55,3 +58,5 @@ GraphicsSettings:
m_AlbedoSwatchInfos: []
m_LightsUseLinearIntensity: 0
m_LightsUseColorTemperature: 0
m_LogWhenShaderIsCompiled: 0
m_AllowEnlightenSupportForUpgradedProject: 1

View File

@ -4,7 +4,7 @@
UnityConnectSettings:
m_ObjectHideFlags: 0
serializedVersion: 1
m_Enabled: 0
m_Enabled: 1
m_TestMode: 0
m_EventOldUrl: https://api.uca.cloud.unity3d.com/v1/events
m_EventUrl: https://cdp.cloud.unity3d.com/v1/events