optimize polygon equality
							parent
							
								
									097790a41f
								
							
						
					
					
						commit
						2dca5f716c
					
				|  | @ -1,5 +1,4 @@ | ||||||
| using System.Linq; | using System; | ||||||
| using System; |  | ||||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||||
| using System.Collections.Immutable; | using System.Collections.Immutable; | ||||||
| using System.Numerics; | using System.Numerics; | ||||||
|  | @ -9,34 +8,32 @@ namespace MoonTools.Core.Bonk | ||||||
| { | { | ||||||
|     /// <summary> |     /// <summary> | ||||||
|     /// A Shape defined by an arbitrary collection of vertices. |     /// A Shape defined by an arbitrary collection of vertices. | ||||||
|     /// NOTE: A Polygon must have more than 2 vertices, be convex, and should not have duplicate vertices. |     /// NOTE: A Polygon must be defined in clockwise order, have more than 2 vertices, be convex, and have no duplicate vertices. | ||||||
|     /// </summary> |     /// </summary> | ||||||
|     public struct Polygon : IShape2D, IEquatable<Polygon> |     public struct Polygon : IShape2D, IEquatable<Polygon> | ||||||
|     { |     { | ||||||
|         private ImmutableArray<Position2D> _vertices; |         public ImmutableArray<Position2D> Vertices { get; private set; } | ||||||
|         public AABB AABB { get; } |         public AABB AABB { get; } | ||||||
| 
 | 
 | ||||||
|         public IEnumerable<Position2D> Vertices { get { return _vertices; } } |         public int VertexCount { get { return Vertices.Length; } } | ||||||
| 
 |  | ||||||
|         public int VertexCount { get { return _vertices.Length; } } |  | ||||||
| 
 | 
 | ||||||
|         // vertices are local to the origin |         // vertices are local to the origin | ||||||
|         public Polygon(IEnumerable<Position2D> vertices) |         public Polygon(IEnumerable<Position2D> vertices) | ||||||
|         { |         { | ||||||
|             _vertices = vertices.ToImmutableArray(); |             Vertices = vertices.ToImmutableArray(); | ||||||
|             AABB = AABB.FromVertices(vertices); |             AABB = AABB.FromVertices(vertices); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public Polygon(ImmutableArray<Position2D> vertices) |         public Polygon(ImmutableArray<Position2D> vertices) | ||||||
|         { |         { | ||||||
|             _vertices = vertices; |             Vertices = vertices; | ||||||
|             AABB = AABB.FromVertices(vertices); |             AABB = AABB.FromVertices(vertices); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public Vector2 Support(Vector2 direction, Transform2D transform) |         public Vector2 Support(Vector2 direction, Transform2D transform) | ||||||
|         { |         { | ||||||
|             var maxDotProduct = float.NegativeInfinity; |             var maxDotProduct = float.NegativeInfinity; | ||||||
|             var maxVertex = _vertices[0].ToVector2(); |             var maxVertex = Vertices[0].ToVector2(); | ||||||
|             foreach (var vertex in Vertices) |             foreach (var vertex in Vertices) | ||||||
|             { |             { | ||||||
|                 var transformed = Vector2.Transform(vertex, transform.TransformMatrix); |                 var transformed = Vector2.Transform(vertex, transform.TransformMatrix); | ||||||
|  | @ -67,11 +64,22 @@ namespace MoonTools.Core.Bonk | ||||||
| 
 | 
 | ||||||
|         public bool Equals(Polygon other) |         public bool Equals(Polygon other) | ||||||
|         { |         { | ||||||
|             var q = from a in _vertices |             if (VertexCount != other.VertexCount) { return false; } | ||||||
|                     join b in other.Vertices on a equals b |  | ||||||
|                     select a; |  | ||||||
| 
 | 
 | ||||||
|             return _vertices.Length == other.VertexCount && q.Count() == _vertices.Length; |             int? offset = null; | ||||||
|  |             for (var i = 0; i < VertexCount; i++) | ||||||
|  |             { | ||||||
|  |                 if (Vertices[0] == other.Vertices[i]) { offset = i; break; } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if (!offset.HasValue) { return false; } | ||||||
|  | 
 | ||||||
|  |             for (var i = 0; i < VertexCount; i++) | ||||||
|  |             { | ||||||
|  |                 if (Vertices[i] != other.Vertices[(i + offset.Value) % VertexCount]) { return false; } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             return true; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public bool Equals(Rectangle rectangle) |         public bool Equals(Rectangle rectangle) | ||||||
|  |  | ||||||
|  | @ -10,51 +10,66 @@ namespace MoonTools.Core.Bonk | ||||||
|     /// </summary> |     /// </summary> | ||||||
|     public struct Rectangle : IShape2D, IEquatable<Rectangle> |     public struct Rectangle : IShape2D, IEquatable<Rectangle> | ||||||
|     { |     { | ||||||
|         public int MinX { get; } |         /// <summary> | ||||||
|         public int MinY { get; } |         /// The minimum position of the rectangle. Note that we assume y-down coordinates. | ||||||
|         public int MaxX { get; } |         /// </summary> | ||||||
|         public int MaxY { get; } |         /// <value></value> | ||||||
| 
 |         public Position2D Min { get; } | ||||||
|  |         /// <summary> | ||||||
|  |         /// The maximum position of the rectangle. Note that we assume y-down coordinates. | ||||||
|  |         /// </summary> | ||||||
|  |         /// <value></value> | ||||||
|  |         public Position2D Max { get; } | ||||||
|         public AABB AABB { get; } |         public AABB AABB { get; } | ||||||
| 
 | 
 | ||||||
|  |         public int Left { get { return Min.X; } } | ||||||
|  |         public int Right { get { return Max.X; } } | ||||||
|  |         public int Top { get { return Min.Y; } } | ||||||
|  |         public int Bottom { get { return Max.Y; } } | ||||||
|  | 
 | ||||||
|  |         public int Width { get; } | ||||||
|  |         public int Height { get; } | ||||||
|  | 
 | ||||||
|  |         public Position2D TopRight { get { return new Position2D(Right, Top); } } | ||||||
|  |         public Position2D BottomLeft { get { return new Position2D(Left, Bottom); } } | ||||||
|  | 
 | ||||||
|         public IEnumerable<Position2D> Vertices |         public IEnumerable<Position2D> Vertices | ||||||
|         { |         { | ||||||
|             get |             get | ||||||
|             { |             { | ||||||
|                 yield return new Position2D(MinX, MinY); |                 yield return new Position2D(Min.X, Min.Y); | ||||||
|                 yield return new Position2D(MinX, MaxY); |                 yield return new Position2D(Min.X, Max.Y); | ||||||
|                 yield return new Position2D(MaxX, MinY); |                 yield return new Position2D(Max.X, Min.Y); | ||||||
|                 yield return new Position2D(MaxX, MaxY); |                 yield return new Position2D(Max.X, Max.Y); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public Rectangle(int minX, int minY, int maxX, int maxY) |         public Rectangle(int minX, int minY, int maxX, int maxY) | ||||||
|         { |         { | ||||||
|             MinX = minX; |             Min = new Position2D(minX, minY); | ||||||
|             MinY = minY; |             Max = new Position2D(maxX, maxY); | ||||||
|             MaxX = maxX; |  | ||||||
|             MaxY = maxY; |  | ||||||
| 
 |  | ||||||
|             AABB = new AABB(minX, minY, maxX, maxY); |             AABB = new AABB(minX, minY, maxX, maxY); | ||||||
|  |             Width = Max.X - Min.X; | ||||||
|  |             Height = Max.Y - Min.Y; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         private Vector2 Support(Vector2 direction) |         private Vector2 Support(Vector2 direction) | ||||||
|         { |         { | ||||||
|             if (direction.X >= 0 && direction.Y >= 0) |             if (direction.X >= 0 && direction.Y >= 0) | ||||||
|             { |             { | ||||||
|                 return new Vector2(MaxX, MaxY); |                 return Max; | ||||||
|             } |             } | ||||||
|             else if (direction.X >= 0 && direction.Y < 0) |             else if (direction.X >= 0 && direction.Y < 0) | ||||||
|             { |             { | ||||||
|                 return new Vector2(MaxX, MinY); |                 return new Vector2(Max.X, Min.Y); | ||||||
|             } |             } | ||||||
|             else if (direction.X < 0 && direction.Y >= 0) |             else if (direction.X < 0 && direction.Y >= 0) | ||||||
|             { |             { | ||||||
|                 return new Vector2(MinX, MaxY); |                 return new Vector2(Min.X, Max.Y); | ||||||
|             } |             } | ||||||
|             else if (direction.X < 0 && direction.Y < 0) |             else if (direction.X < 0 && direction.Y < 0) | ||||||
|             { |             { | ||||||
|                 return new Vector2(MinX, MinY); |                 return new Vector2(Min.X, Min.Y); | ||||||
|             } |             } | ||||||
|             else |             else | ||||||
|             { |             { | ||||||
|  | @ -87,10 +102,7 @@ namespace MoonTools.Core.Bonk | ||||||
| 
 | 
 | ||||||
|         public bool Equals(Rectangle other) |         public bool Equals(Rectangle other) | ||||||
|         { |         { | ||||||
|             return MinX == other.MinX && |             return Min == other.Min && Max == other.Max; | ||||||
|                 MinY == other.MinY && |  | ||||||
|                 MaxX == other.MaxX && |  | ||||||
|                 MaxY == other.MaxY; |  | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public bool Equals(Polygon other) |         public bool Equals(Polygon other) | ||||||
|  | @ -100,7 +112,7 @@ namespace MoonTools.Core.Bonk | ||||||
| 
 | 
 | ||||||
|         public override int GetHashCode() |         public override int GetHashCode() | ||||||
|         { |         { | ||||||
|             return HashCode.Combine(MinX, MinY, MaxX, MaxY); |             return HashCode.Combine(Min, Max); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public static bool operator ==(Rectangle a, Rectangle b) |         public static bool operator ==(Rectangle a, Rectangle b) | ||||||
|  | @ -112,5 +124,15 @@ namespace MoonTools.Core.Bonk | ||||||
|         { |         { | ||||||
|             return !(a == b); |             return !(a == b); | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|  |         public static bool operator ==(Rectangle a, Polygon b) | ||||||
|  |         { | ||||||
|  |             return a.Equals(b); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public static bool operator !=(Rectangle a, Polygon b) | ||||||
|  |         { | ||||||
|  |             return !(a == b); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| using System.Linq; | using MoonTools.Core.Structs; | ||||||
| 
 | 
 | ||||||
| namespace MoonTools.Core.Bonk | namespace MoonTools.Core.Bonk | ||||||
| { | { | ||||||
|  | @ -6,11 +6,20 @@ namespace MoonTools.Core.Bonk | ||||||
|     { |     { | ||||||
|         public static bool Equals(Polygon polygon, Rectangle rectangle) |         public static bool Equals(Polygon polygon, Rectangle rectangle) | ||||||
|         { |         { | ||||||
|             var q = from a in polygon.Vertices |             if (polygon.VertexCount != 4) { return false; } | ||||||
|                     join b in rectangle.Vertices on a equals b |  | ||||||
|                     select a; |  | ||||||
| 
 | 
 | ||||||
|             return polygon.VertexCount == 4 && q.Count() == 4; |             int? minIndex = null; | ||||||
|  |             for (var i = 0; i < 4; i++) | ||||||
|  |             { | ||||||
|  |                 if (polygon.Vertices[i] == rectangle.Min) { minIndex = i; break; } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if (!minIndex.HasValue) { return false; } | ||||||
|  | 
 | ||||||
|  |             return | ||||||
|  |                 polygon.Vertices[(minIndex.Value + 1) % 4] == rectangle.TopRight && | ||||||
|  |                 polygon.Vertices[(minIndex.Value + 2) % 4] == rectangle.Max && | ||||||
|  |                 polygon.Vertices[(minIndex.Value + 3) % 4] == rectangle.BottomLeft; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -288,45 +288,48 @@ namespace Tests | ||||||
|             public void PolygonRectangleEqual() |             public void PolygonRectangleEqual() | ||||||
|             { |             { | ||||||
|                 var a = new Polygon(ImmutableArray.Create( |                 var a = new Polygon(ImmutableArray.Create( | ||||||
|                     new Position2D(1, 1), |  | ||||||
|                     new Position2D(1, -1), |  | ||||||
|                     new Position2D(-1, -1), |                     new Position2D(-1, -1), | ||||||
|  |                     new Position2D(1, -1), | ||||||
|  |                     new Position2D(1, 1), | ||||||
|                     new Position2D(-1, 1) |                     new Position2D(-1, 1) | ||||||
|                 )); |                 )); | ||||||
| 
 | 
 | ||||||
|                 var b = new Rectangle(-1, -1, 1, 1); |                 var b = new Rectangle(-1, -1, 1, 1); | ||||||
| 
 | 
 | ||||||
|                 a.Equals(b).Should().BeTrue(); |                 a.Equals(b).Should().BeTrue(); | ||||||
|  |                 b.Equals(a).Should().BeTrue(); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             [Test] |             [Test] | ||||||
|             public void PolygonRectangleNotEqual() |             public void PolygonRectangleNotEqual() | ||||||
|             { |             { | ||||||
|                 var a = new Polygon(ImmutableArray.Create( |                 var a = new Polygon(ImmutableArray.Create( | ||||||
|                     new Position2D(2, 1), |                     new Position2D(-2, -1), | ||||||
|                     new Position2D(1, -1), |                     new Position2D(1, -1), | ||||||
|                     new Position2D(-1, -1), |                     new Position2D(1, 1), | ||||||
|                     new Position2D(-2, 1) |                     new Position2D(-2, 1) | ||||||
|                 )); |                 )); | ||||||
| 
 | 
 | ||||||
|                 var b = new Rectangle(-1, -1, 1, 1); |                 var b = new Rectangle(-1, -1, 1, 1); | ||||||
| 
 | 
 | ||||||
|                 a.Equals(b).Should().BeFalse(); |                 a.Equals(b).Should().BeFalse(); | ||||||
|  |                 b.Equals(a).Should().BeFalse(); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             [Test] |             [Test] | ||||||
|             public void PolygonRectangleEqualOperator() |             public void PolygonRectangleEqualOperator() | ||||||
|             { |             { | ||||||
|                 var a = new Polygon(ImmutableArray.Create( |                 var a = new Polygon(ImmutableArray.Create( | ||||||
|                     new Position2D(1, 1), |  | ||||||
|                     new Position2D(1, -1), |  | ||||||
|                     new Position2D(-1, -1), |                     new Position2D(-1, -1), | ||||||
|  |                     new Position2D(1, -1), | ||||||
|  |                     new Position2D(1, 1), | ||||||
|                     new Position2D(-1, 1) |                     new Position2D(-1, 1) | ||||||
|                 )); |                 )); | ||||||
| 
 | 
 | ||||||
|                 var b = new Rectangle(-1, -1, 1, 1); |                 var b = new Rectangle(-1, -1, 1, 1); | ||||||
| 
 | 
 | ||||||
|                 (a == b).Should().BeTrue(); |                 (a == b).Should().BeTrue(); | ||||||
|  |                 (b == a).Should().BeTrue(); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             [Test] |             [Test] | ||||||
|  | @ -342,6 +345,7 @@ namespace Tests | ||||||
|                 var b = new Rectangle(-1, -1, 1, 1); |                 var b = new Rectangle(-1, -1, 1, 1); | ||||||
| 
 | 
 | ||||||
|                 (a != b).Should().BeTrue(); |                 (a != b).Should().BeTrue(); | ||||||
|  |                 (b != a).Should().BeTrue(); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue