Community
Fusion API and Scripts
Got a new add-in to share? Need something specialized to be scripted? Ask questions or share what you’ve discovered with the community.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Occurrence Appearance Name

9 REPLIES 9
SOLVED
Reply
Message 1 of 10
gvisca44
340 Views, 9 Replies

Occurrence Appearance Name

Trying to write myself a script that will read a CSV file that contains a list of components - and their desired Appearances and then traverse a model to apply the desired Appearance.

 

I have hit a bit of a snag as follows:

* once the Appearance is applied to an occurrence, I attempt to read back the occurrence.appearance.name I receive an error AttributeError: 'NoneType' object has no attribute 'name'

 

Refer approx line 71 in code below.

 

The API manual suggests an occurrence has an appearance property - that returns an appearance object - which has a corresponding name.  Note the processing of setting the new apperance functions successfully.

 

 

import adsk.core, adsk.fusion, adsk.cam, traceback

app = None
ui  = None

def run(context):
    ui = None
    try:
        app = adsk.core.Application.get()
        ui  = app.userInterface

        fileDialog = ui.createFileDialog()
        fileDialog.title = "Select Appearance File"
        fileDialog.isMultiSelectEnabled = False
        result = fileDialog.showOpen()
        if result != adsk.core.DialogResults.DialogOK:
            return
        else:
            filename = fileDialog.filename

        result = ui.messageBox('Yes = Create points from file\nNo = Update ponits from file', 
                                'Control Points From File', 
                                adsk.core.MessageBoxButtonTypes.YesNoCancelButtonType, 
                                adsk.core.MessageBoxIconTypes.QuestionIconType)
        if result == adsk.core.DialogResults.DialogCancel:
            return
        elif result == adsk.core.DialogResults.DialogYes:
            ProcessAppearanceFile(filename)
        elif result == adsk.core.DialogResults.DialogNo:
            #UpdatePoints(filename)
            return

    except:
        if ui:
            ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

def ProcessAppearanceFile(filename):
    try:
        app = adsk.core.Application.get()
        ui  = app.userInterface
        product = app.activeProduct
        design = adsk.fusion.Design.cast(product)

        root = design.rootComponent
        occs = []

        ui.palettes.itemById('TextCommands').writeText("Debugging")

        occs = root.allOccurrences
        doc = app.activeDocument.name

        if len(occs) == 0:
            ui.messageBox('There are no components in this design.')
            return

        # Open the appearances file 
        with open(filename) as f:
            for line in f:

                line = line.strip()

                appearances = line.split(',')
                componentName = appearances[0]
                componentAppearance = getAppearance(appearances[1])

                for occ in occs:
                    if occ.component.name == componentName:
                        
                        occ.appearance = componentAppearance

                        # THIS IS LINE THAT FAILS
                        ui.palettes.itemById('TextCommands').writeText("New appearance " + occ.appearance.name)
                        # END OF LINE THAT FAILS
    except:
        if ui:
            ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))    

def getAppearance(appearanceName):
    app = adsk.core.Application.get()
    ui  = app.userInterface
    materialLibs = app.materialLibraries
    appearance = None
    for materialLib in materialLibs:
        appearances = materialLib.appearances

        try:
            appearance = appearances.itemByName(appearanceName)
            ui.palettes.itemById('TextCommands').writeText(appearance.name)

        except:
            pass
        
        if appearance:
            break
    return appearance

 

 

9 REPLIES 9
Message 2 of 10
kandennti
in reply to: gvisca44

Hi @gvisca44 .

 

I am guessing because the CSV file was not attached, but I think that the CSV file is read as a normal text file and therefore the appearance is not being acquired properly.
(I think it is a double quotation marks issue).

 

I think you should add a filter to the dialog and use it in the csv module.
It would also be safer to check if the appearance is retrieved.

# Fusion360API Python script
import traceback
import adsk.fusion
import adsk.core
import csv

app = None
ui  = None

