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: 

Can preview but cannot execute in add-in

1 REPLY 1
SOLVED
Reply
Message 1 of 2
sylvain_boyer6TGNB
114 Views, 1 Reply

Can preview but cannot execute in add-in

I am trying to create a simple two side extrusion on a selected edge or line. 
I have a preview button, and the preview handler works fine. However, when I click execute, the component is only created but fails to get the selected line. 

In the snippet code (entry.py) writen below, I have 2 functions: drawSomething(args) which use the selected line/edge to create the extrusion, and drawSomething2(args) which create a component and extrusion hardcoded. One does not work while the other is OK. 

 

Where am I wrong? After couple of days I am stuck on this issue. 

 

import adsk.core
import adsk.fusion
import os
from ...lib import fusion360utils as futil
from ... import config
app = adsk.core.Application.get()
ui = app.userInterface

CMD_ID = f'{config.COMPANY_NAME}_{config.ADDIN_NAME}_duplicate_components'
CMD_NAME = 'Create Extrusion '
CMD_Description = 'Create a an Extrusion as new component'

IS_PROMOTED = True

# Working in DESIGN
WORKSPACE_ID = 'FusionSolidEnvironment'
PANEL_ID = 'SolidScriptsAddinsPanel'   #TODO Change later# PANEL_ID = 'SolidCreatePanel'
COMMAND_BESIDE_ID = 'ScriptsManagerCommand'
ICON_FOLDER = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'resources', '')

local_handlers = []
selectedEdges = []


# constants
DROPDOWN_GROUP_ID = 'drowdown_group'
DROPDOWN_ID = 'dropdown' #TODO
LINE_SELECTION = 'lineSelection'


PREVIEW_GROUP_ID = 'preview_group'
SHOW_PREVIEW_INPUT = 'show_preview'
SHOW_PREVIEW_MANUAL_INPUT = 'show_preview_manual'

def start():
    # Create a command Definition.
    cmd_def = ui.commandDefinitions.addButtonDefinition(CMD_ID, CMD_NAME, CMD_Description, ICON_FOLDER)
    # Add command created handler. The function passed here will be executed when the command is executed.
    futil.add_handler(cmd_def.commandCreated, command_created)
    # ******** Add a button into the UI so the user can run the command. ********
    # Get the target workspace the button will be created in.
    workspace = ui.workspaces.itemById(WORKSPACE_ID)
    # Get the panel the button will be created in.
    panel = workspace.toolbarPanels.itemById(PANEL_ID)
    # Create the button command control in the UI after the specified existing command.
    control = panel.controls.addCommand(cmd_def, COMMAND_BESIDE_ID, False)
    # Specify if the command is promoted to the main toolbar. 
    control.isPromoted = IS_PROMOTED

# Executed when add-in is stopped.
def stop():
    # Get the various UI elements for this command
    workspace = ui.workspaces.itemById(WORKSPACE_ID)
    panel = workspace.toolbarPanels.itemById(PANEL_ID)
    command_control = panel.controls.itemById(CMD_ID)
    command_definition = ui.commandDefinitions.itemById(CMD_ID)
    # Delete the button command control
    if command_control:
        command_control.deleteMe()
    # Delete the command definition
    if command_definition:
        command_definition.deleteMe()


def command_created(args: adsk.core.CommandCreatedEventArgs):
    # General logging for debug.
    futil.log(f'{CMD_NAME} Command Created Event')

    # TODO Create the event handlers you will need for this instance of the command
    futil.add_handler(args.command.execute, command_execute, local_handlers=local_handlers)
    futil.add_handler(args.command.inputChanged, command_input_changed, local_handlers=local_handlers)
    futil.add_handler(args.command.executePreview, command_preview, local_handlers=local_handlers)
    futil.add_handler(args.command.validateInputs, command_validate_input, local_handlers=local_handlers)
    futil.add_handler(args.command.destroy, command_destroy, local_handlers=local_handlers)

    
    # Create the user interface for your command by adding different inputs to the CommandInputs object
    # https://help.autodesk.com/view/fusion360/ENU/?contextId=CommandInputs
    inputs = args.command.commandInputs
    # TODO ******************************** Define your UI Here ********************************
    i1 = inputs.addSelectionInput(LINE_SELECTION, 'Edge', 'Please select a straight line or edge')
    i1.setSelectionLimits(0)
    i1.addSelectionFilter(adsk.core.SelectionCommandInput.Edges)
    i1.addSelectionFilter(adsk.core.SelectionCommandInput.SketchLines)
 

    # Dropdown group
    profileGroup = inputs.addGroupCommandInput(DROPDOWN_GROUP_ID, 'Dropdown group')
    # Drop Down
    profileStandardDropdownInput = profileGroup.children.addDropDownCommandInput(DROPDOWN_ID,'Dropdown',adsk.core.DropDownStyles.TextListDropDownStyle)
    profileStandardDropdownInput.listItems.add('Jim',True)
    profileStandardDropdownInput.listItems.add('Jack',False)
    profileStandardDropdownInput.listItems.add('Jim-Jack',False)    
   
    # Preview 
    previewGroup = inputs.addGroupCommandInput(PREVIEW_GROUP_ID, 'Preview')
    #previewGroup.isExpanded = uiState.getGroupExpandedState(PREVIEW_GROUP_ID)
    previewGroup.children.addBoolValueInput(SHOW_PREVIEW_INPUT, 'Show auto update preview (slow)', True, '', False)
    showPreviewManual = previewGroup.children.addBoolValueInput(SHOW_PREVIEW_MANUAL_INPUT, 'Update preview once', False, '', False)
    showPreviewManual.isFullWidth = True



