Project To Surface API Sample

Description

Projects the specified set of curves onto the specified set of faces using the specified method of projection.

Code Samples

import adsk.core, adsk.fusion, traceback

def run(context):
    ui = None
    try:
        app = adsk.core.Application.get()
        ui = app.userInterface
        
        # Create a document.
        doc = app.documents.add(adsk.core.DocumentTypes.FusionDesignDocumentType)
 
        product = app.activeProduct
        design = adsk.fusion.Design.cast(product)

        # Get the root component of the active design
        rootComp = design.rootComponent

        allOccs = rootComp.occurrences
        transform = adsk.core.Matrix3D.create()
        
        # Create three components under root component
        occ1 = allOccs.addNewComponent(transform)
        subComp1 = occ1.component
        occ2 = allOccs.addNewComponent(transform)
        subComp2 = occ2.component
        occ3 = allOccs.addNewComponent(transform)
        subComp3 = occ3.component
      
        # Create a sketch in sub component 1
        sketches1 = subComp1.sketches
        sketch1 = sketches1.add(rootComp.yZConstructionPlane)
        
        # Get sketch lines
        sketchLines = sketch1.sketchCurves.sketchLines
        
        # Create sketch rectangle
        startPoint = adsk.core.Point3D.create(-8.0, 0, 0)
        endPoint = adsk.core.Point3D.create(8.0, 8.0, 0)
        sketchLines.addTwoPointRectangle(startPoint, endPoint)
        
        # Get the profile of the first sketch
        prof1 = sketch1.profiles.item(0)
        
        # Create an extrusion input
        extrudes1 = subComp1.features.extrudeFeatures
        extInput1 = extrudes1.createInput(prof1, adsk.fusion.FeatureOperations.NewBodyFeatureOperation)
        
        # Define that the extent is a distance extent of 2 cm
        distance1 = adsk.core.ValueInput.createByReal(2.0)
        # Set the distance extent
        extInput1.setDistanceExtent(False, distance1)
        # Set the extrude type to be solid
        extInput1.isSolid = True
        
        # Create the extrusion
        ext1 = extrudes1.add(extInput1)
        
        # Create construction plane
        planes = rootComp.constructionPlanes
        planeInput = planes.createInput()
        offsetValue = adsk.core.ValueInput.createByReal(8.0)
        planeInput.setByOffset(rootComp.yZConstructionPlane, offsetValue)
        plane = planes.add(planeInput)

         # Create a sketch in sub component 2
        sketches2 = subComp2.sketches
        sketch2 = sketches2.add(plane)
        
        # Create the spline.
        points = adsk.core.ObjectCollection.create()
        points.add(adsk.core.Point3D.create(0, 8, 0))
        points.add(adsk.core.Point3D.create(5, 6, 0))
        points.add(adsk.core.Point3D.create(-5, 5, 0))
        
        sketch2Curves = sketch2.sketchCurves
        spline = sketch2Curves.sketchFittedSplines.add(points)
        
        # Create sketch rectangle
        sketch2Lines = sketch2Curves.sketchLines
        startPoint2 = adsk.core.Point3D.create(-4, 2, 0)
        endPoint2 = adsk.core.Point3D.create(3, 4, 0)
        sketch2Lines.addTwoPointRectangle(startPoint2, endPoint2)
        
        # Get the profile of the second sketch
        prof2 = sketch2.profiles.item(0)
        
        # Create an extrusion input       
        extrudes2 = subComp2.features.extrudeFeatures
        extInput2 = extrudes2.createInput(prof2, adsk.fusion.FeatureOperations.NewBodyFeatureOperation)
        
        # Define that the extent is a distance extent of 2 cm
        extent_distance_2 = adsk.fusion.DistanceExtentDefinition.create(adsk.core.ValueInput.createByString("2cm"))
        # Define that the taple angle is 10 degree
        deg10 = adsk.core.ValueInput.createByString("10 deg")

        extInput2.setOneSideExtent(extent_distance_2, adsk.fusion.ExtentDirections.PositiveExtentDirection, deg10)
        
        # Set the extrude type to be solid
        extInput2.isSolid = True

        # Create the extrusion
        ext2 = extrudes2.add(extInput2)
        
        # Get the body with the first extrude
        body = ext1.bodies.item(0)
        
        # Get faces
        faceList = []
        for face in body.faces:
            faceList.append(face)

        # Get curves
        curveList = []
        for curve in sketch2Curves:
            curveList.append(curve)
        
        # Get points
        for point in sketch2.sketchPoints:
            curveList.append(point)
        
        # Get the body with the second extrude
        body2 = ext2.bodies.item(0)
        
        # Get eges
        for edge in body2.edges:
            curveList.append(edge)
        
        # Get construction axis
        curveList.append(rootComp.yConstructionAxis)
        
        # Get construction point
        curveList.append(rootComp.originConstructionPoint)
        
        sketches3 = subComp3.sketches
        # Create a sketch in sub component 3
        skAlongVecProject = sketches3.add(rootComp.yZConstructionPlane)
        # sketch project to surface (along vector)
        projectedEntities = skAlongVecProject.projectToSurface(faceList, curveList, adsk.fusion.SurfaceProjectTypes.AlongVectorSurfaceProjectType, rootComp.xConstructionAxis)

        projectedEntities = []
        # Create a sketch in sub component 3
        skClosestPtProject = sketches3.add(rootComp.yZConstructionPlane)
        # sketch project to surface (closest point)
        projectedEntities = skClosestPtProject.projectToSurface(faceList, curveList, adsk.fusion.SurfaceProjectTypes.ClosestPointSurfaceProjectType)
        
    except:
        if ui:
            ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
