diff --git a/RGB.NET.Core/Devices/AbstractRGBDevice.cs b/RGB.NET.Core/Devices/AbstractRGBDevice.cs index 90c97e1..59d0eae 100644 --- a/RGB.NET.Core/Devices/AbstractRGBDevice.cs +++ b/RGB.NET.Core/Devices/AbstractRGBDevice.cs @@ -175,9 +175,7 @@ namespace RGB.NET.Core if (led != null) { - led.LedRectangle.Location = new Point(layoutLed.X, layoutLed.Y); - led.LedRectangle.Size = new Size(layoutLed.Width, layoutLed.Height); - + led.LedRectangle = new Rectangle(new Point(layoutLed.X, layoutLed.Y), new Size(layoutLed.Width, layoutLed.Height)); led.Shape = layoutLed.Shape; led.ShapeData = layoutLed.ShapeData; diff --git a/RGB.NET.Core/Extensions/RectangleExtensions.cs b/RGB.NET.Core/Extensions/RectangleExtensions.cs new file mode 100644 index 0000000..7d2f85a --- /dev/null +++ b/RGB.NET.Core/Extensions/RectangleExtensions.cs @@ -0,0 +1,115 @@ +using System; + +namespace RGB.NET.Core +{ + public static class RectangleExtensions + { + #region Methods + + /// + /// Sets the of the given rectangle. + /// + /// The rectangle to modify. + /// The new location of the rectangle. + /// The modified . + public static Rectangle SetLocation(this Rectangle rect, Point location) => new Rectangle(location, rect.Size); + + /// + /// Sets the of the of the given rectangle. + /// + /// The rectangle to modify. + /// The new x-location of the rectangle. + /// The modified . + public static Rectangle SetX(this Rectangle rect, double x) => new Rectangle(new Point(x, rect.Location.Y), rect.Size); + + /// + /// Sets the of the of the given rectangle. + /// + /// The rectangle to modify. + /// The new y-location of the rectangle. + /// The modified . + public static Rectangle SetY(this Rectangle rect, double y) => new Rectangle(new Point(rect.Location.X, y), rect.Size); + + /// + /// Sets the of the given rectangle. + /// + /// The rectangle to modify. + /// The new size of the rectangle. + /// The modified . + public static Rectangle SetSize(this Rectangle rect, Size size) => new Rectangle(rect.Location, size); + + /// + /// Sets the of the of the given rectangle. + /// + /// The rectangle to modify. + /// The new width of the rectangle. + /// The modified . + public static Rectangle SetWidth(this Rectangle rect, double width) => new Rectangle(rect.Location, new Size(width, rect.Size.Height)); + + /// + /// Sets the of the of the given rectangle. + /// + /// The rectangle to modify. + /// The new height of the rectangle. + /// The modified . + public static Rectangle SetHeight(this Rectangle rect, double height) => new Rectangle(rect.Location, new Size(rect.Size.Width, height)); + + /// + /// Calculates the percentage of intersection of a rectangle. + /// + /// The intersecting rectangle. + /// The percentage of intersection. + public static double CalculateIntersectPercentage(this Rectangle rect, Rectangle intersectingRect) + { + if (rect.IsEmpty || intersectingRect.IsEmpty) return 0; + + Rectangle intersection = rect.CalculateIntersection(intersectingRect); + return (intersection.Size.Width * intersection.Size.Height) / (rect.Size.Width * rect.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 static Rectangle CalculateIntersection(this Rectangle rect, Rectangle intersectingRectangle) + { + double x1 = Math.Max(rect.Location.X, intersectingRectangle.Location.X); + double x2 = Math.Min(rect.Location.X + rect.Size.Width, intersectingRectangle.Location.X + intersectingRectangle.Size.Width); + + double y1 = Math.Max(rect.Location.Y, intersectingRectangle.Location.Y); + double y2 = Math.Min(rect.Location.Y + rect.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(); + } + + /// + /// Determines if the specified is contained within this . + /// + /// The to test. + /// + public static bool Contains(this Rectangle rect, Point point) => rect.Contains(point.X, point.Y); + + /// + /// Determines if the specified location is contained within this . + /// + /// The X-location to test. + /// The Y-location to test. + /// + public static bool Contains(this Rectangle rect, double x, double y) => (rect.Location.X <= x) && (x < (rect.Location.X + rect.Size.Width)) + && (rect.Location.Y <= y) && (y < (rect.Location.Y + rect.Size.Height)); + + /// + /// Determines if the specified is contained within this . + /// + /// The to test. + /// + public static bool Contains(this Rectangle rect, Rectangle rect2) => (rect.Location.X <= rect2.Location.X) && ((rect2.Location.X + rect2.Size.Width) <= (rect.Location.X + rect.Size.Width)) + && (rect.Location.Y <= rect2.Location.Y) && ((rect2.Location.Y + rect2.Size.Height) <= (rect.Location.Y + rect.Size.Height)); + + #endregion + } +} diff --git a/RGB.NET.Core/Leds/Led.cs b/RGB.NET.Core/Leds/Led.cs index b300065..27bf4ed 100644 --- a/RGB.NET.Core/Leds/Led.cs +++ b/RGB.NET.Core/Leds/Led.cs @@ -44,10 +44,19 @@ namespace RGB.NET.Core set => SetProperty(ref _shapeData, value); } + private Rectangle _ledRectangle; /// /// Gets a rectangle representing the physical location of the relative to the . /// - public Rectangle LedRectangle { get; } + public Rectangle LedRectangle + { + get => _ledRectangle; + set + { + if (SetProperty(ref _ledRectangle, value)) + OnPropertyChanged(nameof(AbsoluteLedRectangle)); + } + } /// /// Gets a rectangle representing the physical location of the on the . @@ -142,6 +151,12 @@ namespace RGB.NET.Core this.Id = id; this.LedRectangle = ledRectangle; this.CustomData = customData; + + device.PropertyChanged += (sender, args) => + { + OnPropertyChanged(nameof(LedRectangle)); + OnPropertyChanged(nameof(AbsoluteLedRectangle)); + }; } #endregion @@ -195,7 +210,7 @@ namespace RGB.NET.Core /// Converts a to a . /// /// The to convert. - public static implicit operator Rectangle(Led led) => led?.LedRectangle; + public static implicit operator Rectangle(Led led) => led?.LedRectangle ?? new Rectangle(); #endregion } diff --git a/RGB.NET.Core/Positioning/Rectangle.cs b/RGB.NET.Core/Positioning/Rectangle.cs index ede55c3..7bf5330 100644 --- a/RGB.NET.Core/Positioning/Rectangle.cs +++ b/RGB.NET.Core/Positioning/Rectangle.cs @@ -8,155 +8,47 @@ using System.Linq; 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 + public struct Rectangle { #region Properties & Fields - private double _x; /// - /// Gets or sets the X-position of this . + /// Gets the representing the top-left corner of the . /// - public double X - { - get => _x; - set - { - if (SetProperty(ref _x, value)) - { - OnPropertyChanged(nameof(Location)); - OnPropertyChanged(nameof(Center)); - } - } - } - - private double _y; - /// - /// Gets or sets the Y-position of this . - /// - public double Y - { - get => _y; - set - { - if (SetProperty(ref _y, value)) - { - OnPropertyChanged(nameof(Location)); - OnPropertyChanged(nameof(Center)); - } - } - } - - private double _width; - /// - /// Gets or sets the width of this . - /// - public double Width - { - get => _width; - set - { - if (SetProperty(ref _width, Math.Max(0, value))) - { - OnPropertyChanged(nameof(Size)); - OnPropertyChanged(nameof(Center)); - OnPropertyChanged(nameof(IsEmpty)); - } - } - } - - private double _height; - /// - /// Gets or sets the height of this . - /// - public double Height - { - get => _height; - set - { - if (SetProperty(ref _height, Math.Max(0, value))) - { - OnPropertyChanged(nameof(Size)); - OnPropertyChanged(nameof(Center)); - OnPropertyChanged(nameof(IsEmpty)); - } - } - } + public Point Location { get; } /// - /// Gets or sets the representing the top-left corner of the . + /// Gets the of the . /// - public Point Location - { - get => new Point(X, Y); - set - { - if (Location != value) - { - _x = value.X; - _y = value.Y; - - OnPropertyChanged(nameof(Location)); - OnPropertyChanged(nameof(Center)); - } - } - } - - /// - /// Gets or sets the of the . - /// - public Size Size - { - get => new Size(Width, Height); - set - { - if (Size != value) - { - _width = value.Width; - _height = value.Height; - - OnPropertyChanged(nameof(Size)); - OnPropertyChanged(nameof(Center)); - OnPropertyChanged(nameof(IsEmpty)); - } - } - } + public Size Size { get; } /// /// Gets a new representing the center-point of the . /// - public Point Center => new Point(X + (Width / 2.0), Y + (Height / 2.0)); + public Point Center { get; } /// /// Gets a bool indicating if both, the width and the height of the rectangle is greater than zero. /// True if the rectangle has a width or a height of zero; otherwise, false. /// - public bool IsEmpty => (Width <= DoubleExtensions.TOLERANCE) || (Height <= DoubleExtensions.TOLERANCE); + 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 . + /// The x-value of the of this . + /// The y-value of the -position of this . + /// The width of the of this . + /// The height of the of this . public Rectangle(double x, double y, double width, double height) : this(new Point(x, y), new Size(width, height)) { } @@ -170,6 +62,7 @@ namespace RGB.NET.Core { this.Location = location; this.Size = size; + Center = new Point(Location.X + (Size.Width / 2.0), Location.Y + (Size.Height / 2.0)); } /// @@ -205,10 +98,10 @@ namespace RGB.NET.Core posY2 = Math.Max(posY2, rectangle.Location.Y + rectangle.Size.Height); } - if (hasPoint) - InitializeFromPoints(new Point(posX, posY), new Point(posX2, posY2)); - else - InitializeFromPoints(new Point(0, 0), new Point(0, 0)); + (Point location, Size size) = hasPoint ? InitializeFromPoints(new Point(posX, posY), new Point(posX2, posY2)) : InitializeFromPoints(new Point(0, 0), new Point(0, 0)); + Location = location; + Size = size; + Center = new Point(Location.X + (Size.Width / 2.0), Location.Y + (Size.Height / 2.0)); } /// @@ -246,82 +139,27 @@ namespace RGB.NET.Core posY2 = Math.Max(posY2, point.Y); } - if (hasPoint) - InitializeFromPoints(new Point(posX, posY), new Point(posX2, posY2)); - else - InitializeFromPoints(new Point(0, 0), new Point(0, 0)); + (Point location, Size size) = hasPoint ? InitializeFromPoints(new Point(posX, posY), new Point(posX2, posY2)) : InitializeFromPoints(new Point(0, 0), new Point(0, 0)); + + Location = location; + Size = size; + Center = new Point(Location.X + (Size.Width / 2.0), Location.Y + (Size.Height / 2.0)); } #endregion #region Methods - private void InitializeFromPoints(Point point1, Point point2) + private static (Point location, Size size) 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); + return (new Point(posX, posY), 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.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(); - } - - /// - /// Determines if the specified is contained within this . - /// - /// The to test. - /// - public bool Contains(Point point) => Contains(point.X, point.Y); - - /// - /// Determines if the specified location is contained within this . - /// - /// The X-location to test. - /// The Y-location to test. - /// - public bool Contains(double x, double y) => (Location.X <= x) && (x < (Location.X + Size.Width)) && (Location.Y <= y) && (y < (Location.Y + Size.Height)); - - /// - /// Determines if the specified is contained within this . - /// - /// The to test. - /// - public bool Contains(Rectangle rect) => (Location.X <= rect.Location.X) && ((rect.Location.X + rect.Size.Width) <= (Location.X + Size.Width)) - && (Location.Y <= rect.Location.Y) && ((rect.Location.Y + rect.Size.Height) <= (Location.Y + Size.Height)); - /// /// Converts the - and -position of this to a human-readable string. /// @@ -338,9 +176,6 @@ namespace RGB.NET.Core if (!(obj is Rectangle compareRect)) return false; - if (ReferenceEquals(this, compareRect)) - return true; - if (GetType() != compareRect.GetType()) return false; @@ -371,7 +206,7 @@ namespace RGB.NET.Core /// The first to compare. /// The second to compare. /// true if and are equal; otherwise, false. - public static bool operator ==(Rectangle rectangle1, Rectangle rectangle2) => rectangle1?.Equals(rectangle2) ?? ReferenceEquals(rectangle2, null); + public static bool operator ==(Rectangle rectangle1, Rectangle rectangle2) => rectangle1.Equals(rectangle2); /// /// Returns a value that indicates whether two specified are equal. diff --git a/RGB.NET.Core/RGBSurface.cs b/RGB.NET.Core/RGBSurface.cs index d2933c7..1db3b08 100644 --- a/RGB.NET.Core/RGBSurface.cs +++ b/RGB.NET.Core/RGBSurface.cs @@ -33,8 +33,6 @@ namespace RGB.NET.Core private readonly LinkedList _ledGroups = new LinkedList(); - private readonly Rectangle _surfaceRectangle = new Rectangle(); - // ReSharper restore InconsistentNaming /// @@ -50,7 +48,7 @@ namespace RGB.NET.Core /// /// Gets a copy of the representing this . /// - public Rectangle SurfaceRectangle => new Rectangle(_surfaceRectangle); + public Rectangle SurfaceRectangle { get; private set; } /// /// Gets a list of all on this . @@ -162,9 +160,8 @@ namespace RGB.NET.Core case BrushCalculationMode.Relative: Rectangle brushRectangle = new Rectangle(leds.Select(led => led.AbsoluteLedRectangle)); Point offset = new Point(-brushRectangle.Location.X, -brushRectangle.Location.Y); - brushRectangle.Location = new Point(0, 0); - brush.PerformRender(brushRectangle, - leds.Select(x => new BrushRenderTarget(x, GetDeviceLedLocation(x, offset)))); + brushRectangle = brushRectangle.SetLocation(new Point(0, 0)); + brush.PerformRender(brushRectangle, leds.Select(x => new BrushRenderTarget(x, GetDeviceLedLocation(x, offset)))); break; case BrushCalculationMode.Absolute: brush.PerformRender(SurfaceRectangle, leds.Select(x => new BrushRenderTarget(x, x.AbsoluteLedRectangle))); @@ -230,9 +227,7 @@ namespace RGB.NET.Core private void UpdateSurfaceRectangle() { Rectangle devicesRectangle = new Rectangle(_devices.Select(d => new Rectangle(d.Location, d.Size))); - - _surfaceRectangle.Width = devicesRectangle.Location.X + devicesRectangle.Size.Width; - _surfaceRectangle.Height = devicesRectangle.Location.Y + devicesRectangle.Size.Height; + SurfaceRectangle = SurfaceRectangle.SetSize(new Size(devicesRectangle.Location.X + devicesRectangle.Size.Width, devicesRectangle.Location.Y + devicesRectangle.Size.Height)); } /// diff --git a/RGB.NET.Groups/Groups/RectangleLedGroup.cs b/RGB.NET.Groups/Groups/RectangleLedGroup.cs index 63b5616..18ffb8c 100644 --- a/RGB.NET.Groups/Groups/RectangleLedGroup.cs +++ b/RGB.NET.Groups/Groups/RectangleLedGroup.cs @@ -2,7 +2,6 @@ // ReSharper disable AutoPropertyCanBeMadeGetOnly.Global // ReSharper disable UnusedMember.Global -using System; using System.Collections.Generic; using System.Linq; using RGB.NET.Core; @@ -28,17 +27,8 @@ namespace RGB.NET.Groups get => _rectangle; set { - Rectangle oldValue = _rectangle; if (SetProperty(ref _rectangle, value)) - { - if (oldValue != null) - oldValue.PropertyChanged -= RectangleChanged; - - if (_rectangle != null) - _rectangle.PropertyChanged += RectangleChanged; - InvalidateCache(); - } } } @@ -110,14 +100,12 @@ namespace RGB.NET.Groups private void RGBSurfaceOnSurfaceLayoutChanged(SurfaceLayoutChangedEventArgs args) => InvalidateCache(); - private void RectangleChanged(object sender, EventArgs eventArgs) => InvalidateCache(); - /// /// /// Gets a list containing all of this . /// /// The list containing all of this . - public override IEnumerable GetLeds() => _ledCache ?? (_ledCache = RGBSurface.Instance.Leds.Where(x => x.AbsoluteLedRectangle.CalculateIntersectPercentage(Rectangle) >= MinOverlayPercentage).ToList()); + public override IEnumerable GetLeds() => _ledCache ??= RGBSurface.Instance.Leds.Where(x => x.AbsoluteLedRectangle.CalculateIntersectPercentage(Rectangle) >= MinOverlayPercentage).ToList(); private void InvalidateCache() => _ledCache = null;