Skip to content

Timing Drawing Speed

If you are writing a video game and want fast drawing times for objects on the screen, there are several different algorithms you can try. You can use the MicroPython time_us function to record the time before and after you call a drawing function and return the difference to get an idea of the time saved in different versions of your drawing functions.

Sample Function Timer Code

Sample Function Code

1
2
3
4
5
6
from utime import ticks_us

start = ticks_us()
my_function()
end = ticks_us()
print('Execution time in microseconds:', end - start)

MicroPython also supports the ticks_cpu() function which could return a smaller granularity for precise time measurements. However, on the Raspberry Pi implementation, the results are exactly the same as the ticks_us() function.

Comparing Two Circle Drawing Algorithms

In the following code, we compare two circle drawing algorithms.

  1. Row Scanner Method - this method scans each pixel in the square around the circle and turns it on if the pixel is within a distance range. It must calculate the distance of each pixel and compare
  2. that distance to both the inside and outside distances. The time-consuming operations are to calculate the squares of the x and y distances.
  3. Point Draw Method - this method walks around the circle and for each degree, it draws a single pixel at the edge of the circle. Each point uses the sine() and cosine() functions to calculate the x and y distance from the center of the circle to that point.

For small circles, it is very inefficient to calculate all 360 points. Scanning all the points in a 5X5 grid only takes 25 calculations. However, the larger the circle becomes, the more points there are to calculate in the row scanner method. A 20X20 circle will need to run the distance calculation 400 times.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
from utime import sleep, ticks_cpu, ticks_us
import math
import ssd1306

# this is the built-in LED on the Pico
led = Pin('LED', Pin.OUT)

WIDTH = 128
HEIGHT = 64
clock=Pin(2)
data=Pin(3)
RES = machine.Pin(4)
DC = machine.Pin(5)
CS = machine.Pin(6)

spi=machine.SPI(0, sck=clock, mosi=data)
oled = ssd1306.SSD1306_SPI(WIDTH, HEIGHT, spi, DC, RES, CS)

# 
def fast_circle(x, y, r, color):
    # draw points around a circle skiping every 4th one
    for theta in range(0, 360, 2):
        # we can save 5% of the time by only doing this once
        radians = math.radians(theta)
        x_pos = int(x + r * math.cos(radians))
        y_pos = int(y + r * math.sin(radians))
        # check if we are within range
        #if 0 <= x_pos < 128 and 0 <= y_pos < 64:
        # we can cut another 5% by not doing these checks
        oled.pixel(x_pos, y_pos, color)

def circle(x, y, r, color):
    diameter1 = (r - 0.5) ** 2
    diameter2 = (r + 0.5) ** 2
    x_min = max(0, int(x - r))
    x_max = min(128, int(x + r + 1))
    y_min = max(0, int(y - r))
    y_max = min(64, int(y + r + 1))

    for y_pos in range(y_min, y_max):
        for x_pos in range(x_min, x_max):
            if ((x_pos - x) ** 2 + (y_pos - y) ** 2 >= diameter1) and ((x_pos - x) ** 2 + (y_pos - y) ** 2 <= diameter2):
                oled.pixel(x_pos, y_pos, color)


start = ticks_us()
circle(32, 32, 10, 1)
end = ticks_us()
print('Standard scanner circle draw time in cpu ticks', end - start)
oled.show()
sleep(1)
start = ticks_us()
fast_circle(96, 32, 10, 1)
end = ticks_us()
print('Fast draw time in cpu ticks', end - start)
oled.show()

Challenge

  1. Write a program that compares drawing speed for various sizes of circles.
  2. Modify the circle function to use the most efficient algorithm
  3. If you have a small circle, how many points do you need to not make the circle appear broken? Try changing the number of points calculated in the line `for theta in range(0, 360, 2):. Can you dynamically change the number of points skipped as the circle becomes smaller?
  4. Can you add a parameter to the circle function that only draws every 3rd point?