def run(context):
    ui = None
    try:
        app = adsk.core.Application.get()
        ui  = app.userInterface

        fileDialog: adsk.core.FileDialog = ui.createFileDialog()
        fileDialog.title = "Select Appearance File"
        fileDialog.filter = 'csv files (*.csv);;'
        fileDialog.isMultiSelectEnabled = False
        result = fileDialog.showOpen()
        if result != adsk.core.DialogResults.DialogOK:
            return
        else:
            filename = fileDialog.filename

        result = ui.messageBox('Yes = Create points from file\nNo = Update ponits from file', 
                                'Control Points From File', 
                                adsk.core.MessageBoxButtonTypes.YesNoCancelButtonType, 
                                adsk.core.MessageBoxIconTypes.QuestionIconType)
        if result == adsk.core.DialogResults.DialogCancel:
            return
        elif result == adsk.core.DialogResults.DialogYes:
            ProcessAppearanceFile(filename)
        elif result == adsk.core.DialogResults.DialogNo:
            #UpdatePoints(filename)
            return

    except:
        if ui:
            ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

def ProcessAppearanceFile(filename):
    try:
        app = adsk.core.Application.get()
        ui  = app.userInterface
        product = app.activeProduct
        design = adsk.fusion.Design.cast(product)

        root = design.rootComponent
        occs = []

        app.log("Debugging")

        occs = root.allOccurrences
        doc = app.activeDocument.name

        if len(occs) == 0:
            ui.messageBox('There are no components in this design.')
            return

        with open(filename) as f:
            reader = csv.reader(f)
            for row in reader:
                componentName = row[0]
                componentAppearance = getAppearance(row[1])

                if not componentAppearance:
                    msg = f'Canceled because "Appearance" cannot be obtained. \n ({row[1]})'
                    ui.messageBox(msg)
                    return

                for occ in occs:
                    print(occ.component.name)
                    print(componentName)
                    if occ.component.name == componentName:
                        
                        occ.appearance = componentAppearance

                        # THIS IS LINE THAT FAILS
                        app.log("New appearance " + occ.appearance.name)
                        # END OF LINE THAT FAILS
    except:
        if ui:
            ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

def getAppearance(appearanceName):
    app = adsk.core.Application.get()
    materialLibs = app.materialLibraries
    appearance = None
    for materialLib in materialLibs:
        appearances = materialLib.appearances

        try:
            appearance = appearances.itemByName(appearanceName)
            app.log(appearance.name)

        except:
            pass

        if appearance:
            break
    return appearance
Message 3 of 10
gvisca44
in reply to: kandennti

Hi @kandennti 

 

I appreciate your response.  CSV file is as simple as component and desired appearance separated by comma per line.

 

I am happy that the application of the correct appearance is working because the appearances are visually present in the model I am working on.

 

I suspect (but am very happy to be corrected) something is screwy about accessing the appearance property of an occurrence object. 

 

Consider the following code.  Getting the appearance by body by component works successfully.

 

However, getting the appearance by occurrence (which I believe should work) fails.  I can certainly SET the appearance this way.  And the occurrence object has an appearance property.

import adsk.core, adsk.fusion, adsk.cam, traceback

def getAppearanceByBody():
    app = adsk.core.Application.get()
    ui  = app.userInterface
    product = app.activeProduct
    design = adsk.fusion.Design.cast(product)

    for comp in design.allComponents:
        for body in comp.bRepBodies:
            app.log('Component-' + comp.name + '\tBody-' + body.name + '\tAppearance-' + body.appearance.name)

def getAppearanceByOccurrence():
    app = adsk.core.Application.get()
    ui  = app.userInterface
    product = app.activeProduct
    design = adsk.fusion.Design.cast(product)

    root = design.rootComponent
    occs = root.allOccurrences

    for occ in occs:
        app.log('Occurrence-' + occ.name + '\tAppearance-' + occ.appearance.name)

