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: 

Selection Errors when Copying Objects

2 REPLIES 2
Reply
Message 1 of 3
Anonymous
460 Views, 2 Replies

Selection Errors when Copying Objects

I've had a reoccuring issue related to selection filters and copying bodies during an execution preview process. I've isolated the problem to the code below. If you run this code and select a plane, a cylinder will be created on that plane, then it will be copied to a new component. This copy will then cause the selectionCommandInput in the command to select the body, not the original plane. I can't understand why this is being selected but it causes an input change and in a large system causes many bugs. It also changes the body color which is undesirable. Can someone explain how to avoid this or correct the bug in the API?

 

Here is the sample code, and an image of the problem. Note that the selectionCommand has filters for planes but clearly the body is selected. When I start this command I just select one of the origin planes and watch the preview execute, once the copy is completed the body is "magically" selected.

Capture.PNG

import adsk.core, adsk.fusion, traceback

app = None
ui  = None
design = None

handlers = []
        
commandId = 'selectionDebugCommand'
commandName = commandId
commandDescription = commandName
selected = None
def getSelection(commandInput):
    entity = commandInput.selection(0).entity
    ui.messageBox(entity.classType())
    if entity.classType() == adsk.fusion.Profile.classType():
        plane = entity.plane
    else:
        ui.messageBox(entity.classType())
        if entity.classType() == adsk.fusion.BRepBody.classType():
            return
        plane = entity.geometry   
    global selected
    selected = entity
