inz-00/Assets/Scripts/AnnotationPass/LocateCitiesPass.cs
2019-11-21 20:40:35 +01:00

96 lines
3.1 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using Assets.Cities;
using Assets.Common;
namespace Assets.AnnotationPass
{
public class LocateCitiesPass : IAnnotationPass
{
public const string CitiesProperty = "Cities";
public const string CityProperty = "City";
public int MaxCitiesCount { get; set; } = 20;
public int MaxPlacementTries { get; set; } = 30;
public float RangeOfInfluence { get; set; } = .5f;
public float CitiesSize { get; set; } = .5f;
private Graph<Location> _locationGraph;
private Graph<MapSite> _basicGraph;
private Random _random;
public LocateCitiesPass(Random random = null)
{
_random = random ?? new Random();
}
City CreateCity(int vertex, int size)
{
City newCity = new City();
var site = _basicGraph.Vertices[vertex];
newCity.Center = site.Center.Clone() as Point;
site.Tags.Add("City.Center");
var sites = new List<MapSite> { site };
var location = site.Metadata.GetProperty<Location>(LandmassPass.SiteLocationProperty);
for (int i = 0; i < size - 1; i++)
{
var neighbours = _basicGraph.Neighbours(site.Index).Select(j => _basicGraph.Vertices[j]).Where(s => s.Metadata.GetProperty<Location>(LandmassPass.SiteLocationProperty) == location).ToList();
site = neighbours[_random.Next(neighbours.Count)];
sites.Add(site);
}
foreach (var s in sites.Distinct())
{
newCity.AddSite(s);
s.Metadata.SetProperty(CityProperty, newCity);
}
newCity.RangeOfInfluence = GetCityRangeOfInfluence(newCity);
return newCity;
}
List<City> CreateCities()
{
List<City> cities = new List<City>();
var vertices = new List<int>();
int guard = MaxPlacementTries;
int createdCitiesCount = 0;
while (createdCitiesCount < MaxCitiesCount && guard-- > 0)
{
var randomLocation = _locationGraph.Vertices.Skip(1).RandomElement(_random);
var randomSite = randomLocation.Sites.RandomElement(_random);
if (cities.Any(c => Point.Dist(PointUtils.Mean(c.Sites.Select(s => s.Center)), randomSite.Center) < c.RangeOfInfluence))
continue;
cities.Add(CreateCity(randomSite.Index, (int)Math.Ceiling(CitiesSize * _random.Next(0, 30))));
guard = MaxPlacementTries;
createdCitiesCount++;
}
return cities;
}
public float GetCityRangeOfInfluence(City city)
{
return RangeOfInfluence*city.Sites.Count;
}
public void Annotate(Map map)
{
_basicGraph = map.Sites.Clone() as Graph<MapSite>;
_locationGraph = map.Metadata.GetProperty<Graph<Location>>(LandmassPass.MapLocationsProperty);
var cities = CreateCities();
map.Metadata.SetProperty(CitiesProperty, cities);
}
}
}