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 the create a gyroid lattice using the Volumetric Model API with the appropriate Graphs, Nodes and 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); // 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 = primaryGraph.getOutputNode(adsk.volume.GraphOutputNodeTypes.LatticeDensityOutputNodeType); let node1 = primaryGraph.getNode("ConstantDensity"); if (!node1) { node1 = primaryGraph.addNode("ConstantDensity", "ConstantScalar"); if (!node1) throw new Error("Failed to add ConstantDensity node."); } else { primaryGraph.disconnect(node1, 0, densityChannel!, 0); } (node1.properties.itemByName("value") as adsk.volume.ScalarGraphNodeProperty).value = 0.5; if (!primaryGraph.connect(node1, 0, densityChannel!, 0)) throw new Error("Failed to connect node1 to density channel."); // Coordinate transform node with asymmetric scaling -> lattice coordinates output const node2 = primaryGraph.addNode("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 = primaryGraph.getOutputNode(adsk.volume.GraphOutputNodeTypes.LatticeCoordinatesOutputNodeType); if (!primaryGraph.connect(node2, 0, coordinateOutput!, 0)) throw new Error("Failed to connect node2 to coordinate channel."); // Gyroid function node -> cell lattice shape output const node3 = cellGraph.addNode("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 = cellGraph.getOutputNode(adsk.volume.GraphOutputNodeTypes.CellLatticeShapeOutputNodeType); if (!cellGraph.connect(node3, 0, cellDensityChannel!, 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 #Creating volumetric model input with the body VolumetricCustomFeatures = features.volumetricCustomFeatures volumetricCustomFeatureInput = VolumetricCustomFeatures.createInput(body) volumetricCustomFeature = VolumetricCustomFeatures.add(volumetricCustomFeatureInput) # build a simple volume - returns type adsk.core.Base volumetricModel = volumetricCustomFeature.volumetricModel # cast to a adsk.volume.VolumetricModel volumetricModel = adsk.volume.VolumetricModel.cast(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) # 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) node1 = primaryGraph.addNode("ConstantDensity", "ConstantScalar") node1.properties.itemByName("value").value = 0.5 densityChannel = primaryGraph.getOutputNode(adsk.volume.GraphOutputNodeTypes.LatticeDensityOutputNodeType) assert primaryGraph.connect(node1, 0, densityChannel, 0), "Failed to connect the node to the density channel" # Create a coordinate node and connect it to the coordinate channel (Primary Graph) node2 = primaryGraph.addNode("NoTransform", "TransformCoords") node2.properties.itemByName("scaling").value = adsk.core.Vector3D.create(1, 2, 3) # Scale the lattice asymmetrically coordinateOutput = primaryGraph.getOutputNode(adsk.volume.GraphOutputNodeTypes.LatticeCoordinatesOutputNodeType) assert primaryGraph.connect(node2, 0, coordinateOutput, 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 = cellGraph.addNode("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 = cellGraph.getOutputNode(adsk.volume.GraphOutputNodeTypes.CellLatticeShapeOutputNodeType) assert cellGraph.connect(node3, 0, cellDensityChannel, 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 product = app.activeProduct design = adsk.fusion.Design.cast(product) 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 VolumetricCustomFeatures = features.volumetricCustomFeatures volumetricCustomFeatureInput = VolumetricCustomFeatures.createInput(body) volumetricCustomFeature = VolumetricCustomFeatures.add(volumetricCustomFeatureInput) # build a simple volume - returns type adsk.core.Base volumetricModel = volumetricCustomFeature.volumetricModel # cast to a adsk.volume.VolumetricModel for autocompletion volumetricModel = adsk.volume.VolumetricModel.cast(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()))