API Combine Cut a Collection of Bodies from another Collection of Bodies ?

API Combine Cut a Collection of Bodies from another Collection of Bodies ?

info83PHN
Advocate Advocate
1,954 Views
12 Replies
Message 1 of 13

API Combine Cut a Collection of Bodies from another Collection of Bodies ?

info83PHN
Advocate
Advocate

Is this possible ?

Wanting to Cut every body from Component 'B' from every Body in Component 'A'

If I iterate thru the 2 components, and create an ObjectCollection of Bodies, and an ObjectCollection of Tools, can I combine Cut the Tools from the Bodies ( and keep the tools) ?

I have adapted this code to iterate thru the components, but not sure how to add the bodies to the 2 ObjectCollections, or if this will even work at all.
If not, any alternate suggestions ?

 

This code fails at the 'Combine cut input' line with a long error that I can't understand

 

import adsk.core, adsk.fusion, traceback


def traverseBODY(occurrences, Ubodies):
    # recursive method to get all bodies from components and sub-components
    for occ in occurrences:
        for bod in occ.bRepBodies:
            Ubodies.append(bod) 
        if occ.childOccurrences:
            traverseBODY(occ.childOccurrences, Ubodies)
    return Ubodies

def traverseTOOL(occurrences, Utools):
    # recursive method to get all bodies from components and sub-components
    for occ in occurrences:
        for bod in occ.bRepBodies:
            Utools.append(bod) 
        if occ.childOccurrences:
            traverseTOOL(occ.childOccurrences, Utools)
    return Utools


def run(context):
    ui = None
    try:
        app = adsk.core.Application.get()
        ui  = app.userInterface
        product = app.activeProduct
        design = adsk.fusion.Design.cast(product)
        rootComp = design.rootComponent
        features = rootComp.features
    
# Get active design
        product = app.activeProduct
        design = adsk.fusion.Design.cast(product)
        if not design:
            ui.messageBox('It is not supported in current workspace, please change to MODEL workspace and try again.')
            return

# History must be captured for this to work
        if design.designType == adsk.fusion.DesignTypes.DirectDesignType:
            design.designType = adsk.fusion.DesignTypes.ParametricDesignType
 
# Get root component in this design
        rootComp = design.rootComponent
              
# Get all Components below root       
        occs = rootComp.occurrences

# add all bodies from all components in the collection 
        Ubodies = []
        Utools = []

# loop thru each root component
        for UrootComp in occs:
            if UrootComp.name == "ComponentB":
                Utools = traverseTOOL(occs, Utools)
            else:
                Ubodies = traverseBODY(occs, Ubodies)

# Combine Cut
        CombineCutInput = rootComp.features.combineFeatures.createInput(Ubodies, Utools)
        CombineCutFeats = features.combineFeatures
        CombineCutInput = CombineCutFeats.createInput(Ubodies, Utools)
        CombineCutInput.operation = adsk.fusion.FeatureOperations.CutFeatureOperation
        CombineCutInput.isKeepToolBodies = True
        CombineCutFeats.add(CombineCutInput)

        ui.messageBox('Operation Completed')

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

 

0 Likes
Accepted solutions (1)
1,955 Views
12 Replies
Replies (12)
Message 2 of 13

tykapl.breuil
Advocate
Advocate

The cut combine feature only accepts one body as the target body, moreover, the tool bodies need to be in an object collection rather than an array.

See the syntax for combineFeatures.createInput : https://help.autodesk.com/view/fusion360/ENU/?guid=GUID-d5196ad2-ff7b-4a45-873c-d9251cb0f0c5

 

0 Likes
Message 3 of 13

info83PHN
Advocate
Advocate

OK. So I sound create a combined Collection of the Tool bodies, and then loop thru the Bodies one at a time, and execute a Combine Cut on each body, using the tools Collection as the Tool ?

 

