@@ 0,0 1,169 @@
+# 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
+
+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
+ #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
+
+ # rotation speed in radians per second
+ omega = pi/4
+
+ # disk speed in (height of the tree) per second
+ # may be positive to reverse direction
+ z_speed = -0.08
+
+ # number of disks and number of segments per disk
+ number_of_disks = 4
+ segments_per_disk = 4
+
+ # brightness factor:
+ # 0 = black
+ # 1 = maximum brightness
+ brightness_factor = 0.4
+
+ # colours in GRB order
+ black = (0, 0, 0)
+ colors = [
+ # add or remove colors as necessary; this is a "christmas palette":
+ (255, 0, 0),
+ (200, 50, 0),
+ (0, 255, 0),
+ (50, 255, 0),
+ (180, 255, 0),
+ (255, 255, 255),
+ #(0, 255, 0),
+ #(165, 255, 0),
+ #(255, 255, 0),
+ #(128, 0, 0),
+ #(0, 0, 255),
+ #(0, 75, 130),
+ #(130, 238, 238),
+ ]
+ colors = [ (round(brightness_factor * g), round(brightness_factor * r), round(brightness_factor * b)) for (g, r, b) in colors ]
+
+ # segment width; 2*pi/len(ray_colors) is the maximum
+ segment_width = 0.5 * pi / segments_per_disk
+
+ # do not change this:
+ disk_thickness = 1 / number_of_disks
+
+ # INITIALISE SOME VALUES
+ t0 = time.time()
+ last_time = t0
+ parity = 0
+ lowermost_disk_height = disk_thickness
+ disks = [random.choice(colors) for _ in range(number_of_disks + 1)]
+ angle_offsets = len(disks) * [2*pi*random.random()]
+
+ while True:
+ # Reset all lights to black
+ for i in range(len(coords)):
+ pixels[i] = black
+
+ now = time.time()
+ delta = now - t0 # time passed since the start
+ lowermost_disk_height += (now - last_time) * z_speed
+ last_time = now
+
+ # Make sure that the lowermost disk starts below the base of the tree and the topmost disk starts above the top so we never get a completely black disk
+ while not (0 <= lowermost_disk_height <= disk_thickness):
+ # forget the topmost disk and add another one
+ if z_speed > 0:
+ disks = [random.choice(colors)] + disks[:-1]
+ angle_offsets = [2*pi*random.random()] + disks[:-1]
+ else:
+ disks = disks[1:] + [random.choice(colors)]
+ angle_offsets = angle_offsets[1:] + [2*pi*random.random()]
+ lowermost_disk_height -= numpy.sign(z_speed) * disk_thickness
+ parity = (parity + 1) % 2 # this makes sure that the disks don't reverse their rotation
+
+ # Turn the lights on again one by one
+ for (j, color) in enumerate(disks):
+ disk_top = lowermost_disk_height + j * disk_thickness
+ #print(f"{lowermost_disk_height}")
+ for (i, (φ, z)) in enumerate(zip(azimuths, zs)):
+ if (disk_top - disk_thickness) < z <= (disk_top):
+ for k in range(segments_per_disk):
+ ray_offset = k * 2*pi / segments_per_disk + angle_offsets[j]
+ if abs(φ + ray_offset + (-1)**(j+parity) * delta * omega) % (2*pi) <= segment_width:
+ pixels[i] = color
+
+ # use the show() option as rarely as possible as it takes ages
+ # do not use show() each time you change a LED but rather wait until you have changed them all
+ pixels.show()
+
+ return 'DONE'
+
+
+# yes, I just put this at the bottom so it auto runs
+xmaslight()