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: 

[Bug?] pointOnFace in rare cases returns a point at a corner of the face

2 REPLIES 2
Reply
Message 1 of 3
nnikbin
159 Views, 2 Replies

[Bug?] pointOnFace in rare cases returns a point at a corner of the face

BRepFace.pointOnFace in some rare cases returns a point at a corner of the face. For example it returns (40, 40, 0) for the following face. The related file is attached.

54.png

It seems to be in contrast to what is promised in the relevant document:

 

Returns a sample point guaranteed to lie on the face's surface, within the face's boundaries, and not on a boundary edge.

 

It may not seem a big deal but for an add-in which depends on the accuracy of this property it could mean the potential for wrong functionality.

 

Tags (1)
Labels (1)
  • bug
2 REPLIES 2
Message 2 of 3
kandennti
in reply to: nnikbin

HI @nnikbin .

 

I'm sorry, but I don't see this as a bug.

 

At least the "Shape Manager" seems to consider a point on an edge to be on a surface.
You can check this by using the isParameterOnFace method.

 

https://help.autodesk.com/view/fusion360/ENU/?guid=GUID-e6682eb7-48f8-472d-9872-71da3c5ba8c8 

# Fusion360API Python script
import adsk.core, adsk.fusion, traceback

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

        face :adsk.fusion.BRepFace = root.bRepBodies[0].faces[0]
        pointOnFace :adsk.core.Point3D = face.pointOnFace
        eva :adsk.core.SurfaceEvaluator = face.evaluator
        _, prm = eva.getParameterAtPoint(pointOnFace)

        ui.messageBox(f'{eva.isParameterOnFace(prm)}')

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

 

 

If it is not convenient on the edge, I think there is no other way but to create such a mechanism, so I made one.

# Fusion360API Python script
import adsk.core, adsk.fusion, traceback
import random

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

        # Point On Face
        face :adsk.fusion.BRepFace = root.bRepBodies[0].faces[0]
        pointOnFace :adsk.core.Point3D = face.pointOnFace
        dumpPoint(pointOnFace, root, 'Point On Face')

        # Point On Face  Exclude On The Edge
        for _ in range(10):
            excludeOnEdge = getPointOnFace_ExcludeOnEdge(face)
            dumpPoint(excludeOnEdge, root, 'Exclude On The Edge')

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

def getPointOnFace_ExcludeOnEdge(
    face :adsk.fusion.BRepFace) -> adsk.core.Point3D:

    def getUniqueParameter(
        minPrm :adsk.core.Point2D,
        maxPrm :adsk.core.Point2D) -> adsk.core.Point2D:

        return adsk.core.Point2D.create(
            random.uniform(minPrm.x, maxPrm.x),
            random.uniform(minPrm.y, maxPrm.y))

    def isPointOnEdges(
        pnt :adsk.core.Point3D,
        toleranceEdgeDistance :float = 0.1) -> bool:

        for edge in face.edges:
            if isPointOnEdge(pnt, edge, toleranceEdgeDistance):
                return True

        return False

    def isPointOnEdge(
        pnt :adsk.core.Point3D,
        edge :adsk.fusion.BRepEdge,
        toleranceEdgeDistance :float) -> bool:

        eva :adsk.core.CurveEvaluator3D = edge.evaluator
        _, prm = eva.getParameterAtPoint(pnt)

        _, prmPnt = eva.getPointAtParameter(prm)
        return pnt.isEqualToByTolerance(prmPnt, toleranceEdgeDistance)

    # ***

    pnt :adsk.core.Point3D = face.pointOnFace
    if not isPointOnEdges(pnt):
        return pnt

    surfEva :adsk.core.SurfaceEvaluator = face.evaluator
    bound :adsk.core.BoundingBox2D = surfEva.parametricRange()

    while True:
        prm = getUniqueParameter(bound.minPoint, bound.maxPoint)

        if not surfEva.isParameterOnFace(prm):
            continue

        _, pnt = surfEva.getPointAtParameter(prm)

        if not isPointOnEdges(pnt):
            return pnt


def dumpPoint(
    pnt :adsk.core.Point3D,
    comp :adsk.fusion.Component,
    name :str):

    skt :adsk.fusion.Sketch = comp.sketches.add(comp.xYConstructionPlane)
    skt.name = name
    skt.sketchPoints.add(pnt)

 

Since it can be done in a random position, the result will change every time you run it.
There may be a better algorithm.

Message 3 of 3
nnikbin
in reply to: kandennti

Hi @kandennti , Thank you for your reply and your code. Actually after finding the rare case issue, I used the almost same method in my code based on this post without even using face.pointOnFace. I think based on its random nature it is almost impossible that this method to return a point on an edge.

 

In my opinion it is a bug. I think the whole point of face.pointOnFace is to return a point which is guaranteed to be within the face's boundaries (not on the boundary) because the boundary conditions causes problems in many algorithms (for example offsetting the edges inward or outward). If we want to find a point on a face and we do not care if it is on an edge or not, we can just use a point on edge or corner and easily find it.

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