@Joshua.mursic .
I have created a sample script that makes the triangular faces of the mesh body appear to be selected, rather than actually selecting them.
What is actually displayed are custom graphics.
# Fusion360API Python script
import traceback
import adsk
import adsk.core as core
import adsk.fusion as fusion
_app: core.Application = None
_ui: core.UserInterface = None
_handlers = []
CMD_INFO = {
'id': 'kantoku_test',
'name': 'test',
'tooltip': 'test'
}
_meshIpt: core.SelectionCommandInput = None
class MyCommandCreatedHandler(core.CommandCreatedEventHandler):
def __init__(self):
super().__init__()
def notify(self, args: core.CommandCreatedEventArgs):
try:
global _handlers
cmd: core.Command = core.Command.cast(args.command)
inputs: core.CommandInputs = cmd.commandInputs
onDestroy = MyCommandDestroyHandler()
cmd.destroy.add(onDestroy)
_handlers.append(onDestroy)
onExecutePreview = MyExecutePreviewHandler()
cmd.executePreview.add(onExecutePreview)
_handlers.append(onExecutePreview)
global _meshIpt
_meshIpt = inputs.addSelectionInput(
'_meshIptId',
'mesh',
'Select Mesh',
)
_meshIpt.addSelectionFilter(core.SelectionCommandInput.MeshBodies)
except:
_ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
class MyExecutePreviewHandler(core.CommandEventHandler):
def __init__(self):
super().__init__()
def notify(self, args: core.CommandEventArgs):
sel: core.Selection = _meshIpt.selection(0)
meshBody: fusion.MeshBody = sel.entity
point: core.Point3D = sel.point
_meshIpt.clearSelection()
meshBody.opacity = 0.5
cgBodies = get_triangle_bodies(meshBody, point)
[_meshIpt.addSelection(b) for b in cgBodies]
class MyCommandDestroyHandler(core.CommandEventHandler):
def __init__(self):
super().__init__()
def notify(self, args: core.CommandEventArgs):
adsk.terminate()
def get_triangle_bodies(
mesh: fusion.MeshBody,
point: core.Point3D,
) -> list[fusion.BRepBody]:
tmpMgr: fusion.TemporaryBRepManager = fusion.TemporaryBRepManager.get()
# *******
def init_lines(
pnts: list[core.Point3D],
) -> list[core.Line3D]:
points = list(pnts)
points.append(pnts[0])
lineLst = []
for p1, p2 in zip(points, points[1:]):
try:
line = core.Line3D.create(p1, p2)
lineLst.append(line)
except:
pass
return lineLst
def init_pointSets(
idxs: list,
nodePoints: list[core.Point3D],
) -> tuple:
return tuple([nodePoints[i] for i in idxs])
def init_wireBodies(
crvs: list,
) -> list[fusion.BRepBody]:
try:
wireBody, _ = tmpMgr.createWireFromCurves(crvs)
return wireBody
except:
pass
def init_tri_faceBodies(
wireBodies: list[fusion.BRepBody],
) -> list[fusion.BRepBody]:
triBodies = []
for b in wireBodies:
try:
triBodies.append(tmpMgr.createFaceFromPlanarWires([b]))
except:
pass
return triBodies
def is_inner(
point: core.Point3D,
pointSet: tuple[core.Point3D],
) -> bool:
vecAB: core.Vector3D = pointSet[1].vectorTo(pointSet[0])
vecBP: core.Vector3D = point.vectorTo(pointSet[1])
vecBC: core.Vector3D = pointSet[2].vectorTo(pointSet[1])
vecCP: core.Vector3D = point.vectorTo(pointSet[2])
vecCA: core.Vector3D = pointSet[0].vectorTo(pointSet[2])
vecAP: core.Vector3D = point.vectorTo(pointSet[0])
vec1: core.Vector3D = vecAB.crossProduct(vecBP)
vec2: core.Vector3D = vecBC.crossProduct(vecCP)
vec3: core.Vector3D = vecCA.crossProduct(vecAP)
dot12: float = vec1.dotProduct(vec2)
dot13: float = vec1.dotProduct(vec3)
return True if dot12 > 0 and dot13 > 0 else False
def draw_cg_bodies(
comp: fusion.Component,
bodyLst: list,
) -> list:
cgGroup: fusion.CustomGraphicsGroup = comp.customGraphicsGroups.add()
cgBodies = [cgGroup.addBRepBody(b) for b in bodyLst]
blue = fusion.CustomGraphicsSolidColorEffect.create(
core.Color.create(0,0,120,255)
)
for b in cgBodies:
b.color = blue
return cgBodies
# *******
triMesh: fusion.TriangleMesh = mesh.displayMesh
nodeIndices = triMesh.nodeIndices
triIndices = [nodeIndices[i: i + 3] for i in range(0, len(nodeIndices), 3)]
nodePoints = [p for p in triMesh.nodeCoordinates]
pointSets = [init_pointSets(idxs, nodePoints) for idxs in triIndices]
triPointSets = [pnts for pnts in pointSets if is_inner(point, pnts)]
if len(triPointSets) < 1: return
lineSets = [init_lines(triPointSet) for triPointSet in triPointSets]
triWires = [init_wireBodies(lines) for lines in lineSets]
triBodies = init_tri_faceBodies(triWires)
cgBodies = draw_cg_bodies(mesh.parentComponent, triBodies)
return cgBodies
def run(context):
try:
global _app, _ui
_app = core.Application.get()
_ui = _app.userInterface
cmdDef: core.CommandDefinition = _ui.commandDefinitions.itemById(
CMD_INFO['id']
)
if not cmdDef:
cmdDef = _ui.commandDefinitions.addButtonDefinition(
CMD_INFO['id'],
CMD_INFO['name'],
CMD_INFO['tooltip']
)
global _handlers
onCommandCreated = MyCommandCreatedHandler()
cmdDef.commandCreated.add(onCommandCreated)
_handlers.append(onCommandCreated)
cmdDef.execute()
adsk.autoTerminate(False)
except:
if _ui:
_ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
But there is a problem. Here is a video of the actual test.
The first MeshBody selected was created from a sphere.
This one shows the targeted triangular surface.
The next meshBody selected is created from a cylinder.
This one shows a completely different surface.
The difference between the two MeshBodies is whether the MeshBody has one or multiple Face Groups.
Finally, when I run the script after changing the Face Group of the cylinder's MeshBody to one, the targeted face is displayed.
My guess, since I haven't looked into it in detail, is that MeshBody.displayMesh is not returning all the information.