Generated buildings

This commit is contained in:
2015-06-10 11:49:43 +03:00
parent 352f212ae9
commit 4b61f0bdb5
47 changed files with 892 additions and 110 deletions

View File

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TransportGame.Model
{
public class Building
{
/// <summary>
/// From lowest to highest level
/// </summary>
public Polygon[][] Polygons { get; set; }
/// <summary>
/// From lowest to highest level
/// </summary>
public float[] LevelHeights { get; set; }
}
}

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 4ef412bd6ccb705428e5569cf84b018f
timeCreated: 1433489978
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using TransportGame.Business;
using TransportGame.Utils;
namespace TransportGame.Model
{
@ -13,21 +14,54 @@ namespace TransportGame.Model
/// </summary>
public Vector2[] Points { get; set; }
/// <summary>
/// Gets or sets the size of the lot
/// </summary>
public float Size { get; set; }
/// <summary>
/// Initializes the building lot
/// </summary>
public BuildingLot()
{
Points = new Vector2[4];
}
public BuildingLot(params Vector2[] points)
/// <summary>
/// Initializes lot with given size
/// </summary>
/// <param name="size">size</param>
public BuildingLot(float size)
{
Points = new Vector2[4];
Size = size;
}
/// <summary>
/// Initializes lot with given points and size
/// </summary>
/// <param name="size">Size</param>
/// <param name="points">Points</param>
public BuildingLot(float size, params Vector2[] points)
{
Points = points;
Size = size;
}
public BuildingLot(IEnumerable<Vector2> points)
/// <summary>
/// Initializes lot with given points and size
/// </summary>
/// <param name="size">Size</param>
/// <param name="points">Points</param>
public BuildingLot(float size, IEnumerable<Vector2> points)
{
Points = points.ToArray();
Size = size;
}
/// <summary>
/// Gets the lot position
/// </summary>
public Vector2 Position
{
get { return Points.Aggregate((x, y) => x + y) / Points.Length; }
@ -39,9 +73,9 @@ namespace TransportGame.Model
/// <param name="a">First lot</param>
/// <param name="b">Second lot</param>
/// <returns></returns>
public static bool Intersect(BuildingLot a, BuildingLot b)
public static bool DoesIntersect(BuildingLot a, BuildingLot b)
{
return (a.Position - b.Position).LengthSq <= ConfigManager.Buildgen.LotSquareSize + ConfigManager.Buildgen.LotSpacing;
return Algorithmss.DoPolygonsIntersect(a.Points, b.Points);
}
/// <summary>
@ -50,7 +84,7 @@ namespace TransportGame.Model
/// <param name="a"></param>
/// <param name="b"></param>
/// <returns></returns>
public static bool Intersect(BuildingLot a, LineSegment b)
public static bool DoesIntersect(BuildingLot a, LineSegment b)
{
for (int i = 0; i < a.Points.Length; i++)
{

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 8d4e9031660798e43954c6c698daf966
timeCreated: 1433365105
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -8,19 +8,49 @@ namespace TransportGame.Model.Config
public class BuildingGeneratorConfig
{
/// <summary>
/// Lot size
/// Minimum lot size
/// </summary>
public float LotSquareSize { get; set; }
public float LotSquareMinSize { get; set; }
/// <summary>
/// Maximum lot size
/// </summary>
public float LotSquareMaxSize { get; set; }
/// <summary>
/// Space between lots
/// </summary>
public float LotSpacing { get; set; }
/// <summary>
/// Maximum number of attempts to generate a lot in a specific area
/// </summary>
public int MaxLotAttempts { get; set; }
/// <summary>
/// Maximum number of levels on a building
/// </summary>
public int MaxBuildingLevels { get; set; }
/// <summary>
/// Maximum height for a building
/// </summary>
public float MaxBuildingHeight { get; set; }
/// <summary>
/// Maximum number of primitive polygons to be generated per level
/// </summary>
public int MaxPolygonsPerLevel { get; set; }
public BuildingGeneratorConfig()
{
LotSquareSize = 1f;
LotSquareMinSize = 5f;
LotSquareMaxSize = 20f;
LotSpacing = 0.1f;
MaxLotAttempts = 3;
MaxBuildingHeight = 20f;
MaxBuildingLevels = 5;
MaxPolygonsPerLevel = 3;
}
}
}

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 67b392479c775904c970253005f9c856
timeCreated: 1433365105
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -75,6 +75,9 @@ namespace TransportGame.Model
[XmlArrayItem("center")]
public List<Vector2> PopulationCenters { get; set; }
/// <summary>
/// Gets or sets the range of one population center (distance how far it influences)
/// </summary>
public float PopulationCenterRange { get; set; }
/// <summary>
@ -89,6 +92,12 @@ namespace TransportGame.Model
[XmlElement("lots")]
public List<BuildingLot> BuildingLots { get; set; }
/// <summary>
/// Gets or sets the buildings
/// </summary>
[XmlElement("buildings")]
public List<Building> Buildings { get; set; }
#endregion
#region Constructors

View File

@ -0,0 +1,247 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TransportGame.Utils;
namespace TransportGame.Model
{
/// <summary>
/// Represents a polygon
/// </summary>
public class Polygon : IPositionable
{
#region Private types
private struct Edge
{
public int U, V;
public Edge(int U, int V)
{
this.U = U;
this.V = V;
}
}
#endregion
/// <summary>
/// Gets or sets the points that define the polygon
/// </summary>
public Vector2[] Points { get; set; }
/// <summary>
/// Gets the gravitational center
/// </summary>
public Vector2 Position
{
get { return Points.Aggregate((x, y) => x + y) / Points.Length; }
}
/// <summary>
/// Initializes polygon
/// </summary>
public Polygon()
{
Points = new Vector2[0];
}
/// <summary>
/// Initializes polygon using given points
/// </summary>
/// <param name="points">Points</param>
public Polygon(IEnumerable<Vector2> points)
{
Points = points.ToArray();
}
/// <summary>
/// Initializes polygon using given points
/// </summary>
/// <param name="points">Points</param>
public Polygon(params Vector2[] points)
{
Points = points;
}
/// <summary>
/// Compares angle between two NORMALIZED vectors.
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <returns></returns>
private static float CompareAngle(Vector2 a, Vector2 b)
{
float sin = Vector2.Cross(a, b);
float cos = Vector2.Dot(a, b);
if (sin >= 0 && cos >= 0)
return sin;
else if (sin >= 0 && cos <= 0)
return 1 + Math.Abs(cos);
else if (sin <= 0 && cos <= 0)
return 2 + Math.Abs(sin);
else return 3 + cos;
}
/// <summary>
/// Returns the union between given polygons
/// </summary>
/// <param name="polys">Polygons</param>
/// <returns>Polygon representing union</returns>
public static Polygon Union(params Polygon[] polys)
{
return Union(polys);
}
/// <summary>
/// Returns the union between given polygons
/// </summary>
/// <param name="polys">Polygons</param>
/// <returns>Polygon representing union</returns>
public static Polygon Union(IEnumerable<Polygon> polys)
{
List<Vector2> vertices = new List<Vector2>();
List<Edge> edges = new List<Edge>();
List<Vector2> union = new List<Vector2>();
foreach (var poly in polys)
{
// Add all points
for (int i = 0; i < poly.Points.Length; i++)
{
int j = (i + 1) % poly.Points.Length;
// Get/add first point
int indexi = vertices.IndexOf(poly.Points[i]);
if (indexi == -1)
{
vertices.Add(poly.Points[i]);
indexi = vertices.Count - 1;
}
// Get/add second point
int indexj = vertices.IndexOf(poly.Points[j]);
if (indexj == -1)
{
vertices.Add(poly.Points[j]);
indexj = vertices.Count - 1;
}
// Add edge
edges.Add(new Edge(indexi, indexj));
}
}
// Intersect edges
for (int i = 0; i < edges.Count; i++)
for (int j = i + 1; j < edges.Count; j++)
{
LineSegment a = new LineSegment(vertices[edges[i].U], vertices[edges[i].V]);
LineSegment b = new LineSegment(vertices[edges[j].U], vertices[edges[j].V]);
var inters = LineSegment.Intersect(a, b);
if (inters.HasValue && inters.Value != a.P0 && inters.Value != a.P1 && inters.Value != b.P0 && inters.Value != b.P1)
{
vertices.Add(inters.Value);
int index = vertices.Count - 1;
edges.Add(new Edge(index, edges[i].V));
edges[i] = new Edge(edges[i].U, index);
edges.Add(new Edge(index, edges[j].V));
edges[j] = new Edge(edges[j].U, index);
}
}
// Compute union
int start = 0;
// Find starting point
for (int i = 0; i < vertices.Count; i++)
if (vertices[i].X + vertices[i].Y < vertices[start].X + vertices[start].Y)
start = i;
int v = start, vold = -1;
Vector2 prev = vertices[v].Normalized;
do
{
union.Add(vertices[v]);
int newV = -1;
float smallestAngle = -1;
Vector2 smallestDir = Vector2.Zero;
foreach (var edge in edges)
{
if ((edge.U == v || edge.V == v) && edge.V != vold && edge.U != vold)
{
int otherv = (edge.U == v) ? edge.V : edge.U;
Vector2 dir = (vertices[otherv] - vertices[v]).Normalized;
// Find smallest angle
float cmpAngle = CompareAngle(-prev, dir);
if (cmpAngle < smallestAngle || smallestAngle < 0)
{
newV = otherv;
smallestAngle = cmpAngle;
smallestDir = dir;
}
}
}
// Advance
prev = smallestDir;
vold = v;
v = newV;
} while (v != start);
return new Polygon(union);
}
public static bool DoPolygonsIntersect(Polygon a, Polygon b)
{
foreach (var poly in new[] { a, b })
{
for (int i = 0; i < poly.Points.Length; i++)
{
int j = (i + 1) % poly.Points.Length;
var normal = new Vector2(poly.Points[j].Y - poly.Points[i].Y, poly.Points[i].X - poly.Points[j].X);
double? minA = null, maxA = null;
foreach (var p in a.Points)
{
var projected = Vector2.Dot(normal, p);
if (minA == null || projected < minA)
minA = projected;
if (maxA == null || projected > maxA)
maxA = projected;
}
double? minB = null, maxB = null;
foreach (var p in b.Points)
{
var projected = Vector2.Dot(normal, p);
if (minB == null || projected < minB)
minB = projected;
if (maxB == null || projected > maxB)
maxB = projected;
}
if (maxA <= minB || maxB <= minA)
return false;
}
}
return true;
}
}
}

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: ee96020375a8f3d4bb7a04e9f7a6b05e
timeCreated: 1433489979
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: