aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--LightInstallation.py14
-rw-r--r--Util.py57
-rw-r--r--behaviors/ColorChangerBehavior.py4
-rw-r--r--config/LightInstallationConfig.xml16
-rw-r--r--operationscore/Behavior.py3
-rw-r--r--operationscore/Input.py3
-rw-r--r--operationscore/SmootCoreObject.py6
-rw-r--r--pixelcore/Pixel.py8
-rw-r--r--pixelcore/Screen.py17
-rw-r--r--pixelmappers/GaussianMapper.py7
10 files changed, 103 insertions, 32 deletions
diff --git a/LightInstallation.py b/LightInstallation.py
index 849e41f..8f71cf0 100644
--- a/LightInstallation.py
+++ b/LightInstallation.py
@@ -1,14 +1,17 @@
from xml.etree.ElementTree import ElementTree
from pixelcore.Screen import *
from pixelcore.PixelStrip import *
-import pdb, sys, time, Util
+import pdb, sys, time, Util, thread
from pygame.locals import *
#Python class to instantiate and drive a Screen through different patterns,
#and effects.
class LightInstallation:
def __init__(self, configFileName):
+ self.timer = Util.Stopwatch()
+ self.timer.start()
self.inputs = {} #dict of inputs and their bound behaviors, keyed by InputId
self.behaviors = {}
+ self.lock = thread.allocate_lock()
self.behaviorOutputs = {} #key: [list of output destinations]
self.behaviorInputs = {}
self.componentDict = {}
@@ -39,6 +42,8 @@ class LightInstallation:
self.registerComponents(self.inputs)
self.registerComponents(self.behaviors)
#Done initializing. Lets start this thing!
+ self.timer.stop()
+ print 'Initialization done. Time: ', self.timer.elapsed(), 'ms'
self.mainLoop()
def initializeMapper(self, mapperConfig):
self.mapper = self.initializeComponent(mapperConfig)[0] #TODO: support
@@ -82,16 +87,21 @@ class LightInstallation:
#self.screen.allOn()
lastLoopTime = Util.time()
refreshInterval = 30
- while 1:
+ runCount = 1000
+ while runCount > 0:
+ runCount -= 1
loopStart = Util.time()
responses = self.evaluateBehaviors() #inputs are all queued when they
#happen, so we only need to run the behaviors
+ self.timer.start()
[self.screen.respond(response) for response in responses if
response != []]
self.screen.timeStep()
[r.render(self.screen) for r in self.renderers]
loopElapsed = Util.time()-loopStart
sleepTime = max(0,refreshInterval-loopElapsed)
+ self.timer.stop()
+ #print self.timer.elapsed()
if sleepTime > 0:
time.sleep(sleepTime/1000)
#evaluates all the behaviors (including inter-dependencies) and returns a
diff --git a/Util.py b/Util.py
index 377c2e3..ea75b05 100644
--- a/Util.py
+++ b/Util.py
@@ -1,18 +1,21 @@
import pdb
from xml.etree.ElementTree import ElementTree
import math,struct
+from bisect import *
#import json # json.loads() to decode string; json.dumps() to encode data
import socket
import random
from pygame.locals import *
import time as clock
from pixelevents.StepEvent import *
+
VERSION = 0x0001
MAGIC = 0x4adc0104
MOREMAGIC = 0xdeadbeef
DEEPMAGIC = 0xc001d00d
MAGICHASH = 0x69000420
PORTOUT = 0x0108
+classArgsMem = {}
UNI = 0
CONFIG_PATH = 'config/'
kinetDict = {'flags': 0, 'startcode': 0, 'pad':0}
@@ -55,23 +58,38 @@ def randomColor():
def chooseRandomColor(colorList):
return random.choice(colorList)
def loadParamRequirementDict(className):
- return fileToDict(CONFIG_PATH + className)
+ if not className in classArgsMem: #WOO CACHING
+ classArgsMem[className] = fileToDict(CONFIG_PATH + className)
+ return classArgsMem[className]
def loadConfigFile(fileName):
- fileName = CONFIG_PATH + fileName
- if '.params' in fileName:
- return fileToDict(fileName)
- if '.xml' in fileName:
- config = ElementTree()
- config.parse(fileName)
- return config
+ try:
+ fileName = CONFIG_PATH + fileName
+ if '.params' in fileName:
+ return fileToDict(fileName)
+ if '.xml' in fileName:
+ config = ElementTree()
+ config.parse(fileName)
+ return config
+ except:
+ return None
def fileToDict(fileName):
fileText = ''
- with open(fileName) as f:
- for line in f:
- fileText += line.rstrip('\n').lstrip('\t') + ' '
+ try:
+ with open(fileName) as f:
+ for line in f:
+ fileText += line.rstrip('\n').lstrip('\t') + ' '
+ except IOError:
+ return {}
if fileText == '':
return {}
return eval(fileText)
+def find_le(a, x):
+ 'Find rightmost value less than or equal to x'
+ return bisect_right(a, x)-1
+
+def find_ge(a, x):
+ 'Find leftmost value greater than x'
+ return bisect_left(a, x)
def safeColor(c):
return [min(channel,255) for channel in c]
def combineColors(c1,c2):
@@ -186,7 +204,22 @@ def testXMLParse(fileName):
config.parse(fileName)
print generateArgDict(config.find('ChildElement'))
print generateArgDict(config.find('Renderer'))
-
+class Stopwatch:
+ def __init__(self):
+ self.running = False
+ self.startTime = -1
+ self.stopTime = -1
+ def start(self):
+ self.startTime = Util.time()
+ self.running = True
+ def elapsed(self):
+ if self.running:
+ return Util.time()-self.startTime
+ else:
+ return self.stopTime - self.startTime
+ def stop(self):
+ self.stopTime = Util.time()
+ self.running = False
##CONSTANTS##
location = 'Location'
diff --git a/behaviors/ColorChangerBehavior.py b/behaviors/ColorChangerBehavior.py
index ca80eb4..12ef6f4 100644
--- a/behaviors/ColorChangerBehavior.py
+++ b/behaviors/ColorChangerBehavior.py
@@ -7,8 +7,8 @@ class ColorChangerBehavior(Behavior):
for sensory in sensorInputs:
newDict = dict(sensory) #don't run into shallow copy issues
if self['ColorList'] != None:
- newDict['Color'] = Util.randomColor(self['ColorList'])
+ newDict['Color'] = Util.chooseRandomColor(self['ColorList'])
else:
- newDict['Color'] = Util.chooseRandomColor()
+ newDict['Color'] = Util.randomColor()
ret.append(newDict)
return ret
diff --git a/config/LightInstallationConfig.xml b/config/LightInstallationConfig.xml
index aa331af..dfa05d7 100644
--- a/config/LightInstallationConfig.xml
+++ b/config/LightInstallationConfig.xml
@@ -46,7 +46,7 @@
<Id>gaussmap</Id>
<CutoffDist>30</CutoffDist>
<Width>5</Width>
- <Height>.5</Height>
+ <Height>1</Height>
</Args>
</PixelMapper>
</PixelMapperConfiguration>
@@ -77,14 +77,14 @@
<RefreshInterval>100</RefreshInterval>
</Args>
</InputElement>
- <InputElement>
+ <!--<InputElement>
<Class>inputs.PygameInput</Class>
- <Args><!--Passed as a dictionary-->
+ <Args>
<Id>followmouse</Id>
<RefreshInterval>100</RefreshInterval>
<FollowMouse>True</FollowMouse>
</Args>
- </InputElement>
+ </InputElement>-->
<InputElement>
<Class>inputs.UDPInput</Class>
<Args>
@@ -134,7 +134,7 @@
<Id>debug</Id>
<z-index>0</z-index>
<Inputs>
- <Id>UDP</Id>
+ <Id>pygame</Id>
</Inputs>
</Args>
</Behavior>
@@ -161,7 +161,7 @@
<RenderToScreen>True</RenderToScreen>
</Args>
</Behavior>
- <Behavior>
+ <!--<Behavior>
<Class>behaviors.BehaviorChain</Class>
<Args>
<Id>mousechaser</Id>
@@ -175,7 +175,7 @@
</ChainedBehaviors>
<RenderToScreen>True</RenderToScreen>
</Args>
- </Behavior>
+ </Behavior>-->
<Behavior>
<Class>behaviors.RunningBehavior</Class>
<Args>
@@ -183,7 +183,7 @@
<Inputs>
<Id>pygame</Id>
</Inputs>
- <StepSize>1</StepSize>
+ <StepSize>10</StepSize>
<RenderToScreen>False</RenderToScreen>
</Args>
</Behavior>
diff --git a/operationscore/Behavior.py b/operationscore/Behavior.py
index e300f6b..83d2e7d 100644
--- a/operationscore/Behavior.py
+++ b/operationscore/Behavior.py
@@ -56,5 +56,6 @@ class Behavior(SmootCoreObject):
try:
return outputs
except:
- pdb.set_trace()
+ pass
+ #pdb.set_trace()
return outputs
diff --git a/operationscore/Input.py b/operationscore/Input.py
index 67a7bb0..9ee59f8 100644
--- a/operationscore/Input.py
+++ b/operationscore/Input.py
@@ -32,7 +32,10 @@ class Input(threading.Thread):
def respond(self, eventDict):
#if eventDict != []:
#pdb.set_trace()
+ self.parentScope.lock.acquire()
self.parentScope.processResponse(self.argDict, eventDict)
+ self.parentScope.lock.release()
+ time.sleep(.001)
def newEvent(self, event): #Mostly just useful for grabbing events from the
#computer running the sim (key presses, clicks etc.)
self.eventQueue.append(event)
diff --git a/operationscore/SmootCoreObject.py b/operationscore/SmootCoreObject.py
index 84319af..d29e710 100644
--- a/operationscore/SmootCoreObject.py
+++ b/operationscore/SmootCoreObject.py
@@ -21,10 +21,8 @@ class SmootCoreObject:
def __getiter__(self):
return self.argDict.__getiter__()
def validateArgs(self, argFileName):
- try:
- self.validateArgDict(Util.loadParamRequirementDict(argFileName))
- except IOError:
- print 'No Arg Dict found for ' + self.className()
+ self.validateArgDict(Util.loadParamRequirementDict(argFileName))#util
+ #caches for us, woo!
def validateArgDict(self, validationDict):
for item in validationDict:
if not item in self.argDict:
diff --git a/pixelcore/Pixel.py b/pixelcore/Pixel.py
index 8c42581..4c8ec89 100644
--- a/pixelcore/Pixel.py
+++ b/pixelcore/Pixel.py
@@ -12,6 +12,7 @@ class Pixel:
def __init__(self, location):
self.location = location
self.events = {}
+ self.memState = None
def turnOn(self):
self.turnOnFor(-1)
#Turn the light white for 'time' ms. Really only meant for testing. Use
@@ -28,7 +29,13 @@ class Pixel:
self.events = {}
#Combines all PixelEvents currently active and computes the current color of
#the pixel.
+ def invalidateState(self):
+ self.memState = None
def state(self):
+ if self.memState != None:
+ return self.memState
+ if len(self.events) == 0:
+ return (0,0,0)
deadEvents = []
currentTime = Util.time()
resultingColor = (0,0,0)
@@ -40,6 +47,7 @@ class Pixel:
else:
deadEvents.append(eventTime)
[self.events.pop(event) for event in deadEvents]
+ self.memState = tuple(resultingColor)
return tuple(resultingColor)
def __str__(self):
return 'Loc: ' + str(self.location)
diff --git a/pixelcore/Screen.py b/pixelcore/Screen.py
index 6b5c737..71b9b0b 100644
--- a/pixelcore/Screen.py
+++ b/pixelcore/Screen.py
@@ -7,11 +7,24 @@ class Screen:
def __init__(self):
self.responseQueue = []
self.pixelStrips = []
+ self.xSortedPixels = []
+ self.xPixelLocs = []
sizeValid = False
def addStrip(self, lS):
self.pixelStrips.append(lS)
self.sizeValid = False #keep track of whether or not our screen size has
#been invalidated by adding more pixels
+ self.computeXSortedPixels()
+ #Returns (pixelIndex, pixel). Does a binary search.
+ def pixelsInRange(self, minX, maxX):
+ minIndex = Util.find_ge(self.xPixelLocs, minX)
+ maxIndex = Util.find_le(self.xPixelLocs, maxX)+1
+ return self.xSortedPixels[minIndex:maxIndex]
+ def computeXSortedPixels(self):
+ for pixel in self:
+ self.xSortedPixels.append((pixel.location[0], pixel))
+ self.xSortedPixels.sort()
+ self.xPixelLocs = [p[0] for p in self.xSortedPixels]
def render(self, surface):
[lS.render(surface) for lS in self.pixelStrips]
def setMapper(self, mapper):
@@ -29,6 +42,7 @@ class Screen:
self.responseQueue = []
for response in tempQueue:
self.processResponse(response)
+ [p.invalidateState() for p in self]
#public
def respond(self, responseInfo):
self.responseQueue.append(responseInfo)
@@ -53,7 +67,8 @@ class Screen:
#each to prevent interference
#[strip.respond(dict(responseInfo)) for strip in self.pixelStrips]
if type(responseInfo) != type(dict()):
- pdb.set_trace()
+ pass
+ #pdb.set_trace()
pixelWeightList = self.mapper.mapEvent(responseInfo['Location'], self)
Util.addPixelEventIfMissing(responseInfo)
for (pixel, weight) in pixelWeightList:
diff --git a/pixelmappers/GaussianMapper.py b/pixelmappers/GaussianMapper.py
index 552f5c9..1cf9e88 100644
--- a/pixelmappers/GaussianMapper.py
+++ b/pixelmappers/GaussianMapper.py
@@ -3,11 +3,14 @@ import Util
class GaussianMapper(PixelMapper):
def mappingFunction(self, eventLocation, screen):
returnPixels = []
- for pixel in screen:
+ [x,y] = eventLocation
+ for (x,pixel) in screen.pixelsInRange(x-self['CutoffDist'], \
+ x+self['CutoffDist']):
pixelDist = Util.dist(pixel.location, eventLocation)
if pixelDist < self['CutoffDist']:
w = Util.gaussian(pixelDist, self['Height'], 0, self['Width'])
if w>1:
- pdb.set_trace()
+ #pdb.set_trace()
+ pass
returnPixels.append((pixel, w))
return returnPixels