Getting the Local Reference Frame

 
 
 

At this time, the SDK does not have an official way to access the local frame reference information. There is, however, a Local Frame Magic Formula for polygon mesh vertices that you can use to evaluate it yourself, or you can use a workaround involving one of the SDK object model's deprecated interfaces.

Tip

Only the magic formula for polygon mesh vertices is provided because it is often used to compute the displacement from local relative shapes on polygon meshes. For other cases, please use the following workaround.

The deprecated Geometry0D, Geometry1D, and Geometry2D interfaces represent the original versions (implemented in v1.0 but deprecated in v1.5) of the Point, Edge, and Facet interfaces, respectively. Each of these interfaces implements a LocalReferenceFrame method which returns the X, Y, and Z axes of the local reference frame at the specified index of the subcomponent.

You can get these deprecated interfaces through the (also deprecated) Geometry_V1 interface, which is available via the CollectionItem.Obj property.

Ok, so here's the catch: the LocalReferenceFrame methods use output objects and so are not available to JScript and the C++ API (Python can handle output arguments from methods without difficulty—see Working with Return Values and Output Arguments for more information). As a workaround, you can implement a custom command (in VBScript) to return an array of these values. That command can then be used by JScript or the C++ API to read the local reference frame, as JScript Example: Using the VBS wrapper to get the Local Reference Frame and C++ Example: Using the VBS wrapper to get the Local Reference Frame illustrate, using a custom command implemented like the one in VBScript Example: Implementing a JScript-compliant version of the LocalReferenceFrame methods or VBScript Example: Implementing a C++ API-compliant version of the LocalReferenceFrame methods.

VBScript Example: Implementing a JScript-compliant version of the LocalReferenceFrame methods

This version of this custom command returns an array containing the output arguments exactly as they are returned from the LocalReferenceFrame methods (that is, a safearray containing the following elements: SIVector3, Boolean, SIVector3, Boolean, SIVector3, Boolean).

Important

The C++ API cannot read the SIVector3 interface and cannot convert it to the CVector3 class, so this version will not work with the C++ API. For a C++ API-compliant version, see VBScript Example: Implementing a C++ API-compliant version of the LocalReferenceFrame methods.

'
' GetLocalReferenceFramePlugin
'

' Registration
function XSILoadPlugin( in_reg )
	in_reg.Author = "yourname"
	in_reg.Name = "GetLocalReferenceFramePlugin"
	in_reg.Email = "yourname@yourcompany.com"
	in_reg.URL = "www.yourcompany.com"
	in_reg.Major = 1
	in_reg.Minor = 0

	in_reg.RegisterCommand "GetLocalReferenceFrame","GetLocalReferenceFrame"

	XSILoadPlugin = true
end function

' De-registration
function XSIUnloadPlugin( in_reg )
	strPluginName = in_reg.Name
	Application.LogMessage strPluginName & " has been unloaded."
	XSIUnloadPlugin = true
end function

' Set up command arguments, return value and flags
function GetLocalReferenceFrame_Init( ctxt )
	dim oCmd
	set oCmd = ctxt.Source
	oCmd.Description = "Get Local Reference Frame"
	oCmd.SetFlag siNoLogging, true
	oCmd.ReturnValue = true

	dim oArgs
	set oArgs = oCmd.Arguments
	oArgs.AddWithHandler "InputObjs", siArgHandlerCollection
	oArgs.Add "Index",		siArgumentInput,	,		siInt4
	oArgs.Add "Dimension",	siArgumentInput,	"0",	siInt2
	
	GetLocalReferenceFrame_Init = true
end function