I am now trying this method but getting stuck with creating the Tools Collection. I am ( I think ) specifying which Component to get the tool Bodies from, but if is returning the total Count of the 5 bodies that are NOT in the Hardware Component, instead of the 19 bodies that ARE in the Hardware component ( and its' sub-components ).

 

Attached pic of the browser structure

 

import adsk.core, adsk.fusion, traceback

def traverseTOOLS(rootComp, occurrences, Utools, uToolCount):
    # recursive method to get all bodies from components and sub-components
    for occ in occurrences:
        for bod in occ.bRepBodies:
            Utools.add(bod) 
            uToolCount+=1
        if occ.childOccurrences:
            traverseTOOLS(rootComp,occ.childOccurrences, Utools,uToolCount)
    return Utools,uToolCount


def run(context):
    ui = None
    try:
        app = adsk.core.Application.get()
        ui  = app.userInterface
        product = app.activeProduct
        design = adsk.fusion.Design.cast(product)
        rootComp = design.rootComponent
        features = rootComp.features
    
# Get active design
        product = app.activeProduct
        design = adsk.fusion.Design.cast(product)
        if not design:
            ui.messageBox('It is not supported in current workspace, please change to MODEL workspace and try again.')
            return
# History must be captured for this to work
        if design.designType == adsk.fusion.DesignTypes.DirectDesignType:
            design.designType = adsk.fusion.DesignTypes.ParametricDesignType
# Get root component in this design
        rootComp = design.rootComponent
# Get all Components below root       
        occs = rootComp.occurrences

# add all bodies from the Hardware component in to the Utools collection 
        Utools = adsk.core.ObjectCollection.create()
# loop thru each root component
        uToolCount = 0
        for UrootComp in occs:
            if UrootComp.name[:8] == "Hardware":
                Utools,uToolCount = traverseTOOLS(UrootComp, occs, Utools, uToolCount)

        ui.messageBox(str(uToolCount) + '\n\nOperation Completed')

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

 

0 Likes
Message 4 of 13

info83PHN
Advocate
Advocate

now getting more confused. I added a messageBox to the function, and that is listing every body, both in the components and in the Hardware component, and the count still returns as '5'

 

def traverseTOOLS(ui, rootComp, occurrences, Utools, uToolCount):
    # recursive method to get all bodies from components and sub-components
    for occ in occurrences:
        for bod in occ.bRepBodies:
            Utools.add(bod) 
            uToolCount+=1
            ui.messageBox(bod.name)
        if occ.childOccurrences:
            traverseTOOLS(ui, rootComp,occ.childOccurrences, Utools,uToolCount)
    return Utools,uToolCount

 

0 Likes
Message 5 of 13

tykapl.breuil
Advocate
Advocate

Would it be possible for you to give me the f3d file so I can test it ?

0 Likes
Message 6 of 13

info83PHN
Advocate
Advocate

f3d zip file attached

0 Likes
Message 7 of 13

tykapl.breuil
Advocate
Advocate

There was a problem in the recursion, if you switch uToolCount to a global variable you get the 10 bodies you want to see (at least in the file you gave me).

Maybe the problem was the combine call as it doesn't work if the target body and the tool bodies do not intersect, a try/except might solve that.

Message 8 of 13

info83PHN
Advocate
Advocate

Hi

Please move the timeline back 7 places, to just after the mirror. Then you will see the Hardware component. The code is supposed to add only bodies from the Hardware component to the ObjectCollection

0 Likes
Message 9 of 13

info83PHN
Advocate
Advocate

The global variable idea worked to retain the count values. Now I have updated the function to count only the solid bodies. It should report 19, but reports 25 - so it is reporting the 19 bodies in the Hardware component, and the 6 bodies in components 1 - 6. I want to add ONLY the 19 bodies from the Hardware component to the ObjectCollection

 

 

def traverseTOOLS(ui, rootComp, occurrences, Utools):
    # recursive method to get all bodies from components and sub-components
    global uToolCount
    for occ in occurrences:
        for bod in occ.bRepBodies:
            if bod.isSolid == True:
                Utools.add(bod) 
                uToolCount+=1
        if occ.childOccurrences:
            traverseTOOLS(ui, rootComp,occ.childOccurrences, Utools)
    return Utools

 

0 Likes
Message 10 of 13

tykapl.breuil
Advocate
Advocate

Sadly as I have an f3z file the timeline is empty.

However I think your problem is when you call traverseTools, you call it with occs which contains all occurrences. Try changing the function call to traverseTOOLS(ui, URootComp, URootComp.childOccurences, Utools)

As a matter of fact, I don't think the component variable has any use in the traverseTOOLS function, you could change it to traverseTOOLS(ui, occs, Utools)

0 Likes
Message 11 of 13

info83PHN
Advocate
Advocate

if you import the f3z file complete, then it loads 3 files. The timeline is in the 'TOP' file

0 Likes
Message 12 of 13

tykapl.breuil
Advocate
Advocate
Accepted solution

Hey so I changed the code around a bit because I realized that we also have to get the bodies directly under the component and tried it with the file you gave me (I did find the timeline !) and it seems to work :

import adsk.core, adsk.fusion, traceback

def traverseComponent(occ, objColl):
    # recursive method to get all bodies from components and sub-components
    for bod in occ.bRepBodies:
        if bod.isSolid == True:
            objColl.add(bod)
    occurrences = occ.childOccurrences
    for occ in occurrences:
        traverseComponent(occ, objColl)


def run(context):
    ui = None
    try:
        app = adsk.core.Application.get()
        ui  = app.userInterface
        product = app.activeProduct
        design = adsk.fusion.Design.cast(product)
        rootComp = design.rootComponent
        features = rootComp.features
    
# Get active design
        product = app.activeProduct
        design = adsk.fusion.Design.cast(product)
        if not design:
            ui.messageBox('It is not supported in current workspace, please change to MODEL workspace and try again.')
            return
# History must be captured for this to work
        if design.designType == adsk.fusion.DesignTypes.DirectDesignType:
            design.designType = adsk.fusion.DesignTypes.ParametricDesignType
# Get root component in this design
        rootComp = design.rootComponent
# Get all Components below root       
        occs = rootComp.occurrences

# add all bodies from the Hardware component in to the Utools collection 
        Utools = adsk.core.ObjectCollection.create()
        Ubodies = adsk.core.ObjectCollection.create()
# loop thru each root component
        for UrootComp in occs:
            if UrootComp.name[:8] == "Hardware":
                traverseComponent(UrootComp, Utools)
            else:
                traverseComponent(UrootComp, Ubodies)

        ui.messageBox(str(Utools.count) + '\n\nOperation Completed')
        ui.messageBox(str(Ubodies.count) + '\n\nOperation Completed')

        CombineCutFeats = features.combineFeatures
        for body in Ubodies:
            try:
                CombineCutInput = CombineCutFeats.createInput(body, Utools)
                CombineCutInput.operation = adsk.fusion.FeatureOperations.CutFeatureOperation
                CombineCutInput.isKeepToolBodies = True
                CombineCutFeats.add(CombineCutInput)
            except:
                pass

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

info83PHN
Advocate
Advocate

Paul Breuil !!  You NAILED IT !! Thank You. If I could find you, I would send you some beer or coffee !

Thank You so much for solving this.