예제 #1
0
 def autoFillOffset(self, thisMob, index):
     """Auto fill offsets attributes."""
     allClear = self.checkOutputConnections(thisMob)
     obj = self.constraintObject
     if not allClear:
         if obj.hasFn(om2.MFn.kDagNode):
             objPath = om2.MFnDagNode(obj).getPath()
             mOut = objPath.inclusiveMatrix()
             targetPlug = om2.MPlug(thisMob, SpaceConstraint.inTarget)
             curTargetPlug = targetPlug.elementByLogicalIndex(index)
             curTargetObj = curTargetPlug.asMObject()
             mtxDataFn = om2.MFnMatrixData(curTargetObj)
             mTarget = mtxDataFn.matrix()
             mOffset = mOut * mTarget.inverse()
             offsetPlug = om2.MPlug(thisMob, SpaceConstraint.inOffset)
             curOffsetPlug = offsetPlug.elementByLogicalIndex(index)
             curOffsetHdle = curOffsetPlug.asMDataHandle()
             mCurOffset = curOffsetHdle.asMatrix()
             if mCurOffset == om2.MMatrix():
                 curOffsetHdle.setMMatrix(mOffset)
                 curOffsetPlug.setMDataHandle(curOffsetHdle)
예제 #2
0
    def drawArrow(startPnt,
                  endPnt,
                  size,
                  radius,
                  subd,
                  lineW,
                  vp2=False,
                  glFT=None,
                  lineList=None):
        """Draw an aim arrow

        Args:
            startPnt (MFloatVector): The base of the vector.
            endPnt (MFloatVector): The end of the vector.
            size (float): The size of the arrow.
            radius (float): The radius of the arrow.
            subd (int): The number of subdivisions of the arrow.
            lineW (float): The width of the lines.
            vp2 (bool: False [Optional]): Draw inside of drawing override for viewport 2.0.
            glFT (instance: None [Optional]): The GL Function Table to draw in viewport 1.0.
            lineList (MPointArray: None [Optional]): The line list to append for drawing override.
        """
        tipSize = 1.0 - size
        step = 2.0 * math.pi / subd
        vAim = endPnt - startPnt
        vBaseOrigin = vAim * tipSize
        nAim = vAim.normal()
        nWorld = om2.MFloatVector(0.0, 1.0, 0.0)
        nBinormal = nWorld ^ nAim
        nBinormal.normalize()
        nNormal = nAim ^ nBinormal
        nNormal.normalize()
        aim = [
            nAim.x, nAim.y, nAim.z, 0.0, nNormal.x, nNormal.y, nNormal.z, 0.0,
            nBinormal.x, nBinormal.y, nBinormal.z, 0.0, startPnt.x, startPnt.y,
            startPnt.z, 1.0
        ]
        mBase = om2.MMatrix(aim)
        mOrigin = om2.MMatrix()
        mOrigin[12] = vBaseOrigin.length()
        mBaseOrigin = mOrigin * mBase
        if vp2:
            lineList.append(om2.MPoint(startPnt))
            lineList.append(om2.MPoint(endPnt))
        else:
            glFT.glLineWidth(lineW)
            glFT.glBegin(omr1.MGL_LINES)
            glFT.glVertex3f(startPnt.x, startPnt.y, startPnt.z)
            glFT.glVertex3f(endPnt.x, endPnt.y, endPnt.z)
            glFT.glEnd()
        for i in range(subd):
            theta = step * i
            mPoint = om2.MMatrix()
            mPoint[13] = math.cos(theta) * radius
            mPoint[14] = math.sin(theta) * radius
            mArrow = mPoint * mBaseOrigin
            if vp2:
                lineList.append(
                    om2.MPoint(mBaseOrigin[12], mBaseOrigin[13],
                               mBaseOrigin[14]))
                lineList.append(om2.MPoint(mArrow[12], mArrow[13], mArrow[14]))
                lineList.append(om2.MPoint(mArrow[12], mArrow[13], mArrow[14]))
                lineList.append(om2.MPoint(endPnt))
            else:
                glFT.glBegin(omr1.MGL_LINES)
                glFT.glVertex3f(mBaseOrigin[12], mBaseOrigin[13],
                                mBaseOrigin[14])
                glFT.glVertex3f(mArrow[12], mArrow[13], mArrow[14])
                glFT.glVertex3f(mArrow[12], mArrow[13], mArrow[14])
                glFT.glVertex3f(endPnt.x, endPnt.y, endPnt.z)
                glFT.glEnd()
        return None
