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: 

Connect displayname to filename and export iLogic

13 REPLIES 13
SOLVED
Reply
Message 1 of 14
nick5MWHR
412 Views, 13 Replies

Connect displayname to filename and export iLogic

Hi!

 

Does someone has an iLogic rule, to run through the whole assembly and connect all filenames of assemblies to corresponding displaynames and export this to excel?

 

Thanks,

 

Nick

13 REPLIES 13
Message 2 of 14
WCrihfield
in reply to: nick5MWHR

Hi @nick5MWHR.  Can you show an example of what the data within the resulting Excel file should look like, and how it should be laid out.  The Document.DisplayName property is Read/Write, so it can be changed.  It usually has a default value, based on document type, when the document is still new, and has not been saved yet, but then it usually defaults to the file name, after the document gets saved.  However, I have seen it sometimes include the file extension, and other times not include the file extension, so it can be slightly unpredictable.  Why do you need to write out a list of file names and display names?  Will this only include files that represent assemblies, or will it also include part files?

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

Message 3 of 14
nick5MWHR
in reply to: nick5MWHR

Hi Wesley,

 

Thanks for the reply.

 

I've included an image on what the output should look like. I know that the displayname can be changed.

 

Our idea is the following:

- AssemblyX is (for example) a conveyor, but at customerY the conveyor is conveyor1 but at CustomerZ the conveyor is conveyor10. Or maybe within one project we use the assembly multiple times and we want to rename these to Conveyor1, Conveyor2 etc, without changing the (internal) assembly-filename.

 

the file extension doesn't need to be included, we only want to recieve the assembly filename and the corresponding displayname, after that we can make the magic happen within excel.

 

Something import to notice, is that it needs to run also through all the subassemblies, and the subassemblies of these etc. All assemblies should be checked, also on deeper levels. Something nice to be added is how deep this assembly is, see also included image.

 

Nick

 

Message 4 of 14
WCrihfield
in reply to: nick5MWHR

There is still something confusing here.  You do not seem to be talking about the Document.DisplayName property here, because the same document can not have multiple values for that one property.  So, I assume you are talking about the name shown in the model browser tree of the main assembly.  Those names usually end with something like ":1", or ":2", and so on, unless renamed on purpose.  This is the value we get back from the ComponentOccurrence.Name property, not a property named DisplayName.  I also do not understand the level values.  Where would 1.2 or 1.4.1 come from.  It seems to me like it should just be Level 1, Level 2, Level 3, and so on, no partial levels.  All components found at top level of main assembly would be at Level 1.  Then all components found at second level down would be at Level 2, and so on.

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

Message 5 of 14
WCrihfield
in reply to: nick5MWHR

Hi @nick5MWHR.  Here is an iLogic rule example that does a task very similar to what you are asking for, but since I did not fully understand some of it, I can only hope this will get you most of the way to where you wanted to go.  Then maybe you can modify it further, as needed, to meet your needs more closely.

Sub Main
	Dim oADoc As AssemblyDocument = TryCast(ThisDoc.Document, Inventor.AssemblyDocument)
	If oADoc Is Nothing Then Logger.Debug(iLogicVb.RuleName & " exited (no AssemblyDocument obtained)") : Return
	Dim oADef As AssemblyComponentDefinition = oADoc.ComponentDefinition
	Dim oOccs As ComponentOccurrences = oADef.Occurrences
	oData = New List(Of List(Of String)) 'to initialize it
	RecurseComponents(oOccs, 1, AddressOf ProcessComponent)
	If oData.Count > 0 Then
		Dim sExcelFile As String = "C:\Temp\Assembly file & component names with levels.xlsx"
		Dim sSheet As String = "Sheet1"
		GoExcel.Open(sExcelFile, sSheet)
		GoExcel.DisplayAlerts = True
		Dim iFirstDataRow As Integer = 2
		Dim iRow As Integer = iFirstDataRow
		GoExcel.CellValue("A1") = "File Name"
		GoExcel.CellValue("B1") = "Component Name"
		GoExcel.CellValue("C1") = "Level"
		For i As Integer = 0 To oData.Count - 1
			Dim oDataEntry As List(Of String) = oData.Item(i)
			'Dim sFileName As String = oDataEntry.Item(0)
			'Dim sCompName As String = oDataEntry.Item(1)
			'Dim sLevel As String = oDataEntry.Item(2)
			GoExcel.CellValues("A" & iRow.ToString, "C" & iRow.ToString) = oDataEntry
			iRow = iRow + 1
		Next i
		GoExcel.Save
	End If
	'MsgBox("This rule's work has finished.",,"Job Is Done!")
