You are on page 1of 13

VBA/API - Part 2

By Neil Munro Last time, we built the user interface for a center of gravity tracker for Autodesk Inventor assemblies. This month we'll add the programming code to insert a special center of gravity (Marker) part, position the Marker part at the assembly, and display the assembly COG coordinates in the current document units.

Download Files
First download, unzip, and save to a folder in your current project, the COG_A.zip file. It is important that the Marker.ipt file in the zipped file be placed in a folder included in the active project. COG_A.zip (zip - 90Kb) You can download the files used in this tutorial from here.

Figure 1: Sizing and alignment tools. The zipped file contains the following files: Marker.ipt COG_A.ivb The included part file (Marker.ipt) is designed specifically for use as an assembly COG marker and the part has the following properties:

1. All part features are controlled by a user-defined scale variable. 2. The part's material is defined as having zero density. 3. The part will not affect COG calculations. The part is symmetrical about the origin geometry. The part's origin planes, axes, and center point can be used as a COG coordinate system in the assembly. The COG_A.ivb file contains the results of last month's tutorial. Feel free to continue on with your own file, but if you missed out, rename this file to COG.ivb and load the project through the Autodesk Inventor VBA IDE. 1. Select Tools > Macro > Visual Basic Editor from the Autodesk Inventor pull-down menu. 2. Select File > Load Project from the VBA pull-down menu. Browse to the folder containing COG.ivb and load it. Review and a Tip Last month's tutorial concentrated on building a user interface for our macro. We placed controls on a form, and then adjusted property values of the controls to format the form to our liking. Finally, we added program code that runs when a user clicks the Cancel or More buttons on the form. The VBA IDE contains a number of tools for sizing and aligning the controls on a form. By default, controls snap to a grid. You can control the grid spacing on the General tab of the Options dialog box (select Tools > Options from the VBA pull-down menu). A selection of alignment and sizing tools is available on the Userform toolbar (select View > Toolbars > Userform from the VBA pull-down menu). You can align and size controls at the same level on a form. Controls within a Frame control are at a different level than controls outside the Frame control. You can select any number of controls, and the last control selected is used as the seed for alignment and sizing. In the top image of Figure 1, the two label controls are selected. The topmost label control is the seed control for sizing and alignment (white grip points). In the middle image, the controls are aligned on their left edges (Label2 aligned to Label1). The bottom image has both controls matched in height and width. Additional spacing and grouping controls are available on the toolbar and from the Format menu.

Autodesk Inventor Objects

Figure 2: Assembly COG project object hierarchy. If you have not read the API overview included in the Autodesk Inventor Programming Help, do so before proceeding. You don't need to understand everything presented there, but it provides a background for this tutorial. Our macro requires access to a number of Autodesk Inventor objects. We'll look at specific objects in detail as we access them. Figure 2 includes a hierarchy of all objects required for our program. You can download a PDF file outlining the complete Autodesk Inventor object hierarchy from the Autodesk Inventor Product Resources on Autodesk.com.

Figure 3: Require variable declaration. The object tree may look quite complicated, but don't be frightened off. Object names are usually quite descriptive and the relationships are similar to the hierarchy shown in Autodesk Inventor browsers. Let's quickly overview the objects depicted in Figure 2. The two objects directly below the Application object are the AssemblyDocument and TransientGeometry objects. TransientGeometry objects, such as points and matrices, are placeholders for geometric information required to place or move real geometry. In our macro, we'll use a Matrix object (contains position and rotation information) to hold information required to move the Marker part to the current assembly COG.

