Making Sure Returned Values are Valid

Some commands and methods may return invalid collections or objects. For example, if you try to use the Find method to return an item that doesn’t exist in the scene, it returns nothing. Unfortunately, if you try to use that invalid object or collection later on in your script, you will get an error.

To find out whether the return object is valid in VBScript

In VBScript, if the command or method returns an invalid object, the TypeName function returns Nothing:

    Set oRoot = ActiveSceneRoot
    Set oChildren = oRoot.FindChildren
    Set oChild = oChildren.Find( "polymsh" )
    If TypeName( oChild ) <> "Nothing" Then
       LogMessage "Found " & oChild.Name
    Else
       LogMessage "Couldn’t find it!"
    End If

To find out whether the return object is valid in JScript

In JScript, if the command or method returns an invalid object, you can trap it with exception handling:

    var oRoot = ActiveSceneRoot;
    var oChildren = oRoot.FindChildren();
    var oChild = oChildren.Find( "polymsh" );

    try {
       sMessage = "Found " + oChild.Name;
    } catch(e) {
       sMessage = "Couldn't find it!";
    } finally {
       LogMessage( sMessage );
    }

Alternatively, you could use the following error trap instead:

    var oRoot = ActiveSceneRoot;
    var oChildren = oRoot.FindChildren();
    var oChild = oChildren.Find( "polymsh" );

    if ( oChild == null ) {
       LogMessage( "Couldn't find it!" );
    } else {
       LogMessage( "Found " + oChild.Name );
    }

Empty Collections

Empty collections can sometimes be tricky. They behave differently depending on how you get them (which command or method returned them). For example, the FindChildren method returns a valid collection containing no members:

    Set oRoot = ActiveSceneRoot
    Set oChildren = oRoot.FindChildren( "sphere" )
    LogMessage oChildren & " contains " & oChildren.Count & " members."

If you run this code snippet on a scene with no objects named “sphere”, the following message appears:

    'INFO : "This collection contains 0 members."

However, the Filter method does not return a valid collection:

    Set oRoot = ActiveSceneRoot
    Set oChildren = oRoot.FindChildren
    Set oPolyMeshes = oChildren.Filter( "polymsh" )
    LogMessage "This collection contains " & oPolyMeshes.Count & " members."

If you run this code snippet on a scene with no polygon mesh objects, the script aborts and the following error message appears:

    'ERROR : "Object required: 'oPolyMeshes'"

You can trap errors of these kinds in VBScript with a combination of Nothing and Count and in JScript with exception handling.

To find out whether a collection contains any items in VBScript

You can use the VBScript TypeName function to test whether the collection returns a valid collection without throwing an error:

    Set oRoot = ActiveSceneRoot
    Set oChildren = oRoot.FindChildren
    If TypeName( oChildren ) = "Nothing" Then
       LogMessage "This collection is empty."
    Else
       LogMessage "This collection has members."
    End If

The only problem is that if the collection is a valid collection with no members and you run this test, you get the wrong results:

    'INFO : "This collection has members."

This means that your test has to include the Count property to find out whether a collection contains any items (collection members):

    Set oRoot = ActiveSceneRoot
    Set oChildren = oRoot.FindChildren( "sphere" )
    Set oPolyMeshes = oChildren.Filter( "polymsh" )

    Call IsCollectionEmpty( oChildren )
    Call IsCollectionEmpty( oPolyMeshes )

    Function IsCollectionEmpty( in_collection )
       If TypeName( in_collection ) <> "Nothing" Then
           If in_collection.Count > 0 Then
              LogMessage "Collection has some members"
           Else
              LogMessage "Collection has no members"
           End If
       Else
           LogMessage "Collection is empty"
       End If
    End Function

| In VBScript, there are functions called IsNull and IsEmpty. Do not use them to test whether your collection is empty, because what it is actually testing for is whether your collection’s data subtype is Null or Empty. For more information on the Null and Empty data types and subtypes, see What is ‘Type’? or msdn2.microsoft.com/en-us/library/9e7a57cf.aspx.

To find out whether a collection contains any items in JScript

You can trap the error using the try...catch...finally statements in JScript. For example, the function in the following code snippet uses the Count property to see whether the collection is valid and if so, whether it has any members:

    var oRoot = ActiveSceneRoot;
    var oChildren = oRoot.FindChildren( "sphere" );
    var oPolyMeshes = oChildren.Filter( "surfmsh" );

    if ( IsCollectionEmpty(oChildren) ){
       // If empty, then...
    }

    if ( IsCollectionEmpty(oPolyMeshes) ){
       // If empty, then...
    }

    function IsCollectionEmpty( in_collection )
    {
       var bCollIsEmpty;
       try {
           if( in_collection.Count > 0 ) {
              bCollIsEmpty = false;
           } else {
              bCollIsEmpty = true;
           }
       } catch(e) {
           bCollIsEmpty = true;
       } finally {
           return bCollIsEmpty;
       }
    }

