change assembly color from assembly level down to part level

change assembly color from assembly level down to part level

Covello_O
Enthusiast Enthusiast
882 Views
9 Replies
Message 1 of 10

change assembly color from assembly level down to part level

Covello_O
Enthusiast
Enthusiast

Hi all

I'm looking for a code that changes the color of the assembly, subassembly and till down to the parts.

I adapted a code that I found here in this Forum it doesen't work something is wrong in the for loop.

Any help is very welcome.

 

 

Dim oAssemblyDoc As Inventor.AssemblyDocument = ThisApplication.ActiveDocument
Dim oDoc As Document

Dim oAsset As Asset
Dim oAsset_Array As New ArrayList
For Each oAsset_Array_X In ThisApplication.ActiveAppearanceLibrary.AppearanceAssets
oAsset_Array.Add(oAsset_Array_X.DisplayName)
oAsset_Array.Sort()
Next
'present the user with the list to choose from
100:
oAsset_Array_Selected = InputListBox("CHOOSE TEXTURE FROM ABOVE LIST", oAsset_Array, oAsset_Array.Item(0), "TEXTURE SELECTION", "LIST OF TEXTURES")
If oAsset_Array_Selected = "" Then GoTo 100 :

For Each oDoc In oAssemblyDoc.AllReferencedDocuments
    If oDoc.DocumentType = kPartDocumentObject Then
        If oAssemblyDoc.ComponentDefinition.Occurrences.AllReferencedOccurrences(oDoc).Count > 0 Then

			Dim comps As ObjectCollection
			Dim comp As Object
			comps = ThisApplication.TransientObjects.CreateObjectCollection

			For Each comp In comps
				comps.Add(comp)
				Dim oDef As PartDocument
				oDef = comp.Definition.Document
				Dim oRenderStyle As RenderStyle
				oRenderStyle = oDef.RenderStyles.Item(oAsset_Array_Selected)
				oDef.ActiveRenderStyle = oRenderStyle
				iLogicVb.UpdateWhenDone = True
				Component.Color(comp.name)=oAsset_Array_Selected
			Next	
		End If
	End If
Next

 

 

0 Likes
883 Views
9 Replies
Replies (9)
Message 2 of 10

Andrii_Humeniuk
Advisor
Advisor

Hi @Covello_O . I see you are trying to do a For operation with the comps variable but it is empty at this point. Because you created it a few lines back and didn't put anything there.

Here are some examples of changing the appearance from the forum: Link, Link, Link.

Your code should look something like this:

Dim oInvApp As Inventor.Application = ThisApplication
Dim oAssemblyDoc As Inventor.AssemblyDocument = oInvApp.ActiveDocument

Dim oAsset As Asset
Dim oAsset_Array As New ArrayList
For Each oAsset_Array_X In oInvApp.ActiveAppearanceLibrary.AppearanceAssets
oAsset_Array.Add(oAsset_Array_X.DisplayName)
oAsset_Array.Sort()
Next
'present the user with the list to choose from
100:
oAsset_Array_Selected = InputListBox("CHOOSE TEXTURE FROM ABOVE LIST", oAsset_Array, oAsset_Array.Item(0), "TEXTURE SELECTION", "LIST OF TEXTURES")
If oAsset_Array_Selected = "" Then GoTo 100 :

Dim oDef As AssemblyComponentDefinition = oAssemblyDoc.ComponentDefinition
Dim oOccs As ComponentOccurrences = oDef.Occurrences
For Each oDoc As Document In oAssemblyDoc.AllReferencedDocuments
    If oDoc.DocumentType = kPartDocumentObject Then
        If oOccs.AllReferencedOccurrences(oDoc).Count > 0 Then
			For Each oOcc As ComponentOccurrence In oOccs.AllReferencedOccurrences(oDoc)
				Dim oPDoc As PartDocument
				oPDoc = oOcc.Definition.Document
				Dim oRenderStyle As RenderStyle
				oRenderStyle = oPDoc.RenderStyles.Item(oAsset_Array_Selected)
				oPDoc.ActiveRenderStyle = oRenderStyle
				iLogicVb.UpdateWhenDone = True
				Component.Color(oOcc.Name) = oAsset_Array_Selected
			Next	
		End If
	End If
Next

