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.
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).
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).
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" ); } }
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.