Share

Manufacturing Workflow API Sample

Description

Manufacturing Workflow API Sample

This sample script starts by creating a simple component which is then used to describe a milling workflow. It creates a setup, a few operations, pick some tools from a Fusion sample tool library using loops and queries and ends up post-processing the operations out using an NC Program.

Code Samples

#include <Core/CoreAll.h>
#include <Fusion/FusionAll.h>
#include <Cam/CamAll.h>
#include <algorithm>

using namespace adsk::core;
using namespace adsk::fusion;
using namespace adsk::cam;

// Constants used in the script
// We assume we are cutting Aluminum here...

// Milling tool library to get tools from
const std::string MILLING_TOOL_LIBRARY = "Milling Tools (Metric)";

// Material properties for feed and speed calculation
const int ALUMINUM_CUTTING_SPEED = 300;     // mm/min
const double ALUMINUM_FEED_PER_TOOTH = 0.1; // mm/tooth

// Tool preset names (which we know exists for the selected tools)
const std::string ALUMINUM_PRESET_ROUGHING = "alu* rou*";
const std::string ALUMINUM_PRESET_FINISHING = "Aluminum - Finishing";

// Tool types used in this script
const std::string BULL_NOSE_END_MILL = "bull nose end mill";
const std::string BALL_END_MILL = "ball end mill";
const std::string FACE_MILL = "face mill";

// Setup work coordinate system (WCS) location
const std::string TOP_CENTER = "top center";
const std::string TOP_XMIN_YMIN = "top 1";
const std::string TOP_XMAX_YMIN = "top 2";
const std::string TOP_XMIN_YMAX = "top 3";
const std::string TOP_XMAX_YMAX = "top 4";
const std::string TOP_SIDE_YMIN = "top side 1";
const std::string TOP_SIDE_XMAX = "top side 2";
const std::string TOP_SIDE_YMAX = "top side 3";
const std::string TOP_SIDE_XMIN = "top side 4";
const std::string CENTER = "center";
const std::string MIDDLE_XMIN_YMIN = "middle 1";
const std::string MIDDLE_XMAX_YMIN = "middle 2";
const std::string MIDDLE_XMIN_YMAX = "middle 3";
const std::string MIDDLE_XMAX_YMAX = "middle 4";
const std::string MIDDLE_SIDE_YMIN = "middle side 1";
const std::string MIDDLE_SIDE_XMAX = "middle side 2";
const std::string MIDDLE_SIDE_YMAX = "middle side 3";
const std::string MIDDLE_SIDE_XMIN = "middle side 4";
const std::string BOTTOM_CENTER = "bottom center";
const std::string BOTTOM_XMIN_YMIN = "bottom 1";
const std::string BOTTOM_XMAX_YMIN = "bottom 2";
const std::string BOTTOM_XMIN_YMAX = "bottom 3";
const std::string BOTTOM_XMAX_YMAX = "bottom 4";
const std::string BOTTOM_SIDE_YMIN = "bottom side 1";
const std::string BOTTOM_SIDE_XMAX = "bottom side 2";
const std::string BOTTOM_SIDE_YMAX = "bottom side 3";
const std::string BOTTOM_SIDE_XMIN = "bottom side 4";

const double PI = 3.14159265358979323846;

std::vector<std::string> getLibrariesURLs(Ptr<ToolLibraries> libraries, Ptr<URL> url);
std::vector<Ptr<Tool>> getToolsFromLibraryByTypeDiameterRangeAndMinFluteLength(
    Ptr<ToolLibrary> toolLibrary,
    std::string tooltype,
    double minDiameter,
    double maxDiameter,
    double minimumFluteLength = 0.0);
Ptr<BRepBody> createSamplePart(Ptr<Design> design);