#include <Core/Application/Application.h>
#include <Core/Application/Document.h>
#include <Core/Application/Documents.h>
#include <Core/Geometry/Point3D.h>
#include <Core/UserInterface/UserInterface.h>
#include <Core/Application/ObjectCollection.h>
#include <Core/Geometry/Matrix3D.h>
#include <Fusion/Construction/ConstructionPlanes.h>
#include <Fusion/Construction/ConstructionPlane.h>
#include <Fusion/Construction/ConstructionPlaneInput.h>
#include <Fusion/Construction/ConstructionAxes.h>
#include <Fusion/Construction/ConstructionAxis.h>
#include <Fusion/Construction/ConstructionAxisInput.h>
#include <Fusion/Construction/ConstructionPoints.h>
#include <Fusion/Construction/ConstructionPointInput.h>
#include <Fusion/Construction/ConstructionPoint.h>
#include <Fusion/Fusion/Design.h>
#include <Fusion/Sketch/Sketch.h>
#include <Fusion/Sketch/Sketches.h>
#include <Fusion/Sketch/SketchCurves.h>
#include <Fusion/Sketch/SketchCurve.h>
#include <Fusion/Sketch/SketchPoints.h>
#include <Fusion/Sketch/SketchPoint.h>
#include <Fusion/Sketch/SketchLines.h>
#include <Fusion/Sketch/SketchLine.h>
#include <Fusion/Sketch/SketchFittedSplines.h>
#include <Fusion/Sketch/SketchFittedSpline.h>
#include <Fusion/Sketch/Profiles.h>
#include <Fusion/Sketch/Profile.h>
#include <Fusion/Features/Features.h>
#include <Fusion/Features/ExtrudeFeatures.h>
#include <Fusion/Features/ExtrudeFeatureInput.h>
#include <Fusion/Features/ExtrudeFeature.h>
#include <Fusion/Features/DistanceExtentDefinition.h>
#include <Fusion/BRep/BRepBodies.h>
#include <Fusion/BRep/BRepBody.h>
#include <Fusion/BRep/BRepFaces.h>
#include <Fusion/BRep/BRepFace.h>
#include <Fusion/BRep/BRepEdges.h>
#include <Fusion/BRep/BRepEdge.h>
#include <Fusion/Components/Occurrence.h>
#include <Fusion/Components/Occurrences.h>
#include <Fusion/Components/Component.h>


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

