Skip to content

Commit 99be141

Browse files
committed
rotateOrder support and other updates
1 parent ee14e24 commit 99be141

File tree

1 file changed

+52
-41
lines changed

1 file changed

+52
-41
lines changed

ml_copyAnim.py

Lines changed: 52 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
# / __ `__ \/ / Licensed under Creative Commons BY-SA
66
# / / / / / / / http://creativecommons.org/licenses/by-sa/3.0/
77
# /_/ /_/ /_/_/ _________
8-
# /_________/ Revision 4, 2014-03-01
8+
# /_________/ Revision 5, 2017-07-19
99
# _______________________________
1010
# - -/__ Installing Python Scripts __/- - - - - - - - - - - - - - - - - - - -
1111
#
@@ -46,15 +46,15 @@
4646
__author__ = 'Morgan Loomis'
4747
__license__ = 'Creative Commons Attribution-ShareAlike'
4848
__category__ = 'animationScripts'
49-
__revision__ = 4
49+
__revision__ = 5
5050

5151
import maya.cmds as mc
5252
import maya.mel as mm
5353
from maya import OpenMaya
5454

5555
try:
5656
import ml_utilities as utl
57-
utl.upToDateCheck(9)
57+
utl.upToDateCheck(31)
5858
except ImportError:
5959
result = mc.confirmDialog( title='Module Not Found',
6060
message='This tool requires the ml_utilities module. Once downloaded you will need to restart Maya.',
@@ -80,6 +80,9 @@ def ui():
8080

8181

8282
def _getStartAndEnd():
83+
'''
84+
Only return start and end if frame range is highlighted. Otherwise use all available animation.
85+
'''
8386

8487
gPlayBackSlider = mm.eval('$temp=$gPlayBackSlider')
8588
if mc.timeControl(gPlayBackSlider, query=True, rangeVisible=True):
@@ -88,16 +91,15 @@ def _getStartAndEnd():
8891
return None, None
8992

9093

91-
def copySingle(source=None, destination=None, pasteMethod='replace', offset=0, addToLayer=False):
94+
def copySingle(source=None, destination=None, pasteMethod='replace', offset=0, addToLayer=False, rotateOrder=True):
9295
'''
9396
Copy animation from a source node and paste it to a destination node
9497
'''
9598

9699
start, end = _getStartAndEnd()
97-
100+
98101
if not source and not destination:
99102
sel = mc.ls(sl=True)
100-
101103
if len(sel) != 2:
102104
OpenMaya.MGlobal.displayWarning('Please select exactly 2 objects.')
103105
return
@@ -108,14 +110,14 @@ def copySingle(source=None, destination=None, pasteMethod='replace', offset=0, a
108110
layer = None
109111
if addToLayer:
110112
layer = utl.createAnimLayer(destination, namePrefix='ml_cp')
111-
112-
copyAnimation(source=source, destination=destination, pasteMethod=pasteMethod, offset=offset, start=start, end=end, layer=layer)
113113

114-
# if sel:
115-
# mc.select(sel)
114+
copyAnimation(source=source, destination=destination, pasteMethod=pasteMethod, offset=offset, start=start, end=end, layer=layer, rotateOrder=rotateOrder)
115+
116+
#if sel:
117+
#mc.select(sel)
116118

117119

118-
def copyHierarchy(sourceTop=None, destinationTop=None, pasteMethod='replace', offset=0, addToLayer=False, layerName=None):
120+
def copyHierarchy(sourceTop=None, destinationTop=None, pasteMethod='replace', offset=0, addToLayer=False, layerName=None, rotateOrder=True):
119121
'''
120122
Copy animation from a source hierarchy and paste it to a destination hierarchy.
121123
'''
@@ -127,16 +129,14 @@ def copyHierarchy(sourceTop=None, destinationTop=None, pasteMethod='replace', of
127129
if len(sel) != 2:
128130
OpenMaya.MGlobal.displayWarning('Please select exactly 2 objects.')
129131
return
130-
132+
131133
sourceTop = sel[0]
132134
destinationTop = sel[1]
133135

134136
#get keyed objects below source
135-
nodes = mc.listRelatives(sourceTop, pa=True, ad=True)
136-
if not nodes:
137-
nodes = list()
137+
nodes = mc.listRelatives(sourceTop, pa=True, ad=True) or []
138138
nodes.append(sourceTop)
139-
keyed = list()
139+
keyed = []
140140

141141
for node in nodes:
142142
# this will only return time based keyframes, not driven keys
@@ -147,42 +147,45 @@ def copyHierarchy(sourceTop=None, destinationTop=None, pasteMethod='replace', of
147147
return
148148

149149
#get a list of all nodes under the destination
150-
destNodes = mc.listRelatives(destinationTop, ad=True)
151-
if not destNodes:
152-
destNodes = list()
153-
destNodes.append(destinationTop)
150+
allDestNodes = mc.listRelatives(destinationTop, ad=True, pa=True) or []
151+
allDestNodes.append(destinationTop)
152+
153+
destNodeMap = {}
154+
duplicate = []
155+
for each in allDestNodes:
156+
name = each.rsplit('|')[-1].rsplit(':')[-1]
157+
if name in duplicate:
158+
continue
159+
if name in destNodeMap.keys():
160+
duplicate.append(name)
161+
continue
162+
destNodeMap[name] = each
154163

155-
destNS = utl.getNamespace(destinationTop)
156-
destNames = [x.rpartition(':')[-1] for x in destNodes]
164+
destNS = utl.getNamespace(destinationTop)
157165

158166
layer = None
159167
if addToLayer:
160168
if not layerName:
161169
layerName = 'copyHierarchy'
162170
layer = utl.createAnimLayer(name=layerName)
163-
171+
164172
for node in keyed:
165-
nodeName = mc.ls(node, shortNames=True)[0]
166-
167-
#strip namespace
168-
if ':' in nodeName:
169-
nodeName = nodeName.rpartition(':')[-1]
173+
#strip name
174+
nodeName = node.rsplit('|')[-1].rsplit(':')[-1]
170175

171-
if nodeName in destNames:
172-
destNode = mc.ls(destNS+nodeName)
173-
if not destNode:
174-
print 'Cannot find destination node: '+destNS+':'+nodeName
175-
continue
176-
if len(destNode) > 1:
177-
print 'Two or more destination nodes have the same name: '+destNS+':'+nodeName
178-
continue
176+
if nodeName in duplicate:
177+
print 'Two or more destination nodes have the same name: '+destNS+nodeName
178+
continue
179+
if nodeName not in destNodeMap.keys():
180+
print 'Cannot find destination node: '+destNS+nodeName
181+
continue
179182

180-
copyAnimation(source=node, destination=destNode[0], pasteMethod=pasteMethod, offset=offset, start=start, end=end, layer=layer)
183+
copyAnimation(source=node, destination=destNodeMap[nodeName], pasteMethod=pasteMethod, offset=offset, start=start, end=end, layer=layer, rotateOrder=rotateOrder)
181184

182185
# if sel:
183186
# mc.select(sel)
184187

185-
def copyAnimation(source=None, destination=None, pasteMethod='replace', offset=0, start=None, end=None, layer=None):
188+
def copyAnimation(source=None, destination=None, pasteMethod='replace', offset=0, start=None, end=None, layer=None, rotateOrder=True):
186189
'''
187190
Actually do the copy and paste from one node to another. If start and end frame is specified,
188191
set a temporary key before copying, and delete it afterward.
@@ -196,6 +199,12 @@ def copyAnimation(source=None, destination=None, pasteMethod='replace', offset=0
196199
utl.minimizeRotationCurves(source)
197200
utl.minimizeRotationCurves(destination)
198201

202+
if rotateOrder:
203+
try:
204+
if mc.getAttr(destination+'.rotateOrder', keyable=True):
205+
mc.setAttr(destination+'.rotateOrder', mc.getAttr(source+'.rotateOrder'))
206+
except:pass
207+
199208
if pasteMethod=='replaceCompletely' or not start or not end:
200209
mc.copyKey(source)
201210
if layer:
@@ -209,8 +218,8 @@ def copyAnimation(source=None, destination=None, pasteMethod='replace', offset=0
209218
return
210219

211220
#story cut keytimes as 2 separate lists means we only have to run 2 cutkey commands, rather than looping through each
212-
cutStart = list()
213-
cutEnd = list()
221+
cutStart = []
222+
cutEnd = []
214223
for curve in animCurves:
215224

216225
#does it have keyframes on the start and end frames?
@@ -225,7 +234,7 @@ def copyAnimation(source=None, destination=None, pasteMethod='replace', offset=0
225234
if not endKey:
226235
mc.setKeyframe(curve, time=(end,), insert=True)
227236
cutEnd.append(curve)
228-
237+
229238
mc.copyKey(source, time=(start,end))
230239
if layer:
231240
for each in mc.ls(type='animLayer'):
@@ -253,3 +262,5 @@ def copyAnimation(source=None, destination=None, pasteMethod='replace', offset=0
253262
# Revision 3: 2012-11-28 : remove debug print
254263
#
255264
# Revision 4: 2014-03-01 : Adding category and fixing bad argument name.
265+
#
266+
# Revision 5: 2017-07-19 : support for non-namespaced hierarchies, transferring rotateOrder

0 commit comments

Comments
 (0)