diff options
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | bridge.py | 90 | ||||
| -rw-r--r-- | color.py | 11 | ||||
| -rw-r--r-- | constants.py | 10 | ||||
| -rw-r--r-- | fish_render.py | 91 |
5 files changed, 120 insertions, 83 deletions
@@ -1 +1,2 @@ +__pycache__ *.pyc @@ -1,87 +1,43 @@ -#!/usr/bin/python +#!/usr/bin/python2 """Simple demo of oscillating colors.""" -from __future__ import division +from __future__ import division, unicode_literals import color -import colorsys -from DummyRig import DummyRig #import lumiversepython -import math -import random +import constants +from DummyRig import DummyRig +import fish_render import time - -FRAME_RATE = 10 #44 -MIN_VALUE = 0 -MAX_VALUE = 1 -MAX_TIME = 4 -MIN_TIME = 0.3 -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) - - +try: + import lumiversepython +except ImportError: + have_lumiversepython = False +else: + have_lumiversepython = True def get_all_lights(rig): """Return a list of all panels.""" return [ - Panel(rig.select('$side={}[$sequence={}]'.format(j, i))) - for j in ['top', 'bot'] for i in range(1, 200) + [ + rig.select('$side={y}[$sequence={x}]'.format({'y': y, 'x': x})) + for y in ('top', 'bot') + ] for x in xrange(1, 200) ] -def pick_HSV(): - """Return a random color in an appropriate interval.""" - hue = random.random() * (MAX_HUE - MIN_HUE) + MIN_HUE - saturation = random.random() * (1 - 0.63) + 0.63 - value = random.random() - return color.HSV(hue, saturation, value) - - -def transition(start, end, step): - """Return a vector equal to (end - start) * step + start.""" - return (end - start) / abs(end - start) * step + start - - -def random_change(): - """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.""" + fish = fish_render.Fish(0, 0, 2, 1, color.red, 1 / constants.FRAME_RATE) + bridge = fish_render.Bridge(lights, fish, rig) while True: - 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) + bridge.update() + time.sleep(1 / constants.FRAME_RATE) def main(): """Run show.""" - rig = DummyRig(200, 2) #lumiversepython.Rig('/home/teacher/Lumiverse/PBridge.rig.json') + if have_lumiversepython: + rig = lumiversepython.Rig('/home/teacher/Lumiverse/PBridge.rig.json') + else: + rig = DummyRig(200, 2) rig.init() lights = get_all_lights(rig) demo(lights, rig) @@ -1,5 +1,5 @@ """Color vector library containing HSV and RGB.""" -from __future__ import division +from __future__ import division, unicode_literals import colorsys import math @@ -82,3 +82,12 @@ class RGB(Vector): def b(self): """Return blue value.""" return self.components[2] + +red = RGB(1, 0, 0) +green = RGB(0, 1, 0) +blue = RGB(0, 0, 1) +cyan = RGB(0, 1, 1) +magenta = RGB(1, 0, 1) +yellow = RGB(1, 1, 0) +white = RGB(1, 1, 1) +black = RGB(0, 0, 0) diff --git a/constants.py b/constants.py new file mode 100644 index 0000000..e19c127 --- /dev/null +++ b/constants.py @@ -0,0 +1,10 @@ +"""Constants that may be tweaked in the future.""" +from __future__ import division, unicode_literals + +FRAME_RATE = 10 #44 +MIN_VALUE = 0 +MAX_VALUE = 1 +MAX_TIME = 4 +MIN_TIME = 0.3 +MAX_HUE = 169 / 360 +MIN_HUE = 250 / 360 diff --git a/fish_render.py b/fish_render.py index be94a23..becd8c1 100644 --- a/fish_render.py +++ b/fish_render.py @@ -1,29 +1,90 @@ +"""Rendering classes and helper functions.""" +from __future__ import division, unicode_literals +import color +import random class Fish(object): - def __init__(self, x, y, width, height, color): + """Object displayed on the bridge, probably a fish.""" + def __init__(self, x, y, width, height, color, step): + """Create fish with default parameters.""" self.x = x self.y = y self.width = width self.height = height self.color = color + self.speed = step + def update(self): + """Swim gently to the other side of the bridge.""" + self.x += self.step -class BridgeRender(object): - WIDTH_SEGMENTS = 200 - HEIGHT_SEGMENTS = 2 - SAMPLES_PER_SEGMENT = 4 # Actual samples is this squared - def __init__(self, fish): +class Light(object): + """Represent a bridge light and its state.""" + def __init__(self, x, y, light, start_color, step): + """Store all facts about a light.""" + self.light = light + self.color = start_color + self.transitioning_to = start_color + self.step = step + self.x = x + self.y = y + + def update(self, fish): + """Change color depending on where the fish is.""" + if abs(self.transitioning_to - self.color) < self.step: + self.step = random_change() + self.transitioning_to = pick_HSV().to_RGB() + new_background = transition( + self.color, self.transitioning_to, self.step + ) + coverage = compute_coverage(fish, self.x, self.y) + new_color = coverage * fish.color + (1 - coverage) * new_background + self.light.setRGBRaw(*new_color.components) + + +class Bridge(object): + """Store objects on the bridge.""" + def __init__(self, lights, fish, rig): + """Initialize with lights and fish.""" + self.lights = lights self.fish = fish + self.rig = rig + + def update(self): + """Compute fish coverages and push lights to bridge.""" + for x, light_col in enumerate(self.lights): + for y, light in enumerate(light_col): + fish.update() + light.update(fish) + self.rig.updateOnce() + + +def compute_coverage(fish, x, y): + """Calculate the coverage of a fish over a box.""" + min_x = max(x, fish.x) + max_x = min(x+1, fish.x + fish.width) + min_y = max(y, fish.y) + max_y = min(y+1, fish.y + fish.height) + coverage = (max_x - min_x) * (max_y - min_y) + return coverage + + +def pick_HSV(): + """Return a random color in an appropriate interval.""" + hue = random.random() * (MAX_HUE - MIN_HUE) + MIN_HUE + saturation = random.random() + value = random.random() + return color.HSV(hue, saturation, value) + - def compute_coverage(self, x, y): - min_x = max(x, self.fish.x - self.fish.width) - max_x = min(x+1, self.fish.x + self.fish.width) - min_y = max(y, self.fish.y - self.fish.height) - max_y = min(y+1, self.fish.y + self.fish.height) +def transition(start, end, step): + """Return a vector equal to (end - start) * step + start.""" + return (end - start) / abs(end - start) * step + start - return (max_x - min_x) * (max_y - min_y) - def compute_color(self, x, y, base_color): - cov = compute_coverage(x, y) - return (cov * self.fish.color) + ((1 - cov) * base_color) +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) |
