diff --git a/TFT_eSPI.cpp b/TFT_eSPI.cpp index a32da1a..0dce6ca 100644 --- a/TFT_eSPI.cpp +++ b/TFT_eSPI.cpp @@ -3895,7 +3895,7 @@ void TFT_eSPI::drawSmoothArc(int32_t x, int32_t y, int32_t r, int32_t ir, int32_ { inTransaction = true; - if (endAngle != startAngle) + if (endAngle != startAngle && (startAngle != 0 || endAngle != 360)) { float sx = -sinf(startAngle * deg2rad); float sy = +cosf(startAngle * deg2rad); @@ -3927,17 +3927,9 @@ void TFT_eSPI::drawSmoothArc(int32_t x, int32_t y, int32_t r, int32_t ir, int32_ drawWedgeLine(asx, asy, aex, aey, 0.3, 0.3, fg_color, bg_color); } - if (endAngle > startAngle) - { - // Draw arc in single sweep - drawArc(x, y, r, ir, startAngle, endAngle, fg_color, bg_color); - } - else - { - // Arc sweeps through 6 o'clock so draw in two parts - drawArc(x, y, r, ir, startAngle, 360, fg_color, bg_color); - drawArc(x, y, r, ir, 0, endAngle, fg_color, bg_color); - } + // Draw arc + drawArc(x, y, r, ir, startAngle, endAngle, fg_color, bg_color); + } else // Draw full 360 { @@ -3949,7 +3941,7 @@ void TFT_eSPI::drawSmoothArc(int32_t x, int32_t y, int32_t r, int32_t ir, int32_ } /*************************************************************************************** -** Function name: sqrt_fraction +** Function name: sqrt_fraction (private function) ** Description: Smooth graphics support function for alpha derivation ***************************************************************************************/ // Compute the fixed point square root of an integer and @@ -3983,7 +3975,7 @@ inline uint8_t TFT_eSPI::sqrt_fraction(uint32_t num) { ***************************************************************************************/ // Centre at x,y // r = arc outer radius, ir = arc inner radius. Inclusive, so arc thickness = r-ir+1 -// Angles MUST be in range 0-360, end angle MUST be greater than start angle +// Angles MUST be in range 0-360 // Arc foreground fg_color anti-aliased with background colour along sides // smooth is optional, default is true, smooth=false means no antialiasing // Note: Arc ends are not anti-aliased (use drawSmoothArc instead for that) @@ -3992,10 +3984,15 @@ void TFT_eSPI::drawArc(int32_t x, int32_t y, int32_t r, int32_t ir, uint32_t fg_color, uint32_t bg_color, bool smooth) { - if (_vpOoB) return; + if (endAngle < startAngle) { + // Arc sweeps through 6 o'clock so draw in two parts + drawArc(x, y, r, ir, startAngle, 360, fg_color, bg_color, smooth); + startAngle = 0; + } + + if (_vpOoB || startAngle == endAngle) return; if (r < ir) transpose(r, ir); // Required that r > ir if (r <= 0 || ir < 0) return; // Invalid r, ir can be zero (circle sector) - if (endAngle < startAngle) transpose(startAngle, endAngle); if (startAngle < 0) startAngle = 0; if (endAngle > 360) endAngle = 360; @@ -4020,8 +4017,8 @@ void TFT_eSPI::drawArc(int32_t x, int32_t y, int32_t r, int32_t ir, // ---¦--- Arc quadrant index // 0 | 3 // Fixed point U16.16 slope table for arc start/end in each quadrant - uint32_t startSlope[4] = {0, 0, 0xFFFFFFFF, 0}; - uint32_t endSlope[4] = {0, 0xFFFFFFFF, 0, 0}; + uint32_t startSlope[4] = {0, 0, 0xFFFFFFFF, 0}; + uint32_t endSlope[4] = {0, 0xFFFFFFFF, 0, 0}; // Ensure maximum U16.16 slope of arc ends is ~ 0x8000 0000 constexpr float minDivisor = 1.0f/0x8000; diff --git a/TFT_eSPI.h b/TFT_eSPI.h index 8065b0f..94cfb80 100644 --- a/TFT_eSPI.h +++ b/TFT_eSPI.h @@ -530,9 +530,9 @@ class TFT_eSPI : public Print { friend class TFT_eSprite; // Sprite class has ac // The start angle may be larger than the end angle. Arcs are always drawn clockwise from the start angle. void drawSmoothArc(int32_t x, int32_t y, int32_t r, int32_t ir, int32_t startAngle, int32_t endAngle, uint32_t fg_color, uint32_t bg_color, bool roundEnds = false); - // As per "drawSmoothArc" except endAngle should be greater than startAngle (angles will be swapped otherwise) + // As per "drawSmoothArc" except the ends of the arc are NOT anti-aliased, this facilitates dynamic arc length changes with + // arc segments and ensures clean segment joints. // The sides of the arc are anti-aliased by default. If smoothArc is false sides will NOT be anti-aliased - // The ends of the arc are NOT anti-aliased, this facilitates dynamic arc length changes with arc segments and ensures clean segment joints void drawArc(int32_t x, int32_t y, int32_t r, int32_t ir, int32_t startAngle, int32_t endAngle, uint32_t fg_color, uint32_t bg_color, bool smoothArc = true); // Draw an anti-aliased filled circle at x, y with radius r diff --git a/examples/Smooth Graphics/Colour_Wheel/Colour_Wheel.ino b/examples/Smooth Graphics/Colour_Wheel/Colour_Wheel.ino new file mode 100644 index 0000000..acc5bc0 --- /dev/null +++ b/examples/Smooth Graphics/Colour_Wheel/Colour_Wheel.ino @@ -0,0 +1,47 @@ +// Arc drawing example - draw a colour wheel + +#include // Include the graphics library +TFT_eSPI tft = TFT_eSPI(); // Create object "tft" + +uint16_t colors[12]; + +// ------------------------------------------------------------------------- +// Setup +// ------------------------------------------------------------------------- +void setup(void) { + Serial.begin(115200); + tft.init(); + tft.fillScreen(TFT_BLACK); + + // Create the outer ring colours + for (uint8_t c = 0; c < 2; c++) { + colors[c + 10] = tft.alphaBlend(128 + c * 127, TFT_RED, TFT_MAGENTA); + colors[c + 8] = tft.alphaBlend(128 + c * 127, TFT_MAGENTA, TFT_BLUE); + colors[c + 6] = tft.alphaBlend(128 + c * 127, TFT_BLUE, TFT_GREEN); + colors[c + 4] = tft.alphaBlend(128 + c * 127, TFT_GREEN, TFT_YELLOW); + colors[c + 2] = tft.alphaBlend(128 + c * 127, TFT_YELLOW, TFT_ORANGE); + colors[c + 0] = tft.alphaBlend(128 + c * 127, TFT_ORANGE, TFT_RED); + } +} + +// ------------------------------------------------------------------------- +// Main loop +// ------------------------------------------------------------------------- +void loop() { + uint16_t rDelta = (tft.width() - 1) / 10; + uint16_t x = tft.width() / 2; + uint16_t y = tft.height() / 2; + bool smooth = true; + + // Draw rings as a series of arcs, increasingly blend colour with white towards middle + for (uint16_t i = 5; i > 0; i--) { + for (uint16_t angle = 0; angle <= 330; angle += 30) { + uint16_t radius = i * rDelta; + uint16_t wheelColor = tft.alphaBlend((i * 255.0)/5.0, colors[angle / 30], TFT_WHITE); + tft.drawArc(x, y, radius, radius - rDelta, angle, angle + 30, wheelColor, TFT_BLACK, smooth); + } + smooth = false; // Only outer ring is smooth + } + + while (1) delay(100); +} diff --git a/examples/Smooth Graphics/Draw_Arc/Draw_Arc.ino b/examples/Smooth Graphics/Draw_Arc/Draw_Arc.ino index f6e9c74..ee5823e 100644 --- a/examples/Smooth Graphics/Draw_Arc/Draw_Arc.ino +++ b/examples/Smooth Graphics/Draw_Arc/Draw_Arc.ino @@ -7,8 +7,6 @@ // The sides of the arc can optionally be smooth or not. Smooth arcs have // a much better appearance, especially at small sizes. -// Start angle for drawArc must be smaller than end angle - #include // Include the graphics library TFT_eSPI tft = TFT_eSPI(); // Create object "tft" @@ -42,7 +40,7 @@ void loop() // 0 degrees is at 6 o'clock position // Arcs are drawn clockwise from start_angle to end_angle - // Start angle for drawArc must be smaller than end angle (function will swap them otherwise) + // Start angle can be greater than end angle, the arc will then be drawn through 0 degrees uint16_t start_angle = random(361); // Start angle must be in range 0 to 360 uint16_t end_angle = random(361); // End angle must be in range 0 to 360 @@ -50,35 +48,6 @@ void loop() tft.drawArc(x, y, radius, inner_radius, start_angle, end_angle, fg_color, bg_color, smooth); - //tft.drawArc(x, y, radius, inner_radius, start_angle, end_angle, fg_color, bg_color); // always smooth sides if parameter is missing - - // The following function allows arcs to be drawn through the 6 o'clock position by drawing in 2 segments if - // the start angle is greater than the end angle - //drawAnyArc(x, y, radius, inner_radius, start_angle, end_angle, fg_color, bg_color, smooth); // smooth sides if parameter is missing - count++; if (count < 30) delay(500); // After 15s draw as fast as possible! } - - -// The following function allows arcs to be drawn through the 0 degree position by drawing in 2 segments - -// Function prototype with default smooth setting -void drawAnyArc(int32_t x, int32_t y, int32_t r, int32_t ir, int32_t startAngle, int32_t endAngle, - uint32_t fg_color, uint32_t bg_color, bool smooth = true); - -void drawAnyArc(int32_t x, int32_t y, int32_t r, int32_t ir, int32_t startAngle, int32_t endAngle, - uint32_t fg_color, uint32_t bg_color, bool smooth) -{ - if (endAngle > startAngle) - { - // Draw arc in single sweep - tft.drawArc(x, y, r, ir, startAngle, endAngle, fg_color, bg_color); - } - else - { - // Arc sweeps through 6 o'clock so draw in two parts - tft.drawArc(x, y, r, ir, startAngle, 360, fg_color, bg_color); - tft.drawArc(x, y, r, ir, 0, endAngle, fg_color, bg_color); - } -}