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.
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()))
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()))
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
Can't find what you're looking for? Ask the community or share your knowledge.