Exemple #1
0
    def compute(self, plug, dataBlock):
        """
        Node computation method:
            * plug is a connection point related to one of our node attributes (either an input or an output).
            * dataBlock contains the data on which we will base our computations.
        """
        # pylint: disable=no-self-use
        if (plug != EulerScalarMath.outEuler
                and plug != EulerScalarMath.outEulerX
                and plug != EulerScalarMath.outEulerY
                and plug != EulerScalarMath.outEulerZ):
            return om2.kUnknownParameter

        operation = dataBlock.inputValue(EulerScalarMath.inOperation).asShort()
        euler = dataBlock.inputValue(EulerScalarMath.inEuler).asDouble3()
        scalar = dataBlock.inputValue(EulerScalarMath.inScalar).asDouble()
        eulerRotOder = dataBlock.inputValue(
            EulerScalarMath.inEulerRotOrder).asShort()
        outRotOrder = dataBlock.inputValue(
            EulerScalarMath.inResRotOrder).asShort()

        eEuler = om2.MEulerRotation(euler, eulerRotOder)

        outEulerHandle = dataBlock.outputValue(EulerScalarMath.outEuler)

        if operation == 0:
            eEuler.reorderIt(outRotOrder)
            outEulerHandle.set3Double(eEuler.x, eEuler.y, eEuler.z)
        elif operation == 1:
            eEuler.reorderIt(outRotOrder)
            eScalar = om2.MEulerRotation(
                om2.MAngle(scalar, om2.MAngle.kDegrees).asRadians(),
                om2.MAngle(scalar, om2.MAngle.kDegrees).asRadians(),
                om2.MAngle(scalar, om2.MAngle.kDegrees).asRadians(),
                outRotOrder)
            eOutEuler = eEuler + eScalar
            outEulerHandle.set3Double(eOutEuler.x, eOutEuler.y, eOutEuler.z)
        elif operation == 2:
            eEuler.reorderIt(outRotOrder)
            eScalar = om2.MEulerRotation(
                om2.MAngle(scalar, om2.MAngle.kDegrees).asRadians(),
                om2.MAngle(scalar, om2.MAngle.kDegrees).asRadians(),
                om2.MAngle(scalar, om2.MAngle.kDegrees).asRadians(),
                outRotOrder)
            eOutEuler = eEuler - eScalar
            outEulerHandle.set3Double(eOutEuler.x, eOutEuler.y, eOutEuler.z)
        elif operation == 3:
            eEuler.reorderIt(outRotOrder)
            eOutEuler = eEuler * scalar
            outEulerHandle.set3Double(eOutEuler.x, eOutEuler.y, eOutEuler.z)

        outEulerHandle.setClean()
Exemple #2
0
    def compute(self, plug, dataBlock):
        """
        Node computation method:
            * plug is a connection point related to one of our node attributes (either an input or an output).
            * dataBlock contains the data on which we will base our computations.
        """
        # pylint: disable=no-self-use
        if (plug != EulerMath.outEuler and plug != EulerMath.outEulerX
                and plug != EulerMath.outEulerY
                and plug != EulerMath.outEulerZ):
            return om2.kUnknownParameter

        operation = dataBlock.inputValue(EulerMath.inOperation).asShort()
        euler1 = dataBlock.inputValue(EulerMath.inEuler1).asDouble3()
        euler2 = dataBlock.inputValue(EulerMath.inEuler2).asDouble3()
        euler1RotOrder = dataBlock.inputValue(
            EulerMath.inEuler1RotOrder).asShort()
        euler2RotOrder = dataBlock.inputValue(
            EulerMath.inEuler2RotOrder).asShort()
        outRotOrder = dataBlock.inputValue(EulerMath.inResRotOrder).asShort()

        eEuler1 = om2.MEulerRotation(euler1, euler1RotOrder)
        eEuler2 = om2.MEulerRotation(euler2, euler2RotOrder)

        outEulerHdle = dataBlock.outputValue(EulerMath.outEuler)

        if operation == 0:
            eEuler1.reorderIt(outRotOrder)
            outEulerHdle.set3Double(eEuler1.x, eEuler1.y, eEuler1.z)
        elif operation == 1:
            eEuler1.reorderIt(outRotOrder)
            eEuler2.reorderIt(outRotOrder)
            eOutEuler = eEuler1 + eEuler2
            outEulerHdle.set3Double(eOutEuler.x, eOutEuler.y, eOutEuler.z)
        elif operation == 2:
            eEuler1.reorderIt(outRotOrder)
            eEuler2.reorderIt(outRotOrder)
            eOutEuler = eEuler1 - eEuler2
            outEulerHdle.set3Double(eOutEuler.x, eOutEuler.y, eOutEuler.z)
        elif operation == 3:
            eEuler1.reorderIt(outRotOrder)
            eEuler2.reorderIt(outRotOrder)
            eOutEuler = eEuler1 * eEuler2
            outEulerHdle.set3Double(eOutEuler.x, eOutEuler.y, eOutEuler.z)

        outEulerHdle.setClean()
