Creating a merge curve SCOP


Applies to: v3.0..v7.0

I was sketching curves out to follow the roads on a map and I wanted to merge all the individual curves into a single NurbsCurveList so I could take advantage of curve functions in ICE. The built-in operators would not allow me to merge or stitch them together and I cannot create a multi-curve list using the curve tools.

I decided to create my own merge curve SCOP (scripted operator) in JScript; this time. I was having trouble getting the NurbsCurveList::Set function to work and it kept giving me cryptic error messages. After digging around on my hard drive for a while I dug up a script from beta Orleans aka v3.0 which revealed the mystery to me; as it was suitably obscure I thought I would share this with you.

For the NurbsCurveList::Set() method to work it expects takes each argument to be an array. The controls points and knots cannot be arrays of the JScript Array() type so you must flatten the arrays. The following code shows how:

	var MergeCurveGeometry = Dictionary.GetObject("mergecurve.crvlist").Geometry;
	var aCurves = Array( Dictionary.GetObject("crvlist.crvlist").Geometry, Dictionary.GetObject("crvlist1.crvlist").Geometry );
	
	var aControlVertex= Array(); 	// arg0
	var aNbControlVertex= Array(); 	// 
	var aKnots = Array(); 		// arg1
	var aNbKnots = Array(); 	// 
	var aClosed= Array(); 		// arg2
	var aDegree= Array(); 		// arg3
	var aParameterization= Array(); // arg4

	for (idxCrv=0;idxCrv<aCurves.length; idxCrv++)
	{
		var inputCurve = aCurves[idxCrv];

		// convert VB array to JScript array
		var vbArgs = new VBArray(inputCurve.Curves(0).Get2( 0/*siSINurbs*/ ));
		var args = vbArgs.toArray(); // VBArray to JScript Array

		var cpoints =  args[0].toArray();
		aControlVertex = aControlVertex.concat(cpoints);
		aNbControlVertex[idxCrv] = cpoints.length / 4;
		
		var knots =  args[1].toArray();
		aKnots = aKnots.concat(knots);
		aNbKnots[idxCrv] = knots.length;
		
		aClosed[idxCrv] = args[2];
		aDegree[idxCrv] = args[3];
		aParameterization[idxCrv] = args[4];
	}

	// add data to  nurbs curve list.
	MergeCurveGeometry.Set( 
		idxCrv, 
		aControlVertex, 
		aNbControlVertex, 
		aKnots, 
		aNbKnots, 
		aClosed, 
		aDegree, 
		aParameterization, 
		0/*siSINurbs*/) ;