extern "C" XI_EXPORT bool run(const char* context)
{
    // Initialisation
    Ptr<Application> app = Application::get();
    Ptr<UserInterface> ui = app->userInterface();

    // Create a new empty document
    Ptr<Document> doc = app->documents()->add(DocumentTypes::FusionDesignDocumentType);

    // Get the design document used to create the sample part
    Ptr<Design> design = app->activeProduct();

    // Switch to manufacturing space
    Ptr<Workspace> camWS = ui->workspaces()->itemById("CAMEnvironment");
    camWS->activate();

    // Get the CAM product
    Ptr<Products> products = doc->products();

    // Create sample part
    Ptr<BRepBody> part = createSamplePart(design);

    // Select cutting tools
    // Get the tool libraries from the library manager
    Ptr<CAMManager> camManager = CAMManager::get();
    Ptr<CAMLibraryManager> libraryManager = camManager->libraryManager();
    Ptr<ToolLibraries> toolLibraries = libraryManager->toolLibraries();

    Ptr<URL> url;
    const bool useHardCodedUrl = false;
    if (useHardCodedUrl)
    {
        // We can use a library URl directly if we know its address
        std::string libUrl = "systemlibraryroot://Samples/Milling Tools (Metric).json";
        url = URL::create(libUrl);
    }
    else
    {
        // Or we can use the tool library objects fusion folder in the tool library
        Ptr<URL> fusionFolder = toolLibraries->urlByLocation(LibraryLocations::Fusion360LibraryLocation);
        std::vector<std::string> fusionLibs = getLibrariesURLs(toolLibraries, fusionFolder);

        // Search the required library url in the libraries
        for (std::string& libUrl : fusionLibs)
        {
            if (libUrl.find(MILLING_TOOL_LIBRARY) != std::string::npos)
            {
                url = URL::create(libUrl);
                break;
            }
        }
    }

    // Load the tool library
    Ptr<ToolLibrary> toolLibrary = toolLibraries->toolLibraryAtURL(url);
    if (!toolLibrary)
    {
        ui->messageBox("Failed to load tool library");
        return false;
    }

    // Create variables to host the milling tools to be used in the operations
    Ptr<Tool> faceTool;
    Ptr<Tool> adaptiveTool;
    Ptr<Tool> finishingTool;

    // Search for 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();

        if (toolType == FACE_MILL && !faceTool)
        {
            // Select the first face tool found
            faceTool = tool;
        }
        else if (toolType == BULL_NOSE_END_MILL && !adaptiveTool)
        {
            // Search the roughing tool
            // We look for a bull nose end mill tool larger or equal to 12mm but less than 14mm
            Ptr<FloatParameterValue> diameterParameter = tool->parameters()->itemByName("tool_diameter")->value();
            double diameter = diameterParameter->value();
            if (diameter >= 1.2 && 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;
    }

    // Using a query, search for a ball end mill tool having diameter between 6 mm and 10 mm and a minimum flute length
    // of 20.001mm
    std::vector<Ptr<Tool>> finishingTools =
        getToolsFromLibraryByTypeDiameterRangeAndMinFluteLength(toolLibrary, BALL_END_MILL, 0.6, 1, 2.0001);

    // For this example, we select the first tool found as our finishing tool
    if (finishingTools.size() == 0)
    {
        ui->messageBox("No ball end mill tool found");
        return false;
    }
    finishingTool = finishingTools[0];

    // Create a 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;
    // 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 and set some properties
    Ptr<Setup> setup = setups->add(setupInput);
    setup->name("CAM Automation Script Sample");
    setup->stockMode(SetupStockModes::RelativeBoxStock);
    // Set the offset mode
    setup->parameters()->itemByName("job_stockOffsetMode")->expression("\"simple\"");
    // Set the offset stock side
    setup->parameters()->itemByName("job_stockOffsetSides")->expression("0 mm");
    // Set the offset stock top
    setup->parameters()->itemByName("job_stockOffsetTop")->expression("1 mm");
    // Set the setup origin
    Ptr<ChoiceParameterValue> wcs_origin = setup->parameters()->itemByName("wcs_origin_boxPoint")->value();
    wcs_origin->value(TOP_XMIN_YMIN);

    // Face operations
    // Calculate the feed and speed for the face operation
    Ptr<FloatParameterValue> toolDiameterParameter = faceTool->parameters()->itemByName("tool_diameter")->value();
    double toolDiameter = toolDiameterParameter->value(); // cm
    Ptr<IntegerParameterValue> numberOfFlutesParameter =
        faceTool->parameters()->itemByName("tool_numberOfFlutes")->value();
    int numberOfFlutes = numberOfFlutesParameter->value();                            // int
    double spindleSpeed = ALUMINUM_CUTTING_SPEED / PI / (toolDiameter * 10) * 1000;   // rpm
    double cuttingFeedrate = spindleSpeed * ALUMINUM_FEED_PER_TOOTH * numberOfFlutes; // mm/min

    // Create a preset with those calculated feeds
    Ptr<ToolPreset> facePreset = faceTool->presets()->add();
    facePreset->name("Aluminum (set by script)");
    Ptr<FloatParameterValue> tool_spindleSpeed = facePreset->parameters()->itemByName("tool_spindleSpeed")->value();
    tool_spindleSpeed->value(int(spindleSpeed));
    facePreset->parameters()
        ->itemByName("tool_feedCutting")
        ->expression(std::to_string(int(cuttingFeedrate)) + " mm/min");

    // Create a face operation input
    Ptr<OperationInput> input = setup->operations()->createInput("face");
    input->tool(faceTool);
    input->toolPreset(facePreset); // Assign created preset
    input->displayName("Face Operation");
    input->parameters()->itemByName("tolerance")->expression("0.01 mm");
    input->parameters()->itemByName("stepover")->expression("0.75 * tool_diameter");
    input->parameters()->itemByName("direction")->expression("\"climb\"");

    // Determine the pass angle along the largest part dimension
    // Get the stock box dimensions in cm
    Ptr<FloatParameterValue> stockXParameter = setup->parameters()->itemByName("job_stockInfoDimensionX")->value();
    double stockX = stockXParameter->value();
    Ptr<FloatParameterValue> stockYParameter = setup->parameters()->itemByName("job_stockInfoDimensionY")->value();
    double stockY = stockYParameter->value();
    // Determine the pass angle to be along the largest length (X or Y) of the block
    if (stockX >= stockY)
    {
        input->parameters()->itemByName("passAngle")->expression("0 deg");
    }
    else
    {
        input->parameters()->itemByName("passAngle")->expression("90 deg");
    }

    // Add the operation to the setup
    Ptr<OperationBase> faceOp = setup->operations()->add(input);

    // Adaptive operations
    input = setup->operations()->createInput("adaptive");
    input->tool(adaptiveTool);
    input->displayName("Adaptive Roughing");
    input->parameters()->itemByName("tolerance")->expression("0.1 mm");
    input->parameters()->itemByName("maximumStepdown")->expression("5 mm");
    input->parameters()->itemByName("fineStepdown")->expression("0.25 * maximumStepdown");
    input->parameters()->itemByName("flatAreaMachining")->expression("false");

    // Look for a tool preset related to aluminum roughing
    std::vector<Ptr<ToolPreset>> presets = adaptiveTool->presets()->itemsByName(ALUMINUM_PRESET_ROUGHING);
    if (presets.size() > 0)
    {
        // We select and use the first preset found
        Ptr<ToolPreset> adaptivePreset = presets[0];
        input->toolPreset(adaptivePreset);
    }

    // Add the operation to the setup
    Ptr<OperationBase> adaptiveOp = setup->operations()->add(input);

    // Finishing tool preset
    // Get a tool preset from the finishing tool
    Ptr<ToolPreset> finishingPreset;
    presets = finishingTool->presets()->itemsByName(ALUMINUM_PRESET_FINISHING);
    if (presets.size() > 0)
    {
        // Use the first aluminum finishing preset found
        finishingPreset = presets[0];
    }

    // Parallel operations
    input = setup->operations()->createInput("parallel");
    input->tool(finishingTool);
    input->displayName("Parallel Finishing");
    input->parameters()->itemByName("tolerance")->expression("0.01 mm");
    input->parameters()->itemByName("cuspHeightStepover")->expression("0.005 mm");
    input->parameters()->itemByName("boundaryMode")->expression("\"selection\"");
    if (finishingPreset)
    {
        // Assign the finishig tool preset
        input->toolPreset(finishingPreset);
    }

    // Add the operation to the setup
    Ptr<OperationBase> parallelOp = setup->operations()->add(input);

    // Use a contour for the sake of demonstration
    Ptr<BRepEdge> limitEdge;
    for (Ptr<BRepEdge> e : part->edges())
    {
        // This is the inner one: intersection of a plane and a sphere making up a circle
        if (e->geometry()->curveType() == Curve3DTypes::Circle3DCurveType)
        {
            limitEdge = e;
            break;
        }
    }

    if (limitEdge)
    {
        // Apply the limits edge to the operation
        Ptr<CadContours2dParameterValue> cadcontours2dParam =
            parallelOp->parameters()->itemByName("machiningBoundarySel")->value();
        Ptr<CurveSelections> chains = cadcontours2dParam->getCurveSelections();
        Ptr<ChainSelection> chain = chains->createNewChainSelection();
        chain->inputGeometry({limitEdge});
        cadcontours2dParam->applyCurveSelections(chains);
    }

    // Steep and shallow operations
    // Create a folder for finishing operations that require Machining Extension
    Ptr<OperationInput> operationInput = setup->operations()->createInput("folder");
    operationInput->displayName("Machining Extension Required");
    Ptr<CAMFolder> folder = setup->operations()->add(operationInput);

    // Create a steep and shallow operation in the folder
    input = setup->operations()->createInput("steep_and_shallow");
    input->tool(finishingTool);
    input->displayName("Steep and Shallow Finishing");
    input->parameters()->itemByName("tolerance")->expression("0.01 mm");
    input->parameters()->itemByName("useAvoidFlats")->expression("true");
    input->parameters()->itemByName("cuspHeightStepdown")->expression("0.005 mm");
    input->parameters()->itemByName("cuspHeightStepover")->expression("cuspHeightStepdown");
    input->parameters()->itemByName("spiral")->expression("true");
    input->parameters()->itemByName("shallowSpiral")->expression("true");
    input->parameters()->itemByName("offsetSmoothing")->expression("true");
    if (finishingPreset)
    {
        // Assign the finishig tool preset
        input->toolPreset(finishingPreset);
    }

    // Add the operation to the folder
    Ptr<OperationBase> steepAndShallowOp = folder->operations()->add(input);

    // Check whether this toolpath is generatable ("steep_and_shallow" required the manufacturing extension)
    bool isSteepAndShallowGeneratable = false;
    for (Ptr<OperationStrategy> op : setup->operations()->compatibleStrategies())
    {
        if (op->name() == "steep_and_shallow")
        {
            if (op->isGenerationAllowed())
            {
                // isGenerationAllowed will be false if the extension is not active thus preventing the
                // steep_and_shallow operation
                isSteepAndShallowGeneratable = true;
            }
            break;
        }
    }

    // Generate operations
    // List the valid operations to generate
    Ptr<ObjectCollection> operations = ObjectCollection::create();
    operations->add(faceOp);
    operations->add(adaptiveOp);
    operations->add(parallelOp);
    if (isSteepAndShallowGeneratable)
    {
        operations->add(steepAndShallowOp);
    }

    // Create progress bar
    Ptr<ProgressDialog> progressDialog = ui->createProgressDialog();
    progressDialog->isCancelButtonShown(false);
    progressDialog->show("Generating operations->()..", "%p%", 0, 100);
    adsk::doEvents(); // Allow Fusion to update so that the progressDialog updates nicely

    // Generate the valid operations
    Ptr<GenerateToolpathFuture> gtf = cam->generateToolpath(operations);

    // Wait for the generation to be finished and update the progress bar
    while (!gtf->isGenerationCompleted())
    {
        // Calculate progress and update the progress bar
        int total = gtf->numberOfOperations();
        int completed = gtf->numberOfCompleted();
        int progress = int(completed * 100 / total);
        progressDialog->progressValue(progress);
        adsk::doEvents(); // Allow Fusion to update so that the screen does not freeze
    }

    // Generation done
    progressDialog->progressValue(100);
    progressDialog->hide();

    // NC Program and post-processing
    // Get the post library from the library manager
    Ptr<PostLibrary> postLibrary = libraryManager->postLibrary();

    // Query the post library to get the postprocessor list
    Ptr<PostConfigurationQuery> postQuery = postLibrary->createQuery(LibraryLocations::Fusion360LibraryLocation);
    postQuery->vendor("Autodesk");
    postQuery->capability(PostCapabilities::Milling);
    std::vector<Ptr<PostConfiguration>> postConfigs = postQuery->execute();

    // Find the "XYZ" post in the post library and import it to the local library
    Ptr<URL> importedURL;
    for (Ptr<PostConfiguration> config : postConfigs)
    {
        if (config->description() == "XYZ")
        {
            Ptr<URL> _url = URL::create("user://");
            importedURL = postLibrary->importPostConfiguration(config, _url, "NCProgramSamplePost.cps");
        }
    }

    // Get the imported local post config
    Ptr<PostConfiguration> postConfig = postLibrary->postConfigurationAtURL(importedURL);

    // Create the NCProgramInput object
    Ptr<NCProgramInput> ncInput = cam->ncPrograms()->createInput();
    ncInput->displayName("NC Program Sample");

    // Change some nc program parameters...
    Ptr<CAMParameters> ncParameters = ncInput->parameters();
    std::string programName = "NCProgramSample";
    Ptr<StringParameterValue> nc_program_filename = ncParameters->itemByName("nc_program_filename")->value();
    nc_program_filename->value(programName);
    Ptr<BooleanParameterValue> nc_program_openInEditor = ncParameters->itemByName("nc_program_openInEditor")->value();
    nc_program_openInEditor->value(true);

    // Set the temporary directory as the output directory
    std::string outputFolder = cam->temporaryFolder();
    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, parallelOp});

    // Add a new ncprogram from the ncprogram input
    Ptr<NCProgram> newProgram = cam->ncPrograms()->add(ncInput);

    // Set the post processor
    newProgram->postConfiguration(postConfig);

    // Change some of the post parameters
    Ptr<CAMParameters> postParameters = newProgram->postParameters();
    Ptr<FloatParameterValue> builtin_tolerance = postParameters->itemByName("builtin_tolerance")->value();
    builtin_tolerance->value(0.02); // NcProgram parameter is passed unchanged to the postprocessor (it has no units)
    Ptr<FloatParameterValue> builtin_minimumChordLength =
        postParameters->itemByName("builtin_minimumChordLength")->value();
    builtin_minimumChordLength->value(0.33); // NcProgram parameter is passed unchanged (it has no units)

    // Update/apply post parameters
    newProgram->updatePostParameters(postParameters);

    // Set post options, by default post process only valid operations containing toolpath data
    Ptr<NCProgramPostProcessOptions> postOptions = NCProgramPostProcessOptions::create();
    // postOptions.PostProcessExecutionBehaviors =
    // adsk.cam.PostProcessExecutionBehaviors.PostProcessExecutionBehavior_PostAll

    // Post-process
    newProgram->postProcess(postOptions);

    // Show the output file
    ui->messageBox(
        "Post processing is complete. The results have been written to:\n" + outputFolder + "/" + programName + ".csv");

    return true;
}