Exemple #3
0
    def compute(self, plug, dataBlock):
        """
        Node computation method:
            * plug is a connection point related to one of our node attributes (either an input or an output).
            * dataBlock contains the data on which we will base our computations.
        """
        # pylint: disable=no-self-use
        vector = dataBlock.inputValue(VectorToEuler.inVector).asFloat3()
        vVector = om2.MVector([unit * (math.pi / 180.0) for unit in vector])

        eEuler = om2.MEulerRotation(vVector)

        outEulerHandle = dataBlock.outputValue(VectorToEuler.outEuler)
        outEulerHandle.set3Double(eEuler.x, eEuler.y, eEuler.z)
        outEulerHandle.setClean()
Exemple #4
0
def getMRotFromNodeOutput(node_mob, rotOrder=om2.MEulerRotation.kXYZ):
    """
    finds the angular output of the argument node and returns it
     as a Euler rotation where that angle is the X element
    :param node_mob: [MObject] the node to get the output port from
    :param rotOrder: [int] the factory constant for the desired rotation order
                            the returned Euler rotation should be set to
    :return: [MEulerRotation] the Euler rotation composition where the
                                angular output on the argument node is the X value
    """
    mfn_dep = om2.MFnDependencyNode(node_mob)
    angle = om2.MAngle(0.0)
    if node_mob.hasFn(om2.MFn.kAnimBlend) and mfn_dep.hasAttribute(
            _MAYA_OUTPUT_ATTRIBUTE_NAME):
        plug = mfn_dep.findPlug(_MAYA_OUTPUT_ATTRIBUTE_NAME, False)
        angle = plug.asMAngle()

    rot = om2.MEulerRotation(angle.asRadians(), 0.0, 0.0, rotOrder)
    return rot
Exemple #5
0
    def compute(self, plug, dataBlock):
        """
        Node computation method:
            * plug is a connection point related to one of our node attributes (either an input or an output).
            * dataBlock contains the data on which we will base our computations.
        """
        rotation = dataBlock.inputValue(TwistExtractor.inRotation).asDouble3()
        rotOrder = dataBlock.inputValue(
            TwistExtractor.inRotationOrder).asShort()
        eRoll = om2.MEulerRotation(rotation, rotOrder)
        useUpObj = dataBlock.inputValue(TwistExtractor.inUseUpVec).asBool()
        revTwist = dataBlock.inputValue(TwistExtractor.inInvTwist).asBool()

        # Non flip ROO = XYZ
        # Not working = XZY
        twistOrder = om2.MEulerRotation.kXYZ
        eRoll.reorderIt(twistOrder)

        # Non-Roll orientation
        mtxFn = om2.MTransformationMatrix()
        mtxFn.rotateBy(eRoll, om2.MSpace.kWorld)
        mRoll = mtxFn.asMatrix()

        qNonRoll = om2.MQuaternion()

        nAim = om2.MVector(mRoll[0], mRoll[1], mRoll[2])
        nAim.normalize()
        nAimAxis = om2.MVector.kXaxisVector
        qAim = om2.MQuaternion(nAimAxis, nAim)
        qNonRoll *= qAim

        if useUpObj:
            vUp = om2.MVector(
                dataBlock.inputValue(TwistExtractor.inUpVec).asFloat3())
            nNormal = vUp - ((vUp * nAim) * nAim)
            nNormal.normalize()
            nUp = om2.MVector.kYaxisVector.rotateBy(qAim)
            angle = nUp.angle(nNormal)
            qNormal = om2.MQuaternion(angle, nAim)
            if not nNormal.isEquivalent(nUp.rotateBy(qNormal), 1.0e-5):
                angle = 2.0 * kPI - angle
                qNormal = om2.MQuaternion(angle, nAim)
            qNonRoll *= qNormal
        eNonRoll = qNonRoll.asEulerRotation()
        eNonRoll = om2.MEulerRotation(eNonRoll.x, eNonRoll.y, eNonRoll.z,
                                      twistOrder)

        # Extract Twist from orientations
        qRoll = eRoll.asQuaternion()
        qExtract180 = qNonRoll * qRoll.inverse()
        eExtract180 = qExtract180.asEulerRotation()
        twist = -eExtract180.x
        if revTwist:
            twist *= -1.0

        # Output Twist
        if plug == TwistExtractor.outTwist:
            outTwistHdle = dataBlock.outputValue(TwistExtractor.outTwist)
            outTwistHdle.setMAngle(om2.MAngle(twist))
            outTwistHdle.setClean()

        # Output Twist Distribution
        if plug == TwistExtractor.outTwistDist:
            invDist = dataBlock.inputValue(TwistExtractor.inRevDist).asBool()
            outTwistDistHdle = dataBlock.outputArrayValue(
                TwistExtractor.outTwistDist)
            outputs = len(outTwistDistHdle)
            step = twist / (outputs - 1) if outputs > 1 else twist
            outList = []
            outList.extend(range(outputs))
            if not invDist:
                outList.reverse()
            # pylint: disable=consider-using-enumerate
            for i in range(len(outList)):
                outTwistDistHdle.jumpToLogicalElement(i)
                resultHdle = outTwistDistHdle.outputValue()
                result = step * outList[i] if outputs > 1 else twist
                resultHdle.setMAngle(om2.MAngle(result))
            outTwistDistHdle.setAllClean()

        return
