// ReSharper disable MemberCanBePrivate.Global // ReSharper disable UnusedMember.Global using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using RGB.NET.Core.Extensions; using RGB.NET.Core.MVVM; namespace RGB.NET.Core { /// /// Represents a rectangle defined by it's position and it's size. /// [DebuggerDisplay("[Location: {Location}, Size: {Size}]")] public class Rectangle : AbstractBindable { #region Properties & Fields private Point _location; /// /// Gets or sets the representing the top-left corner of the . /// public Point Location { get { return _location; } set { if (SetProperty(ref _location, value)) // ReSharper disable once ExplicitCallerInfoArgument OnPropertyChanged(nameof(Center)); } } private Size _size; /// /// Gets or sets the of the . /// public Size Size { get { return _size; } set { if (SetProperty(ref _size, value)) // ReSharper disable once ExplicitCallerInfoArgument OnPropertyChanged(nameof(Center)); } } /// /// Gets a new representing the center-point of the . /// public Point Center => new Point(Location.X + (Size.Width / 2.0), Location.Y + (Size.Height / 2.0)); /// /// Gets a bool indicating if both, the width and the height of the rectangle is greater than zero. /// public bool IsEmpty => (Size.Width > DoubleExtensions.TOLERANCE) && (Size.Height > DoubleExtensions.TOLERANCE); #endregion #region Constructors /// /// Initializes a new instance of the class. /// public Rectangle() : this(new Point(), new Size()) { } /// /// Initializes a new instance of the class using the provided values for ans . /// /// The -position of this . /// The -position of this . /// The of this . /// The of this . public Rectangle(double x, double y, double width, double height) : this(new Point(x, y), new Size(width, height)) { } /// /// Initializes a new instance of the class using the given and . /// /// /// public Rectangle(Point location, Size size) { this.Location = location; this.Size = size; } /// /// Initializes a new instance of the class using the given array of . /// The and is calculated to completely contain all rectangles provided as parameters. /// /// The array of used to calculate the and public Rectangle(params Rectangle[] rectangles) : this(rectangles.AsEnumerable()) { } /// /// Initializes a new instance of the class using the given list of . /// The and is calculated to completely contain all rectangles provided as parameters. /// /// The list of used to calculate the and public Rectangle(IEnumerable rectangles) { double posX = double.MaxValue; double posY = double.MaxValue; double posX2 = double.MinValue; double posY2 = double.MinValue; foreach (Rectangle rectangle in rectangles) { posX = Math.Min(posX, rectangle.Location.X); posY = Math.Min(posY, rectangle.Location.Y); posX2 = Math.Max(posX2, rectangle.Location.X + rectangle.Size.Width); posY2 = Math.Max(posY2, rectangle.Location.Y + rectangle.Size.Height); } InitializeFromPoints(new Point(posX, posY), new Point(posX2, posY2)); } /// /// Initializes a new instance of the class using the given array of . /// The and is calculated to contain all points provided as parameters. /// /// The array of used to calculate the and public Rectangle(params Point[] points) : this(points.AsEnumerable()) { } /// /// Initializes a new instance of the class using the given list of . /// The and is calculated to contain all points provided as parameters. /// /// The list of used to calculate the and public Rectangle(IEnumerable points) : this() { double posX = double.MaxValue; double posY = double.MaxValue; double posX2 = double.MinValue; double posY2 = double.MinValue; foreach (Point point in points) { posX = Math.Min(posX, point.X); posY = Math.Min(posY, point.Y); posX2 = Math.Max(posX2, point.X); posY2 = Math.Max(posY2, point.Y); } InitializeFromPoints(new Point(posX, posY), new Point(posX2, posY2)); } #endregion #region Methods private void InitializeFromPoints(Point point1, Point point2) { double posX = Math.Min(point1.X, point2.X); double posY = Math.Min(point1.Y, point2.Y); double width = Math.Max(point1.X, point2.X) - posX; double height = Math.Max(point1.Y, point2.Y) - posY; Location = new Point(posX, posY); Size = new Size(width, height); } /// /// Calculates the percentage of intersection of a rectangle. /// /// The intersecting rectangle. /// The percentage of intersection. public double CalculateIntersectPercentage(Rectangle intersectingRect) { if (IsEmpty || intersectingRect.IsEmpty) return 0; Rectangle intersection = CalculateIntersection(intersectingRect); return intersection.IsEmpty ? 0 : (intersection.Size.Width * intersection.Size.Height) / (Size.Width * Size.Height); } /// /// Calculates the representing the intersection of this and the one provided as parameter. /// /// The intersecting /// A new representing the intersection this and the one provided as parameter. public Rectangle CalculateIntersection(Rectangle intersectingRectangle) { double x1 = Math.Max(Location.X, intersectingRectangle.Location.X); double x2 = Math.Min(Location.X + Size.Width, intersectingRectangle.Location.X + intersectingRectangle.Size.Width); double y1 = Math.Max(Location.Y, intersectingRectangle.Location.Y); double y2 = Math.Min(Location.Y + Size.Height, intersectingRectangle.Location.Y + intersectingRectangle.Size.Height); if ((x2 >= x1) && (y2 >= y1)) return new Rectangle(x1, y1, x2 - x1, y2 - y1); return new Rectangle(); } #endregion } }