diff --git a/CUE.NET.csproj b/CUE.NET.csproj index 61448c7..8a536c0 100644 --- a/CUE.NET.csproj +++ b/CUE.NET.csproj @@ -66,6 +66,7 @@ + @@ -91,6 +92,7 @@ + diff --git a/Devices/Keyboard/Brushes/LinearGradientBrush.cs b/Devices/Keyboard/Brushes/LinearGradientBrush.cs index 8751c40..7ab8482 100644 --- a/Devices/Keyboard/Brushes/LinearGradientBrush.cs +++ b/Devices/Keyboard/Brushes/LinearGradientBrush.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.Drawing; using System.Linq; +using CUE.NET.Helper; namespace CUE.NET.Devices.Keyboard.Brushes { @@ -48,36 +49,10 @@ namespace CUE.NET.Devices.Keyboard.Brushes if (!GradientStops.Any()) return Color.Transparent; if (GradientStops.Count == 1) return GradientStops.First().Color; - // Based on https://dotupdate.wordpress.com/2008/01/28/find-the-color-of-a-point-in-a-lineargradientbrush/ - PointF startPoint = new PointF(StartPoint.X * rectangle.Width, StartPoint.Y * rectangle.Height); PointF endPoint = new PointF(EndPoint.X * rectangle.Width, EndPoint.Y * rectangle.Height); - PointF intersectingPoint; - if (startPoint.Y.Equals(endPoint.Y)) // Horizontal case - intersectingPoint = new PointF(point.X, startPoint.Y); - - else if (startPoint.X.Equals(endPoint.X)) // Vertical case - intersectingPoint = new PointF(startPoint.X, point.Y); - - else // Diagnonal case - { - float slope = (endPoint.Y - startPoint.Y) / (endPoint.X - startPoint.X); - float orthogonalSlope = -1 / slope; - - float startYIntercept = startPoint.Y - slope * startPoint.X; - float pointYIntercept = point.Y - orthogonalSlope * point.X; - - float intersectingPointX = (pointYIntercept - startYIntercept) / (slope - orthogonalSlope); - float intersectingPointY = slope * intersectingPointX + startYIntercept; - intersectingPoint = new PointF(intersectingPointX, intersectingPointY); - } - - // Calculate distances relative to the vector start - float intersectDistance = CalculateDistance(intersectingPoint, startPoint, endPoint); - float gradientLength = CalculateDistance(endPoint, startPoint, endPoint); - - float offset = intersectDistance / gradientLength; + float offset = GradientHelper.CalculateGradientOffset(startPoint, endPoint, point); // Clip the input if before or after the max/min offset values float max = GradientStops.Max(n => n.Offset); @@ -103,21 +78,6 @@ namespace CUE.NET.Devices.Keyboard.Brushes return Color.FromArgb(colA, colR, colG, colB); } - // Based on https://dotupdate.wordpress.com/2008/01/28/find-the-color-of-a-point-in-a-lineargradientbrush/ - /// - /// Returns the signed magnitude of a point on a vector - /// - private float CalculateDistance(PointF point, PointF origin, PointF direction) - { - float distance = (float)Math.Sqrt((point.Y - origin.Y) * (point.Y - origin.Y) + (point.X - origin.X) * (point.X - origin.X)); - - return (((point.Y < origin.Y) && (direction.Y > origin.Y)) || - ((point.Y > origin.Y) && (direction.Y < origin.Y)) || - ((point.Y.Equals(origin.Y)) && (point.X < origin.X) && (direction.X > origin.X)) || - ((point.Y.Equals(origin.Y)) && (point.X > origin.X) && (direction.X < origin.X))) - ? -distance : distance; - } - #endregion } } diff --git a/Devices/Keyboard/Brushes/RainbowBrush.cs b/Devices/Keyboard/Brushes/RainbowBrush.cs new file mode 100644 index 0000000..9bb0481 --- /dev/null +++ b/Devices/Keyboard/Brushes/RainbowBrush.cs @@ -0,0 +1,71 @@ +using System; +using System.Drawing; +using CUE.NET.Helper; + +namespace CUE.NET.Devices.Keyboard.Brushes +{ + public class RainbowBrush : IBrush + { + #region Properties & Fields + + public PointF StartPoint { get; set; } = new PointF(0f, 0.5f); + public PointF EndPoint { get; set; } = new PointF(1f, 0.5f); + public float StartHue { get; set; } + public float EndHue { get; set; } + + #endregion + + #region Constructors + + public RainbowBrush(float startHue = 0f, float endHue = 360f) + { + this.StartHue = startHue; + this.EndHue = endHue; + } + + public RainbowBrush(PointF startPoint, PointF endPoint, float startHue = 0f, float endHue = 360f) + { + this.StartPoint = startPoint; + this.EndPoint = endPoint; + this.StartHue = startHue; + this.EndHue = endHue; + } + + #endregion + + #region Methods + + public Color GetColorAtPoint(RectangleF rectangle, PointF point) + { + PointF startPoint = new PointF(StartPoint.X * rectangle.Width, StartPoint.Y * rectangle.Height); + PointF endPoint = new PointF(EndPoint.X * rectangle.Width, EndPoint.Y * rectangle.Height); + + float offset = GradientHelper.CalculateGradientOffset(startPoint, endPoint, point); + float range = EndHue - StartHue; + float progress = (StartHue + (range * offset)) / 360f; + + float div = (Math.Abs(progress % 1) * 6); + int value = (int)((div % 1) * 255); + + switch ((int)div) + { + case 0: + return Color.FromArgb(255, 255, value, 0); + case 1: + return Color.FromArgb(255, 255 - value, 255, 0); + case 2: + return Color.FromArgb(255, 0, 255, value); + case 3: + return Color.FromArgb(255, 0, 255 - value, 255); + case 4: + return Color.FromArgb(255, value, 0, 255); + case 5: + return Color.FromArgb(255, 255, 0, 255 - value); + default: + return Color.Transparent; + } + } + + #endregion + } +} diff --git a/Examples/SimpleDevTest/Program.cs b/Examples/SimpleDevTest/Program.cs index 687ac9e..aa661a8 100644 --- a/Examples/SimpleDevTest/Program.cs +++ b/Examples/SimpleDevTest/Program.cs @@ -85,8 +85,8 @@ namespace SimpleDevTest // Create our gradient stop to play with GradientStop moveableStop = new GradientStop(0, Color.FromArgb(0, 255, 0)); - //Create a basic (by default horizontal) brush ... - LinearGradientBrush linearBrush = new LinearGradientBrush(new GradientStop(0, Color.Blue), moveableStop, new GradientStop(1f, Color.Red)); + // Create a basic (by default horizontal) brush ... + LinearGradientBrush linearBrush = new LinearGradientBrush(new GradientStop(0, Color.Blue), moveableStop, new GradientStop(1f, Color.White)); // ... and add it as the keyboard background keyboard.Brush = linearBrush; @@ -122,6 +122,29 @@ namespace SimpleDevTest Wait(2); + // --------------------------------------------------------------------------- + // Time for an even better brush: rainbow + + Console.WriteLine("rainbow-test"); + + // Create an simple horizontal rainbow containing two times the full spectrum + RainbowBrush rainbowBrush = new RainbowBrush(0, 720); + + // Add the rainbow to the keyboard and perform an initial update + keyboard.Brush = rainbowBrush; + keyboard.UpdateLeds(); + + // Let the rainbow move around for 10 secs + for (int i = 0; i < 100; i++) + { + rainbowBrush.StartHue += 10f; + rainbowBrush.EndHue += 10f; + keyboard.UpdateLeds(); + Thread.Sleep(100); + } + + Wait(2); + // --------------------------------------------------------------------------- // Now let us move some points random over the keyboard diff --git a/Helper/GradientHelper.cs b/Helper/GradientHelper.cs new file mode 100644 index 0000000..8b866f0 --- /dev/null +++ b/Helper/GradientHelper.cs @@ -0,0 +1,53 @@ +using System; +using System.Drawing; + +namespace CUE.NET.Helper +{ + public static class GradientHelper + { + // Based on https://dotupdate.wordpress.com/2008/01/28/find-the-color-of-a-point-in-a-lineargradientbrush/ + public static float CalculateGradientOffset(PointF startPoint, PointF endPoint, PointF point) + { + PointF intersectingPoint; + if (startPoint.Y.Equals(endPoint.Y)) // Horizontal case + intersectingPoint = new PointF(point.X, startPoint.Y); + + else if (startPoint.X.Equals(endPoint.X)) // Vertical case + intersectingPoint = new PointF(startPoint.X, point.Y); + + else // Diagnonal case + { + float slope = (endPoint.Y - startPoint.Y) / (endPoint.X - startPoint.X); + float orthogonalSlope = -1 / slope; + + float startYIntercept = startPoint.Y - slope * startPoint.X; + float pointYIntercept = point.Y - orthogonalSlope * point.X; + + float intersectingPointX = (pointYIntercept - startYIntercept) / (slope - orthogonalSlope); + float intersectingPointY = slope * intersectingPointX + startYIntercept; + intersectingPoint = new PointF(intersectingPointX, intersectingPointY); + } + + // Calculate distances relative to the vector start + float intersectDistance = CalculateDistance(intersectingPoint, startPoint, endPoint); + float gradientLength = CalculateDistance(endPoint, startPoint, endPoint); + + return intersectDistance / gradientLength; + } + + // Based on https://dotupdate.wordpress.com/2008/01/28/find-the-color-of-a-point-in-a-lineargradientbrush/ + /// + /// Returns the signed magnitude of a point on a vector + /// + private static float CalculateDistance(PointF point, PointF origin, PointF direction) + { + float distance = (float)Math.Sqrt((point.Y - origin.Y) * (point.Y - origin.Y) + (point.X - origin.X) * (point.X - origin.X)); + + return (((point.Y < origin.Y) && (direction.Y > origin.Y)) || + ((point.Y > origin.Y) && (direction.Y < origin.Y)) || + ((point.Y.Equals(origin.Y)) && (point.X < origin.X) && (direction.X > origin.X)) || + ((point.Y.Equals(origin.Y)) && (point.X > origin.X) && (direction.X < origin.X))) + ? -distance : distance; + } + } +}