Community
Inventor Programming - iLogic, Macros, AddIns & Apprentice
Inventor iLogic, Macros, AddIns & Apprentice Forum. Share your knowledge, ask questions, and explore popular Inventor topics related to programming, creating add-ins, macros, working with the API or creating iLogic tools.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Having lots of trouble with ReferenceKeyManager and BindKeyToObject

8 REPLIES 8
SOLVED
Reply
Message 1 of 9
dhaverstick
606 Views, 8 Replies

Having lots of trouble with ReferenceKeyManager and BindKeyToObject

I have some surfaces that I create and then split. After the split, I need to delete some of the surfaces, do another split on the remaining surfaces, and then delete some surfaces from the end result. I have tried many, many, many different ways to keep track of what faces to keep and what faces to delete but none of them have been foolproof. From the research I've done, it looks like creating reference keys is the method I should be using. Unfortunately, I cannot get the BindKeyToObject method to ever work correctly. I need some guidance, please. Here are the steps I am going through.

 

1) I create some surfaces by revolving a profile.

2) I iterate through the faces and create a reference key for each one.

FacesToSplit = InventorApp.TransientObjects.CreateObjectCollection
ReferenceKeys = New List(Of String)
ReferenceKeyObj = New Byte() {}
KeyContextObj = RepadPartDocument.ReferenceKeyManager.CreateKeyContext

For I = 1 To HeadSurfaceFeature.Faces.Count
    FaceObject = HeadSurfaceFeature.Faces.Item(I)
    FaceObject.GetReferenceKey(ReferenceKeyObj, KeyContextObj)
    ReferenceKeyString = RepadPartDocument.ReferenceKeyManager.KeyToString(ReferenceKeyObj)
    ReferenceKeys.Add(ReferenceKeyString)

    FacesToSplit.Add(FaceObject)
Next

ContextData = New Byte() {}
RepadPartDocument.ReferenceKeyManager.SaveContextToArray(KeyContextObj, ContextData)
Dim ContextDataString As String
ContextDataString = RepadPartDocument.ReferenceKeyManager.KeyToString(ContextData)

3) I now create a Split feature. I went from having 2 faces to now having 4. I need to keep the 2 newly made faces and delete the other 2. My thought process is that I should be able to retrieve the original faces by using the BindKeyToObject method, put them in an ObjectCollection and then create a DeleteFaces feature. Here is my code to retrieve the original faces that I created reference keys for.

FacesToDelete = InventorApp.TransientObjects.CreateFaceCollection
Dim MatchType As Object = Nothing
Dim ReturnObj As Object
ReferenceKeyObj = New Byte() {}
ContextData = New Byte() {}
RepadPartDocument.ReferenceKeyManager.StringToKey(ContextDataString, ContextData)
KeyContextObj = RepadPartDocument.ReferenceKeyManager.LoadContextFromArray(ContextData)

For I = 0 To ReferenceKeys.Count - 1
    ReferenceKeyString = ReferenceKeys.Item(I)
    RepadPartDocument.ReferenceKeyManager.StringToKey(ReferenceKeyString, ReferenceKeyObj)
    ReturnObj = RepadPartDocument.ReferenceKeyManager.BindKeyToObject(ReferenceKeyObj, KeyContextObj, MatchType)

    If TypeOf ReturnObj Is Inventor.Face Then
          FaceObject = CType(ReturnObj, Inventor.Face)
          FacesToDelete.Add(FaceObject)
    End If
Next

 

The problem occurs when I use the BindKeyToObject method. MatchType returns a value of 2 which means there are distinctly many, equally good solutions. I cannot determine what type ReturnObj is other than it has a count of 2 so I guess it is an array or a collection of some sort. That makes no sense to me since I thought a reference key was unique to a particular entity.

 

I sure could use some help here as I have spent a bunch of hours basically banging my head on my desk. Please school me on the proper use of reference keys and/or suggest a better way of keeping track of the faces I need to keep and delete.

 

Thanks in advance,

 

Darren Haverstick

Paul Mueller Company

 

 

8 REPLIES 8
Message 2 of 9
Ralf_Krieg
in reply to: dhaverstick

Hello

 

No, the BindKeyToObject method returns both faces as an ObjectCollection if the original one was splitted. If you split a face, which one should be the "old" and the "new" face?

Can you post a part with manual splits so we can see what you want to achieve? Maybe we find an alternative way.


R. Krieg
RKW Solutions GmbH
www.rkw-solutions.com
Message 3 of 9
dhaverstick
in reply to: dhaverstick

