comparison pyink/MBScene.py @ 1140:d4dbcb93aee0

Separate the tween from the main module. Handle the normal tween correctly.
author wycc
date Wed, 22 Dec 2010 23:02:46 +0800
parents 950076863b7e
children 8f0ee167c5b2
comparison
equal deleted inserted replaced
1138:593a418ed8bf 1140:d4dbcb93aee0
9 import random 9 import random
10 import traceback 10 import traceback
11 import time 11 import time
12 import pybInkscape 12 import pybInkscape
13 import math 13 import math
14 from tween import TweenObject
14 15
15 # Please refer to 16 # Please refer to
16 # http://www.assembla.com/wiki/show/MadButterfly/Inkscape_extention 17 # http://www.assembla.com/wiki/show/MadButterfly/Inkscape_extention
17 # for the designed document. 18 # for the designed document.
18 19
130 self.top = None 131 self.top = None
131 self.last_update = None 132 self.last_update = None
132 pybInkscape.inkscape.connect('change_selection', self.show_selection) 133 pybInkscape.inkscape.connect('change_selection', self.show_selection)
133 self.last_select = None 134 self.last_select = None
134 self.lockui=False 135 self.lockui=False
135 pass 136 self.tween=None
136 137 self.document = None
137 def startPolling(self): 138 self.dom = None
138 objs = self.desktop.selection.list() 139 pass
139 if len(objs) != 1: 140
140 glib.timeout_add(500,self.startPolling)
141 try:
142 self.nameEditor.set_text('')
143 except:
144 traceback.print_exc()
145 pass
146 return
147 o = objs[0]
148 if o == self.last_select:
149 glib.timeout_add(500,self.startPolling)
150 return
151 self.last_select = o
152 try:
153 self.nameEditor.set_text(o.repr.attribute("inkscape:label"))
154 except:
155 self.nameEditor.set_text('')
156 pass
157 glib.timeout_add(500,self.startPolling)
158 def show_selection(self,w,obj): 141 def show_selection(self,w,obj):
159 objs = self.desktop.selection.list() 142 objs = self.desktop.selection.list()
160 try: 143 try:
161 o = objs[0] 144 o = objs[0]
162 print o.getCenter() 145 print o.getCenter()
500 return 483 return
501 pass 484 pass
502 pass 485 pass
503 pass 486 pass
504 487
505 def updateMapping(self):
506 self.nodeToItem={}
507 root = self.dom
508 self.updateMappingNode(root)
509 def updateMappingNode(self,node):
510 for c in node.childList():
511 self.updateMappingNode(c)
512 self.nodeToItem[c.getId()] = c
513 print "Add",c.getId()
514 488
515 489
516 def setCurrentScene(self,nth): 490 def setCurrentScene(self,nth):
517 """ 491 """
518 Update the scene group according to the curretn scene data. There are a couple of cases. 492 Update the scene group according to the curretn scene data. There are a couple of cases.
526 For each layer, we will always use the duplicated scene group whose name as dup. 500 For each layer, we will always use the duplicated scene group whose name as dup.
527 We will put the duplicated scene group inside it. We will create this group if it is not 501 We will put the duplicated scene group inside it. We will create this group if it is not
528 available. 502 available.
529 """ 503 """
530 self.current = nth 504 self.current = nth
531 self.updateMapping() 505 self.tween.updateMapping()
532 for layer in self._framelines: 506 for layer in self._framelines:
533 i=0 507 i=0
534 508
535 # Check the duplicated scene group and create it if it is not available 509 # Check the duplicated scene group and create it if it is not available
536 try: 510 try:
562 layer.duplicateGroup = self.document.createElement("svg:g") 536 layer.duplicateGroup = self.document.createElement("svg:g")
563 layer.duplicateGroup.setAttribute("inkscape:label","dup") 537 layer.duplicateGroup.setAttribute("inkscape:label","dup")
564 layer.duplicateGroup.setAttribute("sodipodi:insensitive","1") 538 layer.duplicateGroup.setAttribute("sodipodi:insensitive","1")
565 s.ref.setAttribute("style","display:none") 539 s.ref.setAttribute("style","display:none")
566 s.ref.parent().appendChild(layer.duplicateGroup) 540 s.ref.parent().appendChild(layer.duplicateGroup)
567 self.updateTweenContent(layer.duplicateGroup, layer.get_tween_type(s.idx),s, layer._keys[i+2], nth) 541 self.tween.updateTweenContent(layer.duplicateGroup, layer.get_tween_type(s.idx),s, layer._keys[i+2], nth)
542 else:
543 layer.duplicateGroup = s.ref.duplicate(self.document)
544 layer.duplicateGroup.setAttribute("style","")
545 layer.duplicateGroup.setAttribute("inkscape:label","dup")
546 layer.duplicateGroup.setAttribute("sodipodi:insensitive","1")
547 s.ref.setAttribute("style","display:none")
548 s.ref.parent().appendChild(layer.duplicateGroup)
568 else: 549 else:
569 s.ref.setAttribute("style","display:none") 550 s.ref.setAttribute("style","display:none")
570 i = i + 2 551 i = i + 2
571 pass 552 pass
572 pass 553 pass
573 pass 554 pass
574 def updateTweenContent(self,obj, typ, source,dest,cur): 555
575 """
576 Update the content of the duplicate scene group. We will use the (start,end) and cur to calculate the percentage of
577 the tween motion effect and then use it to update the transform matrix of the duplicated scene group.
578 """
579 start = source.idx
580 end = dest.idx
581 print cur,start,end
582 percent = (cur-start)*1.0/(end-start)
583 i = 0
584 s = source.ref.firstChild()
585 d = dest.ref.firstChild()
586 sources={}
587 dests={}
588
589 # Collect all objects
590 while d:
591 try:
592 label = d.attribute("inkscape:label")
593 except:
594 d = d.getNext()
595 continue
596 dests[label] = d
597 d = d.getNext()
598 # Check if the object in the source exists in the destination
599 s = source.ref.firstChild()
600 d = dest.ref.firstChild()
601 while s:
602 print s,d
603 try:
604 label = s.attribute("inkscape:label")
605 # Use i8nkscape:label to identidy the equipvalent objects
606 if label:
607 if dests.hasattr(label.value()):
608 self.updateTweenObject(obj,typ,s,dests[label.value()],percent)
609 s = s.getNext()
610 continue
611 except:
612 pass
613 # Search obejcts in the destination
614 while d:
615 try:
616 d.attribute("inkscape:label")
617 d = d.getNext()
618 continue
619 except:
620 pass
621 if s.name() == d.name():
622 self.updateTweenObject(obj,typ,s,d,percent)
623 d = d.getNext()
624 break
625 d = d.getNext()
626 s = s.getNext()
627 def parseTransform(self,obj):
628 """
629 Return the transform matrix of an object
630 """
631 try:
632 t = obj.attribute("transform")
633 print t
634 if t[0:9] == 'translate':
635 print "translate"
636 fields = t[10:].split(',')
637 x = float(fields[0])
638 fields = fields[1].split(')')
639 y = float(fields[0])
640 return [1,0,0,1,x,y]
641 elif t[0:6] == 'matrix':
642 print "matrix"
643 fields=t[7:].split(')')
644 fields = fields[0].split(',')
645 return [float(fields[0]),float(fields[1]),float(fields[2]),float(fields[3]),float(fields[4]),float(fields[5])]
646 except:
647 #traceback.print_exc()
648 return [1,0,0,1,0,0]
649
650 def invA(self,m):
651 d = m[0]*m[3]-m[2]*m[1]
652 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]
653 def mulA(self,a,b):
654 return [a[0]*b[0]+a[1]*b[2],
655 a[0]*b[1]+a[1]*b[3],
656 a[2]*b[0]+a[3]*b[2],
657 a[2]*b[1]+a[3]*b[3],
658 a[0]*b[4]+a[1]*b[5]+a[4],
659 a[2]*b[4]+a[3]*b[5]+a[5]]
660 def parseMatrix(self,m):
661 d = (1-m[0])*(1-m[3])-m[1]*m[2]
662 if d == 0:
663 return [1,0,0,1,m[4],m[5]]
664 else:
665 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]
666
667 def decomposition(self,m):
668 """
669 Decompose the affine matrix into production of translation,rotation,shear and scale.
670 The algorithm is documented at http://lists.w3.org/Archives/Public/www-style/2010Jun/0602.html
671 """
672 if m[0]*m[3] == m[1]*m[2]:
673 print "The affine matrix is singular"
674 return [1,0,0,1,0,0]
675 A=m[0]
676 B=m[2]
677 C=m[1]
678 D=m[3]
679 E=m[4]
680 F=m[5]
681 sx = math.sqrt(A*A+B*B)
682 A = A/sx
683 B = B/sx
684 shear = m[0]*m[1]+m[2]*m[3]
685 C = C - A*shear
686 D = D - B*shear
687 sy = math.sqrt(C*C+D*D)
688 C = C/sy
689 D = D/sy
690 r = A*D-B*C
691 if r == -1:
692 shear = -shear
693 sy = -sy
694 R = math.atan2(B,A)
695 return [sx,sy, R, E,F]
696
697
698 def updateTweenObject(self,obj,typ,s,d,p):
699 """
700 Generate tweened object in the @obj by using s and d in the @p percent
701 http://lists.w3.org/Archives/Public/www-style/2010Jun/0602.html
702 """
703 print 'compare',s,d
704 if typ == 'relocate':
705 print "percent",p
706 newobj = s.duplicate(self.document)
707 newobj.setAttribute("ref", s.getId())
708 top = self.document.createElement("svg:g")
709 top.appendChild(newobj)
710 obj.appendChild(top)
711 print s.name()
712 if s.name() == 'svg:g':
713 # Parse the translate or matrix
714 sm = self.parseTransform(s)
715 dm = self.parseTransform(d)
716 top.setAttribute("transform","translate(%g,%g)" % ((dm[2]-sm[2])*p,(dm[5]-sm[5])*p))
717 else:
718 try:
719 sx = float(s.attribute("x"))
720 sy = float(s.attribute("y"))
721 dx = float(d.attribute("x"))
722 dy = float(d.attribute("y"))
723 tx = (dx-sx)*p
724 ty = (dy-sy)*p
725 print tx,ty
726 top.setAttribute("transform","translate(%g,%g)" % (tx,ty))
727 except:
728 #traceback.print_exc()
729 pass
730 pass
731 elif typ == 'scale':
732 newobj = s.duplicate(self.document)
733 top = self.document.createElement("svg:g")
734 top.appendChild(newobj)
735 obj.appendChild(top)
736
737 print s,d
738 if s.name() == 'svg:g':
739 # Parse the translate or matrix
740 #
741 # D = B inv(A)
742 try:
743 item = self.nodeToItem[s.attribute("id")]
744 (ox,oy) = item.getCenter()
745 except:
746 ox = 0
747 oy = 0
748 try:
749 item = self.nodeToItem[d.attribute("id")]
750 (dx,dy) = item.getCenter()
751 except:
752 dx = 0
753 dy = 0
754
755 sm = self.parseTransform(s)
756 ss = self.decomposition(sm)
757 dm = self.parseTransform(d)
758 dd = self.decomposition(dm)
759 sx = (ss[0]*(1-p)+dd[0]*p)/ss[0]
760 sy = (ss[1]*(1-p)+dd[1]*p)/ss[0]
761 a = ss[2]*(1-p)+dd[2]*p-ss[2]
762 tx = ox*(1-p)+dx*p-ox
763 ty = oy*(1-p)+dy*p-oy
764 m = [math.cos(a),math.sin(a),-math.sin(a),math.cos(a),0,0]
765 m = self.mulA([sx,0,0,sy,0,0],m)
766 m = self.mulA(m,[1,0,0,1,-ox,oy-self.height])
767 m = self.mulA([1,0,0,1,tx,self.height-ty],m)
768
769 top.setAttribute("transform","matrix(%g,%g,%g,%g,%g,%g)" % (m[0],m[2],m[1],m[3],m[4],m[5]))
770 else:
771 try:
772 sw = float(s.attribute("width"))
773 sh = float(s.attribute("height"))
774 dw = float(d.attribute("width"))
775 dh = float(d.attribute("height"))
776 try:
777 item = self.nodeToItem[s.attribute("id")]
778 (ox,oy) = item.getCenter()
779 except:
780 ox = 0
781 oy = 0
782 try:
783 item = self.nodeToItem[d.attribute("id")]
784 (dx,dy) = item.getCenter()
785 except:
786 dx = 0
787 dy = 0
788 try:
789 sm = self.parseTransform(s)
790 ss = self.decomposition(sm)
791 except:
792 ss = [1,1,0,0,0]
793 pass
794 try:
795 dm = self.parseTransform(d)
796 dd = self.decomposition(dm)
797 except:
798 dd = [1,1,0,0,0]
799 pass
800 dd[0] = ss[0]*dw/sw
801 dd[1] = ss[1]*dh/sh
802 sx = (ss[0]*(1-p)+dd[0]*p)/ss[0]
803 sy = (ss[1]*(1-p)+dd[1]*p)/ss[1]
804 a = ss[2]*(1-p)+dd[2]*p-ss[2]
805 tx = ox*(1-p)+dx*p
806 ty = oy*(1-p)+dy*p
807 m = [math.cos(a),math.sin(a),-math.sin(a),math.cos(a),0,0]
808 m = self.mulA([sx,0,0,sy,0,0],m)
809 m = self.mulA(m,[1,0,0,1,-ox,oy-self.height])
810 m = self.mulA([1,0,0,1,tx,self.height-ty],m)
811
812 top.setAttribute("transform","matrix(%g,%g,%g,%g,%g,%g)" % (m[0],m[2],m[1],m[3],m[4],m[5]))
813 except:
814 traceback.print_exc()
815 pass
816 pass
817
818 pass
819 def enterGroup(self,obj): 556 def enterGroup(self,obj):
820 for l in self.layers: 557 for l in self.layers:
821 for s in l.node.childList(): 558 for s in l.node.childList():
822 if s.getId() == obj.attribute("id"): 559 if s.getId() == obj.attribute("id"):
823 self.desktop.setCurrentLayer(s) 560 self.desktop.setCurrentLayer(s)
1120 self.last_update = glib.timeout_add(300,self.show) 857 self.last_update = glib.timeout_add(300,self.show)
1121 def show(self): 858 def show(self):
1122 self.OK = True 859 self.OK = True
1123 self.dom = self.desktop.doc().root() 860 self.dom = self.desktop.doc().root()
1124 self.document = self.desktop.doc().rdoc 861 self.document = self.desktop.doc().rdoc
862 self.tween = TweenObject(self.document,self.dom)
1125 self.parseScene() 863 self.parseScene()
1126 self._create_framelines() 864 self._create_framelines()
1127 self._update_framelines() 865 self._update_framelines()
1128 if self.top == None: 866 if self.top == None:
1129 self.top = gtk.VBox(False,0) 867 self.top = gtk.VBox(False,0)