Message 1 of 2
Scale Component Bodies
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report
I'm trying to create a Add-In, that will take a 3D PCB Model and generate UV test patterns from that.
I've already gotten so far, that i can generate the objects side by side, but somehow i can't change the height of those components, die Scale Feature fails with:
===== Error =====
run Traceback (most recent call last): File "/Users/mneuhaus/Library/Application Support/Autodesk/Autodesk Fusion 360/API/AddIns/PCB - SLA Jigger/PCB - SLA Jigger.py",
line 77, in run scale = scales.add(scaleInput) File "/Users/mneuhaus/Library/Application Support/Autodesk/webdeploy/production/b23c8e7040b9280fa07db4e05c50af253335fcdc/Autodesk Fusion 360.app/Contents/Api/Python/packages/adsk/fusion.py",
line 35368, in add return _fusion.ScaleFeatures_add(self, input)
RuntimeError: 3 : invalid ref point
# Assuming you have not changed the general structure of the template no modification is needed in this file.
from . import commands
from .lib import fusion360utils as futil
import adsk
def run(context):
try:
# This will run the start function in each of your commands as defined in commands/__init__.py
commands.start()
app = adsk.core.Application.get()
ui = app.userInterface
product = app.activeProduct
steps = 0;
for i in range(0, 10):
for z in range(0, i):
steps+=1
progressDialog = ui.createProgressDialog()
progressDialog.cancelButtonText = 'Cancel'
progressDialog.isBackgroundTranslucent = False
progressDialog.isCancelButtonShown = True
progressDialog.show('Progress Dialog', '%p%', 0, steps, 1)
design = adsk.fusion.Design.cast(product)
rootComponent = design.rootComponent
pcbComponent = app.activeProduct.allComponents.itemByName('ERCF Binky - 3D v11')
board = app.activeProduct.allComponents.itemByName('Board')
topCopper = rootComponent.allOccurrencesByComponent(app.activeProduct.allComponents.itemByName('1-copper'))[0]
# topSoldermask = app.activeProduct.allComponents.itemByName('1-soldermask')
# bottomCopper = app.activeProduct.allComponents.itemByName('16-copper')
# bottomSoldermask = app.activeProduct.allComponents.itemByName('16-soldermask')
uvTopLayer = rootComponent.occurrences.addNewComponent(adsk.core.Matrix3D.create())
uvTopLayer.component.name = 'UV-TopLayer'
uvTopLayerComponent = uvTopLayer.component
uvTopLayerSketch: adsk.fusion.Sketch = uvTopLayerComponent.sketches.add(
rootComponent.xYConstructionPlane
)
copySketchFeatures(pcbComponent.sketches.itemByName('Outline'), uvTopLayerSketch)
extrusion = extrude(uvTopLayerSketch.profiles.item(0), '0.035mm', '1.5mm')
uvTopLayerBody = extrusion.bodies.item(0)
uvTopLayerBody.name = "UV-Layer Top"
intersect(uvTopLayerBody, topCopper.bRepBodies)
moveComponent(uvTopLayerComponent, 0, 1.01, 0)
dimensions = get_component_size(uvTopLayerComponent)
for i in range(0, 3):
for z in range(0, i):
progressDialog.progressValue = i+1
vector = adsk.core.Vector3D.create(((dimensions['x']/10) + 0.05), ((dimensions['y']/10) + 0.05) * i, (dimensions['z']/10) * z)
transform = adsk.core.Matrix3D.create()
transform.translation = vector
duplicate = rootComponent.occurrences.addNewComponentCopy(uvTopLayerComponent, transform)
duplicateComponent = duplicate.component
basePt = uvTopLayerSketch.sketchPoints.item(0)
scaleFactor = adsk.core.ValueInput.createByReal(2)
inputColl = adsk.core.ObjectCollection.create()
inputColl.add(duplicateComponent.bRepBodies[0])
scales = rootComponent.features.scaleFeatures
scaleInput = scales.createInput(inputColl, basePt, scaleFactor)
# Set the scale to be non-uniform
xScale = adsk.core.ValueInput.createByReal(1)
yScale = adsk.core.ValueInput.createByReal(1)
zScale = adsk.core.ValueInput.createByReal(10)
scaleInput.setToNonUniform(xScale, yScale, zScale)
scale = scales.add(scaleInput)
progressDialog.hide()
except:
futil.handle_error('run')
def get_component_size(component):
app: adsk.fusion.Application = adsk.core.Application.get()
ui = app.userInterface
des: adsk.fusion.Design = app.activeProduct
# get OrientedBoundingBox
measMgr: adsk.core.MeasureManager = app.measureManager
OrientedBBoies = []
for body in component.bRepBodies:
OrientedBBoies.append(
measMgr.getOrientedBoundingBox(
body,
component.yConstructionAxis.geometry.direction,
component.xConstructionAxis.geometry.direction
)
)
# get Temporary BRepBody
tmpMgr: adsk.fusion.TemporaryBRepManager = adsk.fusion.TemporaryBRepManager.get()
tmpBodies = []
for bBox in OrientedBBoies:
tmpBodies .append(
tmpMgr.createBox(bBox)
)
# get UnionBody
unionBody: adsk.fusion.BRepBody = tmpBodies[0]
if len(tmpBodies) > 1:
for body in tmpBodies[1:]:
tmpMgr.booleanOperation(
unionBody,
body,
adsk.fusion.BooleanTypes.UnionBooleanType
)
# get UnionBody-OrientedBoundingBox
OrientedBBox: adsk.core.OrientedBoundingBox3D = measMgr.getOrientedBoundingBox(
unionBody,
component.yConstructionAxis.geometry.direction,
component.xConstructionAxis.geometry.direction
)
unitsMgr: adsk.core.UnitsManager = des.unitsManager
defLenUnit = unitsMgr.defaultLengthUnits
ratio = unitsMgr.convert(1, unitsMgr.internalUnits, defLenUnit)
return {
'x': round(OrientedBBox.width * ratio, 4),
'y': round(OrientedBBox.length * ratio, 4),
'z': round(OrientedBBox.height * ratio, 4)
}
def get_component_center_point(component):
# Get the bounding box of the component
bounding_box = component.getBoundingBox()
# Calculate the center point of the bounding box
min_point = bounding_box.minPoint
max_point = bounding_box.maxPoint
center_x = (min_point.x + max_point.x) / 2
center_y = (min_point.y + max_point.y) / 2
center_z = (min_point.z + max_point.z) / 2
# Create a Point3D object for the center point
center_point = adsk.core.Point3D.create(center_x, center_y, center_z)
return center_point
# def duplicateBodies(sourceComponent, x, y, z):
# design = adsk.fusion.Design.cast(adsk.core.Application.get().activeProduct)
# rootComponent = design.rootComponent
# vector = adsk.core.Vector3D.create(x, y, z)
# transform = adsk.core.Matrix3D.create()
# transform.translation = vector
# duplicate = rootComponent.occurrences.addNewComponent(transform)
# duplicate.component.name = sourceComponent.name
# duplicateComponent = duplicate.component
# for body in sourceComponent.bRepBodies:
# duplicateComponent.bRepBodies.add(body)
# # # Create a transform to do move
# # vector = adsk.core.Vector3D.create(x, y, z)
# # transform = adsk.core.Matrix3D.create()
# # transform.translation = vector
# # # Create a move feature
# # moveFeats = sourceComponent.features.moveFeatures
# # moveFeatureInput = moveFeats.createInput(bodies, transform)
# # moveFeats.add(moveFeatureInput)
def moveComponent(component, x, y, z):
print(component)
bodies = adsk.core.ObjectCollection.create()
for body in component.bRepBodies:
bodies.add(body)
# Create a transform to do move
vector = adsk.core.Vector3D.create(x, y, z)
transform = adsk.core.Matrix3D.create()
transform.translation = vector
# Create a move feature
moveFeats = component.features.moveFeatures
moveFeatureInput = moveFeats.createInput(bodies, transform)
moveFeats.add(moveFeatureInput)
def intersect(targetBody, intersectingBodies):
design = adsk.fusion.Design.cast(adsk.core.Application.get().activeProduct)
rootComponent = design.rootComponent
combineFeatures = rootComponent.features.combineFeatures
tools = adsk.core.ObjectCollection.create()
for intersectingBody in intersectingBodies:
tools.add(intersectingBody)
input: adsk.fusion.CombineFeatureInput = combineFeatures.createInput(targetBody, tools)
input.isNewComponent = False
input.isKeepToolBodies = True
input.operation = adsk.fusion.FeatureOperations.CutFeatureOperation
return combineFeatures.add(input)
def extrude(profile, distance, offset = '0'):
distance = adsk.core.ValueInput.createByString(distance)
offset = adsk.core.ValueInput.createByString(offset)
extrudes = profile.parentSketch.parentComponent.features.extrudeFeatures
extrudeInput = extrudes.createInput(profile, adsk.fusion.FeatureOperations.NewBodyFeatureOperation)
extentDefinition = adsk.fusion.DistanceExtentDefinition.create(distance)
offsetDefinition = adsk.fusion.OffsetStartDefinition.create(offset)
# taperAngle should be 0 because extrude start face is not a planar face in this case
extrudeInput.setOneSideExtent(extentDefinition, adsk.fusion.ExtentDirections.PositiveExtentDirection)
extrudeInput.startExtent = adsk.fusion.OffsetStartDefinition.create(offset)
return extrudes.add(extrudeInput)
def extrudeFromFace(profile, startFace, distance):
distance = adsk.core.ValueInput.createByString(distance)
extrudes = profile.parentSketch.parentComponent.features.extrudeFeatures
# Extrude Sample 3: Create an extrusion that starts from an entity and goes the specified distance.
extrudeInput = extrudes.createInput(profile, adsk.fusion.FeatureOperations.NewBodyFeatureOperation)
# Create a distance extent definition
extent_distance = adsk.fusion.DistanceExtentDefinition.create(distance)
# Create a start extent that starts from a brep face with an offset of 10 mm.
start_from = adsk.fusion.FromEntityStartDefinition.create(startFace, distance)
# taperAngle should be 0 because extrude start face is not a planar face in this case
extrudeInput.setOneSideExtent(extent_distance, adsk.fusion.ExtentDirections.PositiveExtentDirection)
extrudeInput.startExtent = start_from
# Create the extrusion
return extrudes.add(extrudeInput)
def copySketchFeatures(fromSketch, toSketch):
objs :adsk.core.ObjectCollection = getSketchAllEntities(fromSketch)
matrix = adsk.core.Matrix3D.create()
fromSketch.copy(objs, matrix, toSketch)
def getSketchAllEntities(
skt :adsk.fusion.Sketch
) -> adsk.core.ObjectCollection:
objs = adsk.core.ObjectCollection.create()
[objs.add(e) for e in skt.sketchPoints if not e.isReference]
[objs.add(e) for e in skt.sketchCurves]
[objs.add(e) for e in skt.sketchTexts]
return objs
def stop(context):
try:
# Remove all of the event handlers your app has created
futil.clear_handlers()
# This will run the start function in each of your commands as defined in commands/__init__.py
commands.stop()
except:
futil.handle_error('stop')