' Main implementation
function GetLocalReferenceFrame_Execute( InputObjs, Index, Dimension )
	dim oXDGeometry, aInfoCollection
	dim oXAxis, oYAxis, oZAxis 
	dim bXAxisValid, bYAxisValid, bZAxisValid
	
	set oXAxis = XSIMath.CreateVector3()
	set oYAxis = XSIMath.CreateVector3()
	set oZAxis = XSIMath.CreateVector3()
	
	' Make sure input object is valid
	if TypeName(InputObjs(0)) <> "X3DObject" then
		set GetLocalReferenceFrame_Execute = Nothing
		Application.LogMessage( "Input object is not a valid object: " & InputObj.Type )
		exit function
	end if
	
	' Decide which info to get
	if Dimension = 0 then
		set oXDGeometry = InputObjs(0).Obj.Geometry0D
	elseif Dimension = 1 then
		set oXDGeometry = InputObjs(0).Obj.Geometry1D
	else
		set oXDGeometry = InputObjs(0).Obj.Geometry2D
	end if
	
	' Call the correct method and then use the output arguments to populate the array to return
	oXDGeometry.LocalReferenceFrame i, oXAxis, bXAxisValid, oYAxis, bYAxisValid, oZAxis, bZAxisValid
	aInfoCollection = Array( oXAxis, bXAxisValid, oYAxis, bYAxisValid, oZAxis, bZAxisValid )
	 
	' The array returned will be a 1-dimensional SAFEARRAY
	GetLocalReferenceFrame_Execute = aInfoCollection 
end function

JScript Example: Using the VBS wrapper to get the Local Reference Frame

This example demonstrates how to get the Local Reference Frame information on a cube using JScript. Because JScript cannot handle the output arguments returned by the LocalReferenceFrame methods on the deprecated Geometry0D, Geometry1D, and Geometry2D objects, you must write a custom command in VBScript to extract the information and reformat it for use by JScript. In this example, the expected result is a 1-dimensional safearray containing 3 pairs of SIVector3 and Boolean elements (as implemented in VBScript Example: Implementing a JScript-compliant version of the LocalReferenceFrame methods).

// Create a cube
var objItem = CreatePrim( "Cube", "MeshSurface" );

// Get number of vertices in the cube
var nbrPoints = objItem.ActivePrimitive.Geometry.Points.Count;

// Set up some storage for the local reference frame info
var vc3XAxis = XSIMath.CreateVector3(); var booXAxisValid;
var vc3YAxis = XSIMath.CreateVector3(); var booYAxisValid;
var vc3ZAxis = XSIMath.CreateVector3(); var booZAxisValid;

// Get the local reference frame for each point
for ( var i=0; i<nbrPoints; i++ ) {
	var aResults = GetLocalReferenceFrame( objItem, i, 0 ).toArray();
	vc3XAxis = aResults[0];
	booXAxisValid = aResults[1];
	vc3YAxis = aResults[2];
	booYAxisValid = aResults[3];
	vc3ZAxis = aResults[4];
	booZAxisValid = aResults[5];

	if ( booXAxisValid ) {
		Application.LogMessage ( "Component [" + i + "] X axis : " + vc3XAxis.x + " | " + vc3XAxis.y + " | " + vc3XAxis.z );
	} else {
		Application.LogMessage ( "Component [" + i + "] INVALID X axis" );
	}

	if ( booYAxisValid ) {
		Application.LogMessage ( "Component [" + i + "] Y axis : " + vc3YAxis.x + " | " + vc3YAxis.y + " | " + vc3YAxis.z );
	} else {
		Application.LogMessage ( "Component [" + i + "] INVALID Y axis" );
	}

	if ( booZAxisValid ) {
		Application.LogMessage ( "Component [" + i + "] Z axis : " + vc3ZAxis.x + " | " + vc3ZAxis.y + " | " + vc3ZAxis.z );
	} else {
		Application.LogMessage ( "Component [" + i + "] INVALID Z axis" );
	}
}

