Cannot bind refkey to part edge in assembly

Cannot bind refkey to part edge in assembly

william
Advocate Advocate
481 Views
4 Replies
Message 1 of 5

Cannot bind refkey to part edge in assembly

william
Advocate
Advocate

Hello All
I am having issues trying to bind a refkey to a part edge selected within the assembly context. 


What I am trying to achieve is to store selection sets inside an assembly file by writing the refkeys and key context to custom iproperties. I can then query the election sets later to get information like total length of edges, etc. 

Rule 1: Prompts to select part edges within an assembly, as each edge is selected it adds it to a string variable separated by comma's. Once the selection is complete, write the string variable to a custom iProperty where it can be retrieved later. Likewise for the key context. 

Rule 2: Checks the custom iProperties to see if any selection sets exist, if yes then split the string variable by the comma's to get each individual refkey. Once I have the refkey I should be able to retrieve the object (edge) and get my length info, etc. 
The problem I am having is getting the object from the refkey and key context. It keeps throwing an error on this line.

foundEdge = refKeyMgr.BindKeyToObject(edgeRefKey, refKeyContext)

I am a bit stuck on this. 
I have used the same rules to do something similar for selecting sketch elements inside a part file (see: Rules for selection set of sketch lines and calculating the length. - Autodesk Community - Inventor) and that has worked fine, but it doesn't need the keycontext. I think this is where it is going wrong. 
I have been referencing this post (https://modthemachine.typepad.com/my_weblog/2015/09/understanding-reference-keys-in-inventor.html). 

Any help is appreciated. 

Rule 1:

Sub Main()
	
If ThisApplication.ActiveDocumentType <> kAssemblyDocumentObject Then
    MessageBox.Show("This rule can only be run in an .iam environment" & vbNewLine & "The rule will exit...", "Error Handling",MessageBoxButtons.OK,MessageBoxIcon.Error)
    Return
End If

' Get the active document.
Dim oDoc = ThisDoc.Document

' Set a reference to the ReferenceKeyManager object.
Dim refKeyMgr As ReferenceKeyManager = oDoc.ReferenceKeyManager

' Create a key context.
Dim keyContext As Long = refKeyMgr.CreateKeyContext

' Get the key context as an array of bytes and
' convert it to a string.
Dim contextArray() As Byte = New Byte() {}
refKeyMgr.SaveContextToArray(keyContext, contextArray)
Dim strContext As String
strContext = refKeyMgr.KeyToString(contextArray)
iProperties.Value("Custom", "RefKeyContext") = strContext

Dim SelectionSet As New ArrayList

oCustomPropertySet = oDoc.PropertySets.Item("Inventor User Defined Properties")
userParams = ThisDoc.Document.ComponentDefinition.Parameters.UserParameters

For Each oProp In oCustomPropertySet
	If oProp.name.Contains("RefKeys") Then 
		SelectionSet.Add(oProp.name)
	End If	
Next

SelectionSet.Add("Add new selection set")

SelectedParam = InputListBox("", SelectionSet, SelectionSet, Title := "Available Parameters", ListName := "Please select an Option")

If SelectedParam = "Add new selection set" Then
	myparam = InputBox("Enter the selection set name", "Title", "Test")
	iProperties.Value("Custom", myparam & "_RefKeys") = ""
	Try
		oParameter = userParams.AddByValue(myparam & "_Value", "", UnitsTypeEnum.kMillimeterLengthUnits)
	Catch
		'Parameter already exists
	End Try
	SelectionSet.Add(myparam & "_RefKeys")
	SelectedParam = myparam & "_RefKeys"
End If


Dim oHSet As HighlightSet = oDoc.CreateHighlightSet()
oHSet.Color = ThisApplication.TransientObjects.CreateColor(185, 0, 0) 'Red

Start :

Dim oEdge As Edge
oEdge = ThisApplication.CommandManager.Pick(SelectionFilterEnum.kPartEdgeFilter, "Select a edge to add to the combined measurement")

Dim refKey() As Byte = New Byte() {}
oEdge.GetReferenceKey(refKey, keyContext)
Dim strRefKey As String = refKeyMgr.KeyToString(refKey)


Dim strAccumulatedRefKey As String = strAccumulatedRefKey & "," & strRefKey

oHSet.AddItem(oEdge)

Q = MessageBox.Show("Select another edge?", "Create Selection Set", MessageBoxButtons.YesNo)

oDoc.SelectSet.Clear()

If Q = vbYes Then 
	GoTo Start
End If

iProperties.Value("Custom", SelectedParam) = strAccumulatedRefKey

oHSet.Clear()

End Sub


Rule 2:

'https://forums.autodesk.com/t5/inventor-programming-ilogic/out-of-memory-error-while-working-with-referencekey/td-p/10590755
'https://modthemachine.typepad.com/my_weblog/2015/09/understanding-reference-keys-in-inventor.html

Sub Main()
'On Error Resume Next

If ThisApplication.ActiveDocumentType <> kAssemblyDocumentObject Then
    MessageBox.Show("This rule can only be run in an .iam environment" & vbNewLine & "The rule will exit...", "Error Handling",MessageBoxButtons.OK,MessageBoxIcon.Error)
    Return
End If

' Get the active document
Dim oDoc = ThisDoc.Document

userParams = ThisDoc.Document.ComponentDefinition.Parameters.UserParameters
oCustomPropertySet = oDoc.PropertySets.Item("Inventor User Defined Properties")

oContinue = False
For Each oProp In oCustomPropertySet
	If oProp.name.Contains("RefKeyContext") Then
		oContinue = True
	End If	
Next

If oContinue = False Then
	MessageBox.Show("This document is missing essential information to execute this rule. Please ensure the selection sets have been created and the RefKeyContext property exists." & vbNewLine & "The rule will exit...", "Error Handling",MessageBoxButtons.OK,MessageBoxIcon.Error)
    Return
End If

' Get a reference to the reference key manager.
Dim refKeyMgr As ReferenceKeyManager = oDoc.ReferenceKeyManager

' Read the reference key strings from the file.
Dim context As String = iProperties.Value("Custom", "RefKeyContext")

' Convert the string to byte arrays.
Dim contextArray() As Byte = New Byte() {}
refKeyMgr.StringToKey(context, contextArray)

' Create the context by loading the data.
Dim refKeyContext As Long
refKeyContext = refKeyMgr.LoadContextFromArray(contextArray)

Dim SelectionSet As New ArrayList

For Each oProp In oCustomPropertySet
	If oProp.name.Contains("RefKeys") Then 
		SelectionSet.Add(oProp.name)
	End If	
Next

If SelectionSet.Count <= 0 Then
 Exit Sub
End If

For i = 0 To SelectionSet.Count - 1
	ParameterName = SelectionSet(i).Replace("_RefKeys","")
	ParamExists = False
	
	Dim strRefKeysArray() As String =  iProperties.Value("Custom", SelectionSet(i)).Split(",")
	AccumulatedLength = 0
	
	For j = 1 To strRefKeysArray.Count - 1
		Dim strRefKey As String = strRefKeysArray(j)
	    Dim edgeRefKey() As Byte = New Byte() {}

	    refKeyMgr.StringToKey(strRefKey, edgeRefKey)
	   
		Dim foundEdge As Edge 
		foundEdge = refKeyMgr.BindKeyToObject(edgeRefKey, refKeyContext)

		'*********
'		Dim oEdge As Edge
'		'oEdge = oDoc.SelectSet.Item(1)
'		oEdge = refKeyMgr.BindKeyToObject(edgeRefKey)
		
'		Dim oEval As CurveEvaluator = oEdge.Evaluator
'		Dim oMin, oMax, oLength As Double
'		oEval.GetParamExtents(oMin, oMax)
'		oEval.GetLengthAtParam(oMin, oMax, oLength)
		'***********


'		If TypeOf foundObject Is Inventor.Edge Then
'			'MessageBox.Show("Message", "Title")
'		    Dim foundLine As Edge
'		    foundLine = refKeyMgr.BindKeyToObject(edgeRefKey)
'			Length = foundLine.Length
'		ElseIf TypeOf foundObject Is Inventor.SketchArc Then
'		    Dim foundArc As SketchArc
'		    foundArc = refKeyMgr.BindKeyToObject(edgeRefKey)
'			Length = foundArc.Length
'		Else
'			Length = 0
'		   	'Found object type is not supported
'		End If
		
		AccumulatedLength += oLength
		
	Next
	
		For Each oParam In userParams
			If oParam.Name.Contains(ParameterName & "_Value") Then
				ParamExists = True
				Parameter.Param(oParam.Name).Value = AccumulatedLength
			End If
		Next
	
	If ParamExists = False Then
		'MessageBox.Show("ParameterName: " & ParameterName, "Title")
		oParameter = userParams.AddByValue(ParameterName & "_Value", AccumulatedLength, UnitsTypeEnum.kMillimeterLengthUnits)
	End If

Next


RuleParametersOutput()
iLogicVb.UpdateWhenDone = True

End Sub
0 Likes
Accepted solutions (2)
482 Views
4 Replies
Replies (4)
Message 2 of 5

william
Advocate
Advocate

@YuhanZhang  You had some helpful posts in this thread (Solved: Out of memory error while working with ReferenceKey - Autodesk Community - Inventor) regarding the reference keys. 

Can you see what I am doing wrong in the above rules? 

This is the error I am getting on the below code. Line 70 (second rule)

foundEdge = refKeyMgr.BindKeyToObject(edgeRefKey, refKeyContext)


System.Runtime.InteropServices.COMException (0x80004005): Unspecified error (Exception from HRESULT: 0x80004005 (E_FAIL))
at System.RuntimeType.ForwardCallToInvokeMember(String memberName, BindingFlags flags, Object target, Int32[] aWrapperTypes, MessageData& msgData)
at Inventor.ReferenceKeyManager.BindKeyToObject(Byte[]& ReferenceKey, Int32 KeyContext, Object& MatchType)
at ThisRule.Main() in external rule: Estimating_Selection Set_Assembly Edges_Compute:line 70
at Autodesk.iLogic.Exec.AppDomExec.ExecRuleInAssembly(Assembly assem)
at iLogic.RuleEvalContainer.ExecRuleEval(String execRule)

0 Likes
Message 3 of 5

Michael.Navara
Advisor
Advisor
Accepted solution

I'm sorry I don't test your code, but for this purpose you can use better approach using Attributes. RefKeys are very low level object which can be used, but in my opinion use attributes are more readable and flexible.  

 

 

 

Sub Main()
StoreSelectSet()

PrintAvailableSelectSets()

QuerySelectSet()

End Sub


Private Sub StoreSelectSet()

	'Select set name
	Dim selectSetId = InputBox("SelectSet name (Cancel or empty value to skip)", "Store select set", "")
	If selectSetId = "" Then Return

	'Select set content
	Dim edgesList = New List(Of Edge)()
	Dim pick As Object
	Do
		pick = ThisApplication.CommandManager.Pick(SelectionFilterEnum.kPartEdgeFilter, "Select edge")
		Dim edge = TryCast(pick, Edge)
		If edge IsNot Nothing Then edgesList.Add(edge)
	Loop While pick IsNot Nothing


	'Store select set
	For Each edge As Edge In edgesList
		Dim attributeSet As AttributeSet
		Try
			attributeSet = Edge.AttributeSets("SelectSet")
		Catch ex As Exception
			attributeSet = Edge.AttributeSets.Add("SelectSet")
		End Try
		attributeSet.Add(selectSetId, ValueTypeEnum.kStringType, "")
	Next

End Sub

Private Sub PrintAvailableSelectSets()

	Dim attributeManager As AttributeManager = ThisDoc.Document.AttributeManager
	Dim attributesEnumerator As AttributesEnumerator = attributeManager.FindAttributes("SelectSet")
	Logger.Debug("Defined select sets")
	Dim sets = New List(Of String)
	For Each attribute As Inventor.Attribute In attributesEnumerator.OfType(Of Inventor.Attribute)
		Dim attName As String = Attribute.Name
		If sets.Contains(attName) Then Continue For
		Logger.Debug(attName)
		sets.Add(attName)
	Next
End Sub

Private Sub QuerySelectSet()
	'Select set name
	Dim selectSetId = InputBox("SelectSet name (Cancel or empty value to skip)", "Restore select set", "")
	If selectSetId = "" Then Return

	'Restore select set
	Dim attributeManager As AttributeManager = ThisDoc.Document.AttributeManager
	Dim objectCollection As ObjectCollection = attributeManager.FindObjects("SelectSet", selectSetId)

	ThisDoc.Document.SelectSet.SelectMultiple(objectCollection)
End Sub

 

 

 

EDIT:

Sample how to obtain existing select sets added

 

EDIT 2:

Shorter version of PrintAvailableSelectSets method 

Private Sub PrintAvailableSelectSets()

    Dim attributeManager As AttributeManager = ThisDoc.Document.AttributeManager
    Dim attributesEnumerator As AttributesEnumerator = attributeManager.FindAttributes("SelectSet")
    Logger.Debug("Defined select sets")
    For Each attName In attributesEnumerator.OfType(Of Inventor.Attribute).Select(Function(att) att.Name).Distinct()
        Logger.Debug(attName)
    Next
End Sub

 

0 Likes
Message 4 of 5

william
Advocate
Advocate
Accepted solution

Hello Michael 
Thanks for the reply, it was helpful. I hadn't considered the use of Attribute sets. 

Incidentally I discovered what was wrong with my original code to use rekeys. Since I haven't seen this issue publicized anywhere, I will note some points below. 

The issue on the below line, was that I had the wrong Key Context. 

foundEdge = refKeyMgr.BindKeyToObject(edgeRefKey, refKeyContext)

In my first rule, I first created the key Context, and afterwards created the refkeys for the objects selected. As it turns out, the key context will change with each refkey retrieved. This means to get the correct key context I first need to retrieve the ref keys for the objects first, then create the key context.  
That can be seen in the below code. 

Sub Main ()
    ' Get the active document.
    Dim doc As Document = ThisApplication.ActiveDocument
   
    ' Have a face and edge selected.
    Dim selFace As Face = ThisApplication.CommandManager.Pick(kPartFaceFilter, "Select face.")
    Dim selEdge As Edge = ThisApplication.CommandManager.Pick(kPartEdgeFilter, "Select edge.")

    ' Set a reference to the ReferenceKeyManager object.
    Dim refKeyMgr As ReferenceKeyManager = doc.ReferenceKeyManager

    ' Create a key context.
    Dim keyContext As Long
    keyContext = refKeyMgr.CreateKeyContext
   
     ' Get reference keys from the selected entities.
    Dim faceRefKey() As Byte = New Byte() {}
    Call selFace.GetReferenceKey(faceRefKey, keyContext)
    Dim edgeRefKey() As Byte = New Byte() {}
    Call selEdge.GetReferenceKey(edgeRefKey, keyContext)

    ' Get the key context as an array of bytes and
    ' convert it to a string.
    Dim contextArray() As Byte = New Byte() {}
    Call refKeyMgr.SaveContextToArray(keyContext, contextArray)
    Dim strContext As String
    strContext = refKeyMgr.KeyToString(contextArray)
 

 
    ' Convert the reference keys to strings to make saving it easier.
    Dim strFaceKey As String
    strFaceKey = doc.ReferenceKeyManager.KeyToString(faceRefKey)
    Dim strEdgeKey As String
    strEdgeKey = doc.ReferenceKeyManager.KeyToString(edgeRefKey)
   
    ' Save the results to a file.
	'____Create and write to a text file_________________
	oWrite = System.IO.File.CreateText(ThisDoc.PathAndFileName(False) & ".txt")
	oWrite.WriteLine(strContext)
	oWrite.WriteLine(strEdgeKey)
	oWrite.WriteLine(strFaceKey)
	oWrite.Close()
	'open the file
	ThisDoc.Launch(ThisDoc.PathAndFileName(False) & ".txt")
	
End Sub

Then you can bind the keys back to the objects using this code

Sub Main()
    ' Get the active document.
    Dim doc As Document = ThisApplication.ActiveDocument
   
    ' Get a reference to the reference key manager.
    Dim refKeyMgr As ReferenceKeyManager = doc.ReferenceKeyManager
   
    ' Read the reference key strings from the file.
    Dim context As String
    Dim edgeKey As String
    Dim faceKey As String
	
	'____Open and read a text file_______________________
	oRead = System.IO.File.OpenText(ThisDoc.PathAndFileName(False) & ".txt")
	context = oRead.ReadLine()
    edgeKey = oRead.ReadLine()
    faceKey = oRead.ReadLine()
	oRead.Close()
   
    ' Convert the string to byte arrays.
    Dim edgeRefKey() As Byte = New Byte() {}
    Dim faceRefKey() As Byte = New Byte() {}
    Dim contextArray() As Byte = New Byte() {}
    Call refKeyMgr.StringToKey(edgeKey, edgeRefKey)
    Call refKeyMgr.StringToKey(faceKey, faceRefKey)
    Call refKeyMgr.StringToKey(context, contextArray)

    ' Create the context by loading the data.
    Dim refKeyContext As Long
    refKeyContext = refKeyMgr.LoadContextFromArray(contextArray)
   
    ' Bind back the face and edge.
    Dim foundFace As Face = refKeyMgr.BindKeyToObject(faceRefKey, refKeyContext)
    Dim foundEdge As Edge = refKeyMgr.BindKeyToObject(edgeRefKey,refKeyContext)
   
    ' Highlight the found entities.
    doc.SelectSet.Clear
    doc.SelectSet.Select(foundFace)
    doc.SelectSet.Select(foundEdge)
End Sub

 

Ultimately this ended up being a quicker implementation into my original code than changing to attribute sets, but thanks for the tips. 
 

Message 5 of 5

william
Advocate
Advocate

Here are the modified rules to create the edge selection sets, then compute the accumulated lengths for the edges. 

Create edge selection sets:

Sub Main()
	
If ThisApplication.ActiveDocumentType <> kAssemblyDocumentObject Then
    MessageBox.Show("This rule can only be run in an .iam environment" & vbNewLine & "The rule will exit...", "Error Handling",MessageBoxButtons.OK,MessageBoxIcon.Error)
    Return
End If

' Get the active document.
Dim oDoc = ThisDoc.Document

' Set a reference to the ReferenceKeyManager object.
Dim refKeyMgr As ReferenceKeyManager = oDoc.ReferenceKeyManager

' Create a key context.
Dim keyContext As Long = refKeyMgr.CreateKeyContext

Dim SelectionSet As New ArrayList

oCustomPropertySet = oDoc.PropertySets.Item("Inventor User Defined Properties")
userParams = ThisDoc.Document.ComponentDefinition.Parameters.UserParameters

For Each oProp In oCustomPropertySet
	If oProp.name.Contains("RefKeys") Then 
		SelectionSet.Add(oProp.name)
	End If	
Next

SelectionSet.Add("Add new selection set")
SelectedParam = InputListBox("", SelectionSet, SelectionSet, Title := "Available Parameters", ListName := "Please select an Option")
SelectedParam = SelectedParam.Replace("_RefKeys", "")

If SelectedParam = "Add new selection set" Then
	myparam = InputBox("Enter the selection set name", "Title", "Test")
	Try
		oParameter = userParams.AddByValue(myparam & "_Value", "", UnitsTypeEnum.kMillimeterLengthUnits)
	Catch
		'Parameter already exists
	End Try
	SelectionSet.Add(myparam & "_RefKeys")
	SelectedParam = myparam
End If



Dim oHSet As HighlightSet = oDoc.CreateHighlightSet()
oHSet.Color = ThisApplication.TransientObjects.CreateColor(185, 0, 0) 'Red
Start :
Dim oEdge As Edge
oEdge = ThisApplication.CommandManager.Pick(SelectionFilterEnum.kPartEdgeFilter, "Select a edge to add to the combined measurement")

Dim refKey() As Byte = New Byte() {}
oEdge.GetReferenceKey(refKey, keyContext)
Dim strRefKey As String = refKeyMgr.KeyToString(refKey)
Dim strAccumulatedRefKey As String = strAccumulatedRefKey & "," & strRefKey

oHSet.AddItem(oEdge)
Q = MessageBox.Show("Select another edge?", "Create Selection Set", MessageBoxButtons.YesNo)
oDoc.SelectSet.Clear()
If Q = vbYes Then 
	GoTo Start
End If

' Get the key context as an array of bytes and convert it to a string.
Dim contextArray() As Byte = New Byte() {}
Call refKeyMgr.SaveContextToArray(keyContext, contextArray)
Dim strContext As String
strContext = refKeyMgr.KeyToString(contextArray)

iProperties.Value("Custom", SelectedParam & "_RefKeyContext") = strContext
iProperties.Value("Custom", SelectedParam & "_RefKeys") = strAccumulatedRefKey

oHSet.Clear()

End Sub


Compute accumulated edge lengths. 

'https://forums.autodesk.com/t5/inventor-programming-ilogic/out-of-memory-error-while-working-with-referencekey/td-p/10590755
'https://modthemachine.typepad.com/my_weblog/2015/09/understanding-reference-keys-in-inventor.html

Sub Main()

If ThisApplication.ActiveDocumentType <> kAssemblyDocumentObject Then
    MessageBox.Show("This rule can only be run in an .iam environment" & vbNewLine & "The rule will exit...", "Error Handling",MessageBoxButtons.OK,MessageBoxIcon.Error)
    Return
End If

' Get the active document
Dim oDoc = ThisDoc.Document

userParams = ThisDoc.Document.ComponentDefinition.Parameters.UserParameters
oCustomPropertySet = oDoc.PropertySets.Item("Inventor User Defined Properties")

Dim SelectionSet As New ArrayList

For Each oProp In oCustomPropertySet
	If oProp.name.Contains("RefKeys") Then 
		SelectionSet.Add(oProp.name)
	End If	
Next

If SelectionSet.Count <= 0 Then
 Exit Sub
End If

For i = 0 To SelectionSet.Count - 1
	ParameterName = SelectionSet(i).Replace("_RefKeys","")
	ParamExists = False
	
	
	' Get a reference to the reference key manager.
	Dim refKeyMgr As ReferenceKeyManager = oDoc.ReferenceKeyManager
	
	' Read the reference key strings from the file.
	Dim context As String
	Try
		context = iProperties.Value("Custom", ParameterName & "_RefKeyContext")
	Catch
		MessageBox.Show("This document is missing essential information to execute this rule. Please ensure the selection sets have been created and the RefKeyContext property exists." & vbNewLine & "The rule will exit...", "Error Handling",MessageBoxButtons.OK,MessageBoxIcon.Error)
    	Return
	End Try
	
	' Convert the string to byte arrays.
	Dim contextArray() As Byte = New Byte() {}
	refKeyMgr.StringToKey(context, contextArray)
	
	' Create the context by loading the data.
	Dim refKeyContext As Long
	refKeyContext = refKeyMgr.LoadContextFromArray(contextArray)
	
	
	Dim strRefKeysArray() As String =  iProperties.Value("Custom", SelectionSet(i)).Split(",")
	AccumulatedLength = 0
	
	For j = 1 To strRefKeysArray.Count - 1
		Dim strRefKey As String = strRefKeysArray(j)
	    Dim edgeRefKey() As Byte = New Byte() {}

	    refKeyMgr.StringToKey(strRefKey, edgeRefKey)
	   
		Dim foundEdge As Edge
		Try
			foundEdge = refKeyMgr.BindKeyToObject(edgeRefKey, refKeyContext)
		Catch
			MessageBox.Show("Error getting the edge object from the refkey, the rule will exit")
			Return
		End Try
		Dim oMin, oMax, oLength As Double

		Try
			Dim oEval As CurveEvaluator = foundEdge.Evaluator
			oEval.GetParamExtents(oMin, oMax)
			oEval.GetLengthAtParam(oMin, oMax, oLength)
		Catch
			MessageBox.Show("There was an error getting the length from the edge object. It will be skipped and not added to the accumulated total length. Please check your inputs/select set")
		End Try
		
		AccumulatedLength += oLength
		
	Next
	
		For Each oParam In userParams
			If oParam.Name.Contains(ParameterName & "_Value") Then
				ParamExists = True
				Parameter.Param(oParam.Name).Value = AccumulatedLength
			End If
		Next
	
	If ParamExists = False Then
		'MessageBox.Show("ParameterName: " & ParameterName, "Title")
		oParameter = userParams.AddByValue(ParameterName & "_Value", AccumulatedLength, UnitsTypeEnum.kMillimeterLengthUnits)
	End If

Next


RuleParametersOutput()
iLogicVb.UpdateWhenDone = True

End Sub

 

0 Likes