I haven't tested it, but I hope it works.
You can also use my free Inventor app that does a good job of changing the appearance and calculating the area of ​​the appearance of parts.

Andrii Humeniuk - CAD Coordinator, Autodesk Certified Instructor

LinkedIn | My free Inventor Addin | My Repositories

Did you find this reply helpful ? If so please use the Accept as Solution/Like.

EESignature

0 Likes
Message 3 of 10

b.kushaiynov
Contributor
Contributor

Can it be done  also for selected faces ? 

0 Likes
Message 4 of 10

WCrihfield
Mentor
Mentor

Just adding a couple additional notes in here...

On lines 4, 6, & 7 (of the last code example) it is accessing the proper types of objects (Asset).  But then down in Lines 23, 24, & 25 it is trying to work with very outdated objects (RenderStyle).  See the following online help page about how those objects became outdated back around 2013.

https://help.autodesk.com/view/INVNTOR/2024/ENU/?guid=GUID-2912C0FB-885F-47ED-81C3-AF19584EA9C1 

Those lines of code should have been more like the following:

Dim oAsset As Inventor.Asset = oPDoc.AppearanceAssets.Item(oAsset_Array_Selected)
oPDoc.ActiveAppearance = oAsset

...using the following properties:  PartDocument.AppearanceAssets & PartDocument.ActiveAppearance.

 

Then, this line of code:

iLogicVb.UpdateWhenDone = True

...is a preparatory line of code that only needs to be used once per rule, and usually near the start of the rule, not down within a loop, or at the end of a rule.  Once that is set to True once, the rule will automatically update the document that the rule is focused on, once the rule has finished (not immediately where that line of code is).  In an immediate update was needed at that point, you could have used 'oPDoc.Update', or 'oPDoc.Update2' or 'InventorVb.DocumentUpdate', or similar.  For example:

oPDoc.Update2(True)

 

Then, this line of code:

Component.Color(oOcc.Name) = oAsset_Array_Selected

is likely just fine in that second example, because it is only being used on 'top level' components.  But in the first example, you were attempting to iterate through all referenced documents (at all levels), then checking how many components within (all levels of) the assembly were referencing that document.  If you needed to change the color of an assembly component that was at a lower level (not top level), using that line of code, then you would need to specify the 'path' of the component, instead of just a simple component name.  The 'path' is an array of Strings, starting with the name of the top level component representing the sub assembly, then the names of any components below that, until you get to the name of the component you want it to effect.  This is so that it can fine one, among possibly many, at varying depths of a large assembly.

 

However, that one line of code (an iLogic only snippet) can be changed out, if needed, and replaced by some regular Inventor API code for doing the same task.  For instance, the regular Inventor API object ComponentOccurrence (that you already have a reference to in the second example) has the property ComponentOccurrence.Appearance, and the property ComponentOccurrence.AppearanceSourceType that could be worked with, instead.  That Appearance property provides / accepts an Asset object as its value, just like the PartDocument.ActiveAppearance property.

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

Message 5 of 10

b.kushaiynov
Contributor
Contributor

how will be look like with those changes at the end ? 

Could some one help ? Code is too complicated for me to change or anything to do with it .

0 Likes
Message 6 of 10

WCrihfield
Mentor
Mentor

Hi @b.kushaiynov.

 

This type of task can be very complicated.  There are lots of levels of settings that need to be kept in mind, or it will not work as planned.  Every model document has DVR's (design view representations [DesignViewRepresentations]) in it, and these are what record the visibility, colors, and appearances of objects within that document.  Then, every assembly component occurrence in every level of every assembly has a setting for its appearance, and for its DVR.  And every parent assembly's DVR records how all the components within that assembly are set for their individual appearance and DVR.  If all that is not set-up starting from the lowest level parts first, then on up to the main assembly, then none of it will be coordinated or recorded by any of the DVRs in any of those documents along the way.

 

Even though this code looks long and complex, it still does not yet include all the functionality to support saving all these appearance changes, within all these parts, within DVRs.  If any assembly component's DVR (DesignViewRepresentation) is set to be associative, then running a code like this on it will loose that setting, and therefore loose the appearance coordination between the source model and the assembly component.

 

Here is an updated iLogic code example you can try out though.  I highly recommend that you test this on a smaller assembly containing components that are not that important to production first, just to be safe.

