From 6e265cfa5002a5667681733eae08357f2b9695e5 Mon Sep 17 00:00:00 2001 From: Aaron Perley Date: Tue, 27 Sep 2016 21:39:02 -0400 Subject: Add bridge simulator and cleanup code --- .gitignore | 1 + DummyRig.py | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ bridge.py | 70 ++++++++++++++++++++++++++++++++--------------------------- color.py | 20 ++++++++--------- 4 files changed, 121 insertions(+), 42 deletions(-) create mode 100644 .gitignore create mode 100644 DummyRig.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0d20b64 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.pyc diff --git a/DummyRig.py b/DummyRig.py new file mode 100644 index 0000000..093a655 --- /dev/null +++ b/DummyRig.py @@ -0,0 +1,72 @@ +from Tkinter import * +import re +import threading +import time + +def rgbToTkColor(r, g, b): + if not (0 <= r <= 1 and 0 <= g <= 1 and 0 <= b <= 1): + print "invalid r={}, g={}, b={}".format(r, g, b) + assert(False) + + r_hex = int(r * 0xFF) + g_hex = int(g * 0xFF) + b_hex = int(b * 0xFF) + return "#{:02x}{:02x}{:02x}".format(r_hex, g_hex, b_hex) + +class DummyLight(object): + WIDTH_PX = 8 + HEIGHT_PX = 20 + + def __init__(self, canvas): + self.canvas = canvas + self.color = (0, 0, 0) + + def setRGBRaw(self, r, g, b): + self.color = (r, g, b) + self.canvas.itemconfig(self.rect_id, fill=rgbToTkColor(*self.color)) + + +class DummyRig(object): + def __init__(self, width, height): + self.width = width + self.height = height + self.margin = 5 + + def init(self): + self.root = Tk() + self.canvas = Canvas(self.root, + width=self.width*DummyLight.WIDTH_PX + self.margin*2, + height=self.height*DummyLight.HEIGHT_PX + self.margin*2) + self.canvas.pack() + self.root.resizable(width=0, height=0) + + self.lights = [[DummyLight(self.canvas) for _ in xrange(self.height)] + for _ in xrange(self.width)] + + self.rootThread = threading.Thread(target=self.root.mainloop) + self.rootThread.start() + + self.initRects() + + def select(self, pattern): + match = re.search("\$side=(.*?)\[\$sequence=(.*?)\]", pattern) + if match.group(1) == "bot": + y = 1 + elif match.group(1) == "top": + y = 0 + + x = int(match.group(2)) - 1 + return self.lights[x][y] + + def updateOnce(self): + pass + + def initRects(self): + for x in xrange(self.width): + for y in xrange(self.height): + light = self.lights[x][y] + x0 = self.margin + x * DummyLight.WIDTH_PX + y0 = self.margin + y * DummyLight.HEIGHT_PX + light.rect_id = self.canvas.create_rectangle(x0, y0, x0 + DummyLight.WIDTH_PX, + y0 + DummyLight.HEIGHT_PX, + width=1) diff --git a/bridge.py b/bridge.py index 22d8da2..64fc54f 100644 --- a/bridge.py +++ b/bridge.py @@ -3,23 +3,43 @@ from __future__ import division import color import colorsys -import lumiversepython +from DummyRig import DummyRig #import lumiversepython import math import random import time -FRAME_RATE = 44 +FRAME_RATE = 10 #44 MIN_VALUE = 0 MAX_VALUE = 1 MAX_TIME = 4 MIN_TIME = 0.3 -MAX_HUE = 169 / 360 +MAX_HUE = 230 / 360 MIN_HUE = 250 / 360 +class Panel(object): + def __init__(self, light): + self.light = light + self.current_color = color.RGB(0, 0, 0) + self.target_color = color.RGB(0, 0, 0) + self.delta = color.RGB(1, 1, 1) + + def begin_transition(self, target_color, delta_ticks): + self.target_color = target_color + self.delta = (self.target_color - self.current_color) / delta_ticks + + def tick(self): + self.current_color = self.current_color + self.delta + self.light.setRGBRaw(*self.current_color.components) + + def transition_complete(self): + return abs(self.current_color - self.target_color) < abs(self.delta) + + + def get_all_lights(rig): """Return a list of all panels.""" return [ - rig.select('$side={}[$sequence={}]'.format(j, i)) + Panel(rig.select('$side={}[$sequence={}]'.format(j, i))) for j in ['top', 'bot'] for i in range(1, 200) ] @@ -27,7 +47,7 @@ def get_all_lights(rig): def pick_HSV(): """Return a random color in an appropriate interval.""" hue = random.random() * (MAX_HUE - MIN_HUE) + MIN_HUE - saturation = random.random() + saturation = random.random() * (1 - 0.63) + 0.63 value = random.random() return color.HSV(hue, saturation, value) @@ -38,44 +58,30 @@ def transition(start, end, step): def random_change(): - """Return a random amount that a light should change each frame.""" - min_time = int(MIN_TIME * FRAME_RATE) - max_time = int(MAX_TIME * FRAME_RATE) - return 1 / random.randint(min_time, max_time) + """Return a random number of ticks for a light to change""" + min_ticks = int(MIN_TIME * FRAME_RATE) + max_ticks = int(MAX_TIME * FRAME_RATE) + return random.randint(min_ticks, max_ticks) def demo(lights, rig): """Do some light things.""" - light_status = [ - { - 'change': 0, - 'light': light, - 'current value': color.RGB(0, 0, 0), - 'transitioning to': color.RGB(0, 0, 0), - } - for light in lights - ] while True: - for light_s in light_status: - change = light_s['change'] - light = light_s['light'] - current_value = light_s['current value'] - transitioning_to = light_s['transitioning to'] - if abs(transitioning_to - current_value) < change: - change = random_change() - light_s['change'] = change - transitioning_to = pick_HSV().to_RGB() - light_s['transitioning to'] = transitioning_to - new_color = transition(current_value, transitioning_to, change) - light.setRGBRaw(*new_color.components) - light_s['current value'] = new_color + print "Tick" + for light in lights: + if light.transition_complete(): + if( light == lights[0] ): + print "Transition complete!" + light.begin_transition(pick_HSV().to_RGB(), random_change()) + light.tick() + rig.updateOnce() time.sleep(1 / FRAME_RATE) def main(): """Run show.""" - rig = lumiversepython.Rig('/home/teacher/Lumiverse/PBridge.rig.json') + rig = DummyRig(200, 2) #lumiversepython.Rig('/home/teacher/Lumiverse/PBridge.rig.json') rig.init() lights = get_all_lights(rig) demo(lights, rig) diff --git a/color.py b/color.py index 71fbaaf..a10073b 100644 --- a/color.py +++ b/color.py @@ -11,19 +11,19 @@ class Vector(object): def __add__(self, other): """Add two vectors.""" - return Vector( - *map(lambda x, y: x + y, zip(self.components, other.components)) + return self.__class__( + *map(lambda (x, y): x + y, zip(self.components, other.components)) ) def __sub__(self, other): """Subtract two vectors.""" - return Vector( - *map(lambda x, y: x - y, zip(self.components, other.components)) + return self.__class__( + *map(lambda (x, y): x - y, zip(self.components, other.components)) ) def __mul__(self, other): """Multiply a vector by a constant.""" - return Vector(*map(lambda x: x * other, self.components)) + return self.__class__(*map(lambda x: x * other, self.components)) def __rmul__(self, other): """Multiply a constant by a vector.""" @@ -33,16 +33,16 @@ class Vector(object): """Return the 2-norm of the vector.""" return math.sqrt(sum(map(lambda x: x * x, self.components))) - def __div__(self, scalar): + def __truediv__(self, scalar): """Return self * 1 / scalar.""" return self * (1 / scalar) -def HSV(Vector): +class HSV(Vector): """HSV 3-vector.""" def __init__(self, hue, saturation, value): """Initialize with hue, saturation, and value.""" - super(Vector, self).__init__(hue, saturation, value) + super(HSV, self).__init__(hue, saturation, value) def to_RGB(self): """Convert to an RGB vector.""" @@ -61,11 +61,11 @@ def HSV(Vector): return self.components[2] -def RGB(Vector): +class RGB(Vector): """RGB 3-vector.""" def __init__(self, r, g, b): """Initialize with red green and blue.""" - super(Vector, self).__init__(r, g, b) + super(RGB, self).__init__(r, g, b) def to_HSV(self): """Convert to HSV vector.""" -- cgit v1.3.1