Any reasons why .FindOcurrence() Can't find geometry?

So for starters, this is not my code. I'm pretty sure user NXJournaling wrote it. With that said, I'm curious as to why .FindOcurrence() would not work?

In this case I'm hoping to find solid bodies in a component. It works for all components in my assembly except for a few. I can measure these components interactively using the Measure Bodies function so they have geometry.

Also, they do not appear to be deformed parts. Aside from that, is there any reason why .FindOcurrence() is failing to see solid bodies in the component?

Edit: Okay, so the components in question are promoted bodies...Not sure of that has something to do with it but I haven't worked with promoted bodies much.

'Get a reference to the used ref set.
For Each theRefSet As ReferenceSet In _thePart.GetAllReferenceSets
If theRefSet.Name = refSetName Then
'Find the objects in the reference set.
Dim refObjs() As NXObject = theRefSet.AskAllDirectMembers
For Each temp As NXObject In refObjs
If TypeOf (temp) Is Body Then
Dim theBody As Body = temp
If theBody.IsSolidBody Then
'We found a solid body, find the corresponding occurrence body
'in the assembly and add it to the _occurrenceBodies list.
Dim occurrBody As Body = _theComponent.FindOccurrence(theBody)
If IsNothing(occurrBody) Then
_lw.WriteLine("Could not find OcurrenceBodies in component: " & _theComponent)

Else
_occurrenceBodies.Add(occurrBody)
End If
End If
End If
Next
End If
Next

Deformed parts and promoted bodies are handled differently and FindOccurrence won't work directly in these cases. Also note that the "assembly cut" command creates one or more promoted bodies in the background.

I think that I have some old code to deal with deformed parts and promoted bodies; I'll post it if I can find it.

When dealing with assemblies, I've found that it is generally easier to get the occurrence bodies at the assembly level and use them directly; there is usually no need to start with the prototype bodies.

http://nxjournaling.com/content/select-all-bodies-current-displayed-asse...

What operations are you looking to do on the bodies?

Here is the NXJ_AssemblyContainer code in its current state. It looks like the last time I worked on it was back in 2015. I've been debating whether or not to post this code because 1)it isn't in a state that I consider finished or fully working 2)it isn't very good code 3)I strongly suspect that there is a better way to do all of what it does.

The code takes a very "bottom-up" approach. It looks for components, then gets the prototype bodies from the used reference sets and tries to drive up the chain to the top level assembly. Were I to rewrite this code today, I'd take the opposite approach: I'd gather the occurrence bodies from the top level assembly and work my way down to the components. I think this approach would simplify the code in several ways.

Anyway, here is the code. I hope that it is useful for someone or inspires them to fix it/build on it. Use it at your own risk, I don't guarantee it to work.

'NXJournaling.com
'July 29, 2015

'Helper class to aid in the processing of assemblies.
'This class will report the depth of a component in the assembly,
'find the occurrence body(ies) of the component [including deformed components],
'and allow easy access to the top level children of a given component.

'Usage:
' Pass in a part or component to the New constructor, the class code will:
' - query the part for child components, top-level components will be listed in
' the .AsmComponents property (List(Of NXJ_AssemblyContainer) objects).
' The code will recursively traverse the asssembly tree. Each object in .AsmComponents
' will have its own list of components, allowing you to easily process the entire assembly
' by using a recursive Sub or Function.
' - query the component for the bodies used in the current reference set and find the
' corresponding occurrence bodies in the top level assembly. These occurrence bodies
' can be found in the .OccurrenceBodies property (List(Of Body)).
' - query the component for the "depth" in the assembly. The top-level assembly is depth: 0,
' top level (child) components are depth: 1, grandchildren are depth: 2, etc.

' The .OccurrenceBodies will correctly report the body of a deformed component.

Imports System.Collections.Generic
Imports NXOpen
Imports NXOpen.UF
Imports NXOpen.Assemblies

Public Class NXJ_AssemblyContainer

#Region "Private variables"
Private _theSession As Session = Session.GetSession
Private _theUfSession As UFSession = UFSession.GetUFSession
Private _lw As ListingWindow = _theSession.ListingWindow
Private _logFile As LogFile = _theSession.LogFile
Private _protoPart As Part
Private _topLevelComp As Assemblies.Component = Nothing
#End Region

