From 80afe8699e1e2a6d55761d14c285a44d6aa4739b Mon Sep 17 00:00:00 2001 From: Lukas Himbert Date: Mon, 28 Dec 2020 13:38:57 +0100 Subject: [PATCH] a bad attempt at recreating the stand-up maths intro --- intro.py | 170 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 intro.py diff --git a/intro.py b/intro.py new file mode 100644 index 0000000..fa5aa4f --- /dev/null +++ b/intro.py @@ -0,0 +1,170 @@ +# Try to import board and neopixel to run on the real hardware +try: + import board + import neopixel +except ImportError: + # Error, try to import the simulation from DutChen18 instead (https://github.com/standupmaths/xmastree2020/pull/5) + from sim import board, neopixel + +import numpy + +class Rectangle: + def __init__(self, a, b, c, d, color): + # (a, b, c, d) are the vertices in clockwise or anti-clockwise order (either is fine, but it needs to be consistent). + self.vertices = (a, b, c, d) + self.color = color + + def contains(self, x): + # see https://stackoverflow.com/a/2763387 + a, b, c, d = self.vertices + return 0 <= numpy.dot(x - a, b - a) <= numpy.dot(b - a, b - a) and \ + 0 <= numpy.dot(x - a, d - a) <= numpy.dot(d - a, d - a) + +def xmaslight(): + # This is the code from my + + #NOTE THE LEDS ARE GRB COLOUR (NOT RGB) + + # Here are the libraries I am currently using: + import time + import re + from math import sin, cos, atan2, pi, exp, floor + #import board + #import neopixel + + # You are welcome to add any of these: + import random + import numpy + # import scipy + # import sys + + # If you want to have user changable values, they need to be entered from the command line + # so import sys sys and use sys.argv[0] etc + # some_value = int(sys.argv[0]) + + # IMPORT THE COORDINATES (please don't break this bit) + + coordfilename = "Python/coords.txt" + + fin = open(coordfilename,'r') + coords_raw = fin.readlines() + + coords_bits = [i.split(",") for i in coords_raw] + + coords = [] + + for slab in coords_bits: + new_coord = [] + for i in slab: + new_coord.append(int(re.sub(r'[^-\d]','', i))) + coords.append(new_coord) + + #set up the pixels (AKA 'LEDs') + PIXEL_COUNT = len(coords) # this should be 500 + + pixels = neopixel.NeoPixel(board.D18, PIXEL_COUNT, auto_write=False) + + + # YOU CAN EDIT FROM HERE DOWN + + # unzip coordinates + xs, ys, zs = list(zip(*coords)) + xs = numpy.array(xs) + ys = numpy.array(ys) + zs = numpy.array(zs) + + # normalize heights (0 to 1) + zs = (zs - zs.min()) / (zs.max() - zs.min()) + + # Find center of the tree + x0 = numpy.average([x for (x, _, _) in coords]) + y0 = numpy.average([y for (_, y, _) in coords]) + + # normalized radii (0 to 1) + radii = numpy.sqrt((xs - x0)**2, (ys - y0)**2) + radii = radii / radii.max() + + # azimuths + azimuths = numpy.arctan2(ys, xs) + + # VARIOUS SETTINGS + + # brightness factor: + # 0 = black + # 1 = maximum brightness + brightness_factor = 1.0 + + # shift azimuths (rotate x, y) such that radians in [0, π] are facing the room (radian 3π/2 should be facing into the corner): + # then, the x axis points to the right, and the y axis points toward the room / viewer + azimuths = (- azimuths + 0.7) % (2*pi) + xs = radii * numpy.sin(azimuths) + ys = radii * numpy.cos(azimuths) + + n_rectangles = 9 + + # colours in GRB order + white = tuple(round(255 * brightness_factor) for _ in range(3)) + black = (0, 0, 0) + colors = [ + # might want to change these colors + (40, 40, 40), # dark gray? + (40, 209, 40), # red + (0, 128, 128), # teal + (190, 150, 120), # light brown + (255, 255, 128), # pastel yellow + ] + colors = [tuple(round(c * brightness_factor) for c in color) for color in colors] + + while True: + rectangles = [Rectangle(numpy.array((i/n_rectangles, 0.0)), numpy.array(((i-1)/n_rectangles, 0.0)), numpy.array(((i-1)/n_rectangles, 0.0)), numpy.array((i/n_rectangles, 0.0)), color=colors[i % len(colors)]) for i in range(n_rectangles)] + # reset lights + for i in range(len(coords)): + pixels[i] = black + pixels.show() + + # wait a bit + time.sleep(1.0) + + # phase 1: roll in white from the right + speed = 2.0 + t0 = time.time() + delta = 0 + while delta <= 0.5 * pi / speed: + delta = time.time() - t0 + for (i, (φ, z)) in enumerate(zip(azimuths, zs)): + if φ < delta * speed: + pixels[i] = white + pixels.show() + + time.sleep(0.5) + + # phase 2: striped band grows out sideways + t0 = time.time() + delta = 0 + speed = 2 + w = 0.05 + while delta < w / speed: + now = time.time() + delta = now - t0 + for rect in rectangles: + rect.vertices[0][1] = numpy.clip(-delta * speed, -w, 0) + rect.vertices[1][1] = numpy.clip(-delta * speed, -w, 0) + for (i, (x, y, z)) in enumerate(zip(xs, ys, zs)): + if rect.contains((z, y)) and x >= 0: + pixels[i] = rect.color + pixels.show() + for rect in rectangles: + rect.vertices[0][1] = numpy.clip(-delta * speed, -w, 0) + rect.vertices[1][1] = numpy.clip(-delta * speed, -w, 0) + for (i, (x, y, z)) in enumerate(zip(xs, ys, zs)): + if rect.contains((z, y)) and x >= 0: + pixels[i] = rect.color + pixels.show() + + time.sleep(5) + + return 'DONE' + + +# yes, I just put this at the bottom so it auto runs +xmaslight() -- 2.38.5