Hello,
I was wondering if anyone could help with a more in-depth description / documentation on bodies. Currently I'm getting interesting results when selecting bodies from visible Objects compared to the current session's partCollection object.
When selecting bodies using the current Sessions partCollection object:
For Each part As Part In NxSession.Parts
'ejComp is a custom object
If String.Equals(part.Leaf, ejComp.DisplayName) Then
For Each dispObj As DisplayableObject In part.Bodies
Dim bodyObj As Object = CType(dispObj, Object)
Lw.WriteLine("For body: " & bodyObj.JournalIdentifier)
body.highlight()
'Do other processing
Next
End If
Next
I get different bodies than when I select these bodies by making them the only displayed objects and running:
Dim visibleObjects() As DisplayableObject
visibleObjects = _workPart.Views.WorkView.AskVisibleObjects()
For Each displayableObject As DisplayableObject In visibleObjects
If TypeOf displayableObject Is Body Then
Dim body As Body = displayableObject
Lw.WriteLine("Body: " & body.JournalIdentifier)
body.highlight()
'Do other processing
End If
Next
The JournalIdentifers do not match, however both will cause the seemingly same bodies to highlight.
What causes these two forms of selections to return different bodies?
Different bodies?
It's not clear that the lists of bodies are actually different. Journal identifiers don't mean much, and, as you say, the same set of bodies seems to be getting highlighted. Try printout using body.ToString instead. This will give the body's tag, which is a much more reliable identifier than its journal identifier.
Re: Different bodies?
Here is some output I put together using the bodies.toString() method instead of the journal identifier. This first bit is selecting by component name in the Session's part collection:
*********************
NOW SELECTING WITH VISIBLE OBJECTS
*********************
So the body tags / toStrings are not the same yet they are still highlighting the same parts. I also added abody.OwningComponent.DisplayName to show that the code is looking at the same components.
NX 8.5
NX 9.0
re: different bodies
For each body you encounter, in your program output, please add:
writeline("body is occurrence: " & theBody.IsOccurrence.ToString)
I've not run the experiment myself, but I'm guessing that in one case you are getting the underlying body and in the other case you are getting the assembly occurrence of the body.
re: Body occurences
For Each part As Part In NxSession.Parts
'ejComp is a custom object
If String.Equals(part.Leaf, ejComp.DisplayName) Then
Lw.WriteLine("For Component: " & part.Leaf)
For Each dispObj As DisplayableObject In part.Bodies
Dim bodyObj As Object = CType(dispObj, Object)
Lw.WriteLine(" For body: " & bodyObj.Tag)
Lw.WriteLine(" Body is an occurence: " & bodyObj.IsOccurrence.ToString & vbCrLf)
'Do other processing
Next
End If
Next
Produces the output:
Now with visible objects:
Dim visibleObjects() As DisplayableObject
visibleObjects = _workPart.Views.WorkView.AskVisibleObjects()
For Each displayableObject As DisplayableObject In visibleObjects
If TypeOf displayableObject Is Body Then
Dim body As Body = displayableObject
Lw.WriteLine("For component: " & body.Prototype.OwningPart.Leaf)
Lw.WriteLine(" For Body: " & body.Tag)
Lw.WriteLine(" body is an occurence: " & body.IsOccurrence.ToString)
Lw.WriteLine("")
'Do other processing
End If
Next
Produces the output:
NX 8.5
NX 9.0
re: occurrences
In the first code snippet, the term "component" is a bit misleading; you are actually processing the solid bodies in the part files in session.
In the second code snippet, the term "component" is accurate; you are processing the bodies in the displayed assembly file. Each body shown in an assembly is an occurrence of the body in the owning part file.
The solid bodies in the part
The solid bodies in the part files vs the bodies in the displayed assembly file.
I am new to NX, I understand the displayed assembly file is the component in the assembly navigator that is displayed in your NX session. However I don't have any clue how it differs from the part files in session. And I don't know where to turn for answers, can you help me out with some documentation or explanation?
Thank you
NX 8.5
NX 9.0
re: documentation
The NX help files give a quick overview at:
CAD -> Assemblies -> intro to NX assemblies
Take note of the "component objects", "component part files", and "component occurrences" pages in that section.
In short, the component acts like an invisible box that holds references to geometry in the part file. The component itself doesn't own or control the geometry; when the part geometry is modified, every occurrence is updated because they point back to the original geometry in the part file. So if you have an assembly model of a toy car, there may be 4 wheels in the assembly, but the geometry is controlled by a single wheel part file. The assembly needs to keep track of each of the 4 wheels so each occurrence body gets its own identifier which is different from the identifier of the solid body in the part file.
I hope this helps to illuminate rather than obscure the issue...
filter for holes without blend faces
hi,
I have done a little coding, but won't have blends only closed cylinders / holes, in my collection:
For Each displayableObject As DisplayableObject In visibleObjects
If TypeOf displayableObject Is Body Then
Dim body As Body = displayableObject
If ufs.Assem.IsOccurrence(body.Tag) = False Then
For Each face1 As Face In body.GetFaces()
If face1.SolidFaceType = Face.FaceType.Cylindrical Then
ReDim Preserve localFaces(counter)
counter += 1
Face1.Highlight()
End if
Next
End If
End If
Next
what is to add to get rid of blends in this selection?
thanks in advance
re: filter holes vs. blend faces
If you are dealing with a parameterized model, you can query the face to see if it belongs to a hole feature or a blend feature.
I'll assume you are working with a non-parameterized file; the situation here is more interesting. I don't have any code that proves this will work, but here is what I would try:
Use the function UF_MODL_ask_edge_faces to get references to the other faces that share the circular edges of the cylindrical face. Pick a point near the edge on the cylindrical face and query the face normal at that point (using UF_MODL_ask_face_props or similar). Pick a point on the adjoining face near the first point and again query the face normal at that point. If the angle between the normal vectors is small, the cylindrical face is likely a blend. If the angle between the vectors is large, the cylindrical face is likely a hole or boss. If the normal vector points away from the centerline of the cylindrical face it is a boss, otherwise it is a hole.
Yes thank you! If I
Yes thank you! If I understand you correctly, components / parts are really just an object oriented way to set up designs. The part acts as the class that holds methods (part info), and the assemblies are just references to the objects (parts). Which completely explains the interesting results I was originally getting. And the isOccurence check lets you know if the current object is a reference to the part file.
Thank you for your help, I think I'm starting to understand this better.
NX 8.5
NX 9.0
Data for component's geometry
I am trying to get data from specific component's geometry. This is proving to be a difficult task. I need to get the center of an arc with respect to the absolute coordinate system. Currently I have been using the UFSession.Eval class for this. The problem is, the component class does not have a "getBodies" call, and cannot be converted into a body through casting. Is there another way to get component specific data? (faces, bodies, edges, arcs, curves). The part files won't work for this because there is no relation between the part's and assemblies positional data.
NX 8.5
NX 9.0
Update: I ended up using the
Update: I ended up using the visibleObjects() call, therefore I had DisplayableObjects and could process everything from there. Thanks for the help.
NX 8.5
NX 9.0
Component Bodies vs Part File Bodies
I have a question regarding component bodies / part file bodies and thought this thread was a good place to ask, I'll do my best to explain my situation, please let me know if I'm using bad terminology, thanks.
I have a reference to a component in my assembly, I am unblanking the component so I can askVisibleObjects to obtain the component bodies. However, unblanking the component does not unblank the component bodies, so, in some cases I could have an unblanked component with a blanked component solid body, and the askVisibleObjects code will not return the body.
Due to this scenario I'm looking for an alternative method to find a reference to all component bodies so I can unblank them using a unblank() call. Since askVisibleObjects is off the table and the component class doesn't have a reference to component bodies I'm kind of stuck.
An alternative route I have started to explore is using the component's prototype object to obtain the part file from which the component was created from and look at those solid bodies. However, and this is my question, will unblanking the solid bodies from a part class inherently unblank the component solid bodies?
NX 8.5
NX 9.0
re: unblanking bodies from part file
"will unblanking the solid bodies from a part class inherently unblank the component solid bodies?"
Short answer: No, you will need to unblank the occurrence body(ies) in the assembly file.
Longer answer: One way to get the occurrence body is to query what reference set the component uses in the assembly, get a reference to the component prototype (the part file) and query the bodies used in the given reference set, and finally, use the {component}.FindOccurrence({prototype body}) method on the prototype bodies to get the corresponding occurrence bodies.
p.s. The above strategy won't work on deformed components or promoted bodies.
Occurrence body
Thank you for your response, I'll have to test this method out.
In the meantime I've concluded that for the time being the component prototype bodies will suffice for my program requirements, and have found something very interesting. It will be best to describe with some code:
Dim part as Part = component.prototype ' ensure prototype is a part class
Dim bodyCollection as Body() = part.bodes.toarray() ' get an array of all the bodies from the component's prototype
lw.writeLine(bodyCollection.length)
So this code works to get the body I want, however, I've noticed if the component's reference set is set to empty reference set regardless that I'm collecting the bodies from the component's prototype, the length of the body collection array comes out to 0. Changing the reference set to anything provides a length greater than 0.
Can you help me understand why?
NX 8.5
NX 9.0
re: component body count
I'm not seeing the same results that you describe. I'm running NX 9.0.3.4 and the code below returns the same number of bodies whether the used reference set is "empty" or something else.
Option Strict Off
Imports System
Imports NXOpen
Module Module1
Sub Main()
Dim theSession As Session = Session.GetSession()
If IsNothing(theSession.Parts.BaseWork) Then
'active part required
Return
End If
Dim workPart As Part = theSession.Parts.Work
Dim lw As ListingWindow = theSession.ListingWindow
lw.Open()
Const undoMarkName As String = "report component body count"
Dim markId1 As Session.UndoMarkId
markId1 = theSession.SetUndoMark(Session.MarkVisibility.Visible, undoMarkName)
'report first level components
For Each child As Assemblies.Component In workPart.ComponentAssembly.RootComponent.GetChildren()
lw.WriteLine(child.DisplayName)
lw.WriteLine("reference set: " & child.ReferenceSet)
Dim childPart As Part = child.Prototype
lw.WriteLine("number of bodies: " & childPart.Bodies.ToArray.Length.ToString)
lw.WriteLine("")
Next
lw.Close()
End Sub
Public Function GetUnloadOption(ByVal dummy As String) As Integer
'Unloads the image immediately after execution within NX
GetUnloadOption = NXOpen.Session.LibraryUnloadOption.Immediately
End Function
End Module
Partial loading?
I've noticed the issue I had described earlier ONLY applies if the component was loaded in as "Empty". For example, I open a new part, that part defaults to last reference set saved which was "Empty", the code returns 0 bodies, then I can change the reference set to "Entire Part", then directly change the reference set back to "Empty" and run the code again and it returns 1+ bodies.
Based on this, I'm speculating some partial loading setting is causing the original part file bodies to not be accessible until you change the ref. set?
NX 8.5
NX 9.0
re: partial loading
The parts that I tested on were fully loaded; I think that you are correct that the difference we are seeing has to do with partial loading. The partial loading option will only load the geometry necessary from the part. If the component loads with the "empty" reference set in use, there is no reason to load any geometry until the reference set is changed. If desired, you could use the part's .LoadFully (or .LoadThisPartFully) method to fully load the part before querying the body collection.
Parts.loadFully
Thank you, loading the part fully seems to have fixed the issue and is a more elegant solution than programmatically changing the reference sets.
Appreciate the help, cheers.
NX 8.5
NX 9.0