The AssemblyDocument object represents an assembly file. There are two first-level children of this object that are of interest to us for this macro, the UnitsOfMeasure object and the AssemblyComponentDefinition object. All Autodesk Inventor parameters are unit specific for each document. The UnitsOfMeasure object enables us to retrieve and set unit types and precision. Our program will display the assembly COG coordinates in the current length units for the document. While the AssemblyDocument object represents the assembly file, its first-level child, the AssemblyComponentDefinition object contains the geometry in the file. It is through this object that we can obtain assembly mass properties and information about assembly components. The MassProperties object is a key object in our program. It contains a CenterOfMass property that holds the X, Y, and Z coordinates of the assembly COG. No complex calculations are required; our goal is simply to retrieve this information and move our Marker part there. An assembly is made from parts and subassemblies related by assembly constraints. You can access assembly components in the assembly through the API, and we'll use this to find the Marker part across Autodesk Inventor sessions. You can then move the Marker part into position, scale it, and control the visibility of its origin geometry. We'll examine these objects in more detail later in the tutorial. Variables and Variable Scope Variables are named storage locations that can be modified during program execution. They can store either a single instance or arrays of numbers, strings, and even objects. Good programming practice includes declaring each variable to hold only a specific type of information, such as an integer, string, or a CenterOfMass object. When you declare a variable as a specific object type, it enables the IntelliSense feature in VBA to present the properties and methods associated with the object as you use it in a program statement. Failure to declare variable types often results in difficult-to-solve program errors. VBA can check for undeclared variables if you check the Require Variable Declaration option on the Editor tab of the Options dialog box. (Select Tools > Options from the VBA pull-down menu.) (See Figure 3.)

Figure 4: IntelliSense variable type selection. Variable scope is the life span of a variable. Our program consists of a number of separate

procedures (subroutines and functions), some of which have variables that are only accessible by code in that procedure. Other variables must be accessed from different procedures in the program. You can declare a variable outside a procedure to make it accessible throughout all or parts of a program. If you are not familiar with this programming concept, take a minute to read the VBA Help topics Understanding Scope and Visibility. Search for scoping levels in the VBA Help Index. Declaring Form-Level Variables Still confused? Let's declare some object variables that will be accessed from a number of different procedures in our program. 1. Right-click frmCog in the project explorer and select View Code from the shortcut menu. 2. Scroll to the top of the code window. Enter Option Explicit as the first line in the code window if it is not already present. This turns on variable declaration checking (for all code in the form) even if it was not specified in the Options dialog box. You must declare variables that will hold the objects outlined in our project object model (see Figure 2). Because you are declaring them outside a specific procedure, but inside the form, they will be available from all the procedures created within the form. 3. Type Private m_oDoc as asse under the Option Explicit line (see Figure 4). 4. Note the IntelliSense window scrolls to the first type that matches the current text after the word as. Select AssemblyDocument as the object type for this variable. What about the notation used for the variable name? It is common practice to precede variable names that are declared outside a procedure with an m_ (module) or g_ (global) to indicate the scope of the variable. The variable was preceded by the word Private, making it accessible to all procedures defined inside the form (called module- or form-level variable scope). Procedures in other forms or modules will not be able to access this variable. A Public declaration would make the variable accessible in all procedures in all program modules (a global variable). Declaring Public variables should be avoided if possible; it is easy to lose track of when and where the value of a global variable is changed. The lower case o that precedes the variable name is a reminder that the variable holds an object. Note: Variables that hold objects are often referred to as object variables. 5. Declare the following variables as Private variables in the form (for example, Private m_oTG as TransientGeometry). Variable Name m_oTG Variable Type TransientGeometry

M_oCompDef m_oMassProps m_oOccMarker m_ouom

AssemblyComponentDefinition MassProperties ComponentOccurence UnitsOfMeasure

Document Checking and Form Initialization When a user runs the macro for the first time in an Autodesk Inventor session, the form is loaded by the frmCog.Show statement in the macro. Since the macro only makes sense in an assembly document, we'll add a few lines of code to check if the active document is an assembly.

View Larger Figure 5: Checking for assembly document. 1. In the project explorer, expand the Modules folder and double-click Module1. 2. In the CogTool subroutine, enter the code shown in Figure 5 above the line that loads the form. The code checks the current document and exits without loading the form if the document is not an assembly. 3. Return to the code window for frmCog. 4. Scroll down to the Userform_Initialize routine. You entered one line of code there in the last tutorial to set the height of the form as it loads.

View Larger Figure 6: Checking for assembly document. During the loading of the form, we'll assign values to the object variables declared earlier in the

