Files
@ 4c3060ceddcc
Branch filter:
Location: light9/flax/tracker - annotation
4c3060ceddcc
8.6 KiB
text/plain
autoshifting is controllable now
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 | 45b12307c695 e3a92ccea4be 45b12307c695 e3a92ccea4be e3a92ccea4be e3a92ccea4be 45b12307c695 45b12307c695 45b12307c695 e6ca7c1f0b1e e6ca7c1f0b1e 45b12307c695 45b12307c695 e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e 45b12307c695 45b12307c695 45b12307c695 45b12307c695 e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e 45b12307c695 e6ca7c1f0b1e 45b12307c695 45b12307c695 45b12307c695 e6ca7c1f0b1e 45b12307c695 45b12307c695 45b12307c695 e6ca7c1f0b1e 45b12307c695 45b12307c695 45b12307c695 e6ca7c1f0b1e e6ca7c1f0b1e 45b12307c695 e6ca7c1f0b1e 45b12307c695 e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e 45b12307c695 45b12307c695 e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e 45b12307c695 45b12307c695 45b12307c695 e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e 45b12307c695 45b12307c695 45b12307c695 e6ca7c1f0b1e 45b12307c695 e6ca7c1f0b1e 45b12307c695 45b12307c695 45b12307c695 45b12307c695 45b12307c695 45b12307c695 45b12307c695 e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e 45b12307c695 45b12307c695 45b12307c695 45b12307c695 45b12307c695 45b12307c695 e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e 45b12307c695 45b12307c695 45b12307c695 45b12307c695 45b12307c695 45b12307c695 e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e 45b12307c695 45b12307c695 e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e 45b12307c695 45b12307c695 45b12307c695 e6ca7c1f0b1e 45b12307c695 45b12307c695 45b12307c695 45b12307c695 45b12307c695 45b12307c695 e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e 45b12307c695 45b12307c695 45b12307c695 45b12307c695 e6ca7c1f0b1e 45b12307c695 e6ca7c1f0b1e 45b12307c695 45b12307c695 e6ca7c1f0b1e 45b12307c695 45b12307c695 e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e 45b12307c695 e6ca7c1f0b1e e6ca7c1f0b1e 45b12307c695 e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e 45b12307c695 45b12307c695 e6ca7c1f0b1e 45b12307c695 45b12307c695 45b12307c695 45b12307c695 45b12307c695 45b12307c695 45b12307c695 45b12307c695 45b12307c695 e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e 45b12307c695 e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e 45b12307c695 e6ca7c1f0b1e e6ca7c1f0b1e e6ca7c1f0b1e 45b12307c695 1e4814221a64 45b12307c695 45b12307c695 45b12307c695 e6ca7c1f0b1e 45b12307c695 45b12307c695 | #!/usr/bin/python
from __future__ import division,nested_scopes
import sys
sys.path.append("../../editor/pour")
from skim.zooming import Zooming,Pair
from math import sqrt,sin,cos
from pygame.rect import Rect
from xmlnodebase import xmlnodeclass,collectiveelement,xmldocfile
import dispatcher
import Tkinter as tk
def pairdist(pair1,pair2):
return sqrt((pair1[0]-pair2[0])**2+(pair1[1]-pair2[1])**2)
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,"<Enter>",
lambda ev: canvas.itemconfig(obj,**{attribute:highlightval}))
canvas.tag_bind(obj,"<Leave>",
lambda ev: canvas.itemconfig(obj,**{attribute:normalval}))
class Field(xmlnodeclass):
"""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))
def falloff(self,dist=None):
"""linear falloff from 1 at center, to 0 at dist pixels away
from center"""
return self._getorsettypedattr("falloff",float,dist)
def getdistforintensity(self,intens):
"""returns the distance you'd have to be for the given intensity (0..1)"""
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())
class Fieldset(collectiveelement):
"""group of fields. persistent."""
def childtype(self): return Field
def version(self):
"""read-only version attribute on fieldset tag"""
return self._getorsetattr("version",None)
def report(self,x,y):
"""reports active fields and their intensities"""
active=0
for f in self.getall():
name=f.name()
intens=f.calc(x,y)
if intens>0:
print name,intens,
active+=1
if active>0:
print
def getbounds(self):
"""returns xmin,xmax,ymin,ymax for the non-zero areas of this field"""
r=None
for f in self.getall():
rad=f.getdistforintensity(0)
fx,fy=f.center()
fieldrect=Rect(fx-rad,fy-rad,rad*2,rad*2)
if r is None:
r=fieldrect
else:
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"""
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'),
(.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="arial 10 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
dispatcher.send("field coord changed")
self.setcoords() # redraw
def release(ev):
del self._lastmouse
c.tag_bind(self.txt,"<ButtonPress-1>",press)
c.tag_bind(self.txt,"<B1-Motion>",motion)
c.tag_bind(self.txt,"<B1-ButtonRelease>",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)
dispatcher.send("field coord changed")
self.setcoords()
c.tag_bind(outerring,"<B1-Motion>",motion)
self.setcoords()
class Tracker(tk.Frame):
"""whole tracker widget, which is mostly a view for a
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={}
c=self.canvas=Zooming(self,bg='black',closeenough=5)
c.pack(fill='both',exp=1)
# preserve edge coords over window resize
c.bind("<Configure>",self.configcoords)
c.bind("<Motion>",
lambda ev: self._fieldset().report(*c.canvas2world(ev.x,ev.y)))
def save(ev):
print "saving"
self.fieldsetfile.save()
master.bind("<Key-s>",save)
dispatcher.connect(self.autobounds,"field coord changed")
def _fieldset(self):
return self.fieldsetfile.fieldset()
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
c=self.canvas
cornerx,cornery=c.canvas2world(0,0)
c.move(cornerx-self.xmin,
cornery-self.ymin)
c.setscale(0,0,
c.winfo_width()/(self.xmax-self.xmin),
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()
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()]
########################################################################
########################################################################
root=tk.Tk()
tra=Tracker(root)
tra.pack(fill='both',exp=1)
tra.load("fieldsets/demo")
root.mainloop()
|