Announcements
Attention for Customers without Multi-Factor Authentication or Single Sign-On - OTP Verification rolls out April 2025. Read all about it here.

Create Fluid Volume with API

j.han97
Advocate

Create Fluid Volume with API

j.han97
Advocate
Advocate

Hi all,

 

There is this 'Fluid Volume' command under Solid > Create panel which is pretty useful: (Note: this command only appears in Direct Design mode)

 

jhan97_0-1653375087936.png

 

However, I can't find anything related in the API, so I am guessing this functionality is not exposed in API (yet?).

 

If it cannot be accessed through API, my only chances are to execute it using text commands (I have not tried it, not sure if I can make it work). Or is there any other way to achieve the same functionality, perhaps with a combination of other commands (Combine/Cut, Shell, Interference etc)?

 

My objective is to extract the internal volume of a body, here is a simple demonstration:

jhan97_2-1653375751090.pngjhan97_1-1653375739519.png

 

 

Any idea will be appreciated! Thanks!

0 Likes
Reply
433 Views
7 Replies
Replies (7)

dozerdroid
Enthusiast
Enthusiast

I cannot find the Fluid Volume on the panel ? If someone could give me a pointer I would appreciate it as it would be useful to me. Thx.

1 Like

BrianEkins
Mentor
Mentor

I was also unfamiliar with this command. Here's the help topic that shows the two locations to access it and describes its functionality.

 

The functionality of this command is not exposed by the API. After playing with it a bit, it seems like for some cases you can get the same results using the API. I think for others it would be much more difficult. The easy case is essentially where you would create a body that overlaps the existing body and then create a Combine feature where you cut the original body away from the new overlapping body, which leaves behind the internal cavities. 

---------------------------------------------------------------
Brian Ekins
Inventor and Fusion 360 API Expert
Website/Blog: https://EkinsSolutions.com
1 Like

j.han97
Advocate
Advocate

Hi @dozerdroid ,

 

The exact location of this command (for me) is: Design Workspace -> Solid tab -> Create Panel. It is located between 'Find Features' & 'Create PCB' commands.

 

If you are capturing design history, remember to switch it off (Right click rootComponent -> Do not capture design history). I noticed that this command won't appear in parametric modelling.

 

 

0 Likes

j.han97
Advocate
Advocate

Hi @BrianEkins ,

 

Thanks for your suggestion! I have thought of the Combine feature as well, but just like you mentioned, this only works on straightforward cases where the geometry is simple. While in fact, the bodies could have external features, which makes it difficult to determine a suitable overlapping body.

 

I was working on an alternative method using the BoundaryFillFeature. The principle is quite simple (I thought), but implementing it is way more troublesome than I thought.

 

Here is the principle:

1. Patch the holes on external faces (or known as capping)

2. Create a boundaryFillFeatureInput with the initial body & the surface patches

3. It provides bRepCells (partially-computation of boundaryFillFeatureInput) which occupy the volume of [initial body, inner cavities]

4. To filter out the cell that occupies initial body, interferences are analyzed. The cell that intersects with initial body is abandoned

5. Create the boundaryFillFeature with the remaining cells, this should be the inner-cavity bodies.

6. [Misc] As planned in my command, the inner-cavity bodies are for executePreview only, therefore a customGraphicsGroup is created to show these bodies.

 

The code I was working on & the sample model are attached. To use the command, select the body and click Compute button. The inner volume will be highlighted.

 

I am still working on this and looking for improvement/optimization. Any feedback & suggestion are welcomed! 

0 Likes

j.han97
Advocate
Advocate

I suddenly realize that if I just select all cells of boundaryFillFeatureInput, the resulting body will be have the external geometry of the original body, perfectly overlapping it. So I could just cut this overlapping body with the original body and get the inner cavities.  

 

 

1 Like

kandennti
Mentor
Mentor

Hi @j.han97 .

 

It looked interesting, so I gave it a try.

I think the results are almost equivalent to those obtained by running the Fluid Volume command with the settings "External"-"Box"-"0".

1.png

# Fusion360API Python script

import traceback
import adsk.fusion
import adsk.core
import itertools


def run(context):
    ui = adsk.core.UserInterface.cast(None)
    try:
        app: adsk.core.Application = adsk.core.Application.get()
        ui = app.userInterface

        msg: str = 'Select Trget Body'
        selFilter: str = 'Bodies'
        sel: adsk.core.Selection = selectEnt(msg, selFilter)
        if not sel:
            return

        targetBody: adsk.fusion.BRepBody = sel.entity

        createFluidVolumeExternalLike(targetBody)


    except:
        if ui:
            ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

