Refractoring

This commit is contained in:
2015-06-17 14:06:54 +03:00
parent 670f260a4c
commit 6b008cfa9a
38 changed files with 706 additions and 419 deletions

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using TransportGame.Primitives;
using TransportGame.Utils;
namespace TransportGame.Model
@ -33,13 +34,13 @@ namespace TransportGame.Model
/// Value is a probability, should be between 0 and 1.
/// </remarks>
[XmlElement("moisture")]
public Range Moisture { get; set; }
public Interval Moisture { get; set; }
/// <summary>
/// Gets or sets the vegetation density of the biome
/// </summary>
[XmlElement("vegetationDensity")]
public Range VegetationDensity { get; set; }
public Interval VegetationDensity { get; set; }
/// <summary>
/// Gets or sets an array of textures to use

View File

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TransportGame.Primitives;
namespace TransportGame.Model
{

View File

@ -3,17 +3,16 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using TransportGame.Business;
using TransportGame.Primitives;
using TransportGame.Utils;
namespace TransportGame.Model
{
public class BuildingLot : IPositionable
/// <summary>
/// Building lot
/// </summary>
public class BuildingLot : Polygon
{
/// <summary>
/// Gets or sets the list of points
/// </summary>
public Vector2[] Points { get; set; }
/// <summary>
/// Gets or sets the size of the lot
/// </summary>
@ -23,8 +22,8 @@ namespace TransportGame.Model
/// Initializes the building lot
/// </summary>
public BuildingLot()
: base(new Vector2[4])
{
Points = new Vector2[4];
}
/// <summary>
@ -32,8 +31,8 @@ namespace TransportGame.Model
/// </summary>
/// <param name="size">size</param>
public BuildingLot(float size)
: base(new Vector2[4])
{
Points = new Vector2[4];
Size = size;
}
@ -43,8 +42,8 @@ namespace TransportGame.Model
/// <param name="size">Size</param>
/// <param name="points">Points</param>
public BuildingLot(float size, params Vector2[] points)
: base(points)
{
Points = points;
Size = size;
}
@ -54,30 +53,11 @@ namespace TransportGame.Model
/// <param name="size">Size</param>
/// <param name="points">Points</param>
public BuildingLot(float size, IEnumerable<Vector2> points)
: base(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; }
}
/// <summary>
/// Tests if two building lots intersect
/// </summary>
/// <param name="a">First lot</param>
/// <param name="b">Second lot</param>
/// <returns></returns>
public static bool DoesIntersect(BuildingLot a, BuildingLot b)
{
return Algorithmss.DoPolygonsIntersect(a.Points, b.Points);
}
/// <summary>
/// Tests if a building lot intersects a line segment (such as a road segment)
/// </summary>

View File

@ -4,8 +4,8 @@ using System.Linq;
using System.Text;
using System.Xml.Serialization;
using TransportGame.Model.Road;
using TransportGame.Primitives;
using TransportGame.Utils;
using UnityEngine;
namespace TransportGame.Model
{
@ -256,8 +256,8 @@ namespace TransportGame.Model
if (dist < PopulationCenterRange * PopulationCenterRange)
{
float influence = 1 - (float)dist / (float)(PopulationCenterRange * PopulationCenterRange);
influence = Mathf.Pow(influence, 6) * 0.7f; // Ease
value = Mathf.Clamp01(value + influence);
influence = (float)Math.Pow(influence, 6) * 0.7f; // Ease
value = MathHelper.Clamp01(value + influence);
}
}

View File

@ -1,12 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TransportGame.Model
{
public interface IPositionable
{
Vector2 Position { get; }
}
}

View File

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

View File

@ -1,108 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TransportGame.Model
{
public struct LineSegment
{
public float X0 { get; private set; }
public float Y0 { get; private set; }
public float X1 { get; private set; }
public float Y1 { get; private set; }
public Vector2 P0
{
get
{
return new Vector2(X0, Y0);
}
}
public Vector2 P1
{
get
{
return new Vector2(X1, Y1);
}
}
public float Length
{
get
{
return (P1 - P0).Length;
}
}
public float LengthSq
{
get
{
return (P1 - P0).LengthSq;
}
}
public Vector2 Direction
{
get
{
return (P1 - P0).Normalized;
}
}
public LineSegment(Vector2 p0, Vector2 p1)
: this()
{
X0 = p0.X; Y0 = p0.Y;
X1 = p1.X; Y1 = p1.Y;
}
public LineSegment(float x0, float y0, float x1, float y1)
: this()
{
X0 = x0; Y0 = y0;
X1 = x1; Y1 = y1;
}
public static Vector2? Intersect(LineSegment a, LineSegment b)
{
float s1x = a.X1 - a.X0, s1y = a.Y1 - a.Y0;
float s2x = b.X1 - b.X0, s2y = b.Y1 - b.Y0;
float det = (-s2x * s1y + s1x * s2y);
// Avoid division by zero
// Note: this is an edge case, the vectors might be parallel or colliniar
if (det == 0) return null;
float s = (-s1y * (a.X0 - b.X0) + s1x * (a.Y0 - b.Y0)) / det;
float t = (s2x * (a.Y0 - b.Y0) - s2y * (a.X0 - b.X0)) / det;
// Collision detected
if (s >= 0 && s <= 1 && t >= 0 && t <= 1)
return new Vector2(a.X0 + t * s1x, a.Y0 + t * s1y);
// No collision
return null;
}
/// <summary>
/// Calculates the distance from point p to line segment
/// </summary>
/// <param name="line">Line</param>
/// <param name="p">Point</param>
/// <returns>Distance</returns>
public static float Distance(LineSegment line, Vector2 p)
{
float det = (line.Y1 - line.Y0) * p.X - (line.X1 - line.X0) * p.Y
+ line.X1 * line.Y0 - line.Y1 * line.X0;
return Math.Abs(det) / line.Length;
}
public override string ToString()
{
return string.Format("({0}, {1})->({2}, {3})", X0, Y0, X1, Y1);
}
}
}

View File

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

View File

@ -1,247 +0,0 @@
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

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

View File

@ -1,34 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
namespace TransportGame.Model
{
public class Range
{
[XmlAttribute("min")]
public float Minimum { get; set; }
[XmlAttribute("max")]
public float Maximum { get; set; }
public Range()
{
Minimum = 0;
Maximum = 1;
}
public Range(float min, float max)
{
Minimum = min;
Maximum = max;
}
public override string ToString()
{
return String.Format("[{0}, {1}]", Minimum, Maximum);
}
}
}

View File

@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: b436281f9c7d49f4d935ae009d4559a8
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@ -1,77 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TransportGame.Model
{
public struct Rectangle
{
public float Left { get; set; }
public float Top { get; set; }
public float Right { get; set; }
public float Bottom { get; set; }
public Rectangle(float left, float top, float right, float bottom)
: this()
{
Left = left;
Top = top;
Right = right;
Bottom = bottom;
if (left > right)
throw new ArgumentException("Left must be smaller than right.");
if (top > bottom)
throw new ArgumentException("Top must be smaller than bottom.");
}
public float Width
{
get
{
return Right - Left;
}
set
{
Right = Left + value;
}
}
public float Height
{
get
{
return Bottom - Top;
}
set
{
Bottom = Top + value;
}
}
public bool Contains(float x, float y)
{
return x >= Left && x <= Right && y >= Top && y <= Bottom;
}
public bool Contains(Vector2 p)
{
return Contains(p.X, p.Y);
}
public static bool Intersects (Rectangle a, Rectangle b)
{
return !(b.Left > a.Right ||
b.Right < a.Left ||
b.Top > a.Bottom ||
b.Bottom < a.Top);
}
public override string ToString()
{
return string.Format("({0}, {1}, {2}, {3})", Left, Top, Right, Bottom);
}
}
}

View File

@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: 01c02a9fd2c3d0142905c23fb3142b6f
timeCreated: 1432824087
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 System.Xml.Serialization;
using TransportGame.Primitives;
using TransportGame.Utils;
namespace TransportGame.Model.Road

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using TransportGame.Primitives;
namespace TransportGame.Model.Road
{

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using TransportGame.Primitives;
namespace TransportGame.Model.Road
{

View File

@ -1,344 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
namespace TransportGame.Model
{
public struct Vector2
{
/// <summary>
/// Zero vector
/// </summary>
public static readonly Vector2 Zero = new Vector2(0, 0);
/// <summary>
/// Unit vector
/// </summary>
public static readonly Vector2 Unit = new Vector2(1, 0);
/// <summary>
/// Gets the X component
/// </summary>
[XmlAttribute("x")]
public float X { get; set; }
/// <summary>
/// Gets the Y component
/// </summary>
[XmlAttribute("y")]
public float Y { get; set; }
/// <summary>
/// Initializes a vector2
/// </summary>
/// <param name="x">X component</param>
/// <param name="y">Y component</param>
public Vector2(float x, float y)
: this()
{
X = x;
Y = y;
}
/// <summary>
/// Gets the length of the vector
/// </summary>
public float Length
{
get
{
return (float)Math.Sqrt(LengthSq);
}
}
/// <summary>
/// Gets the length of the vector squared
/// </summary>
public float LengthSq
{
get
{
return X * X + Y * Y;
}
}
/// <summary>
/// Gets the normalized vector
/// </summary>
/// <returns>Normalized vector</returns>
public Vector2 Normalized
{
get
{
float len = Length;
return new Vector2(X / len, Y / len);
}
}
/// <summary>
/// Gets the normalized vector raised to second power
/// </summary>
/// <remarks>
/// This is less computationally expensive (no need to calculate square root).
/// </remarks>
/// <returns>Normalized vector</returns>
public Vector2 NormalizedSq
{
get
{
float len2 = LengthSq;
return new Vector2(X * X / len2, Y * Y / len2);
}
}
/// <summary>
/// Rotates vector by given number of radians
/// </summary>
/// <param name="radians"></param>
/// <returns></returns>
public Vector2 Rotate(float radians)
{
float sin = (float)Math.Sin(radians);
float cos = (float)Math.Cos(radians);
return new Vector2(X * cos - Y * sin, X * sin + Y * cos);
}
/// <summary>
/// Rotates vector by given number of degrees
/// </summary>
/// <param name="degrees"></param>
/// <returns></returns>
public Vector2 RotateDeg(float degrees)
{
return Rotate(degrees * (float)Math.PI / 180f);
}
/// <summary>
/// Sum operator
/// </summary>
/// <param name="a">First vector</param>
/// <param name="b">Second vector</param>
/// <returns>Result of addition</returns>
public static Vector2 operator +(Vector2 a, Vector2 b)
{
return new Vector2(a.X + b.X, a.Y + b.Y);
}
/// <summary>
/// Subtract operator
/// </summary>
/// <param name="a">First vector</param>
/// <param name="b">Second vector</param>
/// <returns>Result of subtraction</returns>
public static Vector2 operator -(Vector2 a, Vector2 b)
{
return new Vector2(a.X - b.X, a.Y - b.Y);
}
/// <summary>
/// Negation operator
/// </summary>
/// <param name="a">Vector</param>
/// <returns>Negated vector</returns>
public static Vector2 operator -(Vector2 a)
{
return new Vector2(-a.X, -a.Y);
}
/// <summary>
/// Multiply by constant
/// </summary>
/// <param name="a">Vector</param>
/// <param name="c">Constant</param>
/// <returns>Result</returns>
public static Vector2 operator *(Vector2 a, float c)
{
return new Vector2(a.X * c, a.Y * c);
}
/// <summary>
/// Multiply by constant
/// </summary>
/// <param name="c">Constant</param>
/// <param name="a">Vector</param>
/// <returns>Result</returns>
public static Vector2 operator *(float c, Vector2 a)
{
return new Vector2(a.X * c, a.Y * c);
}
/// <summary>
/// Divide by constant
/// </summary>
/// <param name="a">Vector</param>
/// <param name="c">Constant</param>
/// <returns>Result</returns>
public static Vector2 operator /(Vector2 a, float c)
{
return new Vector2(a.X / c, a.Y / c);
}
/// <summary>
/// Equality operator
/// </summary>
/// <param name="a">First vector</param>
/// <param name="b">Second vector</param>
/// <returns>True if vectors are equal</returns>
public static bool operator ==(Vector2 a, Vector2 b)
{
return a.X == b.X && a.Y == b.Y;
}
/// <summary>
/// Inequality operator
/// </summary>
/// <param name="a">First vector</param>
/// <param name="b">Second vector</param>
/// <returns>True if vectors are not equal</returns>
public static bool operator !=(Vector2 a, Vector2 b)
{
return a.X != b.X || a.Y != b.Y;
}
/// <summary>
/// Calculates dot product of two vectors
/// </summary>
/// <param name="a">First vector</param>
/// <param name="b">Second vector</param>
/// <returns>Dot product</returns>
public static float Dot(Vector2 a, Vector2 b)
{
return a.X * b.X + a.Y * b.Y;
}
/// <summary>
/// Returns the magnitude of the cross product between the two vectors (z considered 0)
/// </summary>
/// <param name="a">First vector</param>
/// <param name="b">Second vector</param>
/// <returns>Magnitude of cross product</returns>
public static float Cross(Vector2 a, Vector2 b)
{
return (a.X * b.Y) - (a.Y * b.X);
}
/// <summary>
/// Tests if two vectors are colliniar
/// </summary>
/// <param name="a">a</param>
/// <param name="b">b</param>
/// <returns>True if vectors are colliniar</returns>
public static bool AreColliniar(Vector2 a, Vector2 b)
{
return Math.Abs(Cross(a, b)) < 1e-12;
}
/// <summary>
/// Gets the vector corresponding with specified angle (in radians)
/// </summary>
/// <param name="rads">Radians</param>
/// <returns>Vector</returns>
public static Vector2 FromRadians(float rads)
{
return new Vector2((float)Math.Cos(rads), (float)Math.Sin(rads));
}
/// <summary>
/// Gets the vector corresponding with specified angle (in degrees)
/// </summary>
/// <param name="degs">Degrees</param>
/// <returns>Vector</returns>
public static Vector2 FromDegrees(float degs)
{
float rads = (degs * (float)Math.PI / 180f);
return FromRadians(rads);
}
public override string ToString()
{
return String.Format("({0}, {1})", X, Y);
}
public override bool Equals(object obj)
{
if (obj is Vector2)
{
Vector2 other = (Vector2)obj;
return X == other.X && Y == other.Y;
}
return false;
}
public override int GetHashCode()
{
return X.GetHashCode() * 7 + Y.GetHashCode();
}
private class LengthComparerImpl : IComparer<Vector2>
{
public int Compare(Vector2 a, Vector2 b)
{
if (a.LengthSq > b.LengthSq)
return 1;
if (a.LengthSq < b.LengthSq)
return -1;
return 0;
}
}
private class TrigonometricComparerImpl : IComparer<Vector2>
{
private int Quad(Vector2 v)
{
if (v.Y >= 0)
{
if (v.X >= 0)
return 0;
return 1;
}
else
{
if (v.X < 0)
return 2;
return 3;
}
}
public int Compare(Vector2 a, Vector2 b)
{
// If vectors are in different quadrants, we can use quadrant number
int qa = Quad(a), qb = Quad(b);
if (qa != qb)
{
return qa - qb;
}
// In same quadrant. Compute cross product which gives us sin(ab)*len(a)*len(b)
// Vectors are in same quadrant, so angle should be less than 90deg
float cross = Cross(a, b);
if (cross < 0) // Angle > 180 degrees => a > b
return 1;
if (cross > 0) // Angle < 180 degrees => a < b
return -1;
// Points are on the same line. Use distance
if (a.LengthSq > b.LengthSq)
return 1;
else if (a.LengthSq < b.LengthSq)
return -1;
// Points are equal
return 0;
}
}
public static IComparer<Vector2> LengthComparer = new LengthComparerImpl();
public static IComparer<Vector2> TrigonomicComparer = new TrigonometricComparerImpl();
}
}

View File

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