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
|
|
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()
|