#Region "Properties"
Private _thePart As Part = Nothing
Public ReadOnly Property Part() As Part
Get
Return _thePart
End Get
End Property

Private _theComponent As Component = Nothing
Public ReadOnly Property Component() As Component
Get
Return _theComponent
End Get
End Property

Private _components As New List(Of NXJ_AssemblyContainer)
Public ReadOnly Property AsmComponents() As List(Of NXJ_AssemblyContainer)
Get
Return _components
End Get
End Property

Private _parent As Component = Nothing
Public ReadOnly Property Parent() As Component
Get
Return _parent
End Get
End Property

Private _instanceTag As Tag
Public ReadOnly Property InstanceTag() As Tag
Get
Return _instanceTag
End Get
End Property

Private _occurrenceBodies As New List(Of Body)
Public ReadOnly Property OccurrenceBodies() As List(Of Body)
Get
Return _occurrenceBodies
End Get
End Property

Private _depth As Integer = 0
Public ReadOnly Property Depth() As Integer
Get
Return _depth
End Get
End Property

Private _promotedFeatures As New List(Of Features.Promotion)
Public ReadOnly Property PromotionFeatures() As List(Of Features.Promotion)
Get
Return _promotedFeatures
End Get
End Property

Private _parentContainer As NXJ_AssemblyContainer = Nothing
Public ReadOnly Property ParentContainer() As NXJ_AssemblyContainer
Get
Return _parentContainer
End Get
End Property

Private _promotedBodies As New List(Of PromotedBody)
Public ReadOnly Property PromotedBodies() As List(Of PromotedBody)
Get
Return _promotedBodies
End Get
End Property

#End Region

#Region "Public constructor"

Public Sub New(ByVal someComponent As Component)

Me.New(someComponent, Nothing)

End Sub

Public Sub New(ByVal somePart As Part)

Me.New(somePart.ComponentAssembly.RootComponent, Nothing)

End Sub

Public Sub New(ByVal someComponent As Component, ByVal parentContainer As NXJ_AssemblyContainer)

_parentContainer = parentContainer

_thePart = someComponent.Prototype.OwningPart
_theComponent = someComponent
'_parent is Nothing for the top-level assembly
_parent = someComponent.Parent

_logFile.WriteLine("")
_logFile.WriteLine(" ~~ NXJ ~~")
_logFile.WriteLine("New NXJ_AssemblyContainer")
_logFile.WriteLine(" component part: " & _theComponent.Prototype.OwningPart.FullPath)
_logFile.WriteLine(" part: " & _thePart.FullPath)
If IsNothing(parentContainer) Then
_logFile.WriteLine(" parent container: none")
Else
_logFile.WriteLine(" parent container: " & parentContainer.Part.FullPath)
End If

_lw.WriteLine("New NXJ_AssemblyContainer")
_lw.WriteLine(" component part: " & _theComponent.Prototype.OwningPart.FullPath)
_lw.WriteLine(" part: " & _thePart.FullPath)
If IsNothing(parentContainer) Then
_lw.WriteLine(" parent container: none")
Else
_lw.WriteLine(" parent container: " & parentContainer.Part.FullPath)
End If

Dim currComp As Assemblies.Component = _theComponent
Dim parentComp As Assemblies.Component = _parent

'calculate depth and find the top level assembly
Do Until IsNothing(parentComp)
_depth += 1
currComp = parentComp
parentComp = currComp.Parent
_topLevelComp = currComp
Loop

If IsNothing(_thePart) Then
'Component is not loaded, probably could not be found
'with the current search options.

'To do: report this condition,
'attempt to load file,
'and/or throw error as necessary.
Exit Sub
End If

If Not _thePart.IsFullyLoaded Then
'component is partially loaded.
Dim pls As PartLoadStatus
Try
pls = _thePart.LoadThisPartFully

Catch ex As NXException
'_lw.WriteLine("NX exception: " & ex.Message)
_logFile.WriteLine("NX exception: " & ex.Message)
Exit Sub
Catch ex As Exception
'_lw.WriteLine("Exception: " & ex.Message)
_logFile.WriteLine("Exception: " & ex.Message)
Exit Sub
End Try

End If

'The instance tag is not currently put to good use in this class.
'Remove it?
_instanceTag = _theUfSession.Assem.AskInstOfPartOcc(_theComponent.Tag)

