339 lines
14 KiB
Python
339 lines
14 KiB
Python
#Author-Autodesk Inc.
|
|
#Description-Create bolt
|
|
|
|
import adsk.core, adsk.fusion, traceback
|
|
import math
|
|
|
|
defaultBoltName = 'Bolt'
|
|
defaultHeadDiameter = 0.75
|
|
defaultBodyDiameter = 0.5
|
|
defaultHeadHeight = 0.3125
|
|
defaultBodyLength = 2.0
|
|
defaultCutAngle = 30.0 * (math.pi / 180)
|
|
defaultChamferDistance = 0.03845
|
|
defaultFilletRadius = 0.02994
|
|
|
|
# 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)
|
|
|
|
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:
|
|
# when the command is done, terminate the script
|
|
# this will release all globals which will remove all event handlers
|
|
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)
|
|
# keep the handler referenced beyond this function
|
|
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)
|
|
|
|
#to do the thread length
|
|
|
|
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)
|
|
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)
|
|
|
|
#properties
|
|
@property
|
|
def boltName(self):
|
|
return self._boltName
|
|
@boltName.setter
|
|
def boltName(self, value):
|
|
self._boltName = value
|
|
|
|
@property
|
|
def headDiameter(self):
|
|
return self._headDiameter
|
|
@headDiameter.setter
|
|
def headDiameter(self, value):
|
|
self._headDiameter = value
|
|
|
|
@property
|
|
def bodyDiameter(self):
|
|
return self._bodyDiameter
|
|
@bodyDiameter.setter
|
|
def bodyDiameter(self, value):
|
|
self._bodyDiameter = value
|
|
|
|
@property
|
|
def headHeight(self):
|
|
return self._headHeight
|
|
@headHeight.setter
|
|
def headHeight(self, value):
|
|
self._headHeight = value
|
|
|
|
@property
|
|
def bodyLength(self):
|
|
return self._bodyLength
|
|
@bodyLength.setter
|
|
def bodyLength(self, value):
|
|
self._bodyLength = value
|
|
|
|
@property
|
|
def cutAngle(self):
|
|
return self._cutAngle
|
|
@cutAngle.setter
|
|
def cutAngle(self, value):
|
|
self._cutAngle = value
|
|
|
|
@property
|
|
def chamferDistance(self):
|
|
return self._chamferDistance
|
|
@chamferDistance.setter
|
|
def chamferDistance(self, value):
|
|
self._chamferDistance = value
|
|
|
|
@property
|
|
def filletRadius(self):
|
|
return self._filletRadius
|
|
@filletRadius.setter
|
|
def filletRadius(self, value):
|
|
self._filletRadius = value
|
|
|
|
def buildBolt(self):
|
|
global newComp
|
|
newComp = createNewComponent()
|
|
if newComp is None:
|
|
ui.messageBox('New component failed to create', 'New Component Failed')
|
|
return
|
|
|
|
# Create a new sketch.
|
|
sketches = newComp.sketches
|
|
xyPlane = newComp.xYConstructionPlane
|
|
xzPlane = newComp.xZConstructionPlane
|
|
sketch = sketches.add(xyPlane)
|
|
center = adsk.core.Point3D.create(0, 0, 0)
|
|
vertices = []
|
|
for i in range(0, 6):
|
|
vertex = adsk.core.Point3D.create(center.x + (self.headDiameter/2) * math.cos(math.pi * i / 3), center.y + (self.headDiameter/2) * math.sin(math.pi * i / 3),0)
|
|
vertices.append(vertex)
|
|
|
|
for i in range(0, 6):
|
|
sketch.sketchCurves.sketchLines.addByTwoPoints(vertices[(i+1) %6], vertices[i])
|
|
|
|
extrudes = newComp.features.extrudeFeatures
|
|
prof = sketch.profiles[0]
|
|
extInput = extrudes.createInput(prof, adsk.fusion.FeatureOperations.NewBodyFeatureOperation)
|
|
|
|
distance = adsk.core.ValueInput.createByReal(self.headHeight)
|
|
extInput.setDistanceExtent(False, distance)
|
|
headExt = extrudes.add(extInput)
|
|
|
|
fc = headExt.faces[0]
|
|
bd = fc.body
|
|
bd.name = self.boltName
|
|
|
|
#create the body
|
|
bodySketch = sketches.add(xyPlane)
|
|
bodySketch.sketchCurves.sketchCircles.addByCenterRadius(center, self.bodyDiameter/2)
|
|
|
|
bodyProf = bodySketch.profiles[0]
|
|
bodyExtInput = extrudes.createInput(bodyProf, adsk.fusion.FeatureOperations.JoinFeatureOperation)
|
|
|
|
bodyExtInput.setAllExtent(adsk.fusion.ExtentDirections.NegativeExtentDirection)
|
|
bodyExtInput.setDistanceExtent(False, self.bodyLength)
|
|
bodyExt = extrudes.add(bodyExtInput)
|
|
|
|
# create chamfer
|
|
edgeCol = adsk.core.ObjectCollection.create()
|
|
edges = bodyExt.endFaces[0].edges
|
|
for edgeI in edges:
|
|
edgeCol.add(edgeI)
|
|
|
|
chamferFeats = newComp.features.chamferFeatures
|
|
chamferInput = chamferFeats.createInput(edgeCol, True)
|
|
chamferInput.setToEqualDistance(self.chamferDistance)
|
|
chamferFeats.add(chamferInput)
|
|
|
|
# create fillet
|
|
edgeCol.clear()
|
|
loops = headExt.endFaces[0].loops
|
|
edgeLoop = None
|
|
for edgeLoop in loops:
|
|
#since there two edgeloops in the start face of head, one consists of one circle edge while the other six edges
|
|
if(len(edgeLoop.edges) == 1):
|
|
break
|
|
|
|
edgeCol.add(edgeLoop.edges[0])
|
|
filletFeats = newComp.features.filletFeatures
|
|
filletInput = filletFeats.createInput()
|
|
filletInput.addConstantRadiusEdgeSet(edgeCol, self.filletRadius, True)
|
|
filletFeats.add(filletInput)
|
|
|
|
#create revolve feature 1
|
|
revolveSketchOne = sketches.add(xzPlane)
|
|
radius = self.headDiameter/2
|
|
point1 = revolveSketchOne.modelToSketchSpace(adsk.core.Point3D.create(center.x + radius*math.cos(math.pi/6), 0, center.y))
|
|
point2 = revolveSketchOne.modelToSketchSpace(adsk.core.Point3D.create(center.x + radius, 0, center.y))
|
|
|
|
point3 = revolveSketchOne.modelToSketchSpace(adsk.core.Point3D.create(point2.x, 0, (point2.x - point1.x) * math.tan(self.cutAngle)))
|
|
revolveSketchOne.sketchCurves.sketchLines.addByTwoPoints(point1, point2)
|
|
revolveSketchOne.sketchCurves.sketchLines.addByTwoPoints(point2, point3)
|
|
revolveSketchOne.sketchCurves.sketchLines.addByTwoPoints(point3, point1)
|
|
|
|
#revolve feature 2
|
|
point4 = revolveSketchOne.modelToSketchSpace(adsk.core.Point3D.create(center.x + radius*math.cos(math.pi/6), 0, self.headHeight - center.y))
|
|
point5 = revolveSketchOne.modelToSketchSpace(adsk.core.Point3D.create(center.x + radius, 0, self.headHeight - center.y))
|
|
point6 = revolveSketchOne.modelToSketchSpace(adsk.core.Point3D.create(center.x + point2.x, 0, self.headHeight - center.y - (point5.x - point4.x) * math.tan(self.cutAngle)))
|
|
revolveSketchOne.sketchCurves.sketchLines.addByTwoPoints(point4, point5)
|
|
revolveSketchOne.sketchCurves.sketchLines.addByTwoPoints(point5, point6)
|
|
revolveSketchOne.sketchCurves.sketchLines.addByTwoPoints(point6, point4)
|
|
|
|
zaxis = newComp.zConstructionAxis
|
|
revolves = newComp.features.revolveFeatures
|
|
revProf1 = revolveSketchOne.profiles[0]
|
|
revInput1 = revolves.createInput(revProf1, zaxis, adsk.fusion.FeatureOperations.CutFeatureOperation)
|
|
|
|
revAngle = adsk.core.ValueInput.createByReal(math.pi*2)
|
|
revInput1.setAngleExtent(False,revAngle)
|
|
revolves.add(revInput1)
|
|
|
|
revProf2 = revolveSketchOne.profiles[1]
|
|
revInput2 = revolves.createInput(revProf2, zaxis, adsk.fusion.FeatureOperations.CutFeatureOperation)
|
|
|
|
revInput2.setAngleExtent(False,revAngle)
|
|
revolves.add(revInput2)
|
|
|
|
sideFace = bodyExt.sideFaces[0]
|
|
threads = newComp.features.threadFeatures
|
|
threadDataQuery = threads.threadDataQuery
|
|
defaultThreadType = threadDataQuery.defaultMetricThreadType
|
|
recommendData = threadDataQuery.recommendThreadData(self.bodyDiameter, False, defaultThreadType)
|
|
if recommendData[0] :
|
|
threadInfo = threads.createThreadInfo(False, defaultThreadType, recommendData[1], recommendData[2])
|
|
faces = adsk.core.ObjectCollection.create()
|
|
faces.add(sideFace)
|
|
threadInput = threads.createInput(faces, threadInfo)
|
|
threads.add(threadInput)
|
|
def run(context):
|
|
try:
|
|
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
|
|
commandDefinitions = ui.commandDefinitions
|
|
#check the command exists or not
|
|
cmdDef = commandDefinitions.itemById('Bolt')
|
|
if not cmdDef:
|
|
cmdDef = commandDefinitions.addButtonDefinition('Bolt',
|
|
'Create Bolt',
|
|
'Create a bolt.',
|
|
'./resources') # relative resource file path is specified
|
|
|
|
onCommandCreated = BoltCommandCreatedHandler()
|
|
cmdDef.commandCreated.add(onCommandCreated)
|
|
# keep the handler referenced beyond this function
|
|
handlers.append(onCommandCreated)
|
|
inputs = adsk.core.NamedValues.create()
|
|
cmdDef.execute(inputs)
|
|
|
|
# prevent this module from being terminate when the script returns, because we are waiting for event handlers to fire
|
|
adsk.autoTerminate(False)
|
|
except:
|
|
if ui:
|
|
ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
|