Thanks for the help! Attached is a part that represents what I am trying to do with code. Roll back to the first feature I create where two faces are created in the "HeadOuterSurface" revolve feature. Now skip down to the split feature named "RepadOuterEdgeSplit". There are four faces. I want to keep the faces that are blue and delete everything else. Here is the first place I tried to use reference keys to accomplish that task. Next we move to the split feature, "RepadInnerEdgeSplit". I have three faces now. Here I want to delete the black face and keep everything else. Finally, if you move to the end of the part, you are left with a ring that consists of two faces.

 

I've tried a bazillion different things to be able to automatically pick the faces to delete and none of them have worked in all cases.

 

Darren Haverstick

Paul Mueller Company

Message 4 of 9
Ralf_Krieg
in reply to: dhaverstick

Hello

 

I'm not sure but first simple tests seem to succeed. I assume the inner and outer profile could be in one sketch. Extrude the ring (between inner and outer profile) with SetToNextExtent to the HeadOuterSurface. All created faces who are planar (start face) or cylindrical (side faces) can be deleted with a DeleteFace feature. The result are the two faces of a solid.

I've attached a modified version (Iv2022).


R. Krieg
RKW Solutions GmbH
www.rkw-solutions.com
Message 5 of 9
dhaverstick
in reply to: Ralf_Krieg

I appreciate the help but I don't need the part. I can easily create that manually on my own. I need the code that will repeatedly create the part successfully. As I stated before, the trick is being able to correctly determine, with code, which faces to keep and which faces to discard using a method that will work every single time.

 

I thought I had it figured out by placing attribute sets on various edges and identifying faces that had edges with those attribute sets. That seemed to work until a few days ago when someone using my addin with this logic had the process fail. The reason for the failure was that the wrong faces were being identified so that set me back to square one.

 

So then I started looking at reference keys and what capabilities they would give me. I looked at all the examples I could find and tried to duplicate the behavior with very limited success. That led me to this post asking for help. 

 

I don't care what method I use to accomplish the task at hand, I just need it to be foolproof. The problem in a nutshell, is this: I have a face (Face1) that I create with code. I then split the face, with code, which now gives me two faces (Face1 and Face2). I need to be able to to determine with 100% accuracy which face is Face1 and which face is Face2 so that I can perform further actions on both of them.

 

Darren Haverstick

Paul Mueller Company

 

 

Message 6 of 9
dhaverstick
in reply to: dhaverstick

Woohoo! I found the solution!

 

It seemed like I was having no problem creating reference keys for the faces. The problem I had occurred when I retrieved the faces using the reference keys. I kept getting a "parameter incorrect" error. I will step through the process in hopes that it will help someone else out.

 

1) I generated reference keys for all the faces created from a Revolve feature. Here is that code.

Dim ContextData() As Byte
Dim ContextDataString As String
Dim FaceObject As Inventor.Face
Dim FacesToSplit As Inventor.ObjectCollection
Dim KeyContextObj As Long
Dim ReferenceKeyObj() As Byte
Dim ReferenceKeys As List(Of String)
Dim ReferenceKeyString As String

FacesToSplit = InventorApp.TransientObjects.CreateObjectCollection
ReferenceKeys = New List(Of String)
ReferenceKeyObj = New Byte() {}
ContextData = New Byte() {}
KeyContextObj = RepadPartDocument.ReferenceKeyManager.CreateKeyContext

For I = 1 To RepadComponentDefObject.WorkSurfaces.Item(1).SurfaceBodies.Item(1).Faces.Count
    FaceObject = RepadComponentDefObject.WorkSurfaces.Item(1).SurfaceBodies.Item(1).Faces.Item(I)
    FaceObject.GetReferenceKey(ReferenceKeyObj, KeyContextObj)
    ReferenceKeyString = RepadPartDocument.ReferenceKeyManager.KeyToString(ReferenceKeyObj)
    ReferenceKeys.Add(ReferenceKeyString)

    FacesToSplit.Add(FaceObject)
Next

RepadPartDocument.ReferenceKeyManager.SaveContextToArray(KeyContextObj, ContextData)
ContextDataString = RepadPartDocument.ReferenceKeyManager.KeyToString(ContextData)

Yes, I know that I probably don't need to create a key from the KeyContextObj object and the translate that key into a string. I did it because all the examples I could find showed doing that and I didn't have a chance to test the process without doing that.

 

2) Okay, so after I created reference keys for all the original faces, I performed a Split operation. Now I want to delete what's left of the original faces and only keep what was created by the Split.

 

3) To collect the faces I want to delete, I use the BindKeyToObject method to retrieve them. Here is where I was having issues. There is a parameter passed to the BindKeyToObject called MatchType which is typed as an Object. This should be set to Nothing EACH time you call BindKeyToObject. I wasn't doing that and that's why I was getting an error. Here is the working code.

