Reference keys is a topic that not many people know about or understand and is an area I’ve seen people struggle with and misuse. Reference keys are not something you’ll use often in your programs but can be very handy in certain cases.
What is a Reference Key? A reference key is the ID of an object within Inventor. You use the GetReferenceKey method of an object to get its ID, or “key”. You save the ID and at a later time use it to get the same object back. A reference key doesn’t have any time limits, which means you can get the reference key from an object, and the document can go through many changes and versions, and you can still use the reference key to find the same object, even though the object may have changed from when you originally got its reference key. Of course, this assumes the object still exists and hasn’t been deleted or removed through some edit operation.
Below is some sample code that gets the reference key from a selected assembly occurrence. By changing the selection filter the code below will work with any object that supports reference keys except for B-Rep objects (SurfaceBody, FaceShell, Face, Edge, Vertex, EdgeLoop, and EdgeUse) which are discussed later.
Public Sub GetRefKey() ' Get the active document. Dim doc As Document Set doc = ThisApplication.ActiveDocument
' Have an object selected. Dim selection As Object Set selection = ThisApplication.CommandManager.Pick( _ kAssemblyOccurrenceFilter, _ "Select an occurrence.")
' Get a reference key from the selected entity. This will ' fail if the selected object doesn't support reference keys. Dim refKey() As Byte Call selection.GetReferenceKey(refKey)
' Convert the reference key to a string to make saving it easier. Dim strKey As String strKey = doc.ReferenceKeyManager.KeyToString(refKey)
' Print out the reference key string. Debug.Print "RefKey: """ & strKey & """" End Sub
There are a couple of interesting things to note in the above sample. First, a reference key is an array of bytes. A byte is a number between 0 and 255 so a reference key is just a list of small numbers. Second, Inventor creates the reference key and returns it but it’s up to you to save it somewhere so you can use it later. If you’ll be writing out the reference key to a file it’s easier to deal with a String instead of an array of numbers. The KeyToString method does this for you by converting the array of bytes into a String. Later, when you need to use the key, you can use the StringToKey method to convert the String back into an array of bytes. The sample above just prints the result to the immediate window, which in my test resulted in: “AgEBAAQAAAABAAAA”.
General reference key functionality is exposed through the ReferenceKeyManager object which is obtained from a Document object. Every object that supports reference keys has the GetReferenceKey method.
Now that you have a reference key you can use it at any time, with the same document, to get back the same object. The sample below demonstrates this.
Public Sub BindRefKey() ' Get the active document. Dim doc As Document Set doc = ThisApplication.ActiveDocument
' Convert the string back into an array of bytes. Dim refKey() As Byte Call doc.ReferenceKeyManager.StringToKey("AgEBAAQAAAABAAAA", _ refKey)
' Bind the key back to the object. Dim obj As Object Set obj = doc.ReferenceKeyManager.BindKeyToObject(refKey)
' Select the object to be able to see the found object. doc.SelectSet.Clear Call doc.SelectSet.Select(obj) End Sub
Basic Reference Key Workflow The concept of a reference key is fairly simple. The steps are:
Get a reference key from an object.
Save the reference key.
Use the reference key at a later time to get back the same object.
Common Problems There are a few gotchas to be aware of that I’ve seen people struggle with before.
A reference key is only good with the same document you originally got it from.
You should ignore the actual value of a reference key. You shouldn’t compare reference keys themselves to check if two reference keys came for the same object. It’s possible that reference keys with different values will bind back to the same object. Because of this you should always bind both reference keys back to their objects and then compare the objects to see if they’re the same.
You must use a reference key context when working with B-Rep entities. This is discussed below. It’s not needed with other types of objects.
B-Rep Entities and Reference Keys When using reference keys with B-Rep entities the concepts shown above still apply but there is some additional work that you need to do. B-Rep entities don’t have a simple internal identifier like other objects. It’s much more complicated for Inventor to be able to find a specific B-Rep entity because they can go through significant changes as modeling operations are performed. A way to visualize how Inventor can find a specific B-Rep entity is to think of the reference key as a set of instructions that identify a particular entity. For example a specific edge might be identified as the intersection of two faces and the faces might be identified by which sketch line was used to create that face as part of an extrusion. Because of the large amount of information that could be in these instructions, a reference key to a B-Rep entity can be quite large. In order to minimize the size of B-Rep reference keys and also improve performance, the idea of a reference key context was introduced. You can think of the context as a table where the instructions are saved. Several reference keys might use one or more of the same instructions. Having this information in a table allows individual instructions to be re-used. What this means is that a B-Rep reference key isn’t the full set of instructions but is a set of references into this table. This significantly reduces the size of each reference key.
Here is the process of using reference keys for a B-Rep entity, where the new steps are in bold.
Create a reference key context.
Ask an object for its reference key and also providing the key context.
Continue to get reference keys from other objects, using the same key context.
Save the reference keys.
Save the key context.
Use the reference key and the key context at a later time to get back the same object.
The process is essentially the same as described above for non B-Rep entities except for when you ask an object for a reference key or bind back a reference key to an object you also need to provide the key context. The program below is similar to the previous sample except it works for B-Rep entities.
Public Sub GetBRepRefKey() ' Get the active document. Dim doc As Document Set doc = ThisApplication.ActiveDocument
' Have a face and edge selected. Dim selFace As Face Set selFace = ThisApplication.CommandManager.Pick( _ kPartFaceFilter, "Select face.") Dim selEdge As Edge Set selEdge = ThisApplication.CommandManager.Pick( _ kPartEdgeFilter, "Select edge.")
' Set a reference to the ReferenceKeyManager object. Dim refKeyMgr As ReferenceKeyManager Set refKeyMgr = doc.ReferenceKeyManager
' Create a key context. Dim keyContext As Long keyContext = refKeyMgr.CreateKeyContext
' Get reference keys from the selected entities. Dim faceRefKey() As Byte Call selFace.GetReferenceKey(faceRefKey, keyContext) Dim edgeRefKey() As Byte Call selEdge.GetReferenceKey(edgeRefKey, keyContext)
' Get the key context as an array of bytes and ' convert it to a string. Dim contextArray() As Byte Call refKeyMgr.SaveContextToArray(keyContext, contextArray) Dim strContext As String strContext = refKeyMgr.KeyToString(contextArray)
' Convert the reference keys to strings to make saving it easier. Dim strFaceKey As String strFaceKey = doc.ReferenceKeyManager.KeyToString(faceRefKey) Dim strEdgeKey As String strEdgeKey = doc.ReferenceKeyManager.KeyToString(edgeRefKey)
' Save the results to a file. Open "C:\Temp\RefKeys.txt" For Output As #1 Print #1, strContext Print #1, strEdgeKey Print #1, strFaceKey Close #1 End Sub
You may have noticed in the last sample that the variable used for the key context is typed as a Long. Of course, this value isn’t the key context table but is a pointer to the context. Whenever a key context is needed you pass the pointer to the context and when you create a context, a pointer is returned for you to use. When you save the key context along with the reference keys you need to save the full table, not the pointer. The SaveContextToArray method returns an array of bytes that is the full table. This is the data that you need to save, along with any reference keys that were created. The code below binds back to the B-Rep entities.
Public Sub BindBRepRefKey() ' Get the active document. Dim doc As Document Set doc = ThisApplication.ActiveDocument
' Get a reference to the reference key manager. Dim refKeyMgr As ReferenceKeyManager Set refKeyMgr = doc.ReferenceKeyManager
' Read the reference key strings from the file. Dim context As String Dim edgeKey As String Dim faceKey As String Open "C:\Temp\RefKeys.txt" For Input As #1 Line Input #1, context Line Input #1, edgeKey Line Input #1, faceKey Close #1
' Convert the string to byte arrays. Dim edgeRefKey() As Byte Dim faceRefKey() As Byte Dim contextArray() As Byte Call refKeyMgr.StringToKey(edgeKey, edgeRefKey) Call refKeyMgr.StringToKey(faceKey, faceRefKey) Call refKeyMgr.StringToKey(context, contextArray)
' Create the context by loading the data. Dim refKeyContext As Long refKeyContext = refKeyMgr.LoadContextFromArray(contextArray)
' Bind back the face and edge. Dim foundFace As Face Dim foundEdge As Edge Set foundFace = refKeyMgr.BindKeyToObject(faceRefKey, _ refKeyContext) Set foundEdge = refKeyMgr.BindKeyToObject(edgeRefKey, _ refKeyContext)
' Highlight the found entities. doc.SelectSet.Clear doc.SelectSet.Select foundFace doc.SelectSet.Select foundEdge End Sub
Differences with B-Rep Entities when Binding Back There’s a difference when binding back B-Rep entities from other types of entities. The BindKeyToObject method can return an ObjectCollection in the case where the original B-Rep entity has been split into two or more pieces. The picture below shows the progression of a model and the changes that can take place to a face. In the last step face 2 is split into two pieces by an extrude feature. When binding back, both faces will be returned in an ObjectCollection.
Below is some modified code from the sample above that handles this case. When multiples are returned the first one in the collection is considered the “best” match with no priority for the rest of the entities.
' Bind back the face and edge. Dim foundFaces As Object Dim foundEdges As Object Set foundFaces = refKeyMgr.BindKeyToObject(faceRefKey, refKeyContext) Set foundEdges = refKeyMgr.BindKeyToObject(edgeRefKey, refKeyContext)
' Highlight the found entities, special casing for the case where ' more than one might have been returned doc.SelectSet.Clear If TypeOf foundFaces Is ObjectCollection Then Dim obj As Object For Each obj In foundFaces doc.SelectSet.Select obj Next Else doc.SelectSet.Select foundFaces End If
Important Points Here are a few points that I want to emphasize when using reference keys with B-Rep entities.
A single context can be used, and is intended to be used, for multiple reference keys. That’s the reason that the concept of the reference key context was created; so that multiple keys can share the same set of instructions for finding specific entities.
A reference key context and reference keys will only work with the same document they were originally obtained from.
Reference keys will only work with the same reference key context they were originally created with.
When working with B-Rep entities, write code that can handle the return of either a single object or an ObjectCollection.
The BindKeyToObject method can fail if the entity is not available. The CanBindKeyToObject method can be used to first check to see if the key can bind back.
Why Use Reference Keys? An expected question at this point might be why would anyone want to use reference keys? They’re a generic tool that can be used in many ways but here are some examples.
Support associativity in an external read-only application This is one of the more common uses of reference keys. Applications are able to use Apprentice to read B-Rep data and display the model in their application. When the user selects geometry in their applications they’re able to get the corresponding geometry in Apprentice and get the reference key. For example, the geometry might used for a tool path or to position a load or constraint for analysis. Getting reference keys from objects does not require write access to the model. When the model is edited in Inventor they can read in the new geometry and use the reference keys to find the geometry and update their data if the geometry has changed.
Maintaining a reference over a re-compute This is one of the more common general uses of the functionality. An example of this is if you want to write a program that finds all of the circular planar faces in a model and places a hole feature at the center of each one. The first part of your programs finds all of the circular planar faces and then it begins placing holes on each one. The problem is that any references to B-Rep entities are no longer valid after any change has been made to the model. Creating the first hole invalidated all of the references you have to the circular faces. You don’t want to do the analysis again to find circular faces because you’ve potentially added new circular faces by placing the new feature.
Reference keys can help you solve this. Instead of maintaining a reference to a Face object you can get the reference key of each circular planar face. Reference keys are still valid after a compute, so after you create the first hole you can find the next circular planar face by using the saved reference key.
Attributes Attributes can be used in some cases to solve the same issues that reference keys do by providing a way of adding information to an object to find it later. Attributes have the advantage that they’re self-contained and you don’t have to save any information. They also have the advantage of supporting a more powerful search mechanism. They have the disadvantage that they require write access to the file and will require the document to be saved. They also have the disadvantage that they don’t return multiple objects in the case where B-Rep entities have been split.
What Are Transient Keys? There’s one more thing that I want to quickly touch on, which is transient keys. Transient key functionality is only available with B-Rep entities. Each of the B-Rep entities supports the TransientKey property which returns a Long value. This is a simple identifier for that specific B-Rep entity. You can bind back to the B-Rep entity with the transient key using the BindTransientKeyToObject method on the SurfaceBody object. This is much simpler than reference keys because it’s just a single Long and you don’t need a key context. However, there’s a BIG limitation with transient keys. They’re only good as long as the model has not been modified. They’re similar to a live reference to a B-Rep entity in that it doesn’t survive through a model compute.
The purpose of transient keys is to provide the ability to match up B-Rep entities when copying bodies. For example, the AlternateBody property of the SurfaceBody returns a copy of the body it was called on. The new body may even be slightly different than the original body, (for example, some faces may have been split into two). The new body has transient keys that you can get from each B-Rep entity. You can use the BindTransientKeyToObject method to find the equivalent B-Rep entity on the original body. It’s also possible to write out a body as SAT where the transient keys are also output as attributes on the SAT data. This again allows you to match up the B-Rep entities from this output model to the original Inventor model, as long as the model has not been edited since the copy was created.
Quite a few years ago I wrote a little utility that lets you create, view, and edit attributes within a document. If you’re relatively new to the Inventor API and are wondering what attributes are, here’s a post giving a quick introduction.
I’ve used the utility quite a bit over the years and haven’t had any problems but someone recently reported a problem they were having and I had a hard time believing that the problem could exist. I was finally able to reproduce the problem and found out it could be a fairly common problem, it’s just that I happened to always use a certain workflow that avoided it. That’s why it’s always good to get someone else to help test your programs.
I’ve fixed the problem and have a new version available. If you already have a version of “Attribute Helper” installed, you should first uninstall the version you have, which you can do using the standard Windows uninstall utility where you should see “Attribute Helper” listed as one of the installed programs, as shown below.
Once it’s uninstalled, you can install the new version of Attribute Helper. There is some help documentation delivered with the utility with instructions on how to use it and you can quickly determine if it was installed correctly by checking to see if the Attribute Helper command is now available in the Tools panel when you have a document open.
And when you run the Attribute Helper command, you should see the dialog below with the version displayed being “2.4”, as shown below.
A developer just ran into an issue with OnFileResolution when handled inside an application using InventorApprentice. No matter what value they set the FullFileName parameter to, it got ignored.
Wayne already blogged about running into issues with events, but I've only experienced it in a way that the event was not caught at all. This time it is caught but the parameter change has no effect. The same trick helps here too though: make sure that Embed Interop Types is set to False.
IdeaStation's are a good idea for tracking wishes. This way people can also see ideas that they too thought of, but did not actually log in the end thinking that not many people would care about them. Now they just have to give a thumbs up :) - Inventor IdeaStation - Fusion IdeaStation
Though they were mainly created for product wishes, I do not see why they could not also be used for API wishes - and some people are using them for that already.
If you plan to log there an API wish then please use the API-iLogic category add a tag that would make it easier to track those kinds of wishes: InventorApi for InventorAPI wishes, and FusionApi for FusionAPI wishes. If it simply has an API tag and you click on it then it shows the wishes for all the products. Note: I use InventorApi instead of InventorAPI, because for some reason the system automatically turns the tag name into that. :-/
Several years ago I wrote an add-in that creates custom iProperties and parameters that contain the length and width of the flat pattern. (Actually it creates the parameters and sets the “Export Parameter” setting so Inventor will automatically created the iProperties.) It also creates an iProperty with the name of the sheet metal style. There had been a couple of problems reported and everything that I’m aware of has now been fixed.
I know there are several people making use of this add-in but since I originally wrote it Inventor has added additional new native capabilities that should eliminate the need for my add-in in many cases. One of these capabilities, that’s not widely known, is the ability to define expressions for parameter values. This is demonstrated in the picture below where the value of the iProperty named “SheetMetalWidth“ has the value “=<Sheet Metal Width>”. The name can be anything but the value is important. The “=” sign signifies that the iProperty value is an expression and the “<>” sign wraps around a known name. In this example I’m using “Sheet Metal Width” and “Sheet Metal Length” as the known names.
You can also create a single parameter that combines several values in the expression such as “=<Sheet Metal Length> x <Sheet Metal Width>”, which results in the value of the iProperty named “Full Size” as shown below. You can also use the names of iProperties in expressions to create the other example shown below where I’ve used the iProperties “Title” and “Author” to create the iProperty named “New Title”. The value of the Title property in that document is “Extent Sample” and Author is my name. When you edit iProperties that use a function, by default the result is shown in the Value field but clicking the “fx” button to the right of the field will display the original expression and allow you to edit it.
Installing Sheet Metal Extents Add-In
If you still want to use my add-in you should first uninstall any existing Sheet Metal Extents add-ins you might have installed. If you installed it using an installer then you can uninstall it using the standard uninstall tool. If it was installed some other way you can manually delete it. To know what to delete, open the Add-In Manager, choose the Sheet Metal Extents add-in and look at the folder in the location field at the bottom, as shown below. You can delete the entire “Sheet Metal Extents” folder in the ApplicationPlugins folder.
To install the new add-in download and install the add-in from the link below:
After you’ve installed the new add-in you can verify you have the latest version by looking in the Add-In Manager again and checking that the add-in has the name “Sheet Metal Extents 3.5” as shown below.
I just finished working with a customer that was having a problem accessing certain functionality in the API. He had written an initial prototype in VBA that worked as expected but then when he started to convert the program to .Net some of the Inventor API objects he was using weren’t available. The reason is that he was using an old .Net interop.
The Inventor API is exposed using Microsoft’s COM technology. The contents of the API (it’s objects, methods, properties, and events) are described in a file known as a type library. When you use VBA it directly references this type library to know what’s in Inventor’s API and uses this to support Intellisense and to be able to compile and run the program. VB.Net and C# are .Net based languages and don’t support directly calling a COM API. To provide support for COM API’s .Net supports the creation of an interop library that serves as a translation layer between COM and .Net. The Interop provides the same functionality to VB.Net or C# that the type library does to VBA. It describes all of the objects and functions in the Inventor API and converts the .Net API call into a native COM call. As of the last few .Net releases this technology works very good and in almost all cases makes it completely transparent that you’re not working directly with the COM API.
When you create a new .Net or C# program to work with Inventor you need to add a reference to Inventor’s COM interop in order to have access to the API. You do this by using the References command in Visual Studio. In the dialog, use the “Browse” option to the left and then click the “Browse…” button at the bottom of the dialog.
Browse to “C:\Programs Files\Autodesk\Inventor XXXX\Bin\Public Assemblies”, (where XXXX is the version of Inventor you want to use) and select “autodesk.inventor.interop.dll”.
Your program is now dependent on the interop for that version of Inventor. Let’s say that you create a reference to Inventor 2014 and then later you uninstall Inventor and install Inventor 2015. The API is backward compatible so when you installed Inventor 2015 it installed the interop for 2015 but also installed interops for several previous versions so programs dependent on those older version will still continue to work. But it your program needs to use some functionality that is new in Inventor 2015 you need to change the reference to the newer interop where this new functionality is defined.
You can see what references an existing program has in the Solution Explorer in Visual Studio. By default they’re not shown but by clicking the “Show All Files” button a new “References” folder will appear in the tree, as shown below.
You can see more information about a specific reference by selecting it and looking in the Properties window, as shown below. In this case I’ve selected the “autodesk.inventor.interop” and it’s showing me that it’s version 184.108.40.206.
The version numbers are confusing because they don’t directly correlate with the public version of Inventor. Here’s a table showing the public version, the corresponding software version, and the internal development name.
The Inventor API supports some functionality that’s relatively new (since Inventor 2009) and is not very well known. It’s called Transient B-Rep and is accessed through the TransientBRep property on the Application object. It supports some relatively simple functionality and also some of the more complicated capabilities provided by the API. Luckily you don’t have to understand the complicated in order to use the simple.
There was a question on the Inventor Customization Forum recently that asked about being able to quickly perform many Boolean operations on a body by repeatedly moving another body and doing a difference operation. They didn’t need the resulting model to have any intelligence (i.e. be parametric) but just needed accurate geometry. The TransientBRep object supports functionality that makes this possible.
The Inventor API uses the term Transient to mean data that is not seen or saved in the document. It’s data that exists outside of the model. The TransientBRep object provides functions that are a very light wrapper over the Autodesk Shape Manager (ASM) modeling core. When you create a feature in Inventor, it’s also using ASM to do the actual model computations but it is also doing a lot more work to remember all of the feature input, adding additional information to the resulting model to allow for associativity, creating data in the browser to represent the feature, and updating the graphics to display the modified model. Although a key part of the process, the actual modeling is just a piece of all of the work that’s done. Using the TransientBRep functionality allows you to do just the modeling work without all of the overhead of creating a standard feature.
I’ve created a small sample to demonstrate the concept and illustrate how to use the API. I have a part model that contains two bodies. The yellow body will be used as the base or main part material. The red part is used as the tool. In this case it can be thought of as a punch that will be used to remove material from the base part. The punch has been built relative to the model origin, as can be seen by the base work planes.
In addition to the two bodies you can also see several work points that have been created. They’re normal work points except they’ve been named “Punch#”. as shown below. The points are used to specify locations where the tool is to be subtracted from the base.
When the macro is run it prompts you to select the base and tool bodies and then uses the TransientBrep functionality to create transient copies of those and then performs multiple Boolean operations by moving the tool and subtracting it from the base. Finally it creates a base feature using the modified base body and turns off the display of the tool and the base body so the result can be seen, which is shown below.
Below is the sample macro and here is the sample part that I used to test it. The part is an Inventor 2015 model, but this macro will work in previous versions of Inventor too.
Public Sub SampleBoolean() Dim partDoc As PartDocument Set partDoc = ThisApplication.ActiveDocument Dim partDef As PartComponentDefinition Set partDef = partDoc.ComponentDefinition
Dim tg As TransientGeometry Set tg = ThisApplication.TransientGeometry Dim tb As TransientBRep Set tb = ThisApplication.TransientBRep Dim tObjs As TransientObjects Set tObjs = ThisApplication.TransientObjects
' Have the bodies selected. Dim baseBody As SurfaceBody Set baseBody = ThisApplication.CommandManager.Pick( _ kPartBodyFilter, _ "Select the base body")
Dim toolBody As SurfaceBody Set toolBody = ThisApplication.CommandManager.Pick( _ kPartBodyFilter, _ "Select the tool body")
' Copy the two bodies to create transient copies. Dim transBase As SurfaceBody Set transBase = tb.Copy(baseBody) Dim transTool As SurfaceBody Set transTool = tb.Copy(toolBody)
' Create a matrix and a point to use in positioning ' the punch. The matrix is initialized to an identity ' matrix the point is (0,0,0). Dim trans As Matrix Set trans = tg.CreateMatrix Dim lastPosition As Point Set lastPosition = tg.CreatePoint
' Process each work point whose name starts with "Punch" ' by performing a boolean with the tool at that location. Dim wp As WorkPoint For Each wp In partDef.WorkPoints If Left$(UCase(wp.Name), 5) = "PUNCH" Then ' Transform the tool body to the position of the x and ' y coordinates work point, leaving the z as-is. The ' punch is at the last punch so the transform defines ' the difference between the last and the current. trans.Cell(1, 4) = wp.Point.X - lastPosition.X trans.Cell(2, 4) = wp.Point.Y - lastPosition.Y Call tb.Transform(transTool, trans)
' Do the boolean operation. Call tb.DoBoolean(transBase, transTool, _ kBooleanTypeDifference)
' Save the last position. Set lastPosition = wp.Point End If Next
' Create a base body feature of the result. Dim nonParamFeatures As NonParametricBaseFeatures Set nonParamFeatures = partDef.Features.NonParametricBaseFeatures Dim nonParamDef As NonParametricBaseFeatureDefinition Set nonParamDef = nonParamFeatures.CreateDefinition
Dim objs As ObjectCollection Set objs = tObjs.CreateObjectCollection Call objs.Add(transBase) nonParamDef.BRepEntities = objs nonParamDef.OutputType = kSolidOutputType
This has nothing to do with the API but is just something fun that I’ve been able to do with Inventor.
Hood to Coast is a large running relay race here in Portland each August that covers almost 200 miles and has over 1000 twelve-member teams. You can get a small idea what the race is like from the trailer of a documentary that came out a few years ago.
I’ve been on a few teams over the last several years but for the last two years I’ve designed the team T-shirts using Inventor. The first one was for an Autodesk sponsored team named “Sole of the Machine”. Actually it started out as “Soul of the Machine” but after the foot design we changed the name to match. I took advantage of the new T-Spline functionality before it was officially released to design the foot model. I also used the ray tracing in Inventor to render the final image.
Here is the final rendering of the model. You can click on the image to see a higher resolution picture.
This past August I was back with my usual team and the team name was the “Supersonic Slugs”. Here’s the T-Shirt design I modeled this year. Again, using T-Splines and the ray tracing in Inventor.
Here are larger views of the front and back images and clicking them will open a higher resolution image.