Exemple #6
0
    def compute(self, plug, dataBlock):
        """
        Node computation method:
            * plug is a connection point related to one of our node attributes (either an input or an output).
            * dataBlock contains the data on which we will base our computations.
        """
        # pylint: disable=R0201
        blender = dataBlock.inputValue(BlendTransform.inBlender).asFloat()
        if plug == BlendTransform.outTrans:
            trans1Handle = dataBlock.inputArrayValue(BlendTransform.inTrans1)
            trans2Handle = dataBlock.inputArrayValue(BlendTransform.inTrans2)
            outTransHandle = dataBlock.outputArrayValue(
                BlendTransform.outTrans)
            outList = []
            for i in range(min(len(trans1Handle), len(trans2Handle))):
                trans1Handle.jumpToLogicalElement(i)
                trans2Handle.jumpToLogicalElement(i)
                vTrans1 = trans1Handle.inputValue().asFloatVector()
                vTrans2 = trans2Handle.inputValue().asFloatVector()
                vOut = (1.0 - blender) * vTrans1 + blender * vTrans2
                outList.append(vOut)
            for i in range(len(outTransHandle)):
                outTransHandle.jumpToLogicalElement(i)
                resultHandle = outTransHandle.outputValue()
                if i < len(outTransHandle) and i < len(outList):
                    resultHandle.setMFloatVector(outList[i])
                else:
                    resultHandle.setMFloatVector(om2.MFloatVector())
            outTransHandle.setAllClean()

        elif plug == BlendTransform.outRot:
            rotInterp = dataBlock.inputValue(
                BlendTransform.inRotInterp).asShort()
            rot1Handle = dataBlock.inputArrayValue(BlendTransform.inRot1)
            rot2Handle = dataBlock.inputArrayValue(BlendTransform.inRot2)
            outRotHandle = dataBlock.outputArrayValue(BlendTransform.outRot)
            rotOrder1Handle = dataBlock.inputArrayValue(
                BlendTransform.inRot1Order)
            rotOrder2Handle = dataBlock.inputArrayValue(
                BlendTransform.inRot2Order)
            outRotOrderHandle = dataBlock.inputArrayValue(
                BlendTransform.inOutRotOrder)
            outList = []
            for i in range(min(len(rot1Handle), len(rot2Handle))):
                rot1Handle.jumpToLogicalElement(i)
                rot2Handle.jumpToLogicalElement(i)
                rotOrder1 = BlendTransform.checkRotateOrderArrayHandle(
                    rotOrder1Handle, i)
                rotOrder2 = BlendTransform.checkRotateOrderArrayHandle(
                    rotOrder2Handle, i)
                outRotOrder = BlendTransform.checkRotateOrderArrayHandle(
                    outRotOrderHandle, i)
                rot1 = rot1Handle.inputValue().asVector()
                rot2 = rot2Handle.inputValue().asVector()
                eRot1 = om2.MEulerRotation(rot1, rotOrder1)
                eRot2 = om2.MEulerRotation(rot2, rotOrder2)
                eRot1.reorderIt(outRotOrder)
                eRot2.reorderIt(outRotOrder)
                if rotInterp == 0:
                    vRot1 = eRot1.asVector()
                    vRot2 = eRot2.asVector()
                    vOut = (1.0 - blender) * vRot1 + blender * vRot2
                else:
                    qRot1 = eRot1.asQuaternion()
                    qRot2 = eRot2.asQuaternion()
                    eSlerp = om2.MQuaternion.slerp(qRot1, qRot2,
                                                   blender).asEulerRotation()
                    eSlerp.reorderIt(outRotOrder)
                    vOut = eSlerp.asVector()
                outList.append(vOut)
            for i in range(len(outRotHandle)):
                outRotHandle.jumpToLogicalElement(i)
                resultHandle = outRotHandle.outputValue()
                if i < len(outRotHandle) and i < len(outList):
                    resultHandle.setMVector(outList[i])
                else:
                    resultHandle.setMVector(om2.MVector())
            outRotHandle.setAllClean()

        elif plug == BlendTransform.outSca:
            sca1Handle = dataBlock.inputArrayValue(BlendTransform.inSca1)
            sca2Handle = dataBlock.inputArrayValue(BlendTransform.inSca2)
            outScaHandle = dataBlock.outputArrayValue(BlendTransform.outSca)
            outList = []
            for i in range(min(len(sca1Handle), len(sca2Handle))):
                sca1Handle.jumpToLogicalElement(i)
                sca2Handle.jumpToLogicalElement(i)
                vSca1 = sca1Handle.inputValue().asFloatVector()
                vSca2 = sca2Handle.inputValue().asFloatVector()
                vOut = (1.0 - blender) * vSca1 + blender * vSca2
                outList.append(vOut)
            for i in range(len(outScaHandle)):
                outScaHandle.jumpToLogicalElement(i)
                resultHandle = outScaHandle.outputValue()
                if i < len(outScaHandle) and i < len(outList):
                    resultHandle.setMFloatVector(outList[i])
                else:
                    resultHandle.setMFloatVector(om2.MFloatVector())
            outScaHandle.setAllClean()

        elif plug in (BlendTransform.outVis, BlendTransform.outRevVis):
            outVisHandle = dataBlock.outputValue(BlendTransform.outVis)
            outRevVisHandle = dataBlock.outputValue(BlendTransform.outRevVis)
            vis, revVis = BlendTransform.visibilityCalculation(blender)
            outVisHandle.setBool(vis)
            outRevVisHandle.setBool(revVis)
            outVisHandle.setClean()
            outRevVisHandle.setClean()
