Saving assembly and its parts with changed prefix

Saving assembly and its parts with changed prefix

m.rymut
Advocate Advocate
1,855 Views
10 Replies
Message 1 of 11

Saving assembly and its parts with changed prefix

m.rymut
Advocate
Advocate

Hi,

I need an ilogic rule that will let me save an assembly and its parts and subassemblies into designated folder, with a changed prefix.

So what the rule would do is save an assembly and its components with a changed prefix, and then replaced old components in a new assembly with new components with updated prefix.

So it would look like this:

Original assembly:

ER-1_1.1(A)_Main_assembly

ER-1_1.1(A)_Part_1

ER-1_1.1(A)_Part_2

ER-1_1.1(A)_Part_3

ER-1_1.1(A)_Subassembly

    ER-1_1.1(A)_Subassembly_Part1

 

And i would like to copy and replace with other prefix like this:

ER-2_2.2(B2)_Main_assembly

ER-2_2.2(B2)_Part_1

ER-2_2.2(B2)_Part_2

ER-2_2.2(B2)_Part_3

ER-2_2.2(B2)_Subassembly

    ER-2_2.2(B2)_Subassembly_Part1

 

I found this post with similiar rule that i need : 

https://forums.autodesk.com/t5/inventor-ilogic-and-vb-net-forum/save-and-replace-parts-in-an-assembl...

and it was solved by @WCrihfield

 

But naming in this rule is different,  here is the rule:

If ThisApplication.ActiveDocumentType <> DocumentTypeEnum.kAssemblyDocumentObject Then
	MsgBox("This rule '" & iLogicVb.RuleName & "' only works for Assembly Documents.",vbOK, "WRONG DOCUMENT TYPE")
	Return
End If

Dim oADoc As AssemblyDocument = ThisApplication.ActiveDocument

Dim oFileDlg As Inventor.FileDialog = Nothing
ThisApplication.CreateFileDialog(oFileDlg)
oFileDlg.Filter = "Autodesk Inventor Assembly Files (*.iam)|*.iam"
oFileDlg.InitialDirectory = ThisApplication.DesignProjectManager.ActiveDesignProject.WorkspacePath
oFileDlg.FileName = IO.Path.GetFileName(oADoc.FullFileName).TrimEnd("."c,"i"c,"a"c,"m"c)
oFileDlg.DialogTitle = "Specify New Name & Location For Copied Assembly"
oFileDlg.CancelError = True

On Error Resume Next
oFileDlg.ShowSave
If Err.Number <> 0 Then
	MsgBox("No File Saved.", vbOKOnly, "DIALOG CANCELED")
ElseIf oFileDlg.FileName <> "" Then
	oNewFileName = oFileDlg.FileName
	oADoc.SaveAs(oNewFileName, False)
End If

oADoc = Nothing

InventorVb.DocumentUpdate()

oADoc = ThisApplication.ActiveDocument

Dim oLast3Chars As String
For Each oRefDoc As Document In oADoc.AllReferencedDocuments
	ThisApplication.Documents.Open(oRefDoc.FullFileName,False)
	oLast3Chars = Left(Right(oRefDoc.FullFileName, 7), 3)
	If oRefDoc.DocumentType = DocumentTypeEnum.kPartDocumentObject Then
		oRefDoc.SaveAs(Left(oADoc.FullFileName, Len(oADoc.FullFileName) -4) & oLast3Chars & ".ipt", True)
	ElseIf oRefDoc.DocumentType = DocumentTypeEnum.kAssemblyDocumentObject Then
		oRefDoc.SaveAs(Left(oADoc.FullFileName, Len(oADoc.FullFileName) -4) & oLast3Chars & ".iam", True)
	End If
	oRefDoc.Close
Next

Dim oOccDoc As Document
Dim oOccNewFileName As String
For Each oOcc As ComponentOccurrence In oADoc.ComponentDefinition.Occurrences
	oOccDoc = oOcc.Definition.Document
	oLast3Chars = Left(Right(oOccDoc.FullFileName, 7), 3)
	If oOccDoc.DocumentType = DocumentTypeEnum.kPartDocumentObject Then
		oOccNewFileName = Left(oADoc.FullFileName,Len(oADoc.FullFileName)-4) & oLast3Chars & ".ipt"
	ElseIf oOccDoc.DocumentType = DocumentTypeEnum.kAssemblyDocumentObject Then
		oOccNewFileName = Left(oADoc.FullFileName,Len(oADoc.FullFileName)-4) & oLast3Chars & ".iam"
	End If
	oOcc.Replace(oOccNewFileName, True)
