AssemblyContraints.AddFlushContraint problem

AssemblyContraints.AddFlushContraint problem

tonipalhadaco
Explorer Explorer
678 Views
9 Replies
Message 1 of 10

AssemblyContraints.AddFlushContraint problem

tonipalhadaco
Explorer
Explorer

Hello,

 

I appologize in advance for the extension of this post, the many questions asked and the frustration that may be implicitely expressed in this post.

I am working with the Inventor API, creating an Addin for Inventor, using VB.NET.
My goal is to use the method AddFlushContraint, to create a Flush Constraint in an Assembly. I want to do this automatically, without asking any input to the user during the process.

So step by step:

The idea is to mimic the iLogic command:

 

 

Dim Fluchtend_1 As FlushConstraint
Fluchtend_1 = Constraints.AddFlush(name_constraint,
				 component1, entity of component1, 
                                 component2, entity of component2, 
                                 offset).Constraint

 

 

I was previously working with iLogic Rules and this worked jut fine. Unfortunately, it seems to be impossible to use in VB.NET, since there is no equivalent comand for "ThisDoc" (it is only defined within the iLogic-addin), neither for iLogicVb.Automation. Therefore it is not only possible to use the Contraints.AddFlush method shown above. This has been corroborated in various articles and Forum publications that I've read, but if someone knows a way to work around this, it would be a direct solution to my problem.

 

So, I have tried to use the method Inventor.AssemblyContraints.AddFlushContraint. I find the documentation in Inventor 2018 Help | Autodesk pretty bad and incomplete, inclusively giving examples with methods that don't work anymore (is there any other source of documentation for the Inventor API?). Apparently, this method uses 3 inputs (and 2 more optional, that I won't use):

AssemblyConstraints.AddFlushConstraintEntityOne As Object, EntityTwo As Object, Offset As Variant, [BiasPointOne] As Variant, [BiasPointTwo] As Variant ) As FlushConstraint

EntityOne and EntityTwo can be of the type either a Workplane or a FaceProxy, for what I undestood. However, I am not able to access the entities (faces) that I want as Workplane or FaceProxy without further user input. When I was using the iLogic rules, I named the faces that I pretended to define contraints uppon, and I could directly access these entities, through the assigned names.

Even though I can access these entities through their names, in VB.NET, I can only assign them as Inventor.Face type (and neither as Inventor.Workplane or Inventor.FaceProxy). I've tried to use followig method, to convert Face into FaceProxy:

 

 

Dim oFaceProxy As FaceProxy = Nothing
oOcc.CreateGeometryProxy(oFace, oFaceProxy)

'The "oOcc" is the ComponentOccurrence, where the pretended entity is defined
'The "oFace" is the pretended entity, already correctly assigned as type Inventor.Face

 

 

 This was a method proposed in several Forum Publications (e.g. Solved: FaceProxy to Name - Autodesk Community - Inventor). However, it doesn't seem to work for me. In every post that I saw using this method, the "oFace" is assigned as follows:

 

 

Dim oFace As Face = ThisApplication.CommandManager.Pick(SelectionFilterEnum.kPartFaceFilter, "Select Face")

 

 

This is the type of additional user input that I am trying to avoid. And furthermore, even though it is declared of type Inventor.Face, it is actually directly assigned as Inventor.FaceProxy (so, I don't relly understand the usage of the "oOcc.CreateGeometryProxy" as conversion method, because, in reallity, oFace is already of type FaceProxy before this implementation. Every time I've tried to use this "type conversion" with a proper entity of type Inventor.Face, I get an error.). If someone finds me a proper way to convert an Object of type Inventor.Face in Inventor.FaceProxy, my problem would be, once again, solved. Other solution would be to find a method to get an Inventor.FaceProxy object, without using the CommandManager.Pick method above.

I've tried as well to use the following procedure, developed by @BrianEkins in VB.net Find Face by face name. - Autodesk Community - Inventor:

 

 

Public Sub GetNameTest()
    Dim doc As PartDocument = ThisApplication.ActiveDocument
    Dim faceOrEdge As Object = GetNamedEntity(doc, "Brian")
