Mercurial > MadButterfly
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) |