Mercurial > MadButterfly
view pyink/tween.py @ 1146:e14ec6d1a661
CHange the implementation to set the transformation matrix only. This is be more friendly for the animation inside the inskcape.
author | wycc |
---|---|
date | Fri, 24 Dec 2010 14:44:07 +0800 |
parents | 8f0ee167c5b2 |
children | 6586cd10c92f |
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: 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,obj, typ, source,dest,cur): """ Update the content of the duplicate scene group. We will use the (start,end) and cur to calculate the percentage of the tween motion effect and then use it to update the transform matrix of the duplicated scene group. """ start = source.idx end = dest.idx print cur,start,end percent = (cur-start)*1.0/(end-start) i = 0 s = source.ref.firstChild() d = dest.ref.firstChild() sources={} dests={} # Collect ref from the obj o = obj.firstChild() maps={} while o: print "--->",o try: ref = o.getAttribute("ref") except: print o ref = None if ref: maps[ref] = o o = o.next() # Collect all objects while d: try: label = d.getAttribute("inkscape:label") except: d = d.next() continue dests[label] = d d = d.next() # Check if the object in the source exists in the destination s = source.ref.firstChild() d = dest.ref.firstChild() while s: print s,d sid = s.getAttribute("id") if maps.has_key(sid): o = maps[sid] else: o = None try: label = s.getAttribute("inkscape:label") # Use i8nkscape:label to identidy the equipvalent objects if label: if dests.hasattr(label.value()): self.updateTweenObject(obj,typ,s,dests[label.value()],percent,o) s = s.next() continue except: pass # Search obejcts in the destination while d: try: d.getAttribute("inkscape:label") d = d.next() continue except: pass if s.name() == d.name(): self.updateTweenObject(obj,typ,s,d,percent,o) d = d.next() break d = d.next() s = s.next() 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 == 'relocate': newobj = s.duplicate(self.document) top = self.document.createElement("svg:g") top.setAttribute("ref", s.getAttribute("id")) top.appendChild(newobj) obj.appendChild(top) if s.name() == 'svg:g': # Parse the translate or matrix sm = self.parseTransform(s) dm = self.parseTransform(d) top.setAttribute("transform","translate(%g,%g)" % ((dm[2]-sm[2])*p,(dm[5]-sm[5])*p)) else: try: sx = float(s.getAttribute("x")) sy = float(s.getAttribute("y")) dx = float(d.getAttribute("x")) dy = float(d.getAttribute("y")) tx = (dx-sx)*p ty = (dy-sy)*p print tx,ty top.setAttribute("transform","translate(%g,%g)" % (tx,ty)) except: traceback.print_exc() pass pass elif typ == 'scale': self.updateTweenObjectScale(obj,s,d,p,newobj) pass elif typ == 'normal': newobj = s.duplicate(self.document) newobj.setAttribute("ref", s.getAttribute("id")) top = self.document.createElement("svg:g") top.appendChild(newobj) obj.appendChild(top) 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()