Ptr<UserInterface> ui;

extern "C" XI_EXPORT bool run(const char* context)
{
    Ptr<Application> app = Application::get();
    if (!app)
        return false;

    ui = app->userInterface();
    if (!ui)
        return false;

    Ptr<Documents> docs = app->documents();
    if (!docs)
        return false;

    // Create a document.
    Ptr<Document> doc = docs->add(DocumentTypes::FusionDesignDocumentType);
    if (!doc)
        return false;

    Ptr<Design> design = app->activeProduct();
    if (!design)
        return false;

    // Get the root component of the active design
    Ptr<Component> rootComp = design->rootComponent();
    if (!rootComp)
        return false;

    // Create three sub components under root component
    Ptr<Occurrences> occs = rootComp->occurrences();
    if (!occs)
        return false;

    Ptr<Matrix3D> transform = adsk::core::Matrix3D::create();
    if (!transform)
        return false;

    Ptr<Occurrence> subOcc1 = occs->addNewComponent(transform);
    if (!subOcc1)
        return false;

    Ptr<Component> subComp1 = subOcc1->component();
    if (!subComp1)
        return false;

    Ptr<Occurrence> subOcc2 = occs->addNewComponent(transform);
    if (!subOcc2)
        return false;

    Ptr<Component> subComp2 = subOcc2->component();
    if (!subComp2)
        return false;

    Ptr<Occurrence> subOcc3 = occs->addNewComponent(transform);
    if (!subOcc3)
        return false;

    Ptr<Component> subComp3 = subOcc3->component();
    if (!subComp3)
        return false;

    // Create sketch 1 in sub component 1
    Ptr<Sketches> sketches1 = subComp1->sketches();
    if (!sketches1)
        return false;

    Ptr<ConstructionPlane> yzPlane = rootComp->yZConstructionPlane();
    if (!yzPlane)
        return false;

    Ptr<Sketch> sketch1 = sketches1->add(yzPlane);
    if (!sketch1)
        return false;

    // Get sketch curves
    Ptr<SketchCurves> sketchCurves = sketch1->sketchCurves();
    if (!sketchCurves)
        return false;

    // Get sketch lines
    Ptr<SketchLines> sketchLines = sketchCurves->sketchLines();
    if (!sketchLines)
        return false;

    // Create sketch rectangle
    Ptr<Point3D> startPoint = Point3D::create(-8.0, 0, 0);

    Ptr<Point3D> endPoint = Point3D::create(8.0, 8.0, 0);
    sketchLines->addTwoPointRectangle(startPoint, endPoint);

    // Get the profile
    Ptr<Profiles> profs1 = sketch1->profiles();
    if (!profs1)
        return false;

    Ptr<Profile> prof1 = profs1->item(0);

    // Create an extrusion input
    Ptr<Features> feats1 = subComp1->features();
    if (!feats1)
        return false;

    Ptr<ExtrudeFeatures> extrudes1 = feats1->extrudeFeatures();
    if (!extrudes1)
        return false;

    Ptr<ExtrudeFeatureInput> extInput1 = extrudes1->createInput(prof1, FeatureOperations::NewBodyFeatureOperation);

    // Define that the extent is a distance extent of 2 cm
    Ptr<ValueInput> distance1 = ValueInput::createByReal(2.0);
    // Set the distance extent
    extInput1->setDistanceExtent(false, distance1);
    // Set the extrude type to be solid
    extInput1->isSolid(true);

    // Create the extrusion
    Ptr<ExtrudeFeature> ext1 = extrudes1->add(extInput1);
    if (!ext1)
        return false;

    // Create construction plane
    Ptr<ConstructionPlanes> planes = rootComp->constructionPlanes();
    if (!planes)
        return false;

    // Create construction plane input
    Ptr<ConstructionPlaneInput> planeInput = planes->createInput();
    if (!planeInput)
        return false;

    // Add construction plane by offset
    Ptr<ValueInput> offsetValue = ValueInput::createByReal(8.0);
    planeInput->setByOffset(rootComp->yZConstructionPlane(), offsetValue);
    Ptr<ConstructionPlane> plane = planes->add(planeInput);

    // Create sketch 2 in sub component 2
    Ptr<Sketches> sketches2 = subComp2->sketches();
    if (!sketches2)
        return false;

    Ptr<Sketch> sketch2 = sketches2->add(plane);
    if (!sketch2)
        return false;

    // Create an object collection for the points.
    Ptr<ObjectCollection> points = ObjectCollection::create();
    if (!points)
        return false;

    // Define the points the spline with fit through.
    points->add(Point3D::create(0, 8, 0));
    points->add(Point3D::create(5, 6, 0));
    points->add(Point3D::create(-5, 5, 0));

    // Get sketch curves
    Ptr<SketchCurves> sketch2Curves = sketch2->sketchCurves();
    if (!sketch2Curves)
        return false;

    // Create the spline.
    Ptr<SketchFittedSplines> splines = sketch2Curves->sketchFittedSplines();
    if (!splines)
        return false;

    Ptr<SketchFittedSpline> spline = splines->add(points);
    if (!spline)
        return false;

    // Get sketch lines
    Ptr<SketchLines> sketch2Lines = sketch2Curves->sketchLines();
    if (!sketch2Lines)
        return false;

    // Create sketch rectangle
    Ptr<Point3D> startPoint2 = Point3D::create(-4, 2, 0);

    Ptr<Point3D> endPoint2 = Point3D::create(3, 4, 0);
    sketch2Lines->addTwoPointRectangle(startPoint2, endPoint2);

    // Get the profile
    Ptr<Profiles> profs2 = sketch2->profiles();
    if (!profs2)
        return false;

    Ptr<Profile> prof2 = profs2->item(0);

    // Create an extrusion input
    Ptr<Features> feats2 = subComp2->features();
    if (!feats2)
        return false;

    Ptr<ExtrudeFeatures> extrudes2 = feats2->extrudeFeatures();
    if (!extrudes2)
        return false;

    Ptr<ExtrudeFeatureInput> extInput2 = extrudes2->createInput(prof2, FeatureOperations::NewBodyFeatureOperation);

    // Create distance value input
    Ptr<ValueInput> cm2 = adsk::core::ValueInput::createByString("2 cm");

    // Create taper angle value input
    Ptr<ValueInput> deg10 = adsk::core::ValueInput::createByString("10 deg");

    // Create a distance extent definition
    Ptr<DistanceExtentDefinition> extent_distance_2 = adsk::fusion::DistanceExtentDefinition::create(cm2);
        extInput2->setOneSideExtent(extent_distance_2, adsk::fusion::ExtentDirections::PositiveExtentDirection, deg10));

    // Set the extrude type to be solid
    extInput2->isSolid(true);

    // Create the extrusion
    Ptr<ExtrudeFeature> ext2 = extrudes2->add(extInput2);
    if (!ext2)
        return false;

    // Get the body with the first extrude
    Ptr<BRepBodies> bodies = ext1->bodies();
    if (!bodies)
        return false;

    Ptr<BRepBody> body = bodies->item(0);
    if (!body)
        return false;

    // faces
    std::vector<Ptr<BRepFace>> faceVec;
    for (Ptr<BRepFace> face : body->faces())
    {
        faceVec.push_back(face);
    }

    // curves
    std::vector<Ptr<Base>> curveVec;
    for (Ptr<SketchCurve> curve : sketch2Curves)
    {
        curveVec.push_back(curve);
    }

    Ptr<SketchPoints> sketch2Points = sketch2->sketchPoints();
    if (!sketch2Points)
        return false;

    for (Ptr<SketchPoint> point : sketch2Points)
    {
        curveVec.push_back(point);
    }

    // Get the body with the second extrude
    Ptr<BRepBodies> bodies2 = ext2->bodies();
    if (!bodies2)
        return false;

    Ptr<BRepBody> body2 = bodies2->item(0);
    if (!body2)
        return false;

    for (Ptr<BRepEdge> edge : body2->edges())
    {
        curveVec.push_back(edge);
    }

    curveVec.push_back(rootComp->yConstructionAxis());
    curveVec.push_back(rootComp->originConstructionPoint());

    Ptr<Sketches> sketches3 = subComp3->sketches();
    if (!sketches3)
        return false;

    // Create a sketch in sub component 3
    Ptr<Sketch> skAlongVecProject = sketches3->add(yzPlane);
    if (!skAlongVecProject)
        return false;
    // sketch project to surface (along vector)
    std::vector<Ptr<SketchEntity>> projectedEntities = skAlongVecProject->projectToSurface(
        faceVec, curveVec, AlongVectorSurfaceProjectType, rootComp->xConstructionAxis());

    // Create a sketch in sub component 3
    Ptr<Sketch> skClosestPtProject = sketches3->add(yzPlane);
    projectedEntities.clear();
    // sketch project to surface (closest point)
    projectedEntities = skClosestPtProject->projectToSurface(faceVec, curveVec, ClosestPointSurfaceProjectType);


    return true;
}
import { adsk } from "@adsk/fas";