tutorial. To assign a value to an object variable, you must use the Set keyword. Variables that are not objectsare assigned values without the Set keyword. 5. Enter the code shown in Figure 6. ThisApplication is interpreted as the Autodesk Inventor Application object because VBA is running inside Autodesk Inventor. Refer to our object model (see Figure 2) to track the relationship of the objects created. Note: The green text items are comments. It is highly recommended that you add comments to your code as you go. You will find it difficult to understand any lengthy uncommented program when you return to edit it tomorrow or six months from now. Anything after the first single quote in a line is interpreted as a comment.

Finding the Marker Part

Figure 7: Function creation. The Marker part may or may not be present in the assembly when the macro is run. The program must check for the Marker part, and enable or disable various controls based on the answer. How do we check to see if the Marker part is present? Well, there are number of possible solutions, but some are not yet documented. You could check the browser name of every component in the assembly, but what if someone renamed the part in the browser? We'll check the file name of all referenced components in the assembly, which could also fail if the Marker.ipt file is renamed. The challenge of finding the Marker part in a large assembly still remains. In a five-thousandpart assembly, there will almost certainly be a smaller number of unique first-level components. The AssemblyComponentDefinition has an object property that contains the unique component definitions (first level) in the assembly. We'll search through these to find the Marker part. The question of whether the Marker part is currently in the assembly is one that may be asked at

different points in the program. The programming code to ask this question will be placed in a user-defined procedure, so that it can be called from anywhere in the program. Note: The information required from this routine is a simple yes or no. The userdefined procedure will be in the form of a function, rather than a subroutine. A function differs from a subroutine in that the results of the procedure are returned in the function name. This enables the function to be called in an expression. The subroutine presented in the first VBA tutorial (last month) is shown below as a function.
Public Function AddTwo (Int1 as Integer, Int2 as Integer) as Integer AddTwo = Int1 + Int2 End Sub

An example of code that calls the function:


Answer = AddTwo (5, 6)

Create the IsMarkerLoaded function. 1. Select Insert > Procedure from the VBA pull-down menu. 2. Enter IsMarkerLoaded as the procedure name (see Figure 7). 3. Select Function and Private as the Type and Scope respectively. 4. Click OK.

View Larger Figure 8: Function code. 5. Enter the code shown in Figure 8 and then enter the code in Figure 9 to complete the function. The comments are not required but recommended. Let's review the code in Figures 8 and 9. The unique component definitions in the assembly are obtained and iterated through using a loop. The component definitions are stored in a VBA collection (group of common items). The collection has a Count property (number of items in the

collection) and an Item property to enable index-based access to individual objects in the collection. Check the object model in Figure 2 against the code to help understand the hierarchy.

View Larger Figure 9: Function code completed. The associated file name of each component definition is compared against Marker.ipt to find the Marker part in the assembly. If it is found, all extra occurrences of Marker.ipt in the assembly are deleted (after warning the user). The ImmediateOccurences collection holds all occurrences of the component in the assembly. When you remove an item from a collection, all items above the removed item drop down one item number. If there are three occurrences of the Marker part in the assembly, deleting the second item in the collection will leave a first and second item in the collection. Deleting the second item again removes the original number-three item. The function name is then assigned a value of True to indicate the part was found. Finally, you assign the Marker part occurrence to the previously declared module-level object variable m_oOccMarker. Completing the Form Setup After all that, you can now complete the code in the Userform_Initialize subroutine.

Figure 10: Form initialization based on Marker part presence. 1. Add the code in Figure 10 inside the Userform_Initialize subroutine (at the end of the existing

code). Based on the answer to the search for Marker.ipt, you set the state of the controls on the form. Disabled command buttons appear grayed out and do not react to user interaction (for example, mouse click). The UpdateXYZ subroutine updates the display of the assembly COG coordinates on our form. We'll add the UpdateXYZ routine later in the tutorial.

Inserting the Marker Part


You can now write the code to insert an occurrence of Marker.ipt in the assembly. The code can be inserted into the cmdInsert_Click subroutine, but we'll call a user-defined subroutine to perform this task. 1. In the cmdInsert_Click subroutine, enter the following line of code:
Call InsertMarker

2. Add a Private subroutine named InsertMarker to the form.