End Sub

Dim iLevel As Integer
Dim oData As List(Of List(Of String))

Sub RecurseComponents(oComps As ComponentOccurrences, iLevel As Integer, ComponentProcess As Action(Of ComponentOccurrence, Integer))
	If oComps Is Nothing OrElse oComps.Count = 0 Then Return
	For Each oComp As ComponentOccurrence In oComps
		ComponentProcess(oComp, iLevel)
		If oComp.Suppressed = False AndAlso _
			oComp.DefinitionDocumentType = DocumentTypeEnum.kAssemblyDocumentObject Then
			RecurseComponents(oComp.SubOccurrences, iLevel + 1, ComponentProcess)
		End If
	Next oComp
End Sub

Sub ProcessComponent(oComp As ComponentOccurrence, iLevel As Integer)
	If oComp Is Nothing OrElse oComp.Suppressed Then Return
	If TypeOf oComp.Definition Is VirtualComponentDefinition Then Return
	If TypeOf oComp.Definition Is WeldsComponentDefinition Then Return
	Dim sOccName As String = oComp.Name
	Dim sFDN As String = oComp.ReferencedDocumentDescriptor.FullDocumentName
	Dim sFFN As String = ThisApplication.FileManager.GetFullFileName(sFDN)
	Dim sFileName As String = System.IO.Path.GetFileNameWithoutExtension(sFFN)
	Dim oDataEntry As New List(Of String) From {sFileName, sOccName, iLevel.ToString}
	oData.Add(oDataEntry)
End Sub

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 6 of 14
nick5MWHR
in reply to: WCrihfield

Hee Wesley

 

You are right. I mean the name shown in the model browser tree (ComponentOccurrence name)

as for the levels. The reason I indicate this in the way in my example is because it is also displayed this way in a BOM export if you select structured on all levels. This way we also know which sub-assemblies belong to which assembly.

If the order of the tree structure from the model browser does not change when running the rule, then the way you propose is also fine for me.

 

Nick

 

Message 7 of 14
nick5MWHR
in reply to: WCrihfield

Hi Wesley

 

Thank you very much for creating the iLogic rule.

I quickly checked whether the rule works.
There seems to be an error when opening Excel, but this is something we have done before, so we will figure it out later. I have other things to do first, but I will continue with this soon. I will keep you informed about the progress.

 

Nick

Message 8 of 14
WCrihfield
in reply to: nick5MWHR

Hi @nick5MWHR.  That earlier code example simply iterated down through all levels of assembly components, capturing component name, referenced document file name, and what primary level the component was on in the overall structure of the assembly.  However, since you seem to prefer how the structured BOM with all levels included does its Item Number values, I decided that we could do this process by iterating through the structured view of the BOM directly, then just use the Item Number property of the BOMRow for the 'level'.  So, below is a very similar code example that is recursively iterating through the rows in a BOM view, instead of recursively iterating through assembly components.

 

Just remember, down around Lines 19 & 20 is where the Excel file and sheet name are being specified, so you will most likely need to change those, as needed.  This code does not create a new Excel file...just opens one, then writes this data into it.  So, if that Excel file does not already exist, this will not work.  And if the Excel file does exist, make sure the sheet name is correct.  And, if the file and sheet names are OK, but the file already contained other, older data, this code will not clear that old data before it writes the new data into it.  If old data exists, it will be overwritten.  However if the old data had 400 lines of data, and the new data being written to it only has 200 lines of data, the result will be the first 200 lines being new data, but the other 200 below that still being old data.  Just something to keep in mind.  Using the iLogic GoExcel tools is a trade-off of (simplicity & ease of use) vs (more dynamic control).

