Introduction: Drawing Filled Circles and Triangles With MicroPython and Pi Pico

About: Retired teacher of computing - started 1967 with FORTRAN IV. I now play with development boards such as Raspberry Pi, Pico, Arduino, micro:bit and Adafruit CircuitPython boards like the Insybitsy M4 and Circui…

Most of the graphics elements such as text, lines, rectangles and pixels are provided by the framebuf library. We can produce many interesting images with these but adding filled triangles, circles and rings would be really useful.

In this tutorial I'm going to provide these extra routines and demonstrate the capabilities of a small and inexpensive coloured display.

Supplies

All you will need are a Raspberry Pi Pico - about £4

Waveshare 0.96" LCD Display Module for Raspberry Pi Pico (160×80 pixels) - £7

USB cable

Thonny editor - free download

I live in the UK and bought mine from thepihut.com but they are all available worldwide.

Step 1: The Display

The Waveshare 0.96" LCD Display Module for Raspberry Pi Pico (160×80 pixels) has sockets corresponding to the pins on the Pico and the two can be gently pressed together to connect them. Do not press on the screen, just the circuit board, and make sure that you connect them the right way round with the joystick at the USB socket end of the Pico. The joystick and buttons will provide simple inputs for our projects.

As is usual for displays the advertisement shows a colourful photographic image. This is possible, as demonstrated in the picture, and I will provide a link about how to do it at the end.

Most of this tutorial will be about drawing on the screen to create our own images.

Step 2: Documentation

The manufacturer's documentation can be found here:

https://www.waveshare.com/wiki/Pico-lcd-0.96

It is well worth looking at.

Waveshare supply an example program with the screen driver included rather than as a separate library. (I quite like this method as you do not have to keep adding and removing libraries as you change peripherals.) I've provided a version of it below with a few additions.

It shows lines, text and how to access the joystick and buttons. The screen driver is the most important part and must be included in all programs using the screen.

If you have the kit I suggest you download the program and try it out.

Step 3: Circles

If we draw a radius in a circle and then draw in vertical and horizontal lines to form a right angled triangle as shown in the diagram we can use the theorem of Pythagoras to calculate the length of side a for every value of i. If we then draw horizontal lines of length a in both directions from the vertical diameter it will touch both sides of the circle at its circumference. Drawing a series of such lines, for every pixel line, will fill in the circle.

def circle(x,y,r,c):
  lcd.hline(x-r,y,r*2,c)
  for i in range(1,r):
    a = int(math.sqrt(r*r-i*i)) # Pythagoras!
    lcd.hline(x-a,y+i,a*2,c) # Lower half
    lcd.hline(x-a,y-i,a*2,c) # Upper half
    lcd.display()
    utime.sleep(0.1)


If we only draw the end points on the circumference of the circle we will get a ring.

def ring(x,y,r,c):
  lcd.pixel(x-r,y,c)
  lcd.pixel(x+r,y,c)
  lcd.pixel(x,y-r,c)
  lcd.pixel(x,y+r,c)
  lcd.display()
  utime.sleep(0.1)
  for i in range(1,r):
    a = int(math.sqrt(r*r-i*i)) # Pythagoras
    lcd.pixel(x-a,y-i,c)
    lcd.pixel(x+a,y-i,c)
    lcd.pixel(x-a,y+i,c)
    lcd.pixel(x+a,y+i,c)
    lcd.pixel(x-i,y-a,c)
    lcd.pixel(x+i,y-a,c)
    lcd.pixel(x-i,y+a,c)
    lcd.pixel(x+i,y+a,c)
    lcd.display()
    utime.sleep(0.1)

Step 4: Triangles

Drawing triangle outlines is very easy - we just draw three straight lines.

def triangle(x1,y1,x2,y2,x3,y3,c): # Draw outline triangle
  lcd.line(x1,y1,x2,y2,c)
  lcd.line(x2,y2,x3,y3,c)
  lcd.line(x3,y3,x1,y1,c)


Drawing a filled triangle is much more difficult. The technique has been written up here:

http://www.sunshine2k.de/coding/java/TriangleRasterization/TriangleRasterization.html

The method is similar to that used with filled circles - we draw horizontal lines between the edges to fill in the space.

This is easier if we have a triangle with either a horizontal top edge or horizontal bottom edge. If we do not have a horizontal edge we split the original triangle into two triangles with a horizontal line and then draw the triangles separately. This all sounds quite easy but it involves a great deal of mathematics. Thankfully, you do need to understand the maths to use it. I've made a simple command to call the rather complicated routine.

c = colour(0,255,0)
tri_filled(x1,y1,x2,y2,x3,y3,c)
lcd.display()


The full code is in the demo program below and a video of the program running is on the next step.

The code in this program contain several utime.sleep(0.1) instructions to slow things down enough so that we can see what is going on.

Step 5: Slow Video

This runs slowly to show the lines being drawn one at a time. Faster version follows.

Step 6: Graphics Workout for the WS Pi Pico 0.96" LCD Display

I usually provide a 'Workout' example Instructable for each new display I buy to help coders decide if it would be useful for their project. Here is the one for this display. It does all the normal things I've done in the past for direct comparison of speed and visibility: Use the joystick and buttons, plot trigonometric and bar graphs, show text in different sizes, colour gradient backgrounds and now I've added circles and triangles.

I hope you like it.

This is a very long program, 828 lines of code, only possible because this tiny screen does not need a huge frame buffer. There is a real pay off with lower pixel count screens if you want to execute a load of code!

This program has all the delays removed within the circle and triangle routines. I'm impressed with the speed but it only has a small buffer to copy via SPI on every screen redraw!

Step 7: Display Photographs

This is a photograph I took in Kathmandu at the Swayambhunath Temple.

This was originally a .RAW Canon image. I took the following steps:

  1. Process to JPG, crop to 160x80 aspect ratio and resize to 160x80 pixels in Photoshop. (Gimp also works and is free.)
  2. Convert to new RAW format with 2-byte colours rather than 3-byte colours.
  3. Copy file to Pico using rshell on a RaspberryPi 4
  4. Display with Image program and the correct screen driver

Quite a bit of work in the pre-processing department. You can find the necessary code and details here:

http://www.penguintutor.com/programming/picodisplayanimations 



Step 8: Computer Graphics Depend on Mathematics

This project makes use of:

  • Basic arithmetic - counting, calculating, percentage and comparing (< > =)
  • Set theory - bit mapping and masking
  • Number bases - binary, hexadecimal and denary - bits and bytes
  • Geometry - circles, triangles, rectangles, lines and points
  • Co-ordinate geometry - plotting points and intercepts
  • Theorem of Pythagoras
  • Trigonometry - radians, sine, cosine
  • List and suffixes/pointers - byte-array
  • Probability - random numbers
Made with Math Contest

Participated in the
Made with Math Contest