Exemple #7
0
    def compute(self, plug, dataBlock):
        """
        Node computation method:
            * plug is a connection point related to one of our node attributes (either an input or an output).
            * dataBlock contains the data on which we will base our computations.
        """
        # pylint: disable=no-self-use
        if plug != HelperJoint.outTransform:
            return om2.kUnknownParameter

        mSource = dataBlock.inputValue(HelperJoint.inSource).asMatrix()
        mtxFn = om2.MTransformationMatrix(mSource)
        mtxFn.setScale([1.0, 1.0, 1.0], om2.MSpace.kTransform)
        mSource = mtxFn.asMatrix()
        mSourceParent = dataBlock.inputValue(HelperJoint.inSourceParent).asMatrix()

        mParInv = dataBlock.inputValue(HelperJoint.inParInvMtx).asMatrix()
        sourceParSca = dataBlock.inputValue(HelperJoint.inSourceParSca).asFloat3()
        mtxFn = om2.MTransformationMatrix()
        mtxFn.scaleBy(sourceParSca, om2.MSpace.kTransform)
        mInvSca = mtxFn.asMatrix()
        targetListHandle = dataBlock.inputArrayValue(HelperJoint.inTargetList)

        outputList = []

        for i in range(len(targetListHandle)):
            targetListHandle.jumpToLogicalElement(i)
            targetHandle = targetListHandle.inputValue()
            vPosOffset = om2.MVector(targetHandle.child(HelperJoint.inPositionOffset).asFloat3())
            eRotOffset = om2.MEulerRotation(targetHandle.child(HelperJoint.inRotationOffset).asDouble3())
            angle = targetHandle.child(HelperJoint.inRotAngle).asAngle().asRadians()
            restAngle = targetHandle.child(HelperJoint.inRestAngle).asAngle().asRadians()
            rotInterp = targetHandle.child(HelperJoint.inRotInterp).asFloat()
            posMult = targetHandle.child(HelperJoint.inPosMult).asFloat()
            negMult = targetHandle.child(HelperJoint.inNegMult).asFloat()

            mPositionOffset = om2.MMatrix()
            mPositionOffset[12] = vPosOffset.x
            mPositionOffset[13] = vPosOffset.y
            mPositionOffset[14] = vPosOffset.z
            multTranslation = abs(angle) * posMult
            if angle < restAngle:
                multTranslation = abs(angle) * negMult
            vPosOffset.normalize()
            mMultiplier = om2.MMatrix()
            mMultiplier[12] = vPosOffset.x * multTranslation
            mMultiplier[13] = vPosOffset.y * multTranslation
            mMultiplier[14] = vPosOffset.z * multTranslation
            mTargetPoint = mMultiplier * mPositionOffset * mSource
            mTargetOrient = mInvSca * (mSource * (1.0 - rotInterp)) + (mSourceParent * rotInterp)

            vResultPos = om2.MVector(mTargetPoint[12], mTargetPoint[13], mTargetPoint[14])
            mtxFn = om2.MTransformationMatrix(mTargetOrient)
            eResultOri = eRotOffset + mtxFn.rotation(asQuaternion=False)
            mtxFn = om2.MTransformationMatrix()
            mtxFn.setRotation(eResultOri)
            mtxFn.setTranslation(vResultPos, om2.MSpace.kTransform)
            mResult = mtxFn.asMatrix() * mParInv
            outputList.append(mResult)

        outTransHandle = dataBlock.outputArrayValue(HelperJoint.outTransform)
        for i in range(len(outTransHandle)):
            outTransHandle.jumpToLogicalElement(i)
            resultHandle = outTransHandle.outputValue()
            if i < len(outTransHandle) and i < len(outputList):
                resultHandle.setMMatrix(outputList[i])
            else:
                resultHandle.setMMatrix(om2.MMatrix.kIdentity)
