Create new assembly component using user parameter value as new component filename

Create new assembly component using user parameter value as new component filename

kwilson_design
Collaborator Collaborator
938 Views
13 Replies
Message 1 of 14

Create new assembly component using user parameter value as new component filename

kwilson_design
Collaborator
Collaborator

Hey everyone. I'm currently creating an assembly generator form that will create new part components based off part templates. The first tab of the form the user has to enter in the new part component part numbers, which writes to specific user parameters. I then have a rule that will create the new part components but I'm stuck on trying to ensure that when it creates these new parts, it uses the value from the user parameter to create the filename of the new part components. 

 

User enters new part numbers for the new left and right channel parts....

kwilson_design_2-1716560826603.png

 

Those values get written to these user parameters....

kwilson_design_1-1716560439276.png

 

Then the user clicks to run internal rules named "Create Left Channel" and "Create Right Chanel"...

kwilson_design_3-1716560909117.png

 

This is the part where I start hitting a wall. Below is the Create Left Channel rule. I have two issues with it. The first is that it's automatically grounding the first channel it creates despite having that option turned off in the Application Options. I copied that code from another thread and I'm not sure what aspect of the code is causing the grounding but I don't want the parts grounded as I have another rule that will position the new channel part components. The second issue I have is how do I make it so that when it creates the new parts, it doesn't name them generic "Part1, Part 2 etc but rather uses the value of the "Left_channel_part_number" user parameter?

Dim oTemplateLeftChannel As String = "C:\_VaultWorkspace\Designs\ETO\Templates\Generators\AVR\AVR Base Generator (Left Double Channel Design).ipt"
Dim oDoc As AssemblyDocument = ThisApplication.ActiveDocument
Dim oDocumentDefinition As AssemblyComponentDefinition = oDoc.ComponentDefinition
Dim oTG As TransientGeometry = ThisApplication.TransientGeometry
Dim oMatrix As Matrix = oTG.CreateMatrix
Dim pDoc As PartDocument = ThisApplication.Documents.Add(DocumentTypeEnum.kPartDocumentObject, oTemplateLeftChannel, False)
oDocumentDefinition.Occurrences.AddByComponentDefinition(pDoc.ComponentDefinition, oMatrix)

kwilson_design_4-1716561356167.png

Lastly, once they are done working in the generator form and ready to save the assembly, how do i ensure that the new part components files are saved in a specific folder location? The code for creating the channels I posted above does not seem to give you the option to even save the part files. I need the new part components files saved into "C:\_VaultWorkspace\Designs\ETO\Components\PS501" folder.

 

Any help would be greatly appreciated!

Regards,
Kenny
If this post solved your issue please mark "Accept as Solution". It helps everyone...really!
0 Likes
Accepted solutions (1)
939 Views
13 Replies
Replies (13)
Message 2 of 14

WCrihfield
Mentor
Mentor

Hi @kwilson_design.  I do not really use the process of generating new assembly components from the assembly myself, but it looks like you may just need to add a few more lines of code into your code above.

  • One line to store the path for where you want the new part to be saved.
  • One (or more) line for for obtaining the value of the specific UserParameter to use as the file name.
  • One line to join the part's path and the part's file name (from the UserParameter) together into one new String, that can be used in a later line of code, when it saves that part, before insertion.
  • One line for saving the newly created part document, right after your line of code that creates it from the template, using the full path and file name from earlier, but before insertion line of code.
  • Then, hopefully, it will use the file name of that newly saved part as the name of the component, when it inserts in in the following line(s) of code.

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

0 Likes
Message 3 of 14

kwilson_design
Collaborator
Collaborator

Hey @WCrihfield thanks for your valued input! Ok so after your suggestion I don't think I have the 3 bullet point lines you suggested setup correctly. Would you mind taking a look?

 