// Params
// {
//     "useCurrentDocument": false,
//     "saveAsNewDocument": false,
//     "message": "",
//     "hubId": "wip1fqaautodesk4298",
//     "fileURN": "urn:adsk.wipqa:dm.lineage:WlSCDh7RQN6zD2btrrO4SA"
// }

function run() {

// Read the parameters passed with the script
  const scriptParameters = JSON.parse(adsk.parameters);
  if (!scriptParameters) throw Error("Invalid parameters provided.");

  // Get the Fusion API's application object
  const app = adsk.core.Application.get();
  if (!app) throw Error("No asdk.core.Application.");

  // const doc: adsk.core.Document = app.documents.add(adsk.core.DocumentTypes.FusionDesignDocumentType);
  // Create a new empty document
  const doc = getDocument(
    app,
    scriptParameters.useCurrentDocument,
    scriptParameters.hubId,
    scriptParameters.fileURN,
  );
  if (!doc) throw Error("Invalid document.");

 // Ensure we are in the Design environment.
  const design = app.activeProduct as adsk.fusion.Design;

  //Get the root component of the active design.
  const rootComp = design.rootComponent

  const allOccs = rootComp.occurrences
  const transform = adsk.core.Matrix3D.create()

  // Create three components under root component
  const occ1 = allOccs.addNewComponent(transform)
  const subComp1 = occ1.component
  const occ2 = allOccs.addNewComponent(transform)
  const subComp2 = occ2.component
  const occ3 = allOccs.addNewComponent(transform)
  const subComp3 = occ3.component

  // Create a sketch in sub component 1
  const sketches1 = subComp1.sketches
  const sketch1 = sketches1.add(rootComp.yZConstructionPlane)

  // Get sketch lines
  const sketchLines = sketch1.sketchCurves.sketchLines

  // Create sketch rectangle
  const startPoint = adsk.core.Point3D.create(-8.0, 0, 0)
  const endPoint = adsk.core.Point3D.create(8.0, 8.0, 0)
  sketchLines.addTwoPointRectangle(startPoint, endPoint)

  // Get the profile of the first sketch
  const prof1 = sketch1.profiles.item(0)

  // Create an extrusion input
  const extrudes1 = subComp1.features.extrudeFeatures
  const extInput1 = extrudes1.createInput(prof1, adsk.fusion.FeatureOperations.NewBodyFeatureOperation)

  // Define that the extent is a distance extent of 2 cm
  const distance1 = adsk.core.ValueInput.createByReal(2.0)

  // Set the distance extent
  const distanceExtentDef = adsk.fusion.DistanceExtentDefinition.create(distance1)
  extInput1.setOneSideExtent(distanceExtentDef, adsk.fusion.ExtentDirections.PositiveExtentDirection)
  // Set the extrude type to be solid
  extInput1.isSolid = true

  // Create the extrusion
  const ext1 = extrudes1.add(extInput1)

  // Create construction plane
  const planes = rootComp.constructionPlanes
  const planeInput = planes.createInput()
  const offsetValue = adsk.core.ValueInput.createByReal(8.0)
  planeInput.setByOffset(rootComp.yZConstructionPlane, offsetValue)
  const plane = planes.add(planeInput)
  // Create a sketch in sub component 2
  const sketches2 = subComp2.sketches
  const sketch2 = sketches2.add(plane)

  // Create the spline.
  const points = adsk.core.ObjectCollection.create()
  points.add(adsk.core.Point3D.create(0, 8, 0))
  points.add(adsk.core.Point3D.create(5, 6, 0))
  points.add(adsk.core.Point3D.create(-5, 5, 0))

  const sketch2Curves = sketch2.sketchCurves
  const spline = sketch2Curves.sketchFittedSplines.add(points)

  // Create sketch rectangle
  const sketch2Lines = sketch2Curves.sketchLines
  const startPoint2 = adsk.core.Point3D.create(-4, 2, 0)
  const endPoint2 = adsk.core.Point3D.create(3, 4, 0)
  sketch2Lines.addTwoPointRectangle(startPoint2, endPoint2)

  // Get the profile of the second sketch
  const prof2 = sketch2.profiles.item(0)

  // Create an extrusion input
  const extrudes2 = subComp2.features.extrudeFeatures
  const extInput2 = extrudes2.createInput(prof2, adsk.fusion.FeatureOperations.NewBodyFeatureOperation)

  // Define that the extent is a distance extent of 2 cm
  const extent_distance_2 = adsk.fusion.DistanceExtentDefinition.create(adsk.core.ValueInput.createByString("2cm"))
  // Define that the taple angle is 10 degree
  const deg10 = adsk.core.ValueInput.createByString("10 deg")

  extInput2.setOneSideExtent(extent_distance_2, adsk.fusion.ExtentDirections.PositiveExtentDirection, deg10)

  // Set the extrude type to be solid
  extInput2.isSolid = true
  // Create the extrusion
  const ext2 = extrudes2.add(extInput2)

  // Get the body with the first extrude
  const body = ext1.bodies.item(0)

  // Get faces
  const faceList = []
  for(let i: number = 0; i < body.faces.count; i++){
    faceList.push(body.faces.item(i))
  }

  // Get curves
  const curveList = []
  for(let i: number = 0; i < sketch2Curves.count; i++){
    curveList.push(sketch2Curves.item(i))
  }

  // Get points
  for(let i: number = 0;  i < sketch2.sketchPoints.count; i++){
    curveList.push(sketch2.sketchPoints.item(i))
  }

  // Get the body with the second extrude
  const body2 = ext2.bodies.item(0)

  // Get eges

  for(let i: number = 0; i < body2.edges.count; i++){
    curveList.push(body2.edges.item(i))
  }

  // Get construction axis
  curveList.push(rootComp.yConstructionAxis)

  // Get construction point
  curveList.push(rootComp.originConstructionPoint)

  const sketches3 = subComp3.sketches
  // Create a sketch in sub component 3
  const skAlongVecProject = sketches3.add(rootComp.yZConstructionPlane)
  // Create sketch project to surface (along vector)
  const projectedEntitiesAlongVector = skAlongVecProject.projectToSurface(faceList, curveList, adsk.fusion.SurfaceProjectTypes.AlongVectorSurfaceProjectType, rootComp.xConstructionAxis)
  // Create a sketch in sub component 3
  const skClosestPtProject = sketches3.add(rootComp.yZConstructionPlane)
  // Create sketch project to surface (closest point)
  const projectedEntitiesClosestPoint = skClosestPtProject.projectToSurface(faceList, curveList, adsk.fusion.SurfaceProjectTypes.ClosestPointSurfaceProjectType)

  saveDocument(
      doc,
      scriptParameters.saveAsNewDocument,
      scriptParameters.message,
      doc.dataFile.parentFolder,
    );

    while (app.hasActiveJobs) {
    wait(2000);
  }
}
function wait(ms: number) {
  const start = new Date().getTime();
  while (new Date().getTime() - start < ms) adsk.doEvents();
}

