Demonstrates how to create a Volumetric Custom Feature using the API for graph creation.
To run the sample script, have a document open in Fusion’s DESIGN workspace. This script will create a component with a box by sketching then extruding that sketch. It will then use that box as a boundary body and create a Volumetric Custom Feature.
The script will then create a gyroid lattice using the Volumetric Model API with the appropriate graphs, nodes, and pin connections for a minimal example. Finally, the script will convert that Volumetric Model to Mesh using the API and the VolumetricModelToMeshFeature.
/** * Volumetric Custom Feature API Sample * Demonstrates how to create a Volumetric Custom Feature using the API for graph creation. To run the sample script, have a document open in Fusion’s DESIGN workspace. This script will create a component with a box by s... */ import { adsk } from "@adsk/fusion"; function volumetricGraph(volumetricModel: adsk.volume.VolumetricModel): void { const primaryGraph = volumetricModel.getGraph(adsk.volume.GraphTypes.PrimaryGraphType); const cellGraph = volumetricModel.getGraph(adsk.volume.GraphTypes.CellGraphType); const primaryNodes = primaryGraph.nodes; const cellNodes = cellGraph.nodes; // Constant density node -> lattice density output. // The density channel and a default ConstantDensity node may already exist, so reuse the // existing node (disconnecting it first) and only add a new one when it is missing. const densityChannel = primaryNodes.outputNode(adsk.volume.GraphOutputNodeTypes.LatticeDensityOutputNodeType); let node1 = primaryNodes.itemByName("ConstantDensity"); if (!node1) { node1 = primaryNodes.add("ConstantDensity", "ConstantScalar"); if (!node1) throw new Error("Failed to add ConstantDensity node."); } else { node1.outputPins.item(0)!.disconnect(densityChannel!.inputPins.item(0)!); } (node1.properties.itemByName("value") as adsk.volume.ScalarGraphNodeProperty).value = 0.5; if (!node1.outputPins.item(0)!.connect(densityChannel!.inputPins.item(0)!)) throw new Error("Failed to connect node1 to density channel."); // Coordinate transform node with asymmetric scaling -> lattice coordinates output const node2 = primaryNodes.add("NoTransform", "TransformCoords"); if (!node2) throw new Error("Failed to add NoTransform node."); (node2.properties.itemByName("scaling") as adsk.volume.Vector3DGraphNodeProperty).value = adsk.core.Vector3D.create(1, 2, 3); const coordinateOutput = primaryNodes.outputNode(adsk.volume.GraphOutputNodeTypes.LatticeCoordinatesOutputNodeType); if (!node2.outputPins.item(0)!.connect(coordinateOutput!.inputPins.item(0)!)) throw new Error("Failed to connect node2 to coordinate channel."); // Gyroid function node -> cell lattice shape output const node3 = cellNodes.add("gyroid", "FunctionVectorToScalar"); if (!node3) throw new Error("Failed to add gyroid node."); (node3.properties.itemByName("function") as adsk.volume.StringGraphNodeProperty).value = "(sin(x*pi2)*cos(y*pi2)+sin(y*pi2)*cos(z*pi2)+sin(z*pi2)*cos(x*pi2))*0.333333333+0.5"; const cellDensityChannel = cellNodes.outputNode(adsk.volume.GraphOutputNodeTypes.CellLatticeShapeOutputNodeType); if (!node3.outputPins.item(0)!.connect(cellDensityChannel!.inputPins.item(0)!)) throw new Error("Failed to connect node3 to cell lattice shape channel."); } function run(): void { const app = adsk.core.Application.get(); if (!app) throw new Error("No adsk.core.Application."); if (!adsk.volume) throw new Error("No adsk.volume namespace."); if (adsk.volume.GraphTypes.PrimaryGraphType === undefined) throw new Error("enum GraphTypes.PrimaryGraphType is undefined."); if (adsk.volume.VolumetricModel === undefined) throw new Error("class VolumetricModel is undefined."); // Create a new parametric design document to work in const newDoc = app.documents.add(adsk.core.DocumentTypes.FusionDesignDocumentType); if (!newDoc) throw new Error("Failed to create a new Fusion design document."); const design = app.activeProduct as adsk.fusion.Design; if (!design) throw new Error("No active Fusion design."); design.designType = adsk.fusion.DesignTypes.ParametricDesignType; const rootComp = design.rootComponent; // Create a new component occurrence to work in const newCompOcc = rootComp.occurrences.addNewComponent(adsk.core.Matrix3D.create()); const newComp = newCompOcc.component; // Sketch a 10x10 rectangle and extrude 10 cm to produce a boundary body const sketch = newComp.sketches.add(newComp.xYConstructionPlane); sketch.sketchCurves.sketchLines.addTwoPointRectangle( adsk.core.Point3D.create(0, 0, 0), adsk.core.Point3D.create(10, 10, 0) ); sketch.isComputeDeferred = false; const extrudeFeatures = newComp.features.extrudeFeatures; const extrudeInput = extrudeFeatures.createInput( sketch.profiles.item(0)!, adsk.fusion.FeatureOperations.NewBodyFeatureOperation ); const distanceExtent = adsk.fusion.DistanceExtentDefinition.create( adsk.core.ValueInput.createByString("10 cm") ); extrudeInput.setOneSideExtent(distanceExtent, adsk.fusion.ExtentDirections.PositiveExtentDirection); const extrude = extrudeFeatures.add(extrudeInput); if (!extrude) throw new Error("Extrude failed."); const body = extrude.bodies.item(0)!.createForAssemblyContext(newCompOcc)!; const comp = newCompOcc.component; const features = comp.features; // Create the VolumetricModel feature on the body first const volumetricModelFeatures = features.volumetricModelFeatures; const volumetricModelFeatureInput = volumetricModelFeatures.createInput(body); if (!volumetricModelFeatureInput) throw new Error("VolumetricModelFeatures.createInput returned null."); const volumetricModelFeature = volumetricModelFeatures.add(volumetricModelFeatureInput); if (!volumetricModelFeature) throw new Error("VolumetricModelFeatures.add returned null."); // Create a custom feature on top of the existing volumetric model const volumetricCustomFeatures = features.volumetricCustomFeatures; const volumetricCustomFeatureInput = volumetricCustomFeatures.createInput(body); if (!volumetricCustomFeatureInput) throw new Error("VolumetricCustomFeatures.createInput returned null."); const volumetricCustomFeature = volumetricCustomFeatures.add(volumetricCustomFeatureInput); if (!volumetricCustomFeature) throw new Error("VolumetricCustomFeatures.add returned null."); const volumetricModel = volumetricCustomFeature.volumetricModel as adsk.volume.VolumetricModel; if (!volumetricModel) throw new Error("volumetricModel is null."); volumetricGraph(volumetricModel); // Convert the volumetric model to a mesh const volumetricModelToMeshFeatures = features.volumetricModelToMeshFeatures; const volumetricModelToMeshInput = volumetricModelToMeshFeatures.createInput(volumetricModel); if (!volumetricModelToMeshInput) throw new Error("VolumetricModelToMeshFeatures.createInput returned null."); volumetricModelToMeshInput.isComputeSuspended = true; volumetricModelToMeshInput.isSmallShellsRemoved = true; volumetricModelToMeshInput.isVolumetricModelRemoved = true; volumetricModelToMeshInput.smallShellThreshold = adsk.core.ValueInput.createByString("0.05"); volumetricModelToMeshInput.meshingApproach = adsk.fusion.VolumetricMeshingApproachTypes.VolumetricMeshingAdvancedType; volumetricModelToMeshInput.refinementType = adsk.fusion.VolumetricMeshRefinementTypes.VolumetricMeshRefinementMediumType; volumetricModelToMeshFeatures.add(volumetricModelToMeshInput); } run();
# Description: This script is used to create a volumetric model in the API import os, adsk.core, adsk.fusion, adsk.volume, traceback, time def CreateVolumetricModel(component:adsk.fusion.Component,body): """Creation of the volumetric model""" features = component.features # Create the VolumetricModel feature on the body first volumetricModelFeatures = features.volumetricModelFeatures volumetricModelFeatureInput = volumetricModelFeatures.createInput(body) volumetricModelFeature = volumetricModelFeatures.add(volumetricModelFeatureInput) volumetricModel = adsk.volume.VolumetricModel.cast(volumetricModelFeature.volumetricModel) # Create a custom feature on top of the existing volumetric model volumetricCustomFeatures = features.volumetricCustomFeatures volumetricCustomFeatureInput = volumetricCustomFeatures.createInput(volumetricModel) volumetricCustomFeature = volumetricCustomFeatures.add(volumetricCustomFeatureInput) volumetricModel = adsk.volume.VolumetricModel.cast(volumetricCustomFeature.volumetricModel) return volumetricModel def VolumetricGraph(volumetricModel): """Assigning graph and modifying it (adding volume/density)""" #AS LONG AS THE VOLUMETRIC MODEL IS NOT NULL, WE HAVE SUCCESSFULLY CREATED A VOLUMETRIC MODEL #Call the graph and create a volume using it. Add a simple sphere for density as offset. primaryGraph = volumetricModel.getGraph(adsk.volume.GraphTypes.PrimaryGraphType) cellGraph = volumetricModel.getGraph(adsk.volume.GraphTypes.CellGraphType) primaryNodes = primaryGraph.nodes cellNodes = cellGraph.nodes # All the channels are created by default as well as the Boundary sdf # Create a density node and connect it to the density channel (Primary Graph) densityChannel = primaryNodes.outputNode(adsk.volume.GraphOutputNodeTypes.LatticeDensityOutputNodeType) node1 = primaryNodes.itemByName("ConstantDensity") if not node1: node1 = primaryNodes.add("ConstantDensity", "ConstantScalar") else: node1.outputPins.item(0).disconnect(densityChannel.inputPins.item(0)) node1.properties.itemByName("value").value = 0.5 assert node1.outputPins.item(0).connect(densityChannel.inputPins.item(0)), "Failed to connect the node to the density channel" # Create a coordinate node and connect it to the coordinate channel (Primary Graph) node2 = primaryNodes.add("NoTransform", "TransformCoords") node2.properties.itemByName("scaling").value = adsk.core.Vector3D.create(1, 2, 3) # Scale the lattice asymmetrically coordinateOutput = primaryNodes.outputNode(adsk.volume.GraphOutputNodeTypes.LatticeCoordinatesOutputNodeType) assert node2.outputPins.item(0).connect(coordinateOutput.inputPins.item(0)), "Failed to connect the node to the coordinate channel" # Get the density output node from the cell graph and connect the density node to it node3 = cellNodes.add("gyroid", "FunctionVectorToScalar") node3.properties.itemByName("function").value = "(sin(x*pi2)*cos(y*pi2)+sin(y*pi2)*cos(z*pi2)+sin(z*pi2)*cos(x*pi2))*0.333333333+0.5" cellDensityChannel = cellNodes.outputNode(adsk.volume.GraphOutputNodeTypes.CellLatticeShapeOutputNodeType) assert node3.outputPins.item(0).connect(cellDensityChannel.inputPins.item(0)), "Failed to connect the node to the density channel" def run(context): ui = None try: ### Lines from 56 to 84 preparing a document to work with. Creating a body and volumetric lattice. # ALL THIS CODE IS TO GET A BODY AND COMPONENT TO WORK WITH app = adsk.core.Application.get() ui = app.userInterface # Create a new document new_doc = app.documents.add(adsk.core.DocumentTypes.FusionDesignDocumentType) product = app.activeProduct design = adsk.fusion.Design.cast(product) design.designType = adsk.fusion.DesignTypes.ParametricDesignType rootComp = design.rootComponent # new component newCompOcc = rootComp.occurrences.addNewComponent(adsk.core.Matrix3D.create()) newComp = newCompOcc.component # create a new sketch sketches = newComp.sketches sketch = sketches.add(newComp.xYConstructionPlane) sketch.sketchCurves.sketchLines.addTwoPointRectangle(adsk.core.Point3D.create(0, 0, 0), adsk.core.Point3D.create(10, 10, 0)) sketch.isComputeDeferred = False extrudeFeatures = newComp.features.extrudeFeatures extrudeInput = extrudeFeatures.createInput(sketch.profiles.item(0), adsk.fusion.FeatureOperations.NewBodyFeatureOperation) distanceExtent = adsk.fusion.DistanceExtentDefinition.create(adsk.core.ValueInput.createByString('10 cm')) direction = adsk.fusion.ExtentDirections.PositiveExtentDirection extrudeInput.setOneSideExtent(distanceExtent, direction) extrude = extrudeFeatures.add(extrudeInput) body = extrude.bodies.item(0) body = body.createForAssemblyContext(newCompOcc) ### Creating a volumetric model comp = newCompOcc.component features = comp.features # Create the VolumetricModel feature on the body first volumetricModelFeatures = features.volumetricModelFeatures volumetricModelFeatureInput = volumetricModelFeatures.createInput(body) volumetricModelFeature = volumetricModelFeatures.add(volumetricModelFeatureInput) # Create a custom feature on top of the existing volumetric model volumetricCustomFeatures = features.volumetricCustomFeatures volumetricCustomFeatureInput = volumetricCustomFeatures.createInput(body) volumetricCustomFeature = volumetricCustomFeatures.add(volumetricCustomFeatureInput) volumetricModel = adsk.volume.VolumetricModel.cast(volumetricCustomFeature.volumetricModel) VolumetricGraph(volumetricModel) ### Convert to volumetric feature to mesh. # Now we should have valid volumetric models We need to create a Volumetric Model To Mesh volumetricModelToMeshFeatures = features.volumetricModelToMeshFeatures volumetricModelToMeshFeatureInput = volumetricModelToMeshFeatures.createInput(volumetricModel) # Setting all the properties for the volumetric model to mesh feature, though defaults are fine. volumetricModelToMeshFeatureInput.isComputeSuspended = True volumetricModelToMeshFeatureInput.isSmallShellsRemoved = True volumetricModelToMeshFeatureInput.isVolumetricModelRemoved = True volumetricModelToMeshFeatureInput.smallShellThreshold = adsk.core.ValueInput.createByString("0.05") volumetricModelToMeshFeatureInput.meshingApproach = adsk.fusion.VolumetricMeshingApproachTypes.VolumetricMeshingAdvancedType volumetricModelToMeshFeatureInput.refinementType = adsk.fusion.VolumetricMeshRefinementTypes.VolumetricMeshRefinementMediumType # Create the volumetric model to mesh feature volumetricModelToMeshFeatures.add(volumetricModelToMeshFeatureInput) except: if ui: ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))