Dim oTemplate As String = "C:\_VaultWorkspace\Designs\ETO\Templates\Generators\AVR\AVR Base Generator (Left Double Channel Design).ipt"
Dim oPath = "C:\_VaultWorkspace\Designs\ETO\Components\PS501\"
Dim oFilename = Left_channel_part_number 
ThisDoc.FileName(False) = oFilename
Dim oFilename&Path As String = ThisDoc.PathAndFileName(False)
Dim oDoc As AssemblyDocument = ThisApplication.ActiveDocument
Dim oDocumentDefinition As AssemblyComponentDefinition = oDoc.ComponentDefinition
Dim oTG As TransientGeometry = ThisApplication.TransientGeometry
Dim oMatrix As Matrix = oTG.CreateMatrix
Dim pDoc As PartDocument = ThisApplication.Documents.Add(DocumentTypeEnum.kPartDocumentObject, oTemplate, False)
oDocumentDefinition.Occurrences.AddByComponentDefinition(pDoc.ComponentDefinition, oMatrix

kwilson_design_0-1716567801176.png

 

You mentioned you would not typically create components this way, but I'm curious if you could suggest another method you would use to achieve the same result. Thanks gain for taking the time to look at this with me. If I can get this generator working it will drastically save design time for my team and also help create consistent assembly constraints for designs instead of everyone else doing their own thing and sometimes using bad constraint discipline.

Regards,
Kenny
If this post solved your issue please mark "Accept as Solution". It helps everyone...really!
0 Likes
Message 4 of 14

WCrihfield
Mentor
Mentor
Accepted solution

Hi @kwilson_design.  The iLogic snippet 'ThisDoc.FileName' is ReadOnly.  But when working with a regular Inventor API Document type object, its DisplayName is Read/Write, and its FullFileName is Read/Write (usually only written to before save).  The FullDocumentName is ReadOnly though.  Anyways, we only need to store the fill path & file name to a temporary variable until we save the part.  I added in some error proofing along the way to help out, but did not build in any feedback for when they may be used.  One is to ensure that the currently 'active' document is actually an assembly (not some other type of document).  If it not an assembly, it will exit the rule.  Then, I changed how it is accessing the parameter value.  If left as an unquoted blue parameter name, the rule will get triggered to run every time that parameter's value changes, which may be undesirable.  This new way also ensures that the parameter we are looking for actually exists, and has a value.  Next, as you can see, I am using a simple SaveAs on the new part, before attempting to insert an instance of that part as an assembly component into the assembly.  Then I am using the regular Add method, instead of the AddByComponentDefinition method, simply because that makes more sense to me, and seems like it should work the way you seem to need it to work here.  I hope this works as planned for you.

Dim oADoc As Inventor.AssemblyDocument = TryCast(ThisApplication.ActiveDocument, Inventor.AssemblyDocument)
If oADoc Is Nothing Then Return
Dim oADef As AssemblyComponentDefinition = oADoc.ComponentDefinition
Dim oUParams As UserParameters = oADef.Parameters.UserParameters
Dim oFileNameParam As UserParameter = Nothing
Try : oFileNameParam = oUParams.Item("Left_channel_part_number") : Catch : End Try
If oFileNameParam Is Nothing Then Return
Dim sFilename As String = oFileNameParam.Value.ToString
If sFilename = "" Then Return
Dim sTemplate As String = "C:\_VaultWorkspace\Designs\ETO\Templates\Generators\AVR\AVR Base Generator (Left Double Channel Design).ipt"
Dim sPath = "C:\_VaultWorkspace\Designs\ETO\Components\PS501\"
Dim sFFN As String = sPath & sFilename & ".ipt" 'not sure if extension included in parameter value
Dim oMatrix As Inventor.Matrix = ThisApplication.TransientGeometry.CreateMatrix
Dim oPDoc As PartDocument = ThisApplication.Documents.Add(DocumentTypeEnum.kPartDocumentObject, sTemplate, False)
oPDoc.SaveAs(sFFN, False)
Dim oPartOcc As ComponentOccurrence = oADef.Occurrences.Add(oPDoc.FullDocumentName, oMatrix)

 

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

Message 5 of 14

WCrihfield
Mentor
Mentor

By the way, I am not against using the 'CreateComponent' tool, or using the AddByComponentDefinition method, I simply do not use them, because they do not suit my needs right now.  Because of that, I am not as familiar with using them as some others may be.  If using the SaveAs, then regular Add method will not work for you the way you had in mind, then maybe you could attempt to:

oPDoc.DisplayName = sFileName & ".ipt"

oPDoc.FullFileName = sFFN

...then do not use the SaveAs line...

...then maybe the AddByComponentDefinition will work better for you, but I am not sure.  To me, the ComponentDefinition would not contain the file name you want it to use, because that is a File / Document level property.  Another thought, if using the AddByComponentDefinition route, would be to 'capture' the new component it creates, then work with that object to set its Name property, and so on.  Just some additional thoughts.

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

Message 6 of 14

kwilson_design
Collaborator
Collaborator

@WCrihfield thanks Wesley! I'm not real familiar with using the addbycomponent either but found it in a somewhat similar post so figured I'd try and go that route. Your edits worked great, so thanks for that and I appreciate the checks and balances you put in. I really need to start adding those into my code just in case we get someone to run a script on a filetype it's not intended to be ran on. Thanks for the reminder lol.

 

I'm still getting the first part component into the assembly as being grounded. I'm not sure if that's coming from the transient geometry line or the matrix but do you know what is triggering the grounding? It is not the Application Options as I've triple checked ground initial part is not enabled.

Regards,
Kenny
If this post solved your issue please mark "Accept as Solution". It helps everyone...really!
0 Likes
Message 7 of 14

kwilson_design
Collaborator
Collaborator

@WCrihfield I ran into 2 snags when trying this approach.

 

First small issue/bug while testing, if I had already saved new channel components to their folder, deleted them (even in old versions folder, I would get an error if trying to run the generator again and create new components with the same filenames as before. If i would close the Inventor session and start the generator again, I had no errors and it would create the new components using the same name i previously tried. It's like the filename is hung up in cache memory or something. Strange but not a deal breaker and in most user cases, they would not be trying to test the generator using the same filenames looking for any issues. Just thought I'd mention that strange behavior.

 

Second and more import issue is now that we've identified how to save the files per your code and write the new filenames prior to create, I'm now trying to figure out how I can get my "Link Parameters" rule working where it will reference the new component filename model parameter. When I had this working with just writing to a known file (my template) it worked perfect fine of course but now that my code won't "know" what the new filename is until after create, how do I solve that issue? Instead of PS501-_____ L:1 it needs to somehow know the new filename of the new components.

 

kwilson_design_0-1716898816979.png

kwilson_design_1-1716899049468.png

 

Regards,
Kenny
If this post solved your issue please mark "Accept as Solution". It helps everyone...really!
0 Likes
Message 8 of 14

WCrihfield
Mentor
Mentor

Hi @kwilson_design.  The first issue you mentioned in your last response is one that I have heard many times before.  I am not 100% sure how you would be able to get around that issue right now.  I know of a few small tricks for helping to clear the 'memory' of iLogic or Inventor, but I do not know if any of these will work the way you need them to work for that situation.  This issue may be deeper seeded than we can manage by simple code in an iLogic rule.

ThisApplication.CommandManager.ControlDefinitions.Item("iLogic.ClearCodeClipboard").Execute
ThisApplication.CommandManager.ControlDefinitions.Item("iLogic.FreeILogicMemory").Execute
ThisApplication.CommandManager.ClearPrivateEvents

As for your second issue...

That sounds a lot like the issue that is normally solved by 'stabilizing' the model browser tree names for the assembly components within your main assembly.  Stabilizing basically means changing just the names that you see within the model browser tree for those components, without actually changing any file names or Part Number values.  When we do this, those assembly component names that we use within our iLogic codes can stay the same, even if the file names or Part Numbers of those components change.  This is because that model browser tree node name will remain the same, even after you change the name of the file or change its Part Number, because you have already changed its name before to a name that is not default, so it will stay that way.  In your case, after you add the new component into the assembly, you may simply need to obtain a reference to that new component, then change its ComponentOccurrence.Name property value to match one that is already being referenced within your iLogic rule.

 

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

0 Likes
Message 9 of 14

kwilson_design
Collaborator
Collaborator

Hey @WCrihfield thanks again for your input. Yea seems like issue 1 is likely just because of the way I'm repeatedly testing. Most users likely won't encounter this error, or so i hope lol.

 

Regarding issue 2. I think I see what you mean with occurrences but I'm not quite sure how to write it out.

 

Trying to do something like below but I'm not sure if this would even work the way I've written it. I'm getting an error on the line 4 of "name". I'm trying to learn this so i appreciate your patience and willingness to help.

 

Dim oDoc As Document = ThisApplication.ActiveDocument
Dim oOccs As ComponentOccurrences = oDoc.ComponentDefinition.Occurrences

If oOccs.Name.StartsWith(PS501) & oOccs.Name.EndsWith(L) Then
	oOccs.Name = Left_channel_part_number 
Else If oOccs.Name.StartsWith(PS501) & oOccs.Name.EndsWith(R)
	oOccs.Name = Right_channel_part_number 
End If

 

kwilson_design_0-1716908361835.png

 

Regards,
Kenny
If this post solved your issue please mark "Accept as Solution". It helps everyone...really!
0 Likes
Message 10 of 14

WCrihfield
Mentor
Mentor

Hi @kwilson_design.  There is a lot of opportunity for something to possibly go wrong (error) in a code process like this, but here is another code example that will attempt to do what you are wanting there.  Instance number is often important.  If there are two or more instances of same base part, errors may happen.  So, I am reusing 'instance number' of original, when renaming them in this example.

Dim oDoc As Document = ThisApplication.ActiveDocument
Dim oOccs As ComponentOccurrences = oDoc.ComponentDefinition.Occurrences
Dim sCommonStart As String = "PS501"
'define the character that we need to find within the model browser tree name of the assembly component
'this character is where we will need to 'split' its name into 'base name' and 'instance number'.
Dim sSplitChar As Char = ":"
'iterate through each individual component (only in top level, not any deeper)
For Each oOcc As ComponentOccurrence In oOccs
	'define the variables we will need to be working with
	Dim sOccName, sOccBaseName, sOccInstance As String
	sOccName = oOcc.Name 'record its current name (as seen in the model browser)
	'check if it contains the 'split character'
	If sOccName.Contains(sSplitChar) Then
		'if it does, then capture the 'base name' and 'instance number' portions of it
		'Split function splits a single String into an Array of Strings, by the split character
		sOccBaseName = sOccName.Split(sSplitChar)(0)
		sOccInstance = sOccName.Split(sSplitChar)(1)
	Else 'that 'split' character was not found in its name
		sOccBaseName = sOccName
	End If
	'check start and end of 'base name' (without instance number)
	'AndAlso will only process second check, if first check is True, unline regular 'And' keyword
	If sOccBaseName.StartsWith(sCommonStart) AndAlso sOccBaseName.EndsWith("L") Then
		'rename the component using local parameter value, followed by instance number of original
		oOcc.Name = Left_channel_part_number & sSplitChar & sOccInstance
	ElseIf sOccBaseName.StartsWith(sCommonStart) AndAlso sOccBaseName.EndsWith("R") Then
		'rename the component using local parameter value, followed by instance number of original
		oOcc.Name = Right_channel_part_number & sSplitChar & sOccInstance
	End If
Next oOcc

 

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

0 Likes
Message 11 of 14

kwilson_design
Collaborator
Collaborator

So that code you wrote is supposed to rename the browser tree component name or rename/inject the occurrence name within the rule? 

 

When I added Line 32 which was the "link parameters" line of code ...

Parameter(oOcc.Name, "Holes_Distance_To_Insulator1_C_C") = Holes_Distance_To_Insulator1_C_C)

It doesn't seem to do anything or rewrite the browser tree data. Maybe I'm not supposed to add your code with the link parameters but then how else would I get the occurrence name in there? I'm a bit unsure where to add your code or run it as you can see lol.

Dim oDoc As Document = ThisApplication.ActiveDocument
Dim oOccs As ComponentOccurrences = oDoc.ComponentDefinition.Occurrences
Dim sCommonStart As String = "PS501"
'define the character that we need to find within the model browser tree name of the assembly component
'this character is where we will need to 'split' its name into 'base name' and 'instance number'.
Dim sSplitChar As Char = ":"
'iterate through each individual component (only in top level, not any deeper)
For Each oOcc As ComponentOccurrence In oOccs
	'define the variables we will need to be working with
	Dim sOccName, sOccBaseName, sOccInstance As String
	sOccName = oOcc.Name 'record its current name (as seen in the model browser)
	'check if it contains the 'split character'
	If sOccName.Contains(sSplitChar) Then
		'if it does, then capture the 'base name' and 'instance number' portions of it
		'Split function splits a single String into an Array of Strings, by the split character
		sOccBaseName = sOccName.Split(sSplitChar)(0)
		sOccInstance = sOccName.Split(sSplitChar)(1)
	Else 'that 'split' character was not found in its name
		sOccBaseName = sOccName
	End If
	'check start and end of 'base name' (without instance number)
	'AndAlso will only process second check, if first check is True, unline regular 'And' keyword
	If sOccBaseName.StartsWith(sCommonStart) AndAlso sOccBaseName.EndsWith("L") Then
		'rename the component using local parameter value, followed by instance number of original
		oOcc.Name = Left_channel_part_number & sSplitChar & sOccInstance
	ElseIf sOccBaseName.StartsWith(sCommonStart) AndAlso sOccBaseName.EndsWith("R") Then
		'rename the component using local parameter value, followed by instance number of original
		oOcc.Name = Right_channel_part_number & sSplitChar & sOccInstance
	End If
Next oOcc

Parameter(Left_channel_part_number, "Holes_Distance_To_Insulator1_C_C") = Holes_Distance_To_Insulator1_C_C

kwilson_design_0-1716919041442.png

 

 

kwilson_design_2-1716919084092.png

FWIW I also tried using the occurrence name with your code for Line 32 and it doesn't seem to write anything to the part file model parameter. So I'm definitely screwing something up with your code here lol.

Parameter(oLeft_channel_part_number, "Holes_Distance_To_Insulator1_C_C") = Holes_Distance_To_Insulator1_C_C

 

Regards,
Kenny
If this post solved your issue please mark "Accept as Solution". It helps everyone...really!
0 Likes
Message 12 of 14

kwilson_design
Collaborator
Collaborator

Oh and no need to worry with having more than 1 occurrence of the same part number or filename in this generator as that wouldn't be a scenario we would deal with but thanks for thinking of that in your code.

Regards,
Kenny
If this post solved your issue please mark "Accept as Solution". It helps everyone...really!
0 Likes
Message 13 of 14

kwilson_design
Collaborator
Collaborator

@WCrihfield I've also tried this method but still getting errors. I'm so confused at this point lol.

 

Dim doc As AssemblyDocument
doc = ThisDoc.Document
Dim oAsmCompDef As AssemblyComponentDefinition
oAsmCompDef = doc.ComponentDefinition
Dim oComp As ComponentOccurrence
Dim oComps As ComponentOccurrences
oComps = doc.ComponentDefinition.Occurrences 

For Each oComp In oComps
     If oComp.Name.Contains("PS501" & "L") Then
        value = oComp.Definition.Parameters.Item("Left_channel_part_number").Expression
     End If

Next

Parameter(oComp.Definition.Parameters.Item("Left_channel_part_number").Expression, "Holes_Distance_To_Insulator1_C_C") = Holes_Distance_To_Insulator1_C_C

kwilson_design_0-1716929804053.png

 

Regards,
Kenny
If this post solved your issue please mark "Accept as Solution". It helps everyone...really!
0 Likes
Message 14 of 14

WCrihfield
Mentor
Mentor

That is a long barrage of follow-up questions.  I had to leave early yesterday, and may not be that active today either, because I have been sick.  The last code example I posted here was just my attempt at correcting the last code example you posted just before what I posted.  It was meant to be used just once, to correct the model browser tree names for the components.  Then your other code for copying / pushing parameter values from main assembly to sub component parts would have been a separate iLogic rule.

 

I keep seeing something in your responses that you will need to understand and fix.  You will not be able to find a component named "PS501-TRYL:1" if you are only searching for "PS501-TRYL", because it is missing the ":1" at the end.  So, for instance if your variable named 'oLeft_channel_part_number', or the value of your local parameter named "Left_channel_part_number" only have the value "PS501-TRYL", and you are using that variable to specify which component to target within a Parameter() line of code, it will not work.  It must also include that ":1" at the end, just like you see it in the model browser tree.

Also, the following:

oComp.Name.Contains("PS501" & "L")

will not work, because it is searching for "PS501L", not "PS501" then "L" separately.  Then '&' symbol joins two or more Strings into a single String.  Those two checks need to be done separately, like in the example I showed in Message 10 above.  

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

0 Likes