Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Line stroke #1075

Merged
merged 4 commits into from
Sep 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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>();

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);
}
}
}
}

/// <summary>
Expand Down Expand Up @@ -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);
}
}

Expand Down Expand Up @@ -1731,11 +1798,11 @@ public virtual void Show()
}

isUpdating = true;
}

display?.Show();
display?.Show();

isUpdating = false;
isUpdating = false;
}
}

/// <summary>
Expand Down Expand Up @@ -1947,7 +2014,7 @@ protected void DrawBitmap(int x, int y, int width, int height, byte[] bitmap, Sc
/// <param name="x">The non-rotated x position</param>
/// <param name="y">The non-rotated y position</param>
/// <returns></returns>
public int GetXForRotation(int x, int y)
protected int GetXForRotation(int x, int y)
{
if (display is IRotatableDisplay) { return x; }

Expand All @@ -1966,7 +2033,7 @@ public int GetXForRotation(int x, int y)
/// <param name="x">The non-rotated x position</param>
/// <param name="y">The non-rotated y position</param>
/// <returns></returns>
public int GetYForRotation(int x, int y)
protected int GetYForRotation(int x, int y)
{
if (display is IRotatableDisplay) { return y; }

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
using System.Drawing;

namespace Meadow.Foundation.Graphics
{
/// <summary>
/// Represents a 2D point with floating-point coordinates
/// </summary>
public struct PointF
{
/// <summary>
/// Gets an empty point at (0, 0)
/// </summary>
public static PointF Empty => new(0f, 0f);

/// <summary>
/// The X value
/// </summary>
public float X { get; set; }

/// <summary>
/// The Y value
/// </summary>
public float Y { get; set; }

/// <summary>
/// Indicates whether the point is at (0, 0)
/// </summary>
public bool IsEmpty => X == 0f && Y == 0f;

/// <summary>
/// Creates a new PointF struct
/// </summary>
/// <param name="x">The X value</param>
/// <param name="y">The Y value</param>
public PointF(float x = 0f, float y = 0f)
{
X = x;
Y = y;
}

/// <summary>
/// Creates a PointF from a SizeF
/// </summary>
/// <param name="size">The SizeF instance</param>
/// <returns>A new PointF with X and Y from the SizeF</returns>
public static PointF From(SizeF size)
{
return new PointF(size.Width, size.Height);
}

/// <summary>
/// Offsets the point by specified amounts
/// </summary>
/// <param name="x">The amount to offset X</param>
/// <param name="y">The amount to offset Y</param>
public void Offset(float x, float y)
{
X += x;
Y += y;
}

/// <summary>
/// Offsets the point by another PointF
/// </summary>
/// <param name="point">The PointF to offset by</param>
public void Offset(PointF point)
{
X += point.X;
Y += point.Y;
}

/// <summary>
/// Adds two PointF instances
/// </summary>
public static PointF operator +(PointF point, PointF amount)
{
return new PointF(point.X + amount.X, point.Y + amount.Y);
}

/// <summary>
/// Subtracts one PointF from another
/// </summary>
public static PointF operator -(PointF point, PointF amount)
{
return new PointF(point.X - amount.X, point.Y - amount.Y);
}

/// <summary>
/// Compares two PointF instances for equality
/// </summary>
public static bool operator ==(PointF left, PointF right)
{
return left.Equals(right);
}

/// <summary>
/// Compares two PointF instances for inequality
/// </summary>
public static bool operator !=(PointF left, PointF right)
{
return !left.Equals(right);
}

/// <summary>
/// Checks if this instance is equal to another object
/// </summary>
public override bool Equals(object obj)
{
if (obj is PointF point)
{
return X == point.X && Y == point.Y;
}
return false;
}

/// <summary>
/// Gets the hash code for this instance
/// </summary>
public override int GetHashCode()
{
return X.GetHashCode() ^ Y.GetHashCode();
}

/// <summary>
/// Returns a string representation of the point
/// </summary>
public override string ToString()
{
return $"X: {X}, Y: {Y}";
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ namespace Meadow.Foundation.ICs.CAN;
/// </summary>
public partial class Mcp2515 : ICanController
{
/// <summary>
/// Default SPI clock mode for the MCP2515
/// </summary>
public const SpiClockConfiguration.Mode DefaultSpiMode = SpiClockConfiguration.Mode.Mode0;

private byte BRP_Default = 0x01;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ namespace Meadow.Foundation.ICs.IOExpanders;

public abstract partial class FtdiExpander
{
/// <summary>
/// Represents an Ft232h expander I2C bus.
/// </summary>
public class Ft232hI2cBus : I2CBus
{
internal Ft232hI2cBus(FtdiExpander expander, I2cBusSpeed busSpeed)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ namespace Meadow.Foundation.ICs.IOExpanders;

public abstract partial class FtdiExpander
{
/// <summary>
/// Represents an FTDI expander I2C bus.
/// </summary>
public class Ft23xxI2cBus : I2CBus, II2cBus
{
internal Ft23xxI2cBus(FtdiExpander expander, I2cBusSpeed busSpeed)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@

namespace Meadow.Foundation.ICs.IOExpanders;

/// <summary>
/// Represents a collection of FtdiExpander devices connected to the host machine.
/// </summary>
public class FtdiExpanderCollection : IEnumerable<FtdiExpander>
{
private static FtdiExpanderCollection? _instance;
Expand All @@ -28,10 +31,12 @@ private FtdiExpanderCollection()
{
}

/// <summary>
/// Refresh the collection of FtdiExpander devices connected to the host machine.
/// </summary>
public void Refresh()
{
Native.CheckStatus(
Native.Ftd2xx.FT_CreateDeviceInfoList(out uint count));
Native.CheckStatus(Native.Ftd2xx.FT_CreateDeviceInfoList(out uint count));

_expanders.Clear();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using Meadow.Foundation.Sensors.Location.Gnss;
using Meadow.Peripherals.Sensors.Location.Gnss;
using System;

namespace Meadow.Foundation.Sensors.Gnss
{
Expand All @@ -9,11 +8,6 @@ namespace Meadow.Foundation.Sensors.Gnss
/// </summary>
public class MtkDecoder : INmeaDecoder
{
/// <summary>
/// Event raised when a message is received
/// </summary>
public event EventHandler<string> MessageReceived = default!;

/// <summary>
/// Friendly name for the MTK messages.
/// </summary>
Expand Down
Loading