# HG changeset patch # User drewp # Date 2003-07-06 14:47:01 # Node ID 1e4814221a64e6c2a910574fac8196e284607af0 # Parent c3160150435882f6671e7e17e95e87b916833905 new tracker program and demo file diff --git a/flax/fieldsets/demo b/flax/fieldsets/demo --- a/flax/fieldsets/demo +++ b/flax/fieldsets/demo @@ -1,11 +1,3 @@ - -
- - - - - - - - -
+light1: x=30 y=40 falloff=10 +light2: x=60 y=50 falloff=30 +light3: x=40 y=50 falloff=20 diff --git a/flax/tracker b/flax/tracker --- a/flax/tracker +++ b/flax/tracker @@ -1,96 +1,80 @@ #!/usr/bin/python -from __future__ import division,nested_scopes -import sys -sys.path.append("../../editor/pour") -sys.path.append("../light8") - -from Submaster import Submaster +from __future__ import division from skim.zooming import Zooming,Pair from math import sqrt,sin,cos from pygame.rect import Rect -from xmlnodebase import xmlnodeclass,collectiveelement,xmldocfile -from dispatch import dispatcher - -import dmxclient import Tkinter as tk - -defaultfont="arial 8" - -def pairdist(pair1,pair2): - return pair1.dist(pair2) - -def canvashighlighter(canvas,obj,attribute,normalval,highlightval): - """creates bindings on a canvas obj that make attribute go - from normal to highlight when the mouse is over the obj""" - canvas.tag_bind(obj,"", - lambda ev: canvas.itemconfig(obj,**{attribute:highlightval})) - canvas.tag_bind(obj,"", - lambda ev: canvas.itemconfig(obj,**{attribute:normalval})) - -class Field(xmlnodeclass): +class Field: """one light has a field of influence. for any point on the canvas, you can ask this field how strong it is. """ - def name(self,newval=None): - """light/sub name""" - return self._getorsetattr("name",newval) - def center(self,x=None,y=None): - """x,y float coords for the center of this light in the field. returns - a Pair, although it accepts x,y""" - return Pair(self._getorsettypedattr("x",float,x), - self._getorsettypedattr("y",float,y)) + center=Pair(0,0) + falloff=0 - def falloff(self,dist=None): + def setcenter(self,x,y): + self.center=Pair(x,y) + + def setfalloff(self,dist): """linear falloff from 1 at center, to 0 at dist pixels away from center""" - return self._getorsettypedattr("falloff",float,dist) + self.falloff=dist def getdistforintensity(self,intens): """returns the distance you'd have to be for the given intensity (0..1)""" - return (1-intens)*self.falloff() + return (1-intens)*self.falloff def calc(self,x,y): """returns field strength at point x,y""" - dist=pairdist(Pair(x,y),self.center()) - return max(0,(self.falloff()-dist)/self.falloff()) + dist=sqrt( (x-self.center.x)**2 + (y-self.center.y)**2 ) + return max(0,(self.falloff-dist)/self.falloff) -class Fieldset(collectiveelement): +class FieldSet: """group of fields. persistent.""" - def childtype(self): return Field - - def version(self): - """read-only version attribute on fieldset tag""" - return self._getorsetattr("version",None) - + fields=None # lightname : Field + def __init__(self): + self.fields={} + def loadfromfile(self,f): + for line in f: + try: + col=line.index(':') + newfield=Field() + name=line[:col] + params={} + for param in line[col+1:].split(): + eq=param.index('=') + params[param[:eq]]=float(param[eq+1:]) + newfield.setcenter(params['x'],params['y']) + newfield.setfalloff(params['falloff']) + self.addfield(name,newfield) + newfield.name=name # fields have names? + except ValueError: + print "error on line: %s" % line + def savetofile(self,f): + for name,field in self.fields.items(): + print >>f,"%s: x=%s y=%s falloff=%s" % (name, + field.center.x,field.center.y, + field.falloff) + def addfield(self,name,f): + """consider the given field in this set with the given name""" + assert isinstance(f,Field) + self.fields[name]=f def report(self,x,y): """reports active fields and their intensities""" - active=0 - for f in self.getall(): - name=f.name() + for name,f in self.fields.items(): intens=f.calc(x,y) if intens>0: print name,intens, - active+=1 - if active>0: - print - self.dmxsend(x,y) - def dmxsend(self,x,y): - """output lights to dmx""" - levels=dict([(f.name(),f.calc(x,y)) for f in self.getall()]) - dmxlist=Submaster(None,levels).get_dmx_list() - dmxclient.outputlevels(dmxlist) - - + print def getbounds(self): """returns xmin,xmax,ymin,ymax for the non-zero areas of this field""" r=None - for f in self.getall(): + for f in self.fields.values(): rad=f.getdistforintensity(0) - fx,fy=f.center() + fx,fy=f.center.x,f.center.y fieldrect=Rect(fx-rad,fy-rad,rad*2,rad*2) if r is None: r=fieldrect @@ -98,143 +82,70 @@ class Fieldset(collectiveelement): r=r.union(fieldrect) return r.left,r.right,r.top,r.bottom -class Fieldsetfile(xmldocfile): - def __init__(self,filename): - self._openornew(filename,topleveltype=Fieldset) - def fieldset(self): - return self._gettoplevel() - -######################################################################## -######################################################################## - class FieldDisplay: """the view for a Field.""" def __init__(self,canvas,field): self.canvas=canvas self.field=field self.tags=[str(id(self))] # canvas tag to id our objects - - def setcoords(self): - """adjust canvas obj coords to match the field""" - # this uses the canvas object ids saved by makeobjs - f=self.field - c=self.canvas - w2c=self.canvas.world2canvas - - # rings - for intens,ring in self.rings.items(): - rad=f.getdistforintensity(intens) - p1=w2c(*(f.center()-Pair(rad,rad))) - p2=w2c(*(f.center()+Pair(rad,rad))) - c.coords(ring,p1[0],p1[1],p2[0],p2[1]) - - # text - p1=w2c(*f.center()) - c.coords(self.txt,*p1) - - def makeobjs(self): - """(re)create the canvas objs (null coords) and make their bindings""" + def draw(self): c=self.canvas f=self.field c.delete(self.tags) w2c=self.canvas.world2canvas - # make rings - self.rings={} # rad,canvasobj - for intens,color in (#(1,'white'), + def oval(rad,color): + p1=w2c(*(f.center-Pair(rad,rad))) + p2=w2c(*(f.center+Pair(rad,rad))) + c.create_oval(p1[0],p1[1],p2[0],p2[1], + outline=color,width=2,tags=self.tags, + outlinestipple='gray50') + + oval(.01,'white') + for intens,color in ((1,'white'), (.8,'gray90'),(.6,'gray80'),(.4,'gray60'),(.2,'gray50'), (0,'#000080')): - self.rings[intens]=c.create_oval(0,0,0,0, - outline=color,width=2,tags=self.tags, - outlinestipple='gray50') - - # make text - self.txt=c.create_text(0,0,text=f.name(),font=defaultfont+" bold", - fill='white',anchor='c', - tags=self.tags) - - # highlight text bindings - canvashighlighter(c,self.txt,'fill',normalval='white',highlightval='red') - - # position drag bindings - def press(ev): - self._lastmouse=ev.x,ev.y - def motion(ev): - dcan=Pair(*[a-b for a,b in zip((ev.x,ev.y),self._lastmouse)]) - dworld=c.canvas2world_vector(*dcan) - self.field.center(*(self.field.center()+dworld)) - self._lastmouse=ev.x,ev.y - self.setcoords() # redraw - def release(ev): - if hasattr(self,'_lastmouse'): - del self._lastmouse - dispatcher.send("field coord changed") # updates bounds - - c.tag_bind(self.txt,"",press) - c.tag_bind(self.txt,"",motion) - c.tag_bind(self.txt,"",release) - - # radius drag bindings - outerring=self.rings[0] - canvashighlighter(c,outerring, - 'outline',normalval='#000080',highlightval='#4040ff') - def motion(ev): - worldmouse=self.canvas.canvas2world(ev.x,ev.y) - currentdist=pairdist(worldmouse,self.field.center()) - self.field.falloff(currentdist) - self.setcoords() - c.tag_bind(outerring,"",motion) - c.tag_bind(outerring,"",release) # from above - - self.setcoords() - + + oval(f.getdistforintensity(intens),color) + if hasattr(f,'name'): + p1=w2c(*f.center) + c.create_text(p1[0],p1[1],text=f.name, + fill='white',anchor='c') + class Tracker(tk.Frame): """whole tracker widget, which is mostly a view for a - Fieldset. tracker makes its own fieldset""" + FieldSet. tracker makes its own fieldset""" # world coords of the visible canvas (preserved even in window resizes) xmin=0 xmax=100 ymin=0 ymax=100 - - fieldsetfile=None - displays=None # Field : FieldDisplay. we keep these in sync with the fieldset def __init__(self,master): tk.Frame.__init__(self,master) - self.displays={} + self.fieldset=FieldSet() + self.displays={} # Field : FieldDisplay - c=self.canvas=Zooming(self,bg='black',closeenough=5) + c=Zooming(self,bg='black') c.pack(fill='both',exp=1) - # preserve edge coords over window resize + for x,y in ((5,5),(5,95),(95,5),(95,95)): + c.create_text(x,y,text="%s,%s"%(x,y),fill='white') + c.bind("",self.configcoords) - c.bind("", - lambda ev: self._fieldset().report(*c.canvas2world(ev.x,ev.y))) - def save(ev): - print "saving" - self.fieldsetfile.save() - master.bind("",save) - dispatcher.connect(self.autobounds,"field coord changed") + self.canvas=c - def _fieldset(self): - return self.fieldsetfile.fieldset() + c.bind("", + lambda ev: self.fieldset.report(*c.canvas2world(ev.x,ev.y))) - def load(self,filename): - self.fieldsetfile=Fieldsetfile(filename) - self.displays.clear() - for f in self.fieldsetfile.fieldset().getall(): - self.displays[f]=FieldDisplay(self.canvas,f) - self.displays[f].makeobjs() - self.autobounds() def configcoords(self,*args): - # force our canvas coords to stay at the edges of the window + # force canvas coords to line up right c=self.canvas cornerx,cornery=c.canvas2world(0,0) c.move(cornerx-self.xmin, @@ -244,30 +155,24 @@ class Tracker(tk.Frame): c.winfo_height()/(self.ymax-self.ymin)) def autobounds(self): - """figure out our bounds from the fieldset, and adjust the display zooms. - writes the corner coords onto the canvas.""" - self.xmin,self.xmax,self.ymin,self.ymax=self._fieldset().getbounds() + """figure out our bounds from the fieldset, and adjust the display zooms""" + self.xmin,self.xmax,self.ymin,self.ymax=self.fieldset.getbounds() - self.configcoords() - - c=self.canvas - c.delete('cornercoords') - for x,anc2 in ((self.xmin,'w'),(self.xmax,'e')): - for y,anc1 in ((self.ymin,'n'),(self.ymax,'s')): - pos=c.world2canvas(x,y) - c.create_text(pos[0],pos[1],text="%s,%s"%(x,y), - fill='white',anchor=anc1+anc2, - tags='cornercoords') - [d.setcoords() for d in self.displays.values()] + def addfield(self,name,f): + """add the named Field to this display""" + self.fieldset.addfield(name,f) + self.displays[f]=FieldDisplay(self.canvas,f) + self.displays[f].draw() -######################################################################## -######################################################################## - root=tk.Tk() -root.wm_geometry('700x350') + tra=Tracker(root) tra.pack(fill='both',exp=1) -tra.load("fieldsets/demo") +tra.fieldset.loadfromfile(file("fieldsets/demo")) +for f in tra.fieldset.fields.values(): + tra.displays[f]=FieldDisplay(tra.canvas,f) + tra.displays[f].draw() +tra.autobounds() root.mainloop()