- Main Page
- Related Pages
- Modules
- Classes
- Examples

# buildRotationNode.cpp

    //-
    // ==========================================================================
    // Copyright 1995,2006,2008 Autodesk, Inc. All rights reserved.
    //
    // Use of this software is subject to the terms of the Autodesk
    // license agreement provided at the time of installation or download,
    // or which otherwise accompanies this software in either electronic
    // or hard copy form.
    // ==========================================================================
    //+

    #include <string.h>
    #include <maya/MIOStream.h>
    #include <math.h>

    #include <maya/MPxNode.h>

    #include <maya/MFnNumericAttribute.h>
    #include <maya/MFnMatrixAttribute.h>
    #include <maya/MFnUnitAttribute.h>
    #include <maya/MFnEnumAttribute.h>
    #include <maya/MFnPlugin.h>

    #include <maya/MString.h>
    #include <maya/MTypeId.h>
    #include <maya/MPlug.h>
    #include <maya/MVector.h>
    #include <maya/MMatrix.h>
    #include <maya/MTransformationMatrix.h>
    #include <maya/MDataBlock.h>
    #include <maya/MDataHandle.h>

    #define EPSILON             0.001
    #define ROTATE_ORDER_XYZ    0
    #define ROTATE_ORDER_YZX    1
    #define ROTATE_ORDER_ZXY    2
    #define ROTATE_ORDER_XZY    3
    #define ROTATE_ORDER_YXZ    4
    #define ROTATE_ORDER_ZYX    5

    #define McheckErr(stat,msg)         \
        if ( MS::kSuccess != stat ) {   \
            cerr << msg;                \
            return MS::kFailure;        \
        }

    class buildRotation : public MPxNode
    {
    public:
                            buildRotation();
        virtual             ~buildRotation();

        virtual MStatus     compute( const MPlug& plug, MDataBlock& data );

        static  void*       creator();
        static  MStatus     initialize();

    public:

        // Inputs
        static  MObject     up;           // Up vector
        static  MObject         upX;
        static  MObject         upY;
        static  MObject         upZ;
        static  MObject     forward;      // Front Vector
        static  MObject         forwardX;
        static  MObject         forwardY;
        static  MObject         forwardZ;
        static  MObject     rotateOrder;  // Desired rotation order

        // Outputs
        static  MObject     rotate;       // Rotation as a 3 Double
        static  MObject         rotateX;
        static  MObject         rotateY;
        static  MObject         rotateZ;
        static  MObject     rotateMatrix; // Rotation as a matrix

        static  MTypeId     id;
    };

    MTypeId     buildRotation::id( 0x80004 );
    MObject     buildRotation::up;
    MObject     buildRotation::upX;
    MObject     buildRotation::upY;
    MObject     buildRotation::upZ;
    MObject     buildRotation::forward;
    MObject     buildRotation::forwardX;
    MObject     buildRotation::forwardY;
    MObject     buildRotation::forwardZ;
    MObject     buildRotation::rotateOrder;
    MObject     buildRotation::rotate;
    MObject     buildRotation::rotateX;
    MObject     buildRotation::rotateY;
    MObject     buildRotation::rotateZ;
    MObject     buildRotation::rotateMatrix;

    buildRotation::buildRotation() {}
    buildRotation::~buildRotation() {}

    MStatus buildRotation::compute( const MPlug& plug, MDataBlock& data )
    {

        MStatus returnStatus;

        if ((plug == rotate) || (plug.parent() == rotate) || (plug == rotateMatrix)) {
            MDataHandle upData = data.inputValue( up, &returnStatus );
            McheckErr(returnStatus,"ERROR getting up vector data");

            MDataHandle forwardData = data.inputValue( forward, &returnStatus );
            McheckErr(returnStatus,"ERROR getting forward vector data");

            MVector up = upData.asVector();
            MVector forward = forwardData.asVector();

            // Make sure that the up and forward vectors are orthogonal
            //
            if ( fabs( up * forward ) > EPSILON ) {
                // Non-zero dot product
                //
                MVector orthoVec = up ^ forward;
                MVector newForward = orthoVec ^ up;
                if ( forward * newForward < 0.0 ) {
                    // Reverse the vector
                    //
                    newForward *= -1.0;
                }
                forward = newForward;
            }

            // Calculate the rotation required to align the y-axis with the up
            // vector
            //
            MTransformationMatrix firstRot;
            MVector rotAxis = MVector::yAxis ^ up;
            rotAxis.normalize();
            firstRot.setToRotationAxis( rotAxis, MVector::yAxis.angle( up ) );

            // Calculate the second rotation required to align the forward vector
            //
            MTransformationMatrix secondRot;
            MVector transformedForward = firstRot.asMatrix() * forward;
            transformedForward.normalize();
            double angle = transformedForward.angle( MVector::zAxis );
            if ( transformedForward.x < 0.0 ) {
                // Compensate for the fact that the angle method returns
                // the absolute value
                //
                angle *= -1.0;
            }
            secondRot.setToRotationAxis( up, angle );

            // Get the requested rotation order
            //
            MDataHandle orderHandle = data.inputValue( rotateOrder );
            short order = orderHandle.asShort();
            MTransformationMatrix::RotationOrder rotOrder;
            switch ( order ) {
                case ROTATE_ORDER_XYZ:
                    rotOrder = MTransformationMatrix::kXYZ; break;
                case ROTATE_ORDER_YZX:
                    rotOrder = MTransformationMatrix::kYZX; break;
                case ROTATE_ORDER_ZXY:
                    rotOrder = MTransformationMatrix::kZXY; break;
                case ROTATE_ORDER_XZY:
                    rotOrder = MTransformationMatrix::kXZY; break;
                case ROTATE_ORDER_YXZ:
                    rotOrder = MTransformationMatrix::kYXZ; break;
                case ROTATE_ORDER_ZYX:
                    rotOrder = MTransformationMatrix::kZYX; break;
                default:
                    rotOrder = MTransformationMatrix::kInvalid; break;
            }

            MTransformationMatrix result = firstRot.asMatrix() * secondRot.asMatrix();
            result.reorderRotation( rotOrder );

            double rotation[3];
            result.getRotation( rotation, rotOrder, MSpace::kTransform );

            MDataHandle outputRot = data.outputValue( rotate );
            outputRot.set( rotation[0], rotation[1], rotation[2] );
            outputRot.setClean();

            MDataHandle outputMatrix = data.outputValue( rotateMatrix );
            outputMatrix.set( result.asMatrix() );
            outputMatrix.setClean();
        } else
            return MS::kUnknownParameter;

        return MS::kSuccess;
    }

    void* buildRotation::creator()
    {
        return new buildRotation();
    }

    MStatus buildRotation::initialize()
    {
        MFnNumericAttribute nAttr;
        MFnMatrixAttribute  mAttr;
        MFnUnitAttribute    uAttr;
        MFnEnumAttribute    eAttr;
        MStatus             stat;

        // Set up inputs
        //
        upX = nAttr.create( "upX", "ux", MFnNumericData::kDouble );
            nAttr.setStorable(false);
        upY = nAttr.create( "upY", "uy", MFnNumericData::kDouble );
            nAttr.setStorable(false);
        upZ = nAttr.create( "upZ", "uz", MFnNumericData::kDouble );
            nAttr.setStorable(false);
        up = nAttr.create( "up", "u", upX, upY, upZ );
            nAttr.setDefault( 0.0, 1.0, 0.0 );
            nAttr.setStorable(false);

        forwardX = nAttr.create( "forwardX", "fx", MFnNumericData::kDouble, 0.0 );
            nAttr.setStorable(false);
        forwardY = nAttr.create( "forwardY", "fy", MFnNumericData::kDouble, 0.0 );
            nAttr.setStorable(false);
        forwardZ = nAttr.create( "forwardZ", "fz", MFnNumericData::kDouble, 1.0 );
            nAttr.setStorable(false);
        forward = nAttr.create( "forward", "f", forwardX, forwardY, forwardZ );
            nAttr.setDefault( 0.0, 0.0, 1.0 );
            nAttr.setStorable(false);

        rotateOrder = eAttr.create( "rotateOrder", "ro", ROTATE_ORDER_XYZ);
            eAttr.addField("xyz", ROTATE_ORDER_XYZ);
            eAttr.addField("yzx", ROTATE_ORDER_YZX);
            eAttr.addField("zxy", ROTATE_ORDER_ZXY);
            eAttr.addField("xzy", ROTATE_ORDER_XZY);
            eAttr.addField("yxz", ROTATE_ORDER_YXZ);
            eAttr.addField("zyx", ROTATE_ORDER_ZYX);
            eAttr.setStorable(false);

        // Set up outputs
        //
        rotateX = uAttr.create( "rotateX", "rx", MFnUnitAttribute::kAngle, 0.0 );
            nAttr.setStorable(false);
        rotateY = uAttr.create( "rotateY", "ry", MFnUnitAttribute::kAngle, 0.0 );
            nAttr.setStorable(false);
        rotateZ = uAttr.create( "rotateZ", "rz", MFnUnitAttribute::kAngle, 0.0 );
            nAttr.setStorable(false);
        rotate = nAttr.create( "rotate", "r", rotateX, rotateY, rotateZ );
            nAttr.setStorable(false);

        rotateMatrix = mAttr.create( "rotateMatrix", "rm" );
            nAttr.setStorable(false);
            nAttr.setConnectable(true);

        stat = addAttribute( up );
            if (!stat) { stat.perror("addAttribute"); return stat;}
        stat = addAttribute( forward );
            if (!stat) { stat.perror("addAttribute"); return stat;}
        stat = addAttribute( rotate );
            if (!stat) { stat.perror("addAttribute"); return stat;}
        stat = addAttribute( rotateOrder );
            if (!stat) { stat.perror("addAttribute"); return stat;}
        stat = addAttribute( rotateMatrix );
            if (!stat) { stat.perror("addAttribute"); return stat;}

        stat = attributeAffects( up, rotate );
            if (!stat) { stat.perror("attributeAffects"); return stat;}
        stat = attributeAffects( up, rotateMatrix );
            if (!stat) { stat.perror("attributeAffects"); return stat;}
        stat = attributeAffects( forward, rotate );
            if (!stat) { stat.perror("attributeAffects"); return stat;}
        stat = attributeAffects( forward, rotateMatrix );
            if (!stat) { stat.perror("attributeAffects"); return stat;}
        stat = attributeAffects( rotateOrder, rotate );
            if (!stat) { stat.perror("attributeAffects"); return stat;}
        stat = attributeAffects( rotateOrder, rotateMatrix );
            if (!stat) { stat.perror("attributeAffects"); return stat;}

        return MS::kSuccess;
    }

    MStatus initializePlugin( MObject obj )
    {
        MStatus   status;
        MFnPlugin plugin( obj, PLUGIN_COMPANY, "3.0", "Any");

        status = plugin.registerNode( "buildRotation", buildRotation::id,
                             buildRotation::creator, buildRotation::initialize );
        if (!status) {
            status.perror("registerNode");
            return status;
        }

        return status;
    }

    MStatus uninitializePlugin( MObject obj)
    {
        MStatus   status;
        MFnPlugin plugin( obj );

        status = plugin.deregisterNode( buildRotation::id );
        if (!status) {
            status.perror("deregisterNode");
            return status;
        }

        return status;
    }