コード例 #1
0
ファイル: ffdPlanarNode.cpp プロジェクト: jonntd/mayatools-1
MStatus ffdPlanar::getBoundingBox( MDataBlock& block,
                                   unsigned int multiIndex,
                                   MBoundingBox &boundingBoxOut )
{
    MStatus status = MS::kSuccess;
    
    MArrayDataHandle inputHandle = block.outputArrayValue( input );
    inputHandle.jumpToElement( multiIndex );
    MObject mesh = inputHandle.outputValue().child( inputGeom ).asMesh();
    
    MBoundingBox boundingBox = MBoundingBox();
    MFnMesh meshFn( mesh, &status );
    MCheckErr( status, "Error getting mesh from mesh object\n" );
    
    MPointArray pointArray = MPointArray();
    meshFn.getPoints( pointArray, MSpace::kTransform );
    
    for ( int i = 0; i < pointArray.length(); i++ )
    {
        boundingBox.expand( pointArray[i] );
    }
    
    boundingBoxOut = boundingBox;
    return status;
}
コード例 #2
0
void SurfaceAttach::setOutPlugs(MDataBlock dataBlock, const MFnNurbsSurface &fnSurface,
                                const double dataOffset, const bool dataReverse, const short dataGenus, const double dataStaticLength,
                                const MMatrix &dataParentInverse, const short dataDirection) {

    MTransformationMatrix tfm;
    MVector t;
    MEulerRotation r;

    MArrayDataHandle outputHandle = dataBlock.outputArrayValue(SurfaceAttach::out);
    std::int32_t count = outputHandle.elementCount();
    MDataHandle o;

    for (unsigned int k = 0; k < count; ++k) {
        outputHandle.jumpToElement(k);

        // Get Transformations
        tfm = this->matrix(fnSurface, outputHandle.elementIndex(), dataOffset, dataReverse, dataGenus,
                           dataStaticLength, dataParentInverse, dataDirection);
        t = tfm.translation(MSpace::Space::kWorld);
        r = tfm.eulerRotation();

        o = outputHandle.outputValue();
        o.child(SurfaceAttach::translate).set(t);
        o.child(SurfaceAttach::rotate).set(r.x, r.y, r.z);
    }

    // Mark Clean
    dataBlock.setClean(SurfaceAttach::translate);
    dataBlock.setClean(SurfaceAttach::rotate);
    dataBlock.setClean(SurfaceAttach::out);
}
コード例 #3
0
ファイル: rippleDeformer.cpp プロジェクト: jonntd/mayaPlugins
MStatus RippleDeformer::deform(MDataBlock& dataBlock,
								MItGeometry& itGeo,
								const MMatrix& localToWorldMatrix,
								unsigned int geomIndex)
{
	MStatus status;
	
	//get attriubtes as a datahandle
	float env = dataBlock.inputValue(envelope).asFloat();
	float amplitude = dataBlock.inputValue(aAmplitude).asFloat();
	float displace = dataBlock.inputValue(aDisplace).asFloat();
	//get the mesh 
	
	//retrieve the handle to the input attribute
	MArrayDataHandle hInput = dataBlock.outputArrayValue(input, &status);
	CHECK_MSTATUS_AND_RETURN_IT(status);
	//get the input array index handle
	status = hInput.jumpToElement(geomIndex);
	//get the handle of geomIndex attribute
	MDataHandle hInputElement = hInput.outputValue(&status);
	//Get the MObject of the input geometry of geomindex
	MObject oInputGeom = hInputElement.child(inputGeom).asMesh();

	MFnMesh fnMesh(oInputGeom, &status);
	CHECK_MSTATUS_AND_RETURN_IT(status);
	if (oInputGeom.isNull())
	{
		return MS::kSuccess;
	}

	MFloatVectorArray normals;
	fnMesh.getVertexNormals(false, normals);

	MPoint pointPos;
	float weight;
	
	for (; !itGeo.isDone(); itGeo.next())
	{
		//get current point position
		pointPos = itGeo.position();
		weight = weightValue(dataBlock, geomIndex, itGeo.index());
		pointPos.x = pointPos.x + sin(itGeo.index() + displace) * amplitude * normals[itGeo.index()].x * weight * env;
		pointPos.y = pointPos.y + sin(itGeo.index() + displace) * amplitude * normals[itGeo.index()].y * weight * env;
		pointPos.z = pointPos.z + sin(itGeo.index() + displace) * amplitude * normals[itGeo.index()].z * weight * env;
		//setPosition
		itGeo.setPosition(pointPos);
	}	
	
	return MS::kSuccess;
}
コード例 #4
0
ファイル: quatcurve.cpp プロジェクト: jonntd/Public
MStatus n_tentacle::compute( const MPlug& plug, MDataBlock& data )
{
	MStatus returnStatus;

	//make sure we have the curve
	MObject curveObj = data.inputValue(curve).asNurbsCurve();

	if(!curveObj.isNull())
	{
		//get the data
		MArrayDataHandle inMatrixArrayHnd = data.inputArrayValue(matrix);

		int tangentAxisI = data.inputValue(tangentAxis).asInt();
		if(tangentAxisI > 2)
			tangentAxisI = - (tangentAxisI - 2);
		else
			tangentAxisI = tangentAxisI + 1;

		double stretchF = data.inputValue(stretch).asDouble();
		double globalScaleF = data.inputValue(globalScale).asDouble();
		double iniLengthF = data.inputValue(iniLength).asDouble();

		const MFnNurbsCurve curve(curveObj);
		MArrayDataHandle parameterArrayHnd = data.inputArrayValue(parameter);
		MArrayDataHandle blendRotArrayHnd = data.inputArrayValue(blendRot);
		MArrayDataHandle intervalArrayHnd = data.inputArrayValue(interval);
		MArrayDataHandle outTranslateArrayHnd = data.outputArrayValue(outTranslate);
		MArrayDataHandle outRotateArrayHnd = data.outputArrayValue(outRotate);

		int parameterNrPlugs = parameterArrayHnd.elementCount();
		int blendRotNrPlugs = blendRotArrayHnd.elementCount();
		int outTranslateNrPlugs = outTranslateArrayHnd.elementCount();
		int outRotateNrPlugs = outRotateArrayHnd.elementCount();

		//get the current curve length
        double currCurveLen = curve.length();

        if(this->init == false)
        {
        	if(outTranslateNrPlugs == parameterNrPlugs && outRotateNrPlugs == parameterNrPlugs && parameterNrPlugs == blendRotNrPlugs)
        	{
        		this->init = true;
        	}
        }

		if( plug == outTranslate || plug == outRotate || plug == outRotateX || plug == outRotateY || plug == outRotateZ)
		{
			if(this->init)
			{
                MArrayDataBuilder tbuilder(outTranslate, parameterNrPlugs);
                MArrayDataBuilder rbuilder(outRotate, parameterNrPlugs);

				for(int i = 0; i < parameterNrPlugs; i++)
				{
					intervalArrayHnd.jumpToArrayElement(i);
					int intervalI = intervalArrayHnd.inputValue().asInt();

					inMatrixArrayHnd.jumpToArrayElement(intervalI);
					MMatrix matrix1 = inMatrixArrayHnd.inputValue().asMatrix();
					this->removeMatrixScale(matrix1);

					inMatrixArrayHnd.jumpToArrayElement(intervalI + 1);
					MMatrix matrix2 = inMatrixArrayHnd.inputValue().asMatrix();
					this->removeMatrixScale(matrix2);

					parameterArrayHnd.jumpToArrayElement(i);
					double parameterF = parameterArrayHnd.inputValue().asDouble();

					blendRotArrayHnd.jumpToArrayElement(i);
					double blendRotF = blendRotArrayHnd.inputValue().asDouble();

					MVector outPos, outRot;

					this->computeSlerp(matrix1, matrix2, curve, parameterF, blendRotF, iniLengthF, currCurveLen, stretchF, globalScaleF, tangentAxisI, outPos, outRot);

                    MDataHandle outTranslateHnd = tbuilder.addElement(i);
                    outTranslateHnd.set3Double(outPos.x, outPos.y, outPos.z);

                    MDataHandle outRotateHnd = rbuilder.addElement(i);
                    double rotation[3];
                    outRotateHnd.set( outRot.x, outRot.y, outRot.z );

                    //this->output(outPos, outRot, i, outTranslateArrayHnd, outRotateArrayHnd);

				}

                outTranslateArrayHnd.set(tbuilder);
                outTranslateArrayHnd.setAllClean();

                outRotateArrayHnd.set(rbuilder);
                outRotateArrayHnd.setAllClean();
			}
            data.setClean(plug);

		}
		else
		{
			return MS::kUnknownParameter;
		}
	}

	return MS::kSuccess;
}
コード例 #5
0
ファイル: bciosVizNode.cpp プロジェクト: ahmidou/aphid
MStatus BCIViz::compute( const MPlug& plug, MDataBlock& block )
{
	if( plug == outValue ) {
		MStatus status;
		
		MDagPath path;
		MDagPath::getAPathTo(thisMObject(), path);
		
		MMatrix worldInverseSpace = path.inclusiveMatrixInverse();
		
		MDataHandle inputdata = block.inputValue(ainput, &status);
        if(status) {
			const MMatrix drvSpace = inputdata.asMatrix();
			fDriverPos.x = drvSpace(3, 0);
			fDriverPos.y = drvSpace(3, 1);
			fDriverPos.z = drvSpace(3, 2);
			
			fDriverPos *= worldInverseSpace;
		}
		
		fTargetPositions.clear();
		
		MArrayDataHandle htarget = block.inputArrayValue( atargets );
		unsigned numTarget = htarget.elementCount();
		
		fTargetPositions.setLength(numTarget);
		
		for(unsigned i = 0; i<numTarget; i++) {
			MDataHandle tgtdata = htarget.inputValue(&status);
			if(status) {
				const MMatrix tgtSpace = tgtdata.asMatrix();
				MPoint tgtPos(tgtSpace(3,0), tgtSpace(3,1), tgtSpace(3,2));
				tgtPos *= worldInverseSpace;
				MVector disp = tgtPos;
				disp.normalize();
				tgtPos = disp;
				fTargetPositions[i] = tgtPos;
			}
			htarget.next();
		}
		
		m_hitTriangle = 0;
		neighbourId[0] = 0;
		neighbourId[1] = 1;
		neighbourId[2] = 2;
		
		if(!checkTarget())
		{
			MGlobal::displayWarning("convex hull must have no less than 4 targes.");
			return MS::kSuccess;
		}
		
		if(!checkFirstFour(fTargetPositions))
		{
			MGlobal::displayWarning("first 4 targes cannot sit on the same plane.");
			return MS::kSuccess;
		}
		
		if(!constructHull())
		{
			MGlobal::displayWarning("convex hull failed on construction.");
			return MS::kSuccess;
		}

		findNeighbours();
		
		calculateWeight();

        MArrayDataHandle outputHandle = block.outputArrayValue( outValue );
		
		int numWeight = fTargetPositions.length();

		m_resultWeights.setLength(numWeight);
		
		for(int i=0; i < numWeight; i++) 
			m_resultWeights[i] = 0.0;
			
		m_resultWeights[neighbourId[0]] = fAlpha;
		m_resultWeights[neighbourId[1]] = fBeta;
		m_resultWeights[neighbourId[2]] = fGamma;
		
		MArrayDataBuilder builder(outValue, numWeight, &status);
		
		for(int i=0; i < numWeight; i++) {
			MDataHandle outWeightHandle = builder.addElement(i);
			outWeightHandle.set( m_resultWeights[i] );
			//MGlobal::displayInfo(MString("wei ") + i + " " + weights[i]);
		}
		
		outputHandle.set(builder);
		outputHandle.setAllClean();
    }

	return MS::kSuccess;
}
コード例 #6
0
ファイル: dynExprField.cpp プロジェクト: BigRoy/Maya-devkit
MStatus dynExprField::compute(const MPlug& plug, MDataBlock& block)
//
//	Descriptions:
//		compute output force.
//
{
	MStatus status;

	if( !(plug == mOutputForce) )
        return( MS::kUnknownParameter );

	// get the logical index of the element this plug refers to.
	//
	int multiIndex = plug.logicalIndex( &status );
	McheckErr(status, "ERROR in plug.logicalIndex.\n");

	// Get input data handle, use outputArrayValue since we do not
	// want to evaluate both inputs, only the one related to the
	// requested multiIndex. Evaluating both inputs at once would cause
	// a dependency graph loop.
	
	MArrayDataHandle hInputArray = block.outputArrayValue( mInputData, &status );
	McheckErr(status,"ERROR in hInputArray = block.outputArrayValue().\n");
	
	status = hInputArray.jumpToElement( multiIndex );
	McheckErr(status, "ERROR: hInputArray.jumpToElement failed.\n");
	
	// get children of aInputData.
	
	MDataHandle hCompond = hInputArray.inputValue( &status );
	McheckErr(status, "ERROR in hCompond=hInputArray.inputValue\n");
	
	MDataHandle hPosition = hCompond.child( mInputPositions );
	MObject dPosition = hPosition.data();
	MFnVectorArrayData fnPosition( dPosition );
	MVectorArray points = fnPosition.array( &status );
	McheckErr(status, "ERROR in fnPosition.array(), not find points.\n");
	
	// Comment out the following since velocity, and mass are 
	// not needed in this field.
	//
	// MDataHandle hVelocity = hCompond.child( mInputVelocities );
	// MObject dVelocity = hVelocity.data();
	// MFnVectorArrayData fnVelocity( dVelocity );
	// MVectorArray velocities = fnVelocity.array( &status );
	// McheckErr(status, "ERROR in fnVelocity.array(), not find velocities.\n");
	//
	// MDataHandle hMass = hCompond.child( mInputMass );
	// MObject dMass = hMass.data();
	// MFnDoubleArrayData fnMass( dMass );
	// MDoubleArray masses = fnMass.array( &status );
	// McheckErr(status, "ERROR in fnMass.array(), not find masses.\n");

	// The attribute mInputPPData contains the attribute in an array form 
	// parpared by the particleShape if the particleShape has per particle 
	// attribute fieldName_attrName.  
	//
	// Suppose a field with the name dynExprField1 is connecting to 
	// particleShape1, and the particleShape1 has per particle float attribute
	// dynExprField1_magnitude and vector attribute dynExprField1_direction,
	// then hInputPPArray will contains a MdoubleArray with the corresponding
	// name "magnitude" and a MvectorArray with the name "direction".  This 
	// is a mechanism to allow the field attributes being driven by dynamic 
	// expression.
	MArrayDataHandle mhInputPPData = block.inputArrayValue( mInputPPData, &status );
	McheckErr(status,"ERROR in mhInputPPData = block.inputArrayValue().\n");

	status = mhInputPPData.jumpToElement( multiIndex );
	McheckErr(status, "ERROR: mhInputPPArray.jumpToElement failed.\n");

	MDataHandle hInputPPData = mhInputPPData.inputValue( &status );
	McheckErr(status, "ERROR in hInputPPData = mhInputPPData.inputValue\n");

	MObject dInputPPData = hInputPPData.data();
	MFnArrayAttrsData inputPPArray( dInputPPData );

	MDataHandle hOwnerPPData = block.inputValue( mOwnerPPData, &status );
	McheckErr(status, "ERROR in hOwnerPPData = block.inputValue\n");

	MObject dOwnerPPData = hOwnerPPData.data();
	MFnArrayAttrsData ownerPPArray( dOwnerPPData );

	const MString magString("magnitude");
	MFnArrayAttrsData::Type doubleType(MFnArrayAttrsData::kDoubleArray);

	bool arrayExist;
	MDoubleArray magnitudeArray;
	arrayExist = inputPPArray.checkArrayExist(magString, doubleType, &status);
	// McheckErr(status, "ERROR in checkArrayExist(magnitude)\n");
	if(arrayExist) {
	    magnitudeArray = inputPPArray.getDoubleData(magString, &status);
	    // McheckErr(status, "ERROR in inputPPArray.doubleArray(magnitude)\n");
	}

	MDoubleArray magnitudeOwnerArray;
	arrayExist = ownerPPArray.checkArrayExist(magString, doubleType, &status);
	// McheckErr(status, "ERROR in checkArrayExist(magnitude)\n");
	if(arrayExist) {
	    magnitudeOwnerArray = ownerPPArray.getDoubleData(magString, &status);
	    // McheckErr(status, "ERROR in ownerPPArray.doubleArray(magnitude)\n");
	}

	const MString dirString("direction");
	MFnArrayAttrsData::Type vectorType(MFnArrayAttrsData::kVectorArray);

	arrayExist = inputPPArray.checkArrayExist(dirString, vectorType, &status);
        MVectorArray directionArray;
	// McheckErr(status, "ERROR in checkArrayExist(direction)\n");
	if(arrayExist) {
	    directionArray = inputPPArray.getVectorData(dirString, &status);
	    // McheckErr(status, "ERROR in inputPPArray.vectorArray(direction)\n");
	}

	arrayExist = ownerPPArray.checkArrayExist(dirString, vectorType, &status);
        MVectorArray directionOwnerArray;
	// McheckErr(status, "ERROR in checkArrayExist(direction)\n");
	if(arrayExist) {
	    directionOwnerArray = ownerPPArray.getVectorData(dirString, &status);
	    // McheckErr(status, "ERROR in ownerPPArray.vectorArray(direction)\n");
	}

	// Compute the output force.
	//
	MVectorArray forceArray;

	apply( block, points.length(), magnitudeArray, magnitudeOwnerArray, 
	       directionArray, directionOwnerArray, forceArray );

	// get output data handle
	//
	MArrayDataHandle hOutArray = block.outputArrayValue( mOutputForce, &status);
	McheckErr(status, "ERROR in hOutArray = block.outputArrayValue.\n");
	MArrayDataBuilder bOutArray = hOutArray.builder( &status );
	McheckErr(status, "ERROR in bOutArray = hOutArray.builder.\n");

	// get output force array from block.
	//
	MDataHandle hOut = bOutArray.addElement(multiIndex, &status);
	McheckErr(status, "ERROR in hOut = bOutArray.addElement.\n");

	MFnVectorArrayData fnOutputForce;
	MObject dOutputForce = fnOutputForce.create( forceArray, &status );
	McheckErr(status, "ERROR in dOutputForce = fnOutputForce.create\n");

	// update data block with new output force data.
	//
	hOut.set( dOutputForce );
	block.setClean( plug );

	return( MS::kSuccess );
}
コード例 #7
0
ファイル: pushDeformer.cpp プロジェクト: kattkieru/MayaNodes
MStatus PushDeformer::deform(MDataBlock& dataBlock,
								MItGeometry& itGeo,
								const MMatrix& localToWorldMatrix,
								unsigned int geomIndex)
{
	MStatus status;
	//get attribute handles
	double bulgeAmount = dataBlock.inputValue(aAmount, &status).asDouble();
	CHECK_MSTATUS_AND_RETURN_IT(status);
	m_taskData.envelope = dataBlock.inputValue(envelope, &status).asFloat();
	CHECK_MSTATUS_AND_RETURN_IT(status);
	bool useStressV = dataBlock.inputValue(aUseStress, &status).asBool();
	CHECK_MSTATUS_AND_RETURN_IT(status);
	int multiThreadingType = dataBlock.inputValue(aMultiThreadingType, &status).asBool();
	CHECK_MSTATUS_AND_RETURN_IT(status);

	if (m_taskData.envelope <= 0.001)
	{
		return MS::kSuccess;
	}
	// if the use stress plug is turned on pull 
	MDoubleArray stressV;
	if (useStressV == true)
	{
		//pull out the raw data as an Mobject
		MObject stressMap = dataBlock.inputValue(aStressMap, &status).data();
		CHECK_MSTATUS_AND_RETURN_IT(status);
		MFnDoubleArrayData stressDataFn(stressMap);
    m_taskData.stressV = stressDataFn.array();
	}

	//retrieve the handle to the output array attribute
	MArrayDataHandle hInput = dataBlock.outputArrayValue(input, &status);
	CHECK_MSTATUS_AND_RETURN_IT(status);
	//get the input array index handle
	status = hInput.jumpToElement(geomIndex);
	//get the handle of geomIndex attribute
	MDataHandle hInputElement = hInput.outputValue(&status);
	CHECK_MSTATUS_AND_RETURN_IT(status);
	//Get the MObject of the input geometry of geomindex
	MObject oInputGeom = hInputElement.child(inputGeom).asMesh();
	MFnMesh fnMesh(oInputGeom, &status);
	CHECK_MSTATUS_AND_RETURN_IT(status);

  
	fnMesh.getVertexNormals(false, m_taskData.normals, MSpace::kWorld);
	itGeo.allPositions(m_taskData.points, MSpace::kWorld);
  //MGlobal::displayInfo( "test" );
  /*for (int i = 0; i < itGeo.count();  i++)
	{
    MGlobal::displayInfo( MFnAttribute(weightList).isArray );
  }*/
  m_taskData.bulgeAmount = bulgeAmount;

  if(multiThreadingType == 1)
  {
    ThreadData* pThreadData = createThreadData( NUM_TASKS, &m_taskData );
    MThreadPool::newParallelRegion( createTasks, (void*)pThreadData );
    itGeo.setAllPositions(m_taskData.points);
    delete [] pThreadData;
    return MS::kSuccess;
  }


  else if(multiThreadingType == 2)
  {
    tbb::parallel_for(size_t(0), size_t(itGeo.count()), [this](size_t i)
    {
		  //const float w = weightValue(dataBlock, geomIndex, i);
      const float w = 1.0;
		  if (m_taskData.useStressV == true && (m_taskData.stressV.length() > 0))
		  {
			  //deform
			  m_taskData.points[i] += (MVector(m_taskData.normals[i]) * m_taskData.bulgeAmount * m_taskData.envelope * w * m_taskData.stressV[i]);
		  }
		  else
		  {
			  //deform
        m_taskData.points[i] += m_taskData.normals[i] * m_taskData.bulgeAmount * m_taskData.envelope * w;
		  }  
  
    });
  }

  
	//
  else if(multiThreadingType == 3)
  #pragma omp parallel for 

  for (int i = 0; i < itGeo.count();  i++)
	{
		float w = weightValue(dataBlock, geomIndex, itGeo.index());
		if (useStressV == true && (stressV.length() > 0))
		{
			//deform
      m_taskData.points[i] += (MVector(m_taskData.normals[i]) * bulgeAmount * m_taskData.envelope * w * m_taskData.stressV[i]);
			
		}
		else
		{
			//deform
      m_taskData.points[i] += m_taskData.normals[i] * bulgeAmount * m_taskData.envelope * w;

		}
	}
  else
  {
    for (; !itGeo.isDone(); itGeo.next())
	  {
		  float w = weightValue(dataBlock, geomIndex, itGeo.index());
		  if (useStressV == true && (stressV.length() > 0))
		  {
			  //deform
        m_taskData.points[itGeo.index()] += (MVector(m_taskData.normals[itGeo.index()]) * bulgeAmount * m_taskData.envelope * w * m_taskData.stressV[itGeo.index()]);
			
		  }
		  else
		  {
			  //deform
        m_taskData.points[itGeo.index()] += m_taskData.normals[itGeo.index()] * bulgeAmount * m_taskData.envelope * w;
		  }
	  }
  }
	itGeo.setAllPositions(m_taskData.points);

	return MS::kSuccess;

}
コード例 #8
0
ファイル: testDeformer.cpp プロジェクト: yaoyansi/mymagicbox
void TestDeformer::initVertMapping(MDataBlock& data,
                          MItGeometry& iter,
                          const MMatrix& localToWorldMatrix,
                          unsigned int mIndex)
{
    MStatus status;


    MArrayDataHandle vertMapOutArrayData = data.outputArrayValue( vert_map, &status );
    CHECK_MSTATUS( status );

    // use vertMapOutArrayBuilder to modify vertMapOutArrayData
    iter.reset();
    int count = iter.count();
    MArrayDataBuilder vertMapOutArrayBuilder( vert_map, count, &status );
    CHECK_MSTATUS( status );


    MPointArray allPts;// world vertex position of the driven mesh
    allPts.clear();

    // walk through the driven mesh
    /// copy MItGeometry's vertex to vertMapOutArrayData
    int i = 0;
    while( !iter.isDone(&status) )
    {
        CHECK_MSTATUS( status );

        MDataHandle initIndexDataHnd = vertMapOutArrayBuilder.addElement( i, &status );
        CHECK_MSTATUS( status );

        int negIndex = -1;

        initIndexDataHnd.setInt( negIndex );
        initIndexDataHnd.setClean();

        // append a vertex position(world coordination) to allPts
        CHECK_MSTATUS(allPts.append( iter.position() * localToWorldMatrix ));
        i = i+1;
        iter.next();
    }
    CHECK_MSTATUS(vertMapOutArrayData.set( vertMapOutArrayBuilder ));




    /// Append more vertex from each driver mesh to vertMapOutArrayData
    MArrayDataHandle meshAttrHandle = data.inputArrayValue( driver_mesh, &status );
    CHECK_MSTATUS( status );

    int numMeshes = meshAttrHandle.elementCount();
    __debug("%s(), numMeshes=%d", __FUNCTION__, numMeshes);

    CHECK_MSTATUS(meshAttrHandle.jumpToElement(0));
    for( int meshIndex=0; meshIndex < numMeshes; ++meshIndex )
    {
        __debug("%s(), meshIndex=%d", __FUNCTION__, meshIndex);

        MDataHandle currentMesh = meshAttrHandle.inputValue(&status);
        CHECK_MSTATUS(status);

        MObject meshMobj = currentMesh.asMesh();
        __debug("%s(), meshMobj.apiTypeStr()=%s", __FUNCTION__, meshMobj.apiTypeStr());

        __debugMeshInfo(__FUNCTION__, meshMobj);
        {
            _initVertMapping_on_one_mesh(meshMobj, vertMapOutArrayBuilder, allPts);// Note: vertMapOutArrayBuilder is updated in this function!
            //CHECK_MSTATUS(vertMapOutArrayData.set( vertMapOutArrayBuilder ));
        }

        if( !meshAttrHandle.next() )
        {
            break;
        }
    }// for (mesh
    CHECK_MSTATUS(vertMapOutArrayData.set( vertMapOutArrayBuilder ));



}
コード例 #9
0
ファイル: sweptEmitter.cpp プロジェクト: DimondTheCat/xray
MStatus sweptEmitter::compute(const MPlug& plug, MDataBlock& block)
//
//	Descriptions:
//		Call emit emit method to generate new particles.
//
{
	MStatus status;

	// Determine if we are requesting the output plug for this emitter node.
	//
	if( !(plug == mOutput) )
        return( MS::kUnknownParameter );

	// Get the logical index of the element this plug refers to,
	// because the node can be emitting particles into more 
    // than one particle shape.
	//
	int multiIndex = plug.logicalIndex( &status );
	McheckErr(status, "ERROR in plug.logicalIndex.\n");

	// Get output data arrays (position, velocity, or parentId)
	// that the particle shape is holding from the previous frame.
	//
	MArrayDataHandle hOutArray = block.outputArrayValue(mOutput, &status);
	McheckErr(status, "ERROR in hOutArray = block.outputArrayValue.\n");

	// Create a builder to aid in the array construction efficiently.
	//
	MArrayDataBuilder bOutArray = hOutArray.builder( &status );
	McheckErr(status, "ERROR in bOutArray = hOutArray.builder.\n");

	// Get the appropriate data array that is being currently evaluated.
	//
	MDataHandle hOut = bOutArray.addElement(multiIndex, &status);
	McheckErr(status, "ERROR in hOut = bOutArray.addElement.\n");

    // Get the data and apply the function set.
    //
    MFnArrayAttrsData fnOutput;
    MObject dOutput = fnOutput.create ( &status );
    McheckErr(status, "ERROR in fnOutput.create.\n");

	// Check if the particle object has reached it's maximum,
	// hence is full. If it is full then just return with zero particles.
	//
	bool beenFull = isFullValue( multiIndex, block );
	if( beenFull )
	{
		return( MS::kSuccess );
	}

	// Get deltaTime, currentTime and startTime.
	// If deltaTime <= 0.0, or currentTime <= startTime,
	// do not emit new pariticles and return.
	//
	MTime cT = currentTimeValue( block );
	MTime sT = startTimeValue( multiIndex, block );
	MTime dT = deltaTimeValue( multiIndex, block );
	if( (cT <= sT) || (dT <= 0.0) )
	{
		// We do not emit particles before the start time, 
		// and do not emit particles when moving backwards in time.
		// 

		// This code is necessary primarily the first time to 
		// establish the new data arrays allocated, and since we have 
		// already set the data array to length zero it does 
		// not generate any new particles.
		// 
		hOut.set( dOutput );
		block.setClean( plug );

		return( MS::kSuccess );
	}

	// Get speed, direction vector, and inheritFactor attributes.
	//
	double speed = speedValue( block );
	MVector dirV = directionVector( block );
	double inheritFactor = inheritFactorValue( multiIndex, block );

	// Get the position and velocity arrays to append new particle data.
	//
	MVectorArray fnOutPos = fnOutput.vectorArray("position", &status);
	MVectorArray fnOutVel = fnOutput.vectorArray("velocity", &status);

	// Convert deltaTime into seconds.
	//
	double dt = dT.as( MTime::kSeconds );
	
	// Apply rotation to the direction vector
	MVector rotatedV = useRotation ( dirV );


	// position,
	MVectorArray inPosAry;
	// velocity
	MVectorArray inVelAry;
	// emission rate
	MIntArray emitCountPP;


	// Get the swept geometry data
	//
	MObject thisObj = this->thisMObject();
	MPlug sweptPlug( thisObj, mSweptGeometry );

	if ( sweptPlug.isConnected() ) 
	{
		MDataHandle sweptHandle = block.inputValue( mSweptGeometry );
		// MObject sweptData = sweptHandle.asSweptGeometry();
		MObject sweptData = sweptHandle.data();
		MFnDynSweptGeometryData fnSweptData( sweptData );


		// Curve emission
		//
		if (fnSweptData.lineCount() > 0) {
			int numLines = fnSweptData.lineCount();
		
			for ( int i=0; i<numLines; i++ )
			{
				inPosAry.clear();
				inVelAry.clear();
				emitCountPP.clear();

				MDynSweptLine line = fnSweptData.sweptLine( i );

				// ... process current line ...
				MVector p1 = line.vertex( 0 );
				MVector p2 = line.vertex( 1 );

				inPosAry.append( p1 );
				inPosAry.append( p2 );

				inVelAry.append( MVector( 0,0,0 ) );
				inVelAry.append( MVector( 0,0,0 ) );

				// emit Rate for two points on line
				emitCountPP.clear();
				status = emitCountPerPoint( plug, block, 2, emitCountPP );

				emit( inPosAry, inVelAry, emitCountPP,
					dt, speed, inheritFactor, rotatedV, fnOutPos, fnOutVel );

			}
		}

		// Surface emission (nurb or polygon)
		//
		if (fnSweptData.triangleCount() > 0) {
			int numTriangles = fnSweptData.triangleCount();
		
			for ( int i=0; i<numTriangles; i++ )
			{
				inPosAry.clear();
				inVelAry.clear();
				emitCountPP.clear();

				MDynSweptTriangle tri = fnSweptData.sweptTriangle( i );

				// ... process current triangle ...
				MVector p1 = tri.vertex( 0 );
				MVector p2 = tri.vertex( 1 );
				MVector p3 = tri.vertex( 2 );

				MVector center = p1 + p2 + p3;
				center /= 3.0;

				inPosAry.append( center );

				inVelAry.append( MVector( 0,0,0 ) );

				// emit Rate for two points on line
				emitCountPP.clear();
				status = emitCountPerPoint( plug, block, 1, emitCountPP );

				emit( inPosAry, inVelAry, emitCountPP,
					dt, speed, inheritFactor, rotatedV, fnOutPos, fnOutVel );

			}
		}
	}

	// Update the data block with new dOutput and set plug clean.
	//
	hOut.set( dOutput );
	block.setClean( plug );

	return( MS::kSuccess );
}
コード例 #10
0
MStatus CageDeformerNode::deform( MDataBlock& data, MItGeometry& itGeo, const MMatrix &localToWorldMatrix, unsigned int mIndex )
{
    /// main
    MStatus status;
    MThreadUtils::syncNumOpenMPThreads();    // for OpenMP
    // load cage mesh and other attributes
    MObject oCageMesh = data.inputValue( aCageMesh ).asMesh();
    short blendMode = data.inputValue(aBlendMode).asShort();
	bool rotationCosistency = data.inputValue( aRotationConsistency ).asBool();
	bool frechetSum = data.inputValue( aFrechetSum ).asBool();
    short newConstraintMode = data.inputValue(aConstraintMode).asShort();
    double newConstraintWeight = data.inputValue( aConstraintWeight ).asDouble();
    if ( oCageMesh.isNull() || blendMode == 99)
        return MS::kSuccess;
    short newCageMode = data.inputValue(aCageMode).asShort();
    MFnMesh fnCageMesh( oCageMesh, &status );
    CHECK_MSTATUS_AND_RETURN_IT( status );
    MPointArray cagePoints;
    fnCageMesh.getPoints( cagePoints,  MSpace::kWorld );
    // save initial cage state
    if (initCagePoints.length() != cagePoints.length()){
        initCageMesh = oCageMesh;
        initCagePoints=cagePoints;
    }
    // when cage mode is changed
    if(newCageMode != cageMode || newConstraintMode != constraintMode || newConstraintWeight != constraintWeight)
    {
        cageMode = newCageMode;
        constraintMode = newConstraintMode;
        constraintWeight = newConstraintWeight;
	    std::vector<double> tetWeight;
        // read target mesh data
        MArrayDataHandle hInput = data.outputArrayValue( input, &status );
        CHECK_MSTATUS_AND_RETURN_IT( status );
        status = hInput.jumpToElement( mIndex );
        CHECK_MSTATUS_AND_RETURN_IT( status );
        MObject oInputGeom = hInput.outputValue().child( inputGeom ).asMesh();
        MFnMesh inputMesh(oInputGeom);
        inputMesh.getPoints( pts );
		numPts=pts.length();
        for(int j=0; j<numPts; j++ )
            pts[j] *= localToWorldMatrix;
        MIntArray count;
        inputMesh.getTriangles( count, meshTriangles );
		numTet=meshTriangles.length()/3;
		std::vector<Matrix4d> P(numTet);
        tetCenter.resize(numTet);
        tetMatrixC(pts, meshTriangles, P, tetCenter);
        PI.resize(numTet);
		for(int i=0;i<numTet;i++)
			PI[i] = P[i].inverse();
        // prepare cage tetrahedra
        MFnMesh fnInitCageMesh( initCageMesh, &status );
        if(cageMode == 10 || cageMode == 11)  // face mode
        {
			if(cageMode == 10){       // triangulate faces by MAYA standard
                MIntArray count;
                fnInitCageMesh.getTriangles( count, triangles );
                tetWeight.resize(triangles.length()/3, 1.0f);
			}else if(cageMode ==11){  // trianglate faces with more than 3 edges in a symmetric way
				triangles.clear();
				MItMeshPolygon iter(initCageMesh);
				MIntArray tmp;
                MVector normal;
				tetWeight.reserve(4*iter.count());
                unsigned int l;
				for(unsigned int i=0; ! iter.isDone(); i++){
					iter.getVertices(tmp);
					l=tmp.length();
					if(l==3){
						tetWeight.push_back(1.0);
						triangles.append(tmp[0]);
						triangles.append(tmp[1]);
						triangles.append(tmp[2]);
					}else{
						for(unsigned int j=0;j<l;j++){
                            tetWeight.push_back((l-2.0)/l);
							triangles.append(tmp[j]);
							triangles.append(tmp[(j+1) % l]);
							triangles.append(tmp[(j+2) % l]);
						}
					}
					iter.next();
				}
            }
            // face mode compute init matrix
            numPrb=triangles.length()/3;
            initMatrix.resize(numPrb);
            tetMatrix(initCagePoints, triangles, cageMode, initMatrix);
            // compute weight
            w.resize(numTet);
            std::vector< std::vector<double> > idist(numTet);
            for(int j=0;j<numTet;j++){
                idist[j].resize(numPrb);
                w[j].resize(numPrb);
                double sidist = 0.0;
                for(int i=0;i<numPrb;i++){
                    idist[j][i] = tetWeight[i]/distPtTri(tetCenter[j],initMatrix[i]);
                    sidist += idist[j][i];
                }
                assert(sidist>0.0f);
                for(int i=0;i<numPrb;i++)
                    w[j][i] = idist[j][i] /sidist;
            }// face mode end
        }else if(cageMode == 0 || cageMode == 1){   // vertex mode
            triangles.clear();
            std::vector<int> tetCount(initCagePoints.length());
            MItMeshVertex iter(initCageMesh);
            for(int j=0; ! iter.isDone(); j++){
                MIntArray v;
                iter.getConnectedVertices(v);     // at each vertex, construct tetrahedra from connected edges
                int l=v.length();
                if(l==3){
                    if(isDegenerate(initCagePoints[j],initCagePoints[v[0]],initCagePoints[v[1]],initCagePoints[v[2]]) != 0){
                        tetCount[j]++;
                        triangles.append(j);
                        triangles.append(v[0]);
                        triangles.append(v[1]);
                        triangles.append(v[2]);
                    }
                }else{
                    for(int k=0;k<l;k++){
                        if(isDegenerate(initCagePoints[j],initCagePoints[v[k]],initCagePoints[v[(k+1) % l]],initCagePoints[v[(k+2) % l]]) != 0){
                            tetCount[j]++;
                            triangles.append(j);
                            triangles.append(v[k]);
                            triangles.append(v[(k+1) % l]);
                            triangles.append(v[(k+2) % l]);
                        }
                    }
                }
                iter.next();
            }
            numPrb=triangles.length()/4;
            initMatrix.resize(numPrb);
            tetMatrix(initCagePoints, triangles, cageMode, initMatrix);
            // vertex mode compute weight
            w.resize(numTet);
            std::vector< std::vector<double> > idist(numTet);
            tetWeight.resize(numPrb);
            for(int i=0;i<numPrb;i++)
                tetWeight[i]=1.0/(double)tetCount[triangles[4*i]];
            for(int j=0;j<numTet;j++){
                idist[j].resize(numPrb);
                w[j].resize(numPrb);
                double sidist = 0.0;
                for(int i=0;i<numPrb;i++){
                    Vector3d c(initCagePoints[triangles[4*i]].x,initCagePoints[triangles[4*i]].y,initCagePoints[triangles[4*i]].z);
                    idist[j][i] = tetWeight[i] / ((tetCenter[j]-c).squaredNorm());
                    sidist += idist[j][i];
                }
                assert(sidist>0.0f);
                for(int i=0;i<numPrb;i++)
                    w[j][i] = idist[j][i] /sidist;
            }
        }else if(cageMode == 5 || cageMode == 6 ){ // vertex averaged normal mode
            triangles.clear();
            std::vector<int> tetCount(initCagePoints.length());
            MItMeshVertex iter(initCageMesh);
            for(int j=0; ! iter.isDone(); j++){
                MIntArray v;
                iter.getConnectedVertices(v);
                int l=v.length();
                for(int k=0;k<l;k++){
                    tetCount[j]++;
                    triangles.append(j);
                    triangles.append(v[k]);
                    triangles.append(v[(k+1) % l]);
                }
                iter.next();
            }
            numPrb=triangles.length()/3;
            initMatrix.resize(numPrb);
            tetMatrix(initCagePoints, triangles, cageMode, initMatrix);
            // vertex mode compute weight
            w.resize(numTet);
            std::vector< std::vector<double> > idist(numTet);
            tetWeight.resize(numPrb);
            for(int i=0;i<numPrb;i++)
                tetWeight[i]=1.0/(double)tetCount[triangles[3*i]];
            for(int j=0;j<numTet;j++){
                idist[j].resize(numPrb);
                w[j].resize(numPrb);
                double sidist = 0.0;
                for(int i=0;i<numPrb;i++){
                    Vector3d c(initCagePoints[triangles[3*i]].x,initCagePoints[triangles[3*i]].y,initCagePoints[triangles[3*i]].z);
                    idist[j][i] = tetWeight[i] / ((tetCenter[j]-c).squaredNorm());
                    sidist += idist[j][i];
                }
                assert(sidist>0.0f);
                for(int i=0;i<numPrb;i++)
                    w[j][i] = idist[j][i] /sidist;
            }
        }// end of cage setup
        
        // find constraint points
        if(constraintMode == 1){
            numConstraint = numPrb;
        }else{
            numConstraint = 1;    // at least one constraint is necessary to determine global translation
        }
        constraintTet.resize(numConstraint);
        constraintVector.resize(numConstraint);
        // for each cage tetrahedra, constraint the point on the mesh with largest weight
        for(int i=0;i<numConstraint;i++){
            constraintTet[i] = 0;
            for(int j=1;j<numTet;j++){
                if(w[j][i] > w[constraintTet[i]][i]){
                    constraintTet[i] = j;
                }
            }
            constraintVector[i] << tetCenter[constraintTet[i]](0), tetCenter[constraintTet[i]](1), tetCenter[constraintTet[i]](2), 1.0;
        }
        // precompute arap solver
        arapHI(PI, meshTriangles);
    }
    // compute deformation
    if( ! rotationCosistency || numPrb != prevNs.size()){        // clear previous rotation
        prevThetas.clear();
        prevThetas.resize(numPrb, 0.0);
        prevNs.clear();
        prevNs.resize(numPrb, Vector3d::Zero());
    }
    //  find affine transformations for tetrahedra
    std::vector<Matrix4d> cageMatrix(numPrb), SE(numPrb), logSE(numPrb),logAff(numPrb),aff(numPrb);
    std::vector<Matrix3d> logR(numPrb),R(numPrb),logS(numPrb),logGL(numPrb);
    std::vector<Vector3d> L(numPrb);
    std::vector<Vector4d> quat(numPrb);
    tetMatrix(cagePoints, triangles, cageMode, cageMatrix);
    for(int i=0; i<numPrb; i++)
        aff[i]=initMatrix[i].inverse()*cageMatrix[i];
    // compute parametrisation
    if(blendMode == 0 || blendMode == 1 || blendMode == 5)  // polarexp or quaternion
    {
        for(unsigned int i=0;i<numPrb;i++){
            parametriseGL(aff[i].block(0,0,3,3), logS[i] ,R[i]);
            L[i] = transPart(aff[i]);
            if(blendMode == 0){  // Rotational log
                logR[i]=logSOc(R[i], prevThetas[i], prevNs[i]);
            }else if(blendMode == 1){ // Eucledian log
                SE[i]=affine(R[i], L[i]);
                logSE[i]=logSEc(SE[i], prevThetas[i], prevNs[i]);
            }else if(blendMode == 5){ // quaternion
                Quaternion<double> Q(R[i].transpose());
                quat[i] << Q.x(), Q.y(), Q.z(), Q.w();
            }
        }
    }else if(blendMode == 2){    //logmatrix3
        for(unsigned int i=0;i<numPrb;i++){
            logGL[i] = aff[i].block(0,0,3,3).log();
            L[i] = transPart(aff[i]);
        }
    }else if(blendMode == 3){   // logmatrix4
        for(unsigned int i=0;i<numPrb;i++){
            logAff[i] = aff[i].log();
        }
    }
    // compute blended matrices
#pragma omp parallel for
    std::vector<Matrix4d> At(numTet);
    for(int j=0; j<numTet; j++ ){
        if(blendMode==0){
            Matrix3d RR=Matrix3d::Zero();
            Matrix3d SS=Matrix3d::Zero();
            Vector3d l=Vector3d::Zero();
            for(unsigned int i=0; i<numPrb; i++){
                RR += w[j][i] * logR[i];
                SS += w[j][i] * logS[i];
                l += w[j][i] * L[i];
            }
            SS = expSym(SS);
            if(frechetSum){
                RR = frechetSO(R, w[j]);
            }else{
                RR = expSO(RR);
            }
            At[j] = affine(SS*RR, l);
        }else if(blendMode==1){    // rigid transformation
            Matrix4d EE=Matrix4d::Zero();
            Matrix3d SS=Matrix3d::Zero();
            for(unsigned int i=0; i<numPrb; i++){
                EE +=  w[j][i] * logSE[i];
                SS +=  w[j][i] * logS[i];
            }
            if(frechetSum){
                EE = frechetSE(SE, w[j]);
            }else{
                EE = expSE(EE);
            }
            At[j] = affine(expSym(SS),Vector3d::Zero())*EE;
        }else if(blendMode == 2){    //logmatrix3
            Matrix3d G=Matrix3d::Zero();
            Vector3d l=Vector3d::Zero();
            for(unsigned int i=0; i<numPrb; i++){
                G +=  w[j][i] * logGL[i];
                l += w[j][i] * L[i];
            }
            At[j] = affine(G.exp(), l);
        }else if(blendMode == 3){   // logmatrix4
            Matrix4d A=Matrix4d::Zero();
            for(unsigned int i=0; i<numPrb; i++)
                A +=  w[j][i] * logAff[i];
            At[j] = A.exp();
        }else if(blendMode == 5){ // quaternion
            Vector4d q=Vector4d::Zero();
            Matrix3d SS=Matrix3d::Zero();
            Vector3d l=Vector3d::Zero();
            for(unsigned int i=0; i<numPrb; i++){
                q += w[j][i] * quat[i];
                SS += w[j][i] * logS[i];
                l += w[j][i] * L[i];
            }
            SS = expSym(SS);
            Quaternion<double> Q(q);
            Matrix3d RR = Q.matrix().transpose();
            At[j] = affine(SS*RR, l);
        }else if(blendMode==10){
            At[j] = Matrix4d::Zero();
            for(unsigned int i=0; i<numPrb; i++){
                At[j] += w[j][i] * aff[i];
            }
        }
    }
    
    // compute target vertices position
    MatrixXd G=MatrixXd::Zero(numTet+numPts,3);
    arapG(At, PI, meshTriangles, aff, G);
    MatrixXd Sol = solver.solve(G);
    for(unsigned int i=0;i<numPts;i++){
        pts[i].x=Sol(i,0);
        pts[i].y=Sol(i,1);
        pts[i].z=Sol(i,2);
        pts[i] *= localToWorldMatrix.inverse();
    }
    itGeo.setAllPositions(pts);
    return MS::kSuccess;
}
コード例 #11
0
MStatus AlembicCurvesNode::compute(const MPlug &plug, MDataBlock &dataBlock)
{
  ESS_PROFILE_SCOPE("AlembicCurvesNode::compute");
  MStatus status;

  // update the frame number to be imported
  const double inputTime =
      dataBlock.inputValue(mTimeAttr).asTime().as(MTime::kSeconds);
  MString &fileName = dataBlock.inputValue(mFileNameAttr).asString();
  MString &identifier = dataBlock.inputValue(mIdentifierAttr).asString();

  // check if we have the file
  if (fileName != mFileName || identifier != mIdentifier) {
    mSchema.reset();
    if (fileName != mFileName) {
      delRefArchive(mFileName);
      mFileName = fileName;
      addRefArchive(mFileName);
    }
    mIdentifier = identifier;

    // get the object from the archive
    Abc::IObject iObj = getObjectFromArchive(mFileName, identifier);
    if (!iObj.valid()) {
      MGlobal::displayWarning("[ExocortexAlembic] Identifier '" + identifier +
                              "' not found in archive '" + mFileName + "'.");
      return MStatus::kFailure;
    }
    AbcG::ICurves obj(iObj, Abc::kWrapExisting);
    if (!obj.valid()) {
      MGlobal::displayWarning("[ExocortexAlembic] Identifier '" + identifier +
                              "' in archive '" + mFileName +
                              "' is not a Curves.");
      return MStatus::kFailure;
    }
    mObj = obj;
    mSchema = obj.getSchema();
    mCurvesData = MObject::kNullObj;
  }

  if (!mSchema.valid()) {
    return MStatus::kFailure;
  }

  {
    ESS_PROFILE_SCOPE("AlembicCurvesNode::compute readProps");
    Alembic::Abc::ICompoundProperty arbProp = mSchema.getArbGeomParams();
    Alembic::Abc::ICompoundProperty userProp = mSchema.getUserProperties();
    readProps(inputTime, arbProp, dataBlock, thisMObject());
    readProps(inputTime, userProp, dataBlock, thisMObject());

    // Set all plugs as clean
    // Even if one of them failed to get set,
    // trying again in this frame isn't going to help
    for (unsigned int i = 0; i < mGeomParamPlugs.length(); i++) {
      dataBlock.outputValue(mGeomParamPlugs[i]).setClean();
    }

    for (unsigned int i = 0; i < mUserAttrPlugs.length(); i++) {
      dataBlock.outputValue(mUserAttrPlugs[i]).setClean();
    }
  }

  // get the sample
  SampleInfo sampleInfo = getSampleInfo(inputTime, mSchema.getTimeSampling(),
                                        mSchema.getNumSamples());

  // check if we have to do this at all
  if (!mCurvesData.isNull() &&
      mLastSampleInfo.floorIndex == sampleInfo.floorIndex &&
      mLastSampleInfo.ceilIndex == sampleInfo.ceilIndex) {
    return MStatus::kSuccess;
  }

  mLastSampleInfo = sampleInfo;
  const float blend = (float)sampleInfo.alpha;

  // access the camera values
  AbcG::ICurvesSchema::Sample sample;
  AbcG::ICurvesSchema::Sample sample2;
  mSchema.get(sample, sampleInfo.floorIndex);
  if (blend != 0.0f) {
    mSchema.get(sample2, sampleInfo.ceilIndex);
  }

  Abc::P3fArraySamplePtr samplePos = sample.getPositions();
  Abc::P3fArraySamplePtr samplePos2 = sample2.getPositions();
  Abc::Int32ArraySamplePtr nbVertices = sample.getCurvesNumVertices();
  const bool applyBlending =
      (blend == 0.0f) ? false : (samplePos->size() == samplePos2->size());

  Abc::FloatArraySamplePtr pKnotVec = getKnotVector(mObj);
  Abc::UInt16ArraySamplePtr pOrders = getCurveOrders(mObj);

  MArrayDataHandle arrh = dataBlock.outputArrayValue(mOutGeometryAttr);
  MArrayDataBuilder builder = arrh.builder();

  // reference:
  // http://download.autodesk.com/us/maya/2010help/API/multi_curve_node_8cpp-example.html

  const int degree = (sample.getType() == AbcG::kCubic) ? 3 : 1;
  const bool closed = (sample.getWrap() == AbcG::kPeriodic);
  unsigned int pointOffset = 0;
  unsigned int knotOffset = 0;
  for (int ii = 0; ii < nbVertices->size(); ++ii) {
    const unsigned int nbCVs = (unsigned int)nbVertices->get()[ii];
    const int ldegree = (pOrders) ? pOrders->get()[ii] : degree;
    const int nbSpans = (int)nbCVs - ldegree;

    MDoubleArray knots;
    if (pKnotVec) {
      const unsigned int nb_knot = nbCVs + ldegree - 1;
      for (unsigned int i = 0; i < nb_knot; ++i) {
        knots.append(pKnotVec->get()[knotOffset + i]);
      }
      knotOffset += nb_knot;
    }
    else {
      for (int span = 0; span <= nbSpans; ++span) {
        knots.append(double(span));
        if (span == 0 || span == nbSpans) {
          for (int m = 1; m < degree; ++m) {
            knots.append(double(span));
          }
        }
      }
    }

    MPointArray points;
    if (samplePos->size() > 0) {
      points.setLength((unsigned int)nbCVs);
      if (applyBlending) {
        for (unsigned int i = 0; i < nbCVs; ++i) {
          const Abc::P3fArraySample::value_type &vals1 =
              samplePos->get()[pointOffset + i];
          const Abc::P3fArraySample::value_type &vals2 =
              samplePos2->get()[pointOffset + i];
          MPoint &pt = points[i];

          pt.x = vals1.x + (vals2.x - vals1.x) * blend;
          pt.y = vals1.y + (vals2.y - vals1.y) * blend;
          pt.z = vals1.z + (vals2.z - vals1.z) * blend;
        }
      }
      else {
        for (unsigned int i = 0; i < nbCVs; ++i) {
          const Abc::P3fArraySample::value_type &vals =
              samplePos->get()[pointOffset + i];
          MPoint &pt = points[i];
          pt.x = vals.x;
          pt.y = vals.y;
          pt.z = vals.z;
        }
      }
      pointOffset += nbCVs;
    }

    // create a subd either with or without uvs
    MObject mmCurvesData = MFnNurbsCurveData().create();
    if (ldegree == 1 || ldegree == 3)
      mCurves.create(points, knots, ldegree,
                     closed ? MFnNurbsCurve::kClosed : MFnNurbsCurve::kOpen,
                     false, false, mmCurvesData);
    builder.addElement(ii).set(mmCurvesData);
  }
  arrh.set(builder);
  arrh.setAllClean();
  return MStatus::kSuccess;
}
コード例 #12
0
ファイル: puttyNode.cpp プロジェクト: Leopardob/puttynodes
MStatus puttyNode::deform( MDataBlock& block, MItGeometry& iter, const MMatrix& worldMatrix, unsigned int multiIndex)
{
//	MGlobal::displayInfo("deform");
    MStatus status = MS::kSuccess;

    /////////////////////////////////////////////////////////////////////////////////////////////////
    //
    // get inputs
    //
	
	// get the node ready flag
	MDataHandle dh = block.inputValue(aScriptSourced,&status);
	SYS_ERROR_CHECK(status, "Error getting aScriptSourced data handle\n");
	bool scriptSourced = dh.asBool();
	if (!scriptSourced)
		return MS::kSuccess;


	dh = block.inputValue(aNodeReady,&status);
	SYS_ERROR_CHECK(status, "Error getting node ready data handle\n");
	bool nodeReady = dh.asBool();

	// if it's not ready, don't do anything
	if (!nodeReady)
		return MS::kSuccess;

    dh = block.inputValue(aDefSpace,&status);
    SYS_ERROR_CHECK(status, "Error getting defSpace data handle\n");
    short defSpace = dh.asShort();
    
    dh = block.inputValue(aDefWeights,&status);
    SYS_ERROR_CHECK(status, "Error getting defWeights data handle\n");
    short defWeights = dh.asShort();
 
    dh = block.inputValue(aDefEnvelope,&status);
    SYS_ERROR_CHECK(status, "Error getting defEnvelope data handle\n");
    short defEnvelope = dh.asShort();
    

    
    // get the command
    dh = block.inputValue(aCmdBaseName,&status);
    SYS_ERROR_CHECK(status, "Error getting aCmdBaseName  handle\n");    
    MString script =  dh.asString(); 
        
 /*   if (script == "")
    {
        status = MS::kFailure;
        USER_ERROR_CHECK(status, "no script provided!\n");    
    }
   */ 
    /////////////////////////////////////////////////////////////////////////////////////////////////
    //
    // build mel cmd string
    //
    
    // check if it's a valid cmd
        
   
    // get the envelope
    //
    double env = 1;
    
    if (defEnvelope == MSD_ENVELOPE_AUTO)
    {
        dh = block.inputValue(envelope,&status);
    	SYS_ERROR_CHECK(status, "Error getting envelope data handle\n");	
	    env = double(dh.asFloat());	
        
        // early stop 'cause there is nothing more to do
        if (env == 0.0)
            return MS::kSuccess;
    }
    
    // get the points, transform them into the right space if needed
    //
    int count = iter.count();
    MVectorArray points(count);
    for ( ; !iter.isDone(); iter.next()) 
        points[iter.index()] = iter.position();
        
    if ( defSpace == MSD_SPACE_WORLD )
    {
        for (int i = 0;i<count;i++)
            points[i] = MPoint(points[i]) * worldMatrix;
    }
    
    
    // get the weights
    //
    MDoubleArray weights;
    if ( defWeights == MSD_WEIGHTS_AUTO)
    {
        weights.setLength(count);
        
        for (int i = 0;i<count;i++)
            weights[i]  = weightValue(block,multiIndex,i);
        
    }


    // get the object name and type
    // get the input geometry, traverse through the data handles    
    MArrayDataHandle adh = block.outputArrayValue( input, &status );
    SYS_ERROR_CHECK(status,"error getting input array data handle.\n");

    status = adh.jumpToElement( multiIndex );
    SYS_ERROR_CHECK(status, "input jumpToElement failed.\n");

    // compound data 
    MDataHandle cdh = adh.inputValue( &status );
    SYS_ERROR_CHECK(status, "error getting input inputValue\n");
   
    // input geometry child
    dh = cdh.child( inputGeom );
    MObject dInputGeometry = dh.data();
   
    // get the type      
    MString geometryType = dInputGeometry.apiTypeStr();

    // get the name    
//    MFnDagNode dagFn( dInputGeometry, &status);
//    SYS_ERROR_CHECK(status, "error converting geometry obj to dag node\n");
   
//    MString geometryName = dagFn.fullPathName(&status);
//    SYS_ERROR_CHECK(status, "error getting full path name \n");

//    MString geometryType = "";
//    MString geometryName = "";
    
    /////////////////////////////////////////////////////////////////////////////////////////////////
    //  
    //  set the current values on the temp plugs for the script to be picked up
    //
    
    // the position
    MObject thisNode = thisMObject();
    
    MPlug currPlug(thisNode,aCurrPosition);
    MFnVectorArrayData vecD;
    MObject currObj = vecD.create(points,&status);
    currPlug.setValue(currObj);
    SYS_ERROR_CHECK(status, "error setting currPosPlug value\n");
    
    // the weights
    currPlug =MPlug(thisNode,aCurrWeight);
    MFnDoubleArrayData dblD;
    currObj = dblD.create(weights,&status);
    currPlug.setValue(currObj);
    SYS_ERROR_CHECK(status, "error setting currWeightsPlug value\n");
    
    // world matrix
    currPlug =MPlug(thisNode,aCurrWorldMatrix);
    MFnMatrixData matD;
    currObj = matD.create(worldMatrix,&status);
    currPlug.setValue(currObj);
    SYS_ERROR_CHECK(status, "error setting currWorldMatrixPlug value\n");

    // the multi index
    currPlug =MPlug(thisNode,aCurrMultiIndex);
    currPlug.setValue(int(multiIndex));
    SYS_ERROR_CHECK(status, "error setting currMultiIndexPlug value\n");
    
    // geometry name/type
//    currPlug =MPlug(thisNode,aCurrGeometryName);
//    currPlug.setValue(geometryName);
//    SYS_ERROR_CHECK(status, "error setting aCurrGeometryName value\n");

    currPlug =MPlug(thisNode,aCurrGeometryType);
    currPlug.setValue(geometryType);
    SYS_ERROR_CHECK(status, "error setting aCurrGeometryType value\n");

   
    /////////////////////////////////////////////////////////////////////////////////////////////////
    //
    // execute the mel script
    //
    MString melCmd = script+"(\"" +name()+"\","+count+")";
    
    MCommandResult melResult;
    status = MGlobal::executeCommand(melCmd,melResult);
	
	// if the command did not work, then try to resource the script
	// (might have been that we were in a fresh scene and nothing was ready yet
	if (status != MS::kSuccess)
	{
		dh = block.inputValue(aScript,&status);
	    SYS_ERROR_CHECK(status, "Error getting aCmdBaseName  handle\n");    
		MString scriptFile =  dh.asString(); 	

		// try to source the script
		MString cmd = "source \"" + scriptFile+"\"";
			
		MCommandResult melResult;
		status = MGlobal::executeCommand(cmd,melResult);
		// if successfull, retry the command 
		if (!status.error())
		{
			status = MGlobal::executeCommand(melCmd,melResult);
		}
	}

	USER_ERROR_CHECK(status, "Error executing mel command, please check the function you provided is valid, error free and has the appropriate parameters!");

    // check the result type
    if ((melResult.resultType()) != (MCommandResult::kDoubleArray))
    {
        USER_ERROR_CHECK(MS::kFailure, "result of mel command has wrong type, should be doubleArray (which will be interpreted as vectorArray)!");
    }
    
    // get the result as a double array
    MDoubleArray newP;  
    status = melResult.getResult(newP);
    USER_ERROR_CHECK(status, "Error getting result of mel command!");
    
    int newCount = newP.length()/3;
    // size check
    if (newCount != count)
    {
        USER_ERROR_CHECK(MS::kFailure, "the size of the result does not match the size of the input!");
    }

    // convert the double array into a vector array
    MPointArray newPoints(newCount);
    
    for(int i=0;i<newCount;i++)
        newPoints[i]=MPoint(newP[i*3],newP[i*3+1],newP[i*3+2]);
    
    /////////////////////////////////////////////////////////////////////////////////////////////////
    //
    // interprete and apply the result
    //


  
    // do the envelope and weights   
    if ((defEnvelope == MSD_ENVELOPE_AUTO)||((defWeights == MSD_WEIGHTS_AUTO)))
    {
        MDoubleArray envPP(count, env);
    
        if (defWeights == MSD_WEIGHTS_AUTO)
        { 
            for (int i = 0;i<count;i++)
                envPP[i] *= weights[i];
        }

        // linear interpolation between old and new points
        for (int i = 0;i<count;i++)
            newPoints[i] = (points[i] * (1-envPP[i])) + (newPoints[i] * envPP[i]);
    }


    // retransform the result if it was in world space
    if ( defSpace == MSD_SPACE_WORLD )
    {
        MMatrix worldMatrixInv = worldMatrix.inverse();
        
        for (int i = 0;i<count;i++)
            newPoints[i] *= worldMatrixInv;
    }
 
 
    // set the points    
    iter.reset();
  	for ( ; !iter.isDone(); iter.next()) 
     	iter.setPosition(newPoints[iter.index()]);    

    return status;
}
コード例 #13
0
MStatus sgIkSmoothStretch::compute( const MPlug& plug, MDataBlock& data )
{
	MStatus stat;

	if ( plug == aOutputDistance )
	{
		MArrayDataHandle hArrInputDistance = data.inputArrayValue( aInputDistance );
		MDataHandle hStretchAble = data.inputValue( aStretchAble );
		MDataHandle hSmoothArea = data.inputValue( aSmoothArea );

		float stretchAble = hStretchAble.asFloat();

		double allDistance = 0.0;
		int arrayCount = hArrInputDistance.elementCount();

		double* outputDistances = new double[arrayCount]; 

		int multMinus = 1;
		for( int i=0; i<arrayCount; i++ )
		{
			MDataHandle hInputDistance = hArrInputDistance.inputValue();
			double inputDistance = hInputDistance.asDouble();

			if( inputDistance < 0 )
			{
				multMinus = -1;
				outputDistances[i] = -inputDistance;
			}
			else
			{
				outputDistances[i] = inputDistance;
			}
			allDistance += outputDistances[i];
			hArrInputDistance.next();
		}
		
		MDataHandle hInPosition = data.inputValue( aInPosition );
		MDataHandle hInPositionX = hInPosition.child( aInPositionX );
		MDataHandle hInPositionY = hInPosition.child( aInPositionY );
		MDataHandle hInPositionZ = hInPosition.child( aInPositionZ );

		double smoothArea = hSmoothArea.asDouble()*0.1;

		double poseDistance = sqrt( pow( hInPositionX.asDouble(), 2 )+pow( hInPositionY.asDouble(), 2 )+pow( hInPositionZ.asDouble(), 2 ) ) ;
		allDistance = fabs( allDistance );

		double stretchRate = getSmoothStretchRate( outputDistances[0], outputDistances[1], poseDistance, smoothArea );
		double smoothRate  = getSmoothRate( outputDistances[0], outputDistances[1], poseDistance, smoothArea );

		double currentRate = ( 1-stretchAble )*smoothRate + stretchAble*stretchRate;

		outputDistances[0] *= currentRate*multMinus;
		outputDistances[1] *= currentRate*multMinus;

		MArrayDataHandle hArrOutputDistance = data.outputArrayValue( aOutputDistance );
		MArrayDataBuilder bArrOutputDistance( aOutputDistance, arrayCount, &stat );

		for( int i=0; i<arrayCount; i++ )
		{
			MDataHandle hOutputDistance = bArrOutputDistance.addElement( i );
			hOutputDistance.set( outputDistances[i] );
		}

		hArrOutputDistance.set( bArrOutputDistance );
		hArrOutputDistance.setAllClean();

		data.setClean( plug );
	}
	return MS::kSuccess;
}
コード例 #14
0
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
MStatus CVstWeldNode::compute(
	const MPlug &mPlug,
	MDataBlock &mDataBlock )
{
	if ( mPlug == m_oaWeldOutput || mPlug == m_oaTranslate || mPlug == m_oaRotate ||
			mPlug == m_oaTranslateX || mPlug == m_oaTranslateY || mPlug == m_oaTranslateZ ||
			mPlug == m_oaRotateX || mPlug == m_oaRotateY || mPlug == m_oaRotateZ )
	{
		const MObject geoObj = mDataBlock.inputValue( m_iaWorldGeometry ).data();
		if ( geoObj.apiType() == MFn::kMeshData )
		{
			MStatus mStatus;

			MObject meshObj = mDataBlock.inputValue( m_iaWorldGeometry ).asMeshTransformed();
			MFnMesh meshFn( meshObj );
			MItMeshPolygon pIt( meshObj );
			MPointArray facePoints;

			MArrayDataHandle wiAH = mDataBlock.inputArrayValue( m_iaWeldInput );
			MArrayDataHandle woAH = mDataBlock.outputArrayValue( m_oaWeldOutput, &mStatus );
			MArrayDataBuilder woADB = woAH.builder( &mStatus );

			const int nWeldCount = wiAH.elementCount();
			for ( int i = 0; i < nWeldCount; ++i, wiAH.next() )
			{
				MDataHandle wiDH = wiAH.inputValue();

				const MMatrix &offsetMatrix = wiDH.child( m_iaOffsetMatrix ).asMatrix();
				const MMatrix &inverseParentSpace = wiDH.child( m_iaInverseParentSpace ).asMatrix();
				const MEulerRotation::RotationOrder rotationOrder = static_cast< MEulerRotation::RotationOrder >( wiDH.child( m_iaRotateOrder ).asShort() );
				MMatrix geoMatrix;

				switch ( wiDH.child( m_iaType ).asShort() )
				{
				case kMeshFace:
					{
						const int nMeshFaceIndex = wiDH.child( m_iaInt ).asInt();
						GetMeshMatrix( pIt, nMeshFaceIndex, geoMatrix );
					}
					break;
				default:
					merr << "Unknown Weld Type " << wiDH.child( m_iaType ).asShort() << std::endl;
					break;
				}

				const int nWeldIndex = wiAH.elementIndex();
				MDataHandle woDH = woADB.addElement( nWeldIndex );

				MTransformationMatrix L( inverseParentSpace * offsetMatrix * geoMatrix );

				woDH.child( m_oaTranslate ).set( L.getTranslation( MSpace::kWorld ) );
				MEulerRotation e = L.rotation().asEulerRotation();
				e.reorder( rotationOrder );
				woDH.child( m_oaRotate ).set( e.asVector() );
			}
		}
		else
		{
			merr << "Invalid .inputGeometry data of type: " << geoObj.apiTypeStr() << " found while computing " << mPlug.info() << std::endl;
			return MS::kFailure;
		}

		return MS::kSuccess;
	}

	return MS::kUnknownParameter;
}
コード例 #15
0
MStatus stringFormat::compute (const MPlug& plug, MDataBlock& data)
{
	
	MStatus status;
 
	// Check that the requested recompute is one of the output values
	//
	if (plug == attrOutput) {
		// Read the input values
		//
		MDataHandle inputData = data.inputValue (attrFormat, &status);
		CHECK_MSTATUS( status );
		MString format = inputData.asString();

        // Get input data handle, use outputArrayValue since we do not
        // want to evaluate all inputs, only the ones related to the
        // requested multiIndex. This is for efficiency reasons.
        //
		MArrayDataHandle vals = data.outputArrayValue(attrValues, &status);
		CHECK_MSTATUS( status );

		int indx = 0;
		int param;
		char letter;
		while ((indx = findNextMatch(format, indx, param, letter)) > 0) {
			double val = 0.;
			status = vals.jumpToElement(param);
			if (status == MStatus::kSuccess) {
				MDataHandle thisVal = vals.inputValue( &status );
				if (status == MStatus::kSuccess) {
					val = thisVal.asDouble();
				}
			}
			MString replace;
			bool valid = false;
			switch (letter) {
				case 'd':					// Integer
				val = floor(val+.5);
				// No break here

				case 'f':					// Float
				replace.set(val);
				valid = true;
				break;

				case 't':					// Timecode
				{
					const char * sign = "";
					if (val<0) {
						sign = "-";
						val = -val;
					}
					int valInt = (int)(val+.5);
					int sec = valInt / 24;
					int frame = valInt - sec * 24;
					int min = sec / 60;
					sec -= min * 60;
					int hour = min / 60;
					min -= hour * 60;
					char buffer[90];
					if (hour>0)
						sprintf(buffer, "%s%d:%02d:%02d.%02d", 
								sign, hour, min, sec, frame);
					else
						sprintf(buffer, "%s%02d:%02d.%02d", 
								sign, min, sec, frame);
					replace = buffer;
				}
				valid = true;
				break;
			}

			if (valid) {
				format = format.substring(0, indx-2) + 
					replace + format.substring(indx+2, format.length()-1);
				indx += replace.length() - 3;
			}
		}

		// Store the result
		//
		MDataHandle output = data.outputValue(attrOutput, &status );
		CHECK_MSTATUS( status );
		output.set( format );

	} else {
		return MS::kUnknownParameter;
	}

	return MS::kSuccess;
}
コード例 #16
0
ファイル: HesMeshNode.cpp プロジェクト: spinos/aphid
MStatus HesMeshNode::compute( const MPlug& plug, MDataBlock& data )
{
	MStatus stat;
	
	MPlug pnames(thisMObject(), ameshname);
	const unsigned numMeshes = pnames.numElements();
    
	MString cacheName =  data.inputValue( input ).asString();
	std::string substitutedCacheName(cacheName.asChar());
	EnvVar::replace(substitutedCacheName);
	
	MArrayDataHandle meshNameArray = data.inputArrayValue( ameshname );
	MArrayDataHandle meshArry = data.outputArrayValue(outMesh, &stat);
	
    bool hesStat = false;
	if( plug.array() == outMesh ) {
		const unsigned idx = plug.logicalIndex();
		if(BaseUtil::IsImporting)
            hesStat = true;
        else {
            if(idx == 0) 
                AHelper::Info<std::string>(" hes mesh open file ", substitutedCacheName );
            hesStat = BaseUtil::OpenHes(substitutedCacheName, HDocument::oReadOnly);
        }
		
		if(!hesStat) {
			AHelper::Info<std::string >("hes mesh cannot open file ", substitutedCacheName);
			return MS::kFailure;
		}
        
        meshNameArray.jumpToElement(idx);
		const MString meshName = meshNameArray.inputValue().asString();
		
        if(!BaseUtil::HesDoc->find(meshName.asChar())) {
            AHelper::Info<MString>(" hes cannot find mesh ", meshName );
            return MS::kFailure;
		}
        
		meshArry.jumpToElement(idx);
		MDataHandle hmesh = meshArry.outputValue();

		HPolygonalMesh entryMesh(meshName.asChar() );
        
        APolygonalMesh dataMesh;
		entryMesh.load(&dataMesh);
        entryMesh.close();
        
        MFnMeshData dataCreator;
		MObject outMeshData = dataCreator.create(&stat);
			
		if( !stat ) {
			MGlobal::displayWarning("hes mesh cannot create " + meshName);
			return MS::kFailure;
		}
		
        AHelper::Info<MString>(" hes init mesh ", meshName);
		HesperisPolygonalMeshCreator::create(&dataMesh, outMeshData);

		hmesh.set(outMeshData);
	    
		data.setClean(plug);
		
		if( (idx+1)>=numMeshes ) {
			if(!BaseUtil::IsImporting) {
                AHelper::Info<std::string>(" hes mesh close file ", substitutedCacheName );
				BaseUtil::CloseHes();
			}
		}
	} 
	else {
		return MS::kUnknownParameter;
	}

	return MS::kSuccess;
}
コード例 #17
0
ファイル: multiCurveNode.cpp プロジェクト: BigRoy/Maya-devkit
MStatus multiCurve::compute( const MPlug& plug, MDataBlock& data )
{
	MStatus stat;

	if ( plug == outputCurves )
	{
		MDataHandle numCurvesHandle =  data.inputValue(numCurves, &stat);
		PERRORfail(stat, "multiCurve::compute getting numCurves");
		int num = numCurvesHandle.asLong();

		MDataHandle curveOffsetHandle =  data.inputValue(curveOffset, &stat);
		PERRORfail(stat, "multiCurve::compute getting curveOffset");
		double baseOffset = curveOffsetHandle.asDouble();

		MDataHandle inputCurveHandle = data.inputValue(inputCurve, &stat);
		PERRORfail(stat, "multiCurve::compute getting inputCurve");

		MObject inputCurveObject ( inputCurveHandle.asNurbsCurveTransformed() );
		MFnNurbsCurve inCurveFS ( inputCurveObject );

		MArrayDataHandle outputArray = data.outputArrayValue(outputCurves,
															 &stat);
		PERRORfail(stat, "multiCurve::compute getting output data handle");

		// Create an array data build that is preallocated to hold just
		// the number of curves we plan on creating.  When this builder
		// is set in to the MArrayDataHandle at the end of the compute
		// method, the new array will replace the existing array in the
		// scene.
		// 
		// If the number of elements of the multi does not change between
		// compute cycles, then one can reuse the space allocated on a
		// previous cycle by extracting the existing builder from the
		// MArrayDataHandle:
		//		MArrayDataBuilder builder( outputArray.builder(&stat) );
		// this later form of the builder will allow you to rewrite elements
		// of the array, and to grow it, but the array can only be shrunk by
		// explicitly removing elements with the method
		//		MArrayDataBuilder::removeElement(unsigned index);
		//
		MArrayDataBuilder builder(outputCurves, num, &stat);
		PERRORfail(stat, "multiCurve::compute creating builder");
		
		for (int curveNum = 0; curveNum < num; curveNum++) {
			MDataHandle outHandle = builder.addElement(curveNum);
			MFnNurbsCurveData dataCreator;
			MObject outCurveData = dataCreator.create();
			MObject outputCurve  = inCurveFS.copy(inputCurveObject,
												  outCurveData, &stat);
			PERRORfail(stat, "multiCurve::compute copying curve");

			MFnNurbsCurve outCurveFS ( outputCurve );
			MPointArray cvs;

			double offset = baseOffset * (curveNum+1);

			outCurveFS.getCVs ( cvs, MSpace::kWorld );
			int numCVs = cvs.length();
			for (int i = 0; i < numCVs; i++) {
				cvs[i].x += offset;
			}
			outCurveFS.setCVs ( cvs );

			outHandle.set(outCurveData);
		}
		
		// Set the builder back into the output array.  This statement
		// is always required, no matter what constructor was used to
		// create the builder.
		stat = outputArray.set(builder);
		PERRORfail(stat, "multiCurve::compute setting the builder");

		// Since we compute all the elements of the array, instead of
		// just marking the plug we were asked to compute as clean, mark
		// every element of the array as clean to prevent further calls
		// to this compute method during this DG evaluation cycle.
		stat = outputArray.setAllClean();
		PERRORfail(stat, "multiCurve::compute cleaning outputCurves");

	} else {
		return MS::kUnknownParameter;
	}
	
	return stat;
}