I use Nifty Attributes to assign attributes to various edges and faces for the purpose of automating drawing dimensions. I would like to be able to get the names (values) of each of these attributes in a part or assembly to make writing up the dimension creation rule for a drawing a little less tedious. Of course I can find all of these attributes and add them to a collection as objects, but is there a way to get the value of each attribute?
Solved! Go to Solution.
Solved by WCrihfield. Go to Solution.
Hi @dustinbagley. Your post is a little confusing, so I am not sure how to respond or answer your questions. You say that you are already pretty familiar with Attributes, and know how to find them, but then you say that you do not know how to get their values. Since this seems a bit too simplistic, it is most likely not what you were looking for, but the Attribute API object has a property called Value where you would get its value, and a ValueType property, which will tell you what data type it holds. If this is not what you were looking for, please explain in more precise terms what you are expecting as a solution here.
Are you trying to use the iLogic snippets for adding drawing dimension, or are you using mostly Inventor API objects & methods? If you are using the iLogic snippets, then some of what you can do with the Nifty Attributes AddIn may not be usable by those snippets. There is a naming system that is unique to the iLogic ApplicationAddIn, called NamedEntities, and that system works together with the ability you have through the native user interface within a part type document, to select a vertex, edge, or face, then right-click, and select 'Assign Name' from that right-click menu. In that system, a very specifically named AttributeSet is created for you on that object, and a very specifically named Attribute object is created within that AttributeSet for you, then the ValueType is set to String, and the name you type in is set as the Value of that Attribute. If that exact same naming system is not used when assigning names to entities with the Nifty Attributes tool, then those iLogic snippets will not recognize those entity names. And if you have been using other naming systems, you will most likely have to use the longer process through the regular API code. In the API system you would provide those named objects themselves, not just the names that have been assigned to them, when creating the dimensions. That would be where the AttributeManager system would need to come into play.
Wesley Crihfield
(Not an Autodesk Employee)
I had this drawing example on hand, from something I did in the past.
It will create a custom attribute set and then create a new attribute, and then set the value with a time stamp. It will then display the value in a message box. If you run it again, it will show the old value and the new value in the message box.
To see how it works, just create a new drawing and add a title block called "Title Block Small" to it, then add the rule and run it.
I hope this helps.
Best of luck to you in all of your Inventor pursuits,
Curtis
http://inventortrenches.blogspot.com
oDoc = ThisDoc.Document sTBname = "Title Block Small" Try oDef = oDoc.TitleBlockDefinitions.Item(sTBname) Catch MsgBox("no title block definition called '" & sTBname & "' found", , "iLogic") Exit Sub End Try Dim oAttribSets As AttributeSets oAttribSets = oDef.AttributeSets Dim oAttribSet As AttributeSet Try oAttribSet = oAttribSets.Add("TitleBlock_AttributeSet") Catch oAttribSet = oAttribSets.Item("TitleBlock_AttributeSet") End Try For Each oAttribSet In oAttribSets Logger.Info(oAttribSet.Name) Next oTimeStamp = DateString & "_" & TimeString Dim oAttrib As Inventor.Attribute Try oAttribSet.Add("Unique_ID", kStringType, oTimeStamp) Catch oAttrib = oAttribSet.Item("Unique_ID") oExisting = oAttrib.Value End Try oAttrib = oAttribSet.Item("Unique_ID") oAttrib.Value = oTimeStamp Logger.Info(oAttribSet.Count) Logger.Info("Existing: " & oExisting) Logger.Info("New value: " & oAttrib.Value) oMsg = "The title block in this drawing will be time stamped with an attribute called: " & vbLf & _ oAttrib.Name & " , and it has been set to: " & oAttrib.Value & vbLf & _ vbLf & "The previous " & oAttrib.Name & " value was: " & oExisting MessageBox.Show(oMsg, "iLogic")
Thanks for responding. I will try to be more clear than I was initially. In my particular situation, I will be creating a large amount of automated drawings and I am just looking for was to simplifying the processes of automating each one of them. For the dimension automation, I would like to be able to run a rule that looks though the assembly and prints all of the found attributes in the form of a geometry intent into a drawing rule, giving me something to start from that I could then create dimensions with. I thought that I might be able to do this with the FindObjects method of AttributeManager. However, it seems to be the case that the result of this method is a collection of objects that do not retain the 'AttributeValue.' In my case, this would be a string and it is what I need to generate the intent lines in my drawing rules. If there is a way that I can collect these AttributeValues from an assembly, it would be the key to what I am trying to do here. If not, I am considering creating a list of possible names I would use for AttributeValues like so:
Dim Name As String Dim NameArrayList As New ArrayList Dim NameComp1 As String Dim NameCompArrayList1 As New ArrayList Dim NameComp2 As String Dim NameCompArrayList2 As New ArrayList Dim NameComp3 As String Dim NameCompArrayList3 As New ArrayList Dim NameComp4 As String Dim NameCompArrayList4 As New ArrayList 'Location 2 NameCompArrayList1.Add("Upper") NameCompArrayList1.Add("Lower") NameCompArrayList1.Add("Left") NameCompArrayList1.Add("Right") NameCompArrayList1.Add("Top") NameCompArrayList1.Add("Bottom") NameCompArrayList1.Add("Front") NameCompArrayList1.Add("Back") 'Type NameCompArrayList2.Add("Mount") NameCompArrayList2.Add("Plate") NameCompArrayList2.Add("Hole") NameCompArrayList2.Add("Slot") NameCompArrayList2.Add("Angle") NameCompArrayList2.Add("Elbow") NameCompArrayList2.Add("Pipe") NameCompArrayList2.Add("Frame") 'Location 2 NameCompArrayList3.Add("Edge") NameCompArrayList3.Add("Corner") NameCompArrayList3.Add("Point") NameCompArrayList3.Add("Start") NameCompArrayList3.Add("End") NameCompArrayList3.Add("Upper") NameCompArrayList3.Add("Lower") 'Numeric NameCompArrayList4.Add("") NameCompArrayList4.Add("1") NameCompArrayList4.Add("2") NameCompArrayList4.Add("3") NameCompArrayList4.Add("4") NameCompArrayList4.Add("5") NameCompArrayList4.Add("6") NameCompArrayList4.Add("7") NameCompArrayList4.Add("8") NameCompArrayList4.Add("9") NameCompArrayList4.Add("10") For Each NameComp1 In NameCompArrayList1 For Each NameComp2 In NameCompArrayList2 For Each NameComp3 In NameCompArrayList3 For Each NameComp4 In NameCompArrayList4 Name = NameComp1 & NameComp2 & NameComp3 & NameComp4 NameArrayList.Add(Name) Name = "" Next Next Next Next
and then loop through each of them individually to see if I get a hit:
Dim objs As ObjectCollection Dim obj As Object For Each Name In NameArrayList Try objs = oAssemblyDoc.AttributeManager.FindObjects("iLogicEntityNameSet", "iLogicProxyEntityNameSet", Name) 'msgbox(Name) Catch End Try Next 'MsgBox(objs.Count) Exit Sub
Hopefully I explained myself more clearly and I would be glad to hear any of your thoughts or suggestions. Thanks,
Dustin
OK. I assume then that you are only working with top level context attributes of the main assembly then, and not every level of the assembly, because if your assembly is large, that could be a real rats nest of attributes, and there may be a great many duplicates that would be difficult to tell apart. Each Document object keeps track of its own AttributeSets, and does not know about the AttributeSets of other documents. So, if you had multiple components in your assembly that refer to the same base model document, it would be difficult to tell which specific component the identical attributes were associated with in a large collection. I generally like to use variable types like the Dictionary for projects like this. There are several types like this, but they can contain a list of 'entries' which can each contain a 'Key', and a 'Value'. That way you can keep them associated with each other. The main rule about them though, is that the 'Keys' must be unique (no 2 keys can be identical).
About how to get the attribute value from those objects:
Each 'object' you retrieve using that tool will have an 'AttributeSets' property (Intellisense won't suggest this though) that you can set to an AttributeSets type variable. Then you likely know how to get to the Attribute, and its Value from there.
Wesley Crihfield
(Not an Autodesk Employee)
This is getting me very close. I am running a version of your code from an assembly:
oDoc = ThisDoc.Document Try oDef = oDoc Catch MsgBox("no title block definition called '" & sTBname & "' found", , "iLogic") Exit Sub End Try Dim oAttribSets As AttributeSets oAttribSets = oDef.AttributeSets Dim oAttribSet As AttributeSet Try oAttribSet = oAttribSets.Add("iLogicEntityNameSet") Catch oAttribSet = oAttribSets.Item("iLogicEntityNameSet") End Try Dim oAttrib As Inventor.Attribute For Each oAttribSet In oAttribSets Logger.Info(oAttribSet.Name) For Each oAttrib In oAttribSet Try MsgBox(oAttribSet.Name & vbNewLine & oAttrib.Name & vbNewLine & oAttrib.Value) Catch end try Next Next Exit Sub
It is almost getting me the information I need.
At the moment, it is only looping through the _DocumentClass Attributes. Is because I have set oDef to the active assembly document?
If you could help me know what to set it to so that is can loop through the rest of the attributes (EdgeProxies, SketchPointProxies, etc.). I would greatly appreciate it. Thanks,
Dustin
My apologies, I think in my haste, I might have taken you in the wrong direction with that example.
I think @WCrihfield was on the right track with GetNamedEntities
See this link for a working example:
And specifically the zip file at that link:
Cam Connector and Pin 2022.zip
Within the assembly in that zip file is a rule that contains this line:
Dim oNamedEntities = iLogicAuto.GetNamedEntities(oFirstComponent.Definition.Document)
I think if you look at that example, you will see how to get where you are going.
Note that example is actually creating some of the named entities on the fly, which is a bit more involved than what you are wanting to do, but it is also looking for and using existing named entities which is more in line with what you are after.
I think it will make sense once you look at the code. If not post back and I'll try to have a closer look.
I hope this helps.
Best of luck to you in all of your Inventor pursuits,
Curtis
http://inventortrenches.blogspot.com
@WCrihfield Thanks for your help.
However, I'm not quite there yet though. I'm still new at this and I do lean on intellesense and API Help quite a bit. I think you were saying that with the right syntax, I could access the attributes of each collected object. Below is my best guess:
Dim oAssemblyDoc As AssemblyDocument = ThisApplication.ActiveDocument Dim objs As ObjectCollection = oAssemblyDoc.AttributeManager.FindObjects("iLogicEntityNameSet", "iLogicProxyEntityNameSet") Dim obj As Object For Each obj In objs MsgBox(obj.AttributeSets.AttributeSet.Value) Next
Can you help me with the syntax for getting to the value of the attribute of the object? Thanks,
Dustin
Hi @dustinbagley. It may not be as simple as one line of code to get from the returned generic object to the value of its attribute. I just threw together something for you to look at and try out as an iLogic rule. I used two custom Functions to help handle some of the details, and keep the 'main' part of the code as short and simple as possible. I am not even specifying the AttributeSet name or the Attribute name in this code, because those can tend to vary when not using the build-in NamedEntities system. I did add an object type filter in there, to avoid all of the iLogic rules, iLogic forms, and other specs that may be present in the document, and are utilizing the attribute system. The first custom function uses that AttributeManager.FindObjects method, then attempts to filter out the unwanted stuff, while collecting the useful stuff into a nice Dictionary type variable, to keep the named entity together with the name assigned to it, in a collection. Then that first custom function calls the second custom function to help with extracting that one String type Attribute from the 'entity'. This is not a 100% fool proof code, but should work OK in most fairly simple scenarios. The end result right now, is just to show you a message about each named 'entity' it found, by telling you what type of object it is, and what name was assigned to it, just as proof of it finding them OK. If that works, we can do something else with those entities in that Dictionary besides just looping through them with a message.
Sub Main
Dim oDoc As Document = ThisDoc.Document
Dim oDict As Dictionary(Of Object, String) = GetAttributedObjects(oDoc)
If oDict Is Nothing OrElse oDict.Count = 0 Then Exit Sub
For Each oEntry As KeyValuePair(Of Object, String) In oDict
Dim oEntity As Object = oEntry.Key
Dim sName As String = oEntry.Value
Dim sEntityType As String = TypeName(oEntity)
MsgBox("Entity Type = " & sEntityType & vbCrLf & _
"Entity Name = " & sName, vbInformation, "Named Entity Info")
Next
End Sub
Function GetAttributedObjects(oDoc As Document) As Dictionary(Of Object, String)
If oDoc Is Nothing Then Return Nothing
Dim oFoundObjs As ObjectCollection = oDoc.AttributeManager.FindObjects()
If oFoundObjs Is Nothing OrElse oFoundObjs.Count = 0 Then Return Nothing
Dim oDict As New Dictionary(Of Object, String)
For Each oObj In oFoundObjs
Select Case TypeName(oObj)
Case "Face", "FaceProxy", "Edge", "EdgeProxy", "Vertex", "VertexProxy"
Dim oAtt As Inventor.Attribute = GetFirstStringTypeAttribute(oObj) 'runs the other custom function
If oAtt Is Nothing Then Continue For
oDict.Add(oObj, oAtt.Value.ToString)
Case Else
'what to do about other types of entities you may be expecting
End Select
Next 'oObj
Return oDict
End Function
Function GetFirstStringTypeAttribute(oObject As Object) As Inventor.Attribute
If oObject Is Nothing Then Return Nothing
Dim oSets As Inventor.AttributeSets = Nothing
Try : oSets = oObject.AttributeSets : Catch : End Try
If oSets Is Nothing OrElse oSets.Count = 0 Then Return Nothing
For Each oSet As Inventor.AttributeSet In oSets
If oSet.Count = 0 Then Continue For
For Each oAtt As Inventor.Attribute In oSet
If oAtt.ValueType = ValueTypeEnum.kStringType Then Return oAtt
Next 'oAtt
Next 'oSet
Return Nothing
End Function
I'm leaving for the day after posting this, so I'll check back tomorrow.
Wesley Crihfield
(Not an Autodesk Employee)
@WCrihfield I very much appreciate your help. I did not however have much luck with the code you wrote. I did a little investigation so see exactly what it was doing in my assembly. Below is your code with some note from myself:
Sub Main Dim oDoc As Document = ThisDoc.Document Dim oDict As Dictionary(Of Object, String) = GetAttributedObjects(oDoc) '-------In my assembly, this returns 0 MsgBox(oDict.Count & " " & "items in dictionary.") If oDict Is Nothing OrElse oDict.Count = 0 Then Exit Sub For Each oEntry As KeyValuePair(Of Object, String) In oDict Dim oEntity As Object = oEntry.Key Dim sName As String = oEntry.Value Dim sEntityType As String = TypeName(oEntity) MsgBox("Entity Type = " & sEntityType & vbCrLf & _ "Entity Name = " & sName, vbInformation, "Named Entity Info") Next End Sub Function GetAttributedObjects(oDoc As Document) As Dictionary(Of Object, String) If oDoc Is Nothing Then Return Nothing Dim oFoundObjs As ObjectCollection = oDoc.AttributeManager.FindObjects() If oFoundObjs Is Nothing OrElse oFoundObjs.Count = 0 Then Return Nothing Dim oDict As New Dictionary(Of Object, String)
'-------My assembly finds 9 objects MsgBox(oFoundObjs.Count & " " & "objects found.") For Each oObj In oFoundObjs '--------------In my assembly, oObj.TypeName errors on all objects Try MsgBox("TypeName " & oObj.TypeName) Catch MsgBox("String " & oObj.ToString) End Try Select Case TypeName(oObj) Case "Face", "FaceProxy", "Edge", "EdgeProxy", "Vertex", "VertexProxy" Dim oAtt As Inventor.Attribute = GetFirstStringTypeAttribute(oObj) 'runs the other custom function If oAtt Is Nothing Then Continue For oDict.Add(oObj, oAtt.Value.ToString) '-------------------------------In my assembly, this message is triggered 0 times MsgBox("Added object to dictionary") Case Else 'what to do about other types of entities you may be expecting End Select Next 'oObj Return oDict End Function Function GetFirstStringTypeAttribute(oObject As Object) As Inventor.Attribute '-------My assembly runs this function 9 times MsgBox("Running 'Get First...Function'") If oObj Is Nothing Then Return Nothing Dim oSets As Inventor.AttributeSets = Nothing Try : oSets = oObj.AttributeSets : Catch : End Try If oSets Is Nothing OrElse oSets.Count = 0 Then Return Nothing For Each oSet As Inventor.AttributeSet In oSets If oSet.Count = 0 Then Continue For For Each oAtt As Inventor.Attribute In oSet If oAtt.ValueType = ValueTypeEnum.kStringType Then Return oAtt '-------------------------------my assembly returns 0 attributes MsgBox("Returning oAtt") Next 'oAtt Next 'oSet Return Nothing End Function
The 9 objects that it finds seem to be _DocumentClass and the Proxies
All of the proxy values are strings, so I'm not sure why they aren't being picked up by the second function.
Also, as i have been typing this, I have found in my assembly that:
oObj Is Nothing nothing in the second function and so it returns nothing for the 9 objects.
Any thoughts? Again, thank you so much for your help,
Dustin
@WCrihfield After looking at your code again this morning, I got it to work. In the second function, there were some 'oObj's that just need to be updated to 'oObject' and now it is working. This is just what I needed. Thanks so much for your help.
Dustin
Good eye. I was just investigating that myself, and came to a similar conclusion, and was about to post an updated code with more feedback.
By the way, just so you know, in your previous responce's code, there is no such thing as oObj.TypeName. But there is usually an oObj.Type if the object is native to Inventor, and that will usually return a variation of the ObjectTypeEnum, which could then be converted to a String with oObj.Type.ToString. And oObj.ToString will often return something fairly meaningless too, but sometimes it will return something resembling what Type an object was. TypeName() is a simple function available within the vb.net system, and returns a String representing what Type of object variable you supplied within its (). The your last note within the last function was on the next line after the 'Return' keyword, which would have returned the Attribute object it found (if it found one), then it would have exited that Function, and would not reach that message. It would only reach that message durring itterations in which it did not find a String type Attribute. Then there was a second 'Return' line at the end of that Function, for when no String type Attribute was found within the input object, because it must encounter a 'Return' (followed by what to return) at some point in a proper Function.
I also went back and fixed that code in Message 10, so that others will be able to use it wouthout those errors.
Wesley Crihfield
(Not an Autodesk Employee)
Can't find what you're looking for? Ask the community or share your knowledge.