// Return the list of libraries' URLs for the specified libraries
std::vector<std::string> getLibrariesURLs(Ptr<ToolLibraries> libraries, Ptr<URL> url)
{
    std::vector<std::string> urls;
    std::vector<Ptr<URL>> libs = libraries->childAssetURLs(url);
    for (auto& elem : libs)
    {
        urls.push_back(elem->toString());
    }
    for (Ptr<URL> folder : libraries->childFolderURLs(url))
    {
        std::vector<std::string> folderUrls = getLibrariesURLs(libraries, folder);
        urls.insert(urls.end(), folderUrls.begin(), folderUrls.end());
    }
    return urls;
}

//  Return a list of tools that fits the search
std::vector<Ptr<Tool>> getToolsFromLibraryByTypeDiameterRangeAndMinFluteLength(
    Ptr<ToolLibrary> toolLibrary,
    std::string tooltype,
    double minDiameter,
    double maxDiameter,
    double minimumFluteLength)
{
    Ptr<ToolQuery> query = toolLibrary->createQuery();
    // Set the search critera
    query->criteria()->add("tool_type", ValueInput::createByString(tooltype));
    query->criteria()->add("tool_diameter.min", ValueInput::createByReal(minDiameter));
    query->criteria()->add("tool_diameter.max", ValueInput::createByReal(maxDiameter));
    if (minimumFluteLength)
    {
        query->criteria()->add("tool_fluteLength.min", ValueInput::createByReal(minimumFluteLength));
    }
    // Get query results
    std::vector<Ptr<ToolQueryResult>> results = query->execute();
    // Get the tools from the query
    std::vector<Ptr<Tool>> tools;
    // Results have a tool, url, toollibrary and the index of the tool in that library: we just return the tool here
    for (auto& elem : results)
    {
        tools.push_back(elem->tool());
    }
    return tools;
}

