Mercurial > MadButterfly
comparison pyink/tween.py @ 1358:cd0c0c7547b4
Simplify tween function
author | Thinker K.F. Li <thinker@codemud.net> |
---|---|
date | Wed, 16 Feb 2011 15:07:44 +0800 |
parents | a48df5d53ddc |
children | 5313bbfafa67 |
comparison
equal
deleted
inserted
replaced
1357:a48df5d53ddc | 1358:cd0c0c7547b4 |
---|---|
2 # vim: sw=4:ts=8:sts=4 | 2 # vim: sw=4:ts=8:sts=4 |
3 import traceback | 3 import traceback |
4 import math | 4 import math |
5 | 5 |
6 | 6 |
7 def parse_style(style): | 7 def _shift_matrix(x, y): |
8 return (1, 0, 0, 1, x, y) | |
9 | |
10 | |
11 def _rotate_matrix(a): | |
12 return (math.cos(a), math.sin(a), -math.sin(a), math.cos(a), 0, 0) | |
13 | |
14 | |
15 def _scale_matrix(scale_x, scale_y): | |
16 return (scale_x, 0, 0, scale_y, 0, 0) | |
17 | |
18 | |
19 _id_matrix = (1, 0, 0, 1, 0, 0) | |
20 | |
21 | |
22 def _mulA(a, b): | |
23 return (a[0] * b[0] + a[2] * b[1], | |
24 a[1] * b[0] + a[3] * b[1], | |
25 a[0] * b[2] + a[2] * b[3], | |
26 a[1] * b[2] + a[3] * b[3], | |
27 a[0] * b[4] + a[2] * b[5] + a[4], | |
28 a[1] * b[4] + a[3] * b[5] + a[5]) | |
29 | |
30 | |
31 def _parse_style(style): | |
8 attrs = {} | 32 attrs = {} |
9 | 33 |
10 style_parts = style.split(';') | 34 style_parts = style.split(';') |
11 for part in style_parts: | 35 for part in style_parts: |
12 part = part.strip() | 36 part = part.strip() |
21 attrs[name] = value | 45 attrs[name] = value |
22 pass | 46 pass |
23 | 47 |
24 return attrs | 48 return attrs |
25 | 49 |
26 def gen_style(attrs): | 50 |
51 def _gen_style(attrs): | |
27 parts = [name + ':' + value for name, value in attrs.items()] | 52 parts = [name + ':' + value for name, value in attrs.items()] |
28 style = ';'.join(parts) | 53 style = ';'.join(parts) |
29 return style | 54 return style |
55 | |
56 | |
57 def _parse_transform_str(txt): | |
58 if txt[0:9] == 'translate': | |
59 fields = txt[10:].split(',') | |
60 x = float(fields[0]) | |
61 fields = fields[1].split(')') | |
62 y = float(fields[0]) | |
63 return [1, 0, 0, 1 , x, y] | |
64 elif txt[0:6] == 'matrix': | |
65 fields = txt[7:].split(')') | |
66 fields = fields[0].split(',') | |
67 return [float(field) for field in fields] | |
68 pass | |
69 | |
70 | |
71 ## \brief Parse style attributes about animation. | |
72 # | |
73 def _parse_style_ani(node, ani_attrs): | |
74 try: | |
75 style = node.getAttribute('style') | |
76 except: # has no style | |
77 style_attrs = {} | |
78 else: | |
79 style_attrs = _parse_style(style) | |
80 pass | |
81 | |
82 if 'opacity' in style_attrs: | |
83 ani_attrs['opacity'] = float(style_attrs['opacity']) | |
84 pass | |
85 | |
86 if 'display' in style_attrs: | |
87 ani_attrs['display'] = style_attrs['display'] != 'none' | |
88 pass | |
89 pass | |
90 | |
91 | |
92 ## \brief Parse all attributes about animation | |
93 # | |
94 def _parse_attr_ani(node, ani_attrs): | |
95 def _parse_transform_with_center(attr_value): | |
96 value = _parse_transform_str(attr_value) | |
97 x, y = node.spitem.getCenter() | |
98 return (value, (x, y)) | |
99 | |
100 attr_defs = {'x': float, 'y': float, | |
101 'width': float, 'height': float, | |
102 'transform': _parse_transform_with_center} | |
103 | |
104 for attrname, parser in attr_defs.items(): | |
105 try: | |
106 value = node.getAttribute(attrname) | |
107 except: # has no this attribute | |
108 pass | |
109 else: | |
110 parsed_value = parser(value) | |
111 ani_attrs[attrname] = parsed_value | |
112 pass | |
113 pass | |
114 pass | |
115 | |
116 | |
117 ## \brief Interpolate float values. | |
118 # | |
119 def _interp_float(start_value, stop_value, percent): | |
120 if start_value == None or stop_value == None: | |
121 if percent == 1: | |
122 return stop_value | |
123 return start_value | |
124 | |
125 return start_value * (1 - percent) + stop_value * percent | |
126 | |
127 | |
128 ## \brief Interpolate matric. | |
129 # | |
130 def _interp_transform(start_value, stop_value, percent): | |
131 start_matrix = start_value[0] | |
132 start_center_x, start_center_y = start_value[1] | |
133 stop_matrix = stop_value[0] | |
134 stop_center_x, stop_center_y = stop_value[1] | |
135 | |
136 start_scale_x, start_scale_y, start_ang, start_x, start_y = \ | |
137 _decomposition(start_matrix) | |
138 stop_scale_x, stop_scale_y, stop_ang, stop_x, stop_y = \ | |
139 _decomposition(stop_matrix) | |
140 | |
141 interp = lambda x, y: _interp_float(x, y, percent) | |
142 | |
143 factor_x = interp(start_scale_x, stop_scale_x) / start_scale_x | |
144 factor_y = interp(start_scale_y, stop_scale_y) / start_scale_y | |
145 angle = interp(start_ang, stop_ang) | |
146 shift_x = interp(start_center_x, stop_center_x) | |
147 shift_y = interp(start_center_y, stop_center_y) | |
148 | |
149 # Shift center point back to origin | |
150 matrix = start_matrix | |
151 shift_matrix = _shift_matrix(-start_center_x, -start_center_y) | |
152 matrix = _mulA(shift_matrix, matrix) | |
153 # Remove rotation | |
154 rotate_matrix = _rotate_matrix(-start_ang) | |
155 matrix = _mulA(rotate_matrix, matrix) | |
156 | |
157 # Apply new scaling | |
158 scale_matrix = _scale_matrix(factor_x, factor_y) | |
159 matrix = _mulA(scale_matrix, matrix) | |
160 # Rotate to new angle | |
161 rotate_matrix = _rotate_matrix(angle) | |
162 matrix = _mulA(rotate_matrix, matrix) | |
163 # Shift space to aim center point on new position. | |
164 shift_matrix = _shift_matrix(shift_x, shift_y) | |
165 matrix = _mulA(shift_matrix, matrix) | |
166 | |
167 return matrix | |
168 | |
169 | |
170 ## \brief Interpolate for value of display style. | |
171 # | |
172 def _interp_display(start_value, stop_value, percent): | |
173 if percent < 1: | |
174 return start_value | |
175 return stop_value | |
176 | |
177 | |
178 _interp_funcs = { | |
179 'x': _interp_float, 'y': _interp_float, | |
180 'width': _interp_float, 'height': _interp_float, | |
181 'opacity': _interp_float, 'display': _interp_display, | |
182 'transform': _interp_transform} | |
183 | |
184 | |
185 def _tween_interpolation(attrname, start_value, stop_value, percent): | |
186 interp = _interp_funcs[attrname] | |
187 _interp_value = interp(start_value, stop_value, percent) | |
188 return _interp_value | |
189 | |
190 | |
191 def _apply_animation_attrs(ani_attrs, node): | |
192 for attr in ('x', 'y', 'width', 'height', 'opacity', 'display'): | |
193 if attr in ani_attrs: | |
194 node.setAttribute(attr, str(ani_attrs[attr])) | |
195 pass | |
196 pass | |
197 | |
198 if 'transform' in ani_attrs: | |
199 try: | |
200 style = node.getAttribute('style') | |
201 except: | |
202 style = '' | |
203 pass | |
204 | |
205 transform = [str(elm) for elm in ani_attrs['transform']] | |
206 transform_str = 'matrix(' + ','.join(transform) + ')' | |
207 node.setAttribute('transform', transform_str) | |
208 pass | |
209 | |
210 chg_style = [] | |
211 for attrname in 'opacity display'.split(): | |
212 if attrname in ani_attrs: | |
213 chg_style.append((attrname, str(ani_attrs[attrname]))) | |
214 pass | |
215 pass | |
216 if chg_style: | |
217 try: | |
218 style = node.getAttribute('style') | |
219 except: | |
220 style_attrs = chg_style | |
221 else: | |
222 style_attrs = _parse_style(style) | |
223 style_attrs.update(dict(chg_style)) | |
224 pass | |
225 style = _gen_style(style_attrs) | |
226 node.setAttribute('style', style) | |
227 pass | |
228 pass | |
229 | |
230 | |
231 def _decomposition(m): | |
232 """ | |
233 Decompose the affine matrix into production of | |
234 translation,rotation,shear and scale. The algorithm is | |
235 documented at | |
236 http://lists.w3.org/Archives/Public/www-style/2010Jun/0602.html | |
237 """ | |
238 if m[0]*m[3] == m[1]*m[2]: | |
239 print "The affine matrix is singular" | |
240 return [1,0,0,1,0,0] | |
241 A=m[0] | |
242 B=m[2] | |
243 C=m[1] | |
244 D=m[3] | |
245 E=m[4] | |
246 F=m[5] | |
247 sx = math.sqrt(A*A+B*B) | |
248 A = A/sx | |
249 B = B/sx | |
250 shear = m[0]*m[1]+m[2]*m[3] | |
251 C = C - A*shear | |
252 D = D - B*shear | |
253 sy = math.sqrt(C*C+D*D) | |
254 C = C/sy | |
255 D = D/sy | |
256 r = A*D-B*C | |
257 if r == -1: | |
258 shear = -shear | |
259 sy = -sy | |
260 pass | |
261 R = math.atan2(-B,A) | |
262 return [sx,sy, R, E, F] | |
263 | |
264 | |
265 def _normalize_attrs(node1, attrs1, node2, attrs2): | |
266 if node2.name() == 'svg:use': | |
267 for name in 'x y width height'.split(): | |
268 if name in attrs1: | |
269 del attrs1[name] | |
270 pass | |
271 if name in attrs2: | |
272 del attrs2[name] | |
273 pass | |
274 pass | |
275 pass | |
276 | |
277 names = set(attrs1.keys() + attrs2.keys()) | |
278 | |
279 if 'transform' in names: | |
280 if 'transform' not in attrs1: | |
281 center = node1.spitem.getCenter() | |
282 attrs1['transform'] = (_id_matrix, center) | |
283 pass | |
284 if 'transform' not in attrs2: | |
285 center = node2.spitem.getCenter() | |
286 attrs2['transform'] = (_id_matrix, center) | |
287 pass | |
288 | |
289 root = node1.root() | |
290 try: | |
291 root_h = float(root.getAttribute('height')) | |
292 except: | |
293 root_h = 600 # 800x600 | |
294 pass | |
295 | |
296 for attrs in (attrs1, attrs2): | |
297 transform = attrs['transform'] | |
298 center = (transform[1][0], root_h - transform[1][1]) | |
299 attrs['transform'] = (transform[0], center) | |
300 | |
301 if 'x' in attrs: | |
302 del attrs['x'] | |
303 pass | |
304 if 'y' in attrs: | |
305 del attrs['y'] | |
306 pass | |
307 pass | |
308 pass | |
309 | |
310 if 'opacity' in names: | |
311 if 'opacity' not in attrs1: | |
312 attrs1['opacity'] = 1.0 | |
313 pass | |
314 if 'opacity' not in attrs2: | |
315 attrs2['opacity'] = 1.0 | |
316 pass | |
317 | |
318 if node2.name() == 'svg:use': | |
319 attrs2['opacity'] = attrs2['opacity'] * attrs1['opacity'] | |
320 pass | |
321 pass | |
322 | |
323 if 'display' in names: | |
324 if 'display' not in attrs1: | |
325 attrs1['display'] = '' | |
326 pass | |
327 if 'display' not in attrs2: | |
328 attrs2['display'] = '' | |
329 pass | |
330 pass | |
331 | |
332 for name in 'x y width height'.split(): | |
333 if name in names: | |
334 if name not in attrs1: | |
335 attrs1[name] = 0 | |
336 pass | |
337 if name not in attrs2: | |
338 attrs2[name] = 0 | |
339 pass | |
340 pass | |
341 pass | |
342 pass | |
30 | 343 |
31 class TweenObject(object): | 344 class TweenObject(object): |
32 TWEEN_TYPE_NORMAL = 0 | 345 TWEEN_TYPE_NORMAL = 0 |
33 #TWEEN_TYPE_RELOCATE = 1 | 346 #TWEEN_TYPE_RELOCATE = 1 |
34 TWEEN_TYPE_SCALE = 1 | 347 TWEEN_TYPE_SCALE = 1 |
114 start_node_id = start_node.getAttribute('id') | 427 start_node_id = start_node.getAttribute('id') |
115 dup_node = dup_nodes.setdefault(start_node_id, None) | 428 dup_node = dup_nodes.setdefault(start_node_id, None) |
116 try: | 429 try: |
117 stop_node = stop_nodes[start_node_id] | 430 stop_node = stop_nodes[start_node_id] |
118 except KeyError: | 431 except KeyError: |
119 self.updateTweenObject(duplicate_group, tween_type, | 432 stop_node = start_node |
120 start_node, start_node, | 433 pass |
121 percent, dup_node) | |
122 start_node = start_node.next() | |
123 continue | |
124 | |
125 | 434 |
126 self.updateTweenObject(duplicate_group, tween_type, | 435 self.updateTweenObject(duplicate_group, tween_type, |
127 start_node, stop_node, | 436 start_node, stop_node, |
128 percent, dup_node) | 437 percent, dup_node) |
129 start_node = start_node.next() | 438 start_node = start_node.next() |
130 pass | 439 pass |
131 pass | 440 pass |
132 | 441 |
133 def parseTransform(self,obj): | |
134 """ | |
135 Return the transform matrix of an object | |
136 """ | |
137 try: | |
138 t = obj.getAttribute("transform") | |
139 if t[0:9] == 'translate': | |
140 fields = t[10:].split(',') | |
141 x = float(fields[0]) | |
142 fields = fields[1].split(')') | |
143 y = float(fields[0]) | |
144 return [1,0,0,1,x,y] | |
145 elif t[0:6] == 'matrix': | |
146 fields=t[7:].split(')') | |
147 fields = fields[0].split(',') | |
148 return [float(fields[0]),float(fields[1]),float(fields[2]),float(fields[3]),float(fields[4]),float(fields[5])] | |
149 except: | |
150 #traceback.print_exc() | |
151 return [1,0,0,1,0,0] | |
152 | |
153 def invA(self,m): | |
154 d = m[0]*m[3]-m[2]*m[1] | |
155 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] | |
156 | |
157 def mulA(self,a,b): | |
158 return [a[0]*b[0]+a[1]*b[2], | |
159 a[0]*b[1]+a[1]*b[3], | |
160 a[2]*b[0]+a[3]*b[2], | |
161 a[2]*b[1]+a[3]*b[3], | |
162 a[0]*b[4]+a[1]*b[5]+a[4], | |
163 a[2]*b[4]+a[3]*b[5]+a[5]] | |
164 | |
165 def decomposition(self,m): | |
166 """ | |
167 Decompose the affine matrix into production of translation,rotation,shear and scale. | |
168 The algorithm is documented at http://lists.w3.org/Archives/Public/www-style/2010Jun/0602.html | |
169 """ | |
170 if m[0]*m[3] == m[1]*m[2]: | |
171 print "The affine matrix is singular" | |
172 return [1,0,0,1,0,0] | |
173 A=m[0] | |
174 B=m[2] | |
175 C=m[1] | |
176 D=m[3] | |
177 E=m[4] | |
178 F=m[5] | |
179 sx = math.sqrt(A*A+B*B) | |
180 A = A/sx | |
181 B = B/sx | |
182 shear = m[0]*m[1]+m[2]*m[3] | |
183 C = C - A*shear | |
184 D = D - B*shear | |
185 sy = math.sqrt(C*C+D*D) | |
186 C = C/sy | |
187 D = D/sy | |
188 r = A*D-B*C | |
189 if r == -1: | |
190 shear = -shear | |
191 sy = -sy | |
192 R = math.atan2(B,A) | |
193 return [sx,sy, R, E,F] | |
194 | |
195 | 442 |
196 def updateTweenObject(self,obj,typ,s,d,p,newobj): | 443 def updateTweenObject(self, obj, typ, s, d, p, newobj): |
197 """ | 444 """ |
198 Generate tweened object in the @obj by using s and d in the @p percent | 445 Generate tweened object in the @obj by using s and d in the @p percent |
199 http://lists.w3.org/Archives/Public/www-style/2010Jun/0602.html | 446 http://lists.w3.org/Archives/Public/www-style/2010Jun/0602.html |
200 """ | 447 """ |
201 if typ == self.TWEEN_TYPE_SCALE: | 448 if typ == self.TWEEN_TYPE_SCALE: |
202 self.updateTweenObjectScale(obj,s,d,p,newobj) | |
203 pass | |
204 elif typ == self.TWEEN_TYPE_NORMAL: | |
205 if newobj == None: | 449 if newobj == None: |
206 newobj = s.duplicate(self._doc) | 450 newobj = s.duplicate(self._doc) |
207 newobj.setAttribute("ref", s.getAttribute("id")) | 451 newobj.setAttribute("ref", s.getAttribute("id")) |
208 obj.appendChild(newobj) | 452 obj.appendChild(newobj) |
453 pass | |
454 self.update_tween_object_scale(s, d, p, newobj) | |
455 pass | |
456 elif typ == self.TWEEN_TYPE_NORMAL and newobj == None: | |
457 newobj = s.duplicate(self._doc) | |
458 newobj.setAttribute("ref", s.getAttribute("id")) | |
459 obj.appendChild(newobj) | |
460 pass | |
209 pass | 461 pass |
210 | 462 |
211 def _update_tween_style(self, s, d, p, newobj): | 463 def _update_tween_style(self, s, d, p, newobj): |
212 if d.name() == 'svg:use': | 464 if d.name() == 'svg:use': |
213 return | 465 return |
214 try: | 466 try: |
215 s_style = s.getAttribute('style') | 467 s_style = s.getAttribute('style') |
216 except: | 468 except: |
217 s_attrs = {} | 469 s_attrs = {} |
218 else: | 470 else: |
219 s_attrs = parse_style(s_style) | 471 s_attrs = _parse_style(s_style) |
220 pass | 472 pass |
221 | 473 |
222 try: | 474 try: |
223 d_style = d.getAttribute('style') | 475 d_style = d.getAttribute('style') |
224 except: | 476 except: |
225 d_attrs = {} | 477 d_attrs = {} |
226 else: | 478 else: |
227 d_attrs = parse_style(d_style) | 479 d_attrs = _parse_style(d_style) |
228 pass | 480 pass |
229 | 481 |
230 attrs = dict(s_attrs) | 482 attrs = dict(s_attrs) |
231 | 483 |
232 if s_attrs.has_key('opacity'): | 484 if s_attrs.has_key('opacity'): |
242 pass | 494 pass |
243 | 495 |
244 cur_opacity = start_opacity * (1 - p) + end_opacity * p | 496 cur_opacity = start_opacity * (1 - p) + end_opacity * p |
245 attrs['opacity'] = '%g' % (cur_opacity) | 497 attrs['opacity'] = '%g' % (cur_opacity) |
246 | 498 |
247 new_style = gen_style(attrs) | 499 new_style = _gen_style(attrs) |
248 newobj.setAttribute('style', new_style) | 500 newobj.setAttribute('style', new_style) |
249 pass | 501 pass |
250 | 502 |
251 def updateTweenObjectScale_Group(self, s, d, p, newobj, top): | 503 def update_tween_object_scale(self, start, stop, percent, newobj): |
252 # Parse the translate or matrix | 504 start_attrs = {} |
253 # | 505 _parse_style_ani(start, start_attrs) |
254 # D = B inv(A) | 506 _parse_attr_ani(start, start_attrs) |
255 try: | 507 |
256 (ox,oy) = s.spitem.getCenter() | 508 stop_attrs = {} |
257 except: | 509 _parse_style_ani(stop, stop_attrs) |
258 ox = 0 | 510 _parse_attr_ani(stop, stop_attrs) |
259 oy = 0 | 511 |
260 pass | 512 _normalize_attrs(start, start_attrs, stop, stop_attrs) |
261 | 513 |
262 try: | 514 tween_attrs = {} |
263 (dx,dy) = d.spitem.getCenter() | 515 attrs = set(start_attrs.keys() + stop_attrs.keys()) |
264 except: | 516 for attr in attrs: |
265 dx = 0 | 517 start_v = start_attrs[attr] |
266 dy = 0 | 518 stop_v = stop_attrs[attr] |
267 pass | 519 |
268 | 520 if start_v != stop_v: |
269 self._update_tween_style(s, d, p, newobj) | 521 new_v = _tween_interpolation(attr, start_v, stop_v, percent) |
270 | 522 tween_attrs[attr] = new_v |
271 sm = self.parseTransform(s) | 523 pass |
272 ss = self.decomposition(sm) | 524 pass |
273 dm = self.parseTransform(d) | |
274 dd = self.decomposition(dm) | |
275 sx = (ss[0]*(1-p)+dd[0]*p)/ss[0] | |
276 sy = (ss[1]*(1-p)+dd[1]*p)/ss[1] | |
277 a = ss[2]*(1-p)+dd[2]*p-ss[2] | |
278 tx = ox*(1-p)+dx*p | |
279 ty = oy*(1-p)+dy*p | |
280 m = [math.cos(a),math.sin(a),-math.sin(a),math.cos(a),0,0] | |
281 m = self.mulA([sx,0,0,sy,0,0],m) | |
282 m = self.mulA(m,[1,0,0,1,-ox,oy-self.height]) | |
283 m = self.mulA([1,0,0,1,tx,self.height-ty],m) | |
284 | |
285 top.setAttribute("transform","matrix(%g,%g,%g,%g,%g,%g)" % (m[0],m[2],m[1],m[3],m[4],m[5])) | |
286 pass | |
287 | |
288 def updateTweenObjectScale_Use(self, s, d, p, newobj, top): | |
289 # Parse the translate or matrix | |
290 # | |
291 # D = B inv(A) | |
292 try: | |
293 (ox,oy) = s.spitem.getCenter() | |
294 except: | |
295 ox = 0 | |
296 oy = 0 | |
297 pass | |
298 | |
299 try: | |
300 (dx,dy) = d.spitem.getCenter() | |
301 except: | |
302 dx = 0 | |
303 dy = 0 | |
304 pass | |
305 | |
306 self._update_tween_style(s, d, p, newobj) | |
307 | 525 |
308 dm = self.parseTransform(d) | 526 _apply_animation_attrs(tween_attrs, newobj) |
309 dd = self.decomposition(dm) | |
310 sx = 1-(1-dd[0])*p | |
311 sy = 1-(1-dd[1])*p | |
312 a = dd[2]*p | |
313 tx = ox*(1-p)+dx*p | |
314 ty = oy*(1-p)+dy*p | |
315 m = [math.cos(a),math.sin(a),-math.sin(a),math.cos(a),0,0] | |
316 m = self.mulA([sx,0,0,sy,0,0],m) | |
317 m = self.mulA(m,[1,0,0,1,-ox,oy-self.height]) | |
318 m = self.mulA([1,0,0,1,tx,self.height-ty],m) | |
319 | |
320 top.setAttribute("transform","matrix(%g,%g,%g,%g,%g,%g)" % (m[0],m[2],m[1],m[3],m[4],m[5])) | |
321 pass | |
322 | |
323 def updateTweenObjectScale_Primitive(self, s, d, p, newobj, top): | |
324 try: | |
325 if d.name() == "svg:use": | |
326 sw = 1 | |
327 sh = 1 | |
328 dw = 1 | |
329 dh = 1 | |
330 else: | |
331 try: | |
332 sw = float(s.getAttribute("width")) | |
333 except: | |
334 sw = 1 | |
335 try: | |
336 sh = float(s.getAttribute("height")) | |
337 except: | |
338 sh = 1 | |
339 | |
340 try: | |
341 dw = float(d.getAttribute("width")) | |
342 except: | |
343 dw = 1 | |
344 try: | |
345 dh = float(d.getAttribute("height")) | |
346 except: | |
347 dh = 1 | |
348 pass | |
349 | |
350 self._update_tween_style(s, d, p, newobj) | |
351 | |
352 try: | |
353 (ox,oy) = s.spitem.getCenter() | |
354 except: | |
355 ox = 0 | |
356 oy = 0 | |
357 try: | |
358 (dx,dy) = d.spitem.getCenter() | |
359 except: | |
360 dx = 0 | |
361 dy = 0 | |
362 try: | |
363 sm = self.parseTransform(s) | |
364 ss = self.decomposition(sm) | |
365 except: | |
366 ss = [1,1,0,0,0] | |
367 pass | |
368 try: | |
369 dm = self.parseTransform(d) | |
370 dd = self.decomposition(dm) | |
371 except: | |
372 dd = [1,1,0,0,0] | |
373 dd[0] = dd[0]*dw/sw | |
374 dd[1] = dd[1]*dh/sh | |
375 sx = (ss[0]*(1-p)+dd[0]*p)/ss[0] | |
376 sy = (ss[1]*(1-p)+dd[1]*p)/ss[1] | |
377 a = ss[2]*(1-p)+dd[2]*p-ss[2] | |
378 tx = ox*(1-p)+dx*p | |
379 ty = oy*(1-p)+dy*p | |
380 m = [math.cos(a),math.sin(a),-math.sin(a),math.cos(a),0,0] | |
381 m = self.mulA([sx,0,0,sy,0,0],m) | |
382 m = self.mulA(m,[1,0,0,1,-ox,oy-self.height]) | |
383 m = self.mulA([1,0,0,1,tx,self.height-ty],m) | |
384 | |
385 top.setAttribute("transform","matrix(%g,%g,%g,%g,%g,%g)" % (m[0],m[2],m[1],m[3],m[4],m[5])) | |
386 except: | |
387 traceback.print_exc() | |
388 pass | |
389 pass | |
390 | |
391 def updateTweenObjectScale(self,obj,s,d,p,newobj): | |
392 """ | |
393 Generate a new group which contains the original group and then | |
394 add the transform matrix to generate a tween frame between the | |
395 origin and destination scene group. | |
396 | |
397 We will parse the transform matrix of the @s and @d and then | |
398 generate the matrix which is (1-p) of @s and p percent of @d. | |
399 """ | |
400 if newobj and not newobj.firstChild(): | |
401 # newobj is not with expect structure. | |
402 # | |
403 # When a user change tween type of a scene, the structure | |
404 # of dup group created by old tween type may not satisfy | |
405 # the requirement of current tween type. | |
406 newobj.parent().removeChild(newobj) | |
407 newobj = None | |
408 pass | |
409 | |
410 if newobj == None: | |
411 newobj = s.duplicate(self._doc) | |
412 top = self._doc.createElement("svg:g") | |
413 top.setAttribute("ref",s.getAttribute("id")) | |
414 top.appendChild(newobj) | |
415 obj.appendChild(top) | |
416 else: | |
417 top = newobj | |
418 newobj = newobj.firstChild() | |
419 pass | |
420 if s.name() == 'svg:g': | |
421 self.updateTweenObjectScale_Group(s,d,p,newobj,top) | |
422 elif s.name() == 'svg:use': | |
423 self.updateTweenObjectScale_Use(s,d,p,newobj,top) | |
424 else: | |
425 self.updateTweenObjectScale_Primitive(s,d,p,newobj,top) | |
426 pass | 527 pass |
427 pass | 528 pass |
428 | 529 |
429 ## \brief Providing capability of showing scenes. | 530 ## \brief Providing capability of showing scenes. |
430 # | 531 # |