Community
Fusion API and Scripts
Got a new add-in to share? Need something specialized to be scripted? Ask questions or share what you’ve discovered with the community.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Draw OrientedBoundingBox in 2D Sketch

11 REPLIES 11
SOLVED
Reply
Message 1 of 12
aelqabbany
543 Views, 11 Replies

Draw OrientedBoundingBox in 2D Sketch

Hi,

 

I am trying to draw a 2D OrientedBoundingBox around all internal loops on a particular face.

 

My script works, however, the 2D box tends to be massive. Does anyone have any suggestions?

OrientedBoundingBox2D.png

import adsk.core, adsk.fusion, adsk.cam, traceback
app = adsk.core.Application.get()
ui  = app.userInterface
design = adsk.fusion.Design.cast(app.activeProduct)
rootComp = design.rootComponent
TargetBody = rootComp.bRepBodies.item(0)
faceSel = ui.selectEntity('Select a face', 'Faces')
if faceSel:
    face = adsk.fusion.BRepFace.cast(faceSel.entity)
osketch:adsk.fusion.Sketch = rootComp.sketches.add(face)
x:adsk.fusion.BRepLoop

for x in face.loops:
    if x.isOuter:
        continue
    else:
        OBX3D = app.measureManager.getOrientedBoundingBox(x,osketch.xDirection,osketch.yDirection)
        RectMid = osketch.modelToSketchSpace(OBX3D.centerPoint)
        RectMax = adsk.core.Point3D.create(OBX3D.length/10, OBX3D.width/10, OBX3D.height/10)
        RectLineList: adsk.fusion.SketchLineList = osketch.sketchCurves.sketchLines.addCenterPointRectangle(RectMid, RectMax)
11 REPLIES 11
Message 2 of 12
kandennti
in reply to: aelqabbany

Hi @aelqabbany .

 

Try this.

# Fusion360API Python script

import traceback
import adsk.fusion
import adsk.core

def run(context):
    ui = adsk.core.UserInterface.cast(None)
    try:
        app: adsk.core.Application = adsk.core.Application.get()
        ui = app.userInterface

        design = adsk.fusion.Design.cast(app.activeProduct)
        rootComp = design.rootComponent
        TargetBody = rootComp.bRepBodies.item(0)
        faceSel = ui.selectEntity('Select a face', 'Faces')
        if faceSel:
            face = adsk.fusion.BRepFace.cast(faceSel.entity)
        osketch:adsk.fusion.Sketch = rootComp.sketches.add(face)
        x:adsk.fusion.BRepLoop

        for x in face.loops:
            if x.isOuter:
                continue
            else:
                OBX3D = app.measureManager.getOrientedBoundingBox(
                    x,
                    osketch.xDirection,
                    osketch.yDirection
                )

                RectMid: adsk.core.Point3D = osketch.modelToSketchSpace(
                    OBX3D.centerPoint
                )

                RectMax = adsk.core.Point3D.create(
                    RectMid.x + OBX3D.length * 0.5,
                    RectMid.y + OBX3D.width * 0.5,
                    RectMid.z)

                RectLineList: adsk.fusion.SketchLineList = osketch.sketchCurves.sketchLines.addCenterPointRectangle(
                    RectMid,
                    RectMax
                )

    except:
        if ui:
            ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
Message 3 of 12
aelqabbany
in reply to: aelqabbany

Thank you very much @kandennti, that worked beautifully.

 

However, if you can help me out with one more thing, I would really appreciate it.

 

Some of the holes and slots in my part are not aligned to the sketch X/Y axes, therefore the bounding box is not really oriented. Do you have any suggestions for getting an oriented bounding box for those?

 

I've attached some pictures and the part that I am using.

 

Not really min bounding box.png

 

Not really min bounding box 2.png

 

 

Message 4 of 12
kandennti
in reply to: aelqabbany

@aelqabbany .

 

I am very sorry for the delay.

 

In order to create a bounding box in any direction, I think we should be able to select a straight line as a guide.

I felt that it would be better to use a dialog if I wanted to make it this far, so I created a sample and attached it.

 

1.png

If you select only "Target Face", the direction will be the same as before, in the XY direction of the sketch.

If you also select "Guide Line'", the bounding box will be created based on this line direction.

You can also use the "Angle" slider to change the angle as desired.

 

The selected surface and the resulting sketch line are the same color, so it is very difficult to see, but since it is previewed, it should be easy to adjust the angle.

Message 5 of 12
aelqabbany
in reply to: kandennti

Thank you very much, this is great!

 

I'll try to modify it such that it automatically detects all possible guide rails and finds the smallest box possible.

Message 6 of 12
kandennti
in reply to: aelqabbany

Message 7 of 12
aelqabbany
in reply to: aelqabbany

@kandennti I am not sure that I understand. For a single loop the smallest box will always be in one direction unless the loop is a circle. However, a single face can contain many loops, each one requiring the smallest to be in different directions.

 

The approach that I am thinking of is by getting the vectors for all straight lines in the loop. I would also have to draw temporary lines between all center points,  start, endpoints, etc... and get the vectors for those. This would be slow, but in theory, it would give us one correct axis. Then we can cross-multiply with the face normal to give us the other axis.

 

Check the part I attached to this post for a bunch of complicated loops on different faces.

Message 8 of 12
kandennti
in reply to: aelqabbany

@aelqabbany .

 

We know that we can use the BRepBody.getPhysicalProperties method to get the direction of the smallest box.

