Community
Fusion API and Scripts
Got a new add-in to share? Need something specialized to be scripted? Ask questions or share what you’ve discovered with the community.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Export surface from plane cut

6 REPLIES 6
Reply
Message 1 of 7
ivr22
447 Views, 6 Replies

Export surface from plane cut

Hi all,

 

I'm new to the Fusion 360 API and am looking for a way to automate the exporting of the surface (or just the points along the edge of the surface) when doing a plane cut along a body.

I've managed to make a plane cut along a spiral path along a defined spline and am automating that. But then I need to export the export the intersection of the plane and the body to get the cross-sectional area etc. (shown in blue in the second image. I need to do this in Python to automate the extraction of the surface along 100 points along that spiral.

I've included images below to help demonstrate what's needed. Any pointers will be greatly appreciated.

 

Thanks!

Iwan

Labels (4)
6 REPLIES 6
Message 2 of 7
kandennti
in reply to: ivr22

Hi @ivr22 .

 

It looked like fun, so I gave it a try.

# Fusion360API Python script
import adsk.core, adsk.fusion, traceback

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

        # select body
        msg :str = 'Select Body'
        selFiltter :str = 'Bodies'
        sel :adsk.core.Selection = selectEnt(msg ,selFiltter)
        if not sel: return
        body :adsk.fusion.BRepBody = sel.entity

        # select guide curve
        msg = 'Select Guide Curve (SketchCurves)'
        selFiltter = 'SketchCurves'
        sel :adsk.core.Selection = selectEnt(msg ,selFiltter)
        if not sel: return
        crv :adsk.fusion.SketchCurve = sel.entity

        # create Cross Section Surfaces
        createCrossSections(body, crv, 100)

        # finish
        ui.messageBox('Done')

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

def createCrossSections(
    body :adsk.fusion.BRepBody,
    sktCrv :adsk.fusion.SketchCurve,
    count :int) -> list:

    # -- support function --
    def getParams(
        crv :adsk.core.Curve3D) -> list:

        # get Evaluator
        eva :adsk.core.CurveEvaluator3D = crv.evaluator

        # get start end point
        _, startPnt, endPnt = eva.getEndPoints()
        
        # get start/end parameter
        _, sPrm = eva.getParameterAtPoint(startPnt)
        _, ePrm = eva.getParameterAtPoint(endPnt)

        # get length
        _, length = eva.getLengthAtParameter(sPrm, ePrm)

        # get step
        step = length / (count + 1)

        # get parameter
        prms = []
        for idx in range(1,count+1):
            _, prm = eva.getParameterAtLength(sPrm, step * idx)
            prms.append(prm)

        return prms


    def getPlanes(
        crv :adsk.core.Curve3D,
        parameters :list) -> list:

        # get Evaluator
        eva :adsk.core.CurveEvaluator3D = crv.evaluator

        # get tangent
        _, tangents = eva.getTangents(parameters)
        tans = [t for t in tangents]

        # point3d
        _, points = eva.getPointsAtParameters(parameters)
        pnts = [p for p in points]

        # plane
        Plane = adsk.core.Plane
        return  [Plane.create(p, v) for p, v in zip(pnts, tans)]


    def initCrossSections(
        body :adsk.fusion.BRepBody,
        planes :list) -> list:

        tmpMgr :adsk.fusion.TemporaryBRepManager = adsk.fusion.TemporaryBRepManager.get()

        surfs = []
        for pln in planes:
            wire = tmpMgr.planeIntersection(body, pln)
            if not wire:
                continue

            surf = tmpMgr.createFaceFromPlanarWires([wire])
            if not surf:
                continue

            surfs.append(surf)

        return surfs


    def addSurfs(
        comp :adsk.fusion.Component,
        surfs :list) -> list:

        bodies = comp.bRepBodies
        des :adsk.fusion.Design = comp.parentDesign

        breps =[]
        if des.designType == adsk.fusion.DesignTypes.DirectDesignType:
            breps = [bodies.add(surf) for surf in surfs]
        else:
            baseFeatures = comp.features.baseFeatures
            baseFeature = baseFeatures.add()
            baseFeature.startEdit()

            for surf in surfs:
                try:
                    breps.append(bodies.add(surf, baseFeature))
                except:
                    pass

            baseFeature.finishEdit()

        return breps

    # ----

    # Curve
    crv = sktCrv.worldGeometry

    # Params
    prms = getParams(crv)

    # Planes
    plns = getPlanes(crv, prms)

    # CrossSections
    surfs = initCrossSections(body, plns)

    # add surfaces
    comp = sktCrv.parentSketch.parentComponent
    breps = addSurfs(comp, surfs)

    return breps


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

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

1.png

However, I don't think you can get the same results with anything other than the root component.
Also, if you have a cut that has multiple cross sections, you will have multiple surfaces.

Message 3 of 7
ivr22
in reply to: kandennti

That's amazing. Thank you so much.

 

To characterise the slices, I'm looking to export them to Python or Matlab to either get the edge of the slices as splines or surfaces. I can then filter to the surface of interest (of the multiple cuts) characterise them. Any idea on how to do this?



I'm also sometimes getting this error message when trying to run the code. Any idea of why this error would appear?

ivr22_0-1619952044629.png

 

