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: 

Measure minimum distance between two parallel faces

8 REPLIES 8
SOLVED
Reply
Message 1 of 9
j.han97
884 Views, 8 Replies

Measure minimum distance between two parallel faces

Hi all,

 

I have been using measureManager to measure the minimum distance between two faces. I found that in a particular situation where the faces are parallel to each other, the distance measured is not quite what I expected.

 

Take the following model as an example (model is attached with post):

jhan97_0-1634630385084.png

When I measured the distance between the top faces of the two bodies, I expected the following result:

jhan97_1-1634630480285.png

Instead, I got this:

jhan97_2-1634630519813.png

Is there anyway to limit the measurements to be strictly on the selected face?

 

Thank you very much!

Labels (2)
8 REPLIES 8
Message 2 of 9
kandennti
in reply to: j.han97

Hi @j.han97 .

 

We have created a sample that selects two edges and displays the shortest distance.

# Fusion360API Python script

import traceback
import adsk.fusion
import adsk.core

def run(context):
    ui: adsk.core.UserInterface = None
    try:
        app: adsk.core.Application = adsk.core.Application.get()
        ui = app.userInterface
        des: adsk.fusion.Design = app.activeProduct
        root: adsk.fusion.Component = des.rootComponent

        # first edge
        msg: str = 'Select the first edge.'
        selFiltter: str = 'Edges'
        sel: adsk.core.Selection = selectEnt(msg, selFiltter)
        if not sel:
            return
        edge1: adsk.fusion.BRepEdge = sel.entity

        # second edge
        msg = 'Select the second edge.'
        sel: adsk.core.Selection = selectEnt(msg, selFiltter)
        if not sel:
            return
        edge2: adsk.fusion.BRepEdge = sel.entity

        # Minimum Distance
        measMgr: adsk.core.MeasureManager = app.measureManager
        res: adsk.core.MeasureResults = measMgr.measureMinimumDistance(edge1, edge2)

        # convert length units
        unitMgr: adsk.core.UnitsManager = des.unitsManager
        minimumDistance = unitMgr.convert(
            res.value,
            unitMgr.internalUnits,
            unitMgr.defaultLengthUnits
        )

        # result
        ui.messageBox(f'{minimumDistance} {unitMgr.defaultLengthUnits}')

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


def selectEnt(
        msg: str,
        filtterStr: str) -> adsk.core.Selection:

    try:
        app = adsk.core.Application.get()
        ui = app.userInterface
        sel = ui.selectEntity(msg, filtterStr)
        return sel
    except:
        return None

 

I did not notice any problems.

Message 3 of 9
j.han97
in reply to: kandennti

Hi Kandentti,

 

Thank you for your reply.

 

I have considered this approach too. However, there would be a problem in the following situation:

jhan97_0-1634635440053.pngjhan97_1-1634635448723.png

If I measure the distance between edges, the result will be very far from measuring the faces.

(a) Measure distance between edges

jhan97_2-1634635491120.png

(b) Measure distance between faces

jhan97_3-1634635516323.png

Although this situation is not common, I would like to prepare a generic solution to measure distances between faces. 

 

Your advice is very much appreciated!

 

Message 4 of 9
kandennti
in reply to: j.han97

@j.han97 .

 

Sorry, I was mistaken.

 

It may be because BRepFace.geometry is Plane, but I wasn't sure exactly why.

1.png

 

Instead, I measured the shortest distance between all edges and found the shortest distance.

# Fusion360API Python script

import traceback
import adsk.fusion
import adsk.core

def run(context):
    ui: adsk.core.UserInterface = None
    try:
        app: adsk.core.Application = adsk.core.Application.get()
        ui = app.userInterface
        des: adsk.fusion.Design = app.activeProduct
        root: adsk.fusion.Component = des.rootComponent

        # first edge
        msg: str = 'Select the first face.'
        selFiltter: str = 'Faces'
        sel: adsk.core.Selection = selectEnt(msg, selFiltter)
        if not sel:
            return
        face1: adsk.fusion.BRepFace = sel.entity

        # second edge
        msg = 'Select the second face.'
        sel: adsk.core.Selection = selectEnt(msg, selFiltter)
        if not sel:
            return
        face2: adsk.fusion.BRepFace = sel.entity

        # Minimum Distance
        # Measure the shortest distance between all edges.
        res = getPlanarBRepFaceMinimumDistance(face1, face2)

        # convert length units
        unitMgr: adsk.core.UnitsManager = des.unitsManager
        minimumDistance = unitMgr.convert(
            res,
            unitMgr.internalUnits,
            unitMgr.defaultLengthUnits
        )

        # result
        ui.messageBox(f'{minimumDistance} {unitMgr.defaultLengthUnits}')

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