https://help.autodesk.com/view/fusion360/ENU/?guid=GUID-271541AB-027D-4C10-AC4F-D588FE3257E9 

 

After some testing, I found out the following.
・It does not work with the BRepBody created by TemporaryBRepManager.
・It does not work with surfaces.

 

Therefore, it seems that a little ingenuity is needed.
I would like to work on this if I get some time.

 

Message 9 of 12
aelqabbany
in reply to: aelqabbany

Hi @kandennti,

 

This is along the lines of what I was thinking about. I was hoping it would give me boxes aligned to all the edges, but instead it just gives a group of random boxes.

BoundingBoxes.png

 

import traceback
import adsk.fusion
import adsk.core

def getLoopOrientedBoundingBox(oFace: adsk.fusion.BRepFace, osketch, oLoop:adsk.fusion.BRepLoop) -> adsk.core.OrientedBoundingBox3D:
    app: adsk.core.Application = adsk.core.Application.get()
    ui = adsk.core.UserInterface.cast(None)
    ui = app.userInterface
    if oFace.geometry.surfaceType != 0:
        #Face is not planar
        return False
    if oLoop.edges.count <= 1:
        #Circle or ellipse special case
        return False
    
    oFaceGeometry: adsk.core.Plane = oFace.geometry
    oFaceNormal = oFaceGeometry.normal

    VertexCollection = []
    oEdge:adsk.fusion.BRepEdge
    for oEdge in oLoop.edges:
        VertexCollection.append(oEdge.startVertex)
        VertexCollection.append(oEdge.endVertex)
    
    
    VertexCollectionLen = len(VertexCollection)
    VectorCollection = []
    for i in range(VertexCollectionLen):
        for j in range(i+1, VertexCollectionLen):
            oVector = adsk.core.Vector3D.create(VertexCollection[j].geometry.x - VertexCollection[i].geometry.x, VertexCollection[j].geometry.y - VertexCollection[i].geometry.y, VertexCollection[j].geometry.z - VertexCollection[i].geometry.z)
            if oVector.length > 0:
                VectorCollection.append(oVector)

    SmallestBoxArea = 9999999
    SmallestxBX3D: adsk.core.OrientedBoundingBox3D
    xVector : adsk.core.Vector3D
    for xVector in VectorCollection:
        
        yVector = oFaceNormal.crossProduct(xVector)
        xBX3D = app.measureManager.getOrientedBoundingBox(oLoop, xVector, yVector)
        xBX3DArea = xBX3D.length * xBX3D.width

        RectMid: adsk.core.Point3D = osketch.modelToSketchSpace(
                    xBX3D.centerPoint
                )

        RectMax = adsk.core.Point3D.create(
                    RectMid.x + xBX3D.length * 0.5,
                    RectMid.y + xBX3D.width * 0.5,
                    RectMid.z)

        RectLineList: adsk.fusion.SketchLineList = osketch.sketchCurves.sketchLines.addCenterPointRectangle(
                    RectMid,
                    RectMax
                )

        if xBX3DArea < SmallestBoxArea:
            SmallestBoxArea = xBX3DArea
            SmallestxBX3D = xBX3D
    
    return SmallestxBX3D

def run(context):
    ui = adsk.core.UserInterface.cast(None)
    try:
        app: adsk.core.Application = adsk.core.Application.get()
        ui = app.userInterface

        design = adsk.fusion.Design.cast(app.activeProduct)
        rootComp = design.rootComponent
        TargetBody = rootComp.bRepBodies.item(0)
        faceSel = ui.selectEntity('Select a face', 'Faces')
        if faceSel:
            face = adsk.fusion.BRepFace.cast(faceSel.entity)
        osketch:adsk.fusion.Sketch = rootComp.sketches.add(face)
        oLoop:adsk.fusion.BRepLoop

        for oLoop in face.loops:
            if oLoop.isOuter:
                continue
            else:
                OBX3D = getLoopOrientedBoundingBox(face,osketch, oLoop)
                # OBX3D = app.measureManager.getOrientedBoundingBox(
                #     oLoop,
                #     osketch.xDirection,
                #     osketch.yDirection
                # )

                # RectMid: adsk.core.Point3D = osketch.modelToSketchSpace(
                #     OBX3D.centerPoint
                # )

                # RectMax = adsk.core.Point3D.create(
                #     RectMid.x + OBX3D.length * 0.5,
                #     RectMid.y + OBX3D.width * 0.5,
                #     RectMid.z)

                # RectLineList: adsk.fusion.SketchLineList = osketch.sketchCurves.sketchLines.addCenterPointRectangle(
                #     RectMid,
                #     RectMax
                # )

    except:
        if ui:
            ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

 

Message 10 of 12
kandennti
in reply to: aelqabbany

@aelqabbany .

 

After some testing I found that the BRepBody.getPhysicalProperties method does not get the orientation of the smallest box.

 

Therefore, we rotated each loop 90 degrees from 0 to find the angle that results in the smallest size.

1.png

 

Currently it looks for it every 1 degree. It is possible to check more precisely, but the processing time will be longer.

Message 11 of 12
kandennti
in reply to: kandennti

@aelqabbany .

 

We have come up with a more efficient way to locate them with higher precision, so we have modified it.

Message 12 of 12
aelqabbany
in reply to: aelqabbany

Thank you very much @kandennti! You are a legend!

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk DevCon in Munich May 28-29th


Autodesk Design & Make Report