'Check to see if the part is deformable.
'Remember, just because it is deformable does not necessarily mean that
'there will be a deform feature in the parent assembly.
'When adding a deformable part to an assembly, you can hit "Cancel", which
'will leave you with a normal (non-deformed) component in the assembly
'and no deformed feature in the assembly part navigator.
Dim isDeformable As Boolean = False
isDeformable = _theUfSession.Assem.IsPartDeformable(_thePart.Tag)

If isDeformable Then
Me.GetDeformBodies()
Else
'Part is not deformable, don't bother checking for deformed bodies.
Me.GetCompBodies()
End If

Me.GetPromotionFeatures()

Me.GetFirstLevelComponents()

End Sub

#End Region

#Region "Private Methods"

Private Sub GetFirstLevelComponents()
'Get the first level components of this component.
'Each component will be added to the _components list as a new NXJ_AssmeblyContainer.
'When a new NXJ_AssemblyContainer is created, this process will run on it (this method
'is called from the 'New' method), returning all of its first level components...
'Rinse & repeat for each component.
'In this way the class code will recursively traverse the entire assembly.
For Each child As Component In _theComponent.GetChildren()
_components.Add(New NXJ_AssemblyContainer(child, Me))
Next
End Sub

Private Sub GetCompBodies()

_lw.WriteLine("GetCompBodies")

'Get the name of the reference set in use.
Dim refSetName As String = _theComponent.ReferenceSet
_lw.WriteLine(" refSetName = " & refSetName)

'if this is the empty ref set, there are no bodies to get.
If refSetName.ToLower = "empty" Then
_lw.WriteLine(" body count: 0")
_lw.WriteLine("")

Return
End If

'if this is the entire part ref set, get all the bodies in the part.
If refSetName.ToLower = "entire part" Then
For Each tempBody As Body In _thePart.Bodies
If tempBody.IsSolidBody Then
'We found a solid body, find the corresponding occurrence body
'in the assembly and add it to the _occurrenceBodies list.
Dim occurrBody As Body = _theComponent.FindOccurrence(tempBody)
If IsNothing(occurrBody) Then
'look for promotion
Me.GetPromotedBodies()

Else
_occurrenceBodies.Add(occurrBody)
End If
End If
Next
_lw.WriteLine(" body count: " & _occurrenceBodies.Count.ToString)
_lw.WriteLine("")

Return
End If

'Get a reference to the used ref set.
For Each theRefSet As ReferenceSet In _thePart.GetAllReferenceSets

If theRefSet.Name = refSetName Then
'Find the objects in the reference set.
Dim refObjs() As NXObject = theRefSet.AskAllDirectMembers
For Each temp As NXObject In refObjs
If TypeOf (temp) Is Body Then
Dim theBody As Body = temp
If theBody.IsSolidBody Then
'We found a solid body, find the corresponding occurrence body
'in the assembly and add it to the _occurrenceBodies list.
Dim occurrBody As Body = _theComponent.FindOccurrence(theBody)
If IsNothing(occurrBody) Then
'look for promotion
'search through the container's promoted bodies collection to see if a BaseBodyTag matches the prototype body tag
Me.GetPromotedBodies()

Else
_occurrenceBodies.Add(occurrBody)
End If
End If
End If
Next
End If
Next

_lw.WriteLine(" body count: " & _occurrenceBodies.Count.ToString)
_lw.WriteLine("")

End Sub

Private Sub GetPromotedBodies()

_lw.WriteLine("GetPromotedBodies()")

If IsNothing(Me.ParentContainer) Then
Return
End If

_lw.WriteLine("parent container has " & Me.ParentContainer.PromotedBodies.Count.ToString & " promoted bodies")
_lw.WriteLine("this component tag: " & Me.Component.Tag.ToString)

'look for any promoted bodies that relate to this component
For Each tempBody As PromotedBody In Me.ParentContainer.PromotedBodies
_lw.WriteLine(" promoted body component tag: " & tempBody.PromotedFromComponent.Tag.ToString)
_lw.WriteLine(" promoted body component: " & tempBody.PromotedFromComponent.DisplayName)
_lw.WriteLine(" promoted base body tag: " & tempBody.BaseBodyTag.ToString)
If tempBody.PromotedFromComponent.Equals(Me.Component) Then
_lw.WriteLine(" promoted body comes from this component")
If Not _occurrenceBodies.Contains(tempBody.PromotedBody) Then
_occurrenceBodies.Add(tempBody.PromotedBody)
End If
End If
Next

