~quf/xmastree2020

c786cb786cd3d3dba336581c77bb7d1a58353327 — Lukas Himbert 3 years ago d83fa33
counter rotating disks
1 files changed, 169 insertions(+), 0 deletions(-)

A counterrotating-rings.py
A counterrotating-rings.py => counterrotating-rings.py +169 -0
@@ 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()