Next

 

So what i needed to change in it was how the names were generated, but i cant figure it out.

i have tried using lines like this: 

Old_prefix = InputBox("Please enter old prefix", "Warning", "")
New_prefix = InputBox("Please enter new prefix", "Warning", "")
Replace(oADoc.FullFileName, Old_prefix, New_prefix)

So that i could just type in old prefix and new prefix and it would replace the prefix in part name, but i cant really make it work.

I think i have a problem with getting a proper path and filename for the files that i am saving.

i also tried something like this 

oRefDoc.SaveAs(Replace(oADoc.FullFileName, Old_prefix, New_prefix) & ".ipt", True)

 But it still did not work.

Any tips how to do it properly?

0 Likes
Accepted solutions (1)
1,856 Views
10 Replies
Replies (10)
Message 2 of 11

m.rymut
Advocate
Advocate

Ok i managed to make it save files properly, but i cant make it replace old components with new components as it should. It only replaces top components, and does not replace subasembly components.

 

I added 2 lines that would give me old path, then the same for new path after new assembly is saved.

Then i i asked for old and new prefixes.

Next i added lines that replaced old path with new path, having full file name of each part, and then a replace a line that replaced prefixes.

 

I just swapped things from the original code, so it is propably really messy and has stuff in in that it does not need, but i dont really know how to clear it up and how to make that last part which replaces components to work.

And it does not replace parts in subassemblies.

 

 

 

If ThisApplication.ActiveDocumentType <> DocumentTypeEnum.kAssemblyDocumentObject Then
	MsgBox("This rule '" & iLogicVb.RuleName & "' only works for Assembly Documents.",vbOK, "WRONG DOCUMENT TYPE")
	Return
End If

Dim oADoc As AssemblyDocument = ThisApplication.ActiveDocument
Dim Old_Path As String
Old_Path = ThisDoc.Path
Dim oFileDlg As Inventor.FileDialog = Nothing
ThisApplication.CreateFileDialog(oFileDlg)
oFileDlg.Filter = "Autodesk Inventor Assembly Files (*.iam)|*.iam"
oFileDlg.InitialDirectory = ThisApplication.DesignProjectManager.ActiveDesignProject.WorkspacePath
oFileDlg.FileName = IO.Path.GetFileName(oADoc.FullFileName).TrimEnd("."c,"i"c,"a"c,"m"c)
oFileDlg.DialogTitle = "Specify New Name & Location For Copied Assembly"
oFileDlg.CancelError = True

On Error Resume Next
oFileDlg.ShowSave
If Err.Number <> 0 Then
	MsgBox("No File Saved.", vbOKOnly, "DIALOG CANCELED")
ElseIf oFileDlg.FileName <> "" Then
	oNewFileName = oFileDlg.FileName
	oADoc.SaveAs(oNewFileName, False)
End If

oADoc = Nothing

InventorVb.DocumentUpdate()

oADoc = ThisApplication.ActiveDocument
Dim Old_prefix As String
Dim New_prefix As String
Old_prefix = InputBox("Please enter old prefix", "Warning", "")
New_prefix = InputBox("Please enter new prefix", "Warning", "")

Dim New_path As String
New_path = ThisDoc.Path
Dim Old_name_new_path As String
Old_name_new_path = ""
Dim Old_name_new_path2 As String
Old_name_new_path2 = ""
For Each oRefDoc As Document In oADoc.AllReferencedDocuments ThisApplication.Documents.Open(oRefDoc.FullFileName, False) Old_name_new_path = Replace(oRefDoc.FullFileName, Old_path, New_Path) oRefDoc.SaveAs(Replace(Old_name_new_path, Old_prefix, New_prefix), True) oRefDoc.Close Next Dim oOccDoc As Document Dim oOccNewFileName As String For Each oOcc As ComponentOccurrence In oADoc.ComponentDefinition.Occurrences oOccDoc = oOcc.Definition.Document Old_name_new_path2 = Replace(oOccDoc.FullFileName, Old_path, New_Path) oOccNewFileName = Replace(Old_name_new_path2, Old_prefix, New_prefix) oOcc.Replace(oOccNewFileName, True) Next

 

 

 

0 Likes
Message 3 of 11

WCrihfield
Mentor
Mentor