def command_execute(args: adsk.core.CommandEventArgs):
    # General logging for debug
    futil.log(f'{CMD_NAME} Command Execute Event')
    inputs = args.command.commandInputs
    # TODO ******************************** Your code here ********************************
    drawSomething(args)
    # drawSomething2(args)  #drawSomething2(args) does not contain any selection and works
 

# This function will be called when the command needs to compute a new preview in the graphics window
def command_preview(args: adsk.core.CommandEventArgs):
    inputs = args.command.commandInputs
    futil.log(f'{CMD_NAME} Command Preview Event')

    if is_all_input_valid(inputs):
        showPreview: adsk.core.BoolValueCommandInput = inputs.itemById(SHOW_PREVIEW_INPUT)
        showPreviewManual: adsk.core.BoolValueCommandInput = inputs.itemById(SHOW_PREVIEW_MANUAL_INPUT)
        if showPreview.value or showPreviewManual.value:
           #args.isValidResult = drawSomething(args)
           args.isValidResult = drawSomething(args)  #drawSomething2(args) does not contain any selection and works
        
           showPreviewManual.value = False
    else:
        args.executeFailed = True
        args.executeFailedMessage = "Some inputs are invalid, unable to generate preview"    


# This function will be called when the user changes anything in the command dialog
def command_input_changed(args: adsk.core.InputChangedEventArgs):
    changed_input = args.input
    inputs = args.inputs
    futil.log(f'{CMD_NAME} Input Changed Event fired from a change to {changed_input.id}')
    dropdown: adsk.core.DropDownCommandInput = inputs.itemById(DROPDOWN_ID)
    lineSelectionInput: adsk.core.SelectionCommandInput = inputs.itemById(LINE_SELECTION)
    try:
        if changed_input.id == DROPDOWN_ID:
            ui.messageBox('new player selected')
        if changed_input.id == LINE_SELECTION:
            pass
    except:
        ui.messageBox('error')


# This event handler is called when the user interacts with any of the inputs in the dialog
# which allows you to verify that all of the inputs are valid and enables the OK button.
def command_validate_input(args: adsk.core.ValidateInputsEventArgs):
    # General logging for debug.
    futil.log(f'{CMD_NAME} Validate Input Event')
    inputs = args.inputs
    # Verify the validity of the input values. This controls if the OK button is enabled or not.
    args.areInputsValid = is_all_input_valid(inputs)


# This event handler is called when the command terminates.
def command_destroy(args: adsk.core.CommandEventArgs):
    global local_handlers
    local_handlers = []
    futil.log(f'{CMD_NAME} Command Destroy Event')



def is_all_input_valid(inputs: adsk.core.CommandInputs):
    result = True # TODO
    return result


def createNewComponent():
    # Get the active design.
    product = app.activeProduct
    design = adsk.fusion.Design.cast(product)
    rootComp = design.rootComponent
    allOccs = rootComp.occurrences
    newOcc = allOccs.addNewComponent(adsk.core.Matrix3D.create())
    return newOcc.component


