diff options
| -rw-r--r--[-rwxr-xr-x] | bridge.py | 79 | ||||
| -rwxr-xr-x | brige.py | 100 | ||||
| -rw-r--r-- | color.py | 50 | ||||
| -rw-r--r-- | fish_show.py (renamed from fish_render.py) | 36 | ||||
| -rw-r--r-- | show.py | 39 | ||||
| -rw-r--r-- | sunrise.py | 28 |
6 files changed, 121 insertions, 211 deletions
diff --git a/bridge.py b/bridge.py index 4d5d817..70adb99 100755..100644 --- a/bridge.py +++ b/bridge.py @@ -1,12 +1,7 @@ -#!/usr/bin/python2 -"""Simple demo of oscillating colors.""" -from __future__ import division, print_function -import color -import constants -import fish_render -import sunrise -import time -import random +from fish_show import FishShow +from sunrise import SunriseShow +from constants import * + try: import lumiversepython except ImportError: @@ -15,55 +10,35 @@ except ImportError: else: have_lumiversepython = True +class Bridge(object): + WIDTH = 200 + HEIGHT = 2 + def __init__(self): + if have_lumiversepython: + self.rig = lumiversepython.Rig('/home/teacher/Lumiverse/PBridge.rig.json') + else: + self.rig = DummyRig(self.WIDTH, self.HEIGHT) + self.rig.init() + self.lights = self.get_lights() + def update(self): + self.rig.updateOnce() -#fish_render = sunrise - - - - - - -def get_all_lights(rig): - """Return a list of all panels.""" - return [ - [ - fish_render.Light( - x, int(y == 'top'), - rig.select('$side={y}[$sequence={x}]'.format(y=y, x=x)) - ) for y in ('top', 'bot') - ] for x in xrange(1, 200) - ] + def get_light(self, x, y): + return self.lights[x][y] + def get_lights(self): + return [ [ self.rig.select('$side={y}[$sequence={x}]'.format(y=y, x=x)) + for y in ('bot', 'top') ] + for x in xrange(1, self.WIDTH+1)] -def demo(lights, rig): - """Do some light things.""" - #fish = fish_render.Fish(0, 0, 15, 1.5, color.black, 0.05 / constants.FRAME_RATE) - #fish = fish_render.Fish(0, 0, 23, 1.5, color.RGB(193 / 255, 68 / 255, 227 / 255), 0.05 / constants.FRAME_RATE) - fish = fish_render.Fish(0, 0, 23, 1.5, color.black, 0.05 / constants.FRAME_RATE) - bridge = fish_render.Bridge(lights, fish, rig) - current_time = time.time() - count = 0 - while True: - bridge.update() - if count % constants.FRAME_RATE == 0: - time_delta = time.time() - current_time - print(time_delta) - current_time = time.time() - #time.sleep(1 / constants.FRAME_RATE) - count += 1 def main(): - """Run show.""" - 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) + bridge = Bridge() + show = FishShow(bridge) + #show = SunriseShow(bridge) + show.run(framerate=FRAME_RATE) -if __name__ == '__main__': - main() +main()
\ No newline at end of file diff --git a/brige.py b/brige.py deleted file mode 100755 index 314f9db..0000000 --- a/brige.py +++ /dev/null @@ -1,100 +0,0 @@ -#!/usr/bin/python2 -from __future__ import division, print_function -import color -import constants -import curses -import fish_render -import time -import random -try: - import lumiversepython -except ImportError: - have_lumiversepython = False - from DummyRig import DummyRig -else: - have_lumiversepython = True - -def get_all_lights(rig): - """Return a list of all panels.""" - return [ - [ - fish_render.Light( - x, int(y == 'top'), - rig.select('$side={y}[$sequence={x}]'.format(y=y, x=x)) - ) for y in ('top', 'bot') - ] for x in xrange(1, 200) - ] - - -def colorSection(lights, color, *ranges): - for start, end in ranges: - map(lambda l: map(lambda x: x.light.setRGBRaw(*color), l), lights[start:end]) - -def onSection(lights, *ranges): - colorSection(lights, (1, 1, 1), *ranges) - -def offSection(lights, *ranges): - colorSection(lights, (0, 0, 0), *ranges) - -def mapKey(key): - if key == ord('a'): - return (0, 20) - if key == ord('o'): - return (20, 40) - if key == ord('e'): - return (40, 60) - if key == ord('u'): - return (60, 80) - if key == ord('i'): - return (80, 100) - if key == ord('d'): - return (100, 120) - if key == ord('h'): - return (120, 140) - if key == ord('t'): - return (140, 160) - if key == ord('n'): - return (160, 180) - if key == ord('s'): - return (180, 200) - return (0, 0) - -def demo(lights, rig, screen): - """Do some light things.""" - sections = [] - while True: - k = screen.getch() - offSection(lights, *sections) - r = mapKey(k) - try: - i = sections.index(r) - except ValueError: - sections.append(r) - else: - del sections[i] - onSection(lights, *sections) - rig.updateOnce() - -def main(): - """Run show.""" - if have_lumiversepython: - rig = lumiversepython.Rig('/home/teacher/Lumiverse/PBridge.rig.json') - else: - rig = DummyRig(200, 2) - rig.init() - stdscr = curses.initscr() - stdscr.keypad(1) - curses.noecho() - - lights = get_all_lights(rig) - try: - demo(lights, rig, stdscr) - except BaseException: - curses.nocbreak() - stdscr.keypad(0) - curses.echo() - curses.endwin() - raise - -if __name__ == '__main__': - main() @@ -4,41 +4,45 @@ import colorsys import math class Vector(object): - """N-dimensional vector class.""" - def __init__(self, *components): + __slots__ = ('x', 'y', 'z') + + """3-dimensional vector class.""" + def __init__(self, x, y, z): """Create a vector from its components.""" - self.components = components + self.x = x + self.y = y + self.z = z def __add__(self, other): """Add two vectors.""" - return self.__class__( - *map(lambda (x, y): x + y, zip(self.components, other.components)) - ) + return self.__class__(self.x + other.x, self.y + other.y, self.z + other.z) def __sub__(self, other): """Subtract two vectors.""" - return self.__class__( - *map(lambda (x, y): x - y, zip(self.components, other.components)) - ) + return self.__class__(self.x - other.x, self.y - other.y, self.z - other.z) - def __mul__(self, other): + def __mul__(self, scalar): """Multiply a vector by a constant.""" - return self.__class__(*map(lambda x: x * other, self.components)) + return self.__class__(self.x * scalar, self.y * scalar, self.z * scalar) - def __rmul__(self, other): + def __rmul__(self, scalar): """Multiply a constant by a vector.""" - return self * other + return self * scalar def __abs__(self): """Return the 2-norm of the vector.""" - return math.sqrt(sum(map(lambda x: x * x, self.components))) + return math.sqrt(self.x * self.x + self.y * self.y + self.z * self.z) def __truediv__(self, scalar): """Return self * 1 / scalar.""" return self * (1 / scalar) def __eq__(self, other): - return self.components == other.components + return self.x == other.x and self.y == other.y and self.z == other.z + + @property + def components(self): + return (self.x, self.y, self.z) class HSV(Vector): @@ -49,19 +53,19 @@ class HSV(Vector): def to_RGB(self): """Convert to an RGB vector.""" - return RGB(*colorsys.hsv_to_rgb(*self.components)) + return RGB(*colorsys.hsv_to_rgb(self.x, self.y, self.z)) def h(self): """Return hue.""" - return self.components[0] + return self.x def s(self): """Return saturation.""" - return self.components[1] + return self.y def v(self): """Return value.""" - return self.components[2] + return self.z class RGB(Vector): @@ -72,19 +76,19 @@ class RGB(Vector): def to_HSV(self): """Convert to HSV vector.""" - return HSV(*colorsys.rgb_to_hsv(*self.components)) + return HSV(*colorsys.rgb_to_hsv(self.x, self.y, self.z)) def r(self): """Return red value.""" - return self.components[0] + return self.x def g(self): """Return green value.""" - return self.components[1] + return self.y def b(self): """Return blue value.""" - return self.components[2] + return self.z red = RGB(1, 0, 0) green = RGB(0, 1, 0) diff --git a/fish_render.py b/fish_show.py index 18aecac..cda4174 100644 --- a/fish_render.py +++ b/fish_show.py @@ -1,10 +1,10 @@ -"""Rendering classes and helper functions.""" -from __future__ import division, unicode_literals +from __future__ import division import color import random import constants from constants import * import math +from show import Show class Fish(object): """Object displayed on the bridge, probably a fish.""" @@ -28,7 +28,6 @@ class Fish(object): #self.y += 0.01 * math.sin(theta) #print(self.y) - class Light(object): """Represent a bridge light and its state.""" def __init__(self, x, y, light): @@ -61,24 +60,6 @@ class Light(object): *map(lambda x: clamp(0, x, 1), 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): - self.fish.update() - light.update(self.fish) - self.rig.updateOnce() - - def compute_coverage(fish, x, y): """Calculate the coverage of a fish over a box.""" middle_of_fish = fish.x + fish.width / 2 @@ -121,3 +102,16 @@ def random_change(): def clamp(low, x, high): """Return v such that low <= v <= high and |x - v| is minimal.""" return max(low, min(x, high)) + +class FishShow(Show): + def init(self): + self.lights = [Light(x, y, self.bridge.get_light(x, y)) + for y in xrange(self.bridge.HEIGHT) + for x in xrange(self.bridge.WIDTH)] + self.fish = Fish(0, 0, 23, 1.5, color.black, 1) + + + def update(self): + self.fish.update() + for light in self.lights: + light.update(self.fish)
\ No newline at end of file @@ -0,0 +1,39 @@ +from __future__ import division, print_function +import time + +class Clock(object): + def __init__(self): + self.last_tick = time.time() + + def tick(self, framerate): + sec_per_frame = 1.0 / framerate + diff = time.time() - self.last_tick + while diff < sec_per_frame: + diff = time.time() - self.last_tick + + if diff > (1.05 * sec_per_frame): + print("WARN: tick is not being called fast enough\n", + "target {}, actual {}".format(sec_per_frame, diff)) + self.last_tick = time.time() + + +class Show(object): + def __init__(self, bridge): + self.bridge = bridge + self.clock = Clock() + self.running = True + self.init() + + def run(self, framerate=40): + while self.running: + self.update() + self.bridge.update() + self.clock.tick(framerate) + + def init(self): + """Override me""" + raise NotImplementedError + + def update(self): + """Override me""" + raise NotImplementedError @@ -5,8 +5,9 @@ import random import constants from constants import * import math +from show import Show -class Fish(object): +class Sun(object): """Object displayed on the bridge, probably a fish.""" def __init__(self, x, y, width, height, c, step): """Create fish with default parameters.""" @@ -33,7 +34,7 @@ class Fish(object): #theta = random.random() * math.pi / 2 - math.pi / 4 #self.y += 0.01 * math.sin(theta) #print(self.y) - self.y += 0.000005 + self.y += 0.005 if self.y >= 1: self.y = 1 self.wait += 1 @@ -66,21 +67,18 @@ class Light(object): ) -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 +class SunriseShow(Show): + def init(self): + self.lights = [Light(x, y, self.bridge.get_light(x, y)) + for y in xrange(self.bridge.HEIGHT) + for x in xrange(self.bridge.WIDTH)] + self.sun = Sun(0, 0, 23, 1.5, color.black, 1) + 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): - self.fish.update() - light.update(self.fish) - self.rig.updateOnce() + self.sun.update() + for light in self.lights: + light.update(self.sun) def compute_coverage(fish, x, y): |
