@@ 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()