# HG changeset patch # User wycc # Date 1293033646 -28800 # Node ID 8f0ee167c5b2f04186ef1f6b4cd76768deac0bf3 # Parent d4dbcb93aee0ab91252afaf06fa01c2d84437ceb# Parent a2b0685944122ba28cf257f34ba08a7243819712 Fix the issue of the new DOM implementation diff -r a2b068594412 -r 8f0ee167c5b2 pyink/MBScene.py --- a/pyink/MBScene.py Wed Dec 22 13:27:37 2010 +0800 +++ b/pyink/MBScene.py Thu Dec 23 00:00:46 2010 +0800 @@ -11,6 +11,7 @@ import time import pybInkscape import math +from tween import TweenObject # Please refer to # http://www.assembla.com/wiki/show/MadButterfly/Inkscape_extention @@ -132,33 +133,15 @@ pybInkscape.inkscape.connect('change_selection', self.show_selection) self.last_select = None self.lockui=False + self.tween=None + self.document = None + self.dom = None pass - def startPolling(self): - objs = self.desktop.selection.list() - if len(objs) != 1: - glib.timeout_add(500,self.startPolling) - try: - self.nameEditor.set_text('') - except: - traceback.print_exc() - pass - return - o = objs[0] - if o == self.last_select: - glib.timeout_add(500,self.startPolling) - return - self.last_select = o - try: - self.nameEditor.set_text(o.getAttribute("inkscape:label")) - except: - self.nameEditor.set_text('') - pass - glib.timeout_add(500,self.startPolling) def show_selection(self,w,obj): objs = self.desktop.selection.list() try: - o = objs[0].repr + o = objs[0] print o.getCenter() if o == self.last_select: return @@ -241,13 +224,14 @@ pass pass if self.scenemap==None: - self.document.root().setAttribute("xmlns:ns0","http://madbutterfly.sourceforge.net/DTD/madbutterfly.dtd") + #self.desktop.doc().root().repr.setAttribute("xmlns:ns0","http://madbutterfly.sourceforge.net/DTD/madbutterfly.dtd") + self.dom.setAttribute("xmlns:ns0","http://madbutterfly.sourceforge.net/DTD/madbutterfly.dtd") scenes = self.document.createElement("ns0:scenes") node.appendChild(scenes) def update(self): - root = self.document.root() + doc = self.dom rdoc = self.document - for node in root.childList(): + for node in doc.childList(): if node.name() == 'svg:metadata': for t in node.childList(): if t.name() == "ns0:scenes": @@ -267,22 +251,22 @@ """ self.layers = [] self.scenemap = None - root = self.document.root() + doc = self.dom #obs = pybInkscape.PYNodeObserver() #obs = LayerAddRemoveWatcher(self) - #root.addObserver(obs) - addEventListener(root,'DOMNodeInserted',self.updateUI,None) - addEventListener(root,'DOMNodeRemoved',self.updateUI,None) - root.childList() + #doc.addObserver(obs) + addEventListener(doc,'DOMNodeInserted',self.updateUI,None) + addEventListener(doc,'DOMNodeRemoved',self.updateUI,None) + doc.childList() try: - self.width = float(root.getAttribute("width")) - self.height= float(root.getAttribute("height")) + self.width = float(doc.getAttribute("width")) + self.height= float(doc.getAttribute("height")) except: self.width = 640 self.height=480 - for node in root.childList(): + for node in doc.childList(): print node.name() if node.name() == 'svg:metadata': self.parseMetadata(node) @@ -330,7 +314,7 @@ def collectID(self): self.ID = {} - root = self.document.root() + root = self.dom for n in root.childList(): self.collectID_recursive(n) pass @@ -339,7 +323,7 @@ def collectID_recursive(self,node): try: self.ID[node.getAttribute('id')] = 1 - except KeyError: + except: pass for n in node.childList(): self.collectID_recursive(n) @@ -388,12 +372,7 @@ txt.setAttribute("height","100") txt.setAttribute("style","fill:#ff00") ns.appendChild(txt) - try: - gid = self.last_line.node.getAttribute('inkscape:label') + \ - self.newID() - except KeyError: - gid = self.newID() - pass + gid = self.last_line.node.label()+self.newID() self.ID[gid]=1 ns.setAttribute("id",gid) ns.setAttribute("inkscape:groupmode","layer") @@ -509,6 +488,8 @@ pass pass + + def setCurrentScene(self,nth): """ Update the scene group according to the curretn scene data. There are a couple of cases. @@ -524,6 +505,7 @@ available. """ self.current = nth + self.tween.updateMapping() for layer in self._framelines: i=0 @@ -559,255 +541,41 @@ layer.duplicateGroup.setAttribute("sodipodi:insensitive","1") s.ref.setAttribute("style","display:none") s.ref.parent().appendChild(layer.duplicateGroup) - self.updateTweenContent(layer.duplicateGroup, layer.get_tween_type(s.idx),s, layer._keys[i+2], nth) + self.tween.updateTweenContent(layer.duplicateGroup, layer.get_tween_type(s.idx),s, layer._keys[i+2], nth) + else: + layer.duplicateGroup = s.ref.duplicate(self.document) + layer.duplicateGroup.setAttribute("style","") + layer.duplicateGroup.setAttribute("inkscape:label","dup") + layer.duplicateGroup.setAttribute("sodipodi:insensitive","1") + s.ref.setAttribute("style","display:none") + s.ref.parent().appendChild(layer.duplicateGroup) else: s.ref.setAttribute("style","display:none") i = i + 2 pass pass 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. + + def DOMtoItem(self,obj): """ - 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 all objects - while d: - try: - label = d.getAttribute("inkscape:label") - except KeyError: - 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 - 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) - 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) - 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 parseMatrix(self,m): - d = (1-m[0])*(1-m[3])-m[1]*m[2] - if d == 0: - return [1,0,0,1,m[4],m[5]] - else: - return [m[0],m[1],m[2],m[3],(m[4]-m[3]*m[4]+m[1]*m[5])/d,(m[5]-m[0]*m[5]+m[2]*m[4])/d] - - 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 + Find the corresponding PYSPObject object for a DOM object. """ - 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] + return self.DOMtoItem_recursive(self.desktop.doc().root(),obj) - - def updateTweenObject(self,obj,typ,s,d,p): - """ - 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 - """ - print 'compare',s,d - if typ == 'relocate': - print "percent",p - newobj = s.duplicate(self.document) - newobj.setAttribute("ref", s.getAttribute('id')) - top = self.document.createElement("svg:g") - top.appendChild(newobj) - obj.appendChild(top) - print s.name() - 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': - newobj = s.duplicate(self.document) - top = self.document.createElement("svg:g") - top.appendChild(newobj) - obj.appendChild(top) - - print s,d - if s.name() == 'svg:g': - # Parse the translate or matrix - # - # D = B inv(A) - item = s.spitem - (ox,oy) = item.getCenter() - item = d.spitem - (dx,dy) = item.getCenter() - - 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-ox - ty = oy*(1-p)+dy*p-oy - 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) + def DOMtoItem_recursive(self,tree,obj): + nodes = tree.childList() + for s in nodes: + if s.getId() == obj.getAttribute('id'): + return s + d = self.DOMtoItem_recursive(s,obj) + if d != None: return d + - top.setAttribute("transform","matrix(%g,%g,%g,%g,%g,%g)" % (m[0],m[2],m[1],m[3],m[4],m[5])) - else: - try: - sw = float(s.getAttribute("width")) - sh = float(s.getAttribute("height")) - dw = float(d.getAttribute("width")) - dh = float(d.getAttribute("height")) - try: - item = self.nodeToItem[s.attribute("id")] - (ox,oy) = item.getCenter() - except: - ox = 0 - oy = 0 - try: - item = self.nodeToItem[d.attribute("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) - except: - dd = [1,1,0,0,0] - pass - dd[0] = ss[0]*dw/sw - dd[1] = ss[1]*dh/sh - sx = (ss[0]*(1-p)+dd[0]*p)/ss[0] - sy = (ss[1]*(1-p)+dd[1]*p)/ss[1] - 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() - pass - pass - - pass def enterGroup(self,obj): for l in self.layers: for s in l.node.childList(): if s.getAttribute('id') == obj.getAttribute("id"): - self.desktop.setCurrentLayer(s.spitem) + self.desktop.setCurrentLayer(self.DOMtoItem(s)) def selectSceneObject(self,frameline, nth): i = 0 @@ -898,7 +666,7 @@ for i in range(len(self.layers)-1,-1,-1): line = frameline.frameline(nframes) hbox = gtk.HBox() - label = gtk.Label(self.layers[i].node.getAttribute('inkscape:label')) + label = gtk.Label(self.layers[i].node.getAttribute("inkscape:label")) label.set_size_request(100,0) hbox.pack_start(label,expand=False,fill=True) hbox.pack_start(line) @@ -919,11 +687,10 @@ def _update_framelines(self): for frameline in self._framelines: layer = frameline.layer - try: - frameline.label.set_text(frameline.node.getAttribute('inkscape:label')) - except KeyError: - frameline.label.set_text('???') - pass + if frameline.node.getAttribute("inkscape:label")==None: + frameline.label.set_text('???') + else: + frameline.label.set_text(frameline.node.getAttribute("inkscape:label")) for scene in layer.scenes: frameline.add_keyframe(scene.start-1,scene.node) if scene.start != scene.end: @@ -964,10 +731,10 @@ i = i + 1 def duplicateSceneGroup(self,gid): # Search for the duplicated group - root = self.document.root() + doc = self.dom rdoc = self.document orig = None - for node in root.childList(): + for node in doc.childList(): if node.name() == 'svg:g': for t in node.childList(): if t.name() == "svg:g": @@ -977,12 +744,7 @@ if orig == None: return None ns = orig.duplicate(rdoc) - try: - gid = self.last_line.node.getAttribute('inkscape:label') + \ - self.newID() - except KeyError: - gid = self.newID() - pass + gid = self.last_line.node.label()+self.newID() self.ID[gid]=1 ns.setAttribute("id",gid) ns.setAttribute("inkscape:groupmode","layer") @@ -1113,7 +875,9 @@ self.last_update = glib.timeout_add(300,self.show) def show(self): self.OK = True + self.dom = self.desktop.doc().root().repr self.document = self.desktop.doc().rdoc + self.tween = TweenObject(self.document,self.dom) self.parseScene() self._create_framelines() self._update_framelines() diff -r a2b068594412 -r 8f0ee167c5b2 pyink/primitive_test.svg --- a/pyink/primitive_test.svg Wed Dec 22 13:27:37 2010 +0800 +++ b/pyink/primitive_test.svg Thu Dec 23 00:00:46 2010 +0800 @@ -15,7 +15,7 @@ id="svg2" version="1.1" inkscape:version="0.48+devel r9774 custom" - sodipodi:docname="aa.svg"> + sodipodi:docname="primitive_test.svg"> @@ -84,8 +85,8 @@ id="rect3431" height="432.13434" width="64.699173" - y="213.35323" - x="9.338623" /> + y="220.30684" + x="3.5009925" /> diff -r a2b068594412 -r 8f0ee167c5b2 pyink/tween.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pyink/tween.py Thu Dec 23 00:00:46 2010 +0800 @@ -0,0 +1,278 @@ +# -*- 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 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 + 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) + 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) + 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): + """ + 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) + newobj.setAttribute("ref", s.getAttribute("id")) + top = self.document.createElement("svg:g") + 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) + 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): + """ + 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. + """ + newobj = s.duplicate(self.document) + top = self.document.createElement("svg:g") + top.appendChild(newobj) + obj.appendChild(top) + + 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-ox + ty = oy*(1-p)+dy*p-oy + 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: + sw = float(s.getAttribute("width")) + sh = float(s.getAttribute("height")) + dw = float(d.getAttribute("width")) + dh = float(d.getAttribute("height")) + 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) + except: + dd = [1,1,0,0,0] + dd[0] = ss[0]*dw/sw + dd[1] = ss[1]*dh/sh + sx = (ss[0]*(1-p)+dd[0]*p)/ss[0] + sy = (ss[1]*(1-p)+dd[1]*p)/ss[1] + 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()