// CAD creation functions
Ptr<BRepBody> createBox(Ptr<Design> design, double sizeX, double sizeY, double sizeZ);
Ptr<BRepBody> createSphere(Ptr<Design> design, double radius);
Ptr<BRepBody> getBodyFromBooleanOperation(Ptr<Design> design, Ptr<BRepBody> body1, Ptr<BRepBody> body2);

// Create the sample part for this script
Ptr<BRepBody> createSamplePart(Ptr<Design> design)
{

    // The sample part is a box containing a concave side generated by subtracting the intersection from a sphere.
    // The lower face of the box is at Z = 0 and we position the sphere above but intersecting with the box upper face.
    // Fusion's default behaviour is now to ground the first component of an assembly to the parent.
    // This can be overriden, see Preferences->General->Design->Assemblies->First component grounded to parent.
    // However if we make the first component the box, we can move the sphere without changing anything.

    Ptr<BRepBody> box = createBox(design, 22, 15, 5);
    Ptr<BRepBody> sphere = createSphere(design, 7.5);

    // Get the root component
    Ptr<Component> rootComp = design->rootComponent();
    Ptr<Occurrences> occs = rootComp->occurrences();

    // Get the second Occurrence(sphere) as the first occurrence(box) may be grounded to the parent
    Ptr<Occurrence> occ = occs->item(1);
    Ptr<Matrix3D> mat = occ->transform();

    // Matrix translation, moving the sphere up by 10 units along Z axis
    Ptr<Vector3D> origin = Vector3D::create(0, 0, 10);
    mat->translation(origin);

    // Set the transform
    occ->transform(mat);

    // Snapshot - Determining the position is important!!!
    design->snapshots()->add();

    // Cut the sphere / box intersection from the box to leave a concave face
    Ptr<BRepBody> part = getBodyFromBooleanOperation(design, box, sphere);
    return part;
}

