Accessing Operators and Beyond

 
 
 

As operators are applied, they are pushed onto a stack called the operator stack until they are removed (usually by freezing the stack). Because this stack keeps track of the object's history it is also known as the construction history. The object model provides access to the ConstructionHistory object through the Primitive.ConstructionHistory property. which you can use to enumerate over the construction history to access its operators. For more information, see The Operator Stack.

What You Can Do with an Operator

Once you have a pointer to an operator, you can access its input ports (the values that are driving the operator's data change) and its output ports (for example, the parameter being driven) using these methods:

From the ports you can get a pointer to the object to which the port is connected: Port.Target2 (object model) and Port::GetTarget (C++ API).

Tip

To see the input and output ports in the UI, you can use the SDK Explorer (available from the ViewScripting menu) by clicking on the operator and then clicking the Object Details link above the main content pane.

Note that the operator appears in the scene explorer according to which objects it is writing to (that is, it appears in the operator stack of the object it is creating or modifying) so it may appear in multiple places in the scene explorer at once.

The Operator Stack

In the SDK, the operator stack is called the construction history because it keeps track of each persistent change to the object; that is, each operator applied to an object until it is frozen. The operator stack is subdivided into four construction mode regions:

Region Name:

Description:

Name Returned from FullName

Modeling

Defines the basic shape and topology of an object using both deformations and topology operators.

modelingmarker

Shape Modeling

Contains the Cluster Shape Combiner node and lets you apply deformations to define shape keys for shape animation.

shapemarker

Animation

Keeps animated deformations from being removed when the modeling is frozen or a shape is applied

animationmarker

Secondary Shape Modeling

use it to create shape keys for things like muscle bulges on top of an enveloped character

secondaryshapemarker

As soon as an operator is applied, a construction history is built containing the new operator in addition to these four markers. When you enumerate over the operators in the construction history, these four markers will report their full names (shown in the third column in the table above), so you can test each item in the construction history to make sure you have what you think you have.

Navigating the Operator Stack/Construction History

To find an operator applied on a scene object, you need to browse through the contents of the object's ConstructionHistory, which is accessible through the Primitive.ConstructionHistory property (see JScript Example: Picking Operators from a Specific Construction Region for a script example of how to navigate through the construction mode regions).

Note

Currently the Primitive.ConstructionHistory property is only available in the object model. However, by using the CComAPIHandler, a C++ API plug-in can reach the operators connected to a Primitive (see C++ Example: Accessing the Construction History via the CComAPIHandler for an example).

JScript Example: Picking Operators from a Specific Construction Region

In this example, a cube is created and several operators applied in different construction modes. Then the operator stack is read so that only those operators under the Animation construction mode region are considered.

// Set up a scene with a cube and apply a variety of deform operators
// in a variety of construction modes
NewScene( null, false );
var obj = CreatePrim( "Cube", "MeshSurface" );
ApplyOp( "Bulge", "cube", 3, siPersistentOperation, null, 0 );
ApplyOp( "Bend", "cube", 3, siPersistentOperation, null, 0 );
SetValue( "Context.ConstructionMode", 2 );
ApplyOp( "Fold", "cube", 3, siPersistentOperation, null, 2 );
ApplyOp( "Shear", "cube", 3, siPersistentOperation, null, 2 );
SetValue( "Context.ConstructionMode", 3 );
ApplyOp( "Smooth", "cube", 3, siPersistentOperation, null, 3 );


// Get the cube's operator stack/construction history and browse it...
var opstack = new Enumerator( obj.ActivePrimitive.ConstructionHistory );
var getanimops = false;
for ( ; !opstack.atEnd(); opstack.moveNext() ) {
	var op = opstack.item();
	Application.LogMessage( "Current node: " + op.FullName );

	// Use RegularExpression matching to identify the markers in the stack
	var beginregion = false;
	if ( op.FullName.match(/marker/i) != null ) {
		beginregion = true;
	} else {
		beginregion = false;
	}
	
	// Grab only animation operators
	if ( !beginregion && getanimops ) {
		Application.LogMessage( "\tFound this animation operator: " + op.Name );
	}
	
	// Figures out when we're in the Animation region
	if ( beginregion ) {
		if ( op.FullName.match(/animationmarker/i) != null ) {
			getanimops = true;
		} else {
			getanimops = false;
		}
	}
}

//INFO : Current node: cube.polymsh.secondaryshapemarker
//INFO : Current node: cube.polymsh.smoothop
//INFO : Current node: cube.polymsh.animationmarker
//INFO : Current node: cube.polymsh.shearop
//INFO : 	Found this animation operator: Shear Op
//INFO : Current node: cube.polymsh.foldop
//INFO : 	Found this animation operator: Fold Op
//INFO : Current node: cube.polymsh.shapemarker
//INFO : Current node: cube.polymsh.modelingmarker
//INFO : Current node: cube.polymsh.bendop
//INFO : Current node: cube.polymsh.bulgeop
//INFO : Current node: cube.polymsh.geom

C++ Example: Accessing the Construction History via the CComAPIHandler

This example demonstrates how to create a CRefArray of the operators connected to a Primitive using the CComAPIHandler object to access the Construction History.

// Given an X3DObject (e.g. a mesh or nurbs), fills in an array with all the operators connected to its
// primitive.	This function is suitable for re-use in any plug-in that wants to access construction history
void GetOperators( X3DObject in_ops, CRefArray & out_ops )
{
	Primitive primitive = in_ops.GetActivePrimitive() ;
	CComAPIHandler comPrimitive( primitive.GetRef() ) ;

	CComAPIHandler constructionHistory = comPrimitive.GetProperty( L"ConstructionHistory" ) ;
	
	// Currently there isn't a "Count" or "Item" property on the ConstructionHistory 
	// scripting object, so we use Filter to find all operators
	CValue valOperatorCollection	;
	CValueArray args(3)	;
	args[1] = CValue( L"Operators" ) ;	// We want all operators (siOperatorFamily)
	constructionHistory.Call( L"Filter", valOperatorCollection, args ) ;
	

	// Now convert from a OperatorCollection object to a C++ CRefArray
	CComAPIHandler comOpColl = valOperatorCollection ;
	CValue cnt = comOpColl.GetProperty( L"Count" ) ;
	
	CRefArray ops( (LONG)cnt ) ;
	
	for ( LONG i=0 ; i<(LONG)cnt; i++ )
	{
		CValue outOp;
		CValueArray itemsArgs;
		itemsArgs.Add( i );
		comOpColl.Invoke(L"Item", CComAPIHandler::PropertyGet, outOp, itemsArgs);
	
		ops[i] = outOp ;
	}
	
	out_ops = ops ;
}