diff options
-rw-r--r-- | LightInstallation.py | 9 | ||||
-rw-r--r-- | Util.py | 7 | ||||
-rw-r--r-- | behaviors/BehaviorChain.py | 9 | ||||
-rw-r--r-- | behaviors/ColorChangerBehavior.py | 6 | ||||
-rw-r--r-- | behaviors/DecayBehavior.py | 2 | ||||
-rw-r--r-- | behaviors/RecursiveDecay.py | 12 | ||||
-rw-r--r-- | config/GaussianMapper.params | 3 | ||||
-rw-r--r-- | config/LightInstallationConfig.xml | 52 | ||||
-rw-r--r-- | config/RecursiveDecay.params | 2 | ||||
-rw-r--r-- | operationscore/Behavior.py | 1 | ||||
-rw-r--r-- | operationscore/SmootCoreObject.py | 10 | ||||
-rw-r--r-- | pixelmappers/GaussianMapper.py | 13 |
12 files changed, 114 insertions, 12 deletions
diff --git a/LightInstallation.py b/LightInstallation.py index 7d8b7b0..849e41f 100644 --- a/LightInstallation.py +++ b/LightInstallation.py @@ -80,14 +80,20 @@ class LightInstallation: return True def mainLoop(self): #self.screen.allOn() + lastLoopTime = Util.time() + refreshInterval = 30 while 1: - time.sleep(.1) + loopStart = Util.time() responses = self.evaluateBehaviors() #inputs are all queued when they #happen, so we only need to run the behaviors [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) + if sleepTime > 0: + time.sleep(sleepTime/1000) #evaluates all the behaviors (including inter-dependencies) and returns a #list of responses to go to the screen. def evaluateBehaviors(self): @@ -114,7 +120,6 @@ class LightInstallation: if inputId in self.inputBehaviorRegistry: #it could be a behavior self.inputBehaviorRegistry[inputId].append(behavior['Id']) def processResponse(self,inputDict, responseDict): - print inputDict, responseDict inputId = inputDict['Id'] boundBehaviorIds = self.inputBehaviorRegistry[inputId] [self.componentDict[b].addInput(responseDict) for b in boundBehaviorIds] @@ -41,12 +41,19 @@ def addPixelEventIfMissing(responseDict): else: raise Exception('Need Color. Probably') responseDict['PixelEvent'] = StepEvent.generate(300, color) +def gaussian(x,height,center,width): + a=height + b=center + c=width + return a*math.exp(-((x-b)**2)/(2*c**2)) def dist(l1, l2): return math.sqrt(sum([(l1[i]-l2[i])**2 for i in range(len(l1))])) def time(): return clock.time()*1000 def randomColor(): return [random.randint(0,255) for i in range(3)] +def chooseRandomColor(colorList): + return random.choice(colorList) def loadParamRequirementDict(className): return fileToDict(CONFIG_PATH + className) def loadConfigFile(fileName): diff --git a/behaviors/BehaviorChain.py b/behaviors/BehaviorChain.py index 8bf97bb..8b5cb1d 100644 --- a/behaviors/BehaviorChain.py +++ b/behaviors/BehaviorChain.py @@ -4,6 +4,9 @@ import pdb class BehaviorChain(Behavior): def behaviorInit(self): self.feedback = {} #dictionary to allow feedback of recursives + self.hooks = self['RecursiveHooks'] + if self.hooks == None: + self.hooks = {} def processResponse(self, sensorInputs, recursiveInputs): response = sensorInputs for behaviorId in self['ChainedBehaviors']: @@ -14,5 +17,11 @@ class BehaviorChain(Behavior): recurrence = [] (response,recurrence) = behavior.immediateProcessInput(response,\ recurrence) + + if behaviorId in self.hooks: #process recursive hook if there is one + hookBehavior = Util.getComponentById(self.hooks[behaviorId]) + (response, recurrence) = \ + hookBehavior.immediateProcessInput(response, + recurrence) self.feedback[behaviorId] = recurrence return response diff --git a/behaviors/ColorChangerBehavior.py b/behaviors/ColorChangerBehavior.py index 8ecc5f2..ca80eb4 100644 --- a/behaviors/ColorChangerBehavior.py +++ b/behaviors/ColorChangerBehavior.py @@ -6,7 +6,9 @@ class ColorChangerBehavior(Behavior): ret = [] for sensory in sensorInputs: newDict = dict(sensory) #don't run into shallow copy issues - #TODO: support for PixelEvents - newDict['Color'] = Util.randomColor() + if self['ColorList'] != None: + newDict['Color'] = Util.randomColor(self['ColorList']) + else: + newDict['Color'] = Util.chooseRandomColor() ret.append(newDict) return ret diff --git a/behaviors/DecayBehavior.py b/behaviors/DecayBehavior.py index 7956cbc..edc833d 100644 --- a/behaviors/DecayBehavior.py +++ b/behaviors/DecayBehavior.py @@ -11,4 +11,4 @@ class DecayBehavior(Behavior): outDict['PixelEvent'] = \ DecayEvent.generate(self['DecayType'],self['Coefficient'], sensory['Color']) ret.append(outDict) - return ret + return (ret, recursiveInputs) diff --git a/behaviors/RecursiveDecay.py b/behaviors/RecursiveDecay.py new file mode 100644 index 0000000..b119b85 --- /dev/null +++ b/behaviors/RecursiveDecay.py @@ -0,0 +1,12 @@ +from operationscore.Behavior import * +class RecursiveDecay(Behavior): + def processResponse(self, sensorInputs, recursiveInputs): + ret = [] + for response in recursiveInputs: + if not 'ResponsesLeft' in response: + response['ResponsesLeft'] = self['InitialResponseCount'] + else: + response['ResponsesLeft'] -= 1 + if response['ResponsesLeft'] > 0: + ret.append(response) + return (sensorInputs, ret) #no direct ouput diff --git a/config/GaussianMapper.params b/config/GaussianMapper.params new file mode 100644 index 0000000..288ec1d --- /dev/null +++ b/config/GaussianMapper.params @@ -0,0 +1,3 @@ +{'CutoffDist':'CutoffDist, the distance at which a light will not be turned +on','Height':'The height of the gaussian','Width':'The width of the +gaussian'} diff --git a/config/LightInstallationConfig.xml b/config/LightInstallationConfig.xml index 441b7e4..aa331af 100644 --- a/config/LightInstallationConfig.xml +++ b/config/LightInstallationConfig.xml @@ -31,13 +31,24 @@ </Args> </PixelStrip> </PixelConfiguration> - <PixelMapperConfiguration> + <!--<PixelMapperConfiguration> <PixelMapper> <Class>pixelmappers.SimpleMapper</Class> <Args> <Id>simplemap</Id> </Args> </PixelMapper> + </PixelMapperConfiguration>--> + <PixelMapperConfiguration> + <PixelMapper> + <Class>pixelmappers.GaussianMapper</Class> + <Args> + <Id>gaussmap</Id> + <CutoffDist>30</CutoffDist> + <Width>5</Width> + <Height>.5</Height> + </Args> + </PixelMapper> </PixelMapperConfiguration> <RendererConfiguration> <Renderer> @@ -47,7 +58,7 @@ <displaySize>(1300,50)</displaySize> </Args> </Renderer> - <!-- <Renderer> + <Renderer> <Class>renderers.IndoorRenderer</Class> <Args> <Id>indoorRenderer</Id> @@ -56,7 +67,7 @@ <PortMapping>{'strip1':1, 'strip2':2}</PortMapping> </PowerSupply> </Args> - </Renderer>--> + </Renderer> </RendererConfiguration> <InputConfiguration> <InputElement> @@ -67,6 +78,14 @@ </Args> </InputElement> <InputElement> + <Class>inputs.PygameInput</Class> + <Args><!--Passed as a dictionary--> + <Id>followmouse</Id> + <RefreshInterval>100</RefreshInterval> + <FollowMouse>True</FollowMouse> + </Args> + </InputElement> + <InputElement> <Class>inputs.UDPInput</Class> <Args> <Id>UDP</Id> @@ -102,7 +121,7 @@ <Args> <Id>decay</Id> <DecayType>Exponential</DecayType> - <Coefficient>.005</Coefficient> + <Coefficient>.001</Coefficient> <z-index>0</z-index> <RenderToScreen>False</RenderToScreen> <Inputs> @@ -120,6 +139,13 @@ </Args> </Behavior> <Behavior> + <Class>behaviors.RecursiveDecay</Class> + <Args> + <Id>recursivedecay</Id> + <InitialResponseCount>20000</InitialResponseCount> + </Args> + </Behavior> + <Behavior> <Class>behaviors.BehaviorChain</Class> <Args> <Id>runcolordecay</Id> @@ -131,6 +157,22 @@ <Id>running</Id> <Id>decay</Id> </ChainedBehaviors> + <RecursiveHooks>{'running':'recursivedecay'}</RecursiveHooks> + <RenderToScreen>True</RenderToScreen> + </Args> + </Behavior> + <Behavior> + <Class>behaviors.BehaviorChain</Class> + <Args> + <Id>mousechaser</Id> + <Inputs> + <Id>followmouse</Id> + </Inputs> + <ChainedBehaviors> + <Id>echo</Id> + <Id>colorchange</Id> + <Id>decay</Id> + </ChainedBehaviors> <RenderToScreen>True</RenderToScreen> </Args> </Behavior> @@ -141,7 +183,7 @@ <Inputs> <Id>pygame</Id> </Inputs> - <StepSize>10</StepSize> + <StepSize>1</StepSize> <RenderToScreen>False</RenderToScreen> </Args> </Behavior> diff --git a/config/RecursiveDecay.params b/config/RecursiveDecay.params new file mode 100644 index 0000000..fe9d553 --- /dev/null +++ b/config/RecursiveDecay.params @@ -0,0 +1,2 @@ +{'InitialResponseCount':'Initial response count, the number of times a +recursive response can occur, must be specified.'} diff --git a/operationscore/Behavior.py b/operationscore/Behavior.py index 8db2d88..e300f6b 100644 --- a/operationscore/Behavior.py +++ b/operationscore/Behavior.py @@ -37,7 +37,6 @@ class Behavior(SmootCoreObject): except: return (self.processResponse(sensorInputs, recursiveInputs),[]) def addInputs(self, sensorInputs): - print sensorInputs if type(sensorInputs) == type([]): [self.addInput(sensorInput) for sensorInput in sensorInputs] else: diff --git a/operationscore/SmootCoreObject.py b/operationscore/SmootCoreObject.py index 2901ef6..84319af 100644 --- a/operationscore/SmootCoreObject.py +++ b/operationscore/SmootCoreObject.py @@ -3,9 +3,14 @@ import pdb class SmootCoreObject: def __init__(self, argDict): self.argDict = argDict + self.validateArgs(self.className()+'.params') self.init() #call init of inheriting class + # self.__setitem__ = self.argDict.__setitem__ + # self.__getitem__ = self.argDict.__getitem__ def init(self): pass + def className(self): + return str(self.__class__).split('.')[-1] def __setitem__(self,k, item): self.argDict[k] = item def __getitem__(self, item): @@ -16,7 +21,10 @@ class SmootCoreObject: def __getiter__(self): return self.argDict.__getiter__() def validateArgs(self, argFileName): - self.validateArgDict(Util.loadParamRequirementDict(argFileName)) + try: + self.validateArgDict(Util.loadParamRequirementDict(argFileName)) + except IOError: + print 'No Arg Dict found for ' + self.className() def validateArgDict(self, validationDict): for item in validationDict: if not item in self.argDict: diff --git a/pixelmappers/GaussianMapper.py b/pixelmappers/GaussianMapper.py new file mode 100644 index 0000000..552f5c9 --- /dev/null +++ b/pixelmappers/GaussianMapper.py @@ -0,0 +1,13 @@ +from operationscore.PixelMapper import * +import Util +class GaussianMapper(PixelMapper): + def mappingFunction(self, eventLocation, screen): + returnPixels = [] + for pixel in screen: + 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() + returnPixels.append((pixel, w)) + return returnPixels |