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):
When I measured the distance between the top faces of the two bodies, I expected the following result:
Instead, I got this:
Is there anyway to limit the measurements to be strictly on the selected face?
Thank you very much!
Solved! Go to Solution.
Solved by BrianEkins. Go to Solution.
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.
Hi Kandentti,
Thank you for your reply.
I have considered this approach too. However, there would be a problem in the following situation:
If I measure the distance between edges, the result will be very far from measuring the faces.
(a) Measure distance between edges
(b) Measure distance between faces
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!
@j.han97 .
Sorry, I was mistaken.
It may be because BRepFace.geometry is Plane, but I wasn't sure exactly why.
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
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.
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')
Thanks @BrianEkins .
In the past, the measureMinimumDistance method was not available in TemporaryBRepEntity, but I also confirmed that it is supported in Update.
The return value of the TemporaryBRepManager.copy method always returns the result of the RootComponent, so it is ideal for Occurrence elements.
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.
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.