Sub Main
	'make sure we are working with an assembly (not a part or drawing)
	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 oAllRefDocs As DocumentsEnumerator = oADoc.AllReferencedDocuments
	Dim oOccs As ComponentOccurrences = oADef.Occurrences
	If oAllRefDocs.Count = 0 OrElse oOccs.Count = 0 Then Return 'if nothing in it, then exit rule

	'<<< get list of available appearances from acive global appearances library >>>
	Dim oActiveAppAssetsLib As Inventor.AssetsEnumerator = ThisApplication.ActiveAppearanceLibrary.AppearanceAssets
	Dim oAppearanceNames As New List(Of String)
	For Each oAppAsset As Inventor.Asset In oActiveAppAssetsLib
		oAppearanceNames.Add(oAppAsset.DisplayName)
	Next oAppAsset
	oAppearanceNames.Sort 'sort the names
	'have user choose one of the appearance names
	Dim sChosenAssetName As String = InputListBox("Choose Appearance Name.", oAppearanceNames, "", "Appearance Names", "List Of Appearance Names")
	If sChosenAssetName = "" Then Return 'if nothing was chosen, then exit the rule
	'get the actual appearance Asset object by that chosen name
	Dim oChosenAppAsset As Inventor.Asset = oActiveAppAssetsLib.Item(sChosenAssetName)

	'<<< now start iterating through all assembly components that reference parts >>>
	For Each oRefDoc As Inventor.Document In oAllRefDocs
		If Not TypeOf oRefDoc Is PartDocument Then Continue For
		Dim oPDoc As PartDocument = oRefDoc
		Dim oPartOccs As ComponentOccurrencesEnumerator = oOccs.AllReferencedOccurrences(oPDoc)
		If oPartOccs.Count = 0 Then Continue For
		'there must be a 'local' copy of this appearance saved within the part (not just in the global library), or this will fail
		Dim oDocAsset As Inventor.Asset = Nothing
		Try 'try to find a copy of it in the part document
			oDocAsset = oPDoc.AppearanceAssets.Item(oChosenAppAsset.DisplayName)
		Catch 'if not found there, create a copy of the library appearance in the part document
			Try : oDocAsset = oChosenAppAsset.CopyTo(oPDoc, True) : Catch : End Try
		End Try
		If oDocAsset Is Nothing Then Continue For
		Try
			oPDoc.ActiveAppearance = oDocAsset
		Catch
			Logger.Error("Error setting ActiveAppearance of following part:" & vbCrLf & oPDoc.FullDocumentName)
		End Try
		For Each oPartOcc As ComponentOccurrence In oPartOccs
			Try 'main fail if no local copy of this appearance asset exists in this components parent assembly
				oPartOcc.Appearance = oChosenAppAsset
			Catch
				Logger.Error("Error setting Appearance of component named:  " & oPartOcc.Name)
			End Try
		Next oPartOcc
	Next oRefDoc
	oADoc.Update2(True)
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)

0 Likes
Message 7 of 10

Covello_O
Enthusiast
Enthusiast

Many thanks

I tested your code and it seems to work only in 1st level. The .ipt in the subassy weren't be affected.  So it seems to be a difficult task.

I asked ChatGPT to adapt your code to go down to subassy and parts and he wrote this code below. But doesn't change the color to part level as well. I will keep trying.

''from chat gpt
Dim oInvApp As Inventor.Application = ThisApplication
Dim oAssemblyDoc As Inventor.AssemblyDocument = oInvApp.ActiveDocument
iLogicVb.UpdateWhenDone = True
' Collect all appearance assets
Dim oAsset As Asset
Dim oAsset_Array As New ArrayList
For Each oAsset_Array_X In oInvApp.ActiveAppearanceLibrary.AppearanceAssets
    oAsset_Array.Add(oAsset_Array_X.DisplayName)
Next
oAsset_Array.Sort()

' Present the user with the list to choose from
Dim oAsset_Array_Selected As String
100:
oAsset_Array_Selected = InputListBox("CHOOSE TEXTURE FROM ABOVE LIST", oAsset_Array, oAsset_Array.Item(0), "TEXTURE SELECTION", "LIST OF TEXTURES")
If oAsset_Array_Selected = "" Then GoTo 100

' Get the root component definition
Dim oDef As AssemblyComponentDefinition = oAssemblyDoc.ComponentDefinition
Dim oOccs As ComponentOccurrences = oDef.Occurrences

