aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--LightInstallation.py7
-rw-r--r--Util.py7
-rw-r--r--__init__.py0
-rw-r--r--config/.LightInstallationConfig.xml.swpbin20480 -> 0 bytes
-rw-r--r--config/DecayBehavior.params3
-rw-r--r--config/LightInstallationConfig.xml9
-rw-r--r--config/MouseFollowerDemo.xml138
-rw-r--r--config/PixelAssembler.params6
-rw-r--r--operationscore/PixelEvent.py2
-rw-r--r--operationscore/PixelMapper.py17
-rw-r--r--pixelcore/Pixel.py13
-rw-r--r--pixelcore/PixelStrip.py2
-rw-r--r--pixelcore/Screen.py8
-rw-r--r--pixelmappers/SimpleMapper.py14
-rw-r--r--pixelmappers/__init__.py0
15 files changed, 219 insertions, 7 deletions
diff --git a/LightInstallation.py b/LightInstallation.py
index 4efa17b..6866271 100644
--- a/LightInstallation.py
+++ b/LightInstallation.py
@@ -24,17 +24,24 @@ class LightInstallation:
pixelConfig = config.find('PixelConfiguration')
inputConfig = config.find('InputConfiguration')
behaviorConfig = config.find('BehaviorConfiguration')
+ mapperConfig = config.find('PixelMapperConfiguration')
#inits
self.initializeScreen(pixelConfig)
self.initializeRenderers(rendererConfig)
self.initializeInputs(inputConfig)
self.initializeBehaviors(behaviorConfig)
+ self.initializeMapper(mapperConfig)
+
+ self.screen.setMapper(self.mapper)
#registration in dict
self.registerComponents(self.renderers)
self.registerComponents(self.inputs)
self.registerComponents(self.behaviors)
#Done initializing. Lets start this thing!
self.mainLoop()
+ def initializeMapper(self, mapperConfig):
+ self.mapper = self.initializeComponent(mapperConfig)[0] #TODO: support
+ #multiple mappers
def initializeScreen(self, layoutConfig):
pixelAssemblers = self.initializeComponent(layoutConfig)
[self.addPixelStrip(l) for l in pixelAssemblers]
diff --git a/Util.py b/Util.py
index 533f0d9..a398d7c 100644
--- a/Util.py
+++ b/Util.py
@@ -23,6 +23,13 @@ def getComponentById(cid):
return componentDict[cid]
else:
return None
+def addPixelEventIfMissing(responseDict):
+ if not 'PixelEvent' in responseDict:
+ if 'Color' in responseDict:
+ color = responseDict['Color']
+ else:
+ raise Exception('Need Color. Probably')
+ responseDict['PixelEvent'] = StepEvent.generate(300, color)
def dist(l1, l2):
return math.sqrt(sum([(l1[i]-l2[i])**2 for i in range(len(l1))]))
def time():
diff --git a/__init__.py b/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/__init__.py
diff --git a/config/.LightInstallationConfig.xml.swp b/config/.LightInstallationConfig.xml.swp
deleted file mode 100644
index 05e30ce..0000000
--- a/config/.LightInstallationConfig.xml.swp
+++ /dev/null
Binary files differ
diff --git a/config/DecayBehavior.params b/config/DecayBehavior.params
new file mode 100644
index 0000000..67b7dcf
--- /dev/null
+++ b/config/DecayBehavior.params
@@ -0,0 +1,3 @@
+{'DecayType': 'Decay type missing. Specify Exponential or Proportional.',
+ 'Coefficient':'Coeffienct missing. Coefficient for decay type. E^(-ct) if
+ exponential, c/t if proportional.'}
diff --git a/config/LightInstallationConfig.xml b/config/LightInstallationConfig.xml
index 3f73e0c..713646e 100644
--- a/config/LightInstallationConfig.xml
+++ b/config/LightInstallationConfig.xml
@@ -1,7 +1,6 @@
<!---All configuration items contain a "Class" tag specifying the python class they represent, and an "Args" tag specifying the args to be passed in.-->
<LightInstallation>
<PixelConfiguration>
-
<PixelStrip>
<Class>layouts.ZigzagLayout</Class><!--Name of Layout Class,
imported dynamically via a eval('import ' + name)-->
@@ -35,6 +34,14 @@
</Args>
</PixelStrip>
</PixelConfiguration>
+ <PixelMapperConfiguration>
+ <PixelMapper>
+ <Class>pixelmappers.SimpleMapper</Class>
+ <Args>
+ <Id>simplemap</Id>
+ </Args>
+ </PixelMapper>
+ </PixelMapperConfiguration>
<RendererConfiguration>
<Renderer>
<Class>renderers.PygameRenderer</Class>
diff --git a/config/MouseFollowerDemo.xml b/config/MouseFollowerDemo.xml
new file mode 100644
index 0000000..9e9f6e5
--- /dev/null
+++ b/config/MouseFollowerDemo.xml
@@ -0,0 +1,138 @@
+<!---All configuration items contain a "Class" tag specifying the python class they represent, and an "Args" tag specifying the args to be passed in.-->
+<LightInstallation>
+ <LayoutConfiguration>
+
+ <PixelStrip>
+ <Class>layouts.ZigzagLayout</Class><!--Name of Layout Class,
+ imported dynamically via a eval('import ' + name)-->
+ <Args><!--Any args the layout class needs. This go as
+ elements of a dictionary that gets passed to the Layout machinery-->
+ <Id>strip1</Id>
+ <zigLength>25</zigLength>
+ <zigAxis>X</zigAxis>
+ <yDirection>-1</yDirection>
+ <pixelToPixelSpacing>12</pixelToPixelSpacing>
+ <spacing>12</spacing> <!--we can space at any value less the
+ l2lspacing-->
+ <numPixels>50</numPixels>
+ <originLocation>(10,10)</originLocation>
+ </Args>
+ </PixelStrip>
+ <PixelStrip>
+ <Class>layouts.ZigzagLayout</Class><!--Name of Layout Class,
+ imported dynamically via a eval('import ' + name)-->
+ <Args><!--Any args the layout class needs. This go as
+ elements of a dictionary that gets passed to the Layout machinery-->
+ <Id>strip2</Id>
+ <zigLength>25</zigLength>
+ <zigAxis>X</zigAxis>
+ <yDirection>1</yDirection>
+ <pixelToPixelSpacing>12</pixelToPixelSpacing>
+ <spacing>12</spacing> <!--we can space at any value less the
+ l2lspacing-->
+ <numPixels>50</numPixels>
+ <originLocation>(10,30)</originLocation>
+ </Args>
+ </PixelStrip>
+ </LayoutConfiguration>
+ <RendererConfiguration>
+ <Renderer>
+ <Class>renderers.PygameRenderer</Class>
+ <Args>
+ <displaySize>(1300,50)</displaySize>
+ </Args>
+ </Renderer>
+ <Renderer>
+ <Class>renderers.IndoorRenderer</Class>
+ <Args>
+ <PowerSupply>
+ <IP>10.1.218.72</IP>
+ <PortMapping>{'strip1':1, 'strip2':2}</PortMapping>
+ </PowerSupply>
+ </Args>
+ </Renderer>
+ </RendererConfiguration>
+ <InputConfiguration>
+ <InputElement>
+ <Class>inputs.PygameInput</Class>
+ <Args><!--Passed as a dictionary-->
+ <Id>pygame</Id>
+ <RefreshInterval>100</RefreshInterval>
+ </Args>
+ </InputElement>
+ <InputElement>
+ <Class>inputs.PygameInput</Class>
+ <Args><!--Passed as a dictionary-->
+ <Id>followmouse</Id>
+ <FollowMouse>True</FollowMouse>
+ <RefreshInterval>100</RefreshInterval>
+ </Args>
+ </InputElement>
+ <InputElement>
+ <Class>inputs.UDPInput</Class>
+ <Args>
+ <Id>UDP</Id>
+ <Port>6038</Port>
+ <RefreshInterval>100</RefreshInterval>
+ </Args>
+ </InputElement>
+ </InputConfiguration>
+ <BehaviorConfiguration>
+ <Behavior>
+ <Class>behaviors.EchoBehavior</Class>
+ <Args>
+ <Id>echo</Id>
+ <z-index>0</z-index>
+ <RenderToScreen>False</RenderToScreen>
+ <Inputs>
+ </Inputs>
+ </Args>
+ </Behavior>
+ <Behavior>
+ <Class>behaviors.ColorChangerBehavior</Class>
+ <Args>
+ <Id>color</Id>
+ <z-index>0</z-index>
+ <RenderToScreen>False</RenderToScreen>
+ <Inputs>
+ </Inputs>
+ </Args>
+ </Behavior>
+ <Behavior>
+ <Class>behaviors.DecayBehavior</Class>
+ <Args>
+ <Id>decay</Id>
+ <DecayType>Exponential</DecayType>
+ <Coefficient>.01</Coefficient>
+ <z-index>0</z-index>
+ <RenderToScreen>False</RenderToScreen>
+ <Inputs>
+ </Inputs>
+ </Args>
+ </Behavior>
+ <Behavior>
+ <Class>behaviors.DebugBehavior</Class>
+ <Args>
+ <Id>debug</Id>
+ <z-index>0</z-index>
+ <Inputs>
+ <Id>UDP</Id>
+ </Inputs>
+ </Args>
+ </Behavior>
+ <Behavior>
+ <Class>behaviors.BehaviorChain</Class>
+ <Args>
+ <Inputs>
+ <Id>followmouse</Id>
+ </Inputs>
+ <ChainedBehaviors>
+ <Id>echo</Id>
+ <Id>color</Id>
+ <Id>decay</Id>
+ </ChainedBehaviors>
+ <RenderToScreen>True</RenderToScreen>
+ </Args>
+ </Behavior>
+ </BehaviorConfiguration>
+</LightInstallation>
diff --git a/config/PixelAssembler.params b/config/PixelAssembler.params
new file mode 100644
index 0000000..1b1dee5
--- /dev/null
+++ b/config/PixelAssembler.params
@@ -0,0 +1,6 @@
+{'pixelToPixelSpacing':'pixelToPixel spacing not defined in argDict. This is the
+length of wire between 2 adjacent LEDs. Common values are 4 or 12.
+Specified in config XML.', 'numPixels': 'numPixels not defined in
+argDict. Common value: 50.', 'originLocation':'originLocation not
+defined in argDict. Values should be a string in the form (x,y). This
+should be specified in the config XML.'}
diff --git a/operationscore/PixelEvent.py b/operationscore/PixelEvent.py
index 07669cd..8567d93 100644
--- a/operationscore/PixelEvent.py
+++ b/operationscore/PixelEvent.py
@@ -8,6 +8,8 @@ class PixelEvent(SmootCoreObject):
self.initEvent()
def initEvent(self):
pass
+ def scale(c):
+ self['Color'] *= c
def state(self,timeDelay):
pass
diff --git a/operationscore/PixelMapper.py b/operationscore/PixelMapper.py
new file mode 100644
index 0000000..bbbfcf4
--- /dev/null
+++ b/operationscore/PixelMapper.py
@@ -0,0 +1,17 @@
+from operationscore.SmootCoreObject import *
+import Util
+import pdb
+class PixelMapper(SmootCoreObject):
+ def init(self):
+ self.mem = {} #Dictionary of all seen events
+ def mapEvent(self, eventLocation, screen):
+ if eventLocation in self.mem:
+ return self.mem[eventLocation]
+ else:
+ self.mem[eventLocation] = self.mappingFunction(eventLocation, screen)
+ return self.mem[eventLocation]
+ #Takes a Screen and returns a list of tuples
+ #(pixel, weight), with the sum of weights = 1
+ #TODO: consider abstracting away from pixels
+ def mappingFunction(self,eventLocation, screen):
+ pass
diff --git a/pixelcore/Pixel.py b/pixelcore/Pixel.py
index a71dba5..8c42581 100644
--- a/pixelcore/Pixel.py
+++ b/pixelcore/Pixel.py
@@ -3,26 +3,31 @@ import pdb
from pixelevents.StepEvent import *
#Pixel keeps a queue of events (PixelEvent objects) (actually a dictionary
#keyed by event time). Every time is state is
-#requested, it processes all the members of its cue. If a member returns none,
+#requested, it processes all the members of its queue. If a member returns none,
#it is removed from the queue. Otherwise, its value added to the Pixels color
#weighted by z-index.
class Pixel:
radius = 2
timeOff = -1
- def __init__(self, location, color):
+ def __init__(self, location):
self.location = location
- self.color = color
self.events = {}
def turnOn(self):
self.turnOnFor(-1)
+ #Turn the light white for 'time' ms. Really only meant for testing. Use
+ #processInput instead. Also, you shouldn't use this anyway. You should be
+ #using the input method on the screen!
def turnOnFor(self, time):
- event = StepEvent.generate(time, (255,0,255)) #TODO: Move color to
+ event = StepEvent.generate(time, (255,255,255)) #TODO: Move color to
self.processInput(event, 0)
#arg
+ #Add a pixelEvent to the list of active events
def processInput(self,pixelEvent,zindex): #consider migrating arg to dict
self.events[Util.time()] = (zindex, pixelEvent)
def clearAllEvents(self):
self.events = {}
+ #Combines all PixelEvents currently active and computes the current color of
+ #the pixel.
def state(self):
deadEvents = []
currentTime = Util.time()
diff --git a/pixelcore/PixelStrip.py b/pixelcore/PixelStrip.py
index 45d2c8b..c82a87a 100644
--- a/pixelcore/PixelStrip.py
+++ b/pixelcore/PixelStrip.py
@@ -11,7 +11,7 @@ class PixelStrip:
self.argDict = layoutEngine.getStripArgs()
def initStrip(self, layoutEngine):
pixelLocations = layoutEngine.getPixelLocations()
- self.pixels = [Pixel(l, (0,0,0)) for l in pixelLocations]
+ self.pixels = [Pixel(l) for l in pixelLocations]
def __iter__(self):
return self.pixels.__iter__()
def render(self, surface):
diff --git a/pixelcore/Screen.py b/pixelcore/Screen.py
index 9806daa..561dc21 100644
--- a/pixelcore/Screen.py
+++ b/pixelcore/Screen.py
@@ -9,6 +9,8 @@ class Screen:
self.pixelStrips.append(lS)
def render(self, surface):
[lS.render(surface) for lS in self.pixelStrips]
+ def setMapper(self, mapper):
+ self.mapper = mapper
def allOn(self):
[lS.allOn(-1) for lS in self.pixelStrips]
def __iter__(self): #the iterator of all our pixel strips chained togther
@@ -27,5 +29,9 @@ class Screen:
#private
def processResponse(self, responseInfo): #we need to make a new dict for
#each to prevent interference
- [strip.respond(dict(responseInfo)) for strip in self.pixelStrips]
+ #[strip.respond(dict(responseInfo)) for strip in self.pixelStrips]
+ pixelWeightList = self.mapper.mapEvent(responseInfo['Location'], self)
+ Util.addPixelEventIfMissing(responseInfo)
+ for (pixel, weight) in pixelWeightList: #TODO: weighting
+ pixel.processInput(responseInfo['PixelEvent'], 0) #TODO: z-index
diff --git a/pixelmappers/SimpleMapper.py b/pixelmappers/SimpleMapper.py
new file mode 100644
index 0000000..7d730f1
--- /dev/null
+++ b/pixelmappers/SimpleMapper.py
@@ -0,0 +1,14 @@
+from operationscore.PixelMapper import *
+import Util
+class SimpleMapper(PixelMapper):
+ def mappingFunction(self, eventLocation, screen):
+ bestDist = 10**10 #don't kill me, I'm lazy
+ bestPixel = None
+ for pixel in screen:
+ pixelDist = Util.dist(pixel.location, eventLocation)
+ if pixelDist < bestDist:
+ bestPixel = pixel
+ bestDist = pixelDist
+ return [(bestPixel,1)]
+
+
diff --git a/pixelmappers/__init__.py b/pixelmappers/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/pixelmappers/__init__.py