Problems using tmpMgr.booleanOperation()

Problems using tmpMgr.booleanOperation()

maurizio_manzi
Advocate Advocate
335 Views
8 Replies
Message 1 of 9

Problems using tmpMgr.booleanOperation()

maurizio_manzi
Advocate
Advocate

Hello,
To create an OrientedBoundingBox3D from multiple faces, I merge them using the script below.
See the attached script as file and as text.
Most of the time this works very well, but with more complex (many) faces I get an error message.
If I manually stitch the faces together, it works without any issues (see video).
Does anyone have an idea how to successfully combine the faces for the OrientedBoundingBox3D?
Best regards
Maurizio

import traceback
import adsk.core
import adsk.fusion
# import adsk.cam

# Initialize the global variables for the Application and UserInterface objects.
app = adsk.core.Application.get()
ui  = app.userInterface


def run(_context: str):
    """This function is called by Fusion when the script is run."""

    try:
        faces = []
        for i in range(ui.activeSelections.count):
            sel = ui.activeSelections.item(i)
            if isinstance(sel.entity, adsk.fusion.BRepFace):
                faces.append(sel.entity)

        if len(faces) > 0:
            create_union_body(faces)
    except:
        app.log(f'Failed:\n{traceback.format_exc()}')



# Create a temporary UnionBody
def create_union_body(faces: list) -> adsk.fusion.BRepBody:
    if len(faces) < 1:
        return None
    
    tmpMgr: adsk.fusion.TemporaryBRepManager = adsk.fusion.TemporaryBRepManager.get()
    tmpBody: adsk.fusion.BRepBody = tmpMgr.copy(faces[0])

    if len(faces) < 2:
        return tmpBody

    for face in faces[1:]:
        tmpMgr.booleanOperation(
            tmpBody,
            tmpMgr.copy(face),
            adsk.fusion.BooleanTypes.UnionBooleanType,
        )

    return tmpBody

 

 

0 Likes
Accepted solutions (2)
336 Views
8 Replies
Replies (8)
Message 2 of 9

maurizio_manzi
Advocate
Advocate

the cad file and the script

0 Likes
Message 3 of 9

kandennti
Mentor
Mentor

Hi @maurizio_manzi -san.

 

For this data, the offsetting without TemporaryBRepManager did not produce any errors and was fast enough to process.

import traceback
import adsk.core
import adsk.fusion

# Initialize the global variables for the Application and UserInterface objects.
app = adsk.core.Application.get()
ui  = app.userInterface


def run(_context: str):
    """This function is called by Fusion when the script is run."""

    try:
        faces = []
        for i in range(ui.activeSelections.count):
            sel = ui.activeSelections.item(i)
            if isinstance(sel.entity, adsk.fusion.BRepFace):
                faces.append(sel.entity)

        if len(faces) > 0:
            create_clone_bodies(faces)
            print("Done")

    except:
        app.log(f'Failed:\n{traceback.format_exc()}')



# Create Clone Body - zero offset
def create_clone_bodies(faces: list) -> list[adsk.fusion.BRepBody]:
    if len(faces) < 1:
        return None
    
    comp: adsk.fusion.Component = faces[0].body.parentComponent
    offsetFeats: adsk.fusion.OffsetFeatures = comp.features.offsetFeatures

    offsetIpt: adsk.fusion.OffsetFeatureInput = offsetFeats.createInput(
        adsk.core.ObjectCollection.createWithArray(faces),
        adsk.core.ValueInput.createByReal(0),
        adsk.fusion.FeatureOperations.NewBodyFeatureOperation,
        False,
    )

    offsetFeat: adsk.fusion.OffsetFeature = offsetFeats.add(offsetIpt)

    return list(offsetFeat.bodies)
0 Likes
Message 4 of 9

maurizio_manzi
Advocate
Advocate

Hello,
thank you.
I need the result for using in:

orientedBBox: core.OrientedBoundingBox3D = measMgr.getOrientedBoundingBox(face, vecLength,vecWidth,).
My first problem is, I have more faces and getOrientedBoundingBox need a single face.
And I think, I can't use the list(offsetFeat.bodies) for this?
Best regards
Maurizio

0 Likes
Message 5 of 9

kandennti
Mentor
Mentor
Accepted solution

@maurizio_manzi -san.

We can do create_union_body after offset.

I don't know what causes the error with booleanOperation, but I think it is less likely to be an error for surfaces that are far apart.

import traceback
import adsk.core
import adsk.fusion

# Initialize the global variables for the Application and UserInterface objects.
app = adsk.core.Application.get()
ui  = app.userInterface


def run(_context: str):
    """This function is called by Fusion when the script is run."""

    try:
        faces = []
        for i in range(ui.activeSelections.count):
            sel = ui.activeSelections.item(i)
            if isinstance(sel.entity, adsk.fusion.BRepFace):
                faces.append(sel.entity)

        if len(faces) > 0:
            bodies = create_clone_bodies(faces)

            resBody: adsk.fusion.BRepBody = create_union_body(bodies)

            des: adsk.fusion.Design = app.activeProduct
            root: adsk.fusion.Component = des.rootComponent
            root.bRepBodies.add(resBody)
            
            [b.deleteMe() for b in bodies]

            print("Done")

    except:
        app.log(f'Failed:\n{traceback.format_exc()}')


