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