Calling a Command or Method That Might Fail

Some methods or commands will fail if the arguments or context are not correct. For example, the Loft operator takes a connection set of two or more curves as input. If you try to apply it to anything else (in the following example, a torus), the command fails and your script will break .

    // This is the incorrect way to apply the Loft operator:
    var cnxset = ActiveSceneRoot.AddGeometry( "Torus", "MeshSurface" );
    var oplist = ApplyOp( "Loft", cnxset );

    //WARNING : 3040-EDIT-GetConnectionSet - Some input objects are invalid ...
    //ERROR : Subscript out of range: '[number: 0]' - [line 213 in ...
    //ERROR :  - [line 2]

    // This is the correct way to apply the Loft operator:
    var curve1 = ActiveSceneRoot.AddGeometry( "Arc", "NurbsCurve" );
    Translate( curve1, null, null, 2 );
    var curve2 = ActiveSceneRoot.AddGeometry( "Arc", "NurbsCurve" );
    var cnxset = curve1 + "," + curve2;

    var oplist = ApplyOp( "Loft", cnxset );
    var msh = oplist.Item( "OutputObjs" );

This could obviously be avoided by using the correct type of connection set for the operator. However, sometimes your script has to rely on the user to supply input arguments. In this case, you need to make sure you test that input before even calling the command. For example, if you are applying the Loft to a connection set supplied by the user, you could write something like this:

    /*
       This function demonstrates how to provide checks to input objects that
       could cause your scripts to break.
    */
    function MakeMesh( in_cnxset )
    {
       var allgood;
       // It should be either a string or a selection
       if (typeof(in_cnxset) == 'object') {
           // If it's an object, find out if it's the Selection
           if (ClassName(in_cnxset) == "Selection" ) {
              // Check to make sure that we have at least two items
              if (in_cnxset.Count < 2) {
                  LogMessage( "You need at least two curves for Lofting." );
                  allgood = false;
              } else {
              // Check each member to make sure that it's a curve
                  var e = new Enumerator(in_cnxset);
                  for ( ; !e.atEnd(); e.moveNext() ) {
                     var chkit = e.item();
                     if (chkit.Type != 'crvlist') {
                         LogMessage( "You have the right number of objects,"
                             + " but the wrong type!" );
                         allgood = false;
                         break;
                     }
                  }
                  // At this point, all collection members must have been valid
                  allgood = true;

                  // Convert Selection to a real connection set (string)
                  in_cnxset = in_cnxset.GetAsText();
              }
           } else {
              // There are more possibilities (like XSICollections) that could
              // still be correct that you could test for here, but let's
              // assume that no other kind of object is acceptable
              LogMessage( "What did you give me?!? -- Try again." );
              allgood = false;
           }
       } else {
           // If it's not the Selection object make sure it's a string (that is,
           // a real connection set)
           if (typeof(in_cnxset) == 'string') {
              // Real connection sets should actually report that they are
              // strings. To make sure it's a good connection set, we have to
              // examine each item by splitting the string into an array
              // (assuming that it's delimited by commas ',')
              var mbrs = in_cnxset.split( "," );
              for (var m=0; m<mbrs.length; m++) {
                  // Find each item in the scene and make sure that it's
                  // really a curve
                  var fnd = ActiveSceneRoot.FindChild( mbrs[m] );
                  if (fnd != null) {
                     // Make sure we found something to test (avoiding errors)
                     if (fnd.Type != 'crvlist') {
                         // If any member is not a curve, it's no good...
                         LogMessage( "This contains non-curve items." );
                         allgood = false;
                         break;
                     }
                  }
              }
              // At this point, all members of the connection set must be valid
              allgood = true;
           } else {
              // No other kind of data value is acceptable
              LogMessage( "Ummm -- I need at least 2 curves!" );
              allgood = false;
           }
       }

       // Whew! Now can you proceed?...
       if (allgood) {
           var oplist = ApplyOp( "Loft", in_cnxset );
           var msh = oplist.Item( "OutputObjs" );
           return "Success!";
       } else {
           return "Failure :(";
       }
    }

Sometimes you just can’t test for all contingencies. In cases where you expect the call might fail you can use something like the try...catch statement in JScript (or VBScript’s On Error Resume Next if you’re feeling really lucky). This gives you a chance to continue the script or to show an informative message to the user.

Autodesk Softimage v7.5