Copy a Body x times & join them all together

Copy a Body x times & join them all together

dbunch211
Contributor Contributor
1,613 Views
10 Replies
Message 1 of 11

Copy a Body x times & join them all together

dbunch211
Contributor
Contributor

I use a cylinder here as an example, but here is a little background of my goal.  I want to copy one revolution of a screw thread that is created in an add-in I am writing to have customized screw threads. Here is a link to the add-in. https://github.com/geodave810/ThreadTune . In OpenSCAD, I was used to being able to modify the diameter, pitch and angle of the threads and decided to see if I could do the same in fusion using the python API & the python code does work. I draw the thread using a thread profile generated from the user input variables along an approximate helix drawn with spiral points. The more spline points I give it, the more accurate it gets. The accuracy is plenty accurate in 3D printing & probably other use cases. The caveat is the more revolutions of the helix the more likely the program will give an error or bog down. I give an option to use either a Center line or an outside helix for the guide rail.  I don't think the Center line is accurate enough & will sometimes crash with only 90 total spline points.  The more accurate spline using a helix spline for the path on the inside thread & another helix spline along the outside thread as guide rail.  My solution is to just draw one revolution of the helix, copy & join all those bodies. My problem is getting it to work. I am new to coding in this API & after a lot of trial & error & searching for examples of this, I decided to see if someone here could help me. Some of this code is generated by Copilot in Bing.


I get this error when running the code in a new design.
Error: Traceback (most recent call last):
File "C:/Users/DDB/AppData/Roaming/Autodesk/Autodesk Fusion 360/API/Scripts/AP_CopyMove/AP_CopyMove.py", line 47, in run
rootComp.features.moveFeatures.add(rootComp.bRepBodies.item(0), move_vector)
TypeError: MoveFeatures.add() takes 2 positional arguments but 3 were given

 

 

import adsk.core
import adsk.fusion
import traceback

app = adsk.core.Application.get()
ui = app.userInterface

product = app.activeProduct
design = adsk.fusion.Design.cast(product)
rootComp = design.rootComponent
features = rootComp.features

def run(context):
    try:
        z_offset = 1.5  # Distance between cylinders in Z direction
        num_cylinders = 3
        diameter = 5.0
        height = 1.0
# Create a cylinder
        sketches = rootComp.sketches
        xy_plane = rootComp.xYConstructionPlane
        sketch = sketches.add(xy_plane)
        center_point = adsk.core.Point3D.create(0, 0, 0)
        Rad = (diameter / 2.0)
        circle = sketch.sketchCurves.sketchCircles.addByCenterRadius(center_point, Rad)
        cirProf = sketch.profiles.item(0)

        Ht2 = adsk.core.ValueInput.createByReal(height)
        extrudes = rootComp.features.extrudeFeatures
        extrudeFeature = extrudes.addSimple(cirProf, Ht2, adsk.fusion.FeatureOperations.NewBodyFeatureOperation)
 
 # Create a collection of entities for move
        bodies = adsk.core.ObjectCollection.create()
        bodies.add(extrudeFeature.bodies.item(0))

        vector = adsk.core.Vector3D.create(0, 0, 1.0)
        transform = adsk.core.Matrix3D.create()
        transform.translation = vector
        moveFeats = rootComp.features.moveFeatures
        moveFeatureInput = moveFeats.createInput(bodies, transform)
        moveFeats.add(moveFeatureInput)

# Copy the cylinder in Z direction
        z_offset = 1.5
        for i in range(1, num_cylinders):
            move_vector = adsk.core.Vector3D.create(0, 0, i * z_offset)
            rootComp.features.moveFeatures.add(rootComp.bRepBodies.item(0), move_vector)
# Join all cylinders
        bodies = adsk.core.ObjectCollection.create()
        for i in range(3):
            bodies.add(rootComp.bRepBodies.item(i))
        join_input = extrudes.createInput(bodies, adsk.fusion.FeatureOperations.JoinFeatureOperation)
        extrudes.addSimple(join_input)

    except Exception as e:
        ui.messageBox("Error: {}".format(traceback.format_exc()))

