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: 

Can I get the value of an attribute from Attribute Manager?

12 REPLIES 12
SOLVED
Reply
Message 1 of 13
dustinbagley
780 Views, 12 Replies

Can I get the value of an attribute from Attribute Manager?

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?

12 REPLIES 12
Message 2 of 13
WCrihfield
in reply to: dustinbagley

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

EESignature

(Not an Autodesk Employee)

Message 3 of 13

Hi @dustinbagley 

 

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")

 

Message 4 of 13
dustinbagley
in reply to: WCrihfield

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 

 

dustinbagley_0-1687794013882.png

 

Message 5 of 13

This looks like what I need. I will be giving it a try. thanks

Message 6 of 13
WCrihfield
in reply to: dustinbagley

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

EESignature

(Not an Autodesk Employee)

Message 7 of 13
dustinbagley
in reply to: dustinbagley

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.

dustinbagley_0-1687796484204.png

At the moment, it is only looping through the _DocumentClass Attributes. Is because I have set oDef to the active assembly document?

dustinbagley_1-1687796746088.png

 

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

Message 8 of 13

Hi @dustinbagley 

 

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:

https://forums.autodesk.com/t5/inventor-ilogic-and-vb-net-forum/align-cam-connector-in-hole-facing-t...

 

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

 

 

 

 

Message 9 of 13
dustinbagley
in reply to: WCrihfield

@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

Message 10 of 13
WCrihfield
in reply to: dustinbagley

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

EESignature

(Not an Autodesk Employee)

Message 11 of 13
dustinbagley
in reply to: WCrihfield

@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

dustinbagley_0-1687816481502.png

All of the proxy values are strings, so I'm not sure why they aren't being picked up by the second function.

dustinbagley_1-1687816760340.png

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

Message 12 of 13
dustinbagley
in reply to: dustinbagley

@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

Message 13 of 13
WCrihfield
in reply to: dustinbagley

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

EESignature

(Not an Autodesk Employee)

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

Post to forums  

Technology Administrators


Autodesk Design & Make Report