Showing results for 
Search instead for 
Do you mean 
Reply

How to get the unique tag of each part in an assembly.

How do I get the unique Tag of each part in an assembly? I am using the following code to process an assembly and query the tag of each part. However, not all of the parts have a unique tag number. Some of the parts (occurence data) share the same tag.

 

How can I get the unique tag of each part, and not the occurence?

 

  Public Sub ProcessNXData()
        Dim displayPart As Part = theSession.Parts.Display
        Dim workPart As Part = theSession.Parts.Work

        Dim markId1 As NXOpen.Session.UndoMarkId = theSession.SetUndoMark( _
            NXOpen.Session.MarkVisibility.Visible, "Reorder Components")

        Dim theOrders As Assemblies.ComponentOrder() = Nothing
        displayPart.ComponentAssembly.GetComponentOrders(theOrders)

        Echo(displayPart.Leaf & " has " & theOrders.Length & " ComponentOrder objects")

        'following line is used to print name to excel
        Dim c As ComponentAssembly = workPart.ComponentAssembly
        Cells(2, 2).Value = c.RootComponent.GetStringAttribute("DB_PART_NAME")

        'following line is used to print # to excel
        Dim rootDispName As String = (c.RootComponent.DisplayName)
        Cells(2, 3) = rootDispName

        For Each anOrder As Assemblies.ComponentOrder In theOrders

            anOrder.Activate()
            theSession.UpdateManager.DoUpdate(markId1)

            Echo(anOrder.Name & ":")
            WalkAssembyTree(displayPart.ComponentAssembly.RootComponent, anOrder, "")

            'ufs.Ui.DisplayMessage(anOrder.Name, 1)

            theSession.UndoToMark(markId1, "")
        Next

        theSession.DeleteUndoMarksUpToMark(markId1, "", False)

    End Sub

    Sub WalkAssembyTree(ByVal theComponent As NXOpen.Assemblies.Component,
                        ByVal theOrder As NXOpen.Assemblies.ComponentOrder,
                        ByVal indent As String)
        Dim thePart As Part
        Dim kids As Assemblies.Component() = theComponent.GetChildren()
        If kids.Length = 0 Then Return ' Not an assembly or sub-assembly 

        indent = indent + "  "

        ' only Chronological returns any Children 
        If theOrder.OrderType = Order.Type.ChronologicalComponent Then

            kids = theOrder.AskChildrenOrder(theComponent)

            'processes component data (parents)
            For ii As Integer = 0 To kids.Length - 1
                Echo(indent & kids(ii).DisplayName)

                '========================================================
                'code to handle non-geo parts
                thePart = kids(ii).Prototype.OwningPart
                If IsNothing(thePart) Then
                    Continue For
                    'Component is not loaded, probably could not be found
                    'with the current search options.
                End If

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

                    Catch ex As NXException
                        Echo("NX exception: " & ex.Message)
                        Exit Sub
                    End Try
                End If

                If kids(ii).GetNonGeometricState().Equals(True) Then
                    'this is a non-geometric component...
                    ' don't measure it, just record it
                    Cells(row, 3).Value = (kids(ii).Name)
                    Cells(row, 5).value = "Non_Geo"
                Else

                    'do nothing

                End If

                Echo("kids name: <<" & kids(ii).Name & ">>")

                Cells(row, 3).Value = (kids(ii).Name)

                'assigns tag for parents
                TagIdentifier = kids(ii).Tag
                Cells(row, 50).value = TagIdentifier


                'Measure Volume of parts
                Dim theBodies() As Body = thePart.Bodies.ToArray()

                Echo(indent & "Bodies in part: " & theBodies.ToString())

                'process bodies inside components (kids)
                For Each thisBody As Body In theBodies

                    Dim mb As MeasureBodies
                    Dim myMeasure As MeasureManager = theSession.Parts.Display.MeasureManager()
                    Dim massUnits(4) As Unit
                    Dim bbox(5) As Double
                    Dim TCG As String
                    Dim VCG As String
                    Dim LCG As String

                    Dim singleBodyArray(0) As Body

                    singleBodyArray(0) = thisBody

                    massUnits(0) = theSession.Parts.Display.UnitCollection.GetBase("Area")
                    massUnits(1) = theSession.Parts.Display.UnitCollection.GetBase("Volume")
                    massUnits(2) = theSession.Parts.Display.UnitCollection.GetBase("Mass")
                    massUnits(3) = theSession.Parts.Display.UnitCollection.GetBase("Length")

                    mb = myMeasure.NewMassProperties(massUnits, 1, (singleBodyArray))
                    mb.InformationUnit = MeasureBodies.AnalysisUnit.PoundFoot

                    TCG = (mb.Centroid.Y.ToString)
                    LCG = (mb.Centroid.X.ToString)
                    VCG = (mb.Centroid.Z.ToString)

                    'Assign Data to Sheet

                    'populates "number column"
                    Cells(row, 3).Value = (thisBody.OwningPart.Leaf)

                    'Populates volume
                    Cells(row, 11).Value = (mb.Volume.ToString())

                    Cells(row, 14).value = VCG
                    Cells(row, 16).value = LCG
                    Cells(row, 18).value = TCG

                    TagIdentifier = (thisBody.Tag)

                    Cells(row, 50).value = TagIdentifier

                    'Populates Object column as well as searches part attribute data

                                      Echo("thisBody Name: <<" & thisBody.ToString & ">>")

                Next

                row = row + 1

                Dim thisPart As Part = kids(ii).Prototype().OwningPart

                WalkAssembyTree(kids(ii), theOrder, indent)

            Next

        Else

        End If

    End Sub