function getDocument(
  app: adsk.core.Application,
  useCurrentDocument: boolean,
  hubId: string,
  fileURN: string,
): adsk.core.Document {
  if (useCurrentDocument === true) {
    adsk.log(`Using currently open document: ${app.activeDocument.name}.`);
    return app.activeDocument;
  }

  if (hubId) {
    // Possible hubId formats: base64 encoded string, or business:<id>,
    // or personal:<id> (deprecated)
    const hub =
      app.data.dataHubs.itemById(hubId) ||
      app.data.dataHubs.itemById(`a.${adsk.btoa(`business:${hubId}`, true)}`) ||
      app.data.dataHubs.itemById(`a.${adsk.btoa(`personal:${hubId}`, true)}`);
    if (!hub) throw Error(`Hub with id ${hubId} not found.`);
    adsk.log(`Setting hub: ${hub.name}.`);
    app.data.activeHub = hub;
  }

  const file = app.data.findFileById(fileURN);
  if (!file) throw Error(`File not found ${fileURN}.`);
  adsk.log(`Opening ${file.name}`);
  const document = app.documents.open(file, true);
  if (!document) throw Error(`Cannot open file ${file.name}.`);
  return document;
}

function saveDocument(
  doc: adsk.core.Document,
  saveAsNewDocument: boolean,
  message: string,
  destinationFolder: adsk.core.DataFolder,
): boolean {
  if (saveAsNewDocument) {
    adsk.log("Saving as new document.");
    try {
      destinationFolder.parentProject;
    } catch (e) {
      adsk.log(
        "Destination folder is not in a project, setting folder to Fusion Automation Service project.",
      );
      destinationFolder = defaultFolder(
        doc.parent,
        "Fusion Automation Service",
      );
    }
    if (
      doc.saveAs(doc.name + " Additive Ready", destinationFolder, message, "")
    ) {
      adsk.log("Document saved successfully.");
      return true;
    } else {
      adsk.log("Document failed to save.");
      return false;
    }
  }

  if (!doc.isModified) {
    adsk.log("Document not modified, not saving.");
    return true;
  }

  adsk.log(`Saving with message: "${message}".`);
  if (doc.save(message)) {
    adsk.log("Document saved successfully.");
    return true;
  } else {
    adsk.log("Document failed to save.");
    return false;
  }
}

function defaultFolder(app: adsk.core.Application, defaultProjectName: string) {
  const projects = app.data.activeHub.dataProjects;
  if (!projects) throw Error("Unable to get active hub's projects.");
  for (let i = 0; i < projects.count; ++i) {
    const project = projects.item(i)!;
    if (project.name === defaultProjectName) {
      return project.rootFolder;
    }
  }
  adsk.log(`Creating new project: ${defaultProjectName}`);
  const project = projects.add(defaultProjectName);
  if (!project) throw Error("Unable to create new project.");
  return project.rootFolder;
}

run();