I am actually working on a script that detects or identifies the cylindrical portion of the bolt by traversing through the bodies i.e this task has to be performed by the script itself and creates external threading on it, but without using the recommendThreadData function, I wish to know if or not I could set the thread designation and thread class manually every time without changing the default parameters to generate a valid bolt. I am attaching the script below i am having issues when i try to run this fusion shows error and creates a bolt without thread, please suggest necessary changes that could be made in order to perform the intended task of generating bolt with variation in thread designation and thread class to be able to vary the pitch of the thread?
# Author-Autodesk Inc.
# Description-Create bolt with manual threading
import adsk.core, adsk.fusion, traceback
import math
defaultBoltName = 'Bolt'
defaultHeadDiameter = 0.75
defaultBodyDiameter = 0.5
defaultHeadHeight = 0.3125
defaultBodyLength = 1.0
defaultCutAngle = 30.0 * (math.pi / 180)
defaultChamferDistance = 0.03845
defaultFilletRadius = 0.02994
defaultThreadDesignation = 'M10x1.5' # Example of a metric designation
defaultThreadClass = '6g' # Example class for external threads
# Global set of event handlers to keep them referenced for the duration of the command
handlers = []
app = adsk.core.Application.get()
if app:
ui = app.userInterface
newComp = None
def createNewComponent():
# Get the active design.
product = app.activeProduct
design = adsk.fusion.Design.cast(product)
rootComp = design.rootComponent
allOccs = rootComp.occurrences
newOcc = allOccs.addNewComponent(adsk.core.Matrix3D.create())
return newOcc.component
class BoltCommandExecuteHandler(adsk.core.CommandEventHandler):
def __init__(self):
super().__init__()
def notify(self, args):
try:
unitsMgr = app.activeProduct.unitsManager
command = args.firingEvent.sender
inputs = command.commandInputs
bolt = Bolt()
for input in inputs:
if input.id == 'boltName':
bolt.boltName = input.value
elif input.id == 'headDiameter':
bolt.headDiameter = unitsMgr.evaluateExpression(input.expression, "cm")
elif input.id == 'bodyDiameter':
bolt.bodyDiameter = unitsMgr.evaluateExpression(input.expression, "cm")
elif input.id == 'headHeight':
bolt.headHeight = unitsMgr.evaluateExpression(input.expression, "cm")
elif input.id == 'bodyLength':
bolt.bodyLength = adsk.core.ValueInput.createByString(input.expression)
elif input.id == 'cutAngle':
bolt.cutAngle = unitsMgr.evaluateExpression(input.expression, "deg")
elif input.id == 'chamferDistance':
bolt.chamferDistance = adsk.core.ValueInput.createByString(input.expression)
elif input.id == 'filletRadius':
bolt.filletRadius = adsk.core.ValueInput.createByString(input.expression)
elif input.id == 'threadDesignation':
bolt.threadDesignation = input.value
elif input.id == 'threadClass':
bolt.threadClass = input.value
bolt.buildBolt()
args.isValidResult = True
except:
if ui:
ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
class BoltCommandDestroyHandler(adsk.core.CommandEventHandler):
def __init__(self):
super().__init__()
def notify(self, args):
try:
adsk.terminate()
except:
if ui:
ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
class BoltCommandCreatedHandler(adsk.core.CommandCreatedEventHandler):
def __init__(self):
super().__init__()
def notify(self, args):
try:
cmd = args.command
cmd.isRepeatable = False
onExecute = BoltCommandExecuteHandler()
cmd.execute.add(onExecute)
onExecutePreview = BoltCommandExecuteHandler()
cmd.executePreview.add(onExecutePreview)
onDestroy = BoltCommandDestroyHandler()
cmd.destroy.add(onDestroy)
handlers.append(onExecute)
handlers.append(onExecutePreview)
handlers.append(onDestroy)
# Define the inputs
inputs = cmd.commandInputs
inputs.addStringValueInput('boltName', 'Bolt Name', defaultBoltName)
initHeadDiameter = adsk.core.ValueInput.createByReal(defaultHeadDiameter)
inputs.addValueInput('headDiameter', 'Head Diameter','cm',initHeadDiameter)
initBodyDiameter = adsk.core.ValueInput.createByReal(defaultBodyDiameter)
inputs.addValueInput('bodyDiameter', 'Body Diameter', 'cm', initBodyDiameter)
initHeadHeight = adsk.core.ValueInput.createByReal(defaultHeadHeight)
inputs.addValueInput('headHeight', 'Head Height', 'cm', initHeadHeight)
initBodyLength = adsk.core.ValueInput.createByReal(defaultBodyLength)
inputs.addValueInput('bodyLength', 'Body Length', 'cm', initBodyLength)
initCutAngle = adsk.core.ValueInput.createByReal(defaultCutAngle)
inputs.addValueInput('cutAngle', 'Cut Angle', 'deg', initCutAngle)
initChamferDistance = adsk.core.ValueInput.createByReal(defaultChamferDistance)
inputs.addValueInput('chamferDistance', 'Chamfer Distance', 'cm', initChamferDistance)
initFilletRadius = adsk.core.ValueInput.createByReal(defaultFilletRadius)
inputs.addValueInput('filletRadius', 'Fillet Radius', 'cm', initFilletRadius)
# Thread designation and class inputs
inputs.addStringValueInput('threadDesignation', 'Thread Designation', defaultThreadDesignation)
inputs.addStringValueInput('threadClass', 'Thread Class', defaultThreadClass)
except:
if ui:
ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
class Bolt:
def __init__(self):
self._boltName = defaultBoltName
self._headDiameter = defaultHeadDiameter
self._bodyDiameter = defaultBodyDiameter
self._headHeight = defaultHeadHeight
self._bodyLength = adsk.core.ValueInput.createByReal(defaultBodyLength)
self._cutAngle = defaultCutAngle
self._chamferDistance = adsk.core.ValueInput.createByReal(defaultChamferDistance)
self._filletRadius = adsk.core.ValueInput.createByReal(defaultFilletRadius)
self._threadDesignation = defaultThreadDesignation
self._threadClass = defaultThreadClass
def buildBolt(self):
try:
global newComp
newComp = createNewComponent()
if newComp is None:
ui.messageBox('New component failed to create', 'New Component Failed')
return
# Step 1: Create a new sketch on the X-Y plane
sketches = newComp.sketches
xyPlane = newComp.xYConstructionPlane
sketch = sketches.add(xyPlane)
# Step 2: Draw a circle for the bolt body
sketchCircles = sketch.sketchCurves.sketchCircles
bodyDiameter = self._bodyDiameter
bodyCenter = adsk.core.Point3D.create(0, 0, 0)
sketchCircles.addByCenterRadius(bodyCenter, bodyDiameter / 2)
# Step 3: Extrude the circle to create the bolt body
prof = sketch.profiles.item(0)
extrudes = newComp.features.extrudeFeatures
bodyLength = self._bodyLength
extInput = extrudes.createInput(prof, adsk.fusion.FeatureOperations.NewBodyFeatureOperation)
distance = adsk.core.ValueInput.createByReal(bodyLength)
extInput.setDistanceExtent(False, distance)
extInput.isSolid = True
bodyExt = extrudes.add(extInput)
# Step 4: Verify if bodyExt has side faces, which are required for threading
if bodyExt and bodyExt.sideFaces.count > 0:
sideFace = bodyExt.sideFaces[0] # Get the first side face for threading
threads = newComp.features.threadFeatures
threadDataQuery = threads.threadDataQuery
# Set the thread info manually
threadInfo = threads.createThreadInfo(False, 'Metric', self._threadDesignation, self._threadClass)
faces = adsk.core.ObjectCollection.create()
faces.add(sideFace)
threadInput = threads.createInput(faces, threadInfo)
threadInput.isFullLength = True # Adjust this if you want a custom thread length
threads.add(threadInput)
else:
ui.messageBox('Error: The body or side faces of the extrude were not created correctly.')
except:
if ui:
ui.messageBox('Failed to compute the bolt. This is most likely because the input values define an invalid bolt.')
def run(context):
try:
product = app.activeProduct
design = adsk.fusion.Design.cast(product)
if not design:
ui.messageBox('The DESIGN workspace must be active when running this script.')
return
commandDefinitions = ui.commandDefinitions
cmdDef = commandDefinitions.itemById('Bolt')
if not cmdDef:
cmdDef = commandDefinitions.addButtonDefinition('Bolt', 'Create Bolt', 'Create a bolt.', './resources')
onCommandCreated = BoltCommandCreatedHandler()
cmdDef.commandCreated.add(onCommandCreated)
handlers.append(onCommandCreated)
inputs = adsk.core.NamedValues.create()
cmdDef.execute(inputs)
adsk.autoTerminate(False)
except:
if ui:
ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))