Mercurial > MadButterfly
view pyink/tween.py @ 1179:b65df4f0d30a
Change signature of MBScene.insertKeyScene()
author | Thinker K.F. Li <thinker@codemud.net> |
---|---|
date | Fri, 31 Dec 2010 11:10:14 +0800 |
parents | 178b126edd2c |
children | 25e1579ed3d1 |
line wrap: on
line source
# -*- indent-tabs-mode: t; tab-width: 8; python-indent: 4; -*- # vim: sw=4:ts=8:sts=4 import traceback import math class TweenObject: TWEEN_TYPE_NORMAL = 0 #TWEEN_TYPE_RELOCATE = 1 TWEEN_TYPE_SCALE = 1 def __init__(self,doc,dom): self.document = doc self.dom = dom try: self.width = float(dom.getAttribute("width")) self.height = float(dom.getAttribute("height")) except: self.width = 640 self.height = 480 def updateMapping(self): self.nodeToItem={} root = self.dom self.updateMappingNode(root) def updateMappingNode(self,node): for c in node.childList(): self.updateMappingNode(c) try: self.nodeToItem[c.getAttribute("id")] = c except: pass def updateTweenContent(self, duplicate_group, tween_type, start_scene_group, stop_scene_group, percent): """ Update the content of the duplicate scene group. We will use precent, start_scene_group, stop_scene_group to compute transform matrix and update duplicate scene group specified. """ # Collect ref from the obj node = duplicate_group.firstChild() dup_nodes = {} while node: try: ref = node.getAttribute("ref") dup_nodes[ref] = node except: ref = None pass node = node.next() pass # Collect all nodes in stop scene stop_nodes = {} node = stop_scene_group.firstChild() while node: try: node_label = node.getAttribute("ns0:duplicate-src") stop_nodes[node_label] = node except: pass node = node.next() pass # Collect all nodes in start scene start_nodes = {} node = start_scene_group.firstChild() while node: try: node_label = node.getAttribute("id") start_nodes[node_label] = node except: pass node = node.next() pass # Remove duplicate nodes that is not in the set of start nodes for node_ref in dup_nodes: if node_ref not in start_nodes: node = dup_nodes[node_ref] duplicate_group.removeChild(node) pass pass # # Node ID of a node of start scene must be mapped to # 'ns0:duplicate-src' attribute of a node of stop scene. The # nodes which can not be mapped to a node of stop scene are # not manipulated by the tween. # # When a scene is duplicated, 'ns0:duplicate-src' attribute of # nodes, in the new scene, must be setted to ID of respective # one in the duplicated scene. # start_node = start_scene_group.firstChild() while start_node: start_node_id = start_node.getAttribute('id') dup_node = dup_nodes.setdefault(start_node_id, None) try: stop_node = stop_nodes[start_node_id] except KeyError: self.updateTweenObject(duplicate_group, tween_type, start_node, start_node, percent, dup_node) start_node = start_node.next() continue self.updateTweenObject(duplicate_group, tween_type, start_node, stop_node, percent, dup_node) start_node = start_node.next() pass pass def parseTransform(self,obj): """ Return the transform matrix of an object """ try: t = obj.getAttribute("transform") print t if t[0:9] == 'translate': print "translate" fields = t[10:].split(',') x = float(fields[0]) fields = fields[1].split(')') y = float(fields[0]) return [1,0,0,1,x,y] elif t[0:6] == 'matrix': print "matrix" fields=t[7:].split(')') fields = fields[0].split(',') return [float(fields[0]),float(fields[1]),float(fields[2]),float(fields[3]),float(fields[4]),float(fields[5])] except: #traceback.print_exc() return [1,0,0,1,0,0] def invA(self,m): d = m[0]*m[3]-m[2]*m[1] 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] def mulA(self,a,b): return [a[0]*b[0]+a[1]*b[2], a[0]*b[1]+a[1]*b[3], a[2]*b[0]+a[3]*b[2], a[2]*b[1]+a[3]*b[3], a[0]*b[4]+a[1]*b[5]+a[4], a[2]*b[4]+a[3]*b[5]+a[5]] def decomposition(self,m): """ Decompose the affine matrix into production of translation,rotation,shear and scale. The algorithm is documented at http://lists.w3.org/Archives/Public/www-style/2010Jun/0602.html """ if m[0]*m[3] == m[1]*m[2]: print "The affine matrix is singular" return [1,0,0,1,0,0] A=m[0] B=m[2] C=m[1] D=m[3] E=m[4] F=m[5] sx = math.sqrt(A*A+B*B) A = A/sx B = B/sx shear = m[0]*m[1]+m[2]*m[3] C = C - A*shear D = D - B*shear sy = math.sqrt(C*C+D*D) C = C/sy D = D/sy r = A*D-B*C if r == -1: shear = -shear sy = -sy R = math.atan2(B,A) return [sx,sy, R, E,F] def updateTweenObject(self,obj,typ,s,d,p,newobj): """ Generate tweened object in the @obj by using s and d in the @p percent http://lists.w3.org/Archives/Public/www-style/2010Jun/0602.html """ if typ == self.TWEEN_TYPE_SCALE: self.updateTweenObjectScale(obj,s,d,p,newobj) pass elif typ == self.TWEEN_TYPE_NORMAL: print "newobj=",newobj if newobj == None: newobj = s.duplicate(self.document) newobj.setAttribute("ref", s.getAttribute("id")) obj.appendChild(newobj) pass def updateTweenObjectScale(self,obj,s,d,p,newobj): """ Generate a new group which contains the original group and then add the transform matrix to generate a tween frame between the origin and destination scene group. We will parse the transform matrix of the @s and @d and then generate the matrix which is (1-p) of @s and p percent of @d. """ if newobj == None: newobj = s.duplicate(self.document) top = self.document.createElement("svg:g") top.setAttribute("ref",s.getAttribute("id")) top.appendChild(newobj) obj.appendChild(top) else: top = newobj newobj = top.firstChild() if s.name() == 'svg:g': # Parse the translate or matrix # # D = B inv(A) try: item = self.nodeToItem[s.getAttribute("id")] (ox,oy) = item.getCenter() except: ox = 0 oy = 0 try: item = self.nodeToItem[d.getAttribute("id")] (dx,dy) = item.getCenter() except: dx = 0 dy = 0 sm = self.parseTransform(s) ss = self.decomposition(sm) dm = self.parseTransform(d) dd = self.decomposition(dm) sx = (ss[0]*(1-p)+dd[0]*p)/ss[0] sy = (ss[1]*(1-p)+dd[1]*p)/ss[0] a = ss[2]*(1-p)+dd[2]*p-ss[2] tx = ox*(1-p)+dx*p ty = oy*(1-p)+dy*p m = [math.cos(a),math.sin(a),-math.sin(a),math.cos(a),0,0] m = self.mulA([sx,0,0,sy,0,0],m) m = self.mulA(m,[1,0,0,1,-ox,oy-self.height]) m = self.mulA([1,0,0,1,tx,self.height-ty],m) top.setAttribute("transform","matrix(%g,%g,%g,%g,%g,%g)" % (m[0],m[2],m[1],m[3],m[4],m[5])) else: try: try: sw = float(s.getAttribute("width")) except: sw = 1 try: sh = float(s.getAttribute("height")) except: sh = 1 try: dw = float(d.getAttribute("width")) except: dw = 1 try: dh = float(d.getAttribute("height")) except: dh = 1 try: item = self.nodeToItem[s.getAttribute("id")] (ox,oy) = item.getCenter() except: ox = 0 oy = 0 try: item = self.nodeToItem[d.getAttribute("id")] (dx,dy) = item.getCenter() except: dx = 0 dy = 0 try: sm = self.parseTransform(s) ss = self.decomposition(sm) except: ss = [1,1,0,0,0] pass try: dm = self.parseTransform(d) dd = self.decomposition(dm) print "dd=",dd except: dd = [1,1,0,0,0] dd[0] = dd[0]*dw/sw dd[1] = dd[1]*dh/sh print "ss[0]=",ss[0],"dd[0]=",dd[0] sx = (ss[0]*(1-p)+dd[0]*p)/ss[0] sy = (ss[1]*(1-p)+dd[1]*p)/ss[1] print "sx=",sx,"sy=",sy a = ss[2]*(1-p)+dd[2]*p-ss[2] tx = ox*(1-p)+dx*p ty = oy*(1-p)+dy*p m = [math.cos(a),math.sin(a),-math.sin(a),math.cos(a),0,0] m = self.mulA([sx,0,0,sy,0,0],m) m = self.mulA(m,[1,0,0,1,-ox,oy-self.height]) m = self.mulA([1,0,0,1,tx,self.height-ty],m) top.setAttribute("transform","matrix(%g,%g,%g,%g,%g,%g)" % (m[0],m[2],m[1],m[3],m[4],m[5])) except: traceback.print_exc()