diff options
-rw-r--r-- | LightInstallation.py | 14 | ||||
-rw-r--r-- | Util.py | 57 | ||||
-rw-r--r-- | behaviors/ColorChangerBehavior.py | 4 | ||||
-rw-r--r-- | config/LightInstallationConfig.xml | 16 | ||||
-rw-r--r-- | operationscore/Behavior.py | 3 | ||||
-rw-r--r-- | operationscore/Input.py | 3 | ||||
-rw-r--r-- | operationscore/SmootCoreObject.py | 6 | ||||
-rw-r--r-- | pixelcore/Pixel.py | 8 | ||||
-rw-r--r-- | pixelcore/Screen.py | 17 | ||||
-rw-r--r-- | pixelmappers/GaussianMapper.py | 7 |
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 @@ -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 |