motionTraceCmd.py

#-
# ==========================================================================
# Copyright (C) 1995 - 2006 Autodesk, Inc. and/or its licensors.  All 
# rights reserved.
#
# The coded instructions, statements, computer programs, and/or related 
# material (collectively the "Data") in these files contain unpublished 
# information proprietary to Autodesk, Inc. ("Autodesk") and/or its 
# licensors, which is protected by U.S. and Canadian federal copyright 
# law and by international treaties.
#
# The Data is provided for use exclusively by You. You have the right 
# to use, modify, and incorporate this Data into other products for 
# purposes authorized by the Autodesk software license agreement, 
# without fee.
#
# The copyright notices in the Software and this entire statement, 
# including the above license grant, this restriction and the 
# following disclaimer, must be included in all copies of the 
# Software, in whole or in part, and all derivative works of 
# the Software, unless such copies or derivative works are solely 
# in the form of machine-executable object code generated by a 
# source language processor.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. 
# AUTODESK DOES NOT MAKE AND HEREBY DISCLAIMS ANY EXPRESS OR IMPLIED 
# WARRANTIES INCLUDING, BUT NOT LIMITED TO, THE WARRANTIES OF 
# NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR 
# PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE, OR 
# TRADE PRACTICE. IN NO EVENT WILL AUTODESK AND/OR ITS LICENSORS 
# BE LIABLE FOR ANY LOST REVENUES, DATA, OR PROFITS, OR SPECIAL, 
# DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES, EVEN IF AUTODESK 
# AND/OR ITS LICENSORS HAS BEEN ADVISED OF THE POSSIBILITY 
# OR PROBABILITY OF SUCH DAMAGES.
#
# ==========================================================================
#+

#
#   Creation Date:   27 September 2006
#
#   Description:
#
#       Traces the position of an animated object
#       and create a curve showing the object's path.
#
#   Usage:
#
#       Animate an object.
#       Select the object.
#       Run the command in the command window.
#       See the object's path drawn as a curve.
#
#   Options:
#
#       s=<frame>       The start frame.  Default to 1.
#       e=<frame>       The end frame.  Default to 60.
#       b=<frame>       The by frame.  Default to 1.
#
#   Example:
#
#       From Python:
#           import maya
#           maya.cmds.spMotionTrace(s=1, e=100, b=2)
#
#       From Mel:
#           spMotionTrace -s 1 -e 100 -b 2
#

import maya.OpenMaya as OpenMaya
import maya.OpenMayaMPx as OpenMayaMPx
import math, sys

kPluginCmdName="spMotionTrace"

kStartFlag = "-s"
kStartLongFlag = "-startFrame"
kEndFlag = "-e"
kEndLongFlag = "-endFrame"
kByFlag = "-b"
kByLongFlag = "-byFrame"

# command
class motionTrace(OpenMayaMPx.MPxCommand):
    def __init__(self):
        OpenMayaMPx.MPxCommand.__init__(self)
        # setup private data members
        self.__start = 1
        self.__end = 60
        self.__by = 1


    def doIt(self, args):
        """
        This method is called from script when this command is called.
        It should set up any class data necessary for redo/undo,
        parse any given arguments, and then call redoIt.
        """
        argData = OpenMaya.MArgDatabase(self.syntax(), args)

        if argData.isFlagSet(kStartFlag):
            self.__start = argData.flagArgumentInt(kStartFlag, 0)
        if argData.isFlagSet(kEndFlag):
            self.__end = argData.flagArgumentInt(kEndFlag, 0)
        if argData.isFlagSet(kByFlag):
            self.__by = argData.flagArgumentInt(kByFlag, 0)

        self.redoIt()


    def redoIt(self):
        """
        This method performs the action of the command.
        This method iterates over all selected items and
        prints out connected plug and dependency node type
        information.
        """
        picked = OpenMaya.MObjectArray()
        dependNode = OpenMaya.MObject()     # Selected dependency node

        # Create a selection list iterator
        slist = OpenMaya.MSelectionList()
        OpenMaya.MGlobal.getActiveSelectionList(slist)
        iter = OpenMaya.MItSelectionList(slist)

        # Iterate over all selected dependency nodes
        # and save them in a list
        while not iter.isDone():
            # Get the selected dependency node
            iter.getDependNode(dependNode)
            picked.append(dependNode)
            iter.next()

        # sample the animation using start, end, by values
        pointArrays = [ OpenMaya.MPointArray() for i in range(picked.length()) ]

        time = self.__start
        while (time <= self.__end):
            timeval = OpenMaya.MTime(time)
            OpenMaya.MGlobal.viewFrame(timeval)

            # Iterate over selected dependency nodes
            for i in range(picked.length()):
                # Get the selected dependency node
                dependNode = picked[i]

                # Create a function set for the dependency node
                fnDependNode = OpenMaya.MFnDependencyNode(dependNode)

                # Get the translation attribute values
                txAttr = fnDependNode.attribute("translateX")
                txPlug = OpenMaya.MPlug(dependNode, txAttr)
                tx = txPlug.asDouble()

                tyAttr = fnDependNode.attribute("translateY")
                tyPlug = OpenMaya.MPlug(dependNode, tyAttr)
                ty = tyPlug.asDouble()

                tzAttr = fnDependNode.attribute("translateZ")
                tzPlug = OpenMaya.MPlug(dependNode, tzAttr)
                tz = tzPlug.asDouble()

                print "adding", tx, ty, tz, "\n"
                pointArrays[i].append(OpenMaya.MPoint(tx, ty, tz))

            time += self.__by

        # make a path curve for each selected object
        for i in range(picked.length()):
            self.__jMakeCurve(pointArrays[i])


    def __jMakeCurve(self, cvs):
        """
        Make a degree 1 curve from the given CVs.
        
        Note that in Python, a double underscore in front of a member name
        make the method "private" to the class through name-mangling
        """
        deg = 1
        knots = OpenMaya.MDoubleArray()

        for i in range(cvs.length()):
            knots.append(i)

        # Now create the curve
        nullObj = OpenMaya.MObject()
        curveFn = OpenMaya.MFnNurbsCurve()
        curveFn.create(cvs, knots, deg, OpenMaya.MFnNurbsCurve.kOpen, False, False, nullObj)


# Creator
def cmdCreator():
    return OpenMayaMPx.asMPxPtr(motionTrace())


# Syntax creator
def syntaxCreator():
    syntax = OpenMaya.MSyntax()
    syntax.addFlag(kStartFlag, kStartLongFlag, OpenMaya.MSyntax.kLong)
    syntax.addFlag(kEndFlag, kEndLongFlag, OpenMaya.MSyntax.kLong)
    syntax.addFlag(kByFlag, kByLongFlag, OpenMaya.MSyntax.kLong)
    return syntax


# Initialize the script plug-in
def initializePlugin(mobject):
    mplugin = OpenMayaMPx.MFnPlugin(mobject, "Autodesk", "1.0", "Any")
    try:
        mplugin.registerCommand(kPluginCmdName, cmdCreator, syntaxCreator)
    except:
        sys.stderr.write("Failed to register command: %s\n" % kPluginCmdName)
        raise


# Uninitialize the script plug-in
def uninitializePlugin(mobject):
    mplugin = OpenMayaMPx.MFnPlugin(mobject)
    try:
        mplugin.deregisterCommand(kPluginCmdName)
    except:
        sys.stderr.write("Failed to unregister command: %s\n" % kPluginCmdName)
        raise