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: 

Using Traverse sample script, do not get all bodies....

10 REPLIES 10
SOLVED
Reply
Message 1 of 11
Anonymous
998 Views, 10 Replies

Using Traverse sample script, do not get all bodies....

This time, it does work without any error, BUT, I am unable to get all bodies from the occurences.
I test the sample script, it does work well, but instead of a string, I want all bodies in a ObjectCollection, to Copy and Paste them to a new component. It "almost" work, but I am missing a number of bodies from the first couple of Assemblies in my model (come from a Step file from another CAD software). It does work on a simpler model.

I know i don't need the currentLevel, which is only used to indent the string in the sample, i'll remove it later, but I don't think it has anything to do with the difficulty I am having.

I'll attach the F3D file, and copy my code below. Thanks for your help,

Bernard.


 

import adsk.core, adsk.fusion, traceback

# Create a collection to store our bodies 
sourceBodies = adsk.core.ObjectCollection.create()

def traverse(occurences, currentLevel):
    # recursive method to get all bodies from components and sub-components
    for i in range(0, occurences.count):
        occ = occurences.item(i)       
        for bod in occ.bRepBodies:
            sourceBodies.add(bod) 

        if occ.childOccurrences:
            traverse(occ.childOccurrences, currentLevel + 1)
    
def run(context):
    ui = None
    try:
        app = adsk.core.Application.get()
        ui  = app.userInterface
        

        # 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 
        traverse(occs, 1)

        # create the new component , adding "for STL Export" to the name       
        newComp = occs.addNewComponent(adsk.core.Matrix3D.create())                
        newComp.component.name = rootComp.name + " for STL Export"
        adsk.doEvents() 
        # copy paste ALL bodies to the new component
        newComp.component.features.copyPasteBodies.add(sourceBodies)

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

 

10 REPLIES 10
Message 2 of 11
Anonymous
in reply to: Anonymous

Well, I found a solution. Kinda ugly, and which need an explanation from people at Autodesk (or it is a bug?)
Anyway, here it is: with the code as pasted in my previous post, I was getting only 217 bodies in my new component, and I knew I was missing a few. So I went back to the recursive traversal sample script, and just added what I need for bodies, with a counter. I found 313 bodies in the model, checked the collection count was correct, and I knew I had 313 bodies in that collection. Yet, no matter what, I had only 217 bodies in the component.

So, finally, I decided to copyPaste bodies ONE AT A TIME.

        index = 0
        for oneBody in sourceBodies:
            index += 1
            newComp.component.features.copyPasteBodies.add(oneBody)
            adsk.doEvents() 

        ui.messageBox('I pasted ' + str(index) + ' bodies in my new component.' )

It's pretty ugly and much slower than adding the whole collection at once, but at last it works, and I get all my 313 bodies in my new component.

Am I doing something wrong, or is there some kind of memory limitation, or is this some strange bug?

Thanks for your help

Message 3 of 11
kandennti
in reply to: Anonymous

Hi @Anonymous .

 

I fixed it like this.
import adsk.core, adsk.fusion, traceback


lst = [] #body list
STEP = 2 #copyPasteBodies 1 step count

def traverse(occurences, currentLevel):
    # recursive method to get all bodies from components and sub-components
    for i in range(0, occurences.count):
        occ = occurences.item(i)       
        for bod in occ.bRepBodies:
            # sourceBodies.add(bod)
            lst.append(bod)

        if occ.childOccurrences:
            traverse(occ.childOccurrences, currentLevel + 1)
    
def run(context):
    ui = None
    try:
        app = adsk.core.Application.get()
        ui  = app.userInterface
        

        # 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 
        traverse(occs, 1)

        # create the new component , adding "for STL Export" to the name       
        newComp = occs.addNewComponent(adsk.core.Matrix3D.create())                
        newComp.component.name = rootComp.name + " for STL Export"

        num = len(lst) // STEP
        if len(lst) % STEP != 0:
            num += 1

        cpyBodies = newComp.component.features.copyPasteBodies
        sourceBodies = adsk.core.ObjectCollection.create()
        for i in range(num):
            sourceBodies.clear()
            for bod in lst[i * STEP: (i + 1) * STEP]:
                sourceBodies.add(bod)
            cpyBodies.add(sourceBodies)
            adsk.doEvents()

        msg = '-- Body Count (step{})--\nBefor{}\nAfter{}'.format(
            STEP, len(lst), newComp.component.bRepBodies.count)
        ui.messageBox(msg)
    except:
        if ui:
            ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
Modifying "STEP" allows you to adjust the number of objects to be put in the ObjectCollection.
 
It is not realistic to try everything, so I modified some "STEP" and tried them.
1.png
Anything other than STEP = 1 did not give the correct result, and in other cases it was not consistent.
I think it wasn't a memory limit, but ...
 
Some bodies seemed to overlap and I was a little worried.
 
Message 4 of 11
Anonymous
in reply to: kandennti

Thank you. I will look at this closely. I am a bit surprised, as it was looking like the problem was in adding the whole collection at once to the component, rather than adding to the collection.