//INFO : Component [0] X axis : 0.408248290463863 | -0.816496580927726 | 0.408248290463863
//INFO : Component [0] Y axis : -0.577350269189626 | -0.577350269189626 | -0.577350269189626
//INFO : Component [0] Z axis : 0.707106781186547 | 0 | -0.707106781186547
//INFO : Component [1] X axis : -0.408248290463863 | 0.408248290463863 | -0.816496580927726
//INFO : Component [1] Y axis : 0.577350269189626 | -0.577350269189626 | -0.577350269189626
//INFO : Component [1] Z axis : -0.707106781186547 | -0.707106781186547 | 0
//INFO : Component [2] X axis : -0.816496580927726 | -0.408248290463863 | 0.408248290463863
//INFO : Component [2] Y axis : -0.577350269189626 | 0.577350269189626 | -0.577350269189626
//INFO : Component [2] Z axis : 0 | -0.707106781186547 | -0.707106781186547
//INFO : Component [3] X axis : -0.408248290463863 | -0.408248290463863 | -0.816496580927726
//INFO : Component [3] Y axis : 0.577350269189626 | 0.577350269189626 | -0.577350269189626
//INFO : Component [3] Z axis : 0.707106781186547 | -0.707106781186547 | 0
//INFO : Component [4] X axis : 0.408248290463863 | -0.816496580927726 | -0.408248290463863
//INFO : Component [4] Y axis : -0.577350269189626 | -0.577350269189626 | 0.577350269189626
//INFO : Component [4] Z axis : -0.707106781186547 | 0 | -0.707106781186547
//INFO : Component [5] X axis : 0.816496580927726 | 0.408248290463863 | -0.408248290463863
//INFO : Component [5] Y axis : 0.577350269189626 | -0.577350269189626 | 0.577350269189626
//INFO : Component [5] Z axis : 0 | -0.707106781186547 | -0.707106781186547
//INFO : Component [6] X axis : -0.816496580927726 | -0.408248290463863 | -0.408248290463863
//INFO : Component [6] Y axis : -0.577350269189626 | 0.577350269189626 | 0.577350269189626
//INFO : Component [6] Z axis : 0 | 0.707106781186547 | -0.707106781186547
//INFO : Component [7] X axis : -0.408248290463863 | 0.816496580927726 | -0.408248290463863
//INFO : Component [7] Y axis : 0.577350269189626 | 0.577350269189626 | 0.577350269189626
//INFO : Component [7] Z axis : 0.707106781186547 | 0 | -0.707106781186547

VBScript Example: Implementing a C++ API-compliant version of the LocalReferenceFrame methods

The C++ API cannot read the SIVector3 interface and cannot convert it to the CVector3 class, so this version of the custom command returns an array containing the output arguments flattened (that is, each SIVector3 is expanded in place to its x,y,z values).

Note

Only the implementation is presented here, since all other aspects of the custom command (declaration, initialization) remain the same. See VBScript Example: Implementing a JScript-compliant version of the LocalReferenceFrame methods to see the other callbacks for this command.

' Main implementation
function GetLocalReferenceFrame_Execute( InputObjs, Index, Dimension )
	dim oXDGeometry, aInfoCollection
	dim oXAxis, oYAxis, oZAxis 
	dim bXAxisValid, bYAxisValid, bZAxisValid
	
	set oXAxis = XSIMath.CreateVector3()
	set oYAxis = XSIMath.CreateVector3()
	set oZAxis = XSIMath.CreateVector3()
	
	' Make sure input object is valid
	if TypeName(InputObjs(0)) <> "X3DObject" then
		set GetLocalReferenceFrame_Execute = Nothing
		Application.LogMessage( "Input object is not a valid object: " & InputObj.Type )
		exit function
	end if
	
	' Decide which info to get
	if Dimension = 0 then
		set oXDGeometry = InputObjs(0).Obj.Geometry0D
	elseif Dimension = 1 then
		set oXDGeometry = InputObjs(0).Obj.Geometry1D
	else
		set oXDGeometry = InputObjs(0).Obj.Geometry2D
	end if
	
	' Call the correct method and then use the output arguments to populate the array to return
	' In this case we want to return the actual values of the SIVector3, not the SIVector3 
	' itself. This is because the C++ API cannot handle the SIVector3 interface so we need to pass
	' the actual x,y,z values.
	oXDGeometry.LocalReferenceFrame i, oXAxis, bXAxisValid, oYAxis, bYAxisValid, oZAxis, bZAxisValid
	aInfoCollection = Array(	oXAxis.X, oXAxis.Y, oXAxis.Z, bXAxisValid, _
								oYAxis.X, oYAxis.Y, oYAxis.Z, bYAxisValid, _
								oZAxis.X, oZAxis.Y, oZAxis.Z, bZAxisValid )
	 
	' The array returned will be a 1-dimensional SAFEARRAY
	GetLocalReferenceFrame_Execute = aInfoCollection 
