Demonstrates creating a setup, searching tool library to retrieve a tool, create a couple of machining operations and a NC program, ready for post processing.
Use the 2D Strategies model from the Fusion CAM Samples folder as your CAD model.
/** * Basic Milling Workflow Sample * Demonstrates the creation of a basic milling workflow from script Demonstrates creating a setup, searching tool library to retrieve a tool, create a couple of machining operations and a NC program, ready for post proc... */ import { adsk } from '@adsk/fusion'; function run() { // Initialisation const app = adsk.core.Application.get(); if (!app) throw new Error("No adsk.core.Application."); const ui = app.userInterface; if (!ui) throw new Error("No userInterface available."); const PROJECT_URN = 'urn:adsk.wipprod:fs.file:vf.KoBHzV4mTOiNvFStiBwpzA?version=1'; // Production // Load by URN a specific sample project to demonstrate a basic milling workflow. const doc = loadProjectFromURN(PROJECT_URN); if (!doc) return; // Switch to manufacturing space const camWS = ui.workspaces.itemById('CAMEnvironment'); if (!camWS) throw new Error("CAMEnvironment workspace not found."); camWS.activate(); // Get the CAM product const products = doc.products; /////////// Find Tools in Sample Tool Library /////////// // Get the tool libraries from the library manager const camManager = adsk.cam.CAMManager.get(); if (!camManager) throw new Error("No CAMManager available."); const libraryManager = camManager.libraryManager; if (!libraryManager) throw new Error("No CAMLibraryManager available."); const toolLibraries = libraryManager.toolLibraries; if (!toolLibraries) throw new Error("No ToolLibraries available."); // Use Fusion's Metric sample library directly via URL const url = adsk.core.URL.create('systemlibraryroot://Samples/Milling Tools (Metric).json'); const toolLibrary = toolLibraries.toolLibraryAtURL(url); if (!toolLibrary) throw new Error("Sample tool library not found."); let faceTool: adsk.cam.Tool | null = null; let adaptiveTool: adsk.cam.Tool | null = null; // Search for face mill and bull nose end mill for (let i = 0; i < toolLibrary.count; i++) { const tool = toolLibrary.item(i); const toolType = (<adsk.cam.StringParameterValue>(tool.parameters.itemByName("tool_type")?.value)).value; if (toolType === 'face mill' && !faceTool) { faceTool = tool; } else if (toolType === 'bull nose end mill' && !adaptiveTool) { // Look for a bull nose end mill tool >= 10mm but < 14mm const diameter = (<adsk.cam.FloatParameterValue>(tool.parameters.itemByName("tool_diameter")?.value)).value; if (diameter >= 1.0 && diameter < 1.4) { adaptiveTool = tool; } } if (faceTool && adaptiveTool) break; } if (!faceTool) throw new Error("No face mill tool found in library."); if (!adaptiveTool) throw new Error("No bull nose end mill tool found in library."); /////////// Create Setup /////////// const cam = products.itemByProductType("CAMProductType") as adsk.cam.CAM; if (!cam) throw new Error("No CAM product found."); const setups = cam.setups; const setupInput = setups.createInput(adsk.cam.OperationTypes.MillingOperation); const part = cam.designRootOccurrence.bRepBodies.item(0); if (!part) { adsk.log('No part found in the current document, exiting sample script.'); return; } setupInput.models = [part]; const setup = setups.add(setupInput); setup.name = 'CAM Basic Script Sample'; setup.stockMode = adsk.cam.SetupStockModes.RelativeBoxStock; // Set offset mode const stockOffsetMode = setup.parameters.itemByName('job_stockOffsetMode'); if (stockOffsetMode) stockOffsetMode.expression = "'simple'"; // Set offset stock side const stockOffsetSides = setup.parameters.itemByName('job_stockOffsetSides'); if (stockOffsetSides) stockOffsetSides.expression = '0 mm'; // Set offset stock top const stockOffsetTop = setup.parameters.itemByName('job_stockOffsetTop'); if (stockOffsetTop) stockOffsetTop.expression = '2 mm'; // Set setup origin const wcsOriginBoxPoint = setup.parameters.itemByName('wcs_origin_boxPoint'); if (wcsOriginBoxPoint) (<adsk.cam.StringParameterValue>wcsOriginBoxPoint.value).value = 'top 1'; /////////// Face Operation /////////// const faceInput = setup.operations.createInput('face'); faceInput.tool = faceTool; faceInput.displayName = 'Face Operation'; const faceTolerance = faceInput.parameters.itemByName('tolerance'); if (faceTolerance) faceTolerance.expression = '0.01 mm'; const faceStepover = faceInput.parameters.itemByName('stepover'); if (faceStepover) faceStepover.expression = '0.75 * tool_diameter'; const faceDirection = faceInput.parameters.itemByName('direction'); if (faceDirection) faceDirection.expression = "'climb'"; const faceOp = setup.operations.add(faceInput); /////////// Adaptive Operation /////////// const adaptiveInput = setup.operations.createInput('adaptive'); adaptiveInput.tool = adaptiveTool; adaptiveInput.displayName = 'Adaptive Roughing'; const adaptiveTolerance = adaptiveInput.parameters.itemByName('tolerance'); if (adaptiveTolerance) adaptiveTolerance.expression = '0.1 mm'; const adaptiveMaxStepdown = adaptiveInput.parameters.itemByName('maximumStepdown'); if (adaptiveMaxStepdown) adaptiveMaxStepdown.expression = '5 mm'; const adaptiveFineStepdown = adaptiveInput.parameters.itemByName('fineStepdown'); if (adaptiveFineStepdown) adaptiveFineStepdown.expression = '0.25 * maximumStepdown'; const adaptiveFlatArea = adaptiveInput.parameters.itemByName('flatAreaMachining'); if (adaptiveFlatArea) adaptiveFlatArea.expression = 'false'; const adaptiveOp = setup.operations.add(adaptiveInput); /////////// Generate Operations /////////// // Kick off both generations; hold a future for the last one to poll cam.generateToolpath(faceOp); const genFuture = cam.generateToolpath(adaptiveOp); /////////// NC Program and Post-processing /////////// // Get the post library from library manager const postLibrary = libraryManager.postLibrary; const postQuery = postLibrary.createQuery(adsk.cam.LibraryLocations.Fusion360LibraryLocation); postQuery.vendor = "Autodesk"; postQuery.capability = adsk.cam.PostCapabilities.Milling; const postConfigs = postQuery.execute(); // Find the "XYZ" post in the post library and import it to local library let ncExtension = ''; let importedURL: adsk.core.URL | null = null; for (const config of postConfigs) { if (config.description === 'XYZ') { ncExtension = config.extension; const userURL = adsk.core.URL.create("user://"); importedURL = postLibrary.importPostConfiguration(config, userURL, "NCProgramSamplePost.cps"); break; } } if (!importedURL) throw new Error('XYZ post processor not found.'); const postConfig = postLibrary.postConfigurationAtURL(importedURL); if (!postConfig) throw new Error('Failed to get imported post configuration.'); // Create NCProgramInput object const ncInput: adsk.cam.NCProgramInput = cam.ncPrograms.createInput(); ncInput.displayName = 'NC Program Sample'; // Change nc program parameters const ncFilename = 'NCProgramSample'; const ncParameters: adsk.cam.CAMParameters = ncInput.parameters; (<adsk.cam.StringParameterValue>(ncParameters.itemByName("nc_program_filename")?.value)).value = ncFilename; (<adsk.cam.BooleanParameterValue>(ncParameters.itemByName("nc_program_openInEditor")?.value)).value = false; (<adsk.cam.StringParameterValue>(ncParameters.itemByName("nc_program_nc_extension")?.value)).value = ncExtension; // Set temp directory as output directory; replace backslashes for cross-platform safety const outputFolder = String(cam.temporaryFolder).replace(/\\/g, '/'); (<adsk.cam.StringParameterValue>(ncParameters.itemByName("nc_program_output_folder")?.value)).value = outputFolder; // Select the operations to post ncInput.operations = [faceOp, adaptiveOp]; // Add a new NC program from the NC program input const newProgram: adsk.cam.NCProgram = cam.ncPrograms.add(ncInput); // Set post processor newProgram.postConfiguration = postConfig; // Change some post parameters (passed without units to the postprocessor) const postParameters: adsk.cam.CAMParameters = newProgram.postParameters; (<adsk.cam.FloatParameterValue>(postParameters.itemByName("builtin_tolerance")?.value)).value = 0.01; (<adsk.cam.FloatParameterValue>(postParameters.itemByName("builtin_minimumChordLength")?.value)).value = 0.33; // Apply updated post parameters newProgram.updatePostParameters(postParameters); // Set post options (by default, only valid operations with toolpath data are post-processed) const postOptions = adsk.cam.NCProgramPostProcessOptions.create(); if (!postOptions) throw new Error("Failed to create NCProgramPostProcessOptions."); // Ensure toolpaths are visible before post-processing faceOp.isLightBulbOn = true; adaptiveOp.isLightBulbOn = true; // Wait for toolpath generation to complete before post-processing while (!genFuture.isGenerationCompleted) { wait(1000); } newProgram.postProcess(postOptions); // Wait for the post-process job to finish before script exits. // Without this wait loop, Fusion detects the active NC export job and enters // an infinite "Active job(s) detected" wait loop (FUS-216058). while (app.hasActiveJobs) { wait(4000); } wait(5000); adsk.log(`The results have been written to: ${outputFolder}/${ncFilename}${ncExtension}`); } function loadProjectFromURN(urn?: string): adsk.core.Document | null { let doc: adsk.core.Document | null = null; const app = adsk.core.Application.get(); if (!app) throw new Error('No adsk.core.Application.'); if (urn) { try { const project = app.data.findFileById(urn); if (project) { doc = app.documents.open(project, true); } else { adsk.log(`File not found for URN: ${urn}!`); } } catch (e: any) { if (String(e).startsWith('3 : Design is located in another team.')) { if (!doc) { doc = app.activeDocument; } } else if (String(e).startsWith('3 : file not found')) { adsk.log(`File not found for URN: ${urn}!`); } else { adsk.log(`Failed: ${String(e)}`); } } } return doc; } function wait(ms: number) { const start = new Date().getTime(); while (new Date().getTime() - start < ms) adsk.doEvents(); } run();
#include <Core/CoreAll.h>
#include <Fusion/FusionAll.h>
#include <Cam/CamAll.h>
#include <chrono>
#include <thread>
#include <algorithm>
#ifdef _WINDOWS
#include <shlwapi.h>
#else
#include <stdlib.h>
#endif
using namespace adsk::core;
using namespace adsk::fusion;
using namespace adsk::cam;
extern "C" XI_EXPORT bool run(const char* context)
{
// Initialisation
Ptr<Application> app = Application::get();
Ptr<UserInterface> ui = app->userInterface();
Ptr<Document> doc = nullptr;
// Load by URN a specific sample project to demonstrate a basic milling workflow.
std::string urn = "urn:adsk.wipprod:fs.file:vf.KoBHzV4mTOiNvFStiBwpzA?version=1"; // Production
// Load 2D Strategies model from the Fusion CAM Samples folder
Ptr<DataFile> sampleFile = app->data()->findFileById(urn);
if (sampleFile)
{
doc = app->documents()->open(sampleFile, true);
}
// Did we find our document?
if (!doc)
{
ui->messageBox("Sample file not found, using the current document.", "", MessageBoxButtonTypes::OKButtonType);
// Use existing document, load 2D Strategies model from the Fusion CAM Samples folder
doc = app->activeDocument();
}
// Switch to manufacturing space
Ptr<Workspace> camWS = ui->workspaces()->itemById("CAMEnvironment");
camWS->activate();
Ptr<Products> products = doc->products();
if (!products)
return false;
// Check if the document has a CAMProductType. It will return if there are no CAM operations in it.
Ptr<CAM> camProduct = products->itemByProductType("CAMProductType");
if (!camProduct)
{
ui->messageBox(
"There are no CAM operations in the active document. This script requires the active document to contain "
"at least one CAM operation.",
"No CAM Operations Exist",
MessageBoxButtonTypes::OKButtonType,
MessageBoxIconTypes::CriticalIconType);
return false;
}
// Find tools in sample tool library
// Get the tool libraries from the library manager
Ptr<CAMManager> camManager = CAMManager::get();
Ptr<CAMLibraryManager> libraryManager = camManager->libraryManager();
Ptr<ToolLibraries> toolLibraries = libraryManager->toolLibraries();
// We can use a library URl directly if we know its address (here we use Fusion"s Metric sample library)
Ptr<URL> toolLibraryUrl = URL::create("systemlibraryroot://Samples/Milling Tools (Metric).json");
// Load tool library
Ptr<ToolLibrary> toolLibrary = toolLibraries->toolLibraryAtURL(toolLibraryUrl);
if (!toolLibrary)
{
ui->messageBox("Failed to load tool library");
return false;
}
// Create some variables for the milling tools which will be used in the operations
Ptr<Tool> faceTool = nullptr;
Ptr<Tool> adaptiveTool = nullptr;
// Searching the face mill and the bull nose using a loop for the roughing operations
for (Ptr<Tool>& tool : toolLibrary)
{
// Read the tool type
Ptr<ChoiceParameterValue> toolTypeParameter = tool->parameters()->itemByName("tool_type")->value();
std::string toolType = toolTypeParameter->value();
// Select the first face tool found
if (toolType == "face mill" && !faceTool)
{
faceTool = tool;
}
// Search the roughing tool
else if (toolType == "bull nose end mill" && !adaptiveTool)
{
// We look for a bull nose end mill tool larger or equal to 10mm but less than 14mm
Ptr<FloatParameterValue> diameterParameter = tool->parameters()->itemByName("tool_diameter")->value();
double diameter = diameterParameter->value();
if (diameter >= 1.0 && diameter < 1.4)
{
adaptiveTool = tool;
}
}
// Exit when the 2 tools are found
if (faceTool && adaptiveTool)
{
break;
}
}
if (!faceTool)
{
ui->messageBox("No face mill tool found");
return false;
}
if (!adaptiveTool)
{
ui->messageBox("No bull nose end mill tool found");
return false;
}
// Create setup
Ptr<CAM> cam = products->itemByProductType("CAMProductType");
Ptr<Setups> setups = cam->setups();
Ptr<SetupInput> setupInput = setups->createInput(OperationTypes::MillingOperation);
// Create a list for the models to add to the setup Input
std::vector<Ptr<Base>> models;
Ptr<BRepBody> part = cam->designRootOccurrence()->bRepBodies()->item(0);
if (!part)
{
ui->messageBox(
"No part found in the current document, exiting sample script.", "", MessageBoxButtonTypes::OKButtonType);
return false;
}
// Add the part to the model list
models.push_back(part);
// Pass the model list to the setup input
setupInput->models(models);
// Create the setup
Ptr<Setup> setup = setups->add(setupInput);
// Change some properties of the setup
setup->name() = "CAM Basic Script Sample";
setup->stockMode(SetupStockModes::RelativeBoxStock);
// Set offset mode
setup->parameters()->itemByName("job_stockOffsetMode")->expression("'simple'");
// Set offset stock side
setup->parameters()->itemByName("job_stockOffsetSides")->expression("0 mm");
// Set offset stock top
setup->parameters()->itemByName("job_stockOffsetTop")->expression("2 mm");
// Set setup origin
Ptr<ChoiceParameterValue> wcs_origin_boxPoint = setup->parameters()->itemByName("wcs_origin_boxPoint")->value();
wcs_origin_boxPoint->value("top 1");
// Face operation
// Create a face operation input
Ptr<OperationInput> faceInput = setup->operations()->createInput("face");
faceInput->tool(faceTool);
faceInput->displayName("Face Operation");
faceInput->parameters()->itemByName("tolerance")->expression("0.01 mm");
faceInput->parameters()->itemByName("stepover")->expression("0.75 * tool_diameter");
faceInput->parameters()
->itemByName("direction")
->expression("'climb'"); // Must be single quotes inside double quotes
// Add the operation to the setup
Ptr<Operation> faceOp = setup->operations()->add(faceInput);
// Adaptive operation
Ptr<OperationInput> adaptiveInput = setup->operations()->createInput("adaptive");
adaptiveInput->tool(adaptiveTool);
adaptiveInput->displayName("Adaptive Roughing");
adaptiveInput->parameters()->itemByName("tolerance")->expression("0.1 mm");
adaptiveInput->parameters()->itemByName("maximumStepdown")->expression("5 mm");
adaptiveInput->parameters()->itemByName("fineStepdown")->expression("0.25 * maximumStepdown");
adaptiveInput->parameters()->itemByName("flatAreaMachining")->expression("false");
// Add the operation to the setup
Ptr<Operation> adaptiveOp = setup->operations()->add(adaptiveInput);
// Generate operations
cam->generateToolpath(faceOp);
Ptr<GenerateToolpathFuture> genFuture = cam->generateToolpath(adaptiveOp);
// ncProgram and post-processing
// Get the post library from library manager
Ptr<PostLibrary> postLibrary = libraryManager->postLibrary();
// Query post library to get postprocessor list
Ptr<PostConfigurationQuery> postQuery = postLibrary->createQuery(LibraryLocations::Fusion360LibraryLocation);
postQuery->vendor("Autodesk");
postQuery->capability(PostCapabilities::Milling);
std::vector<Ptr<PostConfiguration>> postConfigs = postQuery->execute();
Ptr<URL> importedURL;
std::string ncExtension;
// Find the "XYZ" post in the post library and import it to local library
for (Ptr<PostConfiguration>& config : postConfigs)
{
if (config->description() == "XYZ")
{
ncExtension = config->extension();
Ptr<URL> configUrl = URL::create("user://");
importedURL = postLibrary->importPostConfiguration(config, configUrl, "NCProgramSamplePost.cps");
break;
}
}
// Get the imported local post config
Ptr<PostConfiguration> postConfig = postLibrary->postConfigurationAtURL(importedURL);
// Create NCProgramInput object
Ptr<NCProgramInput> ncInput = cam->ncPrograms()->createInput();
ncInput->displayName("NC Program Sample");
// Change some nc program parameters...
Ptr<CAMParameters> ncParameters = ncInput->parameters();
Ptr<StringParameterValue> nc_program_filename = ncParameters->itemByName("nc_program_filename")->value();
nc_program_filename->value("NCProgramSample");
Ptr<BooleanParameterValue> nc_program_openInEditor = ncParameters->itemByName("nc_program_openInEditor")->value();
nc_program_openInEditor->value(true);
// Set temp directory as output directory
std::string outputFolder = cam->temporaryFolder();
// Variable outputFolder may contain backslashes but nc_program_output_folder requires forward slashes
std::replace_if(
outputFolder.begin(), outputFolder.end(), [](char ch) { return ch == '\\'; }, '/');
Ptr<StringParameterValue> nc_program_output_folder = ncParameters->itemByName("nc_program_output_folder")->value();
nc_program_output_folder->value(outputFolder);
// Select the operations to generate (we skip steep_and_shallow here)
ncInput->operations({faceOp, adaptiveOp});
// Add a new ncprogram from the ncprogram input
Ptr<NCProgram> newProgram = cam->ncPrograms()->add(ncInput);
// Set post processor
newProgram->postConfiguration(postConfig);
// Change some post parameter
Ptr<CAMParameters> postParameters = newProgram->postParameters();
// NcProgram parameters are passed without units to the postprocessor
Ptr<FloatParameterValue> builtin_tolerance = postParameters->itemByName("builtin_tolerance")->value();
builtin_tolerance->value(0.01);
Ptr<FloatParameterValue> builtin_minimumChordLength =
postParameters->itemByName("builtin_minimumChordLength")->value();
builtin_minimumChordLength->value(0.33);
// Update/apply post parameters
newProgram->updatePostParameters(postParameters);
// Post-process
// Set post options, by default post process only valid operations containing toolpath data
Ptr<NCProgramPostProcessOptions> postOptions = NCProgramPostProcessOptions::create();
// Ensure toolpaths are visible
faceOp->isLightBulbOn(true);
adaptiveOp->isLightBulbOn(true);
// To avoid errors, post-process only when toolpath generation has completed
if (!genFuture)
return false;
while (!genFuture->isGenerationCompleted())
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
newProgram->postProcess(postOptions);
// Advise where the NC file is located to indicate completion
ui->messageBox(
"The result has been written to:\n" + outputFolder + "/" + nc_program_filename->value() + ncExtension,
"Post processing is complete \t\t\t\t\t");
return true;
}
import adsk.core, adsk.fusion, adsk.cam, traceback
import time
def run(context):
ui = None
try:
#################### Initialisation #####################
app = adsk.core.Application.get()
ui = app.userInterface
PROJECT_URN = 'urn:adsk.wipprod:fs.file:vf.KoBHzV4mTOiNvFStiBwpzA?version=1' # Production
# Load by URN a specific sample project to demonstrate a basic milling workflow.
doc = loadProjectFromURN(PROJECT_URN)
if doc is None:
return
# Switch to manufacturing space
camWS: adsk.core.Workspace = ui.workspaces.itemById('CAMEnvironment')
camWS.activate()
# Get the CAM product
products: adsk.core.Products = doc.products
#################### Find tools in sample tool library ####################
# Get the tool libraries from the library manager
camManager = adsk.cam.CAMManager.get()
libraryManager: adsk.cam.CAMLibraryManager = camManager.libraryManager
toolLibraries: adsk.cam.ToolLibraries = libraryManager.toolLibraries
# We can use a library URl directly if we know its address (here we use Fusion's Metric sample library)
url = adsk.core.URL.create('systemlibraryroot://Samples/Milling Tools (Metric).json')
# Load tool library
toolLibrary: adsk.cam.ToolLibrary = toolLibraries.toolLibraryAtURL(url)
# Create some variables for the milling tools which will be used in the operations
faceTool: adsk.cam.Tool = None
adaptiveTool: adsk.cam.Tool = None
# Searching the face mill and the bull nose using a loop for the roughing operations
for tool in toolLibrary:
# Read the tool type
toolType = tool.parameters.itemByName('tool_type').value.value
# Select the first face tool found
if toolType == 'face mill' and not faceTool:
faceTool = tool
# Search the roughing tool
elif toolType == 'bull nose end mill' and not adaptiveTool:
# We look for a bull nose end mill tool larger or equal to 10mm but less than 14mm
diameter = tool.parameters.itemByName('tool_diameter').value.value
if diameter >= 1.0 and diameter < 1.4:
adaptiveTool = tool
# Exit when the 2 tools are found
if faceTool and adaptiveTool:
break
#################### Create setup ####################
cam: adsk.cam.CAM = adsk.cam.CAM.cast(products.itemByProductType("CAMProductType"))
setups: adsk.cam.Setups = cam.setups
setupInput: adsk.cam.SetupInput = setups.createInput(adsk.cam.OperationTypes.MillingOperation)
# Create a list for the models to add to the setup Input
models = []
# Identify the part or exit gracefully
try:
part: adsk.fusion.BRepBody = cam.designRootOccurrence.bRepBodies.item(0)
except Exception as e:
ui.messageBox('No part found in the current document, exiting sample script.')
return
# Add the part to the model list
models.append(part)
# Pass the model list to the setup input
setupInput.models = models
# Create the setup
setup: adsk.cam.Setup = setups.add(setupInput)
# Change some properties of the setup
setup.name = 'CAM Basic Script Sample'
setup.stockMode = adsk.cam.SetupStockModes.RelativeBoxStock
# Set offset mode
setup.parameters.itemByName('job_stockOffsetMode').expression = "'simple'"
# Set offset stock side
setup.parameters.itemByName('job_stockOffsetSides').expression = '0 mm'
# Set offset stock top
setup.parameters.itemByName('job_stockOffsetTop').expression = '2 mm'
# Set setup origin
setup.parameters.itemByName('wcs_origin_boxPoint').value.value = 'top 1'
#################### Face operation ####################
# Create a face operation input
faceInput: adsk.cam.OperationInput = setup.operations.createInput('face')
faceInput.tool = faceTool
faceInput.displayName = 'Face Operation'
faceInput.parameters.itemByName('tolerance').expression = '0.01 mm'
faceInput.parameters.itemByName('stepover').expression = '0.75 * tool_diameter'
faceInput.parameters.itemByName('direction').expression = "'climb'"
# Add the operation to the setup
faceOp: adsk.cam.OperationBase = setup.operations.add(faceInput)
#################### Adaptive operation ####################
adaptiveInput = setup.operations.createInput('adaptive')
adaptiveInput.tool = adaptiveTool
adaptiveInput.displayName = 'Adaptive Roughing'
adaptiveInput.parameters.itemByName('tolerance').expression = '0.1 mm'
adaptiveInput.parameters.itemByName('maximumStepdown').expression = '5 mm'
adaptiveInput.parameters.itemByName('fineStepdown').expression = '0.25 * maximumStepdown'
adaptiveInput.parameters.itemByName('flatAreaMachining').expression = 'false'
# Add the operation to the setup
adaptiveOp: adsk.cam.OperationBase = setup.operations.add(adaptiveInput)
##################### Generate operations ####################
cam.generateToolpath(faceOp)
genFuture: adsk.cam.GenerateToolpathFuture = cam.generateToolpath(adaptiveOp)
#################### ncProgram and post-processing ####################
# Get the post library from library manager
postLibrary: adsk.cam.PostLibrary = libraryManager.postLibrary
# Query post library to get postprocessor list
libraryLocation = adsk.cam.LibraryLocations.Fusion360LibraryLocation
postQuery: adsk.cam.PostConfigurationQuery = postLibrary.createQuery(libraryLocation)
postQuery.vendor = "Autodesk"
postQuery.capability = adsk.cam.PostCapabilities.Milling
postConfigs: list[adsk.cam.PostConfiguration] = postQuery.execute()
# Find the "XYZ" post in the post library and import it to local library
ncExtension = ''
for config in postConfigs:
if config.description == 'XYZ':
ncExtension = config.extension
url = adsk.core.URL.create("user://")
importedURL = postLibrary.importPostConfiguration(config, url, "NCProgramSamplePost.cps")
# Get the imported local post config
postConfig: adsk.cam.PostConfiguration = postLibrary.postConfigurationAtURL(importedURL)
# Create NCProgramInput object
ncInput: adsk.cam.NCProgramInput = cam.ncPrograms.createInput()
ncInput.displayName = 'NC Program Sample'
# Change some nc program parameters...
ncFilename = 'NCProgramSample'
ncParameters: adsk.cam.CAMParameters = ncInput.parameters
ncParameters.itemByName('nc_program_filename').value.value = ncFilename
ncParameters.itemByName('nc_program_openInEditor').value.value = True
ncParameters.itemByName('nc_program_nc_extension').value.value = ncExtension
# Set temp directory as output directory
# Make the path valid for Fusion by replacing \\ to / in the path
outputFolder = str(cam.temporaryFolder).replace('\\', '/')
ncParameters.itemByName('nc_program_output_folder').value.value = outputFolder
# Select the operations to generate
ncInput.operations = [faceOp, adaptiveOp]
# Add a new ncprogram from the ncprogram input
newProgram: adsk.cam.NCProgram = cam.ncPrograms.add(ncInput)
# Set post processor
newProgram.postConfiguration = postConfig
# Change some post parameters
postParameters: adsk.cam.CAMParameters = newProgram.postParameters
# NcProgram parameters are passed without units to the postprocessor
postParameters.itemByName('builtin_tolerance').value.value = 0.01
postParameters.itemByName('builtin_minimumChordLength').value.value = 0.33
# Update/apply post parameters
newProgram.updatePostParameters(postParameters)
# Post-process
# Set post options, by default post process only valid operations containing toolpath data
postOptions = adsk.cam.NCProgramPostProcessOptions.create()
# Ensure toolpaths are visible
faceOp.isLightBulbOn = True
adaptiveOp.isLightBulbOn = True
# To avoid errors, post-process only when toolpath generation has completed
while not genFuture.isGenerationCompleted:
time.sleep(1)
newProgram.postProcess(postOptions)
# Advise where the NC file is located to indicate completion
ui.messageBox(f'The results have been written to:\n{outputFolder}/{ncFilename}{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()))
def loadProjectFromURN(urn:str = None) -> adsk.core.Document:
''' Minimal self-contained function to load and return a document via URN or return None safely '''
doc: adsk.core.Document = None
app = adsk.core.Application.get()
if urn is not None:
try: # File not found causes an exception
project: adsk.core.DataFile = app.data.findFileById(urn)
if project:
doc = app.documents.open(project, True)
else:
app.userInterface.messageBox(f'File not found for URN: {urn}!')
except Exception as e:
if str(e)[0:38] == '3 : Design is located in another team.':
# Although the document has been loaded, variable 'doc' may not be populated
if doc is None:
doc: adsk.core.Document = adsk.core.Application.get().activeDocument
elif str(e)[0:20] == '3 : file not found':
app.userInterface.messageBox(f'File not found for URN: {urn}!')
else:
# Abandon for unhandled errors, displaying the error message.
app.userInterface.messageBox(f'Failed:{str(e)}\n{traceback.format_exc()}')
return doc