Thank you so much. This is extremely helpful for my research.

Message 4 of 7
kandennti
in reply to: ivr22

I'm sorry, but I don't understand English at all, so I didn't understand your question about the filter.

 

 

As for the part where the error is occurring, that part uses the method here.

https://help.autodesk.com/view/fusion360/ENU/?guid=GUID-18D6210D-FF0A-4CA8-8244-CFDC30213A4D 

In the documentation, it says something like this.
"Each wire must be closed, they should not overlap, and they should all lie on the same plane."

 

I think the boundary to create the surface is probably overlapping, but I can't find the correct cause without trying with actual data.

Message 5 of 7
ivr22
in reply to: kandennti

Thank you. Can we replace the createFacefromPlanarWires with the create plane along edge function (https://help.autodesk.com/view/fusion360/ENU/?guid=SLD-CONSTRUCT-PLANE-ALONG-PATH) or is that not included in the API?

 

Also my question about faces was about exporting the faces you made as splines (or something similar) for further analysis in Python or Matlab. Do you know if that's possible?

 

Thanks!

Message 6 of 7
kandennti
in reply to: ivr22

@ivr22 .

 

It is possible to create a "plane along path". However, you will need to modify it drastically.

I've never used Matlab before, is it possible to import Iges/Step files?

Message 7 of 7
kandennti
in reply to: kandennti

@ivr22 .

 

Fixed.

# Fusion360API Python script
import adsk.core, adsk.fusion, traceback

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

        # Parametric mode only
        des :adsk.fusion.Design = app.activeProduct
        if des.designType != adsk.fusion.DesignTypes.ParametricDesignType:
            ui.messageBox('Parametric mode only')
            return

        # select body
        msg :str = 'Select Body'
        selFiltter :str = 'Bodies'
        sel :adsk.core.Selection = selectEnt(msg ,selFiltter)
        if not sel: return
        body :adsk.fusion.BRepBody = sel.entity

        # select guide curve
        msg = 'Select Guide Curve (SketchCurves)'
        selFiltter = 'SketchCurves'
        sel :adsk.core.Selection = selectEnt(msg ,selFiltter)
        if not sel: return
        crv :adsk.fusion.SketchCurve = sel.entity

        # create Cross Section Surfaces
        createCrossSections(body, crv, 100)

        # finish
        ui.messageBox('Done')

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


def createCrossSections(
    body :adsk.fusion.BRepBody,
    sktCrv :adsk.fusion.SketchCurve,
    count :int) -> list:

    # -- support function --
    def getRatios(
        count :int) -> list:

        step = 1 / count
        ratios = [v * step for v in range(count)]
        ratios.append(1)

        return ratios


    def getPlanes(
        sktCrv :adsk.fusion.SketchCurve ,
        ratios :list) -> list:

        comp :adsk.fusion.Component = sktCrv.parentSketch.parentComponent
        conPlanes :adsk.fusion.ConstructionPlanes = comp.constructionPlanes
        plnIpt :adsk.fusion.ConstructionPlaneInput = conPlanes.createInput()

        valIpt :adsk.core.ValueInput
        plns = []
        for ratio in ratios:
            valIpt = adsk.core.ValueInput.createByReal(ratio)
            plnIpt.setByDistanceOnPath(sktCrv, valIpt)
            plns.append(conPlanes.add(plnIpt))
            adsk.doEvents()

        return plns


    def initSketch(
        plane :adsk.fusion.ConstructionPlane) -> adsk.fusion.Sketch:

        skts :adsk.fusion.Sketches = plane.component.sketches
        return skts.add(plane)


    def initCrossSections(
        body :adsk.fusion.BRepBody,
        planes :list):

        skts = []
        for plane in planes:
            skt :adsk.fusion.Sketch = initSketch(plane)
            skt.projectCutEdges(body)
            if skt.profiles.count > 0:
                skts.append(skt)
            else:
                skt.deleteMe()

            adsk.doEvents()

        return skts


    def initSurfs(
        skts :list) -> list:

        comp :adsk.fusion.Component = skts[0].parentComponent
        PatchFeats :adsk.fusion.PatchFeatures = comp.features.patchFeatures
        NEWBODY = adsk.fusion.FeatureOperations.NewBodyFeatureOperation

        surfs = []
        for skt in skts:
            if skt.profiles.count < 1:
                continue

            for pro in skt.profiles:
                PatchIpt :adsk.fusion.PatchFeatureInput = PatchFeats.createInput(pro, NEWBODY)
                PatchFeat :adsk.fusion.PatchFeature = PatchFeats.add(PatchIpt)

                surfs.extend([f for f in PatchFeat.faces])

            adsk.doEvents()

        return surfs

    # ----

    # ratio
    ratios = getRatios(count)

    # Planes
    plns = getPlanes(sktCrv, ratios)

    # CrossSections
    skts = initCrossSections(body, plns)
    if len(skts) < 1:
        return []

    # add surfaces
    surfs = initSurfs(skts)

    return surfs


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

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

 

・It works only in parametric mode, because it cannot create the correct plane in direct mode.

・Processing is very slow compared to the first one.

 

Nothing has been done about exporting.

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk DevCon in Munich May 28-29th


Autodesk Design & Make Report