Hi @m.rymut.  Have you considered using the 'ReplaceReference' method on the referenced files, instead of replacing individual assembly components.  Here is a link to an article I wrote about the process, which includes a custom Function that incorporates this method.  It may not be the best option if you are attempting to rebuild constraints when the old and new models do not share ancestry, but it can be pretty nice in direct copied file situations.

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

0 Likes
Message 4 of 11

m.rymut
Advocate
Advocate

Hi, thanks for the reply. i have looked at the article, but from what i undersand, it only replaces one component, which is manually written into the code.
I have tried to figure it out, but i have no idea how to adapt it to my code, so it replaces all components.

0 Likes
Message 5 of 11

WCrihfield
Mentor
Mentor

Hi @m.rymut.  Sorry for the delay, but this is a complex topic which requires some considerable time investment to figure out properly, and I do not really use the 'design copy' type process where I work, because it does not suit our needs.  I have dabbled with this process before for others, but have not used it in really large, complex scenario's before.  The main idea is to iterate through files, and their file references, instead of assembly components, because each level of an assembly can have several components that all reference the same base file, then there may be suppressed components, and virtual components, and all sorts of things that can make that process very inefficient and troublesome.  Using FileDescriptor.ReplaceReference method is far superior in efficiency to replacing components, because if you only have 10 files being referenced, but 100 components, you are only dealing with 10 things instead of 100, plus you have eliminated several possible complications.

 

The thing with a file's ReferencedFileDescriptors though, is they are only the directly referenced ones, and does not include ones down several sub levels deep.  That is why I am using a second iteration of the main assembly's AllReferencedDocuments, to ensure that every document, in every level of the main assembly, is getting all of its direct file references replaced in the example below.

 

I have not tested this code yet, so proceed with caution, and only try it out on some test files first, to make sure it is safe and does the job OK for you, before testing on any important stuff.

Sub Main
	Dim oDoc As Document = ThisDoc.Document
	If oDoc.AllReferencedDocuments.Count = 0 Then Exit Sub
	Dim sNewFullFileName As String = UseSaveAsDialog 'runs the custom Function below
	oDoc.SaveAs(sNewFullFileName, False)
	oDoc = ThisDoc.Document
	Dim sNewPath As String = ThisDoc.Path
	Dim sOldPrefix As String = InputBox("Please enter old prefix", "Warning", "")
	Dim sNewPrefix As String = InputBox("Please enter new prefix", "Warning", "")
	'this next variable is to store a list of old & new FullFileNames, so we can replace them all easier
	Dim oDict As New Dictionary(Of String, String) 'oldFullFileName, then newFullFileName
	Dim oRefDocs As DocumentsEnumerator = oDoc.AllReferencedDocuments
	For Each oRefDoc As Document In oRefDocs 'they are already open, by default
		Dim sFileName As String = System.IO.Path.GetFileName(oRefDoc.FullFileName)
		Dim sNewFileName As String = sFileName.Replace(sOldPrefix, sNewPrefix)
		Dim sNewFullName As String = System.IO.Path.Combine(sNewPath, sNewFileName)
		oRefDoc.SaveAs(sNewFullName, True)
		oDict.Add(oRefDoc.FullFileName, sNewFullName)
	Next 'oRefDoc
	For Each oRefDoc As Document In oRefDocs
		Dim oRFDs As FileDescriptorsEnumerator = oRefDoc.File.ReferencedFileDescriptors
		If oRFDs.Count = 0 Then Continue For
		For Each oRFD As FileDescriptor In oRFDs
			For Each oPair In oDict 'oPair represents an entry in the Dictionary
				If oRFD.FullFileName = oPair.Key Then 'Key = old name portion of Dictionary entry
					oRFD.ReplaceReference(oPair.Value) 'Value = new name portion of Dictionary entry
				End If
			Next 'oPair
		Next 'oRFD
	Next 'oRefDoc
	If oDoc.RequiresUpdate Then oDoc.Update2(True)
	If oDoc.Dirty Then oDoc.Save2(True)
	ThisApplication.Documents.CloseAll(True)
End Sub