Exemple #8
0
    def compute(self, plug, dataBlock):
        """
        Node computation method:
            * plug is a connection point related to one of our node attributes (either an input or an output).
            * dataBlock contains the data on which we will base our computations.
        """
        # pylint: disable=no-self-use
        if plug != AimConstraint.outConstraint:
            return om2.kUnknownParameter

        upVecType = dataBlock.inputValue(AimConstraint.inUpVecType).asShort()
        eOffset = om2.MEulerRotation(
            dataBlock.inputValue(AimConstraint.inOffset).asDouble3())
        qOffset = eOffset.asQuaternion()
        mTargetW = dataBlock.inputValue(AimConstraint.inTargetWMtx).asMatrix()
        targetWeight = dataBlock.inputValue(
            AimConstraint.inTargetWeight).asDouble()
        mConstW = dataBlock.inputValue(AimConstraint.inConstWMtx).asMatrix()
        mConstParInv = dataBlock.inputValue(
            AimConstraint.inConstParInvMtx).asMatrix()
        eConstJntOri = om2.MEulerRotation(
            dataBlock.inputValue(AimConstraint.inConstJntOri).asDouble3())
        qConstJntOri = eConstJntOri.asQuaternion()
        constRotOrder = dataBlock.inputValue(
            AimConstraint.inConstRotOrder).asShort()

        vTarget = om2.MVector(mTargetW[12], mTargetW[13], mTargetW[14])
        vConst = om2.MVector(mConstW[12], mConstW[13], mConstW[14])
        mtxFn = om2.MTransformationMatrix(mConstParInv)
        qConstParInv = mtxFn.rotation(asQuaternion=True)

        primAxis = om2.MVector.kXaxisVector
        secAxis = om2.MVector.kYaxisVector
        qAimConst = om2.MQuaternion()

        nAim = vTarget - vConst
        nAim.normalize()
        qAim = om2.MQuaternion(primAxis, nAim)
        qAimConst *= qAim

        if upVecType != 0:
            if upVecType == 1:
                # World Up
                nWorldUp = om2.MVector(
                    dataBlock.inputValue(
                        AimConstraint.inWorldUpVector).asFloat3())
                nWorldUp.normalize()
                vUp = nWorldUp
            elif upVecType == 2:
                # Object Up
                mWorldUp = dataBlock.inputValue(
                    AimConstraint.inWorldUpMtx).asMatrix()
                vWorldUp = om2.MVector(mWorldUp[12], mWorldUp[13],
                                       mWorldUp[14])
                vUp = vWorldUp - vConst
            elif upVecType == 3:
                # Angle Up
                angleUp = dataBlock.inputValue(
                    AimConstraint.inAngleUp).asAngle().asRadians()
                qTwist = om2.MQuaternion(angleUp, nAim)
                vUp = secAxis.rotateBy(qTwist)
            nNormal = vUp - ((vUp * nAim) * nAim)
            nNormal.normalize()

            nUp = secAxis.rotateBy(qAim)
            angle = nUp.angle(nNormal)
            qNormal = om2.MQuaternion(angle, nAim)
            if not nNormal.isEquivalent(nUp.rotateBy(qNormal), 1.0e-5):
                angle = 2.0 * math.pi - angle
                qNormal = om2.MQuaternion(angle, nAim)
            qAimConst *= qNormal

        qResult = om2.MQuaternion()
        qResult *= qOffset.invertIt()
        qResult *= qAimConst
        qResult *= qConstParInv
        qResult *= qConstJntOri.invertIt()
        eResult = qResult.asEulerRotation()
        eResult.reorderIt(constRotOrder)
        eResult *= targetWeight
        vResult = eResult.asVector()
        outConstraintHandle = dataBlock.outputValue(
            AimConstraint.outConstraint)
        outConstraintHandle.setMVector(vResult)
        outConstraintHandle.setClean()
