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.