// Create a sample box
Ptr<BRepBody> createBox(Ptr<Design> design, double sizeX, double sizeY, double sizeZ)
{
    Ptr<Component> component = design->rootComponent();
    // Create a sketch
    Ptr<Sketches> sketches = component->sketches();
    Ptr<Sketch> sketch = sketches->add(component->xYConstructionPlane());
    Ptr<SketchLines> lines = sketch->sketchCurves()->sketchLines();
    Ptr<SketchLineList> recLines = lines->addTwoPointRectangle(
        Point3D::create(-sizeX / 2, -sizeY / 2, 0), Point3D::create(sizeX / 2, sizeY / 2, 0));
    Ptr<Profile> prof = sketch->profiles()->item(0);
    Ptr<ExtrudeFeatures> extrudes = component->features()->extrudeFeatures();
    Ptr<ValueInput> distance = ValueInput::createByReal(sizeZ);
    Ptr<ExtrudeFeature> ext = extrudes->addSimple(prof, distance, FeatureOperations::NewComponentFeatureOperation);
    return ext->bodies()->item(0);
}

// Create a sample sphere
Ptr<BRepBody> createSphere(Ptr<Design> design, double radius)
{
    Ptr<Component> component = design->rootComponent();
    // Create a new sketch on the xy plane
    Ptr<Sketches> sketches = component->sketches();
    Ptr<ConstructionPlane> xyPlane = component->xYConstructionPlane();
    Ptr<Sketch> sketch = sketches->add(component->xYConstructionPlane());
    // Draw a circle
    Ptr<SketchCircles> circles = sketch->sketchCurves()->sketchCircles();
    Ptr<SketchCircle> circle = circles->addByCenterRadius(Point3D::create(0, 0, 0), radius);
    // Draw a line to use as the axis of revolution
    Ptr<SketchLines> lines = sketch->sketchCurves()->sketchLines();
    Ptr<SketchLine> axisLine = lines->addByTwoPoints(Point3D::create(-radius, 0, 0), Point3D::create(radius, 0, 0));
    // Get the profile defined by half of the circle
    Ptr<Profile> prof = sketch->profiles()->item(0);
    // Create an revolution input to be able to define the input needed for a revolution
    // while specifying the profile and that a new component is to be created
    Ptr<RevolveFeatures> revolves = component->features()->revolveFeatures();
    Ptr<RevolveFeatureInput> revInput =
        revolves->createInput(prof, axisLine, FeatureOperations::NewComponentFeatureOperation);
    // Define that the extent is an angle of 2*pi to get a sphere
    Ptr<ValueInput> angle = ValueInput::createByReal(2 * PI);
    revInput->setAngleExtent(false, angle);
    // Create the extrusion
    Ptr<RevolveFeature> ext = revolves->add(revInput);

    return ext->bodies()->item(0);
}

// Creates a boolean operation between two bodies
Ptr<BRepBody> getBodyFromBooleanOperation(Ptr<Design> design, Ptr<BRepBody> body1, Ptr<BRepBody> body2)
{
    Ptr<Component> model = design->activeComponent();
    Ptr<Features> features = model->features();
    Ptr<ObjectCollection> bodyCollection = ObjectCollection::create();
    bodyCollection->add(body2);
    Ptr<CombineFeatures> combineFeatures = features->combineFeatures();
    Ptr<CombineFeatureInput> combineFeatureInput = combineFeatures->createInput(body1, bodyCollection);
    combineFeatureInput->operation(FeatureOperations(1));
    combineFeatureInput->isKeepToolBodies(false);
    combineFeatureInput->isNewComponent(false);
    Ptr<CombineFeature> returnValue = combineFeatures->add(combineFeatureInput);
    Ptr<BRepBody> part = returnValue->bodies()->item(0);
    return part;
}


Was this information helpful?