forked from MoonsideGames/MoonTools.Bonk
				
			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