end function

C++ Example: Using the VBS wrapper to get the Local Reference Frame

This example demonstrates how to get the Local Reference Frame information on a cube using the C++ API. Because the C++ API cannot handle the output arguments returned by the LocalReferenceFrame methods on the deprecated Geometry0D, Geometry1D, and Geometry2D objects, you must write a custom command in VBScript to extract the information and reformat it for use by the C++ API. In this example, the expected result is a flat array of 12 elements arranged as 3 quartets of double, double, double, bool elements. Each quartet represents the x.y.z values plus an indicator of the validity for each axis (as implemented in VBScript Example: Implementing a C++ API-compliant version of the LocalReferenceFrame methods).

	Application app;
	Model root = app.GetActiveSceneRoot();

	// Create a cube
	X3DObject objItem; root.AddGeometry( L"Cube", L"MeshSurface", L"MyCube", objItem );

	// Get number of vertices in the cube
	CPointRefArray refPoints = objItem.GetActivePrimitive().GetGeometry().GetPoints();
	LONG nbrPoints = refPoints.GetCount();

	// Set up the arguments for the custom command
	CValueArray ccArgs(3); CValue ccOut;
	ccArgs[0] = objItem;
	ccArgs[2] = CValue(0.0);

	// Get the local reference frame for each point
	for ( LONG i=0; i<nbrPoints; ++i ) 
	{
		// Run the command (you only need to change the index number for this example)
		ccArgs[1] = i;
		app.ExecuteCommand( L"GetLocalReferenceFrame", ccArgs, ccOut );
		
		// Grab the output arguments from the returned array
		if ( ccOut.m_t == CValue::siArray ) 
		{
			MATH::CVector3 vc3XAxis; MATH::CVector3 vc3YAxis; MATH::CVector3 vc3ZAxis;
			bool booXAxisValid; bool booYAxisValid; bool booZAxisValid;

			CValueArray aResults(ccOut);
			vc3XAxis.Set( aResults[0], aResults[1], aResults[2]  ); // XAxis 
			booXAxisValid = aResults[3];								// XAxisValid 
			vc3YAxis.Set( aResults[4], aResults[5], aResults[6]  ); // YAxis 
			booYAxisValid = aResults[7];								// YAxisValid 
			vc3ZAxis.Set( aResults[8], aResults[9], aResults[10]  ); // ZAxis 
			booZAxisValid = aResults[11];								// ZAxisValid 

			// Log the information in Softimage
			if ( booXAxisValid ) 
			{
				app.LogMessage ( L"Component [" + CString(i) + L"] X axis : " + CString(vc3XAxis.GetX()) + L" | " + CString(vc3XAxis.GetY()) + L" | " + CString(vc3XAxis.GetZ()) );
			} else {
				app.LogMessage ( L"Component [" + CString(i) + L"] INVALID X axis" );
			}

			if ( booYAxisValid ) 
			{
				app.LogMessage ( L"Component [" + CString(i) + L"] Y axis : " + CString(vc3YAxis.GetX()) + L" | " + CString(vc3YAxis.GetY()) + L" | " + CString(vc3YAxis.GetZ()) );
			} else {
				app.LogMessage ( L"Component [" + CString(i) + L"] INVALID Y axis" );
			}

			if ( booZAxisValid ) 
			{
				app.LogMessage ( L"Component [" + CString(i) + L"] Z axis : " + CString(vc3ZAxis.GetX()) + L" | " + CString(vc3ZAxis.GetY()) + L" | " + CString(vc3ZAxis.GetZ()) );
			} else {
				app.LogMessage ( L"Component [" + CString(i) + L"] INVALID Z axis" );
			}
		}

Local Frame Magic Formula

The local reference frame for vertices of polygon meshes is computed in object space, as the following:

  • Y = vertex normal This is the same as Geometry0D.Normal or Point.Normal (or Point::GetNormal in the C++ API). To compute it yourself, you have to take the normalized sum of the cross products of the pair of consecutive normalized edge vectors around the vertex.

  • X = normalized projection of the first edge vector (starting from current vertex) onto the normal plane.

  • Z = cross prod of X and Y.