summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgroup1 <f16_group1@pbridge.adm.cs.cmu.edu>2016-10-09 14:45:03 -0400
committergroup1 <f16_group1@pbridge.adm.cs.cmu.edu>2016-10-09 14:45:03 -0400
commitdfe1127addf7e31acd63e87db0a5d5e35628ea67 (patch)
tree101526e338590ba0980ff1809a8338cd12b50b4e
parentdd7dd93d9e1ee2e0095f0fa403a499b69aa289a8 (diff)
downloadbridge-dfe1127addf7e31acd63e87db0a5d5e35628ea67.tar.zst
Add twinkle
-rw-r--r--.gitignore3
-rwxr-xr-xbridge.py29
-rwxr-xr-xbrige.py100
-rw-r--r--constants.py22
-rw-r--r--fish_render.py44
-rw-r--r--sunrise.py127
-rwxr-xr-xtwinkle.py112
-rw-r--r--webapp/app/__init__.py11
-rw-r--r--webapp/app/templates/index.html55
-rw-r--r--webapp/app/views.py37
-rwxr-xr-xwebapp/run.py7
11 files changed, 526 insertions, 21 deletions
diff --git a/.gitignore b/.gitignore
index 8d35cb3..c6ad15f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,5 @@
__pycache__
*.pyc
+
+webapp/packages
+webapp/tmp
diff --git a/bridge.py b/bridge.py
index 87b339c..4d5d817 100755
--- a/bridge.py
+++ b/bridge.py
@@ -1,18 +1,30 @@
#!/usr/bin/python2
"""Simple demo of oscillating colors."""
-from __future__ import division, unicode_literals
+from __future__ import division, print_function
import color
import constants
-from DummyRig import DummyRig
import fish_render
+import sunrise
import time
+import random
try:
import lumiversepython
except ImportError:
have_lumiversepython = False
+ from DummyRig import DummyRig
else:
have_lumiversepython = True
+
+
+
+#fish_render = sunrise
+
+
+
+
+
+
def get_all_lights(rig):
"""Return a list of all panels."""
return [
@@ -27,11 +39,20 @@ def get_all_lights(rig):
def demo(lights, rig):
"""Do some light things."""
- fish = fish_render.Fish(0, 0, 2, 1, color.red, 1 / constants.FRAME_RATE)
+ #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()
- time.sleep(1 / constants.FRAME_RATE)
+ 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():
diff --git a/brige.py b/brige.py
new file mode 100755
index 0000000..314f9db
--- /dev/null
+++ b/brige.py
@@ -0,0 +1,100 @@
+#!/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()
diff --git a/constants.py b/constants.py
index e19c127..1685c5a 100644
--- a/constants.py
+++ b/constants.py
@@ -1,10 +1,22 @@
"""Constants that may be tweaked in the future."""
from __future__ import division, unicode_literals
-FRAME_RATE = 10 #44
+FRAME_RATE = 22
MIN_VALUE = 0
MAX_VALUE = 1
-MAX_TIME = 4
-MIN_TIME = 0.3
-MAX_HUE = 169 / 360
-MIN_HUE = 250 / 360
+MAX_TIME = 2
+MIN_TIME = 0.1
+MIN_HUE = 207 / 360
+MAX_HUE = 250 / 360
+MAX_SATURATION = 1
+MIN_SATURATION = 0.5
+MIN_VALUE = 0.3
+MAX_VALUE = 1
+
+# shallow
+MIN_HUE = 169 / 360
+MAX_HUE = 250 / 360
+MAX_SATURATION = 1
+MIN_SATURATION = 0.5
+MIN_VALUE = 0.3
+MAX_VALUE = 1
diff --git a/fish_render.py b/fish_render.py
index 4924016..18aecac 100644
--- a/fish_render.py
+++ b/fish_render.py
@@ -2,6 +2,9 @@
from __future__ import division, unicode_literals
import color
import random
+import constants
+from constants import *
+import math
class Fish(object):
"""Object displayed on the bridge, probably a fish."""
@@ -18,6 +21,12 @@ class Fish(object):
def update(self):
"""Swim gently to the other side of the bridge."""
self.x += self.step
+ if self.x > 200:
+ self.x = 0
+ self.y = 0.25 + 0.25 * math.sin(math.pi * self.x / 10)
+ #theta = random.random() * math.pi / 2 - math.pi / 4
+ #self.y += 0.01 * math.sin(theta)
+ #print(self.y)
class Light(object):
@@ -33,7 +42,7 @@ class Light(object):
def update(self, fish):
"""Change color depending on where the fish is."""
- if abs(self.transitioning_to - self.color) < self.step:
+ if abs(self.transitioning_to - self.color) <= self.step:
self.transitioning_to = pick_HSV().to_RGB()
self.step = (random_change()
* abs(self.color - self.transitioning_to))
@@ -41,7 +50,13 @@ class Light(object):
self.color, self.transitioning_to, self.step
)
coverage = compute_coverage(fish, self.x, self.y)
+ #coverage *= coverage
new_color = coverage * fish.color + (1 - coverage) * new_background
+ #new_color = new_background
+ self.color = new_background
+ if self.x == 30 and self.y == 0:
+ pass
+ #print(self.color.r(), self.color.g(), self.color.b())
self.light.setRGBRaw(
*map(lambda x: clamp(0, x, 1), new_color.components)
)
@@ -61,24 +76,28 @@ class Bridge(object):
for y, light in enumerate(light_col):
self.fish.update()
light.update(self.fish)
- self.rig.updateOnce()
+ 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)
+ middle_of_fish = fish.x + fish.width / 2
+ middle_of_panel = x + 0.5
+ diff = abs(middle_of_fish - middle_of_panel) / (fish.width / 2)
+ scale = 1 - diff
+ min_x = min(max(x, fish.x), x + 1)
+ max_x = max(min(x+1, fish.x + fish.width), x)
+ min_y = min(max(y, fish.y), y + 1)
+ max_y = max(min(y+1, fish.y + fish.height), y)
coverage = (max_x - min_x) * (max_y - min_y)
- return coverage
+ return coverage * scale
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()
+ hue = random.random() * (constants.MAX_HUE - constants.MIN_HUE) + constants.MIN_HUE
+ saturation = random.random() * (MAX_SATURATION - MIN_SATURATION) + MIN_SATURATION
+ value = random.random() * (MAX_VALUE - MIN_VALUE) + MIN_VALUE
return color.HSV(hue, saturation, value)
@@ -88,12 +107,13 @@ def transition(start, end, step):
return start
diff_vector = end - start
step_vector = diff_vector / abs(diff_vector) * step
- return step_vector + start
+ result = step_vector + start
+ return result
def random_change():
"""Return a random amount that a light should change each frame."""
- min_time = int(MIN_TIME * FRAME_RATE)
+ min_time = int(constants.MIN_TIME * FRAME_RATE)
max_time = int(MAX_TIME * FRAME_RATE)
return 1 / random.randint(min_time, max_time)
diff --git a/sunrise.py b/sunrise.py
new file mode 100644
index 0000000..68a423c
--- /dev/null
+++ b/sunrise.py
@@ -0,0 +1,127 @@
+"""Rendering classes and helper functions."""
+from __future__ import division
+import color
+import random
+import constants
+from constants import *
+import math
+
+class Fish(object):
+ """Object displayed on the bridge, probably a fish."""
+ def __init__(self, x, y, width, height, c, step):
+ """Create fish with default parameters."""
+ self.x = x
+ self.y = y
+ self.x = 75
+ self.y = -2
+ self.width = width
+ self.width = 75
+ self.height = height
+ self.height = 2
+ self.color = c
+ self.color = color.RGB(1, 0.5, 0)
+ self.speed = step
+ self.step = step
+ self.wait = 0
+
+ def update(self):
+ """Swim gently to the other side of the bridge."""
+ #self.x += self.step
+ #if self.x > 200:
+ # self.x = 0
+ #self.y = 0.25 + 0.25 * math.sin(math.pi * self.x / 10)
+ #theta = random.random() * math.pi / 2 - math.pi / 4
+ #self.y += 0.01 * math.sin(theta)
+ #print(self.y)
+ self.y += 0.000005
+ if self.y >= 1:
+ self.y = 1
+ self.wait += 1
+ if self.wait >= 200:
+ self.wait = 0
+ self.y = -2
+
+
+class Light(object):
+ """Represent a bridge light and its state."""
+ def __init__(self, x, y, light):
+ """Store all facts about a light."""
+ self.light = light
+ self.color = color.black
+ self.transitioning_to = self.color
+ self.step = 0
+ self.x = x
+ self.y = y
+
+ def update(self, fish):
+ """Change color depending on where the fish is."""
+ if self.y == 1:
+ new_color = color.RGB(0.5, 0.5, 0.5)
+ else:
+ new_color = color.RGB(0.5, 0.5, 0)
+ coverage = compute_coverage(fish, self.x, self.y)
+ ccolor = new_color * (1 - coverage) + fish.color * coverage
+ self.light.setRGBRaw(
+ *map(lambda x: clamp(0, x, 1), ccolor.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
+ middle_of_panel = x + 0.5
+ diff = abs(middle_of_fish - middle_of_panel) / (fish.width / 2)
+ scale = 1 - diff
+ min_x = min(max(x, fish.x), x + 1)
+ max_x = max(min(x+1, fish.x + fish.width), x)
+ min_y = min(max(y, fish.y), y + 1)
+ max_y = max(min(y+1, fish.y + fish.height), y)
+ coverage = (max_x - min_x) * (max_y - min_y)
+ return coverage * scale
+
+
+def pick_HSV():
+ """Return a random color in an appropriate interval."""
+ hue = random.random() * (constants.MAX_HUE - constants.MIN_HUE) + constants.MIN_HUE
+ saturation = random.random() * (MAX_SATURATION - MIN_SATURATION) + MIN_SATURATION
+ value = random.random() * (MAX_VALUE - MIN_VALUE) + MIN_VALUE
+ return color.HSV(hue, saturation, value)
+
+
+def transition(start, end, step):
+ """Return a vector equal to (end - start) * step + start."""
+ if start == end:
+ return start
+ diff_vector = end - start
+ step_vector = diff_vector / abs(diff_vector) * step
+ result = step_vector + start
+ return result
+
+
+def random_change():
+ """Return a random amount that a light should change each frame."""
+ min_time = int(constants.MIN_TIME * FRAME_RATE)
+ max_time = int(MAX_TIME * FRAME_RATE)
+ return 1 / random.randint(min_time, max_time)
+
+
+def clamp(low, x, high):
+ """Return v such that low <= v <= high and |x - v| is minimal."""
+ return max(low, min(x, high))
diff --git a/twinkle.py b/twinkle.py
new file mode 100755
index 0000000..a2cb3d2
--- /dev/null
+++ b/twinkle.py
@@ -0,0 +1,112 @@
+#!/usr/bin/python2
+"""Simple demo of twinkle lights."""
+from __future__ import division
+import color
+import constants
+#from DummyRig import DummyRig
+from fish_render import *
+import fish_render
+from constants import *
+import time
+import random
+try:
+ import lumiversepython
+except ImportError:
+ have_lumiversepython = False
+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 flip():
+ """Return 0 with 99.9% prob. & 1 with .1% prob."""
+ # should be black most of the time
+ return random.random() < 0.0005
+
+
+def twinkle(lights, rig):
+ """Try to do some light things."""
+ light_status = [
+ {
+ 'is_increasing': True,
+ 'is_on': False,
+ 'change': random_change(),
+ 'light': light,
+ 'intensity': 0,
+ }
+ for light_col in lights for light in light_col
+ ]
+ shooting_stars = list()
+ while True:
+ if random.random() < 1:
+ shooting_stars.append([random.randint(1, 180), random.random() < 0.5, 0])
+ for light_s in light_status:
+ is_increasing = light_s['is_increasing']
+ is_on = light_s['is_on']
+ change = light_s['change']
+ light = light_s['light']
+ intensity = light_s['intensity']
+ # R and G are either 0 or 1
+ if not is_on:
+ if flip():
+ is_on = True
+ is_increasing = True
+ change = 1.5 / FRAME_RATE
+ light_s['is_on'] = is_on
+ light_s['is_increasing'] = is_increasing
+ light_s['change'] = change
+ else:
+ continue
+ intensity = clamp(0, intensity + change * (int(is_increasing) * 2 - 1), 1)
+ light.light.setRGBRaw(intensity, intensity, intensity)
+ light_s['intensity'] = intensity
+ if intensity == 0:
+ light_s['is_on'] = False
+ if intensity == 1:
+ light_s['is_increasing'] = False
+ for i, star in enumerate(shooting_stars):
+ star[2] += 1
+ if star[2] > 10:
+ for dx in range(-6, 7):
+ light_status[star[0] + dx]['light'].light.setRGBRaw(0, 0, 0)
+ del shooting_stars[i]
+ continue
+ star[0] += int(star[1]) * 2 - 1
+ for dx in range(-6, 7):
+ intensity = 1 - 1 / 6 * abs(dx)
+ light_status[star[0] + dx]['light'].light.setRGBRaw(intensity, intensity, intensity)
+ rig.updateOnce()
+ time.sleep(1 / FRAME_RATE)
+
+def sunrise(lights, rig):
+ #rig.select('$side={y}[$sequence={x}]'.format(y=y, x=x))
+ rig.select("$side=top[$panel=27|$panel=28]")
+ rig.updateOnce()
+ time.sleep(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)
+ #for light in lights:
+ # light.setRGBRaw(0, 0, 0)
+ rig.updateOnce()
+ time.sleep(3)
+ twinkle(lights, rig)
+
+if __name__ == '__main__':
+ main()
diff --git a/webapp/app/__init__.py b/webapp/app/__init__.py
new file mode 100644
index 0000000..aa2e264
--- /dev/null
+++ b/webapp/app/__init__.py
@@ -0,0 +1,11 @@
+from flask import Flask
+import socketio
+import eventlet
+import eventlet.wsgi
+
+sio = socketio.Server(async_mode='threading')
+app = Flask(__name__)
+app.wsgi_app = socketio.Middleware(sio, app.wsgi_app)
+from app import views
+
+
diff --git a/webapp/app/templates/index.html b/webapp/app/templates/index.html
new file mode 100644
index 0000000..b0d9bb3
--- /dev/null
+++ b/webapp/app/templates/index.html
@@ -0,0 +1,55 @@
+<html>
+ <head>
+ <script type="text/javascript" src="//code.jquery.com/jquery-2.1.4.min.js"></script>
+ <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/socket.io/1.3.5/socket.io.min.js"></script>
+
+ <script>
+ var SPAWN_URL = "/spawn";
+
+ function creature(name, socket) {
+ var self = this;
+ self.name = name;
+ self.socket = socket;
+
+ self.render = function($parent) {
+ var $a = $('<a>');
+ $a.text(self.name);
+ $a.click(self.click.bind(self));
+
+ var $li = $('<li>');
+ $li.append($a);
+ $parent.append($li);
+ };
+
+ self.click = function() {
+ self.socket.emit('spawn', {name:self.name});
+ }
+ }
+
+ $(document).ready(function() {
+ var namespace = '/spawn';
+ var socket = io.connect('http://' + document.domain + ':' + location.port + namespace);
+
+ socket.on('connect', function() {
+ console.log('connected!');
+ });
+
+ socket.on('new creature', function(msg) {
+ console.log('new!');
+ var c = new creature(msg.name, socket);
+ c.render($('#creatures'));
+ });
+
+ socket.on('disconnect', function() {
+ console.log('disconnected');
+ });
+ });
+
+ </script>
+ <title>{{ title }}</title>
+ </head>
+ <body>
+ <h1>Ocean Fun Times</h1>
+ <ul id="creatures"></ul>
+ </body>
+</html>
diff --git a/webapp/app/views.py b/webapp/app/views.py
new file mode 100644
index 0000000..4aa2c05
--- /dev/null
+++ b/webapp/app/views.py
@@ -0,0 +1,37 @@
+from flask import render_template, request
+from app import app, sio
+import time
+
+import threading
+
+thread = None
+
+@app.route('/')
+@app.route('/index')
+def index():
+ return render_template('index.html',
+ title='F16 Group1')
+
+connections = set()
+
+@sio.on('connect', namespace='/spawn')
+def connect(sid, environ):
+ print("connect ", sid)
+ connections.add(sid)
+
+@sio.on('spawn', namespace='/spawn')
+def message(sid, data):
+ print("message ", data)
+
+@sio.on('disconnect', namespace='/spawn')
+def disconnect(sid):
+ print('disconnect', sid)
+ connections.remove(sid)
+
+
+
+def add_creature():
+ time.sleep(5)
+ sio.emit('new creature', {'name': 'fish1'}, namespace='/spawn')
+
+thread = sio.start_background_task(add_creature)
diff --git a/webapp/run.py b/webapp/run.py
new file mode 100755
index 0000000..b5c8c6f
--- /dev/null
+++ b/webapp/run.py
@@ -0,0 +1,7 @@
+#!/usr/bin/env python
+
+import sys
+sys.path.append('packages')
+
+from app import app
+app.run(threaded=True, host='', port=8000)