Mercurial > MadButterfly
view pyink/tween.py @ 1172:178b126edd2c
Implement the correct normal tween. We will duplicate the node in the start scene. Insted of deleting all nodes which is not in the stop scene, we should delete the object which is not in the start scene instead. If we delete objecvt the the stop scene, the object should appear until we reach the stop scene.
author | wycc |
---|---|
date | Thu, 30 Dec 2010 11:50:02 +0800 |
parents | e64b02951627 |
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()