' Stack to handle occurrences
Dim occStack As New Stack(Of ComponentOccurrences)
occStack.Push(oOccs)

' Process all occurrences
Do While occStack.Count > 0
    Dim currentOccs As ComponentOccurrences = occStack.Pop()
    For Each oOcc As ComponentOccurrence In currentOccs
        If oOcc.DefinitionDocumentType = kAssemblyDocumentObject Then
            ' If it's a subassembly, add its occurrences to the stack
            Dim oSubAssem As AssemblyDocument = oOcc.Definition.Document
            Dim oSubOccs As ComponentOccurrences = oSubAssem.ComponentDefinition.Occurrences
            occStack.Push(oSubOccs)
        ElseIf oOcc.DefinitionDocumentType = kPartDocumentObject Then
            ' If it's a part, apply the texture
            Dim oPDoc As PartDocument = oOcc.Definition.Document
            Dim oRenderStyle As RenderStyle
            Try
                oRenderStyle = oPDoc.RenderStyles.Item(oAsset_Array_Selected)
                oPDoc.ActiveRenderStyle = oRenderStyle
                'iLogicVb.UpdateWhenDone = True
                Component.Color(oOcc.Name) = oAsset_Array_Selected
            Catch ex As Exception
                ' Handle any errors, such as missing render style
            End Try
        End If
    Next
Loop

 

0 Likes
Message 8 of 10

Covello_O
Enthusiast
Enthusiast

I tried to complete the code but i'm a newbee in ilogic.
So  this code here throws an error at this line:

localAsset = libAsset.CopyTo(oCompDef)

Any help would be very apreciated.

 

 

Imports Inventor
Imports System.Collections

Sub main()
    Dim oInvApp As Inventor.Application = ThisApplication
    Dim oAsmDoc As AssemblyDocument = DirectCast(ThisDoc.Document, AssemblyDocument)
    Dim oAppearances As String = "Appearances:" & vbCrLf
    Dim oAssemblyDoc As Inventor.AssemblyDocument = oInvApp.ActiveDocument
    Dim oDef As AssemblyComponentDefinition = oAssemblyDoc.ComponentDefinition
    Dim oOccs As ComponentOccurrences = oDef.Occurrences

    ' Collect all appearance assets
    Dim oAsset_Array As New ArrayList
    For Each oAsset In oInvApp.AssetLibraries.Item("Autodesk Appearance Library").AppearanceAssets
        oAsset_Array.Add(oAsset.DisplayName)
    Next
    oAsset_Array.Sort()

    ' Present the user with the list to choose from
    Dim oAsset_Array_Selected As String
    Do
        oAsset_Array_Selected = InputListBox("CHOOSE TEXTURE FROM ABOVE LIST", 
		oAsset_Array, oAsset_Array.Item(0), "TEXTURE SELECTION", "LIST OF TEXTURES")
    Loop While oAsset_Array_Selected = ""

    ' Iterate through all referenced documents
    For Each oRefDoc As Document In oAsmDoc.AllReferencedDocuments
        ' Check if the document is a Part Document
        If oRefDoc.DocumentType = DocumentTypeEnum.kPartDocumentObject Then
            Dim oPDoc As PartDocument = DirectCast(oRefDoc, PartDocument)
            Dim oCompDef As PartComponentDefinition = oPDoc.ComponentDefinition

            ' Ensure there are referenced occurrences
            If oOccs.AllReferencedOccurrences(oRefDoc).Count > 0 Then
                For Each oOcc As ComponentOccurrence In oOccs.AllReferencedOccurrences(oRefDoc)
                    ' Get the local asset if it exists
                    Dim localAsset As Asset = Nothing
                    Try
                        localAsset = oCompDef.Assets.Item(oAsset_Array_Selected)
                    Catch ex As Exception
                        ' Handle the error if the asset is not found
                    End Try

                    ' If the asset does not exist in the document, import it from the library
                    If localAsset Is Nothing Then
                        Try
                            Dim assetLib As AssetLibrary = oInvApp.AssetLibraries.Item("Autodesk Appearance Library")
                            Dim libAsset As Asset = assetLib.AppearanceAssets.Item(oAsset_Array_Selected)
                            localAsset = libAsset.CopyTo(oCompDef)
                        Catch ex As Exception
                            MessageBox.Show("Error importing asset: " & ex.Message, "Error")
                            Exit Sub
                        End Try
                    End If

                    ' Apply the appearance to each body in the part
                    For Each body As SurfaceBody In oCompDef.SurfaceBodies
                        Try
                            body.Appearance = localAsset
                        Catch ex As Exception
                            MessageBox.Show("Error applying appearance: " & ex.Message, "Error")
                        End Try
                    Next

                    ' Update appearance list
                    Dim oAppearance As String = localAsset.DisplayName
                    oAppearances &= vbCrLf & oRefDoc.DisplayName & "    " & oAppearance
                Next
            End If
        End If
    Next

    ' Display the list of appearances
    'MessageBox.Show(oAppearances, "Appearance List")