End Sub

Private Sub GetDeformBodies()

'The part is deformable, but it may or may not be deformed in its parent assembly.

_theUfSession.Disp.SetDisplay(UFConstants.UF_DISP_SUPPRESS_DISPLAY)

Dim currentDisplayPart As Part = _theSession.Parts.Display
Dim partLoadStatus1 As PartLoadStatus = Nothing

Dim theDeformedFeatureTag As Tag = Tag.Null

Dim mappedComp As Assemblies.Component = Nothing
'if a component more than 1 level deep (deeper than a top-level component of the main assembly)
'has a deformable body, we must map the component to its parent to get the deformed feature information
If Me.Depth > 1 Then
'Map the component to its parent. The reference we have (_theComponent) is the instance in the
'top level assembly; we need to get the corresponding component instance in its immediate parent assembly.
mappedComp = _parent.Prototype.OwningPart.ComponentAssembly.MapComponentFromParent(_theComponent)
'For .AskDisplayedDeformationOfPartOcc to work, the file containing the deformed part feature must be the display part.
'The file that contains the deformed part feature is the immediate parent assembly of the file where the
'deformed body is defined. If a deformable body is defined in B.prt, when B.prt is added to A.prt as a component,
'you will be prompted to enter the values for the deformation and a deformed body feature (.FeatureType = "FLEXED_PART")
'will be created in A.prt. In the part navigator (native NX), the deformed body feature will
'have the same name as the deformed body part. In our simple example it would probably show up as:
'B(n)"B", where 'n' is the feature number. Both the feature .Name property and the feature .GetDisplayName method will return
'the file name that contains the deformed body definition.
_theSession.Parts.SetDisplay(_parent.Prototype.OwningPart, False, False, partLoadStatus1)
_theUfSession.Assem.AskDisplayedDeformationOfPartOcc(mappedComp.Tag, theDeformedFeatureTag)

Else
'We are in the top level assembly, and can ask for the deformed feature tag straight away.
_theUfSession.Assem.AskDisplayedDeformationOfPartOcc(_theComponent.Tag, theDeformedFeatureTag)
End If

Dim theDeformedData As UFAssem.DeformedDefinitionData = Nothing
_theUfSession.Assem.AskDeformedDefinitionData(theDeformedFeatureTag, theDeformedData)

If theDeformedFeatureTag = Tag.Null Then
'no deformed feature to process, get the bodies and get out
Me.GetCompBodies()
'reset the display part
_theSession.Parts.SetDisplay(currentDisplayPart, False, False, partLoadStatus1)
'Unsuppress display updates and regenerate the view.
_theUfSession.Disp.SetDisplay(UFConstants.UF_DISP_UNSUPPRESS_DISPLAY)
_theUfSession.Disp.RegenerateDisplay()
'we are done here, skip the rest of the code
Return
End If

'We have a deformed body to deal with. We need to find the deformed body instance
'in the assembly that matches up with the body in our component.

'uf assem cycle objects in comp
'gather all the object tags in the component into a list
Dim theEnts As New List(Of Tag)

Dim aTag As Tag = Tag.Null
Do
_theUfSession.Assem.CycleObjsInComp(_theComponent.Tag, aTag)
If aTag = Tag.Null Then
Exit Do
End If

'Cycle through all the solid bodies in the component (_theComponent),
'add all the tags of solid bodies to a list.
Dim theType As Integer, theSubtype As Integer
_theUfSession.Obj.AskTypeAndSubtype(aTag, theType, theSubtype)
If theSubtype = UFConstants.UF_solid_body_subtype Then
theEnts.Add(aTag)
End If

Loop While True

'Get the tags of the solid bodies belonging to the parent assembly.
Dim parentBodies As New List(Of Tag)
parentBodies = GetParentBodies()

'If a parent's solid body tag matches a tag of an object in the component,
'add that body as an occurrence body.
For Each temp As Tag In parentBodies
If theEnts.Contains(temp) Then
Dim deformedBody As Body
deformedBody = Utilities.NXObjectManager.Get(temp)
_occurrenceBodies.Add(deformedBody)
End If
Next