import itertools
def getPlanarBRepFaceMinimumDistance(
    face1: adsk.fusion.BRepFace,
    face2: adsk.fusion.BRepFace) -> float:

    app: adsk.core.Application = adsk.core.Application.get()
    measMgr: adsk.core.MeasureManager = app.measureManager

    results = []
    for e1, e2 in itertools.product(face1.edges, face2.edges):
        results.append(measMgr.measureMinimumDistance(e1, e2).value)

    return min(results)


def selectEnt(
        msg: str,
        filtterStr: str) -> adsk.core.Selection:

    try:
        app = adsk.core.Application.get()
        ui = app.userInterface
        sel = ui.selectEntity(msg, filtterStr)
        return sel
    except:
        return None
Message 5 of 9
j.han97
in reply to: kandennti

Hi Kandentti,

 

Thank you for your help!

 

I actually did use a similar approach to your solution here. Unfortunately I do not have access to Fusion 360 currently, so I will explain my idea briefly below. (The code will require slight tweak or addition to work properly)

 

1. Calculate minimum distance between the faces.

app = adsk.core.Application.get()
result = app.measureManager.measureMinimumDistance(face_1: adsk.fusion.BRepFace, face_2: adsk.fusion.BRepFace)
distance = result.value

2. Check if both faces are planes.

3. If true, get the normal of the faces and calculate the angle between the normal. 

#Get normal of planar faces (face.geometry.surfaceType should be 0)
f1_normal = face_1.geometry.normal
f2_normal = face_2.geometry.normal

#Check if the normal is reversed
if face_1.isParamReversed:
    f1_normal.scaleBy(-1)
if face_2.isParamReversed:
    f2_normal.scaleBy(-1)

#Calculate angle
angle = f1_normal.angleTo(f2_normal)

4. If the angle is 0 or 180 [degree], we can conclude that the faces are parallel.

5. The main problem here is that for measurement between parallel faces, the measurement points can lie outside of the face boundaries. Hence we check if this situation happens here.

#measureResult returned by measureManager.measureMinimumDistance also provides information about the position of measurement points
f1_point = result.positionOne
f2_point = result.positionTwo

#Now check if both points are on either face
f1_point_on_face = any([face.boundingBox.contains(f1_point) for face in [face_1, face_2]])
f2_point_on_face = any([face.boundingBox.contains(f2_point) for face in [face_1, face_2]])

if f1_point_on_face and f2_point_on_face:
    return True #This indicates the measurement is actually made ON the faces

6. If the verification above failed (measurement is outside of face boundaries), measure the distances between the edges and pick the minimum. This is equivalent to the your code here.

 

This approach gives me the result I expected, but with a considerable amount of extra work. In addition, this brings more computational cost. I still believe that simply limiting the measurement points strictly within faces is the more efficient way to go.

 

Huge thank you to Kandentti for your help. In fact, you always impress me by your efficiency and quality on providing solutions.

Message 6 of 9
BrianEkins
in reply to: j.han97

The API MeasureManager is using the same internal functionality to calculate the measurements as the Measure command.  If you use the Measure command to measure the distance between two planar parallel faces it will give you the distance between the infinite planes associated with the faces.  As you've found, when measuring the distance between bodies, you get the minimum distance between the actual bodies.

 

Using the API you can take advantage of the measure body behavior by creating bodies that only contain the face.  Assuming I have two variables face1 and face2 that reference the two faces I want to measure between, the following will give me that value.

 

tempBR = adsk.fusion.TemporaryBRepManager.get()
body1 = tempBR.copy(face1)
body2 = tempBR.copy(face2)

result = app.measureManager.measureMinimumDistance(body1, body2)
app.log(f'Distance: {result.value} cm')
---------------------------------------------------------------
Brian Ekins
Inventor and Fusion 360 API Expert
Website/Blog: https://EkinsSolutions.com
Message 7 of 9
kandennti
in reply to: BrianEkins

Thanks @BrianEkins .

 

In the past, the measureMinimumDistance method was not available in TemporaryBRepEntity, but I also confirmed that it is supported in Update.

https://forums.autodesk.com/t5/fusion-360-api-and-scripts/can-t-use-measuremanager-getminimumdistanc... 

 

The return value of the TemporaryBRepManager.copy method always returns the result of the RootComponent, so it is ideal for Occurrence elements.

Message 8 of 9
j.han97
in reply to: j.han97

Thanks Brian and Kandentti for your help.

 

Creating temporary bRepBodies seems to be the more elegant way here. I will try this method and compare the computational time required.

 

Will update on this thread as soon as I got the result.

Message 9 of 9
j.han97
in reply to: j.han97

Hi all,

 

I have tested on a small model of 69 faces and the time taken for measuring temporary bRepBodies is approximately 0.5 second while my original approach takes around 3.5 second.

 

Thank you @BrianEkins for your suggestions. I will mark your reply as the solution since it is the most efficient way. Thank you to Kandentti too for your help!

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