Function UseSaveAsDialog() As String 'just reaturns new file name, does not actually save
	Dim oFileDialog As Inventor.FileDialog = Nothing
	ThisApplication.CreateFileDialog(oFileDialog)
	oFileDialog.DialogTitle = "Browse To Folder & Specify New File Name."
	oFileDialog.InitialDirectory = ThisApplication.DesignProjectManager.ActiveDesignProject.WorkspacePath
	oFileDialog.Filter = "Autodesk Inventor Files (*.iam;*.dwg;*.idw;*.ipt:*.ipn;*.ide) | *.iam;*.dwg;*.idw;*ipt;*.ipn;*.ide | All files (*.*)|*.*"
	oFileDialog.FileName = ThisDoc.FileName(False)
	oFileDialog.MultiSelectEnabled = False
	oFileDialog.OptionsEnabled = False
	oFileDialog.InsertMode = False
	oFileDialog.CancelError = True
	Try
		oFileDialog.ShowSave
		Return oFileDialog.FileName
	Catch
		Return ""
	End Try
End Function

 

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

0 Likes
Message 6 of 11

m.rymut
Advocate
Advocate

Hi, thank you for your reply and help, and thank you for the time you are giving to make this work.

I am a total newbie with ilogic, so i might not understand a lot.

Its the first time i see FileDescriptor and i have no idea why is it used, but regardles.

i have tried your code and it kinda works, it copies all the files as i need it to, but it only replaces parts, it does not replace subassemblies. So what happens is i have my copied main assembly, in it i get all copied parts as it should be, but all the subassemblies are from orginal main assembly and the code replaces parts in those original assemblies.

 

My question is, is it possible to take the code i edited, which copied all the files as i needed but didnt replace them, and just edit that last part :

Dim oOccDoc As Document
Dim oOccNewFileName As String
For Each oOcc As ComponentOccurrence In oADoc.ComponentDefinition.Occurrences
	
	oOccDoc = oOcc.Definition.Document
	Old_name_new_path2 = Replace(oOccDoc.FullFileName, Old_path, New_Path)
	oOccNewFileName = Replace(Old_name_new_path2, Old_prefix, New_prefix)
	oOcc.Replace(oOccNewFileName, True)
Next

 Or is it not as easy as that?

Because from i can understand, you changed a lot of the code.

 

Other option, that also might be easier, is to use this rule to copy every file and make new assembly with new prefixes, and make another rule that i would use to replace components, would that be easier and worked better?

So i would just have one rule for copying and one rule for replacing?

Or it does not matter if its one rule doing both or two separate rules?

I dont really have to think about suppressed components, virtual components and all sorts of things like that, i dont really use those, and i have each component turned on and visible.

 

Again, thank you for the help and the time you are giving to help me with this.

0 Likes
Message 7 of 11

WCrihfield
Mentor
Mentor

Hi @m.rymut.  OK.  I think I realize where I made a mistake in my code.

  And

1 or 2 rules:

Keeping all the code in one rule, or splitting it up into two different rules should not make that much difference, but splitting it up will require more code to accomplish, because all of the values and resources that were established in the one rule, would all have to be recreated/reestablished in the other rule again.  Generally when code is split up into different sub/function routines, or into different rules, it may slightly negatively impact performance.  I personally like the idea of keeping main processes split into separate blocks of code, but only if it is done right, where you are sharing all the needed bits of data to/from it, and mostly just when the one block of code would need to run multiple times, while the other doesn't.

 

Yes, we might be able to expand upon your original code to possibly make that work too.  If we were to work on expanding your existing code, what we would need is a separate recursive Sub routine, below the Sub Main...your code...End Sub.  What I mean by that is a routine that will repeat itself under certain conditions, as many times as necessary, to step down through multiple levels of structure.  This would be needed because assembly components are usually structured in several layers.  This separate Sub would process each component in the group supplied to it, but then it would also check each component to see if it has any sub components, and if so, it would run that collection of sub components back through itself again (the same Sub that this code is already within), to process that next layer down, and so on.

 

To fix my code, instead of looping back through the same original oRefDocs a second time, I should have used the Dictionary of old & new file names I had created, to open each 'new' file as a document, then process that documents file references.  That would have avoided changing any of the existing ones, and should have helped insure that every document got processed better.

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

Message 8 of 11

WCrihfield
Mentor
Mentor
Accepted solution

Hi @m.rymut.  I think I may have something prepared that you can try out, along the same lines as your original process, but with the additional recursive Sub routine, like I mentioned.  Again though, not tested, so be careful.