View Larger Figure 11: Setup prior to Marker part placement. 3. Add the code shown in Figure 11 to the InsertMarker subroutine. The code in Figure 11 creates a transient (temporary) matrix that is then filled with the coordinates of the assembly COG. The rotation portion of the matrix is left at the default of zero rotation about each axis. How do we know what information is required by the SetTranslation method of the Matrix object? To obtain help on any object, property, or method, click on the word and press the F1 function key. This displays a help page outlining syntax, argument types, and often includes example code. Go ahead, try it. The most important part of the help system is the sample code section. Many short examples demonstrate how to perform basic operations, such as placing a component in an assembly. Everything is now in place to insert the Marker part. Thinking ahead like good programmers do, we realize that the Marker part may not always be in a folder where Autodesk Inventor can find it (in a project path). An error will occur in our program if the Marker part cannot be found. To

handle this possibility, we'll add code to capture and recover from the error. There are numerous techniques for error handling in VB/VBA; we'll use a technique that handles errors for a single instruction (turn on error handling, execute the code statement that may produce an error, handle the error if it occurs, and finally turn off error handling).

View Larger Figure 12: Insert Marker part. 4. Add the code shown in Figure 12 to the InsertMarker subroutine. Most of the code in Figures 12 and 13 is easy to understand (again, use comments for your own benefit). The line of code placing the Marker part occurrence in the assembly assigns the occurrence to the module-level m_oOccMarker variable. You can now access the Marker part directly through this variable.

View Larger Figure 13: Code to complete InsertMarker subroutine. 5. Complete the subroutine by adding the code in Figure 13 immediately below the On Error Goto 0 line.

Updating the XYZ Labels


Your last task is to update the labels on the form to display the assembly COG coordinates. The form remains visible while you are working in Autodesk Inventor software, so the assembly COG coordinates are always visible.

View Larger Figure 14: Update labels subroutine. 1. Scroll down to the end of the code window and enter the code shown in Figure 14. You can add subroutines and functions without using Insert > Procedure from the pull-down menu. You use the m_oMassProps object variable that was set during form initialization to provide the assembly COG data. For each label, you call a function (value returned in the function name) named ToFourDec to generate a string containing the coordinate in the current document units.

View Larger Figure 15: Generating coordinates in local units. 2. Finally, add the ToFourDec function by entering the code shown in Figure 15. The ToFourDec function is an example of working with values and units in Autodesk Inventor. All distance values in Autodesk Inventor are stored internally in centimeters. All angular values are stored in radians. Users will expect that the information displayed will use the current document units. The UOM object contains methods to convert internal units to documents units. To obtain help on the VBA functions (for example, Format$, or CStr), click on the word and press the F1 function key. Note: The first statement in the ToFourDec function has an underscore chanracter at the end of the first line. VBA interprets this as a continuation character, with the remainder of the statement on the second line. You can type the statement on a single line; we broke the line to fit the graphic on the page. Testing the Macro Let's test our efforts up to this point. 1. Ensure the Marker.ipt is located in a current project path. 2. Open an assembly containing a few components.

3. Select Tools > Macros from the VBA pull-down menu. 4. Click Run in the Macros dialog box. The form loads, and the Insert command button is the only enabled button. 5. Click the Insert button. The Marker part is placed in the assembly, and the form displays the assembly COG coordinates. 6. Click Cancel. 7. Run the macro again. This time the program finds the Marker part is present in the assembly. The Insert button is disabled, and the Update button is enabled. 8. Click Cancel. 9. Place one or two additional occurrences of Marker.ipt in the assembly. 10. Run the macro again. A message is displayed warning of the extra Marker part occurrences, and the extra occurrences are deleted. 11. Click Cancel

Conclusion
Learning both the VBA and Autodesk Inventor object models is a substantial task. Examining code written by others is a great learning opportunity. Another excellent resource is the great number of books available on VB/VBA programming. Next month we'll conclude (finally) this project by adding an Update routine, code to scale the Marker part, and routines to get and set the visibility of the Marker part's origin geometry. Also, look for an introduction to the new Autodesk Inventor Series, which includes Autodesk Inventor 5.3 and Autodesk Mechanical Desktop 6.

You might also like