Hi, hope you're doing great!
I'm creating a 2D Contour operation for my setup, via the api, while making use of the ChainSelection class. As input geometry there's an object collection containing B-Rep Edges. There is a method of the ChainSelection class called set_isReverted in which you can specify if the curve you imported is reverted or not, but I cannot seem to figure out a way to determine if it's reverted or not. I've tried using the get_isParamReversed method of the B-Rep Face class (for the face I'm trying to cut) which returns a boolean and is then used as input parameter for the set_isReverted method, but that doesn't seem to generate proper results.
If anyone can specify when a curve or edge is reverted please let me know!
Also, it seems like it only depends on Fusion's guess to determine if a curve is Reverted or not.
I don't have personal experience with this and am guessing, but I assume you need to look at the start and end vertices of the edges you're using are connected in a way where the end of once connects to the start of the next one. If you have an end that connects to an end then it would need to be reverted. You can get the start and end vertices from an edge by using its startVertex and endVertex properties. But I could be misintrepting what this property is intended to do.
Hi @echatzief -San.
I believe this is probably a continuation of this one.
I came up with the idea this morning to use the outer product of the tangent of the outer edge of the target and the normal of the surface to make the determination.
It is long, but it is the is_outside function that is directly making the determination.
# Fusion360API Python script
import traceback
import adsk.core as core
import adsk.fusion as fusion
import adsk.cam as cam
def run(context):
ui: core.UserInterface = None
try:
app: core.Application = core.Application.get()
ui = app.userInterface
camObj: cam.CAM = get_cam_product()
# setup
setup: cam.Setup = get_setup(camObj)
if not setup: return
# axisZ
axisZ: core.Vector3D = core.Vector3D.create(0,0,1)
# tool
tool: cam.Tool = camObj.documentToolLibrary[0]
# body
prm: cam.CAMParameter = setup.parameters.itemByName("job_model")
body: fusion.BRepBody = list(prm.value.value)[0]
# get target faces
faces = get_planer_face(
body,
axisZ,
)
# create pocket2d
for face in faces:
create_pocket2d(setup, tool, face)
# generate
camObj.generateAllToolpaths(True)
except:
if ui:
ui.messageBox("Failed:\n{}".format(traceback.format_exc()))
def create_pocket2d(
setup: cam.Setup,
tool: cam.Tool,
face: fusion.BRepFace,
) -> None:
input: cam.OperationInput = setup.operations.createInput('pocket2d')
input.tool = tool
edges = get_outer_loop_edges(face)
edge: fusion.BRepEdge = edges[0]
contourParam: cam.CadContours2dParameterValue = input.parameters.itemByName(
'pockets'
).value
curveSelections: cam.CurveSelections = contourParam.getCurveSelections()
chain: cam.CurveSelection = curveSelections.createNewChainSelection()
chain.isReverted = is_outside(face, edge)
chain.inputGeometry = [edge]
contourParam.applyCurveSelections(curveSelections)
setup.operations.add(input)
def is_outside(
face: fusion.BRepFace,
edge: fusion.BRepEdge,
) -> bool:
startPnt: core.Point3D = edge.startVertex.geometry
eva: core.CurveEvaluator3D = edge.evaluator
_, prm = eva.getParameterAtPoint(startPnt)
tangent: core.Vector3D = None
_, tangent = eva.getTangent(prm)
normal: core.Vector3D = get_normal(face)
vec: core.Vector3D = normal.crossProduct(tangent)
vec.scaleBy(0.0001)
pnt: core.Point3D = startPnt.copy()
pnt.translateBy(vec)
tmpMgr: fusion.TemporaryBRepManager = fusion.TemporaryBRepManager.get()
faceBody: fusion.BRepBody = tmpMgr.copy(face)
res: fusion.PointContainment = faceBody.pointContainment(pnt)
return res == fusion.PointContainment.PointOutsidePointContainment
def get_outer_loop_edges(
face: fusion.BRepFace
) -> list[fusion.BRepEdge]:
loop: fusion.BRepLoop = None
for loop in face.loops:
if loop.isOuter:
return list(loop.edges)
return None
def get_normal(
face: fusion.BRepFace
) -> core.Vector3D:
normal: core.Vector3D = face.geometry.normal
if face.isParamReversed:
normal.scaleBy(-1)
return normal
def get_planer_face(
body: fusion.BRepBody,
axisZ: core.Vector3D,
) -> list[fusion.BRepFace]:
face: fusion.BRepFace = None
return [face for face in body.faces
if is_target_face(face, axisZ)]
def is_target_face(
face: fusion.BRepFace,
axisZ: core.Vector3D,
) -> bool:
if face.geometry.objectType != core.Plane.classType():
return False
normal: core.Vector3D = get_normal(face)
return axisZ.isEqualTo(normal)
def get_setup(camObj: cam.CAM) -> cam.Setup:
setups: cam.Setups = camObj.setups
if setups.count < 1:
return None
return setups[0]
def get_cam_product() -> cam.CAM:
app: core.Application = core.Application.get()
activete_cam_env()
return app.activeProduct
def activete_cam_env() -> None:
app: core.Application = core.Application.get()
ui: core.UserInterface = app.userInterface
camWS: core.Workspace = ui.workspaces.itemById('CAMEnvironment')
camWS.activate()
I have been able to successfully determine this with some modifications to your sample model, but I have not tested it enough and may find a counterexample.
There may be an easier way to determine this.
hi, did anybody find a way to determine the isReverted value. I have been puzzling for 2 days now and havent gotten anywhere. The code above did not have satisfactory results. I have tried getting the face normal, and returning the X and Y (if getting the face normal, either x or y should be either 1 or -1(sideface), right? maybe I am wrong on that...)
This is an adaptation of the suggestion by @kandennti above. I've adapted it to work for closed profiles on the XY axis. Hopefully, someone else finds this useful.
def isReverse(chainSelection):
# use a temporary BRepManager to create a face from the chain curves
tmpMgr :fusion.TemporaryBRepManager = adsk.fusion.TemporaryBRepManager.get()
chainCurves = [c.geometry for c in chainSelection.value]
try:
(wire, _) = tmpMgr.createWireFromCurves(chainCurves)
face = tmpMgr.createFaceFromPlanarWires([wire])
# analyze the first curve in the chain; it determines the direction of the chain
sketchCurve = chainSelection.value[0]
curve = sketchCurve.geometry
eval :adsk.core.CurveEvaluator3D = curve.evaluator
(_, startParameter, _) = eval.getParameterExtents()
(_, startPt) = eval.getPointAtParameter(startParameter)
tangent: core.Vector3D = None
(_, tangent) = eval.getTangent(startParameter)
normal: core.Vector3D = core.Vector3D.create(0, 0, 1) # we're always on the XY plane
vec: core.Vector3D = normal.crossProduct(tangent)
vec.scaleBy(0.001)
perpendicularPt: core.Point3D = startPt.copy()
perpendicularPt.translateBy(vec)
res: fusion.PointContainment = face.pointContainment(perpendicularPt) # 0 = inside, 1 = on, 2 = outside
# log(f'Point containment: {res}')
return res != fusion.PointContainment.PointOutsidePointContainment # if the point is not outside, the chain is reverse configuration
except:
log('Error when determining Profile direction.')
_ui.messageBox('Error when determining Profile direction. Do you have an overlap?')
return False
Hi Fellows,
Consider the following snippet of code, supplementing it with the relevant excerpts from the API reference.
interBodycoEdges = brepLoop.coEdges
for coEdge in interBodycoEdges:
if coEdge.isOpposedToEdge:
# do_what_is_needed
pass
if coEdge.isParamReversed:
# do_what_is_needed
pass
Regards
MichaelT
Can't find what you're looking for? Ask the community or share your knowledge.