예제 #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
        ctrlPntsHandle = dataBlock.inputArrayValue(
            QuadraticCurve.inControlPoints)
        ctrlPnts = om2.MPointArray()

        if len(ctrlPntsHandle) < 3:
            return

        for i in range(3):
            ctrlPntsHandle.jumpToLogicalElement(i)
            mCtrlPnt = ctrlPntsHandle.inputValue().asMatrix()
            ctrlPnt = om2.MPoint(mCtrlPnt[12], mCtrlPnt[13], mCtrlPnt[14])
            ctrlPnts.append(ctrlPnt)

        crvKnots = om2.MDoubleArray([0, 0, 1, 1])
        crvDegree = 2
        crvForm = om2.MFnNurbsCurve.kOpen
        crvIs2d = False
        crvRational = False
        crvData = om2.MFnNurbsCurveData().create()
        crvFn = om2.MFnNurbsCurve(crvData)

        crvFn.create(ctrlPnts, crvKnots, crvDegree, crvForm, crvIs2d,
                     crvRational, crvData)
        crvFn.updateCurve()

        if plug == QuadraticCurve.outCurve:
            outCurveHandle = dataBlock.outputValue(QuadraticCurve.outCurve)
            outCurveHandle.setMObject(crvData)
            outCurveHandle.setClean()

        elif plug == QuadraticCurve.outTransforms:
            outTransHandle = dataBlock.outputArrayValue(
                QuadraticCurve.outTransforms)
            lockLength = dataBlock.inputValue(
                QuadraticCurve.inLockLength).asFloat()
            restLength = dataBlock.inputValue(
                QuadraticCurve.inRestLength).asFloat()
            slide = dataBlock.inputValue(QuadraticCurve.inSlide).asFloat()
            numOutputs = len(outTransHandle)
            crvLength = crvFn.length()
            parRejected = crvFn.findParamFromLength(crvLength - restLength)
            stepFull = 1.0 / (numOutputs - 1) if numOutputs > 1 else 0.0
            stepLock = crvFn.findParamFromLength(restLength) / (
                numOutputs - 1) if numOutputs > 1 else 0.0
            step = (1.0 - lockLength) * stepFull + lockLength * stepLock
            parSlide = parRejected * slide * lockLength
            for i in range(numOutputs):
                parameter = (step * i)  # + parSlide
                pos = crvFn.getPointAtParam(parameter, om2.MSpace.kObject)
                vPos = om2.MVector(pos.x, pos.y, pos.z)
                mtx = [
                    1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0,
                    vPos.x, vPos.y, vPos.z, 1.0
                ]
                mOut = om2.MMatrix(mtx)
                outTransHandle.jumpToLogicalElement(i)
                resultHandle = outTransHandle.outputValue()
                resultHandle.setMMatrix(mOut)
            outTransHandle.setAllClean()

        else:
            return om2.kUnknownParameter
예제 #4
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 != DistributeAlongSurface.outTransform:
            return om2.kUnknownParameter

        surfaceHandle = dataBlock.inputValue(DistributeAlongSurface.inSurface)
        surface = surfaceHandle.asNurbsSurface()
        distAlong = dataBlock.inputValue(DistributeAlongSurface.inDistributeAlong).asShort()
        displace = dataBlock.inputValue(DistributeAlongSurface.inDisplace).asFloat()
        alwaysUniform = dataBlock.inputValue(DistributeAlongSurface.inAlwaysUniform).asBool()
        outTransHandle = dataBlock.outputArrayValue(DistributeAlongSurface.outTransform)

        numOutputs = len(outTransHandle)
        surfaceFn = om2.MFnNurbsSurface(surface)
        step = 1.0 / (numOutputs - 1) if numOutputs > 1 else 0.0
        curveData = om2.MFnNurbsCurveData().create()
        curveFn = om2.MFnNurbsCurve(curveData)

        if alwaysUniform:
            numCVs = surfaceFn.numCVsInU if distAlong == 0 else surfaceFn.numCVsInV
            curvePnts = om2.MPointArray()
            curveKnots = surfaceFn.knotsInU() if distAlong == 0 else surfaceFn.knotsInV()
            curveDegree = surfaceFn.degreeInU if distAlong == 0 else surfaceFn.degreeInV
            curveForm = surfaceFn.formInU if distAlong == 0 else surfaceFn.formInV
            curveIs2d = False
            curveRational = False
            for i in range(numCVs):
                if distAlong == 0:
                    curvePnts.append(surfaceFn.cvPosition(i, int(displace)))
                else:
                    curvePnts.append(surfaceFn.cvPosition(int(displace), i))
            curveFn.create(curvePnts, curveKnots, curveDegree, curveForm, curveIs2d, curveRational, curveData)
            curveLength = curveFn.length()

        for i in range(numOutputs):
            if alwaysUniform:
                parU = curveFn.findParamFromLength(curveLength * step * i) if distAlong == 0 else displace
                parV = displace if distAlong == 0 else curveFn.findParamFromLength(curveLength * step * i)
            else:
                parU = step * i if distAlong == 0 else displace
                parV = displace if distAlong == 0 else step * i
            pos = surfaceFn.getPointAtParam(parU, parV, om2.MSpace.kWorld)
            tangents = surfaceFn.tangents(parU, parV, om2.MSpace.kWorld)
            aim = tangents[0].normalize() if distAlong == 0 else tangents[1].normalize()
            normal = surfaceFn.normal(parU, parV, om2.MSpace.kWorld).normalize()
            binormal = tangents[1].normalize() if distAlong == 0 else tangents[0].normalize()
            mtx = [
                aim.x, aim.y, aim.z, 0.0,
                normal.x, normal.y, normal.z, 0.0,
                binormal.x, binormal.y, binormal.z, 0.0,
                pos.x, pos.y, pos.z, 1.0
            ]
            mOut = om2.MMatrix(mtx)
            outTransHandle.jumpToLogicalElement(i)
            resultHandle = outTransHandle.outputValue()
            resultHandle.setMMatrix(mOut)

        surfaceHandle.setClean()
        outTransHandle.setAllClean()

        cmds.refresh()
