comparison pyink/tween.py @ 1140:d4dbcb93aee0

Separate the tween from the main module. Handle the normal tween correctly.
author wycc
date Wed, 22 Dec 2010 23:02:46 +0800
parents
children 8f0ee167c5b2
comparison
equal deleted inserted replaced
1138:593a418ed8bf 1140:d4dbcb93aee0
1 # -*- indent-tabs-mode: t; tab-width: 8; python-indent: 4; -*-
2 # vim: sw=4:ts=8:sts=4
3 import traceback
4 import math
5 class TweenObject:
6 def __init__(self,doc,dom):
7 self.document = doc
8 self.dom = dom
9 self.width = float(dom.attribute("width"))
10 self.height = float(dom.attribute("height"))
11
12 def updateMapping(self):
13 self.nodeToItem={}
14 root = self.dom
15 self.updateMappingNode(root)
16 def updateMappingNode(self,node):
17 for c in node.childList():
18 self.updateMappingNode(c)
19 self.nodeToItem[c.getId()] = c
20 def updateTweenContent(self,obj, typ, source,dest,cur):
21 """
22 Update the content of the duplicate scene group. We will use the (start,end) and cur to calculate the percentage of
23 the tween motion effect and then use it to update the transform matrix of the duplicated scene group.
24 """
25
26 start = source.idx
27 end = dest.idx
28 print cur,start,end
29 percent = (cur-start)*1.0/(end-start)
30 i = 0
31 s = source.ref.firstChild()
32 d = dest.ref.firstChild()
33 sources={}
34 dests={}
35
36 # Collect all objects
37 while d:
38 try:
39 label = d.attribute("inkscape:label")
40 except:
41 d = d.getNext()
42 continue
43 dests[label] = d
44 d = d.getNext()
45 # Check if the object in the source exists in the destination
46 s = source.ref.firstChild()
47 d = dest.ref.firstChild()
48 while s:
49 print s,d
50 try:
51 label = s.attribute("inkscape:label")
52 # Use i8nkscape:label to identidy the equipvalent objects
53 if label:
54 if dests.hasattr(label.value()):
55 self.updateTweenObject(obj,typ,s,dests[label.value()],percent)
56 s = s.getNext()
57 continue
58 except:
59 pass
60 # Search obejcts in the destination
61 while d:
62 try:
63 d.attribute("inkscape:label")
64 d = d.getNext()
65 continue
66 except:
67 pass
68 if s.name() == d.name():
69 self.updateTweenObject(obj,typ,s,d,percent)
70 d = d.getNext()
71 break
72 d = d.getNext()
73 s = s.getNext()
74
75 def parseTransform(self,obj):
76 """
77 Return the transform matrix of an object
78 """
79 try:
80 t = obj.attribute("transform")
81 print t
82 if t[0:9] == 'translate':
83 print "translate"
84 fields = t[10:].split(',')
85 x = float(fields[0])
86 fields = fields[1].split(')')
87 y = float(fields[0])
88 return [1,0,0,1,x,y]
89 elif t[0:6] == 'matrix':
90 print "matrix"
91 fields=t[7:].split(')')
92 fields = fields[0].split(',')
93 return [float(fields[0]),float(fields[1]),float(fields[2]),float(fields[3]),float(fields[4]),float(fields[5])]
94 except:
95 #traceback.print_exc()
96 return [1,0,0,1,0,0]
97
98 def invA(self,m):
99 d = m[0]*m[3]-m[2]*m[1]
100 return [m[3]/d, -m[1]/d, -m[2]/d, m[0]/d, (m[1]*m[5]-m[4]*m[3])/d, (m[4]*m[2]-m[0]*m[5])/d]
101
102 def mulA(self,a,b):
103 return [a[0]*b[0]+a[1]*b[2],
104 a[0]*b[1]+a[1]*b[3],
105 a[2]*b[0]+a[3]*b[2],
106 a[2]*b[1]+a[3]*b[3],
107 a[0]*b[4]+a[1]*b[5]+a[4],
108 a[2]*b[4]+a[3]*b[5]+a[5]]
109
110 def decomposition(self,m):
111 """
112 Decompose the affine matrix into production of translation,rotation,shear and scale.
113 The algorithm is documented at http://lists.w3.org/Archives/Public/www-style/2010Jun/0602.html
114 """
115 if m[0]*m[3] == m[1]*m[2]:
116 print "The affine matrix is singular"
117 return [1,0,0,1,0,0]
118 A=m[0]
119 B=m[2]
120 C=m[1]
121 D=m[3]
122 E=m[4]
123 F=m[5]
124 sx = math.sqrt(A*A+B*B)
125 A = A/sx
126 B = B/sx
127 shear = m[0]*m[1]+m[2]*m[3]
128 C = C - A*shear
129 D = D - B*shear
130 sy = math.sqrt(C*C+D*D)
131 C = C/sy
132 D = D/sy
133 r = A*D-B*C
134 if r == -1:
135 shear = -shear
136 sy = -sy
137 R = math.atan2(B,A)
138 return [sx,sy, R, E,F]
139
140
141 def updateTweenObject(self,obj,typ,s,d,p):
142 """
143 Generate tweened object in the @obj by using s and d in the @p percent
144 http://lists.w3.org/Archives/Public/www-style/2010Jun/0602.html
145 """
146 if typ == 'relocate':
147 newobj = s.duplicate(self.document)
148 newobj.setAttribute("ref", s.getId())
149 top = self.document.createElement("svg:g")
150 top.appendChild(newobj)
151 obj.appendChild(top)
152 if s.name() == 'svg:g':
153 # Parse the translate or matrix
154 sm = self.parseTransform(s)
155 dm = self.parseTransform(d)
156 top.setAttribute("transform","translate(%g,%g)" % ((dm[2]-sm[2])*p,(dm[5]-sm[5])*p))
157 else:
158 try:
159 sx = float(s.attribute("x"))
160 sy = float(s.attribute("y"))
161 dx = float(d.attribute("x"))
162 dy = float(d.attribute("y"))
163 tx = (dx-sx)*p
164 ty = (dy-sy)*p
165 print tx,ty
166 top.setAttribute("transform","translate(%g,%g)" % (tx,ty))
167 except:
168 traceback.print_exc()
169 pass
170 pass
171 elif typ == 'scale':
172 self.updateTweenObjectScale(obj,s,d,p)
173 pass
174 elif typ == 'normal':
175 newobj = s.duplicate(self.document)
176 newobj.setAttribute("ref", s.getId())
177 top = self.document.createElement("svg:g")
178 top.appendChild(newobj)
179 obj.appendChild(top)
180 pass
181
182 def updateTweenObjectScale(self,obj,s,d,p):
183 """
184 Generate a new group which contains the original group and then
185 add the transform matrix to generate a tween frame between the
186 origin and destination scene group.
187
188 We will parse the transform matrix of the @s and @d and then
189 generate the matrix which is (1-p) of @s and p percent of @d.
190 """
191 newobj = s.duplicate(self.document)
192 top = self.document.createElement("svg:g")
193 top.appendChild(newobj)
194 obj.appendChild(top)
195
196 if s.name() == 'svg:g':
197 # Parse the translate or matrix
198 #
199 # D = B inv(A)
200 try:
201 item = self.nodeToItem[s.attribute("id")]
202 (ox,oy) = item.getCenter()
203 except:
204 ox = 0
205 oy = 0
206 try:
207 item = self.nodeToItem[d.attribute("id")]
208 (dx,dy) = item.getCenter()
209 except:
210 dx = 0
211 dy = 0
212
213 sm = self.parseTransform(s)
214 ss = self.decomposition(sm)
215 dm = self.parseTransform(d)
216 dd = self.decomposition(dm)
217 sx = (ss[0]*(1-p)+dd[0]*p)/ss[0]
218 sy = (ss[1]*(1-p)+dd[1]*p)/ss[0]
219 a = ss[2]*(1-p)+dd[2]*p-ss[2]
220 tx = ox*(1-p)+dx*p-ox
221 ty = oy*(1-p)+dy*p-oy
222 m = [math.cos(a),math.sin(a),-math.sin(a),math.cos(a),0,0]
223 m = self.mulA([sx,0,0,sy,0,0],m)
224 m = self.mulA(m,[1,0,0,1,-ox,oy-self.height])
225 m = self.mulA([1,0,0,1,tx,self.height-ty],m)
226
227 top.setAttribute("transform","matrix(%g,%g,%g,%g,%g,%g)" % (m[0],m[2],m[1],m[3],m[4],m[5]))
228 else:
229 try:
230 sw = float(s.attribute("width"))
231 sh = float(s.attribute("height"))
232 dw = float(d.attribute("width"))
233 dh = float(d.attribute("height"))
234 try:
235 item = self.nodeToItem[s.attribute("id")]
236 (ox,oy) = item.getCenter()
237 except:
238 ox = 0
239 oy = 0
240 try:
241 item = self.nodeToItem[d.attribute("id")]
242 (dx,dy) = item.getCenter()
243 except:
244 dx = 0
245 dy = 0
246 try:
247 sm = self.parseTransform(s)
248 ss = self.decomposition(sm)
249 except:
250 ss = [1,1,0,0,0]
251 pass
252 try:
253 dm = self.parseTransform(d)
254 dd = self.decomposition(dm)
255 except:
256 dd = [1,1,0,0,0]
257 dd[0] = ss[0]*dw/sw
258 dd[1] = ss[1]*dh/sh
259 sx = (ss[0]*(1-p)+dd[0]*p)/ss[0]
260 sy = (ss[1]*(1-p)+dd[1]*p)/ss[1]
261 a = ss[2]*(1-p)+dd[2]*p-ss[2]
262 tx = ox*(1-p)+dx*p
263 ty = oy*(1-p)+dy*p
264 m = [math.cos(a),math.sin(a),-math.sin(a),math.cos(a),0,0]
265 m = self.mulA([sx,0,0,sy,0,0],m)
266 m = self.mulA(m,[1,0,0,1,-ox,oy-self.height])
267 m = self.mulA([1,0,0,1,tx,self.height-ty],m)
268
269 top.setAttribute("transform","matrix(%g,%g,%g,%g,%g,%g)" % (m[0],m[2],m[1],m[3],m[4],m[5]))
270 except:
271 traceback.print_exc()