run(None)

 

0 Likes
Accepted solutions (1)
1,614 Views
10 Replies
Replies (10)
Message 2 of 11

dbunch211
Contributor
Contributor

A little update to my original post. I had found this forum message before asking this question and was able to get it to work with components, but not bodies.  I probably just need to study this problem a little more.
https://forums.autodesk.com/t5/fusion-api-and-scripts/copy-body-and-move-by-code/td-p/10554409

I found these resources this morning & with one or more of these, I should be able to figure out what I need.
https://adndevblog.typepad.com/manufacturing/2017/08/fusion-360-api-transform-component-.html

https://help.autodesk.com/view/fusion360/ENU/?guid=GUID-153E540B-6246-460C-8B6A-4C58165CEBAA

https://forums.autodesk.com/t5/fusion-api-and-scripts/copy-and-move-feature-in-loop/td-p/10605881

https://www.instructables.com/Parametric-Modeling-With-Fusion-360-API/

I have this add-in working better than I thought it would & other than this helix sweep problem there is only one thing left for me to add before releasing the next version. Maybe I should add a separate forum topic for this add-in in case there is more interest in this?

Here is what the dialog input now looks like.  The pulldown menu at the top does not work yet, but that will be used to initially fill the diameter & pitch with standard metric sizes from M3 - M30.

ThreadTune_Tab1.JPGThreadTune_Tab2.JPG

0 Likes
Message 3 of 11

BrianEkins
Mentor
Mentor

I don't think you'll be able to use the move feature. I see where it doesn't support the ability to copy. It does in the UI, but not the API. That needs to be fixed.

 

An alternative, and probably the best in your case, is to create a rectangular pattern. Below is a modified version of your code where it creates a small cylinder to act as the shaft, then a larger cylinder that is the "thread" and then it patterns the thread body to create multiple threads, and finally combines them all into a single body by using the Combine feature.

        z_offset = 1.5  # Distance between cylinders in Z direction
        num_cylinders = 3
        diameter = 5.0
        height = 1.0

        # Create a base cylinder
        sketches = rootComp.sketches
        sketch = sketches.add(rootComp.xYConstructionPlane)
        center_point = adsk.core.Point3D.create(0, 0, 0)
        Rad = (diameter / 6)
        circle = sketch.sketchCurves.sketchCircles.addByCenterRadius(center_point, Rad)
        cirProf = sketch.profiles.item(0)

        totalHeight = 5
        Ht2 = adsk.core.ValueInput.createByReal(totalHeight)
        extrudes = rootComp.features.extrudeFeatures
        baseCylExtrude = extrudes.addSimple(cirProf, Ht2, adsk.fusion.FeatureOperations.NewBodyFeatureOperation)
        baseCylBody = baseCylExtrude.bodies[0]
 
        # Create the "thread" cylinder
        sketches = rootComp.sketches
        sketch = sketches.add(rootComp.xYConstructionPlane)
        center_point = adsk.core.Point3D.create(0, 0, 0)
        Rad = (diameter / 2.0)
        circle = sketch.sketchCurves.sketchCircles.addByCenterRadius(center_point, Rad)
        cirProf = sketch.profiles.item(0)

        Ht2 = adsk.core.ValueInput.createByReal(height)
        extrudeFeature = extrudes.addSimple(cirProf, Ht2, adsk.fusion.FeatureOperations.NewBodyFeatureOperation)

        # Create a collection of entities for move
        bodies = adsk.core.ObjectCollection.create()
        bodies.add(extrudeFeature.bodies.item(0))

        # Copy the cylinder in Z direction
        z_offset = 1.5

        patternInput = features.rectangularPatternFeatures.createInput(bodies,
                                        rootComp.zConstructionAxis,
                                        adsk.core.ValueInput.createByReal(num_cylinders),
                                        adsk.core.ValueInput.createByReal(z_offset),
                                        adsk.fusion.PatternDistanceType.SpacingPatternDistanceType)
        
        pattern = features.rectangularPatternFeatures.add(patternInput)
        threadBodies = adsk.core.ObjectCollection.create()
        for body in pattern.bodies:
            threadBodies.add(body)

        # Get the bodies resulting from the pattern.
        combineInput = features.combineFeatures.createInput(baseCylBody, threadBodies)
        combineInput.isKeepToolBodies = False
        combineInput.operation = adsk.fusion.FeatureOperations.JoinFeatureOperation

        combine = features.combineFeatures.add(combineInput)
