From ca59e2c527cbfb0be86901d55f3c439536193679 Mon Sep 17 00:00:00 2001 From: Vlad Ruzov Date: Sun, 7 Sep 2014 20:33:21 +0400 Subject: [PATCH] Lcd extensions DrawCircle, DrawCircleFilled, DrawEllipse, DrawEllipseFilled, DrawRectangle are added; DrawLine is extracted to the individual Lcd extension class; LcdDrawExample is added. --- LcdDrawExample/ExamplesDialog.cs | 68 ++++++++++++++++ LcdDrawExample/LcdDrawExample.csproj | 44 +++++++++++ LcdDrawExample/Program.cs | 14 ++++ MonoBrick.sln | 16 ++-- MonoBrickFirmware/Display/Lcd.cs | 50 ++++-------- MonoBrickFirmware/Display/LcdDrawCircle.cs | 59 ++++++++++++++ MonoBrickFirmware/Display/LcdDrawEllipse.cs | 79 +++++++++++++++++++ MonoBrickFirmware/Display/LcdDrawLine.cs | 41 ++++++++++ MonoBrickFirmware/Display/LcdDrawRectangle.cs | 38 +++++++++ MonoBrickFirmware/MonoBrickFirmware.csproj | 5 ++ 10 files changed, 374 insertions(+), 40 deletions(-) create mode 100644 LcdDrawExample/ExamplesDialog.cs create mode 100644 LcdDrawExample/LcdDrawExample.csproj create mode 100644 LcdDrawExample/Program.cs create mode 100644 MonoBrickFirmware/Display/LcdDrawCircle.cs create mode 100644 MonoBrickFirmware/Display/LcdDrawEllipse.cs create mode 100644 MonoBrickFirmware/Display/LcdDrawLine.cs create mode 100644 MonoBrickFirmware/Display/LcdDrawRectangle.cs diff --git a/LcdDrawExample/ExamplesDialog.cs b/LcdDrawExample/ExamplesDialog.cs new file mode 100644 index 0000000..ed19102 --- /dev/null +++ b/LcdDrawExample/ExamplesDialog.cs @@ -0,0 +1,68 @@ +using System; +using MonoBrickFirmware.Display; +using MonoBrickFirmware.Display.Dialogs; + +namespace LcdDraw +{ + public class ExamplesDialog: Dialog{ + + private int _currentScreen; + private Point _center; + + public ExamplesDialog(string title) : + base(Font.MediumFont, title, Lcd.Width, Lcd.Height-(int)Font.MediumFont.maxHeight) + { + _currentScreen = 1; + _center = new Point (Lcd.Width / 2, Lcd.Height / 2); + } + + protected override bool OnEnterAction () + { + _currentScreen = (_currentScreen == 1 ? 2 : 1); + Lcd.Instance.Clear (); + + return false; // no exit + } + + protected override bool OnEscape() + { + return true; // exit + } + + protected override void OnDrawContent () + { + if (_currentScreen == 1) + DrawFirstScreen (); + else + DrawSecondScreen (); + } + + private void DrawFirstScreen() + { + Lcd.Instance.DrawLine( new Point (0, 0), new Point (Lcd.Width-1, Lcd.Height-1), true); + Lcd.Instance.DrawLine( new Point (0, Lcd.Height-1), new Point (Lcd.Width-1, 0), true); + Lcd.Instance.DrawLine( new Point (40, 40), new Point (Lcd.Width-40, Lcd.Height-40), true); + Lcd.Instance.DrawLine( new Point (40, 100), new Point (Lcd.Width-20, Lcd.Height-60), true); + + Lcd.Instance.DrawCircle (_center, 60, true); + Lcd.Instance.DrawCircle (_center, 50, true); + Lcd.Instance.DrawCircle (_center, 40, true); + Lcd.Instance.DrawCircleFilled (_center, 30, true); + Lcd.Instance.DrawCircleFilled (_center, 20, false); + Lcd.Instance.DrawCircleFilled (_center, 10, true); + + Lcd.Instance.DrawEllipse (_center, 60, 30, true); + } + + private void DrawSecondScreen() + { + Lcd.Instance.DrawEllipseFilled (_center, 60, 30, true); + Lcd.Instance.DrawEllipseFilled (new Point(0, Lcd.Height/2) , 60, 30, false); + + var r = new Rectangle (new Point (15, 28), new Point (Lcd.Width - 15, Lcd.Height - 25)); + Lcd.Instance.DrawRectangle (r, true); + } + + } +} + diff --git a/LcdDrawExample/LcdDrawExample.csproj b/LcdDrawExample/LcdDrawExample.csproj new file mode 100644 index 0000000..f8eb687 --- /dev/null +++ b/LcdDrawExample/LcdDrawExample.csproj @@ -0,0 +1,44 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {2730A667-E9ED-4CA7-8281-CF04EB9707BC} + Exe + LcdDrawExample + LcdDrawExample + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + true + + + true + bin\Release + prompt + 4 + true + + + + + {67261E03-D263-4C42-A5AD-2A4820231B28} + MonoBrickFirmware + + + + + + + + + + \ No newline at end of file diff --git a/LcdDrawExample/Program.cs b/LcdDrawExample/Program.cs new file mode 100644 index 0000000..3fba88c --- /dev/null +++ b/LcdDrawExample/Program.cs @@ -0,0 +1,14 @@ +using System; +using MonoBrickFirmware.Display.Dialogs; + +namespace LcdDraw +{ + public class Program + { + public static void Main (string[] args) + { + var examplesDialog = new ExamplesDialog ("Draw example"); + examplesDialog.Show (); + } + } +} \ No newline at end of file diff --git a/MonoBrick.sln b/MonoBrick.sln index 48cbd14..69a39b6 100644 --- a/MonoBrick.sln +++ b/MonoBrick.sln @@ -52,6 +52,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution version.txt = version.txt EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LcdDrawExample", "LcdDrawExample\LcdDrawExample.csproj", "{2730A667-E9ED-4CA7-8281-CF04EB9707BC}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -72,6 +74,14 @@ Global {11C84BA4-9A8A-4BF2-AA7B-2D45AC63ACAE}.Release|Any CPU.ActiveCfg = Release|x86 {11C84BA4-9A8A-4BF2-AA7B-2D45AC63ACAE}.Release|x86.ActiveCfg = Release|x86 {11C84BA4-9A8A-4BF2-AA7B-2D45AC63ACAE}.Release|x86.Build.0 = Release|x86 + {2730A667-E9ED-4CA7-8281-CF04EB9707BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2730A667-E9ED-4CA7-8281-CF04EB9707BC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2730A667-E9ED-4CA7-8281-CF04EB9707BC}.Debug|x86.ActiveCfg = Debug|Any CPU + {2730A667-E9ED-4CA7-8281-CF04EB9707BC}.Debug|x86.Build.0 = Debug|Any CPU + {2730A667-E9ED-4CA7-8281-CF04EB9707BC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2730A667-E9ED-4CA7-8281-CF04EB9707BC}.Release|Any CPU.Build.0 = Release|Any CPU + {2730A667-E9ED-4CA7-8281-CF04EB9707BC}.Release|x86.ActiveCfg = Release|Any CPU + {2730A667-E9ED-4CA7-8281-CF04EB9707BC}.Release|x86.Build.0 = Release|Any CPU {314570C2-D0F1-45D2-868D-FA54E2F538F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {314570C2-D0F1-45D2-868D-FA54E2F538F8}.Debug|Any CPU.Build.0 = Debug|Any CPU {314570C2-D0F1-45D2-868D-FA54E2F538F8}.Debug|x86.ActiveCfg = Debug|Any CPU @@ -87,7 +97,6 @@ Global {3FCBF457-301A-4F4E-B2E2-D6D2C680FDAC}.Release|x86.ActiveCfg = Release|x86 {3FCBF457-301A-4F4E-B2E2-D6D2C680FDAC}.Release|x86.Build.0 = Release|x86 {46A2BC89-7B2D-40CC-84D2-67A145924A0B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {46A2BC89-7B2D-40CC-84D2-67A145924A0B}.Debug|Any CPU.Build.0 = Debug|Any CPU {46A2BC89-7B2D-40CC-84D2-67A145924A0B}.Debug|x86.ActiveCfg = Debug|Any CPU {46A2BC89-7B2D-40CC-84D2-67A145924A0B}.Debug|x86.Build.0 = Debug|Any CPU {46A2BC89-7B2D-40CC-84D2-67A145924A0B}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -113,7 +122,6 @@ Global {61423DCA-229C-4A9C-B49A-3F2C1432B8F0}.Release|x86.ActiveCfg = Release|x86 {61423DCA-229C-4A9C-B49A-3F2C1432B8F0}.Release|x86.Build.0 = Release|x86 {640B405A-3BE2-423C-A32F-310EE9C4DFF1}.Debug|Any CPU.ActiveCfg = Debug|x86 - {640B405A-3BE2-423C-A32F-310EE9C4DFF1}.Debug|Any CPU.Build.0 = Debug|x86 {640B405A-3BE2-423C-A32F-310EE9C4DFF1}.Debug|x86.ActiveCfg = Debug|x86 {640B405A-3BE2-423C-A32F-310EE9C4DFF1}.Debug|x86.Build.0 = Debug|x86 {640B405A-3BE2-423C-A32F-310EE9C4DFF1}.Release|Any CPU.ActiveCfg = Release|x86 @@ -121,7 +129,6 @@ Global {640B405A-3BE2-423C-A32F-310EE9C4DFF1}.Release|x86.ActiveCfg = Release|x86 {640B405A-3BE2-423C-A32F-310EE9C4DFF1}.Release|x86.Build.0 = Release|x86 {64CFD3F7-4F67-4353-9617-BA4804A2F389}.Debug|Any CPU.ActiveCfg = Debug|x86 - {64CFD3F7-4F67-4353-9617-BA4804A2F389}.Debug|Any CPU.Build.0 = Debug|x86 {64CFD3F7-4F67-4353-9617-BA4804A2F389}.Debug|x86.ActiveCfg = Debug|x86 {64CFD3F7-4F67-4353-9617-BA4804A2F389}.Debug|x86.Build.0 = Debug|x86 {64CFD3F7-4F67-4353-9617-BA4804A2F389}.Release|Any CPU.ActiveCfg = Release|x86 @@ -129,13 +136,13 @@ Global {64CFD3F7-4F67-4353-9617-BA4804A2F389}.Release|x86.ActiveCfg = Release|x86 {64CFD3F7-4F67-4353-9617-BA4804A2F389}.Release|x86.Build.0 = Release|x86 {67261E03-D263-4C42-A5AD-2A4820231B28}.Debug|Any CPU.ActiveCfg = Debug|x86 + {67261E03-D263-4C42-A5AD-2A4820231B28}.Debug|Any CPU.Build.0 = Debug|x86 {67261E03-D263-4C42-A5AD-2A4820231B28}.Debug|x86.ActiveCfg = Debug|x86 {67261E03-D263-4C42-A5AD-2A4820231B28}.Debug|x86.Build.0 = Debug|x86 {67261E03-D263-4C42-A5AD-2A4820231B28}.Release|Any CPU.ActiveCfg = Release|x86 {67261E03-D263-4C42-A5AD-2A4820231B28}.Release|x86.ActiveCfg = Release|x86 {67261E03-D263-4C42-A5AD-2A4820231B28}.Release|x86.Build.0 = Release|x86 {75E781D0-7313-445B-8430-DECB0AD3C96E}.Debug|Any CPU.ActiveCfg = Debug|x86 - {75E781D0-7313-445B-8430-DECB0AD3C96E}.Debug|Any CPU.Build.0 = Debug|x86 {75E781D0-7313-445B-8430-DECB0AD3C96E}.Debug|x86.ActiveCfg = Debug|x86 {75E781D0-7313-445B-8430-DECB0AD3C96E}.Debug|x86.Build.0 = Debug|x86 {75E781D0-7313-445B-8430-DECB0AD3C96E}.Release|Any CPU.ActiveCfg = Release|x86 @@ -188,7 +195,6 @@ Global {E069E7FC-8331-40B1-BB45-119E02210B96}.Release|x86.ActiveCfg = Release|x86 {E069E7FC-8331-40B1-BB45-119E02210B96}.Release|x86.Build.0 = Release|x86 {E5C67E4C-5BDE-419A-9014-241E4FCFD2E8}.Debug|Any CPU.ActiveCfg = Debug|x86 - {E5C67E4C-5BDE-419A-9014-241E4FCFD2E8}.Debug|Any CPU.Build.0 = Debug|x86 {E5C67E4C-5BDE-419A-9014-241E4FCFD2E8}.Debug|x86.ActiveCfg = Debug|x86 {E5C67E4C-5BDE-419A-9014-241E4FCFD2E8}.Debug|x86.Build.0 = Debug|x86 {E5C67E4C-5BDE-419A-9014-241E4FCFD2E8}.Release|Any CPU.ActiveCfg = Release|x86 diff --git a/MonoBrickFirmware/Display/Lcd.cs b/MonoBrickFirmware/Display/Lcd.cs index 1d6c705..9838cde 100644 --- a/MonoBrickFirmware/Display/Lcd.cs +++ b/MonoBrickFirmware/Display/Lcd.cs @@ -30,8 +30,21 @@ public enum Alignment { Left, Center, Right }; private static readonly Lcd instance = new Lcd(); + public static bool IsPixelInLcd(Point pixel) + { + return (pixel.X >= 0) && (pixel.Y >= 0) && (pixel.X <= Lcd.Width) && (pixel.Y <= Lcd.Height); + } + + public static bool IsPixelInLcd(int x, int y) + { + return (x >= 0) && (y >= 0) && (x <= Lcd.Width) && (y <= Lcd.Height); + } + public void SetPixel(int x, int y, bool color) { + if (!IsPixelInLcd (x, y)) + return; + int index = (x/8)+ y * bytesPrLine; int bit = x & 0x7; if (color) @@ -46,7 +59,7 @@ public enum ArrowOrientation{Left, Right, Down, Up} public bool IsPixelSet (int x, int y) { - int index = (x / 8) + y * 23; + int index = (x / 8) + y * bytesPrLine; int bit = x & 0x7; return (displayBuf[index] & (1 << bit)) != 0; } @@ -172,45 +185,12 @@ public void DrawBox(Rectangle r, bool setOrClear) for (int y = r.P1.Y; y <= r.P2.Y; ++y) DrawHLine(new Point(r.P1.X, y), length, setOrClear); } - + public void DrawBitmap(Bitmap bm, Point p) { DrawBitmap(bm.GetStream(), p, bm.Width, bm.Height, true); } - public void DrawLine (Point start, Point end, bool color) - { - int height = Math.Abs (end.Y - start.Y); - int width = Math.Abs (end.X - start.X); - - int ix = start.X; - int iy = start.Y; - int sx = start.X < end.X ? 1 : -1; - int sy = start.Y < end.Y ? 1 : -1; - - int err = width + (-height); - int e2; - - do { - SetPixel (ix, iy, color); - - if (ix == end.X && iy == end.Y) - break; - - e2 = 2 * err; - if (e2 > (-height)) { - err += (-height); - ix += sx; - } - if (e2 < width) { - err += width; - iy += sy; - } - - } while (true); - - } - public void DrawBitmap(BitStreamer bs, Point p, uint xsize, uint ysize, bool color) { for (int yPos = p.Y; yPos != p.Y+ysize; yPos++) diff --git a/MonoBrickFirmware/Display/LcdDrawCircle.cs b/MonoBrickFirmware/Display/LcdDrawCircle.cs new file mode 100644 index 0000000..5ffb549 --- /dev/null +++ b/MonoBrickFirmware/Display/LcdDrawCircle.cs @@ -0,0 +1,59 @@ +using System; + +namespace MonoBrickFirmware.Display +{ + public static class DrawCircleLcdExtension + { + + public static void DrawCircle (this Lcd lcd, Point center, ushort radius, bool color) + { + int f = 1 - radius; + int ddF_x = 0; + int ddF_y = -2 * radius; + int x = 0; + int y = radius; + + var right = new Point(center.X + radius, center.Y); + var top = new Point (center.X, center.Y - radius); + var left = new Point (center.X - radius, center.Y); + var bottom = new Point(center.X, center.Y + radius); + + lcd.SetPixel (right.X, right.Y, color); + lcd.SetPixel (top.X, top.Y, color); + lcd.SetPixel (left.X, left.Y, color); + lcd.SetPixel (bottom.X, bottom.Y, color); + + while (x < y) { + if (f >= 0) { + y--; + ddF_y += 2; + f += ddF_y; + } + x++; + ddF_x += 2; + f += ddF_x + 1; + + lcd.SetPixel (center.X + x, center.Y + y, color); + lcd.SetPixel (center.X - x, center.Y + y, color); + lcd.SetPixel (center.X + x, center.Y - y, color); + lcd.SetPixel (center.X - x, center.Y - y, color); + lcd.SetPixel (center.X + y, center.Y + x, color); + lcd.SetPixel (center.X - y, center.Y + x, color); + lcd.SetPixel (center.X + y, center.Y - x, color); + lcd.SetPixel (center.X - y, center.Y - x, color); + } + } + + public static void DrawCircleFilled (this Lcd lcd, Point center, ushort radius, bool color) + { + for (int y = -radius; y <= radius; y++) { + for (int x = -radius; x <= radius; x++) { + if (x * x + y * y <= radius * radius) { + lcd.SetPixel (center.X + x, center.Y + y, color); + } + } + } + } + + } +} diff --git a/MonoBrickFirmware/Display/LcdDrawEllipse.cs b/MonoBrickFirmware/Display/LcdDrawEllipse.cs new file mode 100644 index 0000000..13d12e5 --- /dev/null +++ b/MonoBrickFirmware/Display/LcdDrawEllipse.cs @@ -0,0 +1,79 @@ +using System; + +namespace MonoBrickFirmware.Display +{ + public static class DraeEllipseLcdExtension + { + + public static void DrawEllipse(this Lcd lcd, Point center, ushort radiusA, ushort radiusB, bool color) + { + + int dx = 0; + int dy = radiusB; + int a2 = radiusA * radiusA; + int b2 = radiusB * radiusB; + int err = b2 - (2 * radiusB - 1) * a2; + int e2; + + do { + lcd.SetPixel(center.X + dx, center.Y + dy, color); /* I. Quadrant */ + lcd.SetPixel(center.X - dx, center.Y + dy, color); /* II. Quadrant */ + lcd.SetPixel(center.X - dx, center.Y - dy, color); /* III. Quadrant */ + lcd.SetPixel(center.X + dx, center.Y - dy, color); /* IV. Quadrant */ + + e2 = 2 * err; + + if (e2 < (2 * dx + 1) * b2) + { + dx++; + err += (2 * dx + 1) * b2; + } + + if (e2 > -(2 * dy - 1) * a2) + { + dy--; + err -= (2 * dy - 1) * a2; + } + } while (dy >= 0); + + while (dx++ < radiusA) + { + lcd.SetPixel(center.X + dx, center.Y, color); + lcd.SetPixel(center.X - dx, center.Y, color); + } + } + + public static void DrawEllipseFilled + (this Lcd lcd, Point center, ushort radiusA, ushort radiusB, bool color) + { + int hh = radiusB * radiusB; + int ww = radiusA * radiusA; + int hhww = hh * ww; + int x0 = radiusA; + int dx = 0; + + // do the horizontal diameter + for (int x = -radiusA; x <= radiusA; x++) + lcd.SetPixel(center.X + x, center.Y, color); + + // now do both halves at the same time, away from the diameter + for (int y = 1; y <= radiusB; y++) + { + int x1 = x0 - (dx - 1); // try slopes of dx - 1 or more + + for (; x1 > 0; x1--) + if (x1 * x1 * hh + y * y * ww <= hhww) + break; + + dx = x0 - x1; // current approximation of the slope + x0 = x1; + + for (int x = -x0; x <= x0; x++) { + lcd.SetPixel(center.X + x, center.Y - y, color); + lcd.SetPixel(center.X + x, center.Y + y, color); + } + } + } + + } +} diff --git a/MonoBrickFirmware/Display/LcdDrawLine.cs b/MonoBrickFirmware/Display/LcdDrawLine.cs new file mode 100644 index 0000000..b7f746a --- /dev/null +++ b/MonoBrickFirmware/Display/LcdDrawLine.cs @@ -0,0 +1,41 @@ +using System; + +namespace MonoBrickFirmware.Display +{ + public static class DrawLineLcdExtension + { + + public static void DrawLine (this Lcd lcd, Point start, Point end, bool color) + { + int height = Math.Abs (end.Y - start.Y); + int width = Math.Abs (end.X - start.X); + + int ix = start.X; + int iy = start.Y; + int sx = start.X < end.X ? 1 : -1; + int sy = start.Y < end.Y ? 1 : -1; + + int err = width + (-height); + int e2; + + do { + lcd.SetPixel (ix, iy, color); + + if (ix == end.X && iy == end.Y) + break; + + e2 = 2 * err; + if (e2 > (-height)) { + err += (-height); + ix += sx; + } + if (e2 < width) { + err += width; + iy += sy; + } + + } while (true); + } + + } +} diff --git a/MonoBrickFirmware/Display/LcdDrawRectangle.cs b/MonoBrickFirmware/Display/LcdDrawRectangle.cs new file mode 100644 index 0000000..8e749cc --- /dev/null +++ b/MonoBrickFirmware/Display/LcdDrawRectangle.cs @@ -0,0 +1,38 @@ +using System; + +namespace MonoBrickFirmware.Display +{ + public static class DrawRectangleLcdExtension + { + + public static void DrawRectangle(this Lcd lcd, Rectangle r, bool color) + { + int length = r.P2.X - r.P1.X; + int height = r.P2.Y - r.P1.Y; + + DrawHLineInLcd(lcd, new Point(r.P1.X, r.P1.Y), length, color); + DrawHLineInLcd(lcd, new Point(r.P1.X, r.P2.Y), length, color); + + DrawVLineInLcd(lcd, new Point(r.P1.X, r.P1.Y+1), height-2, color); + DrawVLineInLcd(lcd, new Point(r.P2.X, r.P1.Y+1), height-2, color); + } + + private static void DrawHLineInLcd(Lcd lcd, Point startPoint, int length, bool color) + { + for (var x = 0; x <= length; x++) { + lcd.SetPixel (startPoint.X + x, startPoint.Y, color); + } + + } + + private static void DrawVLineInLcd(Lcd lcd, Point startPoint, int height, bool color) + { + for (var y = 0; y <= height; y++) { + lcd.SetPixel (startPoint.X, startPoint.Y + y, color); + } + + } + + + } +} diff --git a/MonoBrickFirmware/MonoBrickFirmware.csproj b/MonoBrickFirmware/MonoBrickFirmware.csproj index 369d021..a745100 100644 --- a/MonoBrickFirmware/MonoBrickFirmware.csproj +++ b/MonoBrickFirmware/MonoBrickFirmware.csproj @@ -9,6 +9,7 @@ Library MonoBrickFirmware MonoBrickFirmware + False true @@ -119,6 +120,10 @@ + + + +