Dim BoundObject As Object
Dim FacesToDelete As Inventor.FaceCollection
Dim MatchTypeObj As Object

FacesToDelete = InventorApp.TransientObjects.CreateFaceCollection
ReferenceKeyObj = New Byte() {}
ContextData = New Byte() {}
RepadPartDocument.ReferenceKeyManager.StringToKey(ContextDataString, ContextData)
KeyContextObj = RepadPartDocument.ReferenceKeyManager.LoadContextFromArray(ContextData)

For I = 0 To ReferenceKeys.Count - 1
    MatchTypeObj = Nothing 'this has to be set to nothing for each BindKeyToObject call
    ReferenceKeyString = ReferenceKeys.Item(I)
    RepadPartDocument.ReferenceKeyManager.StringToKey(ReferenceKeyString, ReferenceKeyObj)
    BoundObject = RepadPartDocument.ReferenceKeyManager.BindKeyToObject(ReferenceKeyObj, KeyContextObj, MatchTypeObj)

    'If one of the original faces is split, the reference key will identify both it and the new faces
    'made from the split. So an object collection is returned instead of just a face.
    'In this case, I assume that the face I need to delete is the first one in the collection
    If TypeOf BoundObject Is Inventor.ObjectCollection Then
         ReturnedObjCollection = CType(BoundObject, Inventor.ObjectCollection)
         FaceObject = ReturnedObjCollection.Item(1)
    Else
         FaceObject = CType(BoundObject, Inventor.Face)
    End If

    FacesToDelete.Add(FaceObject)
Next

Before I fixed it, I was setting MatchTypeObj to nothing outside of the loop that iterates through the saved reference keys. The procedure would work for the first iteration and always crash on the second one. That's because MatchTypeObj was no longer nothing. Once I moved that  declaration inside the For Loop, the problem was solved.

 

Anway...I have tested this code against a few different scenarios and it worked in all of them. Hopefully, it will continue to work.

 

Glad this is over!

 

Darren Haverstick

Paul Mueller Company

Message 7 of 9
Ralf_Krieg
in reply to: dhaverstick

Hello

 

Very happy to hear you got it. 🙂

 

The MatchType is a return value. Shouldn't make any difference if is set to nothing or not. My test code runs fine without set it to nothing. *???*

 

The API help says the first face in the returned object collection aka the PrimaryMatch is "Face with the earliest feature". Loving help no one understands. I thought splitting a face in two parts, both parts are from the same earlier feature face. So none of both is earlier than the other.


R. Krieg
RKW Solutions GmbH
www.rkw-solutions.com
Message 8 of 9
dhaverstick
in reply to: Ralf_Krieg

That is interesting that you don't have to set MatchType to nothing to get it to work. In my test case, I had two faces that I assigned reference keys to. When I went to retrieve them, I would loop through the list where I saved the keys. When I set MatchType to nothing outside of the loop, the retrieval would work for the first pass through the loop and always crash on the second pass because MatchType was no longer nothing. I would get the mysterious "invalid parameter" error. When I moved setting MatchType to nothing inside the loop, the problem went away.

 

I found another thread on this forum where a person had a similar problem and solved it by setting MatchType to nothing. Here is a FYI link. https://forums.autodesk.com/t5/inventor-ilogic-api-vba-forum/document-referencekeymanager-bindkeytoo... 

 

Darren

Message 9 of 9
dhaverstick
in reply to: dhaverstick

Well, I thought the solution I posted on 1/13/2022 was THE solution. It turns out to not be the case. Where is the problem? It takes place when I try to determine which faces to delete. If an ObjectCollection object is returned using the BindKeyToObject method, I assumed that the face I needed to delete would ALWAYS be the first one in the collection. That assumption works most of the time but is not a certainty. So I'm basically back to square one. What I did to get over this hurdle of making a selection is use the same code as above but added some lines where the areas of the faces returned in the ObjectCollection were compared. The face with the largest surface area was the one I chose to delete. This is a pretty safe bet for my case but it really bothers me that I cannot lock this selection thing down to ALWAYS work.

 

ReturnedObjCollection = CType(BoundObject, Inventor.ObjectCollection)
FaceObject = ReturnedObjCollection.Item(1)
Area1 = FaceObject.Evaluator.Area
FaceObject = ReturnedObjCollection.Item(2)
Area2 = FaceObject.Evaluator.Area

If Area1 > Area2 Then
   FaceObject = ReturnedObjCollection.Item(1)
Else
   FaceObject = ReturnedObjCollection.Item(2)
End If

 

Darren

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Technology Administrators


Autodesk Design & Make Report