Sub Main
	Dim oADoc As AssemblyDocument = TryCast(ThisDoc.Document, Inventor.AssemblyDocument)
	If oADoc Is Nothing Then Logger.Debug(iLogicVb.RuleName & " exited (no AssemblyDocument obtained)") : Return
	Dim oADef As AssemblyComponentDefinition = oADoc.ComponentDefinition
	Dim oBOM As Inventor.BOM = oADef.BOM
	oBOM.StructuredViewEnabled = True
	oBOM.StructuredViewFirstLevelOnly = False
	Dim oStrBOMView As BOMView = Nothing
	For Each oBOMView As BOMView In oBOM.BOMViews
		If oBOMView.ViewType = BOMViewTypeEnum.kStructuredBOMViewType Then
			oStrBOMView = oBOMView
			Exit For
		End If
	Next oBOMView
	If oStrBOMView Is Nothing Then Return
	oData = New List(Of List(Of String)) 'to initialize it
	RecurseBOMRows(oStrBOMView.BOMRows, AddressOf ProcessBOMRow)
	If oData.Count > 0 Then
		Dim sExcelFile As String = "C:\Temp\Assembly file & component names with levels.xlsx"
		Dim sSheet As String = "Sheet1"
		GoExcel.Open(sExcelFile, sSheet)
		GoExcel.DisplayAlerts = True
		Dim iFirstDataRow As Integer = 2
		Dim iRow As Integer = iFirstDataRow
		GoExcel.CellValue("A1") = "File Name"
		GoExcel.CellValue("B1") = "Component Name"
		GoExcel.CellValue("C1") = "Level"
		For i As Integer = 0 To oData.Count - 1
			Dim oDataEntry As List(Of String) = oData.Item(i)
			'Dim sFileName As String = oDataEntry.Item(0)
			'Dim sCompName As String = oDataEntry.Item(1)
			'Dim sLevel As String = oDataEntry.Item(2)
			GoExcel.CellValues("A" & iRow.ToString, "C" & iRow.ToString) = oDataEntry
			iRow = iRow + 1
		Next i
		GoExcel.Save
	End If
	'MsgBox("This rule's work has finished.",,"Job Is Done!")
End Sub

Dim oData As List(Of List(Of String))

Sub RecurseBOMRows(oBOMRows As BOMRowsEnumerator, BOMRowProcess As Action(Of Inventor.BOMRow))
	If oBOMRows Is Nothing OrElse oBOMRows.Count = 0 Then Return
	For Each oBOMRow As Inventor.BOMRow In oBOMRows
		BOMRowProcess(oBOMRow)
		If oBOMRow.ChildRows IsNot Nothing AndAlso oBOMRow.ChildRows.Count > 0 Then
			RecurseBOMRows(oBOMRow.ChildRows, BOMRowProcess)
		End If
	Next oBOMRow
End Sub

Sub ProcessBOMRow(oBOMRow As Inventor.BOMRow)
	If oBOMRow Is Nothing Then Return
	Dim oCD As Inventor.ComponentDefinition = Nothing
	Dim oRowDoc As Inventor.Document = Nothing
	Dim oOcc As ComponentOccurrence = Nothing
	Try : oCD = oBOMRow.ComponentDefinitions.Item(1) : Catch : End Try
	Try : oRowDoc = oCD.Document : Catch : End Try
	Try : oOcc = oBOMRow.ComponentOccurrences.Item(1) : Catch : End Try
	If (oCD Is Nothing) OrElse (oRowDoc Is Nothing) OrElse (oOcc Is Nothing) Then Return
	Dim sFileName As String = System.IO.Path.GetFileNameWithoutExtension(oRowDoc.FullFileName)
	Dim sOccName As String = oOcc.Name
	Dim sLevel As String = oBOMRow.ItemNumber
	Dim oDataEntry As New List(Of String) From {sFileName, sOccName, sLevel}
	oData.Add(oDataEntry)