# Create Clone Body - zero offset
def create_clone_bodies(faces: list) -> list[adsk.fusion.BRepBody]:
    if len(faces) < 1:
        return None
    
    comp: adsk.fusion.Component = faces[0].body.parentComponent
    offsetFeats: adsk.fusion.OffsetFeatures = comp.features.offsetFeatures

    offsetIpt: adsk.fusion.OffsetFeatureInput = offsetFeats.createInput(
        adsk.core.ObjectCollection.createWithArray(faces),
        adsk.core.ValueInput.createByReal(0),
        adsk.fusion.FeatureOperations.NewBodyFeatureOperation,
        False,
    )

    offsetFeat: adsk.fusion.OffsetFeature = offsetFeats.add(offsetIpt)

    return list(offsetFeat.bodies)


# Create a temporary UnionBody
def create_union_body(faces: list) -> adsk.fusion.BRepBody:
    if len(faces) < 1:
        return None

    tmpMgr: adsk.fusion.TemporaryBRepManager = adsk.fusion.TemporaryBRepManager.get()
    tmpBody: adsk.fusion.BRepBody = tmpMgr.copy(faces[0])

    if len(faces) < 2:
        return tmpBody

    for face in faces[1:]:
        try:
            tmpMgr.booleanOperation(
                tmpBody,
                tmpMgr.copy(face),
                adsk.fusion.BooleanTypes.UnionBooleanType,
            )
        except:
            print("Union error")

    return tmpBody
0 Likes
Message 6 of 9

maurizio_manzi
Advocate
Advocate

Hello,
thank you very much.
It works, but only if document is not parametric.

best regards
Maurizio

0 Likes
Message 8 of 9

maurizio_manzi
Advocate
Advocate

Thank you very much

0 Likes
Message 9 of 9

maurizio_manzi
Advocate
Advocate

Hello,
I try to check if it's parametric and then create a BaseFeature (adjusted run function),
but now it will delete all my bodies in root.
Best regards
Maurizio

import adsk.core, adsk.fusion, adsk.cam, traceback, os, math, subprocess, configparser, re
import adsk.core as core
from typing import Tuple
import platform, getpass, webbrowser

# Initialize the global variables for the Application and UserInterface objects.
app = adsk.core.Application.get()
ui  = app.userInterface


def run(_context: str):
    """This function is called by Fusion when the script is run."""

    try:
        faces = []
        for i in range(ui.activeSelections.count):
            sel = ui.activeSelections.item(i)
            if isinstance(sel.entity, adsk.fusion.BRepFace):
                faces.append(sel.entity)

        if len(faces) > 0:
            bodies = create_clone_bodies(faces) # Create copy of faces with 0 offset, because Fusion sometime causes an error at stitching the original faces
            resBody: adsk.fusion.BRepBody = create_union_body(bodies) # Stitch the faces copys as a resBody
            des: adsk.fusion.Design = app.activeProduct
            root: adsk.fusion.Component = des.rootComponent

            # Optional: Add a base feature if parametric
            baseFeat: fusion.BaseFeature = None
            if des.designType == adsk.fusion.DesignTypes.ParametricDesignType:
                baseFeat = root.features.baseFeatures.add()

            if baseFeat:
                baseFeat.startEdit()
                try:
                    root.bRepBodies.add(resBody, baseFeat) # Add resBody to root
                except:
                    pass
                finally:
                    baseFeat.finishEdit()
            else:
                root.bRepBodies.add(resBody) # Add resBody to root


            [b.deleteMe() for b in bodies]
           

            ui.messageBox("done")

    except:
        app.log(f'Failed:\n{traceback.format_exc()}')


# Create Clone Body - zero offset
def create_clone_bodies(faces: list) -> list[adsk.fusion.BRepBody]:
    if len(faces) < 1:
        return None
    
    comp: adsk.fusion.Component = faces[0].body.parentComponent
    offsetFeats: adsk.fusion.OffsetFeatures = comp.features.offsetFeatures

    offsetIpt: adsk.fusion.OffsetFeatureInput = offsetFeats.createInput(
        adsk.core.ObjectCollection.createWithArray(faces),
        adsk.core.ValueInput.createByReal(0),
        adsk.fusion.FeatureOperations.NewBodyFeatureOperation,
        False,
    )

    offsetFeat: adsk.fusion.OffsetFeature = offsetFeats.add(offsetIpt)

    return list(offsetFeat.bodies)


# Create a temporary UnionBody
def create_union_body(faces: list) -> adsk.fusion.BRepBody:
    if len(faces) < 1:
        return None

    tmpMgr: adsk.fusion.TemporaryBRepManager = adsk.fusion.TemporaryBRepManager.get()
    tmpBody: adsk.fusion.BRepBody = tmpMgr.copy(faces[0])

    if len(faces) < 2:
        return tmpBody

    for face in faces[1:]:
        try:
            tmpMgr.booleanOperation(
                tmpBody,
                tmpMgr.copy(face),
                adsk.fusion.BooleanTypes.UnionBooleanType,
            )
        except:
            print("Union error")

    return tmpBody


0 Likes