///////////////////////////////////////////////////////////////////////////////////////////////// // For this sample script to run, the active Fusion document needs at least one CAM operation. // ///////////////////////////////////////////////////////////////////////////////////////////////// #include <Core/CoreAll.h> #include <CAM/CAMAll.h> #ifdef _WINDOWS #include <shlwapi.h> #else #include <stdlib.h> #endif using namespace adsk::core; using namespace adsk::cam; // Define a base class pointer for common usage. using CAMObjectPtr = Ptr<OperationBase>; // Function to ensure pathnames use forward slashes as required by the NC Program Output Folder. void replaceBackslashWithSlash(std::string& str) { for (char& ch : str) if (ch == '\\') ch = '/'; } // Customised messageBox to handle critical errors in one line void criticalError(Ptr<UserInterface> ui, const std::string& message) { ui->messageBox( message, "Critical Error", MessageBoxButtonTypes::OKButtonType, MessageBoxIconTypes::CriticalIconType); } extern "C" XI_EXPORT bool run(const char* context) { Ptr<Application> app = Application::get(); if (!app) return false; Ptr<UserInterface> ui = app->userInterface(); if (!ui) return false; Ptr<Document> doc = app->activeDocument(); if (!doc) return false; Ptr<Products> products = doc->products(); if (!products) return false; // Check if the document has a CAMProductType, abandon cleanly if not. std::string operationErrorMsg = "This script requires the active document to contain at least one CAM operation."; Ptr<CAM> camProduct = products->itemByProductType("CAMProductType"); if (!camProduct) { criticalError(ui, operationErrorMsg); return false; } // Initialize the CAM manager to access the library manager and the post processor library. Ptr<CAMManager> camManager = CAMManager::get(); Ptr<CAMLibraryManager> libraryManager = camManager->libraryManager(); Ptr<PostLibrary> postLibrary = libraryManager->postLibrary(); // Create a query to filter post processors from the Fusion library by the vendor "Autodesk". Ptr<PostConfigurationQuery> postQuery = postLibrary->createQuery(LibraryLocations::Fusion360LibraryLocation); postQuery->vendor("Autodesk"); // Set the post configuration to use based on Operation Type of the first Setup. Ptr<Setup> setup; Ptr<Setups> setups = camProduct->setups(); if (setups) { setup = setups->item(0); if (!setup) { criticalError(ui, operationErrorMsg); return false; } } OperationTypes opType = setup->operationType(); switch (opType) { case adsk::cam::MillingOperation: postQuery->capability(adsk::cam::PostCapabilities::Milling); break; case adsk::cam::TurningOperation: postQuery->capability(adsk::cam::PostCapabilities::Turning); break; case adsk::cam::JetOperation: postQuery->capability(adsk::cam::PostCapabilities::Jet); break; default: postQuery->capability(adsk::cam::PostCapabilities::Milling); break; } std::vector<Ptr<PostConfiguration>> postConfigs = postQuery->execute(); Ptr<URL> importedURL; std::string ncExtension; std::string postRequired = "RS-274D"; std::string postDescription = ""; // Find the required post in the post library and import it to local library. for (Ptr<PostConfiguration>& config : postConfigs) { if (config->description() == postRequired) { postDescription = postRequired; ncExtension = config->extension(); Ptr<URL> configUrl = URL::create("user://"); importedURL = postLibrary->importPostConfiguration(config, configUrl, "NCProgramSamplePost.cps"); break; } } // Check if the required post was found, abandon cleanly if not. if (postDescription.empty()) { criticalError(ui, "Unable to find postprocessor " + postRequired + "."); return false; } // Get the imported local post config. Ptr<PostConfiguration> postConfig = postLibrary->postConfigurationAtURL(importedURL); // Prompt the user with an option to view the resulting NC file. DialogResults dlgResults = ui->messageBox( "View nc file when done?", "Post-processing", MessageBoxButtonTypes::YesNoButtonType, MessageBoxIconTypes::QuestionIconType); bool viewResult = (dlgResults == DialogResults::DialogYes); // Create NCProgramInput object Ptr<NCProgramInput> ncInput = camProduct->ncPrograms()->createInput(); // Set the value of scenario to 1, 2 or 3 to post all, post the first setup, // or post only the first operation of the first setup. int scenario = 1; std::string message = "Yes \t- All toolpaths will be posted.\n\n" "No \t- Toolpaths in the first setup will be posted.\n\n" "Cancel\t- The first toolpath in the first setup will be posted.\n"; // Spaces appended to the title make the messageBox wider, preventing linw wrapping. DialogResults mbChoice = ui->messageBox( message, "Select what should be post-processed ", MessageBoxButtonTypes::YesNoCancelButtonType, MessageBoxIconTypes::QuestionIconType); if (mbChoice == DialogResults::DialogYes) { scenario = 1; } else if (mbChoice == DialogResults::DialogNo) { scenario = 2; } else { scenario = 3; } // Adjust NC program parameters. ncInput->displayName("Sample NCProgram"); Ptr<CAMParameters> ncParameters = ncInput->parameters(); Ptr<StringParameterValue> nc_program_filename = ncParameters->itemByName("nc_program_filename")->value(); // Embelish the nc filename to indicate chosen scenario and programming language. std::string programName = "NCProgramSampleCPP" + std::to_string(scenario); nc_program_filename->value(programName); // Provide a comment at the top of the file. Ptr<StringParameterValue> nc_program_comment = ncParameters->itemByName("nc_program_comment")->value(); std::string comment = "This is the Post Toolpaths API Sample NC Program"; nc_program_comment->value(comment); // Open nc file in editor if earlier requested. Ptr<BooleanParameterValue> nc_program_openInEditor = ncParameters->itemByName("nc_program_openInEditor")->value(); nc_program_openInEditor->value(viewResult); // Set temp directory as output directory. std::string outputFolder = camProduct->temporaryFolder(); // Variable outputFolder may contain backslashes but we need forward slashes. replaceBackslashWithSlash(outputFolder); Ptr<StringParameterValue> nc_program_output_folder = ncParameters->itemByName("nc_program_output_folder")->value(); nc_program_output_folder->value(outputFolder); // We have already declared a setups Ptr for all 3 scenarios. // Scenarios 2 and 3 use firstSetup. Ptr<Setup> firstSetup = setups->item(0); switch (scenario) { case 1: { // ncInput->operations() expects a list of type 'OperationBase'. // For example: Operation, CAMFolder, CAMPattern, Setup. // It will not accept CAMFolders, CAMPatterns or Setups (all plural) // as they are derived from core.Base. We make our own list instead. // Create a vector for the content of core.Base objects. std::vector<CAMObjectPtr> camObjects; for (size_t i = 0; i < setups->count(); ++i) { // Add the operation to the operations list. camObjects.push_back(setups->item(i)); } ncInput->operations({camObjects}); // Include all setups break; } case 2: { ncInput->operations({firstSetup}); // Only include the first setup break; } case 3: { Ptr<Operation> firstOperation = firstSetup->allOperations()->item(0); if (firstOperation->hasToolpath()) { ncInput->operations({firstOperation}); // First operation of first setup } else { criticalError(ui, "Operation has no toolpath to post"); return false; } break; } } // Create a new NC program using NC Program input and specified parameters and operations. Ptr<NCProgram> newProgram = camProduct->ncPrograms()->add(ncInput); // Configure the post processor newProgram->postConfiguration(postConfig); // Example of changing a post parameter. Parameters need to be declared as their correct type. Ptr<CAMParameters> postParams = newProgram->postParameters(); // Parameter builtin_tolerance is of Type FloatParameterValue. Ptr<FloatParameterValue> builtInTolerance = postParams->itemByName("builtin_tolerance")->value(); // Demonstrating how to check current parameter value and modify it. std::string previous = "Previous builtin_tolerance: " + std::to_string(builtInTolerance->value()); builtInTolerance->value(0.004); app->log(previous + "\tNew value: " + std::to_string(builtInTolerance->value())); // The next assignment returns null if you use a post-processor that does not support // block numbering - for example "XYZ" or "Generic 2D", however you will not need it in that case. Ptr<CAMParameter> showSequenceNumbersParam = postParams->itemByName("showSequenceNumbers"); if (showSequenceNumbersParam) { // Parameter showSequenceNumbers is of type ChoiceParameterValue so "false" is a string not a boolean. Ptr<ChoiceParameterValue> showSequenceNumbers = postParams->itemByName("showSequenceNumbers")->value(); // Demonstrating how to check current parameter value and modify it. previous = "Previous showSequenceNumbers: " + showSequenceNumbers->value(); showSequenceNumbers->value("false"); app->log(previous + "\tNew value: " + showSequenceNumbers->value()); } // Update to apply changes. newProgram->updatePostParameters(postParams); // Finally post the process. Ptr<NCProgramPostProcessOptions> postOptions = adsk::cam::NCProgramPostProcessOptions::create(); newProgram->postProcess(postOptions); // Activate CAM workspace if it is not the active one. if (ui->activeWorkspace()->name() != "Manufacture") { DialogResults result = ui->messageBox( "Activate the CAM Workspace?", "CAM Workspace Activate", MessageBoxButtonTypes::YesNoButtonType, MessageBoxIconTypes::QuestionIconType); if (result == DialogResults::DialogYes) { Ptr<Workspace> camWorkspace = ui->workspaces()->itemById("CAMEnvironment"); camWorkspace->activate(); } } // Indicate completion. ui->messageBox( "Post processing is complete. See file:\n" + outputFolder + "/" + programName + ncExtension, "Post Toolpath API Sample \t\t\t\t\t"); // Prevent line breaks return true; }
# For this sample script to run, the active Fusion document needs at least one CAM operation. import adsk.core, adsk.fusion, adsk.cam, traceback app = adsk.core.Application.get() ui = app.userInterface def criticalError(message:str): ''' Customised messageBox to handle critical errors in one line ''' ui.messageBox( message, 'Critical Error', adsk.core.MessageBoxButtonTypes.OKButtonType, adsk.core.MessageBoxIconTypes.CriticalIconType) def run(context): try: doc: adsk.core.Document = app.activeDocument products: adsk.core.Products = doc.products try: product: adsk.core.Product = products.itemByProductType('CAMProductType') except Exception: product = None # Check if the document has a CAMProductType, abandon cleanly if not. operationErrorMsg = 'This script requires the active document to contain at least one CAM operation.' if product == None: criticalError(operationErrorMsg) return cam = adsk.cam.CAM.cast(product) # Initialize the CAM manager to access the library manager and the post processor library. camManager = adsk.cam.CAMManager.get() libraryManager: adsk.cam.CAMLibraryManager = camManager.libraryManager postLibrary: adsk.cam.PostLibrary = libraryManager.postLibrary # Create a query to filter post processors from the Fusion library by the vendor "Autodesk". postQuery: adsk.cam.PostConfigurationQuery = \ postLibrary.createQuery(adsk.cam.LibraryLocations.Fusion360LibraryLocation) postQuery.vendor = "Autodesk" # Set the post configuration to use based on Operation Type of the first Setup. try: firstSetupOperationType: adsk.cam.OperationTypes = cam.setups.item(0).operationType except: criticalError(operationErrorMsg) return if firstSetupOperationType == adsk.cam.OperationTypes.MillingOperation: postQuery.capability = adsk.cam.PostCapabilities.Milling elif firstSetupOperationType == adsk.cam.OperationTypes.TurningOperation: postQuery.capability = adsk.cam.PostCapabilities.Turning elif firstSetupOperationType == adsk.cam.OperationTypes.JetOperation: postQuery.capability = adsk.cam.PostCapabilities.Jet postConfigs: list[adsk.cam.PostConfiguration] = postQuery.execute() # Check for post configs being available. if len(postConfigs) == 0: criticalError('No post-configurations found.') return # Find the post required in the post library and import it to local library. postRequired = "RS-274D" postDescription = None for config in postConfigs: if config.description == postRequired: postDescription = postRequired ncExtension = config.extension url = adsk.core.URL.create("user://") importedURL = postLibrary.importPostConfiguration(config, url, "NCProgramSamplePost.cps") break # Check if the required post was found, abandon cleanly if not. if not postDescription: criticalError(f'Unable to find postprocessor {postRequired}.') return # Get the imported local post config. postConfig: adsk.cam.PostConfiguration = postLibrary.postConfigurationAtURL(importedURL) # Prompt the user with an option to view the resulting NC file. dlgResults: adsk.core.DialogResults = ui.messageBox( 'View results when post is complete?', 'Post-processing', adsk.core.MessageBoxButtonTypes.YesNoButtonType, adsk.core.MessageBoxIconTypes.QuestionIconType) viewResult: bool = (dlgResults == adsk.core.DialogResults.DialogYes) # Create ncInput object. ncInput: adsk.cam.NCProgramInput = cam.ncPrograms.createInput() # Set the value of scenario to 1, 2 or 3 to post all, post the first setup, # or post only the first operation of the first setup. scenario = 1 # Spaces appended to the title make the messageBox wider, preventing linw wrapping. mbChoice: adsk.core.DialogResults = ui.messageBox( "Yes \t- All toolpaths will be posted.\n\n" \ "No \t- Toolpaths in the first setup will be posted.\n\n" \ "Cancel\t- The first toolpath in the first setup will be posted.\n", "Select what should be post-processed ", adsk.core.MessageBoxButtonTypes.YesNoCancelButtonType, adsk.core.MessageBoxIconTypes.QuestionIconType) if (mbChoice == adsk.core.DialogResults.DialogYes): scenario = 1 elif (mbChoice == adsk.core.DialogResults.DialogNo): scenario = 2 else: scenario = 3 # Adjust NC program parameters. ncInput.displayName = 'Sample NCProgram' # Embelish the nc filename to indicate chosen scenario and programming language. programName:str = f'NCProgramSamplePy{scenario}' programfilename: adsk.cam.CAMParameter = ncInput.parameters.itemByName('nc_program_filename') programfilename.value.value = programName # Provide a comment at the top of the file. comment: adsk.cam.CAMParameter = ncInput.parameters.itemByName('nc_program_comment') comment.value.value = "This is the Post Toolpaths API Sample NC Program" # Open nc file in editor if earlier requested. openInEditor: adsk.cam.CAMParameter = ncInput.parameters.itemByName('nc_program_openInEditor') openInEditor.value.value = viewResult # Set temp directory as output directory # Make the path valid for Fusion by replacing \\ to / in the path outputFolder = str(cam.temporaryFolder).replace('\\', '/') ncInput.parameters.itemByName('nc_program_output_folder').value.value = outputFolder if scenario == 1: # ncInput.operations() expects a list of type 'OperationsBase': Operation, CAMFolder, CAMPattern, Setup # It will not accept CAMFolders, CAMPatterns or Setups (all plural) as they are derived from core.Base opsBaseList: list[adsk.cam.OperationBase] = [] setups: adsk.cam.Setups = cam.setups for setup in setups: opsBaseList.append(setup) ncInput.operations = opsBaseList # Include all setups elif scenario == 2: ncInput.operations = [cam.setups.item(0)] # Only include the first setup elif scenario == 3: firstSetup: adsk.cam.Setup = cam.setups.item(0) firstOperation: adsk.core.Base = firstSetup.allOperations.item(0) if firstOperation.hasToolpath: ncInput.operations = [firstOperation] # Only include the first operation of the first setup else: ui.messageBox('Operation has no toolpath to post') return # Create a new NC program using the current NC Program input including specified parameters and operations newProgram: adsk.cam.NCProgram = cam.ncPrograms.add(ncInput) # Configure the post processor newProgram.postConfiguration = postConfig # Example of changing a post parameter. Parameters need to be declared as their correct type. postParams: adsk.cam.CAMParameters = newProgram.postParameters # Parameter builtin_tolerance is of Type FloatParameterValue. builtInTolerance: adsk.cam.FloatParameterValue = postParams.itemByName('builtin_tolerance') builtInTolerance.value.value = 0.004 # Parameter showSequenceNumbers is of type ChoiceParameterValue so "false" is a string not a boolean. showSequenceNumbers: adsk.cam.ChoiceParameterValue = postParams.itemByName('showSequenceNumbers') # Not all posts support SequenceNumbers if showSequenceNumbers: showSequenceNumbers.value.value = str('false') else: criticalError(f'Parameter showSequenceNumbers cannot be modified for postprocessor: {postRequired} - skipping!') # Update to apply changes. newProgram.updatePostParameters(postParams) # Finally post the process. postOptions = adsk.cam.NCProgramPostProcessOptions.create() newProgram.postProcess(postOptions) # Prompt user with an option to switch to the CAM workspace if it's not already active if ui.activeWorkspace.name != 'Manufacture': activateCAMWorkspace: adsk.core.DialogResults = ui.messageBox( f'Activate the CAM Workspace?','CAM Workspace Activate', adsk.core.MessageBoxButtonTypes.YesNoButtonType, adsk.core.MessageBoxIconTypes.QuestionIconType) if activateCAMWorkspace == adsk.core.DialogResults.DialogYes: camWorkspace: adsk.core.Workspace = ui.workspaces.itemById("CAMEnvironment") camWorkspace.activate() # Indicate completion. ui.messageBox(f'See file:\n{outputFolder}/{programName}{ncExtension}', 'Post processing is complete \t\t\t\t\t'); # Prevent line breaks of the pathname except: if ui: ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))