End Sub

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 9 of 14
nick5MWHR
in reply to: nick5MWHR

Hi,

 

Sorry for the late response, but we tested the code today and it works, however, we’ve got a few questions.

  1. Say we have an assembly named assembly100:1 and assembly100:2 and we changed these names to conveyor1 and conveyor2, only conveyor 1 will be in the excel file.
    1. In the previous post of you, the file names and component shows all assemblies, that is exactly what we want, only we want the level to be 1.1 etc. (which is great about your later post).
  2. Is it possible to also include all parts which have a NON empty IO name (custom iProperty)?
    1. Preferably also attached to the BOM level as above.
  3. If they do have a non empty IO property, also include in the excel the custom iProperty Fabrication Number.
    1. We want to add more properties, but if we have the code we can probably add all the remaining properties ourselves.

 

Thanks again!

 

Nick

Message 10 of 14
nick5MWHR
in reply to: WCrihfield

Hi @WCrihfield , 

 

Again thanks for your reply!

 

We have modified your code to better fit our application. And now we can get most of the data we need, so that is great! Unfortunately we can’t quite get the level functionality to work as we need it. Currently we can get the level of the component in relation to the main assembly. However, we also need to get the level of the component in relation to the sub-assembly. So for example, if we have a main assembly that has a few assemblies, which also have assemblies we would need to get the level as follows: (assembly – level)

Main assembly – 0

            Sub assembly – 0.1

                        Sub-Sub Assembly – 0.1.1

            Sub assembly – 0.2

                        Sub-Sub Assembly – 0.2.1

                                    Part 1 – 0.2.1.1

                                    Part 2 – 0.2.1.2

            Sub Assembly – 0.3

            Etc.

(The . seperator is not strictly neccesary, a string of int as follows is also fine (0211). )

The code from your last post does work for this, however it only works once per unique part/assembly. In our case assemblies and parts can be used more then once.

I have attached the results from the excel sheet as they are now, and have added the requested syntax behind it. If you could help us that would be great!

 

Thanks in advance for your time and expertise!

Message 11 of 14
WCrihfield
in reply to: nick5MWHR

Hi @nick5MWHR.  You said that you modified to the code I posted to better suit your needs, but then it sounds like you are requesting that I modify the code some more to fix the level specification data.  Could you maybe post the modified version of the code you have here, either as a text file, or within a code window, so that if I do post an updated code example, it will already have your modifications in it.  I am not super sure how that level spec would be helpful, because how would you know which number in the sequence represents which sub assembly, when there are 4 or 5 digits in the sequence.  This is just a thought, but maybe a comma separated String which includes either the file names (from main to current) or component names (from top level to current) would be more helpful and informational in letting you know precisely what the assembly structure above a component is, and which sub assemblies are involved in it.  We can get this information much easier also, because there is actually a property for it (ComponentOccurrence.OccurrencePath).  That property of the component will return a ComponentOccurrencesEnumerator type collection which contains every ComponentOccurrence object in this component's path, starting from the top level component, and including the current component, in order.  That collection could be iterated through, in order, and the component names (or referenced file names) could be recorded into either a comma separated String, or an Array of Strings, whichever would work better later.  If simply iterating components recursively with a Sub routine, I can not think of a good way (right now) to keep track of the levels numerically in the custom way you are wanting.  Maybe if each component had an 'Attribute' or 'instance property' where this numerical value was assigned in a way that each one was unique per level, or something like that, but that would involve a whole extra level of preparations ahead of time, and complication.

 

Below are 2 example iLogic rules to test this property.

Dim oPickedOcc As ComponentOccurrence = ThisApplication.CommandManager.Pick(SelectionFilterEnum.kAssemblyLeafOccurrenceFilter, "Select a Component.")
If oPickedOcc Is Nothing Then Return
Dim oOccPath As ComponentOccurrencesEnumerator = oPickedOcc.OccurrencePath
If oOccPath IsNot Nothing AndAlso oOccPath.Count > 0 Then
	For i As Integer = 1 To oOccPath.Count
		Logger.Info(oOccPath.Item(i).Name)
	Next i
