Construction Plane API Sample

Description

Demonstrates creating construction plane by different ways.

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

        # Create sketch
        sketches = rootComp.sketches
        sketch = sketches.add(rootComp.xZConstructionPlane)
        
        # Create sketch circle
        sketchCircles = sketch.sketchCurves.sketchCircles
        centerPoint = adsk.core.Point3D.create(0, 0, 0)
        sketchCircles.addByCenterRadius(centerPoint, 5.0)        
        
        # Get the profile defined by the circle
        prof = sketch.profiles.item(0)

        # Create an extrusion input
        extrudes = rootComp.features.extrudeFeatures
        extInput = extrudes.createInput(prof, adsk.fusion.FeatureOperations.NewBodyFeatureOperation)
        
        # Define that the extent is a distance extent of 5 cm
        distance = adsk.core.ValueInput.createByReal(5)
        # Set the distance extent to be symmetric
        extInput.setDistanceExtent(True, distance)
        # Set the extrude to be a solid one
        extInput.isSolid = True
        
        # Create an cylinder
        extrude = extrudes.add(extInput)

        # Create sketch line
        sketchLines = sketch.sketchCurves.sketchLines
        startPoint = adsk.core.Point3D.create(5, 5, 0)
        endPoint = adsk.core.Point3D.create(5, 10, 0)
        sketchLineOne = sketchLines.addByTwoPoints(startPoint, endPoint)
        endPointTwo = adsk.core.Point3D.create(10, 5, 0)
        # Start the second line at the first line's start sketch point so the two lines share a
        # single topological point. This shared point is what lets auto-chaining traverse from one
        # line to the other (see the connectedChainedCurves example below).
        sketchLineTwo = sketchLines.addByTwoPoints(sketchLineOne.startSketchPoint, endPointTwo)
        
        # Create three sketch points
        sketchPoints = sketch.sketchPoints
        positionOne = adsk.core.Point3D.create(0, 5.0, 0)
        sketchPointOne = sketchPoints.add(positionOne)
        positionTwo = adsk.core.Point3D.create(5.0, 0, 0)
        sketchPointTwo = sketchPoints.add(positionTwo)
        positionThree = adsk.core.Point3D.create(0, -5.0, 0)
        sketchPointThree = sketchPoints.add(positionThree)
        
        # Get the profile again since the sketch has been edit.
        prof = sketch.profiles.item(0)
        
        # Get construction planes
        planes = rootComp.constructionPlanes
        
        # Create construction plane input
        planeInput = planes.createInput()
        
        # Add construction plane by offset
        offsetValue = adsk.core.ValueInput.createByReal(3.0)
        planeInput.setByOffset(prof, offsetValue)
        planeOne = planes.add(planeInput)
        
        # Get the health state of the plane
        health = planeOne.healthState
        if health == adsk.fusion.FeatureHealthStates.ErrorFeatureHealthState or health == adsk.fusion.FeatureHealthStates.WarningFeatureHealthState:
            message = planeOne.errorOrWarningMessage
        
        # Add construction plane by angle
        angle = adsk.core.ValueInput.createByString('30.0 deg')
        planeInput.setByAngle(sketchLineOne, angle, prof)
        planes.add(planeInput)
        
        # Add construction plane by two planes
        planeInput.setByTwoPlanes(prof, planeOne)
        planes.add(planeInput)
        
        # Add construction plane by tangent
        cylinderFace = extrude.sideFaces.item(0)
        planeInput.setByTangent(cylinderFace, angle, rootComp.xYConstructionPlane)
        planes.add(planeInput)
        
        # Add construction plane by two edges
        planeInput.setByTwoEdges(sketchLineOne, sketchLineTwo)
        planes.add(planeInput)
        
        # Add construction plane by three points
        planeInput.setByThreePoints(sketchPointOne, sketchPointTwo, sketchPointThree)
        planes.add(planeInput)

        # Add construction plane by three snap points
        snap1 = adsk.fusion.ConstructionSnapPoint.create(
            sketchPointOne,
            None,
            sketchPointOne.geometry,
            adsk.fusion.ConstructionSnapPointTypes.DefaultConstructionSnapPointType,
        )
        snap2 = adsk.fusion.ConstructionSnapPoint.create(
            sketchPointTwo,
            None,
            sketchPointTwo.geometry,
            adsk.fusion.ConstructionSnapPointTypes.DefaultConstructionSnapPointType,
        )
        snap3 = adsk.fusion.ConstructionSnapPoint.create(
            sketchPointThree,
            None,
            sketchPointThree.geometry,
            adsk.fusion.ConstructionSnapPointTypes.DefaultConstructionSnapPointType,
        )
        planeInput.setByThreeSnapPoints(snap1, snap2, snap3)
        planes.add(planeInput)
        
        # Add construction plane by tangent at point
        planeInput.setByTangentAtPoint(cylinderFace, sketchPointOne)
        planes.add(planeInput)
        
        # Add construction plane by distance on path
        distance = adsk.core.ValueInput.createByReal(1.0)
        planeInput.setByDistanceOnPath(sketchLineOne, distance)
        planes.add(planeInput)

        # Add construction plane by path with proportional distance type
        proportionalPath = adsk.fusion.Path.create(sketchLineOne, adsk.fusion.ChainedCurveOptions.noChainedCurves)
        planeInput.setByPath(proportionalPath, adsk.fusion.PathDistanceTypes.ProportionalPathDistanceType, adsk.core.ValueInput.createByReal(0.3))
        proportionalPathPlane = planes.add(planeInput)

        #Query the ConstructionPlanePathDefinition of the proportional path-based plane
        proportionalPathDef = adsk.fusion.ConstructionPlanePathDefinition.cast(proportionalPathPlane.definition)
        proportionalRetrievedPath = proportionalPathDef.path
        proportionalDistanceType = proportionalPathDef.distanceType
        proportionalDistanceParam = proportionalPathDef.distance

        # Redefine the proportional path-based plane using ConstructionPlanePathDefinition.redefine
        proportionalRedefinedPath = adsk.fusion.Path.create(sketchLineTwo, adsk.fusion.ChainedCurveOptions.noChainedCurves)
        redefineProportionalResult = proportionalPathDef.redefine(
            proportionalRedefinedPath, adsk.fusion.PathDistanceTypes.ProportionalPathDistanceType, adsk.core.ValueInput.createByReal(0.8))
        assert redefineProportionalResult, "redefine should succeed for a valid proportional distance"

        # Verify the redefinition took effect: path, distance type and distance value are all updated.
        proportionalPathDef = adsk.fusion.ConstructionPlanePathDefinition.cast(proportionalPathPlane.definition)
        assert proportionalPathDef.path.item(0).entity == sketchLineTwo, "redefine should update the path to the new curve"
        assert proportionalPathDef.distanceType == adsk.fusion.PathDistanceTypes.ProportionalPathDistanceType
        assert abs(proportionalPathDef.distance.value - 0.8) < 1e-6, "redefine should update the distance value"
        
        # Add construction plane by path with physical distance type
        physicalPath = adsk.fusion.Path.create(sketchLineOne, adsk.fusion.ChainedCurveOptions.noChainedCurves)
        planeInput.setByPath(physicalPath, adsk.fusion.PathDistanceTypes.PhysicalPathDistanceType, adsk.core.ValueInput.createByString('45.0 mm'))
        physicalPathPlane = planes.add(planeInput)
        
        # Query the ConstructionPlanePathDefinition of the physical path-based plane
        physicalPathDef = adsk.fusion.ConstructionPlanePathDefinition.cast(physicalPathPlane.definition)
        physicalRetrievedPath = physicalPathDef.path
        physicalDistanceType = physicalPathDef.distanceType
        physicalDistanceParam = physicalPathDef.distance
        
        # Redefine the physical path-based plane using ConstructionPlanePathDefinition.redefine
        physicalRedefinedPath = adsk.fusion.Path.create(sketchLineTwo, adsk.fusion.ChainedCurveOptions.noChainedCurves)
        redefinePhysicalResult = physicalPathDef.redefine(
            physicalRedefinedPath, adsk.fusion.PathDistanceTypes.PhysicalPathDistanceType, adsk.core.ValueInput.createByString('20.0 mm'))
        assert redefinePhysicalResult, "redefine should succeed for a valid physical distance"

        # Verify the redefinition took effect.
        physicalPathDef = adsk.fusion.ConstructionPlanePathDefinition.cast(physicalPathPlane.definition)
        assert physicalPathDef.path.item(0).entity == sketchLineTwo, "redefine should update the path to the new curve"
        assert physicalPathDef.distanceType == adsk.fusion.PathDistanceTypes.PhysicalPathDistanceType
        assert abs(physicalPathDef.distance.value - 2.0) < 1e-6, "distance value should reflect the new physical distance (20.0 mm = 2.0 cm)"

        # Attempt an invalid redefine: a proportional distance outside [0, 1] must fail and must not
        # modify the plane's existing (physical) definition. The Python API raises RuntimeError
        # for validation failures rather than returning False.
        invalidPath = adsk.fusion.Path.create(sketchLineOne, adsk.fusion.ChainedCurveOptions.noChainedCurves)
        preInvalidDistance = physicalPathDef.distance.value
        try:
            physicalPathDef.redefine(invalidPath, adsk.fusion.PathDistanceTypes.ProportionalPathDistanceType, adsk.core.ValueInput.createByReal(1.5))
            assert False, "redefine should fail for an out-of-range proportional distance"
        except RuntimeError:
            pass

        physicalPathDef = adsk.fusion.ConstructionPlanePathDefinition.cast(physicalPathPlane.definition)
        assert physicalPathDef.distanceType == adsk.fusion.PathDistanceTypes.PhysicalPathDistanceType, "a failed redefine should not change the distance type"
        assert abs(physicalPathDef.distance.value - preInvalidDistance) < 1e-6, "a failed redefine should not modify the existing distance value"

        # Redefine a plane created with proportional distance type to use physical distance type
        # instead. This exercises switching distanceType via redefine, not just the distance value.
        distanceTypeSwitchPath = adsk.fusion.Path.create(sketchLineOne, adsk.fusion.ChainedCurveOptions.noChainedCurves)
        planeInput.setByPath(distanceTypeSwitchPath, adsk.fusion.PathDistanceTypes.ProportionalPathDistanceType, adsk.core.ValueInput.createByReal(0.5))
        distanceTypeSwitchPlane = planes.add(planeInput)
        distanceTypeSwitchDef = adsk.fusion.ConstructionPlanePathDefinition.cast(distanceTypeSwitchPlane.definition)
        assert distanceTypeSwitchDef.distanceType == adsk.fusion.PathDistanceTypes.ProportionalPathDistanceType

        distanceTypeSwitchRedefinedPath = adsk.fusion.Path.create(sketchLineTwo, adsk.fusion.ChainedCurveOptions.noChainedCurves)
        switchDistanceTypeResult = distanceTypeSwitchDef.redefine(
            distanceTypeSwitchRedefinedPath, adsk.fusion.PathDistanceTypes.PhysicalPathDistanceType, adsk.core.ValueInput.createByString('15.0 mm'))
        assert switchDistanceTypeResult, "redefine should succeed when switching distance type from proportional to physical"

        distanceTypeSwitchDef = adsk.fusion.ConstructionPlanePathDefinition.cast(distanceTypeSwitchPlane.definition)
        assert distanceTypeSwitchDef.distanceType == adsk.fusion.PathDistanceTypes.PhysicalPathDistanceType, "redefine should switch the distance type to physical"
        assert abs(distanceTypeSwitchDef.distance.value - 1.5) < 1e-6, "distance value should reflect the new physical distance (15.0 mm = 1.5 cm)"
        
        # Add construction plane along a path positioned to a target ("to object") point.
        # The plane is placed where the path reaches the target point, shifted by the offset
        # (zero here means no offset; positive and negative offsets are both allowed).
        toObjectPath = adsk.fusion.Path.create(sketchLineOne, adsk.fusion.ChainedCurveOptions.noChainedCurves)
        zeroOffset = adsk.core.ValueInput.createByReal(0.0)
        planeInput.setByPathToObject(toObjectPath, sketchPointOne, zeroOffset)
        toObjectPlane = planes.add(planeInput)
        
        # Query the ConstructionPlanePathDefinition of the to-object path-based plane.
        # To Object planes report PhysicalPathDistanceType (non-proportional storage); use toObject
        # to distinguish them from Absolute planes.
        toObjectPathDef = adsk.fusion.ConstructionPlanePathDefinition.cast(toObjectPlane.definition)
        toObjectRetrievedPath = toObjectPathDef.path
        toObjectDistanceType = toObjectPathDef.distanceType
        toObjectTarget = toObjectPathDef.toObject
        toObjectOffsetParam = toObjectPathDef.offset
        
        # Redefine the to-object plane with a different target point and a negative offset.
        toObjectRedefinedPath = adsk.fusion.Path.create(sketchLineTwo, adsk.fusion.ChainedCurveOptions.noChainedCurves)
        redefineToObjectResult = toObjectPathDef.redefineToObject(toObjectRedefinedPath, sketchPointTwo, adsk.core.ValueInput.createByString('-2.0 mm'))
        assert redefineToObjectResult, "redefineToObject should succeed for a valid target point and offset"

        # Verify the redefinition took effect.
        toObjectPathDef = adsk.fusion.ConstructionPlanePathDefinition.cast(toObjectPlane.definition)
        assert toObjectPathDef.path.item(0).entity == sketchLineTwo, "redefineToObject should update the path to the new curve"
        assert toObjectPathDef.toObject == sketchPointTwo, "redefineToObject should update the target point"
        assert abs(toObjectPathDef.offset.value - (-0.2)) < 1e-6, "offset value should reflect the new offset (-2.0 mm = -0.2 cm)"

        # Redefine the to-object plane using ConstructionPlanePathDefinition.redefine (not
        # redefineToObject). Per the API contract this intentionally converts the plane from To
        # Object positioning to Proportional/Absolute positioning and clears toObject and offset.
        toObjectToAbsolutePath = adsk.fusion.Path.create(sketchLineOne, adsk.fusion.ChainedCurveOptions.noChainedCurves)
        convertToAbsoluteResult = toObjectPathDef.redefine(
            toObjectToAbsolutePath, adsk.fusion.PathDistanceTypes.PhysicalPathDistanceType, adsk.core.ValueInput.createByString('10.0 mm'))
        assert convertToAbsoluteResult, "redefine should succeed even when converting a To Object plane to Absolute positioning"

        toObjectPathDef = adsk.fusion.ConstructionPlanePathDefinition.cast(toObjectPlane.definition)
        assert toObjectPathDef.toObject is None, "redefine should clear toObject when converting away from To Object positioning"
        assert toObjectPathDef.offset is None, "redefine should clear offset when converting away from To Object positioning"
        assert toObjectPathDef.distanceType == adsk.fusion.PathDistanceTypes.PhysicalPathDistanceType
        assert abs(toObjectPathDef.distance.value - 1.0) < 1e-6, "distance value should reflect the new physical distance (10.0 mm = 1.0 cm)"

        # Redefine the (now Proportional) proportional-path plane using redefineToObject to convert
        # it the other way, from Proportional/Absolute positioning to To Object positioning.
        proportionalToToObjectPath = adsk.fusion.Path.create(sketchLineOne, adsk.fusion.ChainedCurveOptions.noChainedCurves)
        convertToToObjectResult = proportionalPathDef.redefineToObject(
            proportionalToToObjectPath, sketchPointThree, adsk.core.ValueInput.createByReal(0.0))
        assert convertToToObjectResult, "redefineToObject should succeed when converting a Proportional plane to To Object positioning"

        proportionalPathDef = adsk.fusion.ConstructionPlanePathDefinition.cast(proportionalPathPlane.definition)
        assert proportionalPathDef.toObject == sketchPointThree, "redefineToObject should set toObject when converting to To Object positioning"
        assert proportionalPathDef.offset is not None, "redefineToObject should set offset when converting to To Object positioning"
        assert abs(proportionalPathDef.offset.value) < 1e-6, "offset value should reflect the zero offset that was passed in"
        
        # Add construction plane along a chained path using auto-chaining. This mirrors the UI
        # "Chaining" option: picking a single connected sketch line with Chaining turned on
        # automatically extends the path to the connected line(s). sketchLineOne and sketchLineTwo
        # share a topological start sketch point but are not tangent, so connectedChainedCurves
        # (geometrically connected, tangency not required, sketch curves only) auto-finds both lines.
        chainedPath = adsk.fusion.Path.create(sketchLineOne, adsk.fusion.ChainedCurveOptions.connectedChainedCurves)
        planeInput.setByPath(chainedPath, adsk.fusion.PathDistanceTypes.ProportionalPathDistanceType, adsk.core.ValueInput.createByReal(0.433))
        chainedPathPlane = planes.add(planeInput)
        
        # Query the ConstructionPlanePathDefinition to confirm auto-chaining captured both lines.
        chainedPathDef = adsk.fusion.ConstructionPlanePathDefinition.cast(chainedPathPlane.definition)
        chainedRetrievedPath = chainedPathDef.path
        assert chainedRetrievedPath.count == 2, "Auto-chaining should extend the path to both connected sketch lines"

        # Redefine the plane on the same chained (multi-curve) path with a new proportional distance,
        # confirming redefine works correctly when the path spans multiple curves.
        redefineChainedResult = chainedPathDef.redefine(chainedRetrievedPath, adsk.fusion.PathDistanceTypes.ProportionalPathDistanceType, adsk.core.ValueInput.createByReal(0.75))
        assert redefineChainedResult, "redefine should succeed for a plane defined on a chained multi-curve path"

        chainedPathDef = adsk.fusion.ConstructionPlanePathDefinition.cast(chainedPathPlane.definition)
        assert chainedPathDef.path.count == 2, "redefine should preserve the chained path's curve count"
        assert abs(chainedPathDef.distance.value - 0.75) < 1e-6, "redefine should update the distance on a chained path"
        
        # Add construction plane by perpendicular to plane (planar end face of cylinder)
        endFace = extrude.endFaces.item(0)
        planeInput.setByPerpendicularToPlane(endFace)
        planes.add(planeInput)

        # Add construction plane by perpendicular to plane with explicit distance
        offsetDistance = adsk.core.ValueInput.createByReal(2.0)
        planeInput.setByPerpendicularToPlane(endFace, offsetDistance)
        planes.add(planeInput)

        # Add construction plane by perpendicular to plane through a reference vertex
        refVertex = extrude.endFaces.item(0).vertices.item(0)
        planeInput.setByPerpendicularToPlane(endFace, None, refVertex)
        planes.add(planeInput)

        # Add construction plane by perpendicular to plane in V direction (useUDirection=False)
        planeInput.setByPerpendicularToPlane(rootComp.xYConstructionPlane, None, None, False)
        planes.add(planeInput)

        # Add construction plane with extended display mode (isExtended)
        planeInput = planes.createInput()
        planeInput.isExtended = True
        offsetValue = adsk.core.ValueInput.createByReal(5.0)
        planeInput.setByOffset(prof, offsetValue)
        extendedPlane = planes.add(planeInput)
        assert extendedPlane.isExtended, "Plane should be extended after creation with isExtended=True"

        # Toggle isExtended on existing plane
        extendedPlane.isExtended = False
        assert not extendedPlane.isExtended, "Plane should no longer be extended after setting to False"
        extendedPlane.isExtended = True
        assert extendedPlane.isExtended, "Plane should be extended again after setting to True"

    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/Application/ValueInput.h>
