From a89c772cd64c6790906734f7128947e0f453c7e3 Mon Sep 17 00:00:00 2001 From: rcoh Date: Wed, 15 Dec 2010 00:18:24 -0500 Subject: About halfway done with the Util cleanup. Some stuff left to do with scoping etc. --- .gitignore | 2 + LightInstallation.py | 14 ++-- Util.py | 140 -------------------------------------- behaviors/ColorChangerBehavior.py | 7 +- operationscore/PixelEvent.py | 3 +- operationscore/SmootCoreObject.py | 3 +- pixelcore/Pixel.py | 9 +-- pixelevents/DecayEvent.py | 5 +- renderers/IndoorRenderer.py | 16 ++--- util/ColorOps.py | 11 +++ util/Config.py | 53 +++++++++++++++ util/NetworkOps.py | 6 ++ util/PacketComposition.py | 59 ++++++++++++++++ util/TimeOps.py | 19 ++++++ util/__init__.py | 0 15 files changed, 181 insertions(+), 166 deletions(-) create mode 100644 .gitignore create mode 100644 util/ColorOps.py create mode 100644 util/Config.py create mode 100644 util/NetworkOps.py create mode 100644 util/PacketComposition.py create mode 100644 util/TimeOps.py create mode 100644 util/__init__.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c9b568f --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.pyc +*.swp diff --git a/LightInstallation.py b/LightInstallation.py index e4adab7..5f12abf 100644 --- a/LightInstallation.py +++ b/LightInstallation.py @@ -3,11 +3,13 @@ from pixelcore.Screen import * from pixelcore.PixelStrip import * import pdb, sys, time, Util, thread from pygame.locals import * +import util.TimeOps as clock +import util.Config as configGetter #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 = clock.Stopwatch() self.timer.start() self.inputs = {} #dict of inputs and their bound behaviors, keyed by InputId self.behaviors = {} @@ -22,7 +24,7 @@ class LightInstallation: Util.setComponentDict(self.componentDict) self.screen = Screen() Util.setScreen(self.screen) - config = Util.loadConfigFile(configFileName) + config = configGetter.loadConfigFile(configFileName) #read configs from xml rendererConfig = config.find('RendererConfiguration') pixelConfig = config.find('PixelConfiguration') @@ -75,7 +77,7 @@ class LightInstallation: for configItem in config.getchildren(): [module,className] = configItem.find('Class').text.split('.') exec('from ' + module+'.'+className + ' import *') - args = Util.generateArgDict(configItem.find('Args')) + args = configGetter.generateArgDict(configItem.find('Args')) args['parentScope'] = self #TODO: we shouldn't give away scope #like this, find another way. components.append(eval(className+'(args)')) #TODO: doesn't error @@ -85,12 +87,12 @@ class LightInstallation: return True def mainLoop(self): #self.screen.allOn() - lastLoopTime = Util.time() + lastLoopTime = clock.time() refreshInterval = 30 runCount = 10000 while runCount > 0: runCount -= 1 - loopStart = Util.time() + loopStart = clock.time() responses = self.evaluateBehaviors() #inputs are all queued when they #happen, so we only need to run the behaviors self.timer.start() @@ -98,7 +100,7 @@ class LightInstallation: response != []] self.screen.timeStep() [r.render(self.screen) for r in self.renderers] - loopElapsed = Util.time()-loopStart + loopElapsed = clock.time()-loopStart sleepTime = max(0,refreshInterval-loopElapsed) self.timer.stop() #print self.timer.elapsed() diff --git a/Util.py b/Util.py index 07ce545..2973e33 100644 --- a/Util.py +++ b/Util.py @@ -6,15 +6,8 @@ from bisect import * 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 colorByteMem = {} @@ -52,39 +45,6 @@ def gaussian(x,height,center,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): - if not className in classArgsMem: #WOO CACHING - classArgsMem[className] = fileToDict(CONFIG_PATH + className) - return classArgsMem[className] -def loadConfigFile(fileName): - 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 = '' - try: - print 'File Read' - 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 @@ -92,35 +52,6 @@ def find_le(a, x): 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): - return safeColor([c1[i]+c2[i] for i in range(min(len(c1),len(c2)))]) -def multiplyColor(color, percent): - return safeColor([channel*(percent) for channel in color]) -#parses arguments into python objects if possible, otherwise leaves as strings -def generateArgDict(parentNode, recurse=False): - args = {} - for arg in parentNode.getchildren(): - key = arg.tag - if arg.getchildren() != []: - value = generateArgDict(arg, True) - else: - #convert into python if possible, otherwise don't - try: - value = eval(arg.text) - except (NameError,SyntaxError): - value = str(arg.text) - if key in args: #build of lists of like-elements - if type(args[key]) != type([]): - args[key] = [args[key]] - args[key].append(value) - else: - args[key]=value - #if we should be a list but we aren't: - if len(args.keys()) == 1 and recurse: - return args[args.keys()[0]] - return args #Given a dictionary of connections, returns their topological ordering -- (the #order in which they can be visited such that all parents have been visited #before their children. Returns the order or None if no such ordering exists @@ -149,83 +80,12 @@ def topologicalSort(adjacencyDict): def topoTest(): adj = {'a':['d','c'], 'b':['c'], 'c':['e'], 'd':['e'], 'e':[]} print topologicalOrdering(adj) -def getConnectedSocket(ip,port): - sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - print (ip, port) - sock.connect((ip, port)) - return sock -def composePixelStripData(pixelStrip): - packet = bytearray() - for light in pixelStrip: - color = light.state() - for channel in color: #skip the last value, its an - #alpha value - packet.append(struct.pack('B', channel)) - return packet -# packet = [0]*len(pixelStrip.pixels)*3 #preallocate for speed -# for i in range(len(pixelStrip.pixels)): -#color = pixelStrip.pixels[i].state() -#packet[i:i+2] = color -# return bytearray(packet) -def composePixelStripPacket(pixelStrip,port): - packet = bytearray() - data = composePixelStripData(pixelStrip) - subDict = dict(kinetDict) - subDict['len'] = 38000 #I have no idea why this works. - subDict['port'] = port - #pdb.set_trace() - packet.extend(kinetPortOutPacket(subDict)) - packet.append(0x0) - packet.extend(data) - return packet -def kinetHeader(): - header = bytearray() - header.extend(struct.pack('L', MAGIC)) - header.extend(struct.pack('H', VERSION)) - header.extend(struct.pack('H', PORTOUT)) - header.extend(struct.pack('L', 0)) - return header -def kinetPortOut(): - header = kinetHeader() - header.extend(struct.pack('L', UNI)) - return header -def kinetPortOutPayload(argDict): - payload = bytearray() - payload.extend(struct.pack('B', argDict['port'])) - #payload.append(0x00) #somepadding? lolwtf. - payload.extend(struct.pack('H', argDict['flags'])) - #payload.append(0x00) #somepadding? lolwtf. - payload.extend(struct.pack('H', argDict['len'])) - payload.extend(struct.pack('H', argDict['startcode'])) - #pdb.set_trace() - return payload -def kinetPortOutPacket(payloadArgs): - packet = bytearray() - packet.extend(kinetPortOut()) - packet.extend(kinetPortOutPayload(payloadArgs)) - return packet def testXMLParse(fileName): #pdb.set_trace() config = ElementTree() 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 a3b1739..e1827eb 100644 --- a/behaviors/ColorChangerBehavior.py +++ b/behaviors/ColorChangerBehavior.py @@ -1,5 +1,5 @@ from operationscore.Behavior import * -import Util +import util.ColorOps as color import pdb class ColorChangerBehavior(Behavior): def processResponse(self, sensorInputs, recursiveInputs): @@ -7,9 +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.chooseRandomColor(self['ColorList']) #TODO: this doesn't work. + newDict['Color'] = color.chooseRandomColor(self['ColorList']) #TODO: this doesn't work. else: - newDict['Color'] = Util.randomColor() -#newDict['Color'] = (255,0,0) + newDict['Color'] = color.randomColor() ret.append(newDict) return (ret, recursiveInputs) diff --git a/operationscore/PixelEvent.py b/operationscore/PixelEvent.py index 66b6fdf..27e6e4a 100644 --- a/operationscore/PixelEvent.py +++ b/operationscore/PixelEvent.py @@ -2,6 +2,7 @@ #which should return a color, or None if the response is complete. Consider #requiring a generate event. from operationscore.SmootCoreObject import * +import util.ColorOps as color class PixelEvent(SmootCoreObject): def init(self): self.validateArgs('PixelEvent.params') @@ -11,7 +12,7 @@ class PixelEvent(SmootCoreObject): #Returns a new PixelEvent, but with a response scaled by c. def scale(self,c): newDict = dict(self.argDict) - newDict['Color'] = Util.multiplyColor(newDict['Color'], c) + newDict['Color'] = color.multiplyColor(newDict['Color'], c) return self.__class__(newDict) def state(self,timeDelay): pass diff --git a/operationscore/SmootCoreObject.py b/operationscore/SmootCoreObject.py index 8514b3e..10df299 100644 --- a/operationscore/SmootCoreObject.py +++ b/operationscore/SmootCoreObject.py @@ -2,6 +2,7 @@ import Util import pdb import threading import thread +import util.Config as configGetter class SmootCoreObject(threading.Thread): def __init__(self, argDict, skipValidation = False): self.argDict = argDict @@ -29,7 +30,7 @@ class SmootCoreObject(threading.Thread): def __getiter__(self): return self.argDict.__getiter__() def validateArgs(self, argFileName): - self.validateArgDict(Util.loadParamRequirementDict(argFileName))#util + self.validateArgDict(configGetter.loadParamRequirementDict(argFileName))#util #caches for us, woo! def validateArgDict(self, validationDict): for item in validationDict: diff --git a/pixelcore/Pixel.py b/pixelcore/Pixel.py index ba87dff..f66d0bb 100644 --- a/pixelcore/Pixel.py +++ b/pixelcore/Pixel.py @@ -1,6 +1,7 @@ -import Util +import util.ColorOps as color import pdb from pixelevents.StepEvent import * +import util.TimeOps as clock #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 queue. If a member returns none, @@ -24,7 +25,7 @@ class Pixel: #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) + self.events[clock.time()] = (zindex, pixelEvent) def clearAllEvents(self): self.events = {} #Combines all PixelEvents currently active and computes the current color of @@ -37,13 +38,13 @@ class Pixel: if len(self.events) == 0: return (0,0,0) deadEvents = [] - currentTime = Util.time() + currentTime = clock.time() resultingColor = (0,0,0) for eventTime in self.events: #TODO: right color weighting code (zindex,event) = self.events[eventTime] eventResult = event.state(currentTime-eventTime) if eventResult != None: - resultingColor = Util.combineColors(eventResult, resultingColor) + resultingColor = color.combineColors(eventResult, resultingColor) else: deadEvents.append(eventTime) [self.events.pop(event) for event in deadEvents] diff --git a/pixelevents/DecayEvent.py b/pixelevents/DecayEvent.py index 9a7c600..0b4c820 100644 --- a/pixelevents/DecayEvent.py +++ b/pixelevents/DecayEvent.py @@ -1,5 +1,6 @@ from operationscore.PixelEvent import * -import Util, math +import math +from util.ColorOps import * class DecayEvent(PixelEvent): def initEvent(self): self['Coefficient'] = abs(self['Coefficient']) @@ -8,7 +9,7 @@ class DecayEvent(PixelEvent): decay = math.exp(timeDelay*-1*self['Coefficient']) if self['DecayType'] == 'Proportional': decay = float(self['Coefficient']) / timeDelay - color = Util.multiplyColor(self['Color'], decay) + color = multiplyColor(self['Color'], decay) return color if sum(color) > 5 else None @staticmethod def generate(decayType, coefficient, color): diff --git a/renderers/IndoorRenderer.py b/renderers/IndoorRenderer.py index efe2b3a..2eac162 100644 --- a/renderers/IndoorRenderer.py +++ b/renderers/IndoorRenderer.py @@ -1,15 +1,15 @@ from operationscore.Renderer import * -import socket, Util -import pdb -kinetPort = 6038 +import util.PacketComposition as composer +import util.NetworkOps as network +import socket,pdb +port = 6038 +#Renderer for a Specific Light System. class IndoorRenderer(Renderer): def initRenderer(self): - #pdb.set_trace() self.stripLocations = {} #Dict that stores info necessary to render to #strips - self.sockets = {} #dict of (IP,port)->Socket + self.sockets = {} #dict of (IP)->Socket #a strip -# g self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) powerSupplies = self.argDict['PowerSupply'] if not type(powerSupplies) == type([]): powerSupplies = [powerSupplies] @@ -25,7 +25,7 @@ class IndoorRenderer(Renderer): (ip, port) = self.stripLocations[stripId] if not ip in self.sockets: #do we have a socket to this #strip? if not, spin off a new one - self.sockets[ip] = Util.getConnectedSocket(ip,kinetPort) - packet = Util.composePixelStripPacket(pixelStrip, port) + self.sockets[ip] = network.getConnectedSocket(ip,port) + packet = composer.composePixelStripPacket(pixelStrip, port) self.sockets[ip].send(packet, 0x00) diff --git a/util/ColorOps.py b/util/ColorOps.py new file mode 100644 index 0000000..b0d64a7 --- /dev/null +++ b/util/ColorOps.py @@ -0,0 +1,11 @@ +import random +def randomColor(): + return [random.randint(0,255) for i in range(3)] +def chooseRandomColor(colorList): + return random.choice(colorList) +def safeColor(c): + return [min(channel,255) for channel in c] +def combineColors(c1,c2): + return safeColor([c1[i]+c2[i] for i in range(min(len(c1),len(c2)))]) +def multiplyColor(color, percent): + return safeColor([channel*(percent) for channel in color]) diff --git a/util/Config.py b/util/Config.py new file mode 100644 index 0000000..4cf2ed5 --- /dev/null +++ b/util/Config.py @@ -0,0 +1,53 @@ +from xml.etree.ElementTree import ElementTree +classArgsMem = {} +CONFIG_PATH = 'config/' +def loadParamRequirementDict(className): + if not className in classArgsMem: #WOO CACHING + classArgsMem[className] = fileToDict(CONFIG_PATH + className) + return classArgsMem[className] +def loadConfigFile(fileName): #TODO: error handling etc. + 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 = '' + try: + print 'File Read' + with open(fileName) as f: + for line in f: + fileText += line.rstrip('\n').lstrip('\t') + ' ' + except IOError: + return {} + if fileText == '': + return {} + return eval(fileText) +#parses arguments into python objects if possible, otherwise leaves as strings +def generateArgDict(parentNode, recurse=False): + args = {} + for arg in parentNode.getchildren(): + key = arg.tag + if arg.getchildren() != []: + value = generateArgDict(arg, True) + else: + #convert into python if possible, otherwise don't + try: + value = eval(arg.text) + except (NameError,SyntaxError): + value = str(arg.text) + if key in args: #build of lists of like-elements + if type(args[key]) != type([]): + args[key] = [args[key]] + args[key].append(value) + else: + args[key]=value + #if we should be a list but we aren't: + if len(args.keys()) == 1 and recurse: + return args[args.keys()[0]] + return args diff --git a/util/NetworkOps.py b/util/NetworkOps.py new file mode 100644 index 0000000..a247090 --- /dev/null +++ b/util/NetworkOps.py @@ -0,0 +1,6 @@ +import socket +def getConnectedSocket(ip,port): + sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + print (ip, port) + sock.connect((ip, port)) + return sock diff --git a/util/PacketComposition.py b/util/PacketComposition.py new file mode 100644 index 0000000..5133459 --- /dev/null +++ b/util/PacketComposition.py @@ -0,0 +1,59 @@ +import struct +VERSION = 0x0001 +MAGIC = 0x4adc0104 +MOREMAGIC = 0xdeadbeef +DEEPMAGIC = 0xc001d00d +MAGICHASH = 0x69000420 +PORTOUT = 0x0108 +UNI = 0 +kinetDict = {'flags': 0, 'startcode': 0, 'pad':0} +def composePixelStripData(pixelStrip): + packet = bytearray() + for light in pixelStrip: + color = light.state() + for channel in color: #skip the last value, its an + #alpha value + packet.append(struct.pack('B', channel)) + return packet +# packet = [0]*len(pixelStrip.pixels)*3 #preallocate for speed +# for i in range(len(pixelStrip.pixels)): +#color = pixelStrip.pixels[i].state() +#packet[i:i+2] = color +# return bytearray(packet) +def composePixelStripPacket(pixelStrip,port): + packet = bytearray() + data = composePixelStripData(pixelStrip) + subDict = dict(kinetDict) + subDict['len'] = 38000 #I have no idea why this works. + subDict['port'] = port + #pdb.set_trace() + packet.extend(kinetPortOutPacket(subDict)) + packet.append(0x0) + packet.extend(data) + return packet +def kinetHeader(): + header = bytearray() + header.extend(struct.pack('L', MAGIC)) + header.extend(struct.pack('H', VERSION)) + header.extend(struct.pack('H', PORTOUT)) + header.extend(struct.pack('L', 0)) + return header +def kinetPortOut(): + header = kinetHeader() + header.extend(struct.pack('L', UNI)) + return header +def kinetPortOutPayload(argDict): + payload = bytearray() + payload.extend(struct.pack('B', argDict['port'])) + #payload.append(0x00) #somepadding? lolwtf. + payload.extend(struct.pack('H', argDict['flags'])) + #payload.append(0x00) #somepadding? lolwtf. + payload.extend(struct.pack('H', argDict['len'])) + payload.extend(struct.pack('H', argDict['startcode'])) + #pdb.set_trace() + return payload +def kinetPortOutPacket(payloadArgs): + packet = bytearray() + packet.extend(kinetPortOut()) + packet.extend(kinetPortOutPayload(payloadArgs)) + return packet diff --git a/util/TimeOps.py b/util/TimeOps.py new file mode 100644 index 0000000..dcd5038 --- /dev/null +++ b/util/TimeOps.py @@ -0,0 +1,19 @@ +import time as clock +def time(): + return clock.time()*1000 #all times in MS +class Stopwatch: + def __init__(self): + self.running = False + self.startTime = -1 + self.stopTime = -1 + def start(self): + self.startTime = time() + self.running = True + def elapsed(self): + if self.running: + return time()-self.startTime + else: + return self.stopTime - self.startTime + def stop(self): + self.stopTime = time() + self.running = False diff --git a/util/__init__.py b/util/__init__.py new file mode 100644 index 0000000..e69de29 -- cgit v1.2.3 From 7386cbc7ce48e3996d92d84cff3d1a4dab8f538d Mon Sep 17 00:00:00 2001 From: rcoh Date: Mon, 20 Dec 2010 14:19:09 -0500 Subject: A little bit more util stuff. Migrated the component registry to the ComponentRegistry module. Almost done. --- LightInstallation.py | 16 +++++++++++----- Util.py | 39 --------------------------------------- behaviors/BehaviorChain.py | 5 +++-- behaviors/RunningBehavior.py | 3 ++- config/Outdoor.xml | 2 +- util/ComponentRegistry.py | 17 +++++++++++++++++ 6 files changed, 34 insertions(+), 48 deletions(-) create mode 100644 util/ComponentRegistry.py diff --git a/LightInstallation.py b/LightInstallation.py index 5f12abf..e6e5a26 100644 --- a/LightInstallation.py +++ b/LightInstallation.py @@ -5,6 +5,7 @@ import pdb, sys, time, Util, thread from pygame.locals import * import util.TimeOps as clock import util.Config as configGetter +import util.ComponentRegistry as compReg #Python class to instantiate and drive a Screen through different patterns, #and effects. class LightInstallation: @@ -21,9 +22,10 @@ class LightInstallation: #input #give Util a pointer to our componentRegistry and screen so that everyone can use #it - Util.setComponentDict(self.componentDict) + #Util.setComponentDict(self.componentDict) self.screen = Screen() - Util.setScreen(self.screen) + #Util.setScreen(self.screen) + compReg.registerComponent(self.screen, 'Screen') #TODO: move to constants file config = configGetter.loadConfigFile(configFileName) #read configs from xml rendererConfig = config.find('RendererConfiguration') @@ -70,7 +72,8 @@ class LightInstallation: cid = component['Id'] if cid == None: raise Exception('Components must have Ids!') - self.componentDict[cid] = component + #self.componentDict[cid] = component + compReg.registerComponent(component) def initializeComponent(self, config): components = [] if config != None: @@ -134,8 +137,11 @@ class LightInstallation: def processResponse(self,inputDict, responseDict): inputId = inputDict['Id'] boundBehaviorIds = self.inputBehaviorRegistry[inputId] - [self.componentDict[b].addInput(responseDict) for b in boundBehaviorIds] - + #TODO: fix this, it crashes because inputs get run before beahviors exist + try: + [compReg.getComponent(b).addInput(responseDict) for b in boundBehaviorIds] + except: + print 'Behaviors not initialized yet. WAIT!' def main(argv): print argv if len(argv) == 1: diff --git a/Util.py b/Util.py index 2973e33..8aa4d8a 100644 --- a/Util.py +++ b/Util.py @@ -20,17 +20,6 @@ def pointWithinBoundingBox(point, bb): #this could be in 4 lines, but I'm lazy. print pointWithinBoundingBox((118,21), (10,8,298,42)) def addLocations(l1,l2): return tuple([l1[i]+l2[i] for i in range(len(l1))]) -def setScreen(screen): - globals()["screen"] = screen -def getScreen(): - return screen -def setComponentDict(componentDictRef): - globals()["componentDict"] = componentDictRef -def getComponentById(cid): - if cid in componentDict: - return componentDict[cid] - else: - return None def addPixelEventIfMissing(responseDict): if not 'PixelEvent' in responseDict: if 'Color' in responseDict: @@ -52,34 +41,6 @@ def find_le(a, x): def find_ge(a, x): 'Find leftmost value greater than x' return bisect_left(a, x) -#Given a dictionary of connections, returns their topological ordering -- (the -#order in which they can be visited such that all parents have been visited -#before their children. Returns the order or None if no such ordering exists -#(the graph contains a cycle). -def topologicalSort(adjacencyDict): - def dfsVisit(vertex): - gray[vertex] = 1 - for child in adjacencyDict[vertex]: - if not child in visited: - if child in gray: #We have a cycle. No topological ordering - #exists! - raise Exception('Cycle!') - dfsVisit(child) - orderedList.insert(0, vertex) - visited[vertex] = 1 - orderedList = [] - visited = {} - gray = {} - for vertex in adjacencyDict: - try: - if not vertex in visited: - dfsVisit(vertex) - except: - return None #cycle - return orderedList -def topoTest(): - adj = {'a':['d','c'], 'b':['c'], 'c':['e'], 'd':['e'], 'e':[]} - print topologicalOrdering(adj) def testXMLParse(fileName): #pdb.set_trace() config = ElementTree() diff --git a/behaviors/BehaviorChain.py b/behaviors/BehaviorChain.py index fe50573..65f5c9d 100644 --- a/behaviors/BehaviorChain.py +++ b/behaviors/BehaviorChain.py @@ -1,4 +1,5 @@ from operationscore.Behavior import * +import util.ComponentRegistry as compReg import Util import pdb class BehaviorChain(Behavior): @@ -10,7 +11,7 @@ class BehaviorChain(Behavior): def processResponse(self, sensorInputs, recursiveInputs): response = sensorInputs for behaviorId in self['ChainedBehaviors']: - behavior = Util.getComponentById(behaviorId) + behavior = compReg.getComponent(behaviorId) if behaviorId in self.feedback: recurrence = self.feedback[behaviorId] else: @@ -19,7 +20,7 @@ class BehaviorChain(Behavior): recurrence) if behaviorId in self.hooks: #process recursive hook if there is one - hookBehavior = Util.getComponentById(self.hooks[behaviorId]) + hookBehavior = compReg.getComponent(self.hooks[behaviorId]) #we feed its recurrence in as input to the behavior. (recurrence, hookRecurrence) = \ hookBehavior.immediateProcessInput(recurrence, \ diff --git a/behaviors/RunningBehavior.py b/behaviors/RunningBehavior.py index 3d82d29..4f51898 100644 --- a/behaviors/RunningBehavior.py +++ b/behaviors/RunningBehavior.py @@ -1,4 +1,5 @@ from operationscore.Behavior import * +import util.ComponentRegistry as compReg import pdb import Util class RunningBehavior(Behavior): @@ -15,7 +16,7 @@ class RunningBehavior(Behavior): outDict['Location']= Util.addLocations(outDict['Location'], (outDict['StepSize']*outDict['Dir'],0)) if not Util.pointWithinBoundingBox(outDict['Location'], \ - Util.getScreen().getSize()): + compReg.getComponent('Screen').getSize()): outDict['Dir'] *= -1 ret.append(outDict) ret += newResponses diff --git a/config/Outdoor.xml b/config/Outdoor.xml index 7f054f0..10274b2 100644 --- a/config/Outdoor.xml +++ b/config/Outdoor.xml @@ -120,7 +120,7 @@ inputs.PygameInput followmouse - 10 + 50 True diff --git a/util/ComponentRegistry.py b/util/ComponentRegistry.py new file mode 100644 index 0000000..f8fe00d --- /dev/null +++ b/util/ComponentRegistry.py @@ -0,0 +1,17 @@ +import pdb +#Registry of all components of the light system +#TODO: pick a graceful failure behavior and implement it +registry = {} +def registerComponent(component, cid=None): + if cid != None: + registry[cid] = component + else: + try: + cid = component['Id'] + registry[cid] = component + except: + raise Exception('Must specify Id, component did not store it') +def removeComponent(cid): + registry.pop(cid) +def getComponent(cid): + return registry[cid] -- cgit v1.2.3 From 2736307c1d6d67868ca54a3df951f9e959efedd0 Mon Sep 17 00:00:00 2001 From: rcoh Date: Mon, 20 Dec 2010 14:50:08 -0500 Subject: Util cleanup is done! Util.py is now refactored into the util module. Woo! RCOH --- Util.py | 53 ---------------------------------------- behaviors/DecayBehavior.py | 3 ++- behaviors/EchoBehavior.py | 3 ++- behaviors/RunningBehavior.py | 5 ++-- inputs/PygameInput.py | 7 +++--- inputs/TCPInput.py | 3 ++- operationscore/PixelAssembler.py | 3 ++- operationscore/PixelEvent.py | 8 ++++++ pixelcore/PixelStrip.py | 6 +++-- pixelcore/Screen.py | 8 +++--- pixelmappers/GaussianMapper.py | 5 ++-- pixelmappers/SimpleMapper.py | 2 +- util/Geo.py | 15 ++++++++++++ util/Search.py | 8 ++++++ util/Strings.py | 1 + 15 files changed, 60 insertions(+), 70 deletions(-) delete mode 100644 Util.py create mode 100644 util/Geo.py create mode 100644 util/Search.py create mode 100644 util/Strings.py diff --git a/Util.py b/Util.py deleted file mode 100644 index 8aa4d8a..0000000 --- a/Util.py +++ /dev/null @@ -1,53 +0,0 @@ -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 * -from pixelevents.StepEvent import * - -classArgsMem = {} -UNI = 0 -colorByteMem = {} -CONFIG_PATH = 'config/' -kinetDict = {'flags': 0, 'startcode': 0, 'pad':0} -componentDict = {} -#Only for rough estimates. Kindof lazy on specifics. -def pointWithinBoundingBox(point, bb): #this could be in 4 lines, but I'm lazy. - return sum([(point[i % 2] <= bb[i]) == (i>1) for i in range(4)]) == 4 -print pointWithinBoundingBox((118,21), (10,8,298,42)) -def addLocations(l1,l2): - return tuple([l1[i]+l2[i] for i in range(len(l1))]) -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 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 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 testXMLParse(fileName): - #pdb.set_trace() - config = ElementTree() - config.parse(fileName) - print generateArgDict(config.find('ChildElement')) - print generateArgDict(config.find('Renderer')) -##CONSTANTS## -location = 'Location' - - diff --git a/behaviors/DecayBehavior.py b/behaviors/DecayBehavior.py index edc833d..56e1686 100644 --- a/behaviors/DecayBehavior.py +++ b/behaviors/DecayBehavior.py @@ -1,5 +1,6 @@ from operationscore.Behavior import * from pixelevents.DecayEvent import * +import util.Strings as Strings import Util import pdb class DecayBehavior(Behavior): @@ -7,7 +8,7 @@ class DecayBehavior(Behavior): ret = [] for sensory in sensorInputs: outDict = {} - outDict[Util.location] = sensory[Util.location] + outDict[Strings.LOCATION] = sensory[Strings.LOCATION] outDict['PixelEvent'] = \ DecayEvent.generate(self['DecayType'],self['Coefficient'], sensory['Color']) ret.append(outDict) diff --git a/behaviors/EchoBehavior.py b/behaviors/EchoBehavior.py index a11558a..002f8fb 100644 --- a/behaviors/EchoBehavior.py +++ b/behaviors/EchoBehavior.py @@ -1,4 +1,5 @@ from operationscore.Behavior import * +import util.Strings as Strings import Util import pdb class EchoBehavior(Behavior): @@ -6,7 +7,7 @@ class EchoBehavior(Behavior): ret = [] for sensory in sensorInputs: outDict = {} - outDict[Util.location] = sensory[Util.location] + outDict[Strings.LOCATION] = sensory[Strings.LOCATION] outDict['Color'] = (255,0,0) ret.append(outDict) return ret diff --git a/behaviors/RunningBehavior.py b/behaviors/RunningBehavior.py index 4f51898..1969162 100644 --- a/behaviors/RunningBehavior.py +++ b/behaviors/RunningBehavior.py @@ -1,5 +1,6 @@ from operationscore.Behavior import * import util.ComponentRegistry as compReg +import util.Geo as Geo import pdb import Util class RunningBehavior(Behavior): @@ -13,9 +14,9 @@ class RunningBehavior(Behavior): outDict['Dir'] = 1 #to the right if not 'StepSize' in outDict: outDict['StepSize'] = self['StepSize'] - outDict['Location']= Util.addLocations(outDict['Location'], + outDict['Location']= Geo.addLocations(outDict['Location'], (outDict['StepSize']*outDict['Dir'],0)) - if not Util.pointWithinBoundingBox(outDict['Location'], \ + if not Geo.pointWithinBoundingBox(outDict['Location'], \ compReg.getComponent('Screen').getSize()): outDict['Dir'] *= -1 ret.append(outDict) diff --git a/inputs/PygameInput.py b/inputs/PygameInput.py index 1f438d6..f69d0f5 100644 --- a/inputs/PygameInput.py +++ b/inputs/PygameInput.py @@ -1,4 +1,5 @@ import time, Util +import util.Strings as Strings from operationscore.Input import * import pygame from pygame.locals import * @@ -8,13 +9,13 @@ class PygameInput(Input): def sensingLoop(self): #try: if self['FollowMouse']: - self.respond({Util.location: pygame.mouse.get_pos()}) + self.respond({Strings.LOCATION: pygame.mouse.get_pos()}) return for event in pygame.event.get(): if event.type is KEYDOWN: - self.respond({Util.location: (5,5),'Key': event.key}) + self.respond({Strings.LOCATION: (5,5),'Key': event.key}) if event.type is MOUSEBUTTONDOWN: - self.respond({Util.location: pygame.mouse.get_pos()}) + self.respond({Strings.LOCATION: pygame.mouse.get_pos()}) #except: #raise Exception('Pygame not initialized. Pygame must be \ #initialized.') diff --git a/inputs/TCPInput.py b/inputs/TCPInput.py index acd6243..9f62825 100644 --- a/inputs/TCPInput.py +++ b/inputs/TCPInput.py @@ -1,4 +1,5 @@ import Util +import util.Strings as Strings from operationscore.Input import * import socket, json, time class TCPInput(Input): @@ -25,7 +26,7 @@ class TCPInput(Input): if self.IS_RESPONDING == 1: # if 'responding', respond to the received data dataDict = json.loads(data) # socketDict = {'data':dataDict, 'address':self.address} - socketDict = {Util.location: (100 * (1 - dataDict['x'] / 10), 25 * (1 + dataDict['y'] / 10))} # like PygameInput + socketDict = {Strings.LOCATION: (100 * (1 - dataDict['x'] / 10), 25 * (1 + dataDict['y'] / 10))} # like PygameInput self.respond(socketDict) else: diff --git a/operationscore/PixelAssembler.py b/operationscore/PixelAssembler.py index b6e35ac..c8563fb 100644 --- a/operationscore/PixelAssembler.py +++ b/operationscore/PixelAssembler.py @@ -1,4 +1,5 @@ from operationscore.SmootCoreObject import * +import util.Geo as Geo import Util import pdb class PixelAssembler(SmootCoreObject): @@ -17,7 +18,7 @@ class PixelAssembler(SmootCoreObject): if newLocation == None: raise Exception('Location cannot be null. layoutFunc not \ defined or improperly defined.') - if Util.dist(newLocation, locations[-1]) > \ + if Geo.dist(newLocation, locations[-1]) > \ self['pixelToPixelSpacing']: raise Exception('Illegal pixel location. Distance \ between adjacent pixels must be less than \ diff --git a/operationscore/PixelEvent.py b/operationscore/PixelEvent.py index 27e6e4a..e2b852a 100644 --- a/operationscore/PixelEvent.py +++ b/operationscore/PixelEvent.py @@ -16,4 +16,12 @@ class PixelEvent(SmootCoreObject): return self.__class__(newDict) def state(self,timeDelay): pass + @staticmethod + 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) diff --git a/pixelcore/PixelStrip.py b/pixelcore/PixelStrip.py index c82a87a..cfab948 100644 --- a/pixelcore/PixelStrip.py +++ b/pixelcore/PixelStrip.py @@ -1,4 +1,6 @@ from pixelcore.Pixel import * +import util.Strings as Strings +import util.Geo as Geo from pixelevents.StepEvent import * import pygame import math @@ -21,7 +23,7 @@ class PixelStrip: [l.turnOnFor(time) for l in self.pixels] #TODO: add test-on method to #pixels def respond(self, responseInfo): - location = responseInfo[Util.location] + location = responseInfo[Strings.LOCATION] if not 'PixelEvent' in responseInfo: if 'Color' in responseInfo: color = responseInfo['Color'] @@ -32,7 +34,7 @@ class PixelStrip: pixel.processInput(responseInfo['PixelEvent'], 0) #TODO: z-index def getPixelNearest(self, location): - dists = [(Util.dist(location, pixel.location), pixel) for pixel in self.pixels] + dists = [(Geo.dist(location, pixel.location), pixel) for pixel in self.pixels] dists.sort() return dists[0] #just for now. diff --git a/pixelcore/Screen.py b/pixelcore/Screen.py index 92805a8..a20cc72 100644 --- a/pixelcore/Screen.py +++ b/pixelcore/Screen.py @@ -1,5 +1,7 @@ from pixelcore.Pixel import * from pixelcore.PixelStrip import * +from operationscore.PixelEvent import * +import util.Search as Search import itertools #Class representing a collection of Pixels grouped into PixelStrips. Needs a #PixelMapper, currently set via setMapper by may be migrated into the argDict. @@ -17,8 +19,8 @@ class Screen: 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 + minIndex = Search.find_ge(self.xPixelLocs, minX) + maxIndex = Search.find_le(self.xPixelLocs, maxX)+1 return self.xSortedPixels[minIndex:maxIndex] def computeXSortedPixels(self): for pixel in self: @@ -70,7 +72,7 @@ class Screen: pass #pdb.set_trace() pixelWeightList = self.mapper.mapEvent(responseInfo['Location'], self) - Util.addPixelEventIfMissing(responseInfo) + PixelEvent.addPixelEventIfMissing(responseInfo) for (pixel, weight) in pixelWeightList: pixel.processInput(responseInfo['PixelEvent'].scale(weight), 0) #TODO: z-index diff --git a/pixelmappers/GaussianMapper.py b/pixelmappers/GaussianMapper.py index 04bd447..e94235e 100644 --- a/pixelmappers/GaussianMapper.py +++ b/pixelmappers/GaussianMapper.py @@ -1,4 +1,5 @@ from operationscore.PixelMapper import * +import util.Geo as Geo import Util class GaussianMapper(PixelMapper): def mappingFunction(self, eventLocation, screen): @@ -6,8 +7,8 @@ class GaussianMapper(PixelMapper): [x,y] = eventLocation for (x,pixel) in screen.pixelsInRange(x-self['CutoffDist'], \ x+self['CutoffDist']): - pixelDist = Util.dist(pixel.location, eventLocation) + pixelDist = Geo.dist(pixel.location, eventLocation) if pixelDist < self['CutoffDist']: - w = Util.gaussian(pixelDist, self['Height'], 0, self['Width']) + w = Geo.gaussian(pixelDist, self['Height'], 0, self['Width']) returnPixels.append((pixel, w)) return returnPixels diff --git a/pixelmappers/SimpleMapper.py b/pixelmappers/SimpleMapper.py index 7d730f1..4b5377d 100644 --- a/pixelmappers/SimpleMapper.py +++ b/pixelmappers/SimpleMapper.py @@ -5,7 +5,7 @@ class SimpleMapper(PixelMapper): bestDist = 10**10 #don't kill me, I'm lazy bestPixel = None for pixel in screen: - pixelDist = Util.dist(pixel.location, eventLocation) + pixelDist = Geo.dist(pixel.location, eventLocation) if pixelDist < bestDist: bestPixel = pixel bestDist = pixelDist diff --git a/util/Geo.py b/util/Geo.py new file mode 100644 index 0000000..885c585 --- /dev/null +++ b/util/Geo.py @@ -0,0 +1,15 @@ +#Geometry code +import math +from bisect import * +def pointWithinBoundingBox(point, bb): #this could be in 4 lines, but I'm lazy. + return sum([(point[i % 2] <= bb[i]) == (i>1) for i in range(4)]) == 4 +print pointWithinBoundingBox((118,21), (10,8,298,42)) +def addLocations(l1,l2): + return tuple([l1[i]+l2[i] for i in range(len(l1))]) +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))])) diff --git a/util/Search.py b/util/Search.py new file mode 100644 index 0000000..25882da --- /dev/null +++ b/util/Search.py @@ -0,0 +1,8 @@ +from bisect import * +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) diff --git a/util/Strings.py b/util/Strings.py new file mode 100644 index 0000000..1331db4 --- /dev/null +++ b/util/Strings.py @@ -0,0 +1 @@ +LOCATION = 'Location' -- cgit v1.2.3