Rob Cohee recently posted a video demonstrating some skeletal modeling techniques in Inventor related to . To simplify the process he used a VBA macro that I wrote for him. It’s a simple macro and is useful by itself but also helps to demonstrate some API capabilities. Here’s the macro that I provided Rob.
Public Sub AlignOccurrencesWithConstraints()
Dim assemblydoc As AssemblyDocument
Set assemblydoc = ThisApplication.ActiveDocument
' Get the occurrences in the select set.
Dim occurrenceList As New Collection
Dim entity As Object
For Each entity In assemblydoc.SelectSet
If TypeOf entity Is ComponentOccurrence Then
occurrenceList.Add entity
End If
Next
If occurrenceList.Count < 2 Then
MsgBox "At least two occurrences must be selected."
Exit Sub
End If
' This assumes the first selected occurrence is the "base"
' and will constrain the base workplanes of all the other parts
' to the base workplanes of the first part. If there are
' constraints on the other they end up being over constrained.
' Get the planes from the base part and create proxies for them.
Dim baseOccurrence As ComponentOccurrence
Set baseOccurrence = occurrenceList.Item(1)
Dim BaseXY As WorkPlane
Dim BaseYZ As WorkPlane
Dim BaseXZ As WorkPlane
Call GetPlanes(baseOccurrence, BaseXY, BaseYZ, BaseXZ)
Dim constraints As AssemblyConstraints
Set constraints = assemblydoc.ComponentDefinition.constraints
' Iterate through the other occurrences
Dim i As Integer
For i = 2 To occurrenceList.Count
Dim thisOcc As ComponentOccurrence
Set thisOcc = occurrenceList.Item(i)
' Move it to the base occurrence so that if the base is
' not fully constrained it shouldn't move when the flush
' constraints are added.
thisOcc.Transformation = baseOccurrence.Transformation
' Get the planes from the occurrence
Dim occPlaneXY As WorkPlane
Dim occPlaneYZ As WorkPlane
Dim occPlaneXZ As WorkPlane
Call GetPlanes(thisOcc, occPlaneXY, occPlaneYZ, occPlaneXZ)
' Add the flush constraints.
Call constraints.AddFlushConstraint(BaseXY, occPlaneXY, 0)
Call constraints.AddFlushConstraint(BaseYZ, occPlaneYZ, 0)
Call constraints.AddFlushConstraint(BaseXZ, occPlaneXZ, 0)
Next
End Sub
' Utility function used by the AlignOccurrencesWithConstraints macro.
' Given an occurrence it returns the base work planes that are in
' the part or assembly the occurrence references. It gets the
' proxies for the planes since it needs the work planes in the
' context of the assembly and not in the part or assembly document
' where they actually exist.
Private Sub GetPlanes(ByVal Occurrence As ComponentOccurrence, _
ByRef BaseXY As WorkPlane, _
ByRef BaseYZ As WorkPlane, _
ByRef BaseXZ As WorkPlane)
' Get the work planes from the definition of the occurrence.
' These will be in the context of the part or subassembly, not
' the top-level assembly, which is what we need to return.
Set BaseXY = Occurrence.Definition.WorkPlanes.Item(3)
Set BaseYZ = Occurrence.Definition.WorkPlanes.Item(1)
Set BaseXZ = Occurrence.Definition.WorkPlanes.Item(2)
' Create proxies for these planes. This will act as the work
' plane in the context of the top-level assembly.
Call Occurrence.CreateGeometryProxy(BaseXY, BaseXY)
Call Occurrence.CreateGeometryProxy(BaseYZ, BaseYZ)
Call Occurrence.CreateGeometryProxy(BaseXZ, BaseXZ)
End Sub
The program above constrains the base work planes of the set of selected occurrences to the base work planes of one other selected occurrence (the base part). It places three flush constraints between each part and the base part. The advantage to this is that the occurrences are all constrained to the base part so that if the base part is repositioned all of the other parts will automatically move to maintain the relationship defined by the constraints. The disadvantage is that it’s doing quite a bit of work and each constraint placement causes the assembly to recompute, which is what gave Rob time to go get coffee.
There’s another approach that is much faster if you just need to position parts but don’t need to associate their position to another part. The macro below does this. It’s simpler and runs much faster. This macro positions the parts exactly as the previous macro but instead of creating constraints it just repositions them and then grounds them so they can’t be accidentally moved.
Public Sub AlignOccurrencesWithGround()
Dim assemblydoc As AssemblyDocument
Set assemblydoc = ThisApplication.ActiveDocument
' Get the occurrences in the select set. The first occurrence
' selected will be the "base" where all of the other occurrences
' will be positioned relative to it.
Dim baseOccurrence As ComponentOccurrence
Dim baseTransform As Matrix
Dim transObjects As TransientObjects
Set transObjects = ThisApplication.TransientObjects
Dim occList As ObjectCollection
Set occList = transObjects.CreateObjectCollection
Dim transformList As ObjectCollection
Set transformList = transObjects.CreateObjectCollection
Dim entity As Object
For Each entity In assemblydoc.SelectSet
' Check that the selected entity is an occurrence.
If TypeOf entity Is ComponentOccurrence Then
' Check if the base occurrence has been assigned.
' If not then this is the first occurrence found and
' use it as the base occurrence.
If baseOccurrence Is Nothing Then
Set baseOccurrence = entity
Set baseTransform = baseOccurrence.Transformation
Else
' This is another selected occurrence so just
' add it to the list.
occList.Add entity
transformList.Add baseTransform
End If
End If
Next
' Check that at least a base occurrence and one other occurrence
' was selected.
If occList.Count < 1 Then
MsgBox "At least two occurrences must be selected."
Exit Sub
End If
' Reposition all of the occurrences. The TransformOccurrences
' method was new in Inventor 2009.
Dim assemblyDef As AssemblyComponentDefinition
Set assemblyDef = assemblydoc.ComponentDefinition
Call assemblyDef.TransformOccurrences( occList, _
transformList)
' Iterate through the occurrences and ground them.
Dim i As Integer
For i = 1 To occList.Count
Dim thisOccurrence As ComponentOccurrence
Set thisOccurrence = occList.Item(i)
thisOccurrence.Grounded = True
Next
End Sub
Here’s one final version of this macro that is still even simpler. In the two previous macros the selected occurrences were moved relative to the location of the first selected occurrence. The macro below moves every occurrence to be positioned relative to the base assembly coordinate system. It doesn’t rely on selection but repositions every occurrence and grounds it.
Public Sub AlignOccurrencesWithOrigin()
Dim assemblyDoc As AssemblyDocument
Set assemblyDoc = ThisApplication.ActiveDocument
Dim assemblyDef As AssemblyComponentDefinition
Set assemblyDef = assemblyDoc.ComponentDefinition
' Create a matrix. It is initialized as an identity matrix
' which means it defines a position as the origin and aligned
' with the global x, y, and z axes.
Dim transGeom As TransientGeometry
Set transGeom = ThisApplication.TransientGeometry
Dim baseTransform As Matrix
Set baseTransform = transGeom.CreateMatrix
' Create collections to load the occurrences into.
Dim transObjects As TransientObjects
Set transObjects = ThisApplication.TransientObjects
Dim occList As ObjectCollection
Set occList = transObjects.CreateObjectCollection
Dim transformList As ObjectCollection
Set transformList = transObjects.CreateObjectCollection
' Iterate through all of the occurrences.
Dim occurrence As ComponentOccurrence
For Each occurrence In assemblyDef.Occurrences
' Add each occurrence to the list.
occList.Add occurrence
' Add the transform to the list.
transformList.Add baseTransform
' Ground each occurrence. This is ok to do here
' because the move will ignore the ground condition.
occurrence.Grounded = True
Next
' Reposition all of the occurrences. The TransformOccurrences
' method was new in Inventor 2009.
Set assemblyDef = assemblydoc.ComponentDefinition
Call assemblyDef.TransformOccurrences(occList, _
transformList)
End Sub
Of course these macros just the demonstrate one solution using the API to a specific problem. The same functionality demonstrated above and combined with other API functions can be used in many other ways to solve other problems. All I’m trying to say is that if the macros above don’t quite do what you need them to do it’s time to start investigating Inventor’s API so that you can modify them to solve your specific problems.