'reset the display part
_theSession.Parts.SetDisplay(currentDisplayPart, False, False, partLoadStatus1)

'Unsuppress display updates and regenerate the view.
_theUfSession.Disp.SetDisplay(UFConstants.UF_DISP_UNSUPPRESS_DISPLAY)
_theUfSession.Disp.RegenerateDisplay()

End Sub

Private Function GetParentBodies() As List(Of Tag)

Dim theBodies As New List(Of Tag)

'Find the top-level assembly part.
Dim topLevel As Part = Nothing
Dim parentComp As Assemblies.Component = _parent
Dim currComp As Assemblies.Component = _theComponent
Do
currComp = parentComp
parentComp = currComp.Parent
If IsNothing(parentComp) Then
topLevel = currComp.Prototype.OwningPart
Exit Do
End If
Loop

'Cycle through the solid bodies in the top-level assembly part,
'add all the body tags to a list.
Dim aBodyTag As Tag = Tag.Null
Do
_theUfSession.Obj.CycleObjsInPart(topLevel.Tag, UFConstants.UF_solid_type, aBodyTag)
If aBodyTag = Tag.Null Then
Exit Do
End If

Dim theType As Integer, theSubtype As Integer
_theUfSession.Obj.AskTypeAndSubtype(aBodyTag, theType, theSubtype)
If theSubtype = UFConstants.UF_solid_body_subtype Then
Dim newBody As Body = Utilities.NXObjectManager.Get(aBodyTag)
If newBody.Prototype.OwningPart.Equals(_parent.Prototype.OwningPart) Then
theBodies.Add(aBodyTag)
End If

End If
Loop While True

Return theBodies

End Function

Private Sub GetPromotionFeatures()

For Each temp As Features.Feature In _thePart.Features
If temp.FeatureType <> "PROMOTION" Then
'skip this feature, move on to the next one
Continue For
End If
'this is a promotion feature
_promotedFeatures.Add(temp)
_promotedBodies.Add(New PromotedBody(temp))
Next

End Sub

Private Function GetPromotedBody(ByVal compSourceBody As Body) As Body

_lw.WriteLine("GetPromotedBody")
_lw.WriteLine(" component: " & Me.Component.Prototype.OwningPart.FullPath)
If IsNothing(Me.ParentContainer) Then
_lw.WriteLine(" parent container: none")
Else
_lw.WriteLine(" parent container: " & Me.ParentContainer.Component.Prototype.OwningPart.FullPath)
End If

If IsNothing(Me.ParentContainer) Then
'no parent to check
_lw.WriteLine(" -- no parent, return nothing")
_lw.WriteLine("")
Return Nothing
End If

If Me.ParentContainer.PromotionFeatures.Count = 0 Then
'parent has no promoted bodies
_lw.WriteLine(" -- parent has no promoted bodies")
_lw.WriteLine("")
Return Nothing
End If

For Each tempPromotion As Features.Promotion In Me.ParentContainer.PromotionFeatures

Dim promotedBody As Body = tempPromotion.GetBodies(0)

Dim instancePath() As Tag = Nothing
Dim numInstances As Integer
_theUfSession.Modl.AskPromotionPath(promotedBody.Tag, True, instancePath, numInstances)

_lw.WriteLine(" number of instances: " & numInstances.ToString)
If numInstances > 0 Then
For Each temp As Tag In instancePath
_lw.WriteLine(" " & temp.ToString)

Next
_lw.WriteLine("")

End If

Dim promotionBuilder As Features.PromotionBuilder = Me.ParentContainer.Part.Features.CreatePromotionBuilder(tempPromotion)
Dim sourceBody As Body = promotionBuilder.Body.GetArray(0)
promotionBuilder.Destroy()

If Me.Component.Tag = sourceBody.OwningComponent.Tag Then
Return promotedBody
End If

Next

Return Nothing

End Function

#End Region

End Class

Public Class PromotedBody

#Region "Private variables"
Private _theSession As Session = Session.GetSession
Private _theUfSession As UFSession = UFSession.GetUFSession
Private _logFile As LogFile = _theSession.LogFile
Private _owningPart As Part
#End Region

