diff --git a/RGB.NET.Core/Devices/AbstractRGBDevice.cs b/RGB.NET.Core/Devices/AbstractRGBDevice.cs
index 90c97e1..cd76493 100644
--- a/RGB.NET.Core/Devices/AbstractRGBDevice.cs
+++ b/RGB.NET.Core/Devices/AbstractRGBDevice.cs
@@ -27,14 +27,6 @@ namespace RGB.NET.Core
///
IRGBDeviceInfo IRGBDevice.DeviceInfo => DeviceInfo;
- private Size _size = Size.Invalid;
- ///
- public Size Size
- {
- get => _size;
- set => SetProperty(ref _size, value);
- }
-
private Point _location = new Point(0, 0);
///
public Point Location
@@ -43,6 +35,58 @@ namespace RGB.NET.Core
set => SetProperty(ref _location, value);
}
+ private Size _size = Size.Invalid;
+ ///
+ public Size Size
+ {
+ get => _size;
+ protected set
+ {
+ if (SetProperty(ref _size, value))
+ UpdateActualData();
+ }
+ }
+
+ private Size _actualSize;
+ ///
+ public Size ActualSize
+ {
+ get => _actualSize;
+ private set => SetProperty(ref _actualSize, value);
+ }
+
+ private Rectangle _deviceRectangle;
+ ///
+ public Rectangle DeviceRectangle
+ {
+ get => _deviceRectangle;
+ private set => SetProperty(ref _deviceRectangle, value);
+ }
+
+ private Scale _scale = new Scale(1);
+ ///
+ public Scale Scale
+ {
+ get => _scale;
+ set
+ {
+ if (SetProperty(ref _scale, value))
+ UpdateActualData();
+ }
+ }
+
+ private Rotation _rotation = new Rotation(0);
+ ///
+ public Rotation Rotation
+ {
+ get => _rotation;
+ set
+ {
+ if (SetProperty(ref _rotation, value))
+ UpdateActualData();
+ }
+ }
+
///
/// Gets or sets if the device needs to be flushed on every update.
///
@@ -79,6 +123,12 @@ namespace RGB.NET.Core
#region Methods
+ private void UpdateActualData()
+ {
+ ActualSize = Size * Scale;
+ DeviceRectangle = new Rectangle(Location, new Rectangle(new Rectangle(Location, ActualSize).Rotate(Rotation)).Size);
+ }
+
///
public virtual void Update(bool flushLeds = false)
{
@@ -124,11 +174,21 @@ namespace RGB.NET.Core
/// The to initialize.
/// The representing the position of the to initialize.
///
- protected virtual Led InitializeLed(LedId ledId, Rectangle ledRectangle)
+ [Obsolete("Use InitializeLed(LedId ledId, Point location, Size size) instead.")]
+ protected virtual Led InitializeLed(LedId ledId, Rectangle rectangle) => InitializeLed(ledId, rectangle.Location, rectangle.Size);
+
+ ///
+ /// Initializes the with the specified id.
+ ///
+ /// The to initialize.
+ /// The location of the to initialize.
+ /// The size of the to initialize.
+ /// The initialized led.
+ protected virtual Led InitializeLed(LedId ledId, Point location, Size size)
{
if ((ledId == LedId.Invalid) || LedMapping.ContainsKey(ledId)) return null;
- Led led = new Led(this, ledId, ledRectangle, CreateLedCustomData(ledId));
+ Led led = new Led(this, ledId, location, size, CreateLedCustomData(ledId));
LedMapping.Add(ledId, led);
return led;
}
@@ -171,13 +231,12 @@ namespace RGB.NET.Core
if (Enum.TryParse(layoutLed.Id, true, out LedId ledId))
{
if (!LedMapping.TryGetValue(ledId, out Led led) && createMissingLeds)
- led = InitializeLed(ledId, new Rectangle());
+ led = InitializeLed(ledId, new Point(), new Size());
if (led != null)
{
- led.LedRectangle.Location = new Point(layoutLed.X, layoutLed.Y);
- led.LedRectangle.Size = new Size(layoutLed.Width, layoutLed.Height);
-
+ led.Location = new Point(layoutLed.X, layoutLed.Y);
+ led.Size = new Size(layoutLed.Width, layoutLed.Height);
led.Shape = layoutLed.Shape;
led.ShapeData = layoutLed.ShapeData;
diff --git a/RGB.NET.Core/Devices/IRGBDevice.cs b/RGB.NET.Core/Devices/IRGBDevice.cs
index 9ba17c4..23278ba 100644
--- a/RGB.NET.Core/Devices/IRGBDevice.cs
+++ b/RGB.NET.Core/Devices/IRGBDevice.cs
@@ -24,10 +24,31 @@ namespace RGB.NET.Core
Point Location { get; set; }
///
- /// Gets a copy of the of the whole .
+ /// Gets the of the .
///
Size Size { get; }
+ ///
+ /// Gets the actual of the .
+ /// This includes the .
+ ///
+ Size ActualSize { get; }
+
+ ///
+ /// Gets a representing the logical location of the relative to the .
+ ///
+ Rectangle DeviceRectangle { get; }
+
+ ///
+ /// Gets or sets the scale of the .
+ ///
+ Scale Scale { get; set; }
+
+ ///
+ /// Gets or sets the rotation of the .
+ ///
+ Rotation Rotation { get; set; }
+
///
/// Gets or sets the of the .
///
diff --git a/RGB.NET.Core/Extensions/PointExtensions.cs b/RGB.NET.Core/Extensions/PointExtensions.cs
new file mode 100644
index 0000000..7c413e9
--- /dev/null
+++ b/RGB.NET.Core/Extensions/PointExtensions.cs
@@ -0,0 +1,37 @@
+using System;
+
+namespace RGB.NET.Core
+{
+ public static class PointExtensions
+ {
+ #region Methods
+
+ ///
+ /// Moves the specified by the given amount.
+ ///
+ /// The to move.
+ /// The x-ammount to move.
+ /// The y-ammount to move.
+ /// The new location of the point.
+ public static Point Translate(this Point point, double x = 0, double y = 0) => new Point(point.X + x, point.Y + y);
+
+ ///
+ /// Rotates the specified by the given amuont around the given origin.
+ ///
+ /// The to rotate.
+ /// The rotation.
+ /// The origin to rotate around. [0,0] if not set.
+ /// The new location of the point.
+ public static Point Rotate(this Point point, Rotation rotation, Point origin = new Point())
+ {
+ double sin = Math.Sin(rotation.Radians);
+ double cos = Math.Cos(rotation.Radians);
+
+ point = new Point(point.X - origin.X, point.Y - origin.Y);
+ point = new Point((point.X * cos) - (point.Y * sin), (point.X * sin) + (point.Y * cos));
+ return new Point(point.X + origin.X, point.Y + origin.Y); ;
+ }
+
+ #endregion
+ }
+}
diff --git a/RGB.NET.Core/Extensions/RectangleExtensions.cs b/RGB.NET.Core/Extensions/RectangleExtensions.cs
new file mode 100644
index 0000000..aae9b04
--- /dev/null
+++ b/RGB.NET.Core/Extensions/RectangleExtensions.cs
@@ -0,0 +1,169 @@
+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.
+ /// true if the rectangle contains the given point; otherwise false.
+ 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.
+ /// true if the rectangle contains the given coordinates; otherwise false.
+ 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.
+ /// true if the rectangle contains the given rect; otherwise false.
+ 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));
+
+ ///
+ /// Moves the specified by the given amount.
+ ///
+ /// The to move.
+ /// The amount to move.
+ /// The moved rectangle.
+ public static Rectangle Translate(this Rectangle rect, Point point) => rect.Translate(point.X, point.Y);
+
+ ///
+ /// Moves the specified by the given amount.
+ ///
+ /// The to move.
+ /// The x-ammount to move.
+ /// The y-ammount to move.
+ /// The moved rectangle.
+ public static Rectangle Translate(this Rectangle rect, double x = 0, double y = 0) => new Rectangle(rect.Location.Translate(x, y), rect.Size);
+
+ ///
+ /// Rotates the specified by the given amuont around the given origin.
+ ///
+ ///
+ /// The returned array of is filled with the new locations of the rectangle clockwise starting from the top left:
+ /// [0] = top left
+ /// [1] = top right
+ /// [2] = bottom right
+ /// [3] = bottom left
+ ///
+ /// The to rotate.
+ /// The rotation.
+ /// The origin to rotate around. [0,0] if not set.
+ /// A array of containing the new locations of the corners of the original rectangle.
+ public static Point[] Rotate(this Rectangle rect, Rotation rotation, Point origin = new Point())
+ {
+ Point[] points = {
+ rect.Location, // top left
+ new Point(rect.Location.X + rect.Size.Width, rect.Location.Y), // top right
+ new Point(rect.Location.X + rect.Size.Width, rect.Location.Y + rect.Size.Height), // bottom right
+ new Point(rect.Location.X, rect.Location.Y + rect.Size.Height), // bottom right
+ };
+
+ double sin = Math.Sin(rotation.Radians);
+ double cos = Math.Cos(rotation.Radians);
+
+ for (int i = 0; i < points.Length; i++)
+ {
+ Point point = points[i];
+ point = new Point(point.X - origin.X, point.Y - origin.Y);
+ point = new Point((point.X * cos) - (point.Y * sin), (point.X * sin) + (point.Y * cos));
+ points[i] = new Point(point.X + origin.X, point.Y + origin.Y);
+ }
+
+ return points;
+ }
+
+ #endregion
+ }
+}
diff --git a/RGB.NET.Core/Leds/Led.cs b/RGB.NET.Core/Leds/Led.cs
index b300065..67cea33 100644
--- a/RGB.NET.Core/Leds/Led.cs
+++ b/RGB.NET.Core/Leds/Led.cs
@@ -1,6 +1,7 @@
// ReSharper disable MemberCanBePrivate.Global
using System;
+using System.ComponentModel;
using System.Diagnostics;
namespace RGB.NET.Core
@@ -44,15 +45,81 @@ namespace RGB.NET.Core
set => SetProperty(ref _shapeData, value);
}
+ private Point _location;
///
- /// Gets a rectangle representing the physical location of the relative to the .
+ /// Gets or sets the relative location of the .
///
- public Rectangle LedRectangle { get; }
+ public Point Location
+ {
+ get => _location;
+ set
+ {
+ if (SetProperty(ref _location, value))
+ {
+ UpdateActualData();
+ UpdateAbsoluteData();
+ }
+ }
+ }
+ private Size _size;
///
- /// Gets a rectangle representing the physical location of the on the .
+ /// Gets or sets the size of the .
///
- public Rectangle AbsoluteLedRectangle => (LedRectangle.Location + Device.Location) + new Size(LedRectangle.Size.Width, LedRectangle.Size.Height);
+ public Size Size
+ {
+ get => _size;
+ set
+ {
+ if (SetProperty(ref _size, value))
+ {
+ UpdateActualData();
+ UpdateAbsoluteData();
+ }
+ }
+ }
+
+ private Point _actualLocation;
+ ///
+ /// Gets the actual location of the .
+ /// This includes device-scaling and rotation.
+ ///
+ public Point ActualLocation
+ {
+ get => _actualLocation;
+ private set => SetProperty(ref _actualLocation, value);
+ }
+
+ private Size _actualSize;
+ ///
+ /// Gets the actual size of the .
+ /// This includes device-scaling.
+ ///
+ public Size ActualSize
+ {
+ get => _actualSize;
+ private set => SetProperty(ref _actualSize, value);
+ }
+
+ private Rectangle _ledRectangle;
+ ///
+ /// Gets a rectangle representing the logical location of the relative to the .
+ ///
+ public Rectangle LedRectangle
+ {
+ get => _ledRectangle;
+ private set => SetProperty(ref _ledRectangle, value);
+ }
+
+ private Rectangle _absoluteLedRectangle;
+ ///
+ /// Gets a rectangle representing the logical location of the on the .
+ ///
+ public Rectangle AbsoluteLedRectangle
+ {
+ get => _absoluteLedRectangle;
+ private set => SetProperty(ref _absoluteLedRectangle, value);
+ }
///
/// Indicates whether the is about to change it's color.
@@ -134,20 +201,61 @@ namespace RGB.NET.Core
///
/// The the is associated with.
/// The of the .
- /// The representing the physical location of the relative to the .
+ /// The physical location of the relative to the .
+ /// The size of the .
/// The provider-specific data associated with this led.
- internal Led(IRGBDevice device, LedId id, Rectangle ledRectangle, object customData = null)
+ internal Led(IRGBDevice device, LedId id, Point location, Size size, object customData = null)
{
this.Device = device;
this.Id = id;
- this.LedRectangle = ledRectangle;
+ this.Location = location;
+ this.Size = size;
this.CustomData = customData;
+
+ device.PropertyChanged += DevicePropertyChanged;
}
#endregion
#region Methods
+ private void DevicePropertyChanged(object sender, PropertyChangedEventArgs e)
+ {
+ if ((e.PropertyName == nameof(IRGBDevice.Location)))
+ UpdateAbsoluteData();
+ else if (e.PropertyName == nameof(IRGBDevice.DeviceRectangle))
+ {
+ UpdateActualData();
+ UpdateAbsoluteData();
+ }
+ }
+
+ private void UpdateActualData()
+ {
+ ActualSize = Size * Device.Scale;
+
+ Point actualLocation = (Location * Device.Scale);
+ Rectangle ledRectangle = new Rectangle(Location * Device.Scale, Size * Device.Scale);
+
+ if (Device.Rotation.IsRotated)
+ {
+ Point deviceCenter = new Rectangle(Device.ActualSize).Center;
+ Point actualDeviceCenter = new Rectangle(Device.DeviceRectangle.Size).Center;
+ Point centerOffset = new Point(actualDeviceCenter.X - deviceCenter.X, actualDeviceCenter.Y - deviceCenter.Y);
+
+ actualLocation = actualLocation.Rotate(Device.Rotation, new Rectangle(Device.ActualSize).Center) + centerOffset;
+ ledRectangle = new Rectangle(ledRectangle.Rotate(Device.Rotation, new Rectangle(Device.ActualSize).Center)).Translate(centerOffset);
+ }
+
+ ActualLocation = actualLocation;
+ LedRectangle = ledRectangle;
+ }
+
+ private void UpdateAbsoluteData()
+ {
+ AbsoluteLedRectangle = LedRectangle.Translate(Device.Location);
+ }
+
///
/// Converts the and the of this to a human-readable string.
///
@@ -155,7 +263,7 @@ namespace RGB.NET.Core
public override string ToString() => $"{Id} {Color}";
///
- /// Updates the to the requested .
+ /// Updates the to the requested .
///
internal void Update()
{
@@ -169,7 +277,7 @@ namespace RGB.NET.Core
}
///
- /// Resets the back to default.
+ /// Resets the back to default.
///
internal void Reset()
{
@@ -195,7 +303,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/Point.cs b/RGB.NET.Core/Positioning/Point.cs
index 58eb2d9..9583863 100644
--- a/RGB.NET.Core/Positioning/Point.cs
+++ b/RGB.NET.Core/Positioning/Point.cs
@@ -149,6 +149,14 @@ namespace RGB.NET.Core
return new Point(point1.X / point2.X, point1.Y / point2.Y);
}
+ ///
+ /// Returns a new representing the multiplication of the and the provided .
+ ///
+ /// The .
+ /// The .
+ /// A new representing the multiplication of the and the provided .
+ public static Point operator *(Point point, Scale scale) => new Point(point.X * scale.Horizontal, point.Y * scale.Vertical);
+
#endregion
}
}
diff --git a/RGB.NET.Core/Positioning/Rectangle.cs b/RGB.NET.Core/Positioning/Rectangle.cs
index ede55c3..d3b1618 100644
--- a/RGB.NET.Core/Positioning/Rectangle.cs
+++ b/RGB.NET.Core/Positioning/Rectangle.cs
@@ -8,168 +8,68 @@ 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))
{ }
+ ///
+ /// Initializes a new instance of the class using the (0,0) and the given .
+ ///
+ /// The size of of this .
+ public Rectangle(Size size) : this(new Point(), size)
+ { }
+
///
/// Initializes a new instance of the class using the given and .
///
- ///
- ///
+ /// The location of this of this .
+ /// The size of of this .
public Rectangle(Point location, Size size)
{
this.Location = location;
this.Size = size;
+ Center = new Point(Location.X + (Size.Width / 2.0), Location.Y + (Size.Height / 2.0));
}
///
@@ -205,10 +105,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 +146,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 +183,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 +213,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/Positioning/Rotation.cs b/RGB.NET.Core/Positioning/Rotation.cs
new file mode 100644
index 0000000..0f638ec
--- /dev/null
+++ b/RGB.NET.Core/Positioning/Rotation.cs
@@ -0,0 +1,162 @@
+// ReSharper disable MemberCanBePrivate.Global
+// ReSharper disable UnusedMember.Global
+
+using System;
+using System.Diagnostics;
+
+namespace RGB.NET.Core
+{
+ ///
+ /// Represents an angular rotation.
+ ///
+ [DebuggerDisplay("[{Degrees}°]")]
+ public struct Rotation
+ {
+ #region Constants
+
+ private const double TWO_PI = Math.PI * 2.0;
+ private const double RADIANS_DEGREES_CONVERSION = 180.0 / Math.PI;
+ private const double DEGREES_RADIANS_CONVERSION = Math.PI / 180.0;
+
+ #endregion
+
+ #region Properties & Fields
+
+ ///
+ /// Gets the angle in degrees.
+ ///
+ public double Degrees { get; }
+
+ ///
+ /// Gets the angle in radians.
+ ///
+ public double Radians { get; }
+
+ ///
+ /// Gets a bool indicating if the rotation is > 0.
+ ///
+ public bool IsRotated => !Degrees.EqualsInTolerance(0);
+
+ #endregion
+
+ #region Constructors
+
+ ///
+ /// Initializes a new instance of the class using the provided values.
+ ///
+ /// The rotation in degrees.
+ public Rotation(double degrees)
+ : this(degrees, degrees * DEGREES_RADIANS_CONVERSION)
+ { }
+
+ private Rotation(double degrees, double radians)
+ {
+ this.Degrees = degrees % 360.0;
+ this.Radians = radians % TWO_PI;
+ }
+
+ #endregion
+
+ #region Methods
+
+ ///
+ /// Creates a new Rotation out of the given degree-angle.
+ ///
+ /// The angle in degrees.
+ /// The new rotation.
+ public static Rotation FromDegrees(double degrees) => new Rotation(degrees);
+
+ ///
+ /// Creates a new Rotation out of the given radian-angle.
+ ///
+ /// The angle in radians.
+ /// The new rotation.
+ public static Rotation FromRadians(double radians) => new Rotation(radians * RADIANS_DEGREES_CONVERSION, radians);
+
+ ///
+ /// Tests whether the specified is equivalent to this .
+ ///
+ /// The rotation to test.
+ /// true if is equivalent to this ; otherwise, false.
+ public bool Equals(Rotation other) => Degrees.EqualsInTolerance(other.Degrees);
+
+ ///
+ /// Tests whether the specified object is a and is equivalent to this .
+ ///
+ /// The object to test.
+ /// true if is a equivalent to this ; otherwise, false.
+ public override bool Equals(object obj) => obj is Rotation other && Equals(other);
+
+ ///
+ /// Returns a hash code for this .
+ ///
+ /// An integer value that specifies the hash code for this .
+ public override int GetHashCode() => Degrees.GetHashCode();
+
+ #endregion
+
+ #region Operators
+
+ ///
+ /// Returns a value that indicates whether two specified are equal.
+ ///
+ /// The first to compare.
+ /// The second to compare.
+ /// true if and are equal; otherwise, false.
+ public static bool operator ==(Rotation rotation1, Rotation rotation2) => rotation1.Equals(rotation2);
+
+ ///
+ /// Returns a value that indicates whether two specified are equal.
+ ///
+ /// The first to compare.
+ /// The second to compare.
+ /// true if and are not equal; otherwise, false.
+ public static bool operator !=(Rotation rotation1, Rotation rotation2) => !(rotation1 == rotation2);
+
+ ///
+ /// Returns a new representing the addition of the and the provided value.
+ ///
+ /// The .
+ /// The value to add.
+ /// A new representing the addition of the and the provided value.
+ public static Rotation operator +(Rotation rotation, double value) => new Rotation(rotation.Degrees + value);
+
+ ///
+ /// Returns a new representing the subtraction of the and the provided value.
+ ///
+ /// The .
+ /// The value to substract.
+ /// A new representing the subtraction of the and the provided value.
+ public static Rotation operator -(Rotation rotation, double value) => new Rotation(rotation.Degrees - value);
+
+ ///
+ /// Returns a new representing the multiplication of the and the provided value.
+ ///
+ /// The .
+ /// The value to multiply with.
+ /// A new representing the multiplication of the and the provided value.
+ public static Rotation operator *(Rotation rotation, double value) => new Rotation(rotation.Degrees * value);
+
+ ///
+ /// Returns a new representing the division of the and the provided value.
+ ///
+ /// The .
+ /// The value to device with.
+ /// A new representing the division of the and the provided value.
+ public static Rotation operator /(Rotation rotation, double value) => value.EqualsInTolerance(0) ? new Rotation(0) : new Rotation(rotation.Degrees / value);
+
+ ///
+ /// Converts a double to a .
+ ///
+ /// The rotation in degrees to convert.
+ public static implicit operator Rotation(double rotation) => new Rotation(rotation);
+
+ ///
+ /// Converts to a double representing the rotation in degrees.
+ ///
+ /// The rotatio to convert.
+ public static implicit operator double(Rotation rotation) => rotation.Degrees;
+
+ #endregion
+ }
+}
diff --git a/RGB.NET.Core/Positioning/Scale.cs b/RGB.NET.Core/Positioning/Scale.cs
new file mode 100644
index 0000000..04b8f09
--- /dev/null
+++ b/RGB.NET.Core/Positioning/Scale.cs
@@ -0,0 +1,144 @@
+// ReSharper disable MemberCanBePrivate.Global
+// ReSharper disable UnusedMember.Global
+
+using System.Diagnostics;
+
+namespace RGB.NET.Core
+{
+ ///
+ /// Represents a scaling.
+ ///
+ [DebuggerDisplay("[Horizontal: {Horizontal}, Vertical: {Vertical}]")]
+ public struct Scale
+ {
+ #region Properties & Fields
+
+ ///
+ /// Gets the horizontal scaling value.
+ ///
+ public double Horizontal { get; }
+
+ ///
+ /// Gets the vertical scaling value.
+ ///
+ public double Vertical { get; }
+
+ #endregion
+
+ #region Constructors
+
+ ///
+ /// Initializes a new instance of the class using the provided values.
+ ///
+ /// The value used for horizontal and vertical scaling. 0 if not set.
+ public Scale(double scale = 1.0) : this(scale, scale)
+ { }
+
+ ///
+ /// Initializes a new instance of the class using the provided values.
+ ///
+ /// The value used for horizontal scaling.
+ /// The value used for vertical scaling.
+ public Scale(double horizontal, double vertical)
+ {
+ this.Horizontal = horizontal;
+ this.Vertical = vertical;
+ }
+
+ #endregion
+
+ #region Methods
+
+ ///
+ /// Tests whether the specified is equivalent to this .
+ ///
+ /// The scale to test.
+ /// true if is equivalent to this ; otherwise, false.
+ public bool Equals(Scale other) => Horizontal.EqualsInTolerance(other.Horizontal) && Vertical.EqualsInTolerance(other.Vertical);
+
+ ///
+ /// Tests whether the specified object is a and is equivalent to this .
+ ///
+ /// The object to test.
+ /// true if is a equivalent to this ; otherwise, false.
+ public override bool Equals(object obj) => obj is Scale other && Equals(other);
+
+ ///
+ /// Returns a hash code for this .
+ ///
+ /// An integer value that specifies the hash code for this .
+ public override int GetHashCode() { unchecked { return (Horizontal.GetHashCode() * 397) ^ Vertical.GetHashCode(); } }
+
+ ///
+ /// Deconstructs the scale into the horizontal and vertical value.
+ ///
+ /// The horizontal scaling value.
+ /// The vertical scaling value.
+ public void Deconstruct(out double horizontalScale, out double verticalScale)
+ {
+ horizontalScale = Horizontal;
+ verticalScale = Vertical;
+ }
+
+ #endregion
+
+ #region Operators
+
+ ///
+ /// Returns a value that indicates whether two specified are equal.
+ ///
+ /// The first to compare.
+ /// The second to compare.
+ /// true if and are equal; otherwise, false.
+ public static bool operator ==(Scale scale1, Scale scale2) => scale1.Equals(scale2);
+
+ ///
+ /// Returns a value that indicates whether two specified are equal.
+ ///
+ /// The first to compare.
+ /// The second to compare.
+ /// true if and are not equal; otherwise, false.
+ public static bool operator !=(Scale scale1, Scale scale2) => !(scale1 == scale2);
+
+ ///
+ /// Returns a new representing the addition of the and the provided value.
+ ///
+ /// The .
+ /// The value to add.
+ /// A new representing the addition of the and the provided value.
+ public static Scale operator +(Scale scale, double value) => new Scale(scale.Horizontal + value, scale.Vertical + value);
+
+ ///
+ /// Returns a new representing the subtraction of the and the provided value.
+ ///
+ /// The .
+ /// The value to substract.
+ /// A new representing the subtraction of the and the provided value.
+ public static Scale operator -(Scale scale, double value) => new Scale(scale.Horizontal - value, scale.Vertical - value);
+
+ ///
+ /// Returns a new representing the multiplication of the and the provided value.
+ ///
+ /// The .
+ /// The value to multiply with.
+ /// A new representing the multiplication of the and the provided value.
+ public static Scale operator *(Scale scale, double value) => new Scale(scale.Horizontal * value, scale.Vertical * value);
+
+ ///
+ /// Returns a new representing the division of the and the provided value.
+ ///
+ /// The .
+ /// The value to device with.
+ /// A new representing the division of the and the provided value.
+ public static Scale operator /(Scale scale, double value) => value.EqualsInTolerance(0) ? new Scale(0) : new Scale(scale.Horizontal / value, scale.Vertical / value);
+
+
+ ///
+ /// Converts a double to a .
+ ///
+ /// The scale value to convert.
+ public static implicit operator Scale(double scale) => new Scale(scale);
+
+ #endregion
+ }
+}
diff --git a/RGB.NET.Core/Positioning/Size.cs b/RGB.NET.Core/Positioning/Size.cs
index d6b7c6f..74f9153 100644
--- a/RGB.NET.Core/Positioning/Size.cs
+++ b/RGB.NET.Core/Positioning/Size.cs
@@ -94,6 +94,17 @@ namespace RGB.NET.Core
}
}
+ ///
+ /// Deconstructs the size into the width and height value.
+ ///
+ /// The width.
+ /// The height.
+ public void Deconstruct(out double width, out double height)
+ {
+ width = Width;
+ height = Height;
+ }
+
#endregion
#region Operators
@@ -172,6 +183,14 @@ namespace RGB.NET.Core
/// A new representing the division of the and the provided factor.
public static Size operator /(Size size, double factor) => factor.EqualsInTolerance(0) ? Invalid : new Size(size.Width / factor, size.Height / factor);
+ ///
+ /// Returns a new representing the multiplication of the and the given .
+ ///
+ /// The to scale.
+ /// The scaling factor.
+ /// A new representing the multiplication of the and the given .
+ public static Size operator *(Size size, Scale scale) => new Size(size.Width * scale.Horizontal, size.Height * scale.Vertical);
+
#endregion
}
}
diff --git a/RGB.NET.Core/RGBSurface.cs b/RGB.NET.Core/RGBSurface.cs
index d2933c7..7ba3183 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,12 +160,11 @@ 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(led => new BrushRenderTarget(led, led.AbsoluteLedRectangle.Translate(offset))));
break;
case BrushCalculationMode.Absolute:
- brush.PerformRender(SurfaceRectangle, leds.Select(x => new BrushRenderTarget(x, x.AbsoluteLedRectangle)));
+ brush.PerformRender(SurfaceRectangle, leds.Select(led => new BrushRenderTarget(led, led.AbsoluteLedRectangle)));
break;
default:
throw new ArgumentException();
@@ -180,12 +177,6 @@ namespace RGB.NET.Core
renders.Key.Led.Color = renders.Value;
}
- private Rectangle GetDeviceLedLocation(Led led, Point extraOffset)
- {
- Rectangle absoluteRectangle = led.AbsoluteLedRectangle;
- return (absoluteRectangle.Location + extraOffset) + absoluteRectangle.Size;
- }
-
///
/// Attaches the given .
///
@@ -229,10 +220,8 @@ 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;
+ Rectangle devicesRectangle = new Rectangle(_devices.Select(d => d.DeviceRectangle));
+ SurfaceRectangle = SurfaceRectangle.SetSize(new Size(devicesRectangle.Location.X + devicesRectangle.Size.Width, devicesRectangle.Location.Y + devicesRectangle.Size.Height));
}
///
diff --git a/RGB.NET.Core/RGBSurfaceDeviceLoader.cs b/RGB.NET.Core/RGBSurfaceDeviceLoader.cs
index b3fe9e6..f233282 100644
--- a/RGB.NET.Core/RGBSurfaceDeviceLoader.cs
+++ b/RGB.NET.Core/RGBSurfaceDeviceLoader.cs
@@ -63,7 +63,7 @@ namespace RGB.NET.Core
foreach (IRGBDevice device in Devices)
{
device.Location += new Point(posX, 0);
- posX += device.Size.Width + 1;
+ posX += device.ActualSize.Width + 1;
}
}
diff --git a/RGB.NET.Groups/Groups/RectangleLedGroup.cs b/RGB.NET.Groups/Groups/RectangleLedGroup.cs
index 63b5616..1b23c26 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(led => led.AbsoluteLedRectangle.CalculateIntersectPercentage(Rectangle) >= MinOverlayPercentage).ToList();
private void InvalidateCache() => _ledCache = null;