def drawSomething(args: adsk.core.CommandEventArgs):
    inputs = args.command.commandInputs
    lineSelectionInput: adsk.core.SelectionCommandInput = inputs.itemById(LINE_SELECTION)
    try:
        global newComp
        newComp = createNewComponent()
        if newComp is None:
            ui.messageBox('New component failed to create', 'New Component Failed')
            return
        else:
            ui.messageBox('Component created')
            # Get the line or edge
            selObj = lineSelectionInput.selection(0)
            entity = selObj.entity
            ui.messageBox('Line was selected from the selection')

            lineLength = entity.length   
            ui.messageBox('The line length is :'+str(entity.length))


            # create the normal plane
            planes = newComp.constructionPlanes
            planeInput = planes.createInput()
            planeInput.setByDistanceOnPath(entity, adsk.core.ValueInput.createByReal(0.5))
            plane = planes.add(planeInput)
            ui.messageBox('Construction plane created')
            # create the sketch
            sketches = newComp.sketches
            sketch = sketches.add(plane)
            ui.messageBox('Sketch created')
            # Draw the sketch #TODO replace by a defined profile sketch linked to profile name
            pipeRadius = lineLength/20
            center = plane.geometry.origin
            center = sketch.modelToSketchSpace(center)
            sketch.sketchCurves.sketchCircles.addByCenterRadius(center, pipeRadius)
            profile = sketch.profiles[0]
            ui.messageBox('sketch drawn')
            # Extrude 
            feats = newComp.features
            extrudeFeats = feats.extrudeFeatures
            ui.messageBox('feature created')
            extrudeInput = extrudeFeats.createInput(profile, adsk.fusion.FeatureOperations.NewBodyFeatureOperation)
            extent_distance_1 = adsk.fusion.DistanceExtentDefinition.create(adsk.core.ValueInput.createByReal(lineLength/2))
            extent_distance_2 = adsk.fusion.DistanceExtentDefinition.create(adsk.core.ValueInput.createByReal(lineLength/2))
            deg5 = adsk.core.ValueInput.createByString("5 deg")
            deg10 = adsk.core.ValueInput.createByString("10 deg")
            extrudeInput.setTwoSidesExtent(extent_distance_1, extent_distance_2, deg5, deg10)
            extrude7 = extrudeFeats.add(extrudeInput)
            ui.messageBox('body extruded')
    except:
        if ui:
            ui.messageBox('Failed to compute the extrusion: drawSomething()')    



def drawSomething2(args: adsk.core.CommandEventArgs):
    inputs = args.command.commandInputs
    lineSelectionInput: adsk.core.SelectionCommandInput = inputs.itemById(LINE_SELECTION)
    try:
        # global newComp
        newComp = createNewComponent()
        if newComp is None:
            ui.messageBox('New component failed to create', 'New Component Failed')
            return
        # create the normal plane
        planes = newComp.constructionPlanes
        planeInput = planes.createInput()
        planeInput.setByOffset(newComp.xYConstructionPlane,adsk.core.ValueInput.createByReal(10))
        plane = planes.add(planeInput)
        # create the sketch
        sketches = newComp.sketches
        sketch = sketches.add(plane)
        # Draw the sketch #TODO replace by a defined profile sketch linked to profile name
        pipeRadius = 2 #lineLength/20
        center = plane.geometry.origin
        center = sketch.modelToSketchSpace(center)
        sketch.sketchCurves.sketchCircles.addByCenterRadius(center, pipeRadius)
        profile = sketch.profiles[0]
        # Extrude 
        feats = newComp.features
        extrudeFeats = feats.extrudeFeatures
        extrudeInput = extrudeFeats.createInput(profile, adsk.fusion.FeatureOperations.NewBodyFeatureOperation)
        extent_distance_1 = adsk.fusion.DistanceExtentDefinition.create(adsk.core.ValueInput.createByReal(5))
        extent_distance_2 = adsk.fusion.DistanceExtentDefinition.create(adsk.core.ValueInput.createByReal(5))
        deg5 = adsk.core.ValueInput.createByString("5 deg")
        deg10 = adsk.core.ValueInput.createByString("10 deg")
        extrudeInput.setTwoSidesExtent(extent_distance_1, extent_distance_2, deg5, deg10)
        extrude7 = extrudeFeats.add(extrudeInput)
    except:
        if ui:
            ui.messageBox('Failed to compute the Extrusion. drawSomething2()')    


 

Tags (3)
Labels (1)
1 REPLY 1
Message 2 of 2

Apparently, there is a bit different behavior when executing versus preview.

 

What's happening is that when you execute, the selections are cleared when you make a change to the design. Specifically, in your case, it's when you create the component. To work around this, you need to get the selection first. Here's a slightly modified version of your drawSomething function where I moved the two lines that get the selection to before the call to createNewComponent.

 

def drawSomething(args: adsk.core.CommandEventArgs):
    inputs = args.command.commandInputs
    lineSelectionInput: adsk.core.SelectionCommandInput = inputs.itemById(LINE_SELECTION)
    try:
        global newComp
        selObj = lineSelectionInput.selection(0)
        entity = selObj.entity
        newComp = createNewComponent()
        if newComp is None:

 

Another fix is if at the end of the drawSomething you add the following line:

return True

 

You're already using the return value of drawSomething to set the isValidResult value. If this is set to True, when the command is executed, it doesn't do anything and uses the result created from the last preview.

args.isValidResult = drawSomething(args)

 

---------------------------------------------------------------
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