Private _promotionFeature As Features.Promotion
Public ReadOnly Property PromotionFeature() As Features.Promotion
Get
Return _promotionFeature
End Get
End Property

Private _promotedBody As Body
Public ReadOnly Property PromotedBody() As Body
Get
Return _promotedBody
End Get
End Property

Private _promotedFromComponent As Component
Public ReadOnly Property PromotedFromComponent() As Component
Get
Return _promotedFromComponent
End Get
End Property

Private _baseBodyTag As Tag
Public ReadOnly Property BaseBodyTag() As Tag
Get
Return _baseBodyTag
End Get
End Property

Private _isNestedPromotion As Boolean = False
Public ReadOnly Property IsNestedPromotion() As Boolean
Get
Return _isNestedPromotion
End Get
End Property

Public Sub New(ByVal thePromotedFeature As Features.Promotion)

_promotionFeature = thePromotedFeature
_owningPart = _promotionFeature.OwningPart
_logFile.WriteLine("_owningPart: " & _owningPart.FullPath)
Me.GetBody()

End Sub

Private Sub GetBody()

Dim promBodies() As Body = _promotionFeature.GetBodies
_promotedBody = promBodies(0)
'.GetBodies will contain a single body
'if multiple bodies are selected in the promote body dialog, a separate promote body feature
' will be created for each

_logFile.WriteLine(" promotion feature body: " & promBodies.Length.ToString)
'the body that has been promoted up into the assembly (owned by the assembly part)
_logFile.WriteLine(" body tag: " & promBodies(0).Tag.ToString)
_logFile.WriteLine(" body IsOccurrence: " & promBodies(0).IsOccurrence.ToString)

'Check for nested promotions (promotions of promotions)
'AskPromotionPath
Dim fullPath As Boolean = True
Dim instancePathTags() As Tag = Nothing
Dim numInstances As Integer

_theUfSession.Modl.AskPromotionPath(_promotedBody.Tag, fullPath, instancePathTags, numInstances)
_logFile.WriteLine(" number of instances (levels of promotions): " & numInstances.ToString)
For Each pathTag As Tag In instancePathTags
_logFile.WriteLine(" instance path tag: " & pathTag.ToString)
Next

If numInstances > 1 Then
_isNestedPromotion = True
End If

'_baseBodyTag = _promotedBody.Tag
'For i As Integer = 0 To numInstances - 1
' 'This will return the tag of the body that was promoted.
' Dim baseTag As Tag = Tag.Null
' _theUfSession.Modl.PromMapObjectDown(_baseBodyTag, baseTag)
' _logFile.WriteLine(" base body tag: " & baseTag.ToString)

' Dim baseBody As Body = Utilities.NXObjectManager.Get(baseTag)
' _logFile.WriteLine("baseBody.Tag: " & baseBody.Tag)
' _logFile.WriteLine("baseBody.GetType: " & baseBody.GetType.ToString)
' '_logFile.WriteLine(" base body owning component: " & baseBody.Prototype.OwningComponent.DisplayName)

' Dim baseBodyIsPromotion As Boolean = False
' baseBodyIsPromotion = _theUfSession.Obj.IsObjectAPromotion(baseTag)
' _logFile.WriteLine("baseBody is a promotion: " & baseBodyIsPromotion.ToString)

' _baseBodyTag = baseTag
'Next

_baseBodyTag = _promotedBody.Tag
Do Until Not _theUfSession.Obj.IsObjectAPromotion(_baseBodyTag)
Dim baseTag As Tag = Tag.Null
_theUfSession.Modl.PromMapObjectDown(_baseBodyTag, baseTag)

_logFile.WriteLine(" base body tag: " & baseTag.ToString)
Dim baseBody As Body = Utilities.NXObjectManager.Get(baseTag)
'_logFile.WriteLine("baseBody.Tag: " & baseBody.Tag)
'_logFile.WriteLine("baseBody.GetType: " & baseBody.GetType.ToString)
_logFile.WriteLine("baseBody.OwningPart: " & baseBody.OwningPart.FullPath)

_baseBodyTag = baseTag

Loop

'if nested, there will be no promotionBuilder.Body to get (it will be consumed)

'when creating assembly containers, change display part to each new part
'to ensure promoted bodies will be available?

