From 41d8b9acb7b0af3181d9c53d529aeaacf837cb33 Mon Sep 17 00:00:00 2001 From: Adrian Stevens Date: Sun, 26 Feb 2023 16:15:07 -0800 Subject: [PATCH] Add DrawArc method and improve DrawCircle when using a stroke > 1 --- .../Driver/MicroGraphics.cs | 105 +++++++++++++++++- 1 file changed, 100 insertions(+), 5 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 1063f504b6..09fd8d7abf 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 @@ -1,5 +1,6 @@ using Meadow.Foundation.Graphics.Buffers; using Meadow.Peripherals.Displays; +using Meadow.Units; using System; using System.Threading.Tasks; @@ -484,6 +485,90 @@ public void DrawVerticalLine(int x, int y, int length, Color color) Fill(x, y - yOffset, width, length, color); } + /// + /// Draw a circular arc between two angles + /// + /// + /// Note that y axis is inversed so the arc will be flipped from the standard cartesian plain + /// + /// Abscissa of the centre point of the circle + /// Ordinate of the centre point of the circle + /// Radius of the circle + /// The arc starting angle + /// The arc ending angle + /// The color of the circle + /// If true, the center of the arc is between the assigned pixel and the next pixel, false it's directly on the center pixel + + public void DrawArc(int centerX, int centerY, int radius, Angle startAngle, Angle endAngle, Color color, bool centerBetweenPixels) + { + var d = 3 - 2 * radius; + var x = 0; + var y = radius; + + int offset = centerBetweenPixels ? 1 : 0; + + var start = new Angle(startAngle.Degrees + 0); + var end = new Angle(endAngle.Degrees + 0); + + int strokeOffset = Stroke / 2; + + if (end < start) + { + end += new Angle(360); + } + + bool IsCoordinateOnArc(int x, int y, int octect) + { + var angle = Math.Atan2(-y, x); + if (angle < 0) { angle += 2 * Math.PI; } + + if (angle >= start.Radians && angle <= end.Radians) + { + return true; + } + return false; + } + + void DrawArcPoint(int x, int y, Color color) + { + if (Stroke == 1) + { + DrawPixel(x, y, color); + } + else + { + DrawCircleFilled(x, y, Stroke / 2, true, color); + } + } + + while (x <= y) + { + if (IsCoordinateOnArc(y, -x, 1)) DrawArcPoint(centerX + y - offset, centerY - x, color); //1 + if (IsCoordinateOnArc(x, -y, 2)) DrawArcPoint(centerX + x - offset, centerY - y, color); //2 + + if (IsCoordinateOnArc(-x, -y, 3)) DrawArcPoint(centerX - x, centerY - y, color); //3 + if (IsCoordinateOnArc(-y, -x, 4)) DrawArcPoint(centerX - y, centerY - x, color); //4 + + if (IsCoordinateOnArc(-y, x, 5)) DrawArcPoint(centerX - y, centerY + x - offset, color); //5 + if (IsCoordinateOnArc(-x, y, 6)) DrawArcPoint(centerX - x, centerY + y - offset, color); //6 + + if (IsCoordinateOnArc(x, y, 7)) DrawArcPoint(centerX + x - offset, centerY + y - offset, color); //7 + if (IsCoordinateOnArc(y, x, 8)) DrawArcPoint(centerX + y - offset, centerY + x - offset, color); //8 + + if (d < 0) + { + d += (2 * x) + 1; + } + else + { + d += (2 * (x - y)) + 1; + y--; + } + x++; + } + + } + /// /// Draw a triangle /// @@ -857,7 +942,7 @@ private void DrawCircleQuadrantOutline(int centerX, int centerY, int radius, int private void DrawCircleOutline(int centerX, int centerY, int radius, bool centerBetweenPixels, Color color) { //I prefer the look of the original Bresenham’s decision param calculation - var d = 3 - 2 * radius; // (5 - (radius * 4)) / 4; + var d = 3 - 2 * radius; var x = 0; var y = radius; @@ -900,10 +985,10 @@ private void DrawCircleFilled(int centerX, int centerY, int radius, bool centerB while (x <= y) { - DrawHorizontalLine(centerX - x, centerY + y - offset, 2 * x - offset, color); - DrawHorizontalLine(centerX - x, centerY - y, 2 * x - offset, color); - DrawHorizontalLine(centerX - y, centerY + x - offset, 2 * y - offset, color); - DrawHorizontalLine(centerX - y, centerY - x, 2 * y - offset, color); + DrawHorizontalLine(centerX - x, centerY + y - offset, 2 * x - offset + 1, color); + DrawHorizontalLine(centerX - x, centerY - y, 2 * x - offset + 1, color); + DrawHorizontalLine(centerX - y, centerY + x - offset, 2 * y - offset + 1, color); + DrawHorizontalLine(centerX - y, centerY - x, 2 * y - offset + 1, color); if (d < 0) { @@ -916,6 +1001,16 @@ private void DrawCircleFilled(int centerX, int centerY, int radius, bool centerB } x++; } + + if (Stroke > 1) + { + offset = Stroke >> 1; + + for (int i = 0; i < Stroke; i++) + { + DrawCircleOutline(centerX, centerY, radius - offset + i, centerBetweenPixels, color); + } + } } ///