def createFluidVolumeExternalLike(
    body: adsk.fusion.BRepBody) -> list:

    # ***********
    def addBodies(
        comp: adsk.fusion.Component,
        bodyLst: list) -> list:

        des: adsk.fusion.Design = comp.parentDesign

        baseFeat: adsk.fusion.BaseFeature = None
        if des.designType == adsk.fusion.DesignTypes.ParametricDesignType:
            baseFeat = comp.features.baseFeatures.add()

        bodies: adsk.fusion.BRepBodies = comp.bRepBodies

        if baseFeat:
            baseFeat.startEdit()
            try:
                [bodies.add(b, baseFeat) for b in bodyLst]
            except:
                pass
            finally:
                baseFeat.finishEdit()
                return [b for b in baseFeat.bodies]
        else:
            return [bodies.add(b) for b in bodyLst]

    def getExternalShells(
        shells: adsk.fusion.BRepShells,
        faces: list) -> list:

        return [shell for shell in shells if isExternal(shell, faces)]

    def isExternal(
        shell: adsk.fusion.BRepShell,
        faces: list) -> bool:

        pnts = [v.geometry for v in shell.vertices]
        for [p, f] in list(itertools.product(pnts, faces)):
            if isPointOnFace(p, f):
                return True

        return False

    def isPointOnFace(
        point: adsk.core.Point3D,
        face: adsk.fusion.BRepFace) -> bool:

        eva: adsk.core.SurfaceEvaluator = face.evaluator
        _, prm = eva.getParameterAtPoint(point)
        _, pnt = eva.getPointAtParameter(prm)
        if not pnt.isEqualTo(point):
            return False

        return eva.isParameterOnFace(prm)
    # ***********

    app: adsk.core.Application = adsk.core.Application.get()
    des: adsk.fusion.Design = app.activeProduct
    root: adsk.fusion.Component = des.rootComponent

    # Clone
    tmpMgr: adsk.fusion.TemporaryBRepManager = adsk.fusion.TemporaryBRepManager.get()
    clone: adsk.fusion.BRepBody = tmpMgr.copy(body)

    # BoundingBox
    measMgr: adsk.core.MeasureManager = app.measureManager
    bBox: adsk.core.OrientedBoundingBox3D = measMgr.getOrientedBoundingBox(
        clone,
        adsk.core.Vector3D.create(1, 0, 0),
        adsk.core.Vector3D.create(0, 1, 0),
    )
    difBody: adsk.fusion.BRepBody = tmpMgr.createBox(bBox)
    brepBBox: adsk.fusion.BRepBody = addBodies(root, [difBody])[0]

    # Difference
    tmpMgr.booleanOperation(
        difBody,
        clone,
        adsk.fusion.BooleanTypes.DifferenceBooleanType
    )

    # External shells
    externals = getExternalShells(difBody.shells, brepBBox.faces)
    brepBBox.deleteMe()

    occ: adsk.fusion.Occurrence = root.occurrences.addNewComponent(
        adsk.core.Matrix3D.create()
    )
    comp: adsk.fusion.Component = occ.component

    # Add bodies
    bodies = [tmpMgr.copy(s) for s in externals]
    addBodies(comp, bodies)


def selectEnt(
        msg: str,
        filterStr: str) -> adsk.core.Selection:

    try:
        app = adsk.core.Application.get()
        ui = app.userInterface
        sel = ui.selectEntity(msg, filterStr)
        return sel
    except:
        return None

 

The Fluid Volume command is only available for DirectDesignType, but when using ParametricDesignType, I created Bodies as BaseFeature.

1.png

 

1 Like

j.han97
Advocate
Advocate

Thanks @kandennti for your idea! I am not entirely convinced that your method is suitable for this use case because the geometries could be very complicated with lots of external features. The external bounding box method cannot effectively differentiate between internal/external cavities.

 

I follow on my previous thoughts and @BrianEkins suggestions to use boundaryFillFeature to find the external-shape of the body, then use CombineFeature to cut the original bodies, finally obtaining the inner-cavity bodies.

 

The code & samples I have used are attached with this reply, and I would like to show some demonstration of the add-in:

jhan97_0-1653553450820.png

The add-in will add a button near the end of modify panel

jhan97_1-1653553531558.png

Sample model for demonstration.

jhan97_2-1653553647978.png

Fluid Volume command [internal, with patched openings] to show the internal cavities

 

jhan97_4-1653553866612.png

Run the command and select bodies to be involved. If multiple bodies are selected, they will be combined.

jhan97_5-1653553993454.png

Click Compute button to preview the result

jhan97_6-1653554024275.png

3 internal cavities are identified and highlighted

 

Note: Till this step, the original objective of this thread is achieved. But I was actually trying to do something a little bit different. A further step is taken to remove the internal cavities (simply by merging them with the target body). Since this feels like a two-phase action (identify cavities ----> remove cavities), I separated them into two commands, and set the first command to execute the second command when it finishes. 

 

Clicking OK will lead to second phase --- removing internal cavities:

jhan97_7-1653554437098.png

Similar display highlighting the inner cavities. Note differences of command dialog (Remove cavity)

jhan97_8-1653554489803.png

Select cavities to be removed and click OK

jhan97_10-1653554550154.png

jhan97_9-1653554541971.png

Now the inner cavities are removed

 

Not sure if this will be useful for anyone else, but it does make my workflow easier. Just sharing it for fun though, cheers!

1 Like