End Sub


Public Function GetNamedEntity(doc As Inventor.Document, name As String) As Object
    Dim attribMgr As AttributeManager = doc.AttributeManager
    Dim objsFound As ObjectCollection
    objsFound = attribMgr.FindObjects("iLogicEntityNameSet", "iLogicEntityName", name)
    
    If objsFound.Count > 0 Then
        Return(objsFound.Item(1))
    Else
        Return(Nothing)
    End If
End Function

 

 

However, once again, I am unable to assign the output Object of GetNamedEntities(...) as Inventor.WorkPlane or Inventor.FaceProxy.

 

The solution I found, for now, is to run an iLogic Rule (where I've implemented the Constraints.AddFlush method) from the Inventor API, but this is naturally not a good procedure. I am trying to develop a solution as independent from iLogic as possible.

 

Any help is very welcome. Thanks,
António Sanches

 

2 Extra questions:

I've been programing in VB.NET for a while now, and I'm constantly coming across complicated problems for very simple precodures. The documentation and support for VB.NET seems to be also very poor and out of date (because Microsoft is no longer developping VB.NET...). Should I start implementing my solutions in C#? Is troubleshooting easier in C# than in VB.NET?

Is there any way to define input for external iLogic rules (in iLogic, I used to use SharedVariable) from the Inventor API?

0 Likes
Accepted solutions (1)
679 Views
9 Replies
Replies (9)
Message 2 of 10

tonipalhadaco
Explorer
Explorer

If it helps, when I was using iLogic, I used to get the entities I wanted to use through:

oFace1 = iLogicVb.Automation.GetNamedEntities(ThisApplication.ActiveDocument).TryGetEntity("Top")

'Get the face with the name "Top" from the current PartDocument

 

0 Likes
Message 3 of 10

WCrihfield
Mentor
Mentor

Wow.  There is a ton of ground to cover here.  So my response may see a bit jumbled.  The process of assigning names to entities in the Part environment has been around for quite some time, but was advanced quite a bit in the 2019.1 release, with the addition of the NamedEntities Interface within the iLogic add-in, and the user interface tool being added, where you can right-click on geometry, then choose 'Assign Name...'from the right-click menu, then see those named entities listed in another 'tab' (DockableWindow) beside the Model, iLogic, iLogic Log, tabs.  Behind all of that, it is just using the AttributeSets.AttributeSet.Attribute system, which is present not only at Document level, but on almost any object in Inventor.  A very specific AttributeSet.Name and very specific Attribute.Name are used, just for that narrow set of functionality for that one Interface tool.  And that system is only used for Face, Edge, or Vertex items, not for any type of work feature, so it will never return a WorkPlane type object.  And since that system is also restricted to only working in the Part environment, it will never directly return an type of 'proxy', because it will never be in the context of an assembly.  Any geometry that is only present within an assembly due to a component being inserted into the assembly, will be a 'proxy', if selected within the context of the assembly, because it is not the original object, it is a copy of the original.

Proxies: (Link)

A proxy type object will only ever be found within the context of an assembly, never a part.  It is not exactly 'created' by that popular function (ComponentOccurrence.CreateGeometryProxy), but rather retrieves a reference to the 'virtual' copy of the input geometry, which is now in the 'context' of the parent assembly.  And this function only works for one (parent/child) step at a time.  So if the 'real' gometry is 3 levels down within sub assemblies, you will need to use that function at least 2 times to get the top level reference 'proxy' of that geometry.  I actually developed a custom recursive function once, just for retrieving the top level proxy object that is representing an input (regular/original/native) object.

Function GetTopLevelProxy(oInputObj As Object) As Object
	If IsNothing(oInputObj) Then Return Nothing
	If TypeName(oInputObj).EndsWith("Proxy") = False Then Return oInputObj
	Dim oParentOcc As ComponentOccurrence = oInputObj.ContainingOccurrence
	Dim oNextLevelUpProxy As Object = Nothing
	oParentOcc.CreateGeometryProxy(oInputObj, oNextLevelUpProxy)
	If oParentOcc.ParentOccurrence Is Nothing Then
		Return oNextLevelUpProxy
	Else
		GetTopLevelProxy(oNextLevelUpProxy)
	End If
End Function

If this solved your problem, or answered your question, please click ACCEPT SOLUTION .
Or, if this helped you, please click (LIKE or KUDOS) 👍.

 

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

Message 4 of 10

tonipalhadaco
Explorer
Explorer

@WCrihfield first of all, thanks for your response and for al the help.
I am already aware of everything you described. I am indeed working in an Assembly and I know that the information is all already there. My only problem is accessing it and assigning it to a variable I can work with.

In other words, my problem is not get the top level of a given Proxy object, but rather the other way around: get the proxy and assign it to a Variable.

Idealy it would be soemthing as simple as:

Dim myFaceProxy as FaceProxy = "some method to access the proxy of NamedEntity "Top" (Face), from ComponentOccurence (Part) "x" of my Assembly".

Again, without using the CommandManager.Pick method...

So that I can then use this "myFaceProxy" as an input for the AssemblyConstraints.AddFlushConstraint(...) method.

0 Likes
Message 5 of 10

WCrihfield
Mentor
Mentor
Accepted solution

OK.  So I guess my next question would be...is the original named face within a 'top level' part type component, or is it down within one or more levels of sub assemblies?  If this code will be for a VB.NET Add-In, then using the NamedEntites interface may be out of the question, but I'm not entirely sure about that either, because I know we can access and run iLogic rules from outside of the iLogic Add-In, by accessing the ApplicationAddIn Object representing the iLogic AddIn, then getting its Automation object, then using that object similarly to how you would normally use 'iLogicVb.Automation' within an iLogic rule.  But without using the NamedEntities interface, we would be looking at something similar looking to what you pointed out from Brian Ekins above, but perhaps developed a little further.  Then maybe we could change it to accept a ComponentOccurrence object, instead of a Document object, but I would not recommend that, because we really need the Document reference, and getting the right version of the Document reference from a ComponentOccurrence can get complicated in certain situations.  It would be better to extract the proper Document reference from 'parent' ComponentOccurrence ahead of time, then supply that to the method.  But after that step is taken care of, we would still need to deal with the situation of if the parent component is not a 'top level' component, which might require some 'recursive' processing, similar to the function I provided above.  Possibly as a separate method, instead of combined, to keep it clean.  So, if you used a function like his first, then used a function like mine above on the returned object, then you should be able to use the object returned by my function in your constraint creation method.

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

Message 6 of 10

tonipalhadaco
Explorer
Explorer

Thanks once again for the response.

 

Unfortunately, I am afraid nothing of that works as well... So, step by step:

1. Using the NamedEntities interface is indeed out of question I think: I've already got the Automation object:

 

m_Automation = InitializeAddIn()

Private Function InitializeAddIn() As Object
    Dim addIn As ApplicationAddIn
    For Each addIn In g_inventorApplication.ApplicationAddIns
        If addIn.ClassIdString = "{3BDD8D79-2179-4B11-8A5A-257B1C0263AC}" Then
            addIn.Activate()
            Return addIn.Automation
        End If
    Next
    Return Nothing
End Function

 

However, I don't seem to be able to use the same methods that I used with the iLogicVb.Automation. E.g., if I try to use the GetNamedEntities(...) method, I get the following error: "The public member GetNamedEntities for the type iLogicAutomation was not found." So I guess using the NamedEntities interface or any of the iLogicVb.Automation methods is out of question.

2. Then, the original named face is indeed within a 'Top Level' part type component, so let's focus on that, before digging into sub-assemblies.

Again, the function developed by @BrianEkins only allows me to get the Entity Object that I pretend as an object of type Face, and not as an object of type FaceProxy.

And once again, my goal is not to get parents of a given FaceProxy (like your function does). My goal is to get the FaceProxy Object.

3. To conclude, the solution could be, as you pointed out previously, in the AttributSets. But after some trials, I observed that there are no defined AttributeSets, either for the Assembly or for the Part (ComponentOccurrence) inside the Assembly. Both are empty. So, maybe it is also not possible to use AttributeSets, I don't know.

 

0 Likes
Message 7 of 10

WCrihfield
Mentor
Mentor

Hi @tonipalhadaco.  If you have assigned a name to a face in the part using the regular 'Assign Name' user interface tool, but you are not finding any AttributeSets or Attributes in the part with the specific names mentioned in the code above, then I don't know what to tell you.  That sounds like a problem for someone at Autodesk to deal with, because it is not normal behavior/functionality.  What version of Inventor are you using.  I hope you know that if you use something like Nifty Attributes or Attribute Helper to assign names to the entities, but did not follow the naming conventions of the NamedEntities interface, then you will not find them the usual ways.  You will have to provide the specific AttributeSet name and Attribute name you used when you assigned the names to those entities through that add-in.

Anyways, below is an iLogic/vb.net example with a custom Function in it for you to try out.

Sub Main
	If ThisApplication.ActiveDocumentType <> DocumentTypeEnum.kAssemblyDocumentObject Then
		MsgBox("An Assembly Document must be active for this rule to work. Exiting.", vbCritical, "")
		Exit Sub
	End If
	Dim oADoc As AssemblyDocument = ThisApplication.ActiveDocument
	Dim oADef As AssemblyComponentDefinition = oADoc.ComponentDefinition
	Dim oOccs As ComponentOccurrences = oADef.Occurrences
	Dim oOcc As ComponentOccurrence = oOccs.ItemByName("Part1:1")
	Dim oFaceProxy As FaceProxy = GetNamedEntityProxy(oOcc, "Face1")
	If Not IsNothing(oFaceProxy) Then
		'create your constraints with it
	End If
	
End Sub

Function GetNamedEntityProxy(oComp As ComponentOccurrence, oEntityName As String) As Object
	If IsNothing(oComp) Or oEntityName = "" Then Return Nothing
	If oComp.Suppressed Then Return Nothing 'or try to open its file by its referenced file name
	If TypeOf oComp.Definition Is VirtualComponentDefinition Then Return Nothing
	If oComp.DefinitionDocumentType <> DocumentTypeEnum.kPartDocumentObject Then Return Nothing
	Dim oOccPDoc As PartDocument = oComp.Definition.Document
	If oOccPDoc.ComponentDefinition.IsModelStateMember Then 'only works on 2022 or later
		oOccPDoc = oOccPDoc.ComponentDefinition.FactoryDocument 'only works on 2022 or later
	End If
	Dim oObjCol As ObjectCollection = oOccPDoc.AttributeManager.FindObjects("iLogicEntityNameSet", "iLogicEntityName", oEntityName)
	If oObjCol.Count = 0 Then Return Nothing
	Dim oObjProxy As Object = Nothing
	oComp.CreateGeometryProxy(oObjCol.Item(1), oObjProxy)
	Return oObjProxy
End Function

 

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

Message 8 of 10

tonipalhadaco
Explorer
Explorer

Hello @WCrihfield! Once again, thank you for the effort and help.

 

Unfortunately, the solution you offered doesn't work. You have just arriven at my main problem: the CreateGeometryProxy method doesn't really work (as I said in the original post). It allwas pops the following error: "False Parameter. (Exception from HRESULT: 0x80070057 (E_INVALIDARG))". In fact, this allways happens when the first argument of this method (in your case "oObjCol.Item(1)") is of type Face.

In other examples that I've seen, the CreateGeometryProxy method is allways used right after using the CommandManager.Pick method... well, in this case it works, because the output of this method is already of type FaceProxy (independently of the type that you declare the output variable as...). Give it a try: if you write, for example:

 

Dim facePicked As Face = ThisApplication.CommandManager.Pick(SelectionFilterEnum.kPartFaceFilter, "Select Face")
MsgBox(TypeName(facePicked))

Dim facePickedProxy As Object = Nothing
oComp.CreateGeometryProxy(facePicked, facePickedProxy)

 

you'll see that the Message Box pops out "FaceProxy", even though I have declared facePicked as of type Face...

So, in fact, the method CreateGeometryProxy is assigning the value of facePicked (As FaceProxy) to the variable facePickedProxy... which is a bit stupid, to be honest. You'd rather just do:

 

Dim facePickedProxy As FaceProxy = facePicked

 

 The result would be exactly the same. Give it a try.

So, to conclude, I don't really get the goal of the function CreategeometryProxy... I guess it was designed to convert an object of type Face into an object of type FaceProxy, but it doesn't really work... What a shame.

 

Anyway, I would appreciate @WCrihfield if you could try your implementation and see if it works (please just make sure that the first input variable for the method CreateGeometryProxy (in your case "oObjCol.Item(1)") is of the type Face), I would be very thankfull. Just to confirm that it is not a "me" problem.

0 Likes
Message 9 of 10

tonipalhadaco
Explorer
Explorer

Finally I was able to solve the problem! It turns out that I was not defining correctly the iLogic.Automation object. Now I can already use the GetNamedEntities(component).TryGetEntity(entity name) method. Even though the output of this method is of type Face, the method "component.CreateGeometryProxy(input entity, output entity)" seems to work just fine. From here, I can already use the "output entity" (of type FaceProxy) as an input for the AddFlushContraint(...) method.

 

Anyway, I leave here the 2 important remarks that I got out of this discussion:

1. The "component.CreateGeometryProxy(input entity, output entity)" doesn't seem to work if the "input entity" was got through the AttributeManager.FindObjects(...) method.

2. You don't need to use the CreateGeometryProxy method to get a FaceProxy object, if you got that entity with the method CommandManager.Pick(...). Even though you may declare the output variable as of type Face, it automatically converts it to type FaceProxy (as explained in my previous reply).

 

All in all, thank you very much @WCrihfield for all the help and good discussion. This was my first post in an Autodesk Forum and I find it really good that there is someone "on the other side of the screen" that I can discuss some topics with. I will accept the messages where you mention the NamedEntities as solution, because the solution was indeed in using the GetNamedEntities method.

0 Likes
Message 10 of 10

WCrihfield
Mentor
Mentor

Hi @tonipalhadaco.  I just got back to work today after a long vacation.  I have been away since my last post date, and am back today.  I am glad to hear that your code is finally working for you, and that I was able to help a bit.  Just wanted to add a couple more statements here, in an effort to help a little bit more, because the whole 'proxy' thing has always been a pretty confusing topic.

 

When you have a part actively open on your screen, and you manually select any face in your model by mouse, that will always be a regular Face type object, and never a FaceProxy type object.  But when you have any assembly actively open on your screen, and you manually select any face within that assembly by mouse, it will always already be a FaceProxy type object, and never a regular Face type object.  There is no way to directly convert a regular Face type object to a FaceProxy type object.  And there is no way to directly convert a FaceProxy type object to a Face type object.  All 'proxy' type objects (there are several types) are only naturally found within assemblies, and never directly within parts.  And since the NamedEntities interface only works within Parts, you will always get the regular Face (or Edge, or Vertex), and never a FaceProxy (or EdgeProxy, or VertexProxy) type objects returned directly from that interface.

 

Another thing that may help you understand the difference between the two types (Face & FaceProxy) a bit better, is knowing how they are defined.  In vb.net programming there are blocks of code called a Class.  This is something that developers use, similar to an order form for an object, that they want to use.  Within a Class, the developer dictates what 'Properties' and/or 'Methods' and/or 'Events' are available, either privately (for internal use) or publicly, for this object.  The Face type object, and the FaceProxy type object, are each defined by a Class block of code somewhere within Autodesks files.  The FaceProxy Class is actually 'derived' from the Face Class, which means that it inherits all the same Properties, Methods, & Events defined within the Face Class, then it has some of its own additional Properties, Methods, & Events.  Because of this 'derived' Class association, a FaceProxy type object will sometimes pass the test as being a Face, in certain tests, because its Class is derived from the Face Class.

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

0 Likes