#import a class, TransformEditController
# setTemplate on/off
# setVisible on/off
"""example
!!!the dynPar nodes will be deleted from maya scene
make sure before using this tool you have no nodes by these names
!!if you dont see anything happening
!you might have to call stop
!!if youre getting nowhere
!make sure the thing you want to move is in a group
import Transform
import PositionCalculator
import HierarchyCalculator
import ConnectionCalculator
import AttributeCalculator
import ShapeConstraint
import BasicConstraint
import ConstraintCopier
import DisplayEditor
import SceneCheck
import Main
reload(Transform)
reload(PositionCalculator)
reload(HierarchyCalculator)
reload(ConnectionCalculator)
reload(AttributeCalculator)
reload(ShapeConstraint)
reload(BasicConstraint)
reload(ConstraintCopier)
reload(DisplayEditor)
reload(SceneCheck)
reload(Main)
dynPar = Main.Main('parent' , 'child', 'childGrp')
dynPar.start()
dynPar.stop()
"""
import Transform as trf
import PositionCalculator as pc
import HierarchyCalculator as hc
import ShapeConstraint as cnt
import BasicConstraint as bnt
import ConstraintCopier as cpy
import DisplayEditor as dpy
import SceneCheck as sc
import maya.cmds as mc
class Main:
def __init__(self,parentName ='_parent',childName = '_child', childParentName = '_childParent'):
"""
needs arguments
makes assumptions about input
0. assumes input has no connections or constraints preventing them to move
1. assumes input is on stage
2. assumes group child control parent has one child the child control animator wants auto moved
3. assumes the dummy name variables were never made by the animator for his/her scene
makes assumption about type of connection animator wants
1. assumes parent constraint is the way a child is auto moved
Why?
- does not make any cleaning up of backend nodes
- does not make sure animator controls are at right place after cleanup
- does not check if user input is on maya scene
- does not check if user created objects of same name as
"""
#user vars DO NOT TOUCH
self._userParentCtrlName = parentName
self._userChildCtrl = childName
self._userChildCtrlGrpParentName = childParentName
name = parentName+'_'+childName+'_'+childParentName
#duumy var
#start var
self.sceneGrpName = 'naDynPar_do_not_touch_'+name
self.sceneParentName = 'naDynPar_parent_'+name
self.sceneChildName = 'naDynPar_child_'+name
self.sceneParentWorldName = 'naDynPar_world_'+name
#stop var
self.whereIsParentLoc = 'naDynPar_whereIsParent_'+name
self.whereIsChildLoc = 'naDynPar_whereIsChild_'+name
#stop and stop var
self.worldUserOption = 'world'
self.isStartReady = True #call start,stop,start,stop order good, start,start bad, or stop,stop bad
#Move to UserInterfaceChecker
#--assertIsParentChildAndGroupOnStage
#--assertGroupOfChildCorrect
#--assertOnInitializationPrivateVariablesNotOnStage
#printMessageStartError
#printMessageStopError
#could add get and set methods for user input ?? may be beter in UserInterface class
def start(self):
"""
"""
#get current selection
sceneChecker = sc.SceneCheck()
currentSelection = sceneChecker.getCurrentSelection()
if self.isStartReady == True:
self.__startBackend()
#dont call start again until it has been stopped first
self.isStartReady = False
#restore current selection
sceneChecker.restoreSelectionOrClear(currentSelection)
def stop(self):
"""
"""
#get current selection
sceneChecker = sc.SceneCheck()
currentSelection = sceneChecker.getCurrentSelection()
if self.isStartReady == False:
self.__stopBackend()
self.isStartReady = True
#restore current selection
sceneChecker.restoreSelectionOrClear(currentSelection)
def parentSceneFolderToThisNull(self,_null):
"""
This is not used by this tool only by others that want to help with cleaning
This generally should not be called by the user
assumes null exists on stage
assumes it can move the pivot of this null
"""
#to prevent skipping while parenting
#match input nulls pivot to sceneGrp's pivot, that is where we will be parenting to
#parent sceneGrp to null, no movement cause pivots are the same !!!
sceneChecker = sc.SceneCheck()
_isAllOnStage = False
_isAllOnStage = sceneChecker.isAllOnStage( [self.sceneGrpName, _null])
#do nothing unless everything is on scene
if _isAllOnStage == True:
sceneGrpName = self.sceneGrpName
userNull = _null
#snap the user null pivot to dummyGroup holder
snapCalculator = pc.PositionCalculator()
snapCalculator.matchPivot( sceneGrpName, userNull )
#put all dummy node into trashHolder
parentCalculator = hc.HierarchyCalculator()
parentCalculator.parent( sceneGrpName, userNull )
else:
print 'did not parent to scene folder'
#private
def __startBackend(self):
"""
This creates backend nulls, setups up connecting them, all to achieve a dynamic parenting
sort of thing.
"""
_userParentCtrlName = self._userParentCtrlName
_userChildCtrl = self._userChildCtrl
_userChildCtrlGrpParentName = self._userChildCtrlGrpParentName
#make four dummy nodes
#on every press of start tool resets so
#--create a group to hold 2 trash back end nodes
#--make an extra dummy node for the case _parentCtrlName is self.worldUserOption
trashHolder = trf.TransformGroup(self.sceneGrpName)
parentLoc = trf.TransformLocator(self.sceneParentName)
childLoc = trf.TransformLocator(self.sceneChildName)
worldLoc = trf.TransformLocator(self.sceneParentWorldName)
#make tool created nulls harder to select by user
self.__templateDynParStartDummyNode()
self.__visibilityOffDynParStartDummyNode()
#put all dummy node into trashHolder
parentCalculator = hc.HierarchyCalculator()
parentCalculator.parent( self.sceneParentName, self.sceneGrpName )
parentCalculator.parent( self.sceneChildName, self.sceneGrpName )
parentCalculator.parent( self.sceneParentWorldName, self.sceneGrpName )
#SNAPPING
#snap the user child arg group pivot to user child arg control
#snap the child dummy to the users child argument
snapCalculator = pc.PositionCalculator()
snapCalculator.matchPivot( _userChildCtrl, _userChildCtrlGrpParentName )
snapCalculator.matchPositionAndOrientation( _userChildCtrlGrpParentName, self.sceneChildName )
#snapping the two dummy nodes to the maya scene objects
###parent snapping
if _userParentCtrlName == self.worldUserOption:
snapCalculator.matchPositionAndOrientation( self.sceneParentWorldName, self.sceneParentName )
else:
#snap the parent dummy to the user parent arg
snapCalculator.matchPositionAndOrientation( _userParentCtrlName, self.sceneParentName )
#CREATING CONSTRAINT
###make parent dummy drive child dummy by constraint
#make type parent
#draw
cntDummyName = 'dynpar_constraint'
constraintMaker = cnt.ShapeConstraint(cntDummyName)
parentCntType = bnt.ParentBasicConstraint()
maintainOffset = True
constraintMaker.draw( self.sceneParentName,self.sceneChildName,parentCntType, maintainOffset = True)
#make a copier
#copy
constraintCopier = cpy.ConstraintCopier()
if _userParentCtrlName != self.worldUserOption:
#parent constraint between child dummy and parent dummy to user parent and user child
constraintCopier.copy([self.sceneParentName,self.sceneChildName] , [_userParentCtrlName, _userChildCtrlGrpParentName])
else:
#parent constraint between child dummy and parent dummy to world dummy and user child
constraintCopier.copy([self.sceneParentName,self.sceneChildName] , [self.sceneParentWorldName, _userChildCtrlGrpParentName])
def __stopBackend(self):
"""
stop should not be exposed unless
--start has been called
makes assumptions on animator input
--assumes given start( a, b ) that stop is stop( a, b ) same arguments in both calls
makes assumptions on animator removing tool created objects
--assumes all backend things created by tool are not touched, deleted renamed moved etc by user
"""
_userParentCtrlName = self._userParentCtrlName
_userChildCtrl = self._userChildCtrl
_userChildCtrlGrpParentName = self._userChildCtrlGrpParentName
#tool for remember where animator controls are now
whereIsParentLoc = trf.TransformLocator(self.whereIsParentLoc)
whereIsChildLoc = trf.TransformLocator(self.whereIsChildLoc)
#tool for snapping dummys to user args
snapCalculator = pc.PositionCalculator()
#when world is not the parent
#snap the dummy parent to the user parent arg
#snap the dummy child to the user child arg
if _userParentCtrlName != self.worldUserOption:
snapCalculator.matchPositionAndOrientation(_userParentCtrlName, self.whereIsParentLoc)
snapCalculator.matchPositionAndOrientation(_userChildCtrlGrpParentName, self.whereIsChildLoc)
#assumes delete removes
## backend to backend constraints
## backend to user constraints
## backend group
## backend locators
self.__deleteDynParStartDummyNode()
if _userParentCtrlName != self.worldUserOption:
#snap the user parent to the dummy parent
snapCalculator.matchPositionAndOrientation( self.whereIsParentLoc, _userParentCtrlName )
#snap the user child arg to the dummy child
snapCalculator.matchPositionAndOrientation( self.whereIsChildLoc, _userChildCtrlGrpParentName )
#delete temp dummy nodes
self.__deleteDynParStopDummyNode()
#match child parent pivot to child pivot
snapCalculator.matchPivot(_userChildCtrl,_userChildCtrlGrpParentName)
def __deleteDynParStartDummyNode(self):
delList = [ self.sceneParentWorldName, self.sceneChildName, self.sceneParentName, self.sceneGrpName ]
self.__deleteIfExists(delList)
#mc.delete(delList)
def __deleteDynParStopDummyNode(self):
delList = [ self.whereIsParentLoc, self.whereIsChildLoc ]
self.__deleteIfExists(delList)
#mc.delete(delList)
def __deleteIfExists(self,_list):
"""
add existence checks before deleting
in case user has deleted scene objects
or something else messed up here
"""
dummyObjects = _list
sceneChecker = sc.SceneCheck()
for element in dummyObjects:
isOnStage = sceneChecker.isAllOnStage( [element] )
if isOnStage == True:
mc.delete(element)
else:
print 'Thought: %s :should be on scene' %element
def __templateDynParStartDummyNode(self):
templateList = [self.sceneParentWorldName, self.sceneChildName, self.sceneParentName, self.sceneGrpName ]
displayEditor = dpy.DisplayEditor(templateList)
displayEditor.setTemplateOn()
def __visibilityOffDynParStartDummyNode(self):
visibilityOffList = [self.sceneParentWorldName, self.sceneChildName, self.sceneParentName, self.sceneGrpName ]
displayEditor = dpy.DisplayEditor(visibilityOffList)
displayEditor.setVisibilityOff()