JScript has the Array() type which when passed to C++ ends up as a pointer to a scripting object. The internal code is expecting either a flat 1 dimensional array or a 2 dimensional array constructed from a VBArray. It is not able to convert an JScript Array of JScript Arrays and fails; but fails to tell you why - shame on me :(

The following code implements a self-installing plugin for the MergeCurve SCOP. The DebugCurve argument is a mask and can be used in conjunction with Debug=1 to outputted only the curves indicated by the DebugCurve bit mask. For example, DebugCurve=3 will show input curves: curve0 and curve1.

// jsMergeCurvePlugin
function XSILoadPlugin( in_reg )
{
	in_reg.Author = "sinwood";
	in_reg.Name = "jsMergeCurvePlugin";
	in_reg.Email = "";
	in_reg.URL = "";
	in_reg.Major = 1;
	in_reg.Minor = 0;

	in_reg.RegisterOperator("jsMergeCurve");
	in_reg.RegisterCommand("ApplyjsMergeCurve","ApplyjsMergeCurve");
	
	in_reg.RegisterCommand("jsMergeCurveExample","jsMergeCurveExample");
	//RegistrationInsertionPoint - do not remove this line

	return true;
}

function XSIUnloadPlugin( in_reg )
{
	var strPluginName;
	strPluginName = in_reg.Name;
	Application.LogMessage(strPluginName + " has been unloaded.",siVerbose);
	return true;
}

function ApplyjsMergeCurve_Init( in_ctxt )
{
	var oCmd;
	oCmd = in_ctxt.Source;
	oCmd.Description = "Create an instance of jsMergeCurve operator";
	oCmd.SetFlag(siNoLogging,false);

	// TODO: You may want to add some arguments to this command so that the operator
	// can be applied to objects without depending on their specific names.
	// Tip: the Collection ArgumentHandler is very useful
	return true;
}

function ApplyjsMergeCurve_Execute(  )
{

	Application.LogMessage("ApplyjsMergeCurve_Execute called",siVerbose);
	// TODO: This generated code works by hardcoding the exact names of the
	// input and output objects.
	// If you want to operator to be applied to objects with different names
	// you way want to generalise this code to determine the objects
	// based on the Selection or the arguments to this command
	// 
	// Note: The AddCustomOp command is an alternative way to build the operator
	var newOp = XSIFactory.CreateObject("jsMergeCurve");
	newOp.AddOutputPort("mergecurve.crvlist");
	newOp.AddInputPort("mergecurve.crvlist");
	newOp.AddInputPort("crvlist.crvlist");
	newOp.AddInputPort("crvlist1.crvlist");
//	newOp.AddInputPort("crvlist2.crvlist");
//	newOp.AddInputPort("crvlist3.crvlist");
//	newOp.AddInputPort("crvlist9.crvlist");
	newOp.Connect();
	return newOp;
}

function jsMergeCurve_Define( in_ctxt )
{
	var oCustomOperator;
	var oPDef;
	oCustomOperator = in_ctxt.Source;
	oPDef = XSIFactory.CreateParamDef("Debug",siInt4,siClassifUnknown,siPersistable | siKeyable,"","",0,0,32,0,32);
	oCustomOperator.AddParameter(oPDef);
	oPDef = XSIFactory.CreateParamDef("DebugCurve",siInt4,siClassifUnknown,siPersistable | siKeyable,"","",31,31,32,0,32);
	oCustomOperator.AddParameter(oPDef);

	oCustomOperator.AlwaysEvaluate = false;
	oCustomOperator.Debug = 1;
	return true;
}

function jsMergeCurve_Init( in_ctxt )
{
	Application.LogMessage("jsMergeCurve_Init called",siVerboseMsg);
	return true;
}

function jsMergeCurve_Term( in_ctxt )
{
	Application.LogMessage("jsMergeCurve_Term called",siVerboseMsg);
	return true;
}

function jsMergeCurve_Update( in_ctxt )
{
	var debug= in_ctxt.GetParameterValue("Debug");
	var DebugCurve = in_ctxt.GetParameterValue("DebugCurve");

	Application.LogMessage("jsMergeCurve_Update called",siVerboseMsg);

	var aCurves = Array();
	var cInputs = in_ctxt.Source.InputPorts.Count;
	
	for ( idxIn=1; idxIn < cInputs ; idxIn++)
		aCurves[aCurves.length] = in_ctxt.GetInputValue(idxIn).Geometry;
	
	if (debug)
	{
		var aDebugCurves = Array();
		for ( i=0; i < aCurves.length; i++)
		{
			if (DebugCurve & (1<<i))
				aDebugCurves[aDebugCurves.length] = aCurves[i];
		}
		if (aDebugCurves.length)
			aCurves=aDebugCurves;
	}
 
 	MergeCurves( in_ctxt.OutputTarget.Geometry, aCurves );

	return true;
}

function jsMergeCurve_DefineLayout( in_ctxt )
{
	var oLayout,oItem;
	oLayout = in_ctxt.Source;
	oLayout.Clear();
	oLayout.AddItem("DebugCurve");
	return true;
}

function jsMergeCurve_OnInit( )
{
	Application.LogMessage("jsMergeCurve_OnInit called",siVerbose);
}

function jsMergeCurve_OnClosed( )
{
	Application.LogMessage("jsMergeCurve_OnClosed called",siVerbose);
}

function jsMergeCurve_DebugCurve_OnChanged( )
{
	Application.LogMessage("jsMergeCurve_DebugCurve_OnChanged called",siVerbose);
	var oParam;
	oParam = PPG.DebugCurve;
	var paramVal;
	paramVal = oParam.Value;
	Application.LogMessage("New value: " + paramVal,siVerbose);
}

function MergeCurves(geomOut, aCurves)
{
	var aControlVertex= Array();
	var aNbControlVertex= Array();
	var aKnots = Array();
	var aNbKnots = Array();
	var aClosed= Array();
	var aDegree= Array();
	var aParameterization= Array();

	for (idxCrv=0;idxCrv<aCurves.length; idxCrv++)
	{
		var inputCurve = aCurves[idxCrv];

		// convert VB array to JScript array
		var vbArgs = new VBArray(inputCurve.Curves(0).Get2( 0/*siSINurbs*/ ));
		var args = vbArgs.toArray();

		// get the control points 
		var vbArg0 = new VBArray(args[0]);
		var cpoints = vbArg0.toArray();

		aControlVertex = aControlVertex.concat( cpoints );
		aNbControlVertex[idxCrv]  = cpoints.length/4; 
		logmessage( "Curve "+idxCrv+" cpoints  = "+cpoints.toString() );
		logmessage( "Curve "+idxCrv+" nb cpoints  = "+cpoints.length/4 );
			
		var vbArg1 = new VBArray(args[1]);
		var knots = vbArg1.toArray();
		
		aKnots = aKnots.concat( knots );
		aNbKnots[idxCrv] = knots.length;
		logmessage( "Curve "+idxCrv+" knots = "+knots.toString() );
		logmessage( "Curve "+idxCrv+" nb knots = "+knots.length );

		aClosed[idxCrv] = args[2];
		logmessage( "Curve "+idxCrv+" closed = "+args[2].toString() );
		
		aDegree[idxCrv] = args[3];
		logmessage( "Curve "+idxCrv+" Degree= "+args[3].toString() );
		
		aParameterization[idxCrv] = args[4];
		logmessage( "Curve "+idxCrv+" Parameterization= "+args[4].toString() );
	}

	// add data to  nurbs curve list.
	geomOut.Set( 
		idxCrv, 
		aControlVertex, 
		aNbControlVertex, 
		aKnots, 
		aNbKnots, 
		aClosed, 
		aDegree, 
		aParameterization, 
		0/*siSINurbs*/) ;
}


function jsMergeCurveExample_Init( in_ctxt )
{
	var oCmd;
	oCmd = in_ctxt.Source;
	oCmd.Description = "";
	oCmd.ReturnValue = true;

	return true;
}

function jsMergeCurveExample_Execute(  )
{

	Application.LogMessage("jsMergeCurveExample_Execute called",siVerbose);
	
	NewScene(null, null);
	SICreateCurve("crvlist", 1, 1);
	SIAddPointOnCurveAtEnd("crvlist", 3.19494584837545, 0, -2.11387260127993, false, 0, null);
	SIAddPointOnCurveAtEnd("crvlist", 0.535499398315283, 0, -0.572130761030627, false, 0, null);
	SIAddPointOnCurveAtEnd("crvlist", -2.77376654632972, 0, 1.21050824175763, false, 0, null);
	DeselectAll();
	SICreateCurve("crvlist1", 1, 1);
	SIAddPointOnCurveAtEnd("crvlist1", -1.75090252707581, 0, -2.35476976381888, false, 0, null);
	SIAddPointOnCurveAtEnd("crvlist1", -6.61853188928996E-02, 0, -0.283054165983883, false, 0, null);
	SIAddPointOnCurveAtEnd("crvlist1", 1.61853188929001, 0, 1.69230256683554, false, 0, null);
	CreatePrim("Arc", "NurbsCurve", null, null);
	FreezeModeling(null, null, null);
	SetValue("arc.Name", "mergecurve", null);
	
	ApplyjsMergeCurve();
	
	return true;
}

This page was last modified 02:00, 18 Sep 2009.
This page has been accessed 9581 times.

© Copyright 2009 Autodesk Inc. All Rights Reserved. Privacy Policy | Legal Notices and Trademarks | Report Piracy