Demonstrates how to automate the creation of an additive MJF manufacturing setup and arrange components within the build volume of a 3D printer.
To run the sample script, have a design with one or more components open in Fusion’s DESIGN workspace. This script will switch the UI from the DESIGN workspace to the MANUFACTURE workspace, create a new Manufacturing Model, and create an Additive Arrange using that manufacturing model as an input.
The setup will select an MJF 3D printer from Fusion’s machine library and a print setting from the print setting library. All components in the Manufacturing model will be automatically arranged within the build volume of the selected MJF machine.
import adsk.core, adsk.fusion, adsk.cam, traceback, tempfile, time app = adsk.core.Application.get() ui = app.userInterface # Global set of event handlers to keep them referenced for the duration of the command handlers = [] def createManufacturingModel(cam: adsk.cam.CAM): showMessage('=============================================') showMessage('Creating Manufacturing Model...') manufacturingModels = cam.manufacturingModels mmInput = manufacturingModels.createInput() mmInput.name = "My Manufacturing Model - MJF" manufacturingModel = manufa0cturingModels.add(mmInput) showMessage('Getting occurrences...') occs = getValidOccurrences(manufacturingModel.occurrence) if len(occs) == 0: ui.messageBox('No component has been added to the scene.') return (None, []) return (manufacturingModel, occs) # Create an additive setup. def createAdditiveSetup(models: list[adsk.fusion.Occurrence], cam: adsk.cam.CAM, libraryManager: adsk.cam.CAMLibraryManager): showMessage('Creating Setup...') setups = cam.setups input = setups.createInput(adsk.cam.OperationTypes.AdditiveOperation) input.models = models input.name = 'AdditiveSetup' printSettingLibrary = libraryManager.printSettingLibrary machineLibrary = libraryManager.machineLibrary printSetting = None machine = None if True: # URL-structure browsing printSettingUrl = printSettingLibrary.urlByLocation(adsk.cam.LibraryLocations.Fusion360LibraryLocation) ## .Fusion360LibraryLocation vs .LocalLibraryLocation etc. printSettings = printSettingLibrary.childPrintSettings(printSettingUrl) machineUrl = machineLibrary.urlByLocation(adsk.cam.LibraryLocations.Fusion360LibraryLocation) ## .Fusion360LibraryLocation vs .LocalLibraryLocation etc. machines = machineLibrary.childMachines(machineUrl) for ps in printSettings: if ps.name == "HP - MJF": #print setting name from fusions library printSetting = ps break for machine in machines: #model name from fusions library if machine.model == "Jet Fusion 5200": machine = machine break input.machine = machine input.printSetting= printSetting setup = setups.add(input) return setup def createAdditiveArrange(setup: adsk.cam.Setup, cam: adsk.cam.CAM): # Define and create the arrange operation. showMessage('Generating Additive Arrange...') operationInput = setup.operations.createInput('additive_arrange') arrange = setup.operations.add(operationInput) parameter: adsk.cam.StringParameterValue = arrange.parameters.itemByName("arrange_arrangement_type").value parameter.value = 'Pack3D_MC' parameter: adsk.cam.StringParameterValue = arrange.parameters.itemByName("arrange_priority_type").value parameter.value = 'priority_volume' # Specify the values to control the arrangement. All length units are centimeters. parameter: adsk.cam.FloatParameterValue = arrange.parameters.itemByName("arrange_platform_clearance").value parameter.value = 0.0 parameter: adsk.cam.FloatParameterValue = arrange.parameters.itemByName("arrange_frame_width").value parameter.value = 0.5 parameter: adsk.cam.FloatParameterValue = arrange.parameters.itemByName("arrange_ceiling_clearance").value parameter.value = 0.0 parameter: adsk.cam.FloatParameterValue = arrange.parameters.itemByName("arrange_object_spacing").value parameter.value = 0.5 parameter: adsk.cam.StringParameterValue = arrange.parameters.itemByName("arrange_mc_partRotation").value parameter.value = 'arbitrary' parameter: adsk.cam.BooleanParameterValue = arrange.parameters.itemByName("arrange_mc_startfromposition").value parameter.value = False future = cam.generateToolpath(arrange) while (future.isGenerationCompleted == False): time.sleep(0.5) # Event handler that reacts to when the command is executed. class MyCommandExecuteHandler(adsk.core.CommandEventHandler): def __init__(self): super().__init__() def notify(self, args): try: # Make sure the TEXT COMMAND palette is visible. textPalette = ui.palettes.itemById('TextCommands') if not textPalette.isVisible: textPalette.isVisible = True adsk.doEvents() doc = app.activeDocument products = doc.products # Make camWS = ui.workspaces.itemById('CAMEnvironment') camWS.activate() cam = adsk.cam.CAM.cast(products.itemByProductType("CAMProductType")) # Design creation designWS = ui.workspaces.itemById('FusionSolidEnvironment') designWS.activate() design = adsk.fusion.Design.cast(products.itemByProductType("DesignProductType")) camWS.activate() libraryManager = adsk.cam.CAMManager.get().libraryManager templateLibrary = libraryManager.templateLibrary # The block below is the gist of this script. # Each method can be edited to fit the user's needs. (manufacturingModel, occs) = createManufacturingModel(cam) if manufacturingModel is None: return setup: adsk.cam.Setup = createAdditiveSetup(occs, cam, libraryManager) machineElements = setup.machine.elements machineDimsList = machineElements.itemsByType(adsk.cam.AdditivePlatformMachineElement.staticTypeId()) machineDims: adsk.cam.AdditivePlatformMachineElement = machineDimsList[0] origin = machineDims.origin machineSize = machineDims.size maxPointX = - origin.x + machineSize.x createAdditiveArrange(setup, cam) ui.activeSelections.clear() ui.activeSelections.add(setup) app.activeViewport.fit() showMessage('Finished.') except: if ui: ui.messageBox('Failed:\n{}'.format(traceback.format_exc())) # Event handler that reacts to when the command is destroyed. This terminates the script if this has not happened before in an exception. class MyCommandDestroyHandler(adsk.core.CommandEventHandler): def __init__(self): super().__init__() def notify(self, args): try: # When the command is done, terminate the script showMessage('Script is terminating.') adsk.terminate() except: if ui: ui.messageBox('Failed:\n{}'.format(traceback.format_exc())) adsk.terminate() # Event handler that reacts when the command definition is executed which # results in the command being created and this event being fired. class MyCommandCreatedHandler(adsk.core.CommandCreatedEventHandler): def __init__(self): super().__init__() def notify(self, args): try: # Get the command that was created. cmd = adsk.core.Command.cast(args.command) onExecute = MyCommandExecuteHandler() cmd.execute.add(onExecute) handlers.append(onExecute) onDestroy = MyCommandDestroyHandler() cmd.destroy.add(onDestroy) handlers.append(onDestroy) except: if ui: ui.messageBox('Failed:\n{}'.format(traceback.format_exc())) def run(context): try: global app, ui # Get the existing command definition or create it if it doesn't already exist. cmdDef = ui.commandDefinitions.itemById('MJFExampleScript') if not cmdDef: cmdDef = ui.commandDefinitions.addButtonDefinition('MJFExampleScript', 'MJF Example Script', 'Sample to demonstrate a workflow for MJF printers.') # Connect to the command created event. onCommandCreated = MyCommandCreatedHandler() cmdDef.commandCreated.add(onCommandCreated) handlers.append(onCommandCreated) # Execute the command definition. cmdDef.execute() # Keeps the script alive until it is terminated by the onDestroy event. adsk.autoTerminate(False) except: if ui: ui.messageBox('Failed:\n{}'.format(traceback.format_exc())) # Given an occurrence, this finds all child occurrences that contain either a # B-Rep or Mesh body. It is recursive, so it will find all occurrences at all levels. def getValidOccurrences(occurrence: adsk.fusion.Occurrence) -> list[adsk.fusion.Occurrence]: result = [] for childOcc in occurrence.childOccurrences: if (childOcc.bRepBodies.count + childOcc.component.meshBodies.count > 0): result.append(childOcc) result.extend(getValidOccurrences(childOcc)) return result def showMessage(message): app.log(message) # Give control back to Fusion, so it can update the UI. adsk.doEvents()