End If

...or like this, where a custom Function is used to convert the 'path' into an Array of Strings.

Sub Main
	Dim oPickedOcc As ComponentOccurrence = ThisApplication.CommandManager.Pick(SelectionFilterEnum.kAssemblyLeafOccurrenceFilter, "Select a Component.")
	If oPickedOcc Is Nothing Then Return
	Dim oOccPath() As String = GetComponentPath(oPickedOcc)
	If oOccPath IsNot Nothing AndAlso oOccPath.Length > 0 Then
		For i As Integer = LBound(oOccPath) To UBound(oOccPath)
			Logger.Info(oOccPath(i))
		Next i
	End If
End Sub

Function GetComponentPath(oOcc As ComponentOccurrence) As String()
	If oOcc Is Nothing Then Return Nothing
	Dim oOccPathOccs As ComponentOccurrencesEnumerator = oOcc.OccurrencePath
	Dim oOccPath(oOccPathOccs.Count - 1) As String
	For i As Integer = 1 To oOccPathOccs.Count
		oOccPath(i-1) = oOccPathOccs.Item(i).Name
	Next
	Return oOccPath
End Function

 

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

Message 12 of 14
nick5MWHR
in reply to: WCrihfield

Hi @WCrihfield , thank you for your quick reply!

You are correct in assuming that the component names would be more helpful than the numbers as we had previously suggested. I just tested both your examples and the latest of the 2 is exactly what we need. I just copied them to a string with a “ - ” as separator. A comma would also be fine.

I tried to incorporate the function in our current code, but I cannot seem get it to work for all components. Could you perhaps help us integrate this function in the code? It would be much appreciated!! I have attached the code that we currently have below. I had added more filters yesterday, but with the assembly’s I am currently using, they are not of use so I left those out.

Thanks in advance!

 

Message 13 of 14
nick5MWHR
in reply to: nick5MWHR

Hi @WCrihfield , thank you so much for you helped, I've managed to make it work, thanks to you!

I added the following code to make add a seperate sign, which I'll later use in excel to seperate the names. I've added multiple functions to the code, but I'm getting stuck at a certain part... Maybe you could take a look at my new post?

 

https://forums.autodesk.com/t5/inventor-programming-ilogic/identify-constraints-on-a-particular-part...

 

 

 

If oOccPath IsNot Nothing AndAlso oOccPath.Length > 0 Then
		For i As Integer = LBound(oOccPath) To UBound(oOccPath)
			'Logger.Info(oOccPath(i))
			
			If i >= 1 Then
			sOccPath = sOccPath & ";" & (oOccPath(i)) 
			Else
			sOccPath = sOccPath & (oOccPath(i))
		End If
			
			'MsgBox(oOccPath(i).ToString)
		Next i	
	End If

 

 

 

Message 14 of 14
WCrihfield
in reply to: nick5MWHR

Hi @nick5MWHR.  Looks like I'm a little late responding here.  I was away on vacation most of last week, and just got back to work yesterday.  I'm only active on here while at work, so sometimes I get too many things going on in my head at the same time, and forget about one (or more) forum topics that I had previously been involved with in the forums.  Anyways, here is a slightly edited version of that last block of code.  The extra set of () characters around oOccPath(i) was not necessary, and checking the Index number did not seem like the most intuitive way to check for first entry, so this example just checks if the variable's value is an 'empty' String, and if so, just sets its value to the current component's name.  I added the variable declaration in there, just for clarity, and to help it not throw errors while I was editing it.

Dim sOccPath As String = ""
If oOccPath IsNot Nothing AndAlso oOccPath.Length > 0 Then
	For i As Integer = LBound(oOccPath) To UBound(oOccPath)
		If sOccPath = "" Then
			sOccPath = oOccPath(i)
		Else
			sOccPath = sOccPath & ";" & oOccPath(i)
		End If
	Next i
End If

 

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