From c899e5922b69a498b91cab60cdce80aeb02a7419 Mon Sep 17 00:00:00 2001 From: 0xFEEDC0DE64 Date: Fri, 12 Jun 2020 22:22:52 +0200 Subject: [PATCH] Refactored vu meter into own widget class --- src/displays/metersdisplay.h | 150 ++--------------------------------- src/widgets/verticalmeter.h | 2 + src/widgets/vumeter.h | 145 +++++++++++++++++++++++++++++++++ 3 files changed, 154 insertions(+), 143 deletions(-) create mode 100644 src/widgets/vumeter.h diff --git a/src/displays/metersdisplay.h b/src/displays/metersdisplay.h index 5b42ab7..4395471 100644 --- a/src/displays/metersdisplay.h +++ b/src/displays/metersdisplay.h @@ -9,6 +9,7 @@ #include "globals.h" #include "utils.h" #include "widgets/verticalmeter.h" +#include "widgets/vumeter.h" namespace { class MainMenu; @@ -26,14 +27,9 @@ public: void rotate(int offset) override; private: - // Draw the analogue meter on the screen - void analogMeter(); + VuMeter m_vuMeter; - // Update needle position - void plotNeedle(float value); - - float ltx = 0; // Saved x coord of bottom of needle - uint16_t osx = 120, osy = 120; // Saved x & y coords + int d = 0; static constexpr auto x = 40; std::array meters{{ @@ -44,15 +40,13 @@ private: VerticalMeter{"A4", 4*x, 160}, VerticalMeter{"A5", 5*x, 160} }}; - - int d = 0; }; void MetersDisplay::initScreen() { tft.fillScreen(TFT_BLACK); - analogMeter(); // Draw analogue meter + m_vuMeter.start(); for (auto &meter : meters) meter.start(); @@ -60,16 +54,13 @@ void MetersDisplay::initScreen() void MetersDisplay::redraw() { - plotNeedle(avgSpeedKmh); + m_vuMeter.redraw(avgSpeedKmh); - tft.setTextColor(TFT_GREEN, TFT_BLACK); - - d += 4; if (d >= 360) d = 0; - - // Create a Sine wave for testing int i{}; for (auto &meter : meters) meter.redraw(50 + 50 * sin((d + (i++ * 60)) * 0.0174532925)); + + d += 4; if (d >= 360) d -= 360; } void MetersDisplay::rotate(int offset) @@ -83,131 +74,4 @@ void MetersDisplay::rotate(int offset) switchScreen(); #endif } - -void MetersDisplay::analogMeter() -{ - // Meter outline - tft.fillRect(0, 0, 239, 126, TFT_GREY); - tft.fillRect(5, 3, 230, 119, TFT_WHITE); - - tft.setTextColor(TFT_BLACK); // Text colour - - // Draw ticks every 5 degrees from -50 to +50 degrees (100 deg. FSD swing) - for (int i = -50; i < 51; i += 5) { - // Long scale tick length - int tl = 15; - - // Coodinates of tick to draw - float sx = cos((i - 90) * 0.0174532925); - float sy = sin((i - 90) * 0.0174532925); - uint16_t x0 = sx * (100 + tl) + 120; - uint16_t y0 = sy * (100 + tl) + 140; - uint16_t x1 = sx * 100 + 120; - uint16_t y1 = sy * 100 + 140; - - // Coordinates of next tick for zone fill - float sx2 = cos((i + 5 - 90) * 0.0174532925); - float sy2 = sin((i + 5 - 90) * 0.0174532925); - int x2 = sx2 * (100 + tl) + 120; - int y2 = sy2 * (100 + tl) + 140; - int x3 = sx2 * 100 + 120; - int y3 = sy2 * 100 + 140; - - // Yellow zone limits - //if (i >= -50 && i < 0) { - // tft.fillTriangle(x0, y0, x1, y1, x2, y2, TFT_YELLOW); - // tft.fillTriangle(x1, y1, x2, y2, x3, y3, TFT_YELLOW); - //} - - // Green zone limits - if (i >= 0 && i < 25) { - tft.fillTriangle(x0, y0, x1, y1, x2, y2, TFT_GREEN); - tft.fillTriangle(x1, y1, x2, y2, x3, y3, TFT_GREEN); - } - - // Orange zone limits - if (i >= 25 && i < 50) { - tft.fillTriangle(x0, y0, x1, y1, x2, y2, TFT_ORANGE); - tft.fillTriangle(x1, y1, x2, y2, x3, y3, TFT_ORANGE); - } - - // Short scale tick length - if (i % 25 != 0) tl = 8; - - // Recalculate coords incase tick lenght changed - x0 = sx * (100 + tl) + 120; - y0 = sy * (100 + tl) + 140; - x1 = sx * 100 + 120; - y1 = sy * 100 + 140; - - // Draw tick - tft.drawLine(x0, y0, x1, y1, TFT_BLACK); - - // Check if labels should be drawn, with position tweaks - if (i % 25 == 0) { - // Calculate label positions - x0 = sx * (100 + tl + 10) + 120; - y0 = sy * (100 + tl + 10) + 140; - switch (i / 25) { - case -2: tft.drawCentreString("0", x0, y0 - 12, 2); break; - case -1: tft.drawCentreString("7.5", x0, y0 - 9, 2); break; - case 0: tft.drawCentreString("15", x0, y0 - 6, 2); break; - case 1: tft.drawCentreString("22.5", x0, y0 - 9, 2); break; - case 2: tft.drawCentreString("30", x0, y0 - 12, 2); break; - } - } - - // Now draw the arc of the scale - sx = cos((i + 5 - 90) * 0.0174532925); - sy = sin((i + 5 - 90) * 0.0174532925); - x0 = sx * 100 + 120; - y0 = sy * 100 + 140; - // Draw scale arc, don't draw the last part - if (i < 50) tft.drawLine(x0, y0, x1, y1, TFT_BLACK); - } - - tft.drawString("KM/h", 5 + 230 - 40, 119 - 20, 2); // Units at bottom right - tft.drawCentreString("KM/h", 120, 70, 4); // Comment out to avoid font 4 - tft.drawRect(5, 3, 230, 119, TFT_BLACK); // Draw bezel line - - plotNeedle(0.f); // Put meter needle at 0 -} - -void MetersDisplay::plotNeedle(float value) -{ - tft.setTextColor(TFT_BLACK, TFT_WHITE); - char buf[8]; dtostrf(value, 4, 0, buf); - tft.drawRightString(buf, 50, 119 - 25, 4); - - if (value < -3) value = -3; // Limit value to emulate needle end stops - if (value > 33) value = 33; - - float sdeg = map(value, -3, 33, -150, -30); // Map value to angle - // Calcualte tip of needle coords - float sx = cos(sdeg * 0.0174532925); - float sy = sin(sdeg * 0.0174532925); - - // Calculate x delta of needle start (does not start at pivot point) - float tx = tan((sdeg + 90) * 0.0174532925); - - // Erase old needle image - tft.drawLine(120 + 20 * ltx - 1, 140 - 20, osx - 1, osy, TFT_WHITE); - tft.drawLine(120 + 20 * ltx, 140 - 20, osx, osy, TFT_WHITE); - tft.drawLine(120 + 20 * ltx + 1, 140 - 20, osx + 1, osy, TFT_WHITE); - - // Re-plot text under needle - tft.setTextColor(TFT_BLACK); - tft.drawCentreString("KM/h", 120, 70, 4); // // Comment out to avoid font 4 - - // Store new needle end coords for next erase - ltx = tx; - osx = sx * 98 + 120; - osy = sy * 98 + 140; - - // Draw the needle in the new postion, magenta makes needle a bit bolder - // draws 3 lines to thicken needle - tft.drawLine(120 + 20 * ltx - 1, 140 - 20, osx - 1, osy, TFT_RED); - tft.drawLine(120 + 20 * ltx, 140 - 20, osx, osy, TFT_MAGENTA); - tft.drawLine(120 + 20 * ltx + 1, 140 - 20, osx + 1, osy, TFT_RED); -} } diff --git a/src/widgets/verticalmeter.h b/src/widgets/verticalmeter.h index a0270b0..9b9de10 100644 --- a/src/widgets/verticalmeter.h +++ b/src/widgets/verticalmeter.h @@ -46,6 +46,8 @@ void VerticalMeter::start() void VerticalMeter::redraw(int value) { + tft.setTextColor(TFT_GREEN, TFT_BLACK); + char buf[8]; dtostrf(value, 4, 0, buf); tft.drawRightString(buf, m_x + 36 - 5, 187 - 27 + 155 - 18, 2); diff --git a/src/widgets/vumeter.h b/src/widgets/vumeter.h new file mode 100644 index 0000000..a28a4a4 --- /dev/null +++ b/src/widgets/vumeter.h @@ -0,0 +1,145 @@ +#pragma once + +#include "globals.h" + +namespace { +class VuMeter +{ +public: + void start(); + void redraw(float value); + +private: + float ltx; // Saved x coord of bottom of needle + uint16_t osx, osy; // Saved x & y coords +}; + +void VuMeter::start() +{ + ltx = 0; + osx = 120; + osy = 120; + + // Meter outline + tft.fillRect(0, 0, 239, 126, TFT_GREY); + tft.fillRect(5, 3, 230, 119, TFT_WHITE); + + tft.setTextColor(TFT_BLACK); // Text colour + + // Draw ticks every 5 degrees from -50 to +50 degrees (100 deg. FSD swing) + for (int i = -50; i < 51; i += 5) { + // Long scale tick length + int tl = 15; + + // Coodinates of tick to draw + float sx = cos((i - 90) * 0.0174532925); + float sy = sin((i - 90) * 0.0174532925); + uint16_t x0 = sx * (100 + tl) + 120; + uint16_t y0 = sy * (100 + tl) + 140; + uint16_t x1 = sx * 100 + 120; + uint16_t y1 = sy * 100 + 140; + + // Coordinates of next tick for zone fill + float sx2 = cos((i + 5 - 90) * 0.0174532925); + float sy2 = sin((i + 5 - 90) * 0.0174532925); + int x2 = sx2 * (100 + tl) + 120; + int y2 = sy2 * (100 + tl) + 140; + int x3 = sx2 * 100 + 120; + int y3 = sy2 * 100 + 140; + + // Yellow zone limits + //if (i >= -50 && i < 0) { + // tft.fillTriangle(x0, y0, x1, y1, x2, y2, TFT_YELLOW); + // tft.fillTriangle(x1, y1, x2, y2, x3, y3, TFT_YELLOW); + //} + + // Green zone limits + if (i >= 0 && i < 25) { + tft.fillTriangle(x0, y0, x1, y1, x2, y2, TFT_GREEN); + tft.fillTriangle(x1, y1, x2, y2, x3, y3, TFT_GREEN); + } + + // Orange zone limits + if (i >= 25 && i < 50) { + tft.fillTriangle(x0, y0, x1, y1, x2, y2, TFT_ORANGE); + tft.fillTriangle(x1, y1, x2, y2, x3, y3, TFT_ORANGE); + } + + // Short scale tick length + if (i % 25 != 0) tl = 8; + + // Recalculate coords incase tick lenght changed + x0 = sx * (100 + tl) + 120; + y0 = sy * (100 + tl) + 140; + x1 = sx * 100 + 120; + y1 = sy * 100 + 140; + + // Draw tick + tft.drawLine(x0, y0, x1, y1, TFT_BLACK); + + // Check if labels should be drawn, with position tweaks + if (i % 25 == 0) { + // Calculate label positions + x0 = sx * (100 + tl + 10) + 120; + y0 = sy * (100 + tl + 10) + 140; + switch (i / 25) { + case -2: tft.drawCentreString("0", x0, y0 - 12, 2); break; + case -1: tft.drawCentreString("7.5", x0, y0 - 9, 2); break; + case 0: tft.drawCentreString("15", x0, y0 - 6, 2); break; + case 1: tft.drawCentreString("22.5", x0, y0 - 9, 2); break; + case 2: tft.drawCentreString("30", x0, y0 - 12, 2); break; + } + } + + // Now draw the arc of the scale + sx = cos((i + 5 - 90) * 0.0174532925); + sy = sin((i + 5 - 90) * 0.0174532925); + x0 = sx * 100 + 120; + y0 = sy * 100 + 140; + // Draw scale arc, don't draw the last part + if (i < 50) tft.drawLine(x0, y0, x1, y1, TFT_BLACK); + } + + tft.drawString("KM/h", 5 + 230 - 40, 119 - 20, 2); // Units at bottom right + tft.drawCentreString("KM/h", 120, 70, 4); // Comment out to avoid font 4 + tft.drawRect(5, 3, 230, 119, TFT_BLACK); // Draw bezel line +} + +void VuMeter::redraw(float value) +{ + tft.setTextColor(TFT_BLACK, TFT_WHITE); + char buf[8]; dtostrf(value, 4, 0, buf); + tft.drawRightString(buf, 50, 119 - 25, 4); + + if (value < -3) value = -3; // Limit value to emulate needle end stops + if (value > 33) value = 33; + + float sdeg = map(value, -3, 33, -150, -30); // Map value to angle + // Calcualte tip of needle coords + float sx = cos(sdeg * 0.0174532925); + float sy = sin(sdeg * 0.0174532925); + + // Calculate x delta of needle start (does not start at pivot point) + float tx = tan((sdeg + 90) * 0.0174532925); + + // Erase old needle image + tft.drawLine(120 + 20 * ltx - 1, 140 - 20, osx - 1, osy, TFT_WHITE); + tft.drawLine(120 + 20 * ltx, 140 - 20, osx, osy, TFT_WHITE); + tft.drawLine(120 + 20 * ltx + 1, 140 - 20, osx + 1, osy, TFT_WHITE); + + // Re-plot text under needle + tft.setTextColor(TFT_BLACK); + tft.drawCentreString("KM/h", 120, 70, 4); // // Comment out to avoid font 4 + + // Store new needle end coords for next erase + ltx = tx; + osx = sx * 98 + 120; + osy = sy * 98 + 140; + + // Draw the needle in the new postion, magenta makes needle a bit bolder + // draws 3 lines to thicken needle + tft.drawLine(120 + 20 * ltx - 1, 140 - 20, osx - 1, osy, TFT_RED); + tft.drawLine(120 + 20 * ltx, 140 - 20, osx, osy, TFT_MAGENTA); + tft.drawLine(120 + 20 * ltx + 1, 140 - 20, osx + 1, osy, TFT_RED); +} +}