Exemple #9
0
    def compute(self, plug, dataBlock):
        """
        Node computation method:
            * plug is a connection point related to one of our node attributes (either an input or an output).
            * dataBlock contains the data on which we will base our computations.
        """
        if plug != IKVChainSolver.outChain:
            return om2.kUnknownParameter

        # Get Basis Quaternion
        mRoot = dataBlock.inputValue(IKVChainSolver.inRoot).asMatrix()
        mHandle = dataBlock.inputValue(IKVChainSolver.inHandle).asMatrix()
        mPoleVector = dataBlock.inputValue(
            IKVChainSolver.inPoleVector).asMatrix()
        pvMode = dataBlock.inputValue(IKVChainSolver.inPvMode).asShort()
        prefAngle = dataBlock.inputValue(
            IKVChainSolver.inPreferredAngle).asAngle().asRadians()
        twist = dataBlock.inputValue(
            IKVChainSolver.inTwist).asAngle().asRadians()
        snap = dataBlock.inputValue(IKVChainSolver.inSnapUpVector).asFloat()
        mSnap = dataBlock.inputValue(IKVChainSolver.inSnap).asMatrix()
        flip = dataBlock.inputValue(IKVChainSolver.inFlip).asBool()

        vRoot = om2.MVector(mRoot[12], mRoot[13], mRoot[14])
        vHandle = om2.MVector(mHandle[12], mHandle[13], mHandle[14])
        vPoleVector = om2.MVector(mPoleVector[12], mPoleVector[13],
                                  mPoleVector[14])
        vSnap = om2.MVector(mSnap[12], mSnap[13], mSnap[14])

        primAxis = om2.MVector.kXaxisVector
        secAxis = om2.MVector.kYaxisVector
        if flip:
            primAxis = -om2.MVector.kXaxisVector
            secAxis = -om2.MVector.kYaxisVector
        binAxis = primAxis ^ secAxis
        qBasis = om2.MQuaternion()

        vAim = vHandle - vRoot
        nAim = vAim.normal()
        qAim = om2.MQuaternion(primAxis, nAim)
        qBasis *= qAim

        vStartSnap = vSnap - vRoot
        vEndSnap = vSnap - vHandle

        if pvMode == 0:
            vUp = vPoleVector - vRoot
        else:
            qTwist = om2.MQuaternion(prefAngle + twist, nAim)
            vUp = secAxis.rotateBy(qTwist)
        nNormalPole = vUp - ((vUp * nAim) * nAim)
        nNormalPole.normalize()
        if snap > 0.0:
            nNormalSnap = vStartSnap - ((vStartSnap * nAim) * nAim)
            nNormalSnap.normalize()
            nNormal = (1.0 - snap) * nNormalPole + snap * nNormalSnap
        else:
            nNormal = nNormalPole

        nUp = secAxis.rotateBy(qAim)
        angle = nUp.angle(nNormal)
        qNormal = om2.MQuaternion(angle, nAim)
        if not nNormal.isEquivalent(nUp.rotateBy(qNormal), 1.0e-5):
            angle = 2.0 * math.pi - angle
            qNormal = om2.MQuaternion(angle, nAim)
        qBasis *= qNormal

        # Solver Triangle
        restStartLen = dataBlock.inputValue(
            IKVChainSolver.inRestLenStart).asFloat()
        restEndLen = dataBlock.inputValue(
            IKVChainSolver.inRestLenEnd).asFloat()
        compressionLimit = dataBlock.inputValue(
            IKVChainSolver.inCompressionLimit).asFloat()
        softVal = dataBlock.inputValue(IKVChainSolver.inSoftness).asFloat()

        startSnapLen = vStartSnap.length()
        endSnapLen = vEndSnap.length()

        startLen = (1.0 - snap) * restStartLen + snap * startSnapLen
        endLen = (1.0 - snap) * restEndLen + snap * endSnapLen
        chainLen = (1.0 - snap) * (restStartLen + restEndLen) + snap * (
            startSnapLen + endSnapLen)
        handleLen = vAim.length()

        rigidLen = max(min(handleLen, chainLen), chainLen * compressionLimit)
        dc = chainLen
        da = (1.0 - softVal) * dc
        if handleLen > da and softVal > 0.0:
            ds = dc - da
            softLen = ds * (1.0 - math.pow(math.e, (da - handleLen) / ds)) + da
            solverLen = (1.0 - snap) * softLen + snap * rigidLen
        else:
            solverLen = rigidLen

        # Pre Calculations
        startLenSquared = math.pow(startLen, 2.0)
        endLenSquared = math.pow(endLen, 2.0)
        solverLenSquared = math.pow(solverLen, 2.0)
        stretch = dataBlock.inputValue(IKVChainSolver.inStretch).asDouble()
        squashMultStart = dataBlock.inputValue(
            IKVChainSolver.inSquashMultStart).asFloat2()
        squashMultEnd = dataBlock.inputValue(
            IKVChainSolver.inSquashMultEnd).asFloat2()
        if stretch > 0.0:
            clampStretch = dataBlock.inputValue(
                IKVChainSolver.inClampStretch).asDouble()
            clampValue = dataBlock.inputValue(
                IKVChainSolver.inClampValue).asDouble()
            squash = dataBlock.inputValue(IKVChainSolver.inSquash).asDouble()
            if handleLen > da and softVal > 0.0:
                scaleFactor = handleLen / solverLen
            else:
                scaleFactor = handleLen / chainLen
            if handleLen >= da:
                clampFactor = (
                    1.0 - clampStretch) * scaleFactor + clampStretch * min(
                        scaleFactor, clampValue)
                stretchFactor = (1.0 - stretch) + stretch * clampFactor
            else:
                stretchFactor = 1.0
            squashFactor = (1.0 -
                            squash) + squash * (1.0 / math.sqrt(stretchFactor))
        else:
            stretchFactor = 1.0
            squashFactor = 1.0

        hierarchyMode = dataBlock.inputValue(
            IKVChainSolver.inHierarchyMode).asBool()
        useScale = dataBlock.inputValue(IKVChainSolver.inUseScale).asBool()
        outChainHandle = dataBlock.outputArrayValue(IKVChainSolver.outChain)
        offsetHandle = dataBlock.inputArrayValue(IKVChainSolver.inOffset)
        jntOriHandle = dataBlock.inputArrayValue(IKVChainSolver.inJntOri)
        mParInv = dataBlock.inputValue(IKVChainSolver.inParInvMtx).asMatrix()
        srtList = []
        offsetList = []
        jntOriList = []

        for i in range(len(offsetHandle)):
            offsetHandle.jumpToLogicalElement(i)
            eOff = om2.MEulerRotation(offsetHandle.inputValue().asDouble3())
            qOff = eOff.asQuaternion()
            offsetList.append(qOff)

        for i in range(len(jntOriHandle)):
            jntOriHandle.jumpToLogicalElement(i)
            eOri = om2.MEulerRotation(jntOriHandle.inputValue().asDouble3())
            qOri = eOri.asQuaternion()
            jntOriList.append(qOri)

        # First Output
        # Scale
        firstStretch = stretchFactor
        firstScaX = firstStretch
        if not useScale:
            firstStretch = 1.0
        firstSquash = [
            squashFactor * squashMultStart[0],
            squashFactor * squashMultStart[1]
        ]
        firstSca = [firstStretch, firstSquash[0], firstSquash[1]]
        # Rotation
        betaCosPure = (startLenSquared + solverLenSquared -
                       endLenSquared) / (2.0 * startLen * solverLen)
        betaCos = min(max(betaCosPure, -1.0), 1.0)
        beta = math.acos(betaCos)
        qBeta = om2.MQuaternion(beta, binAxis)
        qFirstRotW = qBeta * qBasis
        qFirstRot = om2.MQuaternion()
        if len(offsetList) >= 1:
            qFirstRot *= offsetList[0].invertIt()
        qFirstRot *= qFirstRotW
        if len(jntOriList) >= 1:
            qFirstRot *= jntOriList[0].invertIt()
        # Translation
        vFirstPos = vRoot
        # Matrix Output
        mtxFn = om2.MTransformationMatrix()
        mtxFn.setScale(firstSca, om2.MSpace.kTransform)
        mtxFn.setRotation(qFirstRot)
        mtxFn.setTranslation(vFirstPos, om2.MSpace.kTransform)
        mFirst = mtxFn.asMatrix()
        mFirst *= mParInv
        srtList.append(mFirst)

        # Second Output
        # Scale
        secondStretch = stretchFactor
        secondScaX = secondStretch
        if not useScale:
            secondStretch = 1.0
        secondSquash = [
            squashFactor * squashMultEnd[0], squashFactor * squashMultEnd[1]
        ]
        secondSca = [secondStretch, secondSquash[0], secondSquash[1]]
        # Rotation
        gammaCosPure = (startLenSquared + endLenSquared -
                        solverLenSquared) / (2.0 * startLen * endLen)
        gammaCos = min(max(gammaCosPure, -1.0), 1.0)
        gamma = math.acos(gammaCos)
        gammaCmp = gamma + beta - math.pi
        qGamma = om2.MQuaternion(gammaCmp, binAxis)
        qSecondRotW = qGamma * qBasis
        qSecondRot = om2.MQuaternion()
        if len(offsetList) >= 2:
            qSecondRot *= offsetList[1].invertIt()
        qSecondRot *= qSecondRotW
        if hierarchyMode:
            qSecondRot *= qFirstRotW.invertIt()
            if len(offsetList) >= 1:
                qSecondRot *= offsetList[0].invertIt()
        if len(jntOriList) >= 2:
            qSecondRot *= jntOriList[1].invertIt()
        # Translation
        if hierarchyMode:
            vSecondPos = primAxis * startLen
            if not useScale:
                vSecondPos *= firstScaX
        else:
            vSecondOri = nAim.rotateBy(om2.MQuaternion(
                beta, nAim ^ nNormal)) * startLen
            if not useScale:
                vSecondOri *= firstScaX
            vSecondPos = vRoot + vSecondOri
        # Matrix Output
        mtxFn = om2.MTransformationMatrix()
        mtxFn.setScale(secondSca, om2.MSpace.kTransform)
        mtxFn.setRotation(qSecondRot)
        mtxFn.setTranslation(vSecondPos, om2.MSpace.kTransform)
        mSecond = mtxFn.asMatrix()
        if not hierarchyMode:
            mSecond *= mParInv
        srtList.append(mSecond)

        # Third Output
        # Rotation
        qThirdRot = qBasis
        if hierarchyMode:
            qThirdRot *= qSecondRotW.invertIt()
            if len(offsetList) >= 2:
                qThirdRot *= offsetList[1].invertIt()
        # Translation
        if hierarchyMode:
            vThirdPos = primAxis * endLen
            if not useScale:
                vThirdPos *= secondScaX
        else:
            vThirdPos = vRoot + nAim * solverLen
            if not useScale:
                vThirdPos = vRoot + nAim * solverLen * stretchFactor
        # Matrix Output
        mtxFn = om2.MTransformationMatrix()
        mtxFn.setRotation(qThirdRot)
        mtxFn.setTranslation(vThirdPos, om2.MSpace.kTransform)
        mThird = mtxFn.asMatrix()
        if not hierarchyMode:
            mThird *= mParInv
        srtList.append(mThird)

        # Set outputs
        for i in range(len(outChainHandle)):
            outChainHandle.jumpToLogicalElement(i)
            resultHandle = outChainHandle.outputValue()
            if i < len(outChainHandle) and i < len(srtList):
                resultHandle.setMMatrix(srtList[i])
            else:
                resultHandle.setMMatrix(om2.MMatrix.kIdentity)

        outChainHandle.setAllClean()
    def compute(self, plug, dataBlock):
        """
        Node computation method:
            * plug is a connection point related to one of our node attributes (either an input or an output).
            * dataBlock contains the data on which we will base our computations.
        """
        # pylint: disable=no-self-use
        eConstJntOri = om2.MEulerRotation(
            dataBlock.inputValue(
                ParentConstraint.inConstraintJntOri).asDouble3())
        mConstParInv = dataBlock.inputValue(
            ParentConstraint.inConstraintParInvMtx).asMatrix()
        constRotOrder = dataBlock.inputValue(
            ParentConstraint.inConstraintRotOrder).asShort()
        constParSca = dataBlock.inputValue(
            ParentConstraint.inConstraintParSca).asFloat3()
        targetListHandle = dataBlock.inputArrayValue(
            ParentConstraint.inTargetList)
        mTargetsAdded = om2.MMatrix()
        mtxFn = om2.MTransformationMatrix()
        mtxFn.scaleBy(constParSca, om2.MSpace.kTransform)
        mInvSca = mtxFn.asMatrix()

        for i in range(len(targetListHandle)):
            targetListHandle.jumpToLogicalElement(i)
            targetHandle = targetListHandle.inputValue()
            # targetJntOri = om2.MEulerRotation(targetHandle.child(ParentConstraint.inTargetJntOri).asDouble3())
            # targetRotOrder = targetHandle.child(ParentConstraint.inTargetRotOrder).asShort()
            mTargetW = targetHandle.child(
                ParentConstraint.inTargetWorldMatrix).asMatrix()
            mOffset = targetHandle.child(
                ParentConstraint.inTargetOffset).asMatrix()
            targetWeight = targetHandle.child(
                ParentConstraint.inTargetWeight).asFloat()

            mTarget = mOffset * (mTargetW * targetWeight)
            if mTargetsAdded == om2.MMatrix():
                mTargetsAdded = mTarget
            else:
                mTargetsAdded += mTarget

        mResult = mTargetsAdded * mConstParInv * mInvSca

        if plug == ParentConstraint.outConstTrans:
            outTransHandle = dataBlock.outputValue(
                ParentConstraint.outConstTrans)
            outTrans = om2.MFloatVector(mResult[12], mResult[13], mResult[14])
            outTransHandle.setMFloatVector(outTrans)
            outTransHandle.setClean()
        if plug == ParentConstraint.outConstRot:
            outRotHandle = dataBlock.outputValue(ParentConstraint.outConstRot)
            mtxFn = om2.MTransformationMatrix(mResult)
            eRotMtx = mtxFn.rotation(asQuaternion=False)
            qRotMtx = eRotMtx.asQuaternion()
            qConstJntOri = eConstJntOri.asQuaternion()
            qOutRot = qRotMtx * qConstJntOri.invertIt()
            outRot = qOutRot.asEulerRotation().reorderIt(constRotOrder)
            outRotHandle.setMVector(outRot.asVector())
            outRotHandle.setClean()
        if plug == ParentConstraint.outConstSca:
            outScaHandle = dataBlock.outputValue(ParentConstraint.outConstSca)
            mtxFn = om2.MTransformationMatrix(mResult)
            outSca = mtxFn.scale(om2.MSpace.kWorld)
            outScaHandle.set3Float(outSca[0], outSca[1], outSca[2])
            outScaHandle.setClean()