Obtaining Feature Information

I am working on a tool that modifies feature parameters in multiple ways. The features in this case are Hole Series features which have an Axis and a Point to define the Hole Series feature placement and vector.

I can modify everything I need to when the selection input is the Hole Series feature itself however I want to find the feature by selecting the component the feature is created from instead. Its a far better user experience. I am having a hell of a time doing that.

The code I wrote will take screw component selections (driving component for hole series feature) grab the tag and parent component (where the features reside) and search each feature for the tag of the driving component. That last part is what I cant seem to do. I have tried all of the Feature class functions (getparents, getchildren, etc) and also the theUfSession.Modl functions (AskFeatRelatives, AskReferencesOfFeatures, etc) without any luck.

The Hole Series feature information does not contain the driving component but both the Axis and Point features do.

It stands to reason (at least to me) that if the information window contains the name of what I'm after there is a way for the API to retrieve it as well. Though I need to grab the tag and not just the name as there could be multiple instances of the same screw being used for different features.

Any suggestions?

I'm trying to create an example file for myself based on your post; however, I rarely use the "hole series" command, so I'm having some trouble recreating your situation. Does your part navigator screenshot show the assembly part navigator? Did you create the wave links separately before creating the hole feature, or were they created as part of the hole series feature?

I'm guessing that you wave-linked the axis and point objects from the screw to the assembly, then created a hole series feature in the desired component. Is this correct?

These Hole Series features are created from the Reusable Pocket command when ran against a Part Family enabled component. How it all works is a bit of an explanation but its accessible through the Reuse Library / Reuse Examples that come with NX out of the box. To create an exact feature tree and relationship like the one I have I would do the following.

-Create an assembly with 3 items. 2 component bodies to serve as targets (basically 2 plates) and a 3rd to serve as the fastener subassembly node (where all the fasteners will live).

-Make fastener node your workpart.

-Add a Metric Hex Head Reuse Library component. (if your reuse library is missing the examples they are found "C:\Program Files\Siemens\NX2007\NXPARTS\Reuse Library\Reuse Examples\Standard Parts")

-Move the screw component to a feasible position inside the assembly (on top of the first target and intersecting with the other)

-Run Reuseable Pocket and select your screw. Hole Series should automatically be selected and then hit ok.

This should create a very close scenario to what I am working with. I have a Part Family component of my own creation that I call in with other code, but I am using the same methodology here with my other routines for subtraction.

Ok, I've created the parts:

Assembly
  base plate
  top plate
  fastener

With "fastener" as the work part, I pulled in a bolt from the reuse library. This added the bolt as a component to the "fastener" part. When I ran the "reusable pocket" command, it resulted in a linked datum axis, linked point, and screw hole series features being created in the "fastener" part. The base plate has a "linked threaded hole" feature and the top plate has a "linked counterbored screw hole" feature.

If I understand correctly, you want to query the "fastener" component to find the components where the holes are created - "base plate" and "top plate" in my example. Is this correct?

Close...I want to query the part navigator in the fastener subassembly for the "Linked Datum Axis" and/or "Linked Counterbored Screw Hole" and tie it to the Reuse Library Bolt that was inserted using the meta data from either of those 2 features.

So the programming logic would be something like

-user inputs bolt as selection
-program grabs the tag of the bolt and the parent of the bolt (Fastener subassembly)
-program does a for each feature loop inspecting each feature inside Fastener subassembly.
-if program finds "Linked Datum Axis" JID it searches for the bolt as its driving component. If found, then do some stuff.

I think AskAssyCtxtPartOcc may be of use here. The link below shows how to use it to find the source component of a wave linked mirror body. With some modification, we should be able to get it to tell us the bolt component used for a particular linked feature. I'll try to work up a better example if I can find some time today.

https://nxjournaling.com/comment/2287#comment-2287

I put together some "proof of concept" code. It does not have any error checking and I have not done extensive testing; but it seems to work on my simple assembly (details in a previous post). When run with the top level assembly as the display and work part, the journal will prompt to select a component. It will then get the immediate parent of the component and look for wave link features. The information is saved in a dictionary that you can query by component to find a list of features that use the component in a link.

I hope this helps.

'NXJournaling.com
'March 13, 2024

Option Strict Off
Imports System
Imports System.Collections.Generic
Imports NXOpen
Imports NXOpen.Assemblies
Imports NXOpen.UF

Module Module4

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

Dim lw As ListingWindow = theSession.ListingWindow

Sub Main()

If IsNothing(theSession.Parts.BaseWork) Then
'active part required
Return
End If

Dim workPart As Part = theSession.Parts.Work
lw.Open()

Const undoMarkName As String = "NXJ bolt mapping"
Dim markId1 As Session.UndoMarkId
markId1 = theSession.SetUndoMark(Session.MarkVisibility.Visible, undoMarkName)

'use a dictionary to hold the results
Dim waveLinkDic As New Dictionary(Of Assemblies.Component, List(Of Features.Feature))

'select bolt component
Dim compBolt As Assemblies.Component = Nothing
If SelectComponent("select bolt component", compBolt) = Selection.Response.Cancel Then
'no bolt selected
Return
End If

'get immediate parent of bolt component (the fastener subassembly)
Dim compFastenerSubassembly As Component = Nothing
compFastenerSubassembly = compBolt.Parent

lw.WriteLine("selected bolt: " & compBolt.Name & ", tag: " & compBolt.Tag.ToString)
lw.WriteLine("fastener assembly: " & compFastenerSubassembly.Name & ", tag: " & compFastenerSubassembly.Tag.ToString)
lw.WriteLine("")

'find wave linked features in fastener assembly, fastener assembly should be fully loaded (not checked in this journal)
Dim partFastenerSubassembly As Part = compFastenerSubassembly.Prototype