End Sub

 

0 Likes
Message 9 of 10

WCrihfield
Mentor
Mentor

Hi @Covello_O.  Asking an AI bot to write code to automate Inventor does not seem to produce good results from what I have seen examples of in this forum.  It is better to learn to write the code yourself first, that way you have a better idea what is going to happen when you run the code.  Spending some time looking around in this forum, and looking at the code examples found here that worked for others is a good place to start.  This forum has search functionality that can be used to find other forum topics and responses related to your search terms.

 

An iLogic rule in Inventor can be far more powerful, and have far greater reach than most folks would originally imagine, so they can be dangerous if you do not understand them.  They can control a lot more than just Inventor.  They can reach out and control other applications (such as Excel, Outlook, Word, and others) and system resources also, and can even process entire folders full of files, if designed to.

 

In your first code after my last response, I see that it is using a 'Stack' type collection, which I have never seen used in an iLogic rule before.  Then that example also still had the old RenderStyle objects in it, which should not be used in any new code projects.  Then in the last code you posted, it looks like you are trying to get the Asset objects from a PartComponentDefinition type of object, which will not work.  Then again in a later line of code, it is trying to copy an Asset object to a PartComponentDefinition type of object, which will not work.  Asset objects are either stored within an AssetLibrary, or in a PartDocument, not in a ComponentDefinition.  My earlier example showed you how to possibly get them from a PartDocument or set one to a PartDocument.  The PartDocument object is a different object than the PartComponentDefinition object.

 

As I mentioned before, setting appearances in an assembly should be done starting from the bottom, not from the top.  These code attempts are all trying to do it starting from the top, so you may not be able to achieve the results you want this way.  When you change the color of an assembly component, that color change is recorded by whichever DVR was active in that component's parent assembly at that moment.  When you look at the model browser tree in an assembly, you will see a folder near the top named "Representations", then if you expand that browser node, you will see a category named 'View'.  Then, if you expand that browser node, you will see the individual DVR's (design view representations).  Like the image below.

WCrihfield_0-1717421095110.png

That is where things like component visibility and component color or appearance settings are being recorded.  This is recorded in this document, not some other higher level assembly.  Then, if this assembly is added into a higher level assembly as an assembly component, you can set that component to one of these DVR's that are defined within this assembly (not a DVR from some other assembly).  This will control the appearance of that component within the parent level assembly.  This is partially why this needs to be done starting from the bottom, instead of from the top.  None of these codes are doing anything with the DVR's, but are just trying to force appearance changes at multiple levels of an assembly while ignoring all the DVR's of all the documents along the way.

 

I did create a different version of the code that I created earlier, using a different strategy, to see if it might possibly work any better for you.  The code is within the attached text file.  However, like all the earlier code examples, it is still completely ignoring all of the DVR's in all the documents along the way, so it is still not ideal either.

 

To make a task like this easier in the future, you should have one or more custom DVR's defined within each model document that you would like to control the appearance of.  While that custom DVR is active, make sure the model looks the way you want it to look, then save the model.  Then when you place an instance of that model into an assembly, set the instance to the custom DVR that you defined within that model, to maintain control of its appearance.  That is the proper way to control appearances in an assembly.

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

0 Likes
Message 10 of 10

Covello_O
Enthusiast
Enthusiast

Many thanks for taking the time to reply and explain it so good.

I already looking in the forum for ilogic code. I ask chat gpt especially when I need some explanation.

And of course I have to understand the code that I am writing. And I will continue to learn here.

So thank you I will try your code later.

 

0 Likes