Message 5 of 11
BrianEkins
in reply to: Anonymous

Curiosity got the best of me and I had to look at this one.  At first glance, it looks like it might be a bug in the API that not all of the bodies aren't being copied.  I didn't spend enough time to see if there's anything unusual about the bodies not being copied.  But even if there is something different about them I don't see why it would prevent copying them.

Below is some code that takes a different approach and it's successful with this model.

import adsk.core, adsk.fusion, traceback


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

        if occ.childOccurrences:
            traverse(occ.childOccurrences, bodies)
    return bodies


def run(context):
    ui = None
    try:
        app = adsk.core.Application.get()
        ui  = app.userInterface
        
        # 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 
        bodies = []
        bodies = traverse(occs, bodies)

        # create the new component , adding "for STL Export" to the name       
        newOcc = occs.addNewComponent(adsk.core.Matrix3D.create())                
        newOcc.component.name = rootComp.name + " for STL Export"

        # copy paste ALL bodies to the new component
        baseFeature = newOcc.component.features.baseFeatures.add()
        baseFeature.startEdit()

        tempBRep = adsk.fusion.TemporaryBRepManager.get()

        ui.messageBox('Num bodies: ' + str(bodies.count))
        for body in bodies:
            transBody = tempBRep.copy(body)
            newOcc.component.bRepBodies.add(transBody, baseFeature)

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

 

---------------------------------------------------------------
Brian Ekins
Inventor and Fusion 360 API Expert
Website/Blog: https://EkinsSolutions.com
Message 6 of 11
Anonymous
in reply to: BrianEkins

Thank you Brian! I'll spend some time with this, have to learn about using baseFeatures. Did not even know/think I could use this here.

If baseFeatures is used, do I still need to check about designTypes?

Anyway, than you very much.

Message 7 of 11
MichaelT_123
in reply to: Anonymous

Hi Mr.BernardACK8A,

 

Please find attached the BOM in Excel format which might help you (by using a cross reference) trace the issue.

One side word if I may. The significant project as the one you presented would certainly be managed better/easier in long term if bodies were properly named and also components described.

Regarding the code you might consider using allOccurrences instead traversing the design (in essence flattening it)

 

Regards

MichaelT

 

MichaelT
Message 8 of 11
MichaelT_123
in reply to: MichaelT_123

PS. System problem with attachment... will try tomorrow

 

Hi Mr.BernardACK8A, 

 

Please find attached the BOM in Excel format which might help you (by using a cross reference) trace the issue.

One side word if I may. The significant project as the one you presented would certainly be managed better/easier in long term if bodies were properly named and also components described.

Regarding the code you might consider using allOccurrences instead traversing the design (in essence flattening it)

 

Regards

MichaelT

 

 

MichaelT
Message 9 of 11
Anonymous
in reply to: MichaelT_123


@MichaelT_123 wrote:

Hi Mr.BernardACK8A,

 

Please find attached the BOM in Excel format which might help you (by using a cross reference) trace the issue.

One side word if I may. The significant project as the one you presented would certainly be managed better/easier in long term if bodies were properly named and also components described.

Regarding the code you might consider using allOccurrences instead traversing the design (in essence flattening it)

 

Regards

MichaelT

 


I totally agree with you it would be far better to name everything, but this is  for a very special kind of use where it does not really matter much.

Message 10 of 11
MichaelT_123
in reply to: Anonymous

Hi Mr.BernardACK8A,

 

... could not fulfil my promise of days before. Hopefully today everything will go smoothly.

Please find the Excel file attached which was fed on the test file you presented (after a slight rectification of it).

Although as you have mentioned your original problem is gone, the file and its associates might give you some fresh ideas in your subsequent F360 endeavours.

 

FourAxis.png

 

Regards

MichaelT

 

PS.

Most hyperlinks in the file will not work. Only those highlighted hopefully will.

FourAxis one requires for viewing red/cyan glasses (size 63 MB).

MichaelT
Message 11 of 11
Anonymous
in reply to: BrianEkins


@BrianEkins wrote:

Curiosity got the best of me and I had to look at this one.  At first glance, it looks like it might be a bug in the API that not all of the bodies aren't being copied.  I didn't spend enough time to see if there's anything unusual about the bodies not being copied. 

 

 


Hi Brian, I tested your solution, which is more elegant and noticeably faster, but (there is always a "but"... ) would there be a way to keep the bodies name? It looks like base feature get rid of them. I added a line in "traverse" to have them

def traverse(occurences):
    # recursive method to get all bodies from components and sub-components
    for occ in occurences:           
        bodies = occ.bRepBodies          
        for bod in bodies:
            bod.name = occ.name
            sourceBodies.add(bod) 
            adsk.doEvents()  

        if occ.childOccurrences:
            traverse(occ.childOccurrences)


but using your method, when the bodies are copied to the base feature, they get renamed. Maybe I am not doing this properly, but it would be very useful to be able to keep the body's parent name.

Thanks for your help,
and best regards,

Bernard

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