For Each tempFeat As Features.Feature In partFastenerSubassembly.Features
If IsLinkedFeature(tempFeat) Then
'lw.WriteLine("linked feature found: " & tempFeat.GetFeatureName)
Dim fromComp As Assemblies.Component = Nothing
fromComp = WaveLinkFromComp(compFastenerSubassembly, tempFeat)
If IsNothing(fromComp) Then
'skip this one for now
lw.WriteLine("error: source component not found")
Continue For
Else
'lw.WriteLine("source component: " & fromComp.Name & ", tag: " & fromComp.Tag.ToString)
'does this component exist in the dictionary?
If waveLinkDic.ContainsKey(fromComp) Then
'add wave link feature to list of features
waveLinkDic.Item(fromComp).Add(tempFeat)
Else
'add component as key and create a new list that holds the wave link feature
waveLinkDic.Add(fromComp, New List(Of Features.Feature)({tempFeat}))
End If
End If
End If
Next

'report what we found for the selected component
lw.WriteLine("the following features link to the selected component [" & compBolt.Tag.ToString & "]")
For Each tempFeature As Features.Feature In waveLinkDic.Item(compBolt)
lw.WriteLine(" " & tempFeature.GetFeatureName)
Next

'uncomment the following code to report all the live links found in the fastener assembly
'lw.WriteLine("")
'lw.WriteLine("")
'lw.WriteLine("All info")
'lw.WriteLine("The fastener assembly contains the following links (component name [tag]):")
'For Each kvp As KeyValuePair(Of Assemblies.Component, List(Of Features.Feature)) In waveLinkDic
' lw.WriteLine(" " & kvp.Key.DisplayName & " [" & kvp.Key.Tag.ToString & "]")
' For Each tempFeat As Features.Feature In kvp.Value
' lw.WriteLine(" " & tempFeat.GetFeatureName)
' Next
'Next

lw.Close()

End Sub

Function SelectComponent(ByVal prompt As String, ByRef selObj As TaggedObject) As Selection.Response

Dim theUI As UI = UI.GetUI
Dim title As String = "Select a component"
Dim includeFeatures As Boolean = False
Dim keepHighlighted As Boolean = False
Dim selAction As Selection.SelectionAction = Selection.SelectionAction.ClearAndEnableSpecific
Dim cursor As Point3d
Dim scope As Selection.SelectionScope = Selection.SelectionScope.AnyInAssembly
Dim selectionMask_array(0) As Selection.MaskTriple

With selectionMask_array(0)
.Type = UFConstants.UF_component_type
.Subtype = UFConstants.UF_component_subtype
End With

Dim resp As Selection.Response = theUI.SelectionManager.SelectTaggedObject(prompt,
title, scope, selAction,
includeFeatures, keepHighlighted, selectionMask_array,
selObj, cursor)
If resp = Selection.Response.ObjectSelected OrElse resp = Selection.Response.ObjectSelectedByName Then
Return Selection.Response.Ok
Else
Return Selection.Response.Cancel
End If

End Function

Function IsLinkedFeature(theFeature As Features.Feature) As Boolean
'function written by Amy Webster, Siemens support
Dim arule As String = "mqc_isLinkedFeature(" & theFeature.Tag.ToString & ")"

Dim ruleName As String = ""
theUfSession.Cfi.GetUniqueFilename(ruleName)

theSession.Parts.Work.RuleManager.CreateDynamicRule("root:", ruleName, "Boolean", arule, "")
Dim isLinked As String = theSession.Parts.Work.RuleManager.EvaluateAsString("root:" & ruleName & ":")
theSession.Parts.Work.RuleManager.DeleteDynamicRule("root:", ruleName)

If isLinked.CompareTo("TRUE") = 0 Then Return True Else Return False

End Function

Function WaveLinkFromComp(ByVal toComp As Assemblies.Component, ByVal linkedFeature As Features.Feature) As Assemblies.Component

'the "toComp" is the part component that owns the wave linked features
'the component returned by this function (the "fromComp") is the source component for the wave link
'PartOcc = Part Occurrence (AKA component)

Dim theXformTag As Tag
Dim fromPartOccTag As Tag
Dim fromComp As Assemblies.Component = Nothing

theUfSession.Wave.AskLinkXform(linkedFeature.Tag, theXformTag)
'lw.WriteLine("theXformTag: " & theXformTag.ToString)
theUfSession.So.AskAssyCtxtPartOcc(theXformTag, toComp.Tag, fromPartOccTag)

Try
fromComp = Utilities.NXObjectManager.Get(fromPartOccTag)

Catch ex As NXException
lw.WriteLine("NX exception: " & ex.Message)
Catch ex As Exception
lw.WriteLine("Exception: " & ex.Message)
End Try

If IsNothing(fromComp) Then
'lw.WriteLine("fromComp is nothing")
Return Nothing
Else
'lw.WriteLine("linked from part: " & fromComp.Prototype.OwningPart.Leaf & " [component name: " & fromComp.Name & "]")
Return fromComp
End If

End Function

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

There is a lot to dissect here. I am in the office today and should have the afternoon to dig into this and try to implement it into my code. I'll let you know what I come up with.

Thank you for your help. It's greatly appreciated.

As a quick aside, did you happen to see my response to the "Highlighting Or Selecting Components In Assembly Navigator" thread? I'm curious what your thoughts on that are. My programs always use the blockstyler and it was the first time I've seen it be an issue for a call.

I'm pretty early still in my testing but this is working for me so far. The WaveLinkFromComp() function containing the AskLinkXform and AskAssyCtxtPartOcc calls was what I was missing.

You're the Patron Saint of NXOpen API.

Thank you very much for your help.