From ff59efeb780e5f275402c910355b1abdd577be22 Mon Sep 17 00:00:00 2001 From: Adrian Stevens Date: Thu, 12 Sep 2024 16:25:02 -0700 Subject: [PATCH 1/4] A few XML comments --- .../ICs.CAN.Mcp2515/Driver/Mcp2515.cs | 3 +++ .../Driver/FtdiExpander.Ft232hI2cBus.cs | 3 +++ .../Driver/FtdiExpander.Ft23xxI2cBus.cs | 3 +++ .../Driver/FtdiExpanderCollection.cs | 9 +++++++-- 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/Source/Meadow.Foundation.Peripherals/ICs.CAN.Mcp2515/Driver/Mcp2515.cs b/Source/Meadow.Foundation.Peripherals/ICs.CAN.Mcp2515/Driver/Mcp2515.cs index 53c4563877..b5e2b063aa 100644 --- a/Source/Meadow.Foundation.Peripherals/ICs.CAN.Mcp2515/Driver/Mcp2515.cs +++ b/Source/Meadow.Foundation.Peripherals/ICs.CAN.Mcp2515/Driver/Mcp2515.cs @@ -10,6 +10,9 @@ namespace Meadow.Foundation.ICs.CAN; /// public partial class Mcp2515 : ICanController { + /// + /// Default SPI clock mode for the MCP2515 + /// public const SpiClockConfiguration.Mode DefaultSpiMode = SpiClockConfiguration.Mode.Mode0; private byte BRP_Default = 0x01; diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/FtdiExpander.Ft232hI2cBus.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/FtdiExpander.Ft232hI2cBus.cs index e487c89457..8e452a0c84 100644 --- a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/FtdiExpander.Ft232hI2cBus.cs +++ b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/FtdiExpander.Ft232hI2cBus.cs @@ -6,6 +6,9 @@ namespace Meadow.Foundation.ICs.IOExpanders; public abstract partial class FtdiExpander { + /// + /// Represents an Ft232h expander I2C bus. + /// public class Ft232hI2cBus : I2CBus { internal Ft232hI2cBus(FtdiExpander expander, I2cBusSpeed busSpeed) diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/FtdiExpander.Ft23xxI2cBus.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/FtdiExpander.Ft23xxI2cBus.cs index 62b8f7f9b4..fea9caa4d4 100644 --- a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/FtdiExpander.Ft23xxI2cBus.cs +++ b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/FtdiExpander.Ft23xxI2cBus.cs @@ -5,6 +5,9 @@ namespace Meadow.Foundation.ICs.IOExpanders; public abstract partial class FtdiExpander { + /// + /// Represents an FTDI expander I2C bus. + /// public class Ft23xxI2cBus : I2CBus, II2cBus { internal Ft23xxI2cBus(FtdiExpander expander, I2cBusSpeed busSpeed) diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/FtdiExpanderCollection.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/FtdiExpanderCollection.cs index d01575c325..b69fe0fa54 100644 --- a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/FtdiExpanderCollection.cs +++ b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Ftxxxx/Driver/FtdiExpanderCollection.cs @@ -7,6 +7,9 @@ namespace Meadow.Foundation.ICs.IOExpanders; +/// +/// Represents a collection of FtdiExpander devices connected to the host machine. +/// public class FtdiExpanderCollection : IEnumerable { private static FtdiExpanderCollection? _instance; @@ -28,10 +31,12 @@ private FtdiExpanderCollection() { } + /// + /// Refresh the collection of FtdiExpander devices connected to the host machine. + /// public void Refresh() { - Native.CheckStatus( - Native.Ftd2xx.FT_CreateDeviceInfoList(out uint count)); + Native.CheckStatus(Native.Ftd2xx.FT_CreateDeviceInfoList(out uint count)); _expanders.Clear(); From 862eb38bad7f9be5990d8379b15f1d2037c07319 Mon Sep 17 00:00:00 2001 From: Adrian Stevens Date: Thu, 12 Sep 2024 16:29:40 -0700 Subject: [PATCH 2/4] Remove unused event handler --- .../Sensors.Gnss.Mt3339/Driver/MtkDecoder.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Gnss.Mt3339/Driver/MtkDecoder.cs b/Source/Meadow.Foundation.Peripherals/Sensors.Gnss.Mt3339/Driver/MtkDecoder.cs index 631f3d7230..4fcb8c750e 100644 --- a/Source/Meadow.Foundation.Peripherals/Sensors.Gnss.Mt3339/Driver/MtkDecoder.cs +++ b/Source/Meadow.Foundation.Peripherals/Sensors.Gnss.Mt3339/Driver/MtkDecoder.cs @@ -1,6 +1,5 @@ using Meadow.Foundation.Sensors.Location.Gnss; using Meadow.Peripherals.Sensors.Location.Gnss; -using System; namespace Meadow.Foundation.Sensors.Gnss { @@ -9,11 +8,6 @@ namespace Meadow.Foundation.Sensors.Gnss /// public class MtkDecoder : INmeaDecoder { - /// - /// Event raised when a message is received - /// - public event EventHandler MessageReceived = default!; - /// /// Friendly name for the MTK messages. /// From 7845acd848f51f20276462793874ef63dd46f904 Mon Sep 17 00:00:00 2001 From: Adrian Stevens Date: Thu, 12 Sep 2024 16:29:47 -0700 Subject: [PATCH 3/4] Add PointF --- .../Graphics.MicroGraphics/Driver/PointF.cs | 132 ++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 Source/Meadow.Foundation.Libraries_and_Frameworks/Graphics.MicroGraphics/Driver/PointF.cs diff --git a/Source/Meadow.Foundation.Libraries_and_Frameworks/Graphics.MicroGraphics/Driver/PointF.cs b/Source/Meadow.Foundation.Libraries_and_Frameworks/Graphics.MicroGraphics/Driver/PointF.cs new file mode 100644 index 0000000000..f59a42d958 --- /dev/null +++ b/Source/Meadow.Foundation.Libraries_and_Frameworks/Graphics.MicroGraphics/Driver/PointF.cs @@ -0,0 +1,132 @@ +using System.Drawing; + +namespace Meadow.Foundation.Graphics +{ + /// + /// Represents a 2D point with floating-point coordinates + /// + public struct PointF + { + /// + /// Gets an empty point at (0, 0) + /// + public static PointF Empty => new(0f, 0f); + + /// + /// The X value + /// + public float X { get; set; } + + /// + /// The Y value + /// + public float Y { get; set; } + + /// + /// Indicates whether the point is at (0, 0) + /// + public bool IsEmpty => X == 0f && Y == 0f; + + /// + /// Creates a new PointF struct + /// + /// The X value + /// The Y value + public PointF(float x = 0f, float y = 0f) + { + X = x; + Y = y; + } + + /// + /// Creates a PointF from a SizeF + /// + /// The SizeF instance + /// A new PointF with X and Y from the SizeF + public static PointF From(SizeF size) + { + return new PointF(size.Width, size.Height); + } + + /// + /// Offsets the point by specified amounts + /// + /// The amount to offset X + /// The amount to offset Y + public void Offset(float x, float y) + { + X += x; + Y += y; + } + + /// + /// Offsets the point by another PointF + /// + /// The PointF to offset by + public void Offset(PointF point) + { + X += point.X; + Y += point.Y; + } + + /// + /// Adds two PointF instances + /// + public static PointF operator +(PointF point, PointF amount) + { + return new PointF(point.X + amount.X, point.Y + amount.Y); + } + + /// + /// Subtracts one PointF from another + /// + public static PointF operator -(PointF point, PointF amount) + { + return new PointF(point.X - amount.X, point.Y - amount.Y); + } + + /// + /// Compares two PointF instances for equality + /// + public static bool operator ==(PointF left, PointF right) + { + return left.Equals(right); + } + + /// + /// Compares two PointF instances for inequality + /// + public static bool operator !=(PointF left, PointF right) + { + return !left.Equals(right); + } + + /// + /// Checks if this instance is equal to another object + /// + public override bool Equals(object obj) + { + if (obj is PointF point) + { + return X == point.X && Y == point.Y; + } + return false; + } + + /// + /// Gets the hash code for this instance + /// + public override int GetHashCode() + { + return X.GetHashCode() ^ Y.GetHashCode(); + } + + /// + /// Returns a string representation of the point + /// + public override string ToString() + { + return $"X: {X}, Y: {Y}"; + } + } +} \ No newline at end of file From 25b17646995ecfa19bc26c83801fd2be807df87f Mon Sep 17 00:00:00 2001 From: Adrian Stevens Date: Thu, 12 Sep 2024 16:32:35 -0700 Subject: [PATCH 4/4] Fix logic when drawing stroked angled lines --- .../Driver/MicroGraphics.cs | 111 ++++++++++++++---- 1 file changed, 89 insertions(+), 22 deletions(-) diff --git a/Source/Meadow.Foundation.Libraries_and_Frameworks/Graphics.MicroGraphics/Driver/MicroGraphics.cs b/Source/Meadow.Foundation.Libraries_and_Frameworks/Graphics.MicroGraphics/Driver/MicroGraphics.cs index de1167f068..cc1d44fcab 100644 --- a/Source/Meadow.Foundation.Libraries_and_Frameworks/Graphics.MicroGraphics/Driver/MicroGraphics.cs +++ b/Source/Meadow.Foundation.Libraries_and_Frameworks/Graphics.MicroGraphics/Driver/MicroGraphics.cs @@ -2,6 +2,8 @@ using Meadow.Peripherals.Displays; using Meadow.Units; using System; +using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; namespace Meadow.Foundation.Graphics @@ -316,9 +318,88 @@ public void DrawLine(int x0, int y0, int x1, int y1) DrawLine(x0, y0, x1, y1, PenColor); } - private bool IsTallerThanWide(int x0, int y0, int x1, int y1) + private void DrawThickLine(float x0, float y0, float x1, float y1, int thickness, Color color) { - return Math.Abs(x0 - x1) < Math.Abs(y0 - y1); + // Calculate the direction vector of the line + float dx = x1 - x0; + float dy = y1 - y0; + float length = MathF.Sqrt(dx * dx + dy * dy); + + if (length == 0) + { + // Avoid division by zero + return; + } + + // Normalize the direction vector + dx /= length; + dy /= length; + + // Calculate the perpendicular vector + float px = -dy; + float py = dx; + + // Scale the perpendicular vector by half the thickness + float halfThickness = thickness / 2.0f; + px *= halfThickness; + py *= halfThickness; + + // Calculate the four corners of the thick line's quadrilateral + var p1 = new PointF(x0 + px, y0 + py); + var p2 = new PointF(x1 + px, y1 + py); + var p3 = new PointF(x1 - px, y1 - py); + var p4 = new PointF(x0 - px, y0 - py); + + // Define the points of the polygon + var points = new PointF[] { p1, p2, p3, p4 }; + + // Draw and fill the polygon + DrawFilledPolygon(points, color); + } + + private void DrawFilledPolygon(PointF[] points, Color color) + { + // Convert PointF to Point by rounding to nearest integer + var integerPoints = points.Select(p => new Point((int)Math.Round(p.X), (int)Math.Round(p.Y))).ToArray(); + + // Proceed with polygon filling using integer coordinates + FillPolygon(integerPoints, color); + } + + private void FillPolygon(Point[] points, Color color) + { + // Find the bounding box of the polygon + int minY = points.Min(p => p.Y); + int maxY = points.Max(p => p.Y); + + // For each scanline between minY and maxY + for (int y = minY; y <= maxY; y++) + { + var nodeX = new List(); + + int j = points.Length - 1; + for (int i = 0; i < points.Length; i++) + { + if ((points[i].Y < y && points[j].Y >= y) || (points[j].Y < y && points[i].Y >= y)) + { + int x = (int)(points[i].X + (float)(y - points[i].Y) / (points[j].Y - points[i].Y) * (points[j].X - points[i].X)); + nodeX.Add(x); + } + j = i; + } + + nodeX.Sort(); + + for (int i = 0; i < nodeX.Count; i += 2) + { + if (i + 1 < nodeX.Count) + { + int xStart = nodeX[i]; + int xEnd = nodeX[i + 1]; + DrawHorizontalLine(xStart, y, xEnd - xStart + 1, color); + } + } + } } /// @@ -367,23 +448,9 @@ public void DrawLine(int x0, int y0, int x1, int y1, Color color) { DrawSingleWidthLine(x0, y0, x1, y1, color); } - else if (IsTallerThanWide(x0, y0, x1, y1)) - { - int xOffset = Stroke >> 1; - - for (int i = 0; i < Stroke; i++) - { - DrawSingleWidthLine(x0 - xOffset + i, y0, x1 - xOffset + i, y1, color); - } - } else { - int yOffset = Stroke >> 1; - - for (int i = 0; i < Stroke; i++) - { - DrawSingleWidthLine(x0, y0 - yOffset + i, x1, y1 - yOffset + i, color); - } + DrawThickLine(x0, y0, x1, y1, Stroke, color); } } @@ -1731,11 +1798,11 @@ public virtual void Show() } isUpdating = true; - } - display?.Show(); + display?.Show(); - isUpdating = false; + isUpdating = false; + } } /// @@ -1947,7 +2014,7 @@ protected void DrawBitmap(int x, int y, int width, int height, byte[] bitmap, Sc /// The non-rotated x position /// The non-rotated y position /// - public int GetXForRotation(int x, int y) + protected int GetXForRotation(int x, int y) { if (display is IRotatableDisplay) { return x; } @@ -1966,7 +2033,7 @@ public int GetXForRotation(int x, int y) /// The non-rotated x position /// The non-rotated y position /// - public int GetYForRotation(int x, int y) + protected int GetYForRotation(int x, int y) { if (display is IRotatableDisplay) { return y; }