http://www.technoblogy.com/show?3ZYQ Logo Technoblogy Arduino and AVR projects [ ] [Search] Recent posts V 2022 * Drawing Filled Quadrilaterals and Triangles * Reading from a TFT Display * I2C SD-Card Module PCB * I2C SD-Card Module * Monochrome Low-Power Display Library * Three-Channel Chart Plotter * Adding File Storage to an Arduino * Universal TFT Display Backpack * Tiny TFT Graphics Library 2 * On Bytes and Pins * Tiny I2C Routines for all AVR Microcontrollers * Minimal RP2040 Board * Printing to a Serial LED Display * 16 LEDs Kishi Puzzle Solution * Twinkling Pendant * Morse Code Message Pendant * Controlling RGB LED Strips with a Single Function * 16 LEDs Solution and a New Puzzle > 2021 * Using a Timer on the Arduino Uno or Arduino Zero * AM Morse-Code Transmitter * 16 LEDs Puzzle * Low-Power LCD Clock * Measuring Your Own Supply Voltage * 100MHz Frequency Meter * Pocket Op Amp Lab PCB * Frequency Divider Using CCL * Pocket Op Amp Lab Cookbook * I2C Detective * Pocket Op Amp Lab * Five LEDs Puzzle Solution * Five LEDs Puzzle PCB > 2020 * Compact TFT Graphics Library * Five LEDs Puzzle * Frequency Probe * Combination Lock using CCL * Diffusion Clock * Smooth Big Text * Simple Sprite Routines for the Wio Terminal * Saving Screenshots from a TFT Display * Simple Sprite Routines for the PyGamer/PyBadge * Reading the PyBadge Display * Minimal ATmega4809 on a Breadboard * Big Time * Four Sample Player * Mega Tiny Time Watch [Updated] > 2019 * Eight-Character Alphanumeric Display * Festive Lights Programming Challenge * UPDI Programmer Stick * New ATtiny Low Power * Nano Current Meter * ATtiny Running Lisp * Minimal I2C for the New AVR Microcontrollers * Getting Started with the New ATtiny Chips * Visible Lisp Computer * Simple DataFlash Board * Magic 3D Clock * Tiny TFT Graphics Library * Illuminated Button Matrix * Two-Digit Thermometer * Minimal ATSAMD21 Computer 2 * Minimal ATSAMD21 Computer * Tiny Thermocouple Thermometer * Twelve PWM Outputs from an ATtiny85 * Tiny Function Generator PCB * ATtiny10 Thermometer PCB * ATtiny10 Thermometer * Lisp Badge [Updated] > 2018 * ATtiny85 Weather Station [Updated] * Widget Dashboard * Tiny MIDI Player * Colour Graphics Library * I2C GPS Module PCB * Tiny Terminal 2 * Tiny Function Plotter * I2C GPS Module * Simple LCD Character Display * Alcohol Unit Counter * Tiny Machine-Code Monitor * One Input 20-key Keypad Interface * Programmable Signal Generator * Minimal Tiny I2C Routines * ATtiny85 20MHz Internal Clock * ATtiny10 POV Pendant * IR Remote Wand * IR Remote Control Detective [Updated] * Harmonic Function Generator * Tiny Graphics Library * Secret Maze PCB * Tiny Function Generator Sine Wave * Tiny Function Generator * Secret Maze * Playing Notes on the ATtiny85 * Tiny Colour Watch > 2017 * Continuity Tester * Programming the ATtiny10 [Updated] * Proto Power Supply * Using an ATmega328 without a crystal * Bounce-Free Rotary Encoder * Four-Channel Thermometer * Flexible GPS Parser * Tiny Face Watch * Driving Four RGB LEDs from an ATtiny85 * Big Text for Little Display * ATtiny85 Graphics Display * Tiny Time 2 Watch * 10 or 12-bit DAC from the ATtiny85 * Simple 1-Wire Interface * Audio Pitch Shifter * Tiny Lisp Computer 2 PCB * GameBone Simple Electronic Game > 2016 * Tiny Time Watch * Tiny Lisp Computer 2 * Tiny Lisp Computer * Text Display for the Arduino Uno * Simple PS/2 Keyboard Interface * Making Your Own I2C Peripherals * Using the ATmega1284 with the Arduino IDE * Digital Clock Using Lisp * Making millis() tell the time * A Lightweight Alternative to tone * Adjustable Load * Programming ATtinys with Arduino 1.6.8 [Updated] * Digital Music Box [Updated] * Using the Arduino IDE Without Cores * Flashing Thermometer * Portable Lab Power Supply * ATtiny85 Sound Level Meter > 2015 * ATtiny85 Bargraph Voltmeter * TinyNav Simple GPS Navigator [Updated] * Dot Matrix Clock * Simple Rotary Encoder Interface [Updated] * Driving LED Displays with Fewer I/O Lines * Infrared Controlled Buggy * Powering Projects from a 1.5V Battery * IR Remote Control Switch * Odometer/Speedometer Pendant [Updated] * Push-Button On/Off Switches * Simple ATtiny USI UART 2 * Sony NEX/Alpha Remote Control * IR Remote Control Receiver * Bulls & Cows Game 2 * IR Remote Control Tool (NEC) * IR Remote Control Tool * Bulls & Cows Game * Tiny Terminal * Choosing a Friendly AVR Chip > 2014 * Simple GPS Odometer * Simple Compass Display * Tiny GPS Speedometer [Updated] * Minimal GPS Parser [Updated] * Simple ATtiny USI UART * Timescale Clock * Tiny Synth * Waveform Generation using an ATtiny85 * Audio Sample Player * ATtiny85 Analogue Clock * Radio Time Code Clock * Four PWM Outputs from the ATtiny85 * ATtiny-Based Beginner's Kit * MINIL Machine-Code Monitor * One Input Keypad Interface * Conundrometer Game * Getting Extra Pins on ATtiny * Simple Tones for ATtiny * ATtiny Low Power Topics > Games * Conundrometer Game * Bulls & Cows Game * Bulls & Cows Game 2 * GameBone Simple Electronic Game * Secret Maze * Secret Maze PCB * Five LEDs Puzzle * Five LEDs Puzzle PCB * 16 LEDs Puzzle * 16 LEDs Solution and a New Puzzle * 16 LEDs Kishi Puzzle Solution > Sound & Music * Audio Sample Player * Simple Tones for ATtiny * Waveform Generation using an ATtiny85 * Tiny Synth * ATtiny85 Sound Level Meter * Digital Music Box [Updated] * A Lightweight Alternative to tone * Audio Pitch Shifter * Playing Notes on the ATtiny85 * Tiny Function Generator * Tiny Function Generator Sine Wave * Harmonic Function Generator * Tiny MIDI Player * Tiny Function Generator PCB * Four Sample Player > Watches & Clocks * Radio Time Code Clock * ATtiny85 Analogue Clock * Timescale Clock * Dot Matrix Clock * Digital Clock Using Lisp * Tiny Time Watch * Tiny Time 2 Watch * Tiny Face Watch * Tiny Colour Watch * Magic 3D Clock * Mega Tiny Time Watch [Updated] * Big Time * Diffusion Clock * Low-Power LCD Clock > GPS * Simple ATtiny USI UART * Simple ATtiny USI UART 2 * Minimal GPS Parser [Updated] * Tiny GPS Speedometer [Updated] * Simple Compass Display * Simple GPS Odometer * Odometer/Speedometer Pendant [Updated] * TinyNav Simple GPS Navigator [Updated] * Flexible GPS Parser * I2C GPS Module * I2C GPS Module PCB > Power Supplies * Portable Lab Power Supply * Adjustable Load * Proto Power Supply > Computers * MINIL Machine-Code Monitor * Tiny Lisp Computer * Tiny Lisp Computer 2 * Tiny Lisp Computer 2 PCB * Tiny Machine-Code Monitor * Lisp Badge [Updated] * Minimal ATSAMD21 Computer * Minimal ATSAMD21 Computer 2 * Visible Lisp Computer * ATtiny Running Lisp * Minimal ATmega4809 on a Breadboard * Minimal RP2040 Board > Graphics * Tiny Terminal * ATtiny85 Graphics Display * Big Text for Little Display * Tiny Graphics Library * Tiny Function Plotter * Tiny Terminal 2 * Colour Graphics Library * Widget Dashboard * Tiny TFT Graphics Library * Reading the PyBadge Display * Simple Sprite Routines for the PyGamer/PyBadge * Simple Sprite Routines for the Wio Terminal * Smooth Big Text * Compact TFT Graphics Library * Tiny TFT Graphics Library 2 * Universal TFT Display Backpack * Three-Channel Chart Plotter * Monochrome Low-Power Display Library * Reading from a TFT Display > Thermometers * Flashing Thermometer * Simple 1-Wire Interface * Four-Channel Thermometer * Tiny Graphics Library * ATtiny85 Weather Station [Updated] * ATtiny10 Thermometer * ATtiny10 Thermometer PCB * Tiny Thermocouple Thermometer * Two-Digit Thermometer > Wearables * Odometer/Speedometer Pendant [Updated] * ATtiny10 POV Pendant * ATtiny10 Thermometer PCB * Morse Code Message Pendant * Twinkling Pendant > Test Equipment * IR Remote Control Tool * IR Remote Control Tool (NEC) * IR Remote Control Receiver * Sony NEX/Alpha Remote Control * IR Remote Control Switch * ATtiny85 Bargraph Voltmeter * Driving Four RGB LEDs from an ATtiny85 * Continuity Tester * IR Remote Control Detective [Updated] * IR Remote Wand * Programmable Signal Generator * Alcohol Unit Counter * Illuminated Button Matrix * Simple DataFlash Board * Nano Current Meter * UPDI Programmer Stick * Frequency Probe * Pocket Op Amp Lab * I2C Detective * Pocket Op Amp Lab PCB * 100MHz Frequency Meter * Three-Channel Chart Plotter * I2C SD-Card Module * I2C SD-Card Module PCB > Tutorials * ATtiny Low Power * Getting Extra Pins on ATtiny * One Input Keypad Interface * ATtiny-Based Beginner's Kit * Four PWM Outputs from the ATtiny85 * Choosing a Friendly AVR Chip * Push-Button On/Off Switches * Powering Projects from a 1.5V Battery * Driving LED Displays with Fewer I/O Lines * Simple Rotary Encoder Interface [Updated] * Using the Arduino IDE Without Cores * Programming ATtinys with Arduino 1.6.8 [Updated] * Using the ATmega1284 with the Arduino IDE * Making Your Own I2C Peripherals * Simple 1-Wire Interface * 10 or 12-bit DAC from the ATtiny85 * Bounce-Free Rotary Encoder * Using an ATmega328 without a crystal * Programming the ATtiny10 [Updated] * ATtiny85 20MHz Internal Clock * Minimal Tiny I2C Routines * One Input 20-key Keypad Interface * Simple LCD Character Display * Twelve PWM Outputs from an ATtiny85 * Minimal I2C for the New AVR Microcontrollers * New ATtiny Low Power * Saving Screenshots from a TFT Display * Smooth Big Text * Pocket Op Amp Lab Cookbook * Frequency Divider Using CCL * Measuring Your Own Supply Voltage * Using a Timer on the Arduino Uno or Arduino Zero * Printing to a Serial LED Display * Tiny I2C Routines for all AVR Microcontrollers * On Bytes and Pins > PCB-Based Projects * Tiny Time Watch * GameBone Simple Electronic Game * Tiny Time 2 Watch * Tiny Face Watch * Proto Power Supply * Continuity Tester * Tiny Colour Watch * Secret Maze PCB * Tiny Machine-Code Monitor * ATtiny10 POV Pendant * I2C GPS Module PCB * Lisp Badge [Updated] * ATtiny10 Thermometer PCB * Tiny Function Generator PCB * Two-Digit Thermometer * Illuminated Button Matrix * Simple DataFlash Board * UPDI Programmer Stick * Eight-Character Alphanumeric Display * Mega Tiny Time Watch [Updated] * Big Time * Frequency Probe * Five LEDs Puzzle PCB * Pocket Op Amp Lab PCB * Low-Power LCD Clock * 16 LEDs Puzzle * Morse Code Message Pendant * Twinkling Pendant * Minimal RP2040 Board * Universal TFT Display Backpack * I2C SD-Card Module PCB By processor AVR ATtiny > ATtiny10 * Programming the ATtiny10 [Updated] * ATtiny10 POV Pendant * ATtiny10 Thermometer * ATtiny10 Thermometer PCB * Morse Code Message Pendant * Twinkling Pendant > ATtiny2313 * Simple GPS Odometer * Driving LED Displays with Fewer I/O Lines * Dot Matrix Clock > ATtiny84 * Radio Time Code Clock * Timescale Clock * IR Remote Control Tool * IR Remote Control Tool (NEC) * Simple ATtiny USI UART 2 * Odometer/Speedometer Pendant [Updated] * Adjustable Load * Alcohol Unit Counter * Two-Digit Thermometer * Nano Current Meter * Frequency Probe > ATtiny841 * Making Your Own I2C Peripherals * I2C GPS Module * I2C GPS Module PCB > ATtiny85 * ATtiny Low Power * Simple Tones for ATtiny * MINIL Machine-Code Monitor * Four PWM Outputs from the ATtiny85 * ATtiny85 Analogue Clock * Audio Sample Player * Waveform Generation using an ATtiny85 * Tiny Synth * Simple ATtiny USI UART * Tiny GPS Speedometer [Updated] * Simple Compass Display * Tiny Terminal * IR Remote Control Receiver * Sony NEX/Alpha Remote Control * Simple ATtiny USI UART 2 * Push-Button On/Off Switches * IR Remote Control Switch * Infrared Controlled Buggy * Simple Rotary Encoder Interface [Updated] * TinyNav Simple GPS Navigator [Updated] * ATtiny85 Bargraph Voltmeter * ATtiny85 Sound Level Meter * Flashing Thermometer * Digital Music Box [Updated] * Tiny Time Watch * GameBone Simple Electronic Game * Audio Pitch Shifter * Simple 1-Wire Interface * 10 or 12-bit DAC from the ATtiny85 * Tiny Time 2 Watch * ATtiny85 Graphics Display * Big Text for Little Display * Driving Four RGB LEDs from an ATtiny85 * Tiny Face Watch * Flexible GPS Parser * Four-Channel Thermometer * Bounce-Free Rotary Encoder * Continuity Tester * Tiny Colour Watch * Playing Notes on the ATtiny85 * Secret Maze * Tiny Function Generator * Tiny Function Generator Sine Wave * Secret Maze PCB * Tiny Graphics Library * Harmonic Function Generator * IR Remote Control Detective [Updated] * IR Remote Wand * ATtiny85 20MHz Internal Clock * Programmable Signal Generator * Tiny Machine-Code Monitor * Tiny Function Plotter * Tiny Terminal 2 * Colour Graphics Library * Tiny MIDI Player * Widget Dashboard * ATtiny85 Weather Station [Updated] * Tiny Function Generator PCB * Twelve PWM Outputs from an ATtiny85 * Tiny Thermocouple Thermometer * Tiny TFT Graphics Library * Magic 3D Clock * Four Sample Player * Diffusion Clock * Five LEDs Puzzle * Five LEDs Puzzle PCB * Printing to a Serial LED Display * Tiny TFT Graphics Library 2 > ATtiny861 * Portable Lab Power Supply > ATtiny88 * Illuminated Button Matrix AVR ATmega > ATmega328 * Conundrometer Game * Bulls & Cows Game * Bulls & Cows Game 2 * A Lightweight Alternative to tone * Digital Clock Using Lisp * Simple PS/2 Keyboard Interface * Text Display for the Arduino Uno * Tiny Lisp Computer * Using an ATmega328 without a crystal * Proto Power Supply * Simple LCD Character Display * UPDI Programmer Stick * Using a Timer on the Arduino Uno or Arduino Zero > ATmega1284 * Using the ATmega1284 with the Arduino IDE * Tiny Lisp Computer 2 * Tiny Lisp Computer 2 PCB * Lisp Badge [Updated] AVR 0-series and 1-series > ATtiny1614 * I2C SD-Card Module * I2C SD-Card Module PCB > ATtiny3216 * ATtiny Running Lisp * Big Time > ATtiny402 * New ATtiny Low Power * Printing to a Serial LED Display * Tiny TFT Graphics Library 2 * Three-Channel Chart Plotter * Monochrome Low-Power Display Library > ATtiny404 * 16 LEDs Puzzle * 16 LEDs Solution and a New Puzzle > ATtiny414 * Mega Tiny Time Watch [Updated] * 100MHz Frequency Meter * Measuring Your Own Supply Voltage * Universal TFT Display Backpack > ATmega4809 * Minimal ATmega4809 on a Breadboard AVR DA/DB-series > AVR128DA28 * Combination Lock using CCL * Frequency Divider Using CCL * Measuring Your Own Supply Voltage > AVR128DA48 * Low-Power LCD Clock > AVR128DB28 * Pocket Op Amp Lab * Pocket Op Amp Lab Cookbook * Pocket Op Amp Lab PCB * Measuring Your Own Supply Voltage ARM > ATSAMD21 * Minimal ATSAMD21 Computer * Minimal ATSAMD21 Computer 2 * Visible Lisp Computer * Using a Timer on the Arduino Uno or Arduino Zero > RP2040 * Minimal RP2040 Board About me * About me * Follow @technoblogy Feeds RSS feed Drawing Filled Quadrilaterals and Triangles 15th August 2022 This is an extension to my graphics libraries to plot filled quadrilaterals and triangles: Cubes.jpg Coloured quadrilaterals drawn using the routine is this article, on an Adafruit 240x240 colour TFT display. It is designed for use with my colour TFT graphics library, Tiny TFT Graphics Library 2. With one minor change it can also be used with the version of that library that supports reading from supported TFT displays, Reading from a TFT Display. It will probably also work with other graphics libraries. The triangle and quadrilateral plotting routines share much of the same code, so the resulting routines are quite compact, and should fit on microcontrollers with limited memory. You may wonder why I didn't just write a routine to plot filled triangles, and then draw quadrilaterals as two adjacent triangles. The answer is that with the libraries that support exclusive-OR plotting this results in a visible line between the two triangles, because that line is drawn twice; having a dedicated routine to plot quadrilaterals avoids this. In addition, this routine is faster. Drawing filled quadrilaterals Quadrilaterals are plotted by FillQuad(), which plots an arbitrary quadrilateral from the coordinates of its four vertices. For example, suppose the quadrilateral is the diamond shape shown below, defined by the coordinates x[0],y[0], x[1],y[1], x[2],y[2], and x[3],y[3]. First the routine sorts the four coordinates in order of increasing y: FillQuad1.gif This takes five comparisons and up to five exchanges: if (y0 > y1) { swap(y0, y1); swap(x0, x1); } if (y2 > y3) { swap(y2, y3); swap(x2, x3); } if (y1 > y3) { swap(y1, y3); swap(x1, x3); } if (y0 > y2) { swap(y0, y2); swap(x0, x2); } if (y1 > y2) { swap(y1, y2); swap(x1, x2); } The routine swap() is defined as a macro, for efficiency. Next, the quadrilateral is divided into three sections by drawing horizontal lines from x[1],y[1 ]to the opposite side at a point I'll call x[4], and from[ ]x[2],y[2] to the opposite side at point x[5]: FillQuad.gif These x values are given by: int16_t x4 = x0 + (x2 - x0) * (y1 - y0) / (y2 - y0); int16_t x5 = x1 + (x3 - x1) * (y2 - y1) / (y3 - y1); Finally we fill each section by drawing a horizontal line for each integral value of y from y[0] to y[3]. In each case the x coordinates of the line are calculated in a and b. The bottom section is filled with: for (y = y0; y <= y1; y++) { a = x0 + (x4 - x0) * (y - y0) / (y1 - y0); b = x0 + (x1 - x0) * (y - y0) / (y1 - y0); if (a > b) swap(a, b); MoveTo(a, y); DrawTo(b, y); } The middle section is filled with: for (; y <= y2; y++) { a = x4 + (x2 - x4) * (y - y1) / (y2 - y1); b = x1 + (x5 - x1) * (y - y1) / (y2 - y1); if (a > b) swap(a, b); MoveTo(a, y); DrawTo(b, y); } and the top section is filled with: for (; y <= y3; y++) { a = x2 + (x3 - x2) * (y - y2) / (y3 - y2); b = x5 + (x3 - x5) * (y - y2) / (y3 - y2); if (a > b) swap(a, b); MoveTo(a, y); DrawTo(b, y); } Catering for special cases There's one special case we need to treat differently, in a quadrilateral when x[4] and x[5] are both on the same side of the line from x[0],y[0] to x[3],y[3]: FillQuad3.gif The routine tests for this situation, and converts it to the original configuration, with the code: int16_t x4 = x0 + (x3 - x0) * (y1 - y0) / (y3 - y0); int16_t x5 = x0 + (x3 - x0) * (y2 - y0) / (y3 - y0); if ((x5 > x2) == (x4 > x1)) { swap(x2, x5); Concave quadrilaterals FillQuad() doesn't currently handle concave quadrilaterals; for example: FillQuad4.gif If necessary, draw these as two triangles. Optimising the code You may be tempted to try optimising the code by precalculating repeated subexpressions, and incrementing a and b in each of the three loops rather than recalculating them from scratch. However, I tried this and it made negligible difference to the execution time, probably because the compiler does a pretty good job of spotting such optimisations. I've therefore omitted them as they make the routine longer and harder to understand. Drawing filled triangles Triangles are drawn by FillTriangle(). this simple sorts the three coordinates in order of increasing y, and then calls the FillQuad() code with the last coordinate repeated twice. Using the routines with different graphics libraries The three occurrences of the line: MoveTo(a, y); DrawTo(b, y); should be the only thing you need to change if you're using these routines with a different graphics library. If the library has a fast routine for drawing horizontal lines you'll get substantially better performance by using this. In my Tiny TFT Graphics Library 2 the most efficient way to draw a single pixel high horizontal line is to call FillRect(), as it bypasses the Bresenham line algorithm used by DrawTo(), so replace these three lines with: MoveTo(a, y); FillRect(b - a + 1, 1); This is over ten times faster, so I've made it the default choice; for example, plotting: FillQuad(120, 120, 180, 150, 200, 200, 150, 180); took 556ms using DrawTo(), and 41ms using FillRect() on a 20MHz ATtiny414. Cubes demo Here's a simple demo program to draw the stack of coloured cubes shown at the start of this article, consisting of 18 quadrilaterals: void Cubes () { int h = 21, w = 36, x0 = 120, y0 = 100; for (int y=y0, i=2; y<=y0+h*6; y=y+h*3, i--) { for (int x=x0-w*i; x<=x0+w*i; x = x+w*2) { fore = Colour(255, 8, 8); // Red FillQuad(x, y, x - w, y - h, x, y - h*2, x + w, y - h); fore = Colour(16, 16, 255); // Blue FillQuad(x - w, y - h, x, y - h*2, x, y - h*4, x - w, y - h*3); fore = Colour(192, 128, 0); // Orange FillQuad(x, y - h*2, x, y - h*4, x + w, y - h*3 ,x + w, y - h); } } } It's designed for a 240x240 or 320x240 display, but it should be easy to adapt it for other displays by changing the constants in the first line. I used the Adafruit 1.54" 240x240 colour TFT display, fitted to my TFT display backpack; see Universal TFT Display Backpack. Resources Here are the quadrilateral and triangle routines, and the demo program: Quadrilaterals and triangles. Updates 17th August 2022: Forgot to include the macro swap(); added now. --------------------------------------------------------------------- Previous: Reading from a TFT Display --------------------------------------------------------------------- Please enable JavaScript to view the comments powered by Disqus. blog comments powered by Disqus Copyright (c) 2014-2020