unicorn_hat_sim.py (3748B)
1 import sys 2 import colorsys 3 import pygame.gfxdraw 4 5 try: 6 import pygame 7 except ImportError: 8 print("To simulate a unicorn HAT on your computer, please pip install pygame") 9 10 class UnicornHatSim(object): 11 def __init__(self, width, height, rotation_offset = 0): 12 # Compat with old library 13 self.AUTO = None 14 self.PHAT = None 15 16 # Set some defaults 17 self.rotation_offset = rotation_offset 18 self.rotation(0) 19 self.pixels = [(0, 0, 0)] * width * height 20 self.pixel_size = 15 21 self.width = width 22 self.height = height 23 self.window_width = width * self.pixel_size 24 self.window_height = height * self.pixel_size 25 26 # Init pygame and off we go 27 pygame.init() 28 pygame.display.set_caption("Unicorn HAT simulator") 29 self.screen = pygame.display.set_mode([self.window_width, self.window_height]) 30 # self.clear() 31 self.screen.fill((0, 0, 0)) 32 33 def set_pixel(self, x, y, r, g, b): 34 i = (x * self.width) + y 35 self.pixels[i] = [int(r), int(g), int(b)] 36 37 def get_pixels(self): 38 """Returns a 2d array of 3-tuple RGB values repsenting pixel colours """ 39 px = [] 40 for y in range(self.height): 41 row = [] 42 for x in range(self.width): 43 i = (x * self.width) + y 44 row.append(self.pixels[i]) 45 px.append(row) 46 return px 47 48 def draw(self): 49 for event in pygame.event.get(): # User did something 50 if event.type == pygame.QUIT: 51 print("Exiting...") 52 sys.exit() 53 54 for x in range(self.width): 55 for y in range(self.height): 56 self.draw_led(x, y) 57 58 def show(self): 59 # self.clear() 60 self.screen.fill((0, 0, 0)) 61 self.draw() 62 pygame.display.flip() 63 64 def draw_led(self, x, y): 65 self.draw_gfxcircle(x,y) 66 67 def draw_gfxcircle(self, x, y): 68 p = self.pixel_size 69 w_x = int(x * p + self.pixel_size / 2) 70 w_y = int((self.height - 1 - y) * p + self.pixel_size / 2) 71 r = int(self.pixel_size / 4) 72 color = self.pixels[self.index(x, y)] 73 pygame.gfxdraw.aacircle(self.screen, w_x, w_y, r, color) 74 pygame.gfxdraw.filled_circle(self.screen, w_x, w_y, r, color) 75 76 def get_shape(self): 77 return (self.width, self.height) 78 79 def brightness(self, *args): 80 pass 81 82 def rotation(self, r): 83 self._rotation = int(round(r/90.0)) % 3 84 85 def clear(self): 86 # self.screen.fill((0, 0, 0)) 87 self.pixels = [(0, 0, 0)] * self.width * self.height 88 89 def get_rotation(self): 90 return self._rotation * 90 91 92 def set_layout(self, *args): 93 pass 94 95 def set_pixel_hsv(self, x, y, h, s=1.0, v=1.0): 96 r, g, b = [int(n*255) for n in colorsys.hsv_to_rgb(h, s, v)] 97 self.set_pixel(x, y, r, g, b) 98 99 def off(self): 100 print("Closing window") 101 pygame.quit() 102 103 def index(self, x, y): 104 # Offset to match device rotation 105 rot = (self.get_rotation() + self.rotation_offset) % 360 106 107 if rot == 0: 108 xx = x 109 yy = y 110 elif rot == 90: 111 xx = self.height - 1 - y 112 yy = x 113 elif rot == 180: 114 xx = self.width - 1 - x 115 yy = self.height - 1 - y 116 elif rot == 270: 117 xx = y 118 yy = self.width - 1 - x 119 return (xx * self.width) + yy 120 121 # SD hats works as expected 122 unicornhat = UnicornHatSim(8,8) 123 unicornphat = UnicornHatSim(8, 4) 124 125 # Unicornhat HD seems to be the other way around (not that there's anything wrong with that), so we rotate it 180 deg 126 unicornhathd = UnicornHatSim(16, 16, 180)