'----------------------------------
Dim promotionBuilder As Features.PromotionBuilder
'promotionBuilder = _owningPart.Features.CreatePromotionBuilder(_promotionFeature)
promotionBuilder = _owningPart.Features.CreatePromotionBuilder(_promotionFeature)

Dim theBodies() As Body = promotionBuilder.Body.GetArray
'the body that is being promoted (owned by the component)
_logFile.WriteLine(" body IsOccurrence: " & theBodies(0).IsOccurrence.ToString)
If theBodies(0).IsOccurrence Then
_promotedFromComponent = theBodies(0).OwningComponent

_logFile.WriteLine(" occurrence body tag: " & theBodies(0).Tag.ToString)
Dim protoBod As Body = theBodies(0).Prototype
_logFile.WriteLine(" prototype body tag: " & protoBod.Tag.ToString)
_logFile.WriteLine(" owning component: " & theBodies(0).OwningComponent.DisplayName)
_logFile.WriteLine(" owning component tag: " & theBodies(0).OwningComponent.Tag.ToString)
_logFile.WriteLine(" parent part: " & theBodies(0).OwningComponent.Prototype.OwningPart.FullPath)
_logFile.WriteLine(" parent part tag: " & theBodies(0).OwningComponent.Prototype.OwningPart.Tag.ToString)
_logFile.WriteLine(" owning component ref set: " & theBodies(0).OwningComponent.ReferenceSet)

Else
_logFile.WriteLine(" prototype body tag: " & theBodies(0).Tag.ToString)

End If

End Sub

End Class

Hello, thank you for the code. That must of took a long time to write! Thanks for sharing it. With some work I've been able to make it work for me with deformed parts and such.

I had a question about Occurrences though. From what I have read in the documentation an occurrence is defined as such:

- An occurrence of a component is a pointer to geometry in the component file. You can use component occurrences to create one or more references to a component without creating additional geometry. Because geometry is not copied with an occurrence, when you change the component, all occurrences of that component are updated.

I have some particular models in my organization where .FindOcurrence() always leads to the wrong volume. If I use the function below where I instead collect all solid bodies (Instances?) I am able to get the correct volume.

I'm wondering if in the case of these assemblies there is an issue with the Occurrences, or pointers. Perhaps they are pointing to the wrong geometry? Is there any way to confirm this theory and perhaps debug it?

Thanks again.

Function AskAllBodies(ByVal thePart As Part) As List(Of Body)

Dim theBodies As New List(Of Body)

Dim aBodyTag As Tag = Tag.Null
Do
theUfSession.Obj.CycleObjsInPart(thePart.Tag, _
UFConstants.UF_solid_type, aBodyTag)
If aBodyTag = Tag.Null Then
Exit Do
End If

Dim theType As Integer, theSubtype As Integer
theUfSession.Obj.AskTypeAndSubtype(aBodyTag, theType, theSubtype)
If theSubtype = UFConstants.UF_solid_body_subtype Then
theBodies.Add(Utilities.NXObjectManager.Get(aBodyTag))

End If
Loop While True

Return theBodies

End Function

When it comes to getting information about the assembly, such as the mass properties, I recommend a top down approach. The "AskAllBodies" function above gives you all the bodies that are actually used in the assembly. Trying to drive from the bottom up (as my long code post does) is fraught with difficulty if and when wave links, promoted bodies, and deformed parts are involved.

If the top down method works for you, why not use it?

I guess you're right. It is much simpler and a little faster too. The only issue there would be is "AskAllBodies" returns the mass properties per body, instead of per component. For the most part this is easy to work with, as you only need to know which component the bodies belong too.

The only thing that trips me up is the CoGs. If one needed the Centers of Gravity per component, is there a way to convert Component Solid Body(s)to a single CoG that represents the component?

I'm wondering if this can be done mathematically, or do you need to query the CoG per component?

Thanks again.

If you know the mass and CoG of each individual body, finding the CoG of the system is easy. Take the mass of each individual body multiplied by the X coordinate of its CoG, sum up those values, and divide by the total mass of all the bodies. This will give you the X coordinate of the system CoG. Repeat the process for the Y and Z coordinates.

See "center of mass for particles" on this page:
http://hyperphysics.phy-astr.gsu.edu/hbase/cm.html