예제 #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.
        """
        # pylint: disable=no-self-use
        # if not dataBlock.isClean(SpaceConstraint.inSpace):
        #     om2.MGlobal.displayInfo("\tSpace attribute is dirty.")
        #     om2.MUserEventMessage.postUserEvent("preCompute", self)

        curSpace = dataBlock.inputValue(SpaceConstraint.inSpace).asShort()

        offsetMatchHdle = dataBlock.inputArrayValue(
            SpaceConstraint.inOffsetMatches)
        offsetHdle = dataBlock.inputArrayValue(SpaceConstraint.inOffset)
        targetHdle = dataBlock.inputArrayValue(SpaceConstraint.inTarget)
        offsetMatchList = []
        offsetList = []
        targetList = []

        for i in range(len(offsetMatchHdle)):
            offsetMatchHdle.jumpToLogicalElement(i)
            mOffMatch = offsetMatchHdle.inputValue().asMatrix()
            offsetMatchList.append(mOffMatch)

        for i in range(len(offsetHdle)):
            offsetHdle.jumpToLogicalElement(i)
            mOff = offsetHdle.inputValue().asMatrix()
            offsetList.append(mOff)

        for i in range(len(targetHdle)):
            targetHdle.jumpToLogicalElement(i)
            mTgt = targetHdle.inputValue().asMatrix()
            targetList.append(mTgt)

        if len(offsetList) == 0 or len(targetList) == 0:
            mResult = om2.MMatrix()
        else:
            minRequired = min(len(offsetList), len(targetList)) - 1
            if curSpace > minRequired:
                curSpace = minRequired
            mResult = offsetMatchList[curSpace] * offsetList[
                curSpace] * targetList[curSpace]

        mtxFn = om2.MTransformationMatrix(mResult)

        if plug == SpaceConstraint.outConstTrans:
            vTransD = om2.MVector(mResult[12], mResult[13], mResult[14])
            vTrans = om2.MFloatVector(vTransD)
            outTransHdle = dataBlock.outputValue(SpaceConstraint.outConstTrans)
            outTransHdle.setMFloatVector(vTrans)
            outTransHdle.setClean()

        if plug == SpaceConstraint.outConstRot:
            eRot = mtxFn.rotation(asQuaternion=False)
            outRotHdle = dataBlock.outputValue(SpaceConstraint.outConstRot)
            outRotHdle.setMVector(eRot.asVector())
            outRotHdle.setClean()

        if plug == SpaceConstraint.outConstSca:
            outSca = mtxFn.scale(om2.MSpace.kWorld)
            outScaHdle = dataBlock.outputValue(SpaceConstraint.outConstSca)
            outScaHdle.set3Float(outSca[0], outSca[1], outSca[2])
            outScaHdle.setClean()
예제 #6
0
    def spaceMatchCallback(msg, plug, otherPlug, clientData):
        """
        The callback function.
        Note: Attribute Changed messages will not be generated while Maya is either in playback or scrubbing modes.
        If you need to do something during playback or scrubbing you will have to register a callback for the
        timeChanged message which is the only message that is sent during those modes.
            * msg [MNodeMessage::AttributeMessage] is the kind of attribute change triggering the callback.
            * plug [MPlug] is the node's plug where the connection changed.
            * otherPlug [MPlug] is the plug opposite the node's plug where the connection changed.
            * clientData [void*] is the user defined data passed to this callback function.
        """
        # pylint: disable=unused-argument
        # 6144 = create input array element.
        # 16385 = connecting output.
        # 16386 = disconnecting output.
        # 2052 = change output in compute method.
        # 2056 = set attribute.
        # 10240 = delete element plug from array attribute.
        # 18434 = disconnect input plug.
        # 18433 = connect input plug.

        thisMob = clientData.thisMObject()
        if not isinstance(clientData, SpaceConstraint):
            # SpaceConstraint *pMesh = static_cast<SpaceConstraint *>(clientData);
            om2.MGlobal.displayError(
                "[gfTools] gfSpaceConstraint don't recognize the clientData for space match callback. Callback functionality skiped."
            )
            return
        match = om2.MPlug(thisMob, SpaceConstraint.inSpaceMatch).asBool()
        if not match:
            return
        if msg == 2056:
            if plug == SpaceConstraint.inSpace:
                lastValue = clientData.lastSpace
                curValue = plug.asShort()
                # 1- Get the output plug
                allClear = clientData.checkOutputConnections(thisMob)
                # 2- Check if the curValue is valid. If it is not, get the last valid.
                targetPlug = om2.MPlug(thisMob, SpaceConstraint.inTarget)
                offsetPlug = om2.MPlug(thisMob, SpaceConstraint.inOffset)
                offsetMatchPlug = om2.MPlug(thisMob,
                                            SpaceConstraint.inOffsetMatches)
                numTarget = targetPlug.numElements() - 1
                if curValue > numTarget:
                    curValue = numTarget
                # 3- If the node have necessary connections...
                if not allClear and (numTarget + 1) > 0:
                    outObj = clientData.constraintObject
                    if outObj.hasFn(om2.MFn.kDagNode):
                        # 4- Get the last world matrix of the target
                        lastOffsetMatchPlug = offsetMatchPlug.elementByLogicalIndex(
                            lastValue)
                        lastOffsetMatchObj = lastOffsetMatchPlug.asMObject()
                        mtxDataFn = om2.MFnMatrixData(lastOffsetMatchObj)
                        mOffsetMatch = mtxDataFn.matrix()
                        lastOffsetPlug = offsetPlug.elementByLogicalIndex(
                            lastValue)
                        lastOffsetObj = lastOffsetPlug.asMObject()
                        mtxDataFn = om2.MFnMatrixData(lastOffsetObj)
                        mOffset = mtxDataFn.matrix()
                        lastTargetPlug = targetPlug.elementByLogicalIndex(
                            lastValue)
                        lastTargetObj = lastTargetPlug.asMObject()
                        mtxDataFn = om2.MFnMatrixData(lastTargetObj)
                        mTarget = mtxDataFn.matrix()
                        mLastOutputW = mOffsetMatch * mOffset * mTarget
                        # 5- Get the current world matrix of the target
                        curTargetPlug = targetPlug.elementByLogicalIndex(
                            curValue)
                        curTargetObj = curTargetPlug.asMObject()
                        mtxDataFn = om2.MFnMatrixData(curTargetObj)
                        mTarget = mtxDataFn.matrix()
                        curOffsetPlug = offsetPlug.elementByLogicalIndex(
                            curValue)
                        curOffsetObj = curOffsetPlug.asMObject()
                        mtxDataFn = om2.MFnMatrixData(curOffsetObj)
                        mOffset = mtxDataFn.matrix()
                        mCurOutputW = mOffset * mTarget
                        # 6- Get the result of the match and set it into the plug
                        mResult = mLastOutputW * mCurOutputW.inverse()
                        curOffsetMatchPlug = offsetMatchPlug.elementByLogicalIndex(
                            curValue)
                        curOffsetMatchHdle = curOffsetMatchPlug.asMDataHandle()
                        curOffsetMatchHdle.setMMatrix(mResult)
                        curOffsetMatchPlug.setMDataHandle(curOffsetMatchHdle)
                        # 7- Clean the offset match plug from last value
                        lastOffsetMatchHdle = lastOffsetMatchPlug.asMDataHandle(
                        )
                        lastOffsetMatchHdle.setMMatrix(om2.MMatrix())
                        lastOffsetMatchPlug.setMDataHandle(lastOffsetMatchHdle)
                clientData.lastSpace = curValue
예제 #7
0
 def spaceMatchCallback2(node, plug, clientData):
     """Node dirty callback. Works, but not quite. """
     # 1- Check if space plug is dirty.
     if plug == SpaceConstraint.inSpace:
         # 2- Check if clientData is valid.
         thisMob = clientData.thisMObject()
         if not isinstance(clientData, SpaceConstraint):
             om2.MGlobal.displayError(
                 "[gfTools] gfSpaceConstraint don't recognize the clientData for space matching. Callback functionality skipped."
             )
             return
         # 3- Check if automatic space matching is enable.
         match = om2.MPlug(thisMob, SpaceConstraint.inSpaceMatch).asBool()
         if not match:
             return
         # 4- Check if space attribute changed.
         lastValue = clientData.lastSpace
         curValue = plug.asShort()
         spacePlug = om2.MPlug(thisMob, SpaceConstraint.inSpace)
         om2.MGlobal.displayInfo("Current space value: %s" %
                                 str(spacePlug.asShort()))
         if curValue == lastValue:
             return
         # 5- Check if any output is been used and get the output object.
         allClear = clientData.checkOutputConnections(thisMob)
         # 6- Check the inputs.
         targetPlug = om2.MPlug(thisMob, SpaceConstraint.inTarget)
         offsetPlug = om2.MPlug(thisMob, SpaceConstraint.inOffset)
         offsetMatchPlug = om2.MPlug(thisMob,
                                     SpaceConstraint.inOffsetMatches)
         numTarget = targetPlug.numElements() - 1
         if curValue > numTarget:
             curValue = numTarget
         # 7- If the node have necessary connections...
         if not allClear and (numTarget + 1) > 0:
             outObj = clientData.constraintObject
             if outObj.hasFn(om2.MFn.kDagNode):
                 # 8- Get the last world matrix of the target.
                 lastOffsetMatchPlug = offsetMatchPlug.elementByLogicalIndex(
                     lastValue)
                 lastOffsetMatchObj = lastOffsetMatchPlug.asMObject()
                 mtxDataFn = om2.MFnMatrixData(lastOffsetMatchObj)
                 mOffsetMatch = mtxDataFn.matrix()
                 lastOffsetPlug = offsetPlug.elementByLogicalIndex(
                     lastValue)
                 lastOffsetObj = lastOffsetPlug.asMObject()
                 mtxDataFn = om2.MFnMatrixData(lastOffsetObj)
                 mOffset = mtxDataFn.matrix()
                 lastTargetPlug = targetPlug.elementByLogicalIndex(
                     lastValue)
                 lastTargetObj = lastTargetPlug.asMObject()
                 mtxDataFn = om2.MFnMatrixData(lastTargetObj)
                 mTarget = mtxDataFn.matrix()
                 mLastOutputW = mOffsetMatch * mOffset * mTarget
                 # 9- Get the current world matrix of the target.
                 curTargetPlug = targetPlug.elementByLogicalIndex(curValue)
                 curTargetObj = curTargetPlug.asMObject()
                 mtxDataFn = om2.MFnMatrixData(curTargetObj)
                 mTarget = mtxDataFn.matrix()
                 curOffsetPlug = offsetPlug.elementByLogicalIndex(curValue)
                 curOffsetObj = curOffsetPlug.asMObject()
                 mtxDataFn = om2.MFnMatrixData(curOffsetObj)
                 mOffset = mtxDataFn.matrix()
                 mCurOutputW = mOffset * mTarget
                 # 10- Get the result of the match and set it into the plug.
                 mResult = mLastOutputW * mCurOutputW.inverse()
                 curOffsetMatchPlug = offsetMatchPlug.elementByLogicalIndex(
                     curValue)
                 curOffsetMatchHdle = curOffsetMatchPlug.asMDataHandle()
                 curOffsetMatchHdle.setMMatrix(mResult)
                 curOffsetMatchPlug.setMDataHandle(curOffsetMatchHdle)
                 # 11- Clean the offset match plug from last value.
                 lastOffsetMatchHdle = lastOffsetMatchPlug.asMDataHandle()
                 lastOffsetMatchHdle.setMMatrix(om2.MMatrix())
                 lastOffsetMatchPlug.setMDataHandle(lastOffsetMatchHdle)
                 om2.MGlobal.displayInfo("Performing space matching...")
         # 12- Store the current space value in class to be accessed later on.
         clientData.lastSpace = curValue
예제 #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 != 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)
    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()