---------------------------------------------------------------
Brian Ekins
Inventor and Fusion 360 API Expert
Website/Blog: https://EkinsSolutions.com
Message 4 of 11

dbunch211
Contributor
Contributor

Thanks for the work around.  I will take a closer look at it tomorrow.  Maybe I should just consider making this a component rather than body.

0 Likes
Message 5 of 11

dbunch211
Contributor
Contributor

After some further thought on this, think I have a simpler solution.  I could draw a thread profile for each pitch distance and do the same thing for the helix, then create a separate sweep for each revolution joining each of them together for each sweep.  It does not seem like it would change my current code too much either.  I have made a lot of changes the last couple of days, so I released a new version of this today. https://github.com/geodave810/ThreadTune/releases/tag/V1.1.0

0 Likes
Message 6 of 11

kandennti
Mentor
Mentor

Hi @dbunch211 -San.

 

This is not directly related to the content, but I noticed it and wanted to share it with you.

 

You are probably using a .gitignore file, which is created in python on github, and the manifest file is not uploaded as is. If others download the file, they will not be able to run it.

 

I would suggest deleting it or making it a comment.

kandennti_0-1714657644588.png

 

0 Likes
Message 7 of 11

dbunch211
Contributor
Contributor

Where is that .manifest you are referring to?  I downloaded my latest release & searched through all those files & in the folder on my machine where the add-in lies & do not see .manifest referenced anywhere.

0 Likes
Message 8 of 11

kandennti
Mentor
Mentor

@dbunch211 -San.

 

The minimum file structure required as an add-in is,

 

  • Folder name
  • .py file with entry points
  • .manifest file

The three files must have the same name.

Looking at your add-in repository, I see that the "ThreadTune.manifest" file is missing.

kandennti_0-1714661056852.png

 

0 Likes
Message 9 of 11

dbunch211
Contributor
Contributor

Thanks for finding that problem.  I deleted that somewhere along the line not knowing any better & restored it from an earlier backup & updated in the github repository & created a new release version of v.1.1.1  Let me know if that fixes the problem.

Message 10 of 11

dbunch211
Contributor
Contributor
Accepted solution

I figured out a solution that works for me.  I draw a profile for each thread section for the length of the screw & connect them all together as one profile, draw a one revolution helix for the path & guiderail & it will sweep all the threads with the single revolution helix.  I also found a couple of bugs calculating the wrong number for 

variable YB_B & YB_T.  It was giving the wrong thread angle but seems to have worked on the version I uploaded which does not make sense to me.  Here are a couple of screen captures to show my new method for sweeping the threads.  I will upload the next version when I test it a little more.
ThreadTune_SingleHelixSketch.jpgThreadTune_SingleHelixSolid.jpg
Message 11 of 11

dbunch211
Contributor
Contributor

After a bit of testing, my solution using the single revolution Helix with all the threads swept all at once works as well as the Long Helix with a single thread and is considerably faster the longer the threads you have.

 

Here is an example of speed difference between Helix & LongHelix option:
using the settings M12x1.75 30mm Height 30deg top & bottom angle and 18 spline points
Helix elapsed time is 3.64 seconds on my machine with virtually no difference in accuracy
LongHelix elapsed time is 11.65 seconds on my machine.

 

Since resolving the problem that this topic was about, I am going to start a new topic as an Add-in announcement, to continue with any other problems & solutions related to this add-in.

I released v1.2.0 this morning.  https://github.com/geodave810/ThreadTune/releases/tag/V1.2.0

 

Further discussion about the program on this forum can be found here: Add-in announcement: Fine-Tune your Screw Thread Designs in Autodesk Fusion. Feedback & ideas welcom...