def run(context):
    ui = None
    try:
        app = adsk.core.Application.get()
        ui  = app.userInterface
        
        ui.messageBox('APPEARANCES BY COMPONENT BODY')
        app.log('**** APPEARANCES BY COMPONENT BODY ****')
        getAppearanceByBody()

        ui.messageBox('APPEARANCES BY OCCURRENCE')
        app.log('****   APPEARANCES BY OCCURRENCE   ****')
        getAppearanceByOccurrence()

    except:
        if ui:
            app.log('Failed:\n{}'.format(traceback.format_exc()))

 

Regards, 

 

Glenn.

Message 4 of 10
kandennti
in reply to: gvisca44

@gvisca44 .

 

I understand what you mean.

Certainly the name property was not available in the case of Ocarens.

1.png

I think it is a bug.

How about using the id property?

Message 5 of 10
BrianEkins
in reply to: gvisca44

The appearance property of the Occurrence object can return null. When an appearance is added to an occurrence, it overrides the colors assigned to the body and faces. Getting the occurrence appearance is getting the override color. If there isn't an override, it will return None.

---------------------------------------------------------------
Brian Ekins
Inventor and Fusion 360 API Expert
Website/Blog: https://EkinsSolutions.com
Message 6 of 10
gvisca44
in reply to: kandennti

@kandennti 

I had the same thought.  id also failed.

 

 

Message 7 of 10
gvisca44
in reply to: BrianEkins

@BrianEkins 

yes ... after several hours of messing around I did finally get my head around the nuance.

 

However - my original statement remains ... when I apply an apperance to an occurrence it works successfully (can physically see it on the model).  When I attempt to read the appearance of that same occurrence - I receive the error. 

Message 8 of 10
BrianEkins
in reply to: gvisca44

Here's a small standalone script that I wrote to test this. Create a new design and create a new component (Occurrence) within the design and then run the script. Each time you run it, it will change the appearance of the occurrence from gold to steel and back. I'm also able to get the appearance after it's set.

 

def run(context):
    try:
        app = adsk.core.Application.get()
        ui = app.userInterface
        des = adsk.fusion.Design.cast(_app.activeProduct)
        root = des.rootComponent

        if root.occurrences.count == 0:
            ui.messageBox('There must be at least one occurrence in the design.')
            return

        occ = root.occurrences[0]

        app.log(f'Running test on {occ.name}')
        newName = 'Gold - Polished'
        if occ.appearance is None:
            app.log(f'  The occurrence has NO appearance override.')
        else:
            app.log(f'  The current appearance override is {occ.appearance.name}')

            if occ.appearance.name == 'Gold - Polished':
                newName = 'Steel - Satin'

        newAppearance = des.appearances.itemByName(newName)
        if newAppearance is None:
            lib = app.materialLibraries.itemByName('Fusion 360 Appearance Library')
            libAppearance = lib.appearances.itemByName(newName)
            newAppearance = des.appearances.addByCopy(libAppearance, newName)

        occ.appearance = newAppearance

        app.log(f'   After setting appearance the occurrence appearance is: {occ.appearance.name}')
    except:
        ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

 

---------------------------------------------------------------
Brian Ekins
Inventor and Fusion 360 API Expert
Website/Blog: https://EkinsSolutions.com
Message 9 of 10
gvisca44
in reply to: BrianEkins

Thanks Brian

 

There's a small error in the script as posted:

        app = adsk.core.Application.get()
        ui = app.userInterface
        des = adsk.fusion.Design.cast(_app.activeProduct)

note the underscore before app.activeProduct

But thats ok ... I think I have found the issue (more than likely in the way I am processing things)

 

Now - imagine you run that same script - but 

 

You have a design with 1 occurence (as you state)

You have a design that uses the above as a linked design (which is the way all my designs operate).

 

Now run the script again on the second design.

Message 10 of 10
BrianEkins
in reply to: gvisca44

That's it. I can reproduce it with a linked design. I'll see that a bug is filed.

---------------------------------------------------------------
Brian Ekins
Inventor and Fusion 360 API Expert
Website/Blog: https://EkinsSolutions.com

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

Post to forums  

Autodesk DevCon in Munich May 28-29th


Autodesk Design & Make Report