rockingTransformCheck.cpp
#include <maya/MPxTransform.h>
#include <maya/MPxTransformationMatrix.h>
#include <maya/MGlobal.h>
#include <maya/MFnNumericAttribute.h>
#include <maya/MTransformationMatrix.h>
#include <maya/MFnDependencyNode.h>
#include <maya/MIOStream.h>
#include "rockingTransformCheck.h"
MTypeId rockingTransformCheckNode::idCheck(kRockingTransformCheckNodeID);
MTypeId rockingTransformCheckMatrix::idCheck(kRockingTransformCheckMatrixID);
rockingTransformCheckMatrix::rockingTransformCheckMatrix()
{
}
void *rockingTransformCheckMatrix::creator()
{
        return new rockingTransformCheckMatrix();
}
rockingTransformCheckNode::rockingTransformCheckNode()
:       ParentClass()
{
}
rockingTransformCheckNode::rockingTransformCheckNode(MPxTransformationMatrix *tm)
:       ParentClass(tm)
{
}
rockingTransformCheckNode::~rockingTransformCheckNode()
{
}
MPxTransformationMatrix *rockingTransformCheckNode::createTransformationMatrix()
{
        return new rockingTransformCheckMatrix();
}
void *rockingTransformCheckNode::creator()
{
        return new rockingTransformCheckNode();
}
const char* rockingTransformCheckNode::className() 
{
        return "rockingTransformCheckNode";
}
MEulerRotation rockingTransformCheckNode::applyRotationLocks(const MEulerRotation &toTest,
                                                                        const MEulerRotation &savedRotation,
                                                                        MStatus *ReturnStatus )
{
#ifdef ALLOW_DG_TO_HANDLE_LOCKS
        
        return toTest;
#else
        
        
        
        
        
        MStatus status;
        MObject object = thisMObject();
        MFnDependencyNode depNode( object );
        MObject rotateLockPlug = depNode.findPlug( "rotateLockPlug", &status );
        
        
        if ( rotateLockPlug.isNull() )
                return toTest;
        
        
        
        return savedRotation;
#endif
}
MEulerRotation rockingTransformCheckNode::applyRotationLimits(const MEulerRotation &unlimitedRotation,
                                                                          MDataBlock & ,
                                                                          MStatus *ReturnStatus )
{
#ifdef CHECK_ROTATION_LIMITS_USING_ATTRIBUTES
        
        
        
        MEulerRotation newRotation = unlimitedRotation;
        MDGContext context = block.context();
        updateMatrixAttrs(minRotLimitEnable, context);
        updateMatrixAttrs(maxRotLimitEnable, context);
        double3 &minLimit = block.inputValue(minRotLimit).asDouble3();
        double3 &maxLimit = block.inputValue(maxRotLimit).asDouble3();
        unsigned ii = 0, jj = 0;
        for (jj = MFnTransform::kRotateMinX, ii = 0; ii < 3; ++ii, ++jj) {
                if (isLimited((MFnTransform::LimitType)jj) && 
                        newRotation[ii] < minLimit[ii]) {
                        newRotation[ii] = minLimit[ii];
                }
                if (isLimited((MFnTransform::LimitType)(++jj)) &&
                        newRotation[ii] > maxLimit[ii]) {
                        newRotation[ii] = maxLimit[ii];
                }
        }
        if ( ReturnStatus )
                *ReturnStatus = MS::kSuccess;
        return newRotation;
#else
        
        
        
        
        DegreeRadianConverter conv;
        double degrees = conv.radiansToDegrees( unlimitedRotation.x );
        if ( degrees < 60 )
                return unlimitedRotation;
        MEulerRotation euler;
        euler.x = conv.degreesToRadians( 60.0 );
        if ( ReturnStatus )
                *ReturnStatus = MS::kSuccess;
        return euler;
#endif
}
MStatus rockingTransformCheckNode::checkAndSetRotation(MDataBlock &block,
                                                                        const MPlug& plug,
                                                                        const MEulerRotation& newRotation, 
                                                                        MSpace::Space space )
{
        const MDGContext context = block.context();
        updateMatrixAttrs(context);
        MStatus status = MS::kSuccess;
        MEulerRotation outRotation = newRotation;
        if (context.isNormal()) {
                
                
                MPxTransformationMatrix *xformMat = baseTransformationMatrix;
                
                
                
                MEulerRotation savedRotation = 
                        xformMat->eulerRotation(MSpace::kTransform, &status);
                ReturnOnError(status);
                
                
                
                
                
                status = baseTransformationMatrix->rotateTo(newRotation, space);
                ReturnOnError(status);
                outRotation = xformMat->eulerRotation(MSpace::kTransform, &status);
                ReturnOnError(status);
                
                
                
                outRotation = applyRotationLimits(outRotation, block, &status);
                ReturnOnError(status);
                outRotation = applyRotationLocks(outRotation, savedRotation, &status);
                ReturnOnError(status);
                
                
                status = xformMat->rotateTo(outRotation, MSpace::kTransform);
                ReturnOnError(status);
                
                
                
                
                
                
                outRotation = xformMat->eulerRotation(MSpace::kTransform, &status);
                ReturnOnError(status);
        } else {
                
                
                
                double3 &s3 = block.inputValue(rotate).asDouble3();
                MEulerRotation savedRotation(s3[0], s3[1], s3[2]);
                
                
                
                MPxTransformationMatrix *local = createTransformationMatrix();
                if (NULL == local) {
                        MGlobal::displayError("rockingTransformCheck::checkAndSetRotation internal error");
                        return status;
                }
                
                
                status = computeLocalTransformation(local, block);
                if ( MS::kSuccess != status)
                {
                        delete local;
                        return status;
                }
                
                
                
                status = local->rotateTo(newRotation, space);
                if ( MS::kSuccess != status)
                {
                        delete local;
                        return status;
                }
                outRotation = local->eulerRotation(MSpace::kTransform, &status);
                if ( MS::kSuccess != status)
                {
                        delete local;
                        return status;
                }
                
                
                outRotation = applyRotationLimits(outRotation, block, &status);
                if ( MS::kSuccess != status)
                {
                        delete local;
                        return status;
                }
                outRotation = applyRotationLocks(outRotation, savedRotation, &status);
                if ( MS::kSuccess != status)
                {
                        delete local;
                        return status;
                }
                status = local->rotateTo(outRotation, MSpace::kTransform);
                if ( MS::kSuccess != status)
                {
                        delete local;
                        return status;
                }
                
                
                
                outRotation = local->eulerRotation(MSpace::kTransform, &status);
                if ( MS::kSuccess != status)
                {
                        delete local;
                        return status;
                }
                delete local;
        }
        MDataHandle handle = block.outputValue(plug, &status);
        if ( MS::kSuccess != status)
        {
                return status;
        }
        if (plug == rotate) {
                handle.set(outRotation.x, outRotation.y, outRotation.z);
        } else if (plug == rotateX) {
                handle.set(outRotation.x);
        } else if (plug == rotateY) {
                handle.set(outRotation.y);
        } else {
                handle.set(outRotation.z);
        }
        return status;
}
                                                                                        
rockingTransformCheckMatrix *rockingTransformCheckNode::getRockingTransformCheckMatrix()
{
        rockingTransformCheckMatrix *ltm = (rockingTransformCheckMatrix *) baseTransformationMatrix;
        return ltm;
}