5 REPLIES

Re: How to get the unique tag of each part in an assembly.

[ Edited ]

I don't see where the variable "TagIdentifier" is initially declared, but the first time it is used it refers to a component tag.

 

TagIdentifier = kids(ii).Tag
Cells(row, 50).value = TagIdentifier

Assuming that your code only processes each component once, all of these returned tags will be unique.

 

TagIdentifier is later changed to refer to a body tag.

TagIdentifier = (thisBody.Tag)

"thisBody" comes from the "theBodies" array, which comes from the .Bodies collection of "thePart". "thePart" is defined as:

thePart = kids(ii).Prototype.OwningPart

Which makes it a part object (prototype) not a component (part occurrence). The "TagIdentifier" is processing the tags of the prototype bodies. If the part is used as a component more than once in your assembly, the same prototype body tags will be returned each time you process one of the part occurrences.

Re: How to get the unique tag of each part in an assembly.

Okay, so whether or not it is a component tag or a part tag, if more than one instance of a part or component is processed more than once, it will return the same tag number?

 

How could I use the AskOccsOfPart method to return a unique tag for each part?

 

 

 

 

 

 

Re: How to get the unique tag of each part in an assembly.

I strongly suggest that you carefully read chapter 11 of the SNAP getting started guide to learn the difference between a prototype and an occurrence. Then re-read my answer.

 

If you still have a question after that, post back.

Re: How to get the unique tag of each part in an assembly.

Okay, I understand. Thanks for that reference. I suppose I can just abandon that code altogether then. I think I am limited in the code I can use because I am running the code remotely, and certain functions do not run as they should. I have a function that if used properly would process the instance bodies, but it does not work in my coding environment.

 

GTAC provided me this however: 

 

Option Strict Off

Imports System
Imports NXOpen
Imports NXOpen.UF
Imports NXOpen.UI
Imports NXOpen.Assemblies
Imports NXOpen.Utilities

Module report_assembly_body_centroids

    Dim theSession As Session = Session.GetSession()
    Dim ufs As UFSession = UFSession.GetUFSession()

    Sub Main()

 ' This assumes the assembly is loaded.

        Dim dp As Part = theSession.Parts.Display
        theSession.EnableRedo(False)

        Dim nextBody As NXOpen.Tag = NXOpen.Tag.Null

        Do
            Dim t As Integer, st As Integer
            Dim isOcc As Boolean = False

            ufs.Obj.CycleTypedObjsInPart(dp.Tag, UFConstants.UF_solid_type, nextBody)
            If nextBody.Equals(NXOpen.Tag.Null) Then
                Exit Do
            End If
            ufs.Obj.AskTypeAndSubtype(nextBody, t, st)
            If st <> UFConstants.UF_solid_body_subtype Then
                Continue Do
            End If
            isOcc = ufs.Assem.IsOccurrence(nextBody)
            If isOcc.Equals(True) Then
                Echo("Found occurrence body: " & nextBody.ToString())
            End If

            Dim theNXOM As NXObjectManager = theSession.GetObjectManager
            Dim theObj As NXObject = theNXOM.GetTaggedObject(nextBody)
            Dim theBody As Body = CType(theObj, Body)


            Dim myMeasure As MeasureManager = theSession.Parts.Display.MeasureManager()
            Dim massUnits(4) As Unit

            massUnits(0) = theSession.Parts.Display.UnitCollection.GetBase("Area")
            massUnits(1) = theSession.Parts.Display.UnitCollection.GetBase("Volume")
            massUnits(2) = theSession.Parts.Display.UnitCollection.GetBase("Mass")
            massUnits(3) = theSession.Parts.Display.UnitCollection.GetBase("Length")

            Dim singleBodyArray() As Body = {theBody}
            Dim mb As MeasureBodies = myMeasure.NewMassProperties(massUnits, 1, singleBodyArray)
            mb.InformationUnit = MeasureBodies.AnalysisUnit.PoundFoot

            Dim centroidalPoint As Point3d = mb.Centroid()
            Echo("Centroid: " & centroidalPoint.X & "  " & centroidalPoint.Y & "  " & centroidalPoint.Z)

Loop Until nextBody.Equals(NXOpen.Tag.Null)

 

This does infact give me the unique tag of each part, and it runs fine in my coding environment. It also gives me the right centers and volume. There is one thing however, that I do need from it that I can't seem to get. The names of the parts.

 

I tried querying some attributes from theBody (specifically DB_PART_NAME), or just the name of the part by using .name or .ToString. Nothing will return however. The only thing I am able to return is nextBody.ToString.

 

How do I get return the names of the parts?

Re: How to get the unique tag of each part in an assembly.

"I suppose I can just abandon that code altogether then."

 

I didn't mean to imply that your previous code was worthless; rather I was trying to point out why you were not getting the results you were after. If you fix the logic errors in the previous code, I think that you can get it to do what you need.

 

The latest code you posted is also very close. Once you know that you have an occurrence body, get the body from the tag using the object manager then you can query the body's owning component and the owning part of the prototype body.

 

Once again, watch out for deformed components and promoted bodies. They may not show up as occurrence bodies.