Sub Main
	If ThisDoc.Document.DocumentType <> 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 = ThisDoc.Document
	Dim oRefDocs As DocumentsEnumerator = oADoc.AllReferencedDocuments
	If oRefDocs.Count = 0 Then Exit Sub
	Dim sNewFullFileName As String = UseSaveAsDialog 'runs the custom Function below
	If sNewFullFileName = "" Then Exit Sub
	oADoc.SaveAs(sNewFullFileName, False)
	oADoc = ThisDoc.Document
	Dim sNewPath As String = ThisDoc.Path
	Dim sOldPrefix As String = InputBox("Please enter old prefix", "Warning", "")
	Dim sNewPrefix As String = InputBox("Please enter new prefix", "Warning", "")
	'this next variable is to store a list of old & new FullFileNames, so we can replace them all easier
	Dim oDict As New Dictionary(Of String, String) 'oldFullFileName, then newFullFileName
	For Each oRefDoc As Document In oRefDocs 'they are already open, by default
		Dim sFileName As String = System.IO.Path.GetFileName(oRefDoc.FullFileName)
		Dim sNewFileName As String = sFileName.Replace(sOldPrefix, sNewPrefix)
		Dim sNewFullName As String = System.IO.Path.Combine(sNewPath, sNewFileName)
		oRefDoc.SaveAs(sNewFullName, True)
		oDict.Add(oRefDoc.FullFileName, sNewFullName)
	Next 'oRefDoc
	Dim oOccs As ComponentOccurrences = oADoc.ComponentDefinition.Occurrences
	RecursivelyReplaceAllComponents(oOccs, oDict) 'run our custom Sub below
	If oADoc.RequiresUpdate Then oADoc.Update2(True)
	If oADoc.Dirty Then oADoc.Save2(True)
	ThisApplication.Documents.CloseAll(True)
End Sub

Function UseSaveAsDialog() As String 'just reaturns new file name, does not actually save
	Dim oFileDialog As Inventor.FileDialog = Nothing
	ThisApplication.CreateFileDialog(oFileDialog)
	oFileDialog.DialogTitle = "Specify New Name & Location For Copied Assembly"
	oFileDialog.InitialDirectory = ThisApplication.DesignProjectManager.ActiveDesignProject.WorkspacePath
	oFileDialog.Filter = "Autodesk Inventor Assemblies (*.iam) | *.iam"
	oFileDialog.FileName = ThisDoc.FileName(False)
	oFileDialog.MultiSelectEnabled = False
	oFileDialog.OptionsEnabled = False
	oFileDialog.InsertMode = False
	oFileDialog.CancelError = True
	Try : oFileDialog.ShowSave : Return oFileDialog.FileName
	Catch : Return "" : End Try
End Function

Sub RecursivelyReplaceAllComponents(oComps As ComponentOccurrences, oFileNamePairs As Dictionary(Of String, String))
	If IsNothing(oComps) OrElse oComps.Count = 0 Then Exit Sub
	If IsNothing(oFileNamePairs) OrElse oFileNamePairs.Count = 0 Then Exit Sub
	For Each oComp As ComponentOccurrence In oComps
		For Each oPair In oFileNamePairs
			If oComp.ReferencedDocumentDescriptor.ReferencedFileDescriptor.FullFileName = oPair.Key Then
				Try : oComp.Replace(oPair.Value, True) : Catch : End Try
			End If
		Next 'oPair
		If oComp.SubOccurrences.Count > 0 Then
			RecursivelyReplaceAllComponents(oComp.SubOccurrences, oFileNamePairs)
		End If
	Next 'oComp
End Sub

 

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

Message 9 of 11

m.rymut
Advocate
Advocate
Hi, sorry for a late reply,
I have tried your code on some test assemblies and the rule seems to work perfectly and exacly as needed.
I will test it some more, but i think its good.
Thank you very much for your help and the time you have given for this.
0 Likes
Message 10 of 11

jerrydTCYEY
Participant
Participant
I am in the same situation, what does this snippet do?
0 Likes
Message 11 of 11

WCrihfield
Mentor
Mentor

Hi @jerrydTCYEY.  I did not need to use this routine where I work, because we do not use that type of process for anything.  However, what it basically is attempting to do is copy an entire assembly to another location, with different prefix in their file names.  But it tries to do so in a way that cuts all connections with the original assembly, so that it is completely independent.  To do this, it shows the user a file browser dialog, so they can specify where to save the main assembly, and what its new file name should be.  Then asks the user to specify what the 'old' prefix was, and what the 'new' prefix should be.  Then it iterates through every referenced document in the entire assembly, saving each of them to the new location, with the old prefix replaced by the new prefix in their file names.  Then once that process is done, it then iterates through every assembly component (at every level) and replaces them, so that they will now be referencing the new file in the other location.  Then finishes up by updating and saving the assembly again.

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

0 Likes