class ApplyAppearanceInputChangedHandler(adsk.core.InputChangedEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        try:
            ui.messageBox("change")
            cmd = args.firingEvent.sender
            inputs = cmd.commandInputs
            global commandId
            for inputI in inputs:
                    getSelection(inputI)
        except:
            if ui:
                ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
def createNewComponent(rootComp):
    allOccs = rootComp.occurrences
    newOcc = allOccs.addNewComponent(adsk.core.Matrix3D.create())
    return newOcc.component
class ApplyAppearanceExecuteHandler(adsk.core.CommandEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        try:
            if selected == None:
                ui.messageBox("Nothing")
                return
            global design
            global selected
            root = design.rootComponent
            sketches = root.sketches
            ui.messageBox(selected.classType())
            sketch = sketches.add(selected)
            sketch.sketchCurves.sketchCircles.addByCenterRadius(adsk.core.Point3D.create(0,0,0), 10)
            extrudes = root.features.extrudeFeatures
            prof = sketch.profiles[0]
            extInput = extrudes.createInput(prof, adsk.fusion.FeatureOperations.NewBodyFeatureOperation)
            distance = adsk.core.ValueInput.createByReal(-5)
            extInput.setDistanceExtent(False, distance)
            extrudes.add(extInput)
            comp1=createNewComponent(root)
            occurencesOfCopy = root.allOccurrencesByComponent(comp1)
            occ =occurencesOfCopy.item(0)
#        collection = adsk.core.ObjectCollection.create()
            for body in root.bRepBodies:
                body.copyToComponent(occ)
#            collection.add(body)
        except:
            if ui:
                ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

class ApplyAppearanceCreatedHandler(adsk.core.CommandCreatedEventHandler):    
    def __init__(self):
        super().__init__()        
    def notify(self, args):
        try:
            cmd = args.command
            cmd.isRepeatable = False
            onExecute = ApplyAppearanceExecuteHandler()
            cmd.execute.add(onExecute)
            cmd.executePreview.add(onExecute)
            onInputChanged = ApplyAppearanceInputChangedHandler()
            cmd.inputChanged.add(onInputChanged)
            # keep the handler referenced beyond this function
            handlers.append(onExecute)
            handlers.append(onInputChanged)
            inputs = cmd.commandInputs
            global commandId
            selectionInput = inputs.addSelectionInput(commandId + '_selection', 'Select', 'Select plane')
            selectionInput.addSelectionFilter('PlanarFaces')
            selectionInput.addSelectionFilter('ConstructionPlanes')
            selectionInput.addSelectionFilter('Profiles')
        except:
            if ui:
                ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

def run(context):
    try:
        global app
        app = adsk.core.Application.get()
        global ui
        ui = app.userInterface
        global design
        design = adsk.fusion.Design.cast(app.activeProduct)

        global commandId
        global commandName
        global commandDescription
        
        cmdDef = ui.commandDefinitions.itemById(commandId)
        if not cmdDef:
            cmdDef = ui.commandDefinitions.addButtonDefinition(commandId, commandName, commandDescription) # no resource folder is specified, the default one will be used

        onCommandCreated = ApplyAppearanceCreatedHandler()
        cmdDef.commandCreated.add(onCommandCreated)
        # keep the handler referenced beyond this function
        handlers.append(onCommandCreated)

        inputs = adsk.core.NamedValues.create()
        cmdDef.execute(inputs)

        # prevent this module from being terminate when the script returns, because we are waiting for event handlers to fire
        adsk.autoTerminate(False)

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

2 REPLIES 2
Message 2 of 3
Anonymous
in reply to: Anonymous

Here is a bad solution to the problem. At the end of execute preview I can check that selectionCommandInputs are only holding items that they can use, comparing them to their filters as in the code below. However this only allows me to clear the selection filters if there is a failure which is bad UI design because it removes user input. Is there a better solution?

#Author-Autodesk Inc.
#Description-Apply an appearance to selected faces, bodies or occurrences.

import adsk.core, adsk.fusion, traceback

app = None
ui  = None
design = None

handlers = []
        
commandId = 'selectionDebugCommand'
commandName = commandId
commandDescription = commandName
commandInput = None
selected = None
def getSelection():
    global commandInput
    ui.messageBox("Seaking selection")
    entity = commandInput.selection(0).entity
    ui.messageBox(entity.classType())
    if entity.classType() == adsk.fusion.BRepBody.classType():
        ui.messageBox("Selected Body")
        commandInput.clearSelection()
        return 
    global selected
    selected = entity
    ui.messageBox("retrieved Selection")
class ApplyAppearanceInputChangedHandler(adsk.core.InputChangedEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        try:
            ui.messageBox("change")
            getSelection()
        except:
            if ui:
                ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
def createNewComponent(rootComp):
    allOccs = rootComp.occurrences
    newOcc = allOccs.addNewComponent(adsk.core.Matrix3D.create())
    return newOcc.component
class ApplyAppearanceExecuteHandler(adsk.core.CommandEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        try:
            if selected == None:
                ui.messageBox("Nothing")
                return
            global design
            global selected
            root = design.rootComponent
            sketches = root.sketches
            sketch = sketches.add(selected)
            sketch.sketchCurves.sketchCircles.addByCenterRadius(adsk.core.Point3D.create(0,0,0), 10)
            extrudes = root.features.extrudeFeatures
            prof = sketch.profiles[0]
            extInput = extrudes.createInput(prof, adsk.fusion.FeatureOperations.NewBodyFeatureOperation)
            distance = adsk.core.ValueInput.createByReal(-5)
            extInput.setDistanceExtent(False, distance)
            extrudes.add(extInput)
            comp1=createNewComponent(root)
            occurencesOfCopy = root.allOccurrencesByComponent(comp1)
            occ =occurencesOfCopy.item(0)
#        collection = adsk.core.ObjectCollection.create()
            for body in root.bRepBodies:
                body.copyToComponent(occ)
#            collection.add(body)
            getSelection()
        except:
            if ui:
                ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

class ApplyAppearanceCreatedHandler(adsk.core.CommandCreatedEventHandler):    
    def __init__(self):
        super().__init__()        
    def notify(self, args):
        try:
            cmd = args.command
            cmd.isRepeatable = False
            onExecute = ApplyAppearanceExecuteHandler()
            cmd.execute.add(onExecute)
            cmd.executePreview.add(onExecute)
            onInputChanged = ApplyAppearanceInputChangedHandler()
            cmd.inputChanged.add(onInputChanged)
            # keep the handler referenced beyond this function
            handlers.append(onExecute)
            handlers.append(onInputChanged)
            inputs = cmd.commandInputs
            global commandId
            selectionInput = inputs.addSelectionInput(commandId + '_selection', 'Select', 'Select plane')
            selectionInput.addSelectionFilter('PlanarFaces')
            selectionInput.addSelectionFilter('ConstructionPlanes')
            selectionInput.addSelectionFilter('Profiles')
            global commandInput
            commandInput = selectionInput
        except:
            if ui:
                ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

def run(context):
    try:
        global app
        app = adsk.core.Application.get()
        global ui
        ui = app.userInterface
        global design
        design = adsk.fusion.Design.cast(app.activeProduct)

        global commandId
        global commandName
        global commandDescription
        
        cmdDef = ui.commandDefinitions.itemById(commandId)
        if not cmdDef:
            cmdDef = ui.commandDefinitions.addButtonDefinition(commandId, commandName, commandDescription) # no resource folder is specified, the default one will be used

        onCommandCreated = ApplyAppearanceCreatedHandler()
        cmdDef.commandCreated.add(onCommandCreated)
        # keep the handler referenced beyond this function
        handlers.append(onCommandCreated)

        inputs = adsk.core.NamedValues.create()
        cmdDef.execute(inputs)

        # prevent this module from being terminate when the script returns, because we are waiting for event handlers to fire
        adsk.autoTerminate(False)

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

Message 3 of 3
marshaltu
in reply to: Anonymous

Hello,

 

Thank you for reporting issue to us. I can reproduce the issue and narrow it down to the bug of body.copyToComponent(). We logged UP-28927 in our internal system to track the issue. We will investigate and fix in future releases.

 

Unfortunately I have no better workaround for you.

 

Thanks,

Marshal



Marshal Tu
Fusion 360 Developer
Autodesk, Inc.

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

Post to forums  

Autodesk Design & Make Report