using Assets.Common; using Assets.Map; using Assets.Voronoi; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using UnityEngine; namespace Assets.Scripts { public class PointProximityComparer : IEqualityComparer { double _threshold; public PointProximityComparer(double threshold = 0.2) { _threshold = threshold; } public bool Equals(Point x, Point y) { return Point.Dist(x, y) < _threshold; } public int GetHashCode(Point obj) { return obj.GetHashCode(); } } public class City { public Graph startGraph { get; set; } public List sitesList { get; set; } public Graph roads { get; set; } = new Graph(); public List<(int, int)> boundariesEdges { get; set; } public Graph mainRoad { get; set; } = new Graph(); public City(Graph startGraph) { this.startGraph = startGraph; this.sitesList = new List(); this.boundariesEdges = new List<(int, int)>(); } public City(Graph startGraph, List sitesList) : this(startGraph) { this.sitesList = sitesList; } public void AddSite(Site site) { sitesList.Add(site); FixBoundaryEdges(site); } private void FixBoundaryEdges(Site site) { var a = boundariesEdges; var b = site.Edges.Select(x => x.Item1 < x.Item2 ? x : (x.Item2, x.Item1)); boundariesEdges = a.Union(b).Except(a.Intersect(b)).ToList(); } public void CreateRoadGraph(IList points) { VoronoiGenerator generator = new VoronoiGenerator(sitesList.SelectMany(site => site.Vertices.Select(i => points[i]).Append(site.Point)).Distinct(new PointProximityComparer(4)).ToList()); generator.Generate(); roads = generator.Delaunay.Morph(s => s.Point, e => Point.Dist(generator.Delaunay.Vertices[e.Item1].Point, generator.Delaunay.Vertices[e.Item2].Point)); } } [Serializable] public class GraphGeneratorDebug { public bool displayVertices = false; public bool displayCrossroads = true; public bool displayEdges = false; public bool displayCities = true; public bool displayCityRoads = true; public bool displayCityMainRoads = true; public bool displayWorldRoads = false; } [RequireComponent(typeof(GraphGenerator))] public class CityGenerator : MonoBehaviour { private System.Random _random; private Graph _voronoiGraph; private Graph _locationGraph; private Graph _basicGraph; private List verticesForRoads; private List verticesForCitites; public GraphGeneratorDebug debug; public City city; public List cities = new List(); Graph roads = new Graph(); Graph mainRoads = new Graph(); List CountProbablitityOfCity(List vertices) { List probabilities = new List(); vertices.ForEach(v => probabilities.Add((v % 2 == 0 ? _random.Next(0, 50) : _random.Next(50, 100)))); return probabilities; } List LocateCities() { // var verticesForCitites = CountProbablitityOfCity(ChoosePoints(20)); // verticesForCitites.Sort(); // return verticesForCitites.GetRange(0, 10); return ChoosePoints(20); } City CreateCity(int vertex, int size) { City newCity = new City(_basicGraph); var site = _basicGraph.Vertices[vertex]; var sites = new List() { site }; var location = site.Location; for (int i = 0; i < size - 1; i++) { location = site.Location; var neighbours = _basicGraph.Neighbours(site.Index).Select(j => _basicGraph.Vertices[j]).Where(s => s.Location == location).ToList(); site = neighbours[_random.Next(neighbours.Count)]; sites.Add(site); } foreach (var s in sites.Distinct()) { newCity.AddSite(s); } newCity.CreateRoadGraph(_voronoiGraph.Vertices); newCity.mainRoad = ConnectPointsIntoRoads(newCity.roads); return newCity; } List ChoosePoints(int number) { var vertices = new List(); for (int i = 0; i < number; i++) { var randomLocation = _locationGraph.Vertices[_random.Next(1, _locationGraph.Vertices.Count())]; var count = randomLocation.Sites.Count(); Site randomPoint; randomPoint = randomLocation.Sites[_random.Next(0, count)]; vertices.Add(randomPoint.Index); } return vertices; } Graph ConnectPointsIntoRoads(Graph graph) { //1.Sort all the edges in non - decreasing order of their weight. //2.Pick the smallest edge.Check if it forms a cycle with the spanning tree formed so far. If cycle is not formed, include this edge.Else, discard it. //3.Repeat step#2 until there are (V-1) edges in the spanning tree. graph.Edges = graph.Edges.OrderBy(e => graph.GetEdgeData(e)); graph._edgeData = graph._edgeData.OrderBy(e => e.Value).ToDictionary(e => e.Key, k => k.Value); Graph spanningTree = new Graph(); spanningTree.Vertices = graph.Vertices; foreach (var edge in graph.Edges) { spanningTree.AddEdge(edge.Item1, edge.Item2); if (Graph.HasCycle(spanningTree)) spanningTree.DeleteEdge(edge.Item1, edge.Item2); if (spanningTree.Edges.Count() == spanningTree.Vertices.Count() - 1) break; } return spanningTree; } void CreateWorldRoadGraph() { roads.Vertices = verticesForCitites.Select(i => _basicGraph.Vertices[i]).ToList(); VoronoiGenerator generator = new VoronoiGenerator(roads.Vertices.Select(s => s.Point).ToList()); generator.Generate(); roads.Edges = generator.Delaunay.Edges; } void AddLanesToRoads() { // ergo dodaj randomowe połączenia xd } // UI Methods public void Start() { Reset(); } public void Reset() { var graphGenerator = GetComponent(); _random = new System.Random(graphGenerator.seed); cities = new List(); } public void NewCity() { cities.Add(CreateCity(LocateCities()[_random.Next(0, 10)], _random.Next(0, 10))); } public void Generate() { var graphGenerator = GetComponent(); graphGenerator.Generate(); _basicGraph = graphGenerator.VoronoiGenerator.Delaunay.Morph(l => l); _voronoiGraph = graphGenerator.VoronoiGenerator.Voronoi; _locationGraph = graphGenerator.LocationGenerator.Result; verticesForCitites = LocateCities(); foreach (var index in verticesForCitites) { cities.Add(CreateCity(index, _random.Next(0, 10))); } CreateWorldRoadGraph(); mainRoads = roads.Morph(s => s.Point); } private void DisplayGraphVertices(Graph graph) { 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); } } private void DisplayGraphCrossroads(Graph graph, List vertices) { foreach (var v in vertices.Select(i => graph.Vertices[i].ToVector3())) { Gizmos.DrawSphere(v, 1); } } private void DisplayGraphCities(List cities) { foreach (City city in cities) { Gizmos.color = Color.magenta; foreach (var (a, b) in city.boundariesEdges) { Gizmos.DrawLine(_voronoiGraph.Vertices[a].ToVector3(), _voronoiGraph.Vertices[b].ToVector3()); } foreach (var a in city.sitesList) Gizmos.DrawSphere(a.Point.ToVector3(), 1); } } private void DisplayGraphEdges(Graph graph) { var edges = graph.Edges .Select(edge => (graph.Vertices[edge.Item1], graph.Vertices[edge.Item2])) .Select(edge => (edge.Item1.ToVector3(), edge.Item2.ToVector3())); foreach (var (s, e) in edges) Gizmos.DrawLine(s, e); } private void OnDrawGizmos() { if (debug.displayVertices) { Gizmos.color = Color.white; DisplayGraphVertices(_basicGraph.Morph(l => l.Point)); } if (debug.displayEdges) { Gizmos.color = Color.white; DisplayGraphEdges(_basicGraph.Morph(l => l.Point)); } if (debug.displayCrossroads) { Gizmos.color = Color.magenta; DisplayGraphCrossroads(_basicGraph.Morph(l => l.Point), verticesForRoads); } if (debug.displayCities) { Gizmos.color = Color.magenta; DisplayGraphCities(cities); } if (debug.displayCityRoads) { Gizmos.color = Color.blue; foreach (var city in cities) { DisplayGraphEdges(city.roads); DisplayGraphVertices(city.roads); } } if (debug.displayCityMainRoads) { Gizmos.color = new Color(2.54f, 0.127f, 1.56f); //Gizmos.color = Color.green; foreach (var city in cities) { DisplayGraphEdges(city.mainRoad); } } if (debug.displayWorldRoads) { // Gizmos.color = new Color(0.254f, 0.127f, 0.156f); Gizmos.color = Color.blue; DisplayGraphEdges(mainRoads); } } } }