Scale Component Bodies

Scale Component Bodies

apocalip
Contributor Contributor
366 Views
1 Reply
Message 1 of 2

Scale Component Bodies

apocalip
Contributor
Contributor

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')

 

 

0 Likes
367 Views
1 Reply
Reply (1)
Message 2 of 2

BrianEkins
Mentor
Mentor

It will help to have a simpler sample that demonstrates the specific issue you're having, along with a model that can be used to reproduce it.

---------------------------------------------------------------
Brian Ekins
Inventor and Fusion 360 API Expert
Website/Blog: https://EkinsSolutions.com