#include <Core/Geometry/Point3D.h>
#include <Core/Geometry/Vector3D.h>
#include <Core/UserInterface/UserInterface.h>
#include <Fusion/Components/Component.h>
#include <Fusion/Construction/ConstructionPlane.h>
#include <Fusion/Construction/ConstructionPlanes.h>
#include <Fusion/Construction/ConstructionPlaneInput.h>
#include <Fusion/Fusion/Design.h>
#include <Fusion/Sketch/Sketch.h>
#include <Fusion/Sketch/Sketches.h>
#include <Fusion/Sketch/SketchPoints.h>
#include <Fusion/Sketch/SketchPoint.h>
#include <Fusion/Sketch/SketchCurves.h>
#include <Fusion/Sketch/SketchCircles.h>
#include <Fusion/Sketch/SketchCircle.h>
#include <Fusion/Sketch/SketchLines.h>
#include <Fusion/Sketch/SketchLine.h>
#include <Fusion/Sketch/SketchPoints.h>
#include <Fusion/Sketch/SketchPoint.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/BRep/BRepFaces.h>
#include <Fusion/BRep/BRepFace.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 sketch
    Ptr<Sketches> sketches = rootComp->sketches();
    if (!sketches)
        return false;

    Ptr<Sketch> sketch = sketches->add(rootComp->xYConstructionPlane());
    if (!sketch)
        return false;

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

    Ptr<SketchCircles> circles = curves->sketchCircles();
    if (!circles)
        return false;
    Ptr<Point3D> centerPoint = Point3D::create(0, 0, 0);
    circles->addByCenterRadius(centerPoint, 5.0);

    // Get the profile defined by the circle
    Ptr<Profiles> profs = sketch->profiles();
    if (!profs)
        return false;
    Ptr<Profile> prof = profs->item(0);

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

    Ptr<ExtrudeFeatures> extrudes = features->extrudeFeatures();
    if (!extrudes)
        return false;
    Ptr<ExtrudeFeatureInput> extInput = extrudes->createInput(prof, FeatureOperations::NewBodyFeatureOperation);

    // Define that the extent is a distance extent of 5 cm
    Ptr<ValueInput> distance = ValueInput::createByReal(5.0);

    // Set the distance extent to be symmetric
    extInput->setDistanceExtent(true, distance);

    // Set the extrude to be a solid one
    extInput->isSolid(true);

    // Create an cylinder
    Ptr<ExtrudeFeature> extrude = extrudes->add(extInput);
    if (!extrude)
        return false;

    // Create sketch line
    Ptr<SketchLines> sketchLines = curves->sketchLines();
    if (!sketchLines)
        return false;
    Ptr<Point3D> startPoint = Point3D::create(5.0, 5.0, 0);
    Ptr<Point3D> endPoint = Point3D::create(5.0, 10.0, 0);
    Ptr<SketchLine> sketchLineOne = sketchLines->addByTwoPoints(startPoint, endPoint);
    Ptr<Point3D> endPointTwo = Point3D::create(10.0, 5.0, 0);
    Ptr<SketchLine> sketchLineTwo = sketchLines->addByTwoPoints(startPoint, endPointTwo);

    // Create three sketch points
    Ptr<SketchPoints> sketchPoints = sketch->sketchPoints();
    if (!sketchPoints)
        return false;
    Ptr<Point3D> positionOne = Point3D::create(0, 5.0, 0);
    Ptr<SketchPoint> sketchPointOne = sketchPoints->add(positionOne);
    Ptr<Point3D> positionTwo = Point3D::create(5.0, 0, 0);
    Ptr<SketchPoint> sketchPointTwo = sketchPoints->add(positionTwo);
    Ptr<Point3D> positionThree = Point3D::create(0, -5.0, 0);
    Ptr<SketchPoint> sketchPointThree = sketchPoints->add(positionThree);

    prof = profs->item(0);

    // Get construction planes
    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(3.0);
    planeInput->setByOffset(prof, offsetValue);
    Ptr<ConstructionPlane> planeOne = planes->add(planeInput);

    // Get the health state of a construction plane
    adsk::fusion::FeatureHealthStates health = planeOne->healthState();
    if (health == adsk::fusion::FeatureHealthStates::ErrorFeatureHealthState ||
        health == adsk::fusion::FeatureHealthStates::WarningFeatureHealthState)
    {
        std::string msg = planeOne->errorOrWarningMessage();
    }

    // Add construction plane by angle
    Ptr<ValueInput> angle = ValueInput::createByString("30.0 deg");
    planeInput->setByAngle(sketchLineOne, angle, prof);
    planes->add(planeInput);

    // Add construction plane by two planes
    planeInput->setByTwoPlanes(prof, planeOne);
    planes->add(planeInput);

    // Add construction plane by tangent
    Ptr<BRepFaces> extSideFaces = extrude->sideFaces();
    if (!extSideFaces)
        return false;
    Ptr<BRepFace> cylinderFace = extSideFaces->item(0);
    planeInput->setByTangent(cylinderFace, angle, rootComp->xZConstructionPlane());
    planes->add(planeInput);

    // Add construction plane by two edges
    planeInput->setByTwoEdges(sketchLineOne, sketchLineTwo);
    planes->add(planeInput);

    // Add construction plane by three points
    planeInput->setByThreePoints(sketchPointOne, sketchPointTwo, sketchPointThree);
    planes->add(planeInput);

    // Add construction plane by tangent at point
    planeInput->setByTangentAtPoint(cylinderFace, sketchPointOne);
    planes->add(planeInput);

    // Add construction plane by distance on path
    distance = ValueInput::createByReal(1.0);
    planeInput->setByDistanceOnPath(sketchLineOne, distance);
    planes->add(planeInput);

    return true;
}
/**
 * Construction Plane API Sample
 * Demonstrates creating construction plane by different ways.
 */

import { adsk } from '@adsk/fusion';

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

  // Create a document.
  const doc = app.documents.add(adsk.core.DocumentTypes.FusionDesignDocumentType)

  // Create a document.
  const design = app.activeProduct as adsk.fusion.Design

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

  // Create sketch
  const sketches = rootComp.sketches
  const sketch = sketches.add(rootComp.xZConstructionPlane)

  // Create sketch circle
  const sketchCircles = sketch.sketchCurves.sketchCircles
  const centerPoint = adsk.core.Point3D.create(0, 0, 0)
  sketchCircles.addByCenterRadius(centerPoint, 5.0)

  // Get the profile defined by the circle
  let prof = sketch.profiles.item(0)

  // Create an extrusion input
  const extrudes = rootComp.features.extrudeFeatures
  const extInput = extrudes.createInput(prof, adsk.fusion.FeatureOperations.NewBodyFeatureOperation)

  // Define that the extent is a distance extent of 5 cm
  const distance1 = adsk.core.ValueInput.createByReal(5)
  // Set the distance extent to be symmetric
  extInput.setSymmetricExtent(distance1, adsk.fusion.ExtentDirections.PositiveExtentDirection)

  // Set the extrude to be a solid one
  extInput.isSolid = true

  // Create an cylinder
  const extrude = extrudes.add(extInput)
  // Create sketch line
  const sketchLines = sketch.sketchCurves.sketchLines
  const startPoint = adsk.core.Point3D.create(5, 5, 0)
  const endPoint = adsk.core.Point3D.create(5, 10, 0)
  const sketchLineOne = sketchLines.addByTwoPoints(startPoint, endPoint)
  const endPointTwo = adsk.core.Point3D.create(10, 5, 0)
  const sketchLineTwo = sketchLines.addByTwoPoints(startPoint, endPointTwo)

  // Create three sketch points
  const sketchPoints = sketch.sketchPoints
  const positionOne = adsk.core.Point3D.create(0, 5.0, 0)
  const sketchPointOne = sketchPoints.add(positionOne)
  const positionTwo = adsk.core.Point3D.create(5.0, 0, 0)
  const sketchPointTwo = sketchPoints.add(positionTwo)
  const positionThree = adsk.core.Point3D.create(0, -5.0, 0)
  const sketchPointThree = sketchPoints.add(positionThree)

  // Get the profile again since the sketch has been edit.
  prof = sketch.profiles.item(0)

  // Get construction planes
  const planes = rootComp.constructionPlanes

  // Create construction plane input
  const planeInput = planes.createInput()

  // Add construction plane by offset
  const offsetValue = adsk.core.ValueInput.createByReal(3.0)
  planeInput.setByOffset(prof, offsetValue)
  const planeOne = planes.add(planeInput)

  // Get the health state of the plane
  let message = ""
  const health = planeOne.healthState
  if (health == adsk.fusion.FeatureHealthStates.WarningFeatureHealthState || health == adsk.fusion.FeatureHealthStates.ErrorFeatureHealthState) {
    message = axis.errorOrWarningMessage
  }
  adsk.log(message)

  // Add construction plane by angle
  const angle = adsk.core.ValueInput.createByString('30.0 deg')
  planeInput.setByAngle(sketchLineOne, angle, prof)
  planes.add(planeInput)

  // Add construction plane by two planes
  planeInput.setByTwoPlanes(prof, planeOne)
  planes.add(planeInput)

  // Add construction plane by tangent
  const cylinderFace = extrude.sideFaces.item(0)
  planeInput.setByTangent(cylinderFace, angle, rootComp.xYConstructionPlane)
  planes.add(planeInput)

  // Add construction plane by two edges
  planeInput.setByTwoEdges(sketchLineOne, sketchLineTwo)
  planes.add(planeInput)

  // Add construction plane by three points
  planeInput.setByThreePoints(sketchPointOne, sketchPointTwo, sketchPointThree)
  planes.add(planeInput)

  // Add construction plane by tangent at point
  planeInput.setByTangentAtPoint(cylinderFace, sketchPointOne)
  planes.add(planeInput)

  // Add construction plane by distance on path
  const distance2 = adsk.core.ValueInput.createByReal(1.0)
  planeInput.setByDistanceOnPath(sketchLineOne, distance2)
  planes.add(planeInput)

}
run();