Message 1 of 1
Snapshots.add reverts component position instead of capturing it..
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report
Hello, I am looking for a way to capture transformed component position, so I could draw sketches on it etc..
I have seen a few posts, where users had the similar experience, but they did solve that with design.snapshots.add() method.
https://forums.autodesk.com/t5/fusion-api-and-scripts/adding-sketch-to-face-reverts-component-transl...
https://forums.autodesk.com/t5/fusion-api-and-scripts/adding-sketch-to-face-reverts-component-transl...
In my case, this method reverts the component position instead, can't figure out why..
#Author-
#Description-
import adsk.core, adsk.fusion, adsk.cam, traceback
from .doc import Doc
def run(context):
ui = None
try:
app = adsk.core.Application.get()
ui = app.userInterface
design :adsk.fusion.Design = app.activeProduct
__transform()
if design.snapshots.hasPendingSnapshot:
design.snapshots.add()
adsk.doEvents()
except:
if ui:
ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
def __transform():
"""
Transforms the given body based on its geometric properties.
The longest edge defines the X-axis, and the Z-axis is set to the opposite
normal of the largest face by area. The body is transformed to align with
these vectors.
Validates and adjusts orientation if necessary.
"""
app = adsk.core.Application.get()
ui = adsk.core.Application.get().userInterface
try:
# Access the component and its bodies collection
design :adsk.fusion.Design = app.activeProduct
root_component = design.rootComponent
target_body: adsk.fusion.BRepBody = root_component.bRepBodies.item(0) # The body to transform
new_body: adsk.fusion.BRepBody = target_body
if not target_body:
ui.messageBox("Target body is not defined.")
return None
occs = root_component.allOccurrences
if occs.count == 0:
occ = root_component.occurrences.addNewComponent(adsk.core.Matrix3D.create())
occ.component.name = "Machining Component"
occ.component.partNumber = root_component.partNumber
new_body = target_body.copyToComponent(occ)
else:
occ = root_component.allOccurrences.item(0)
if occ.component.name != "Machining Component":
raise Exception("Invalid Document!")
# Validate orientation of the occurrence before returning
if __validate_orientation(occ):
return target_body
# Identify geometric properties
longest_edge = max(new_body.edges, key=lambda e: e.length)
x_vector = get_normal_from_edge(longest_edge)
x_vector.normalize()
largest_face = max(new_body.faces, key=lambda f: f.area)
z_vector = get_normal_from_face(largest_face)
z_vector.scaleBy(-1) # Opposite direction
z_vector.normalize()
# Calculate the Y-axis vector as a cross product of Z and X
y_vector = z_vector.crossProduct(x_vector)
y_vector.normalize()
# Recompute X-axis to ensure orthogonality
x_vector = y_vector.crossProduct(z_vector)
x_vector.normalize()
# Create the transformation matrix
transform_matrix = adsk.core.Matrix3D.create()
origin = occ.component.originConstructionPoint.geometry # Origin point
transform_matrix.setWithCoordinateSystem(origin, x_vector, y_vector, z_vector)
transform_matrix.invert()
# Apply transformation
# transform_result = root_component.transformOccurrences([occ], [transform_matrix], True)
occ.transform2 = transform_matrix
# if not transform_result:
# raise Exception("Couldn't transform the occurrences.")
# Validate the final orientation
if not __validate_orientation(occ):
raise Exception("Orientation validation failed after transformation.")
# adsk.doEvents()
# vp = app.activeViewport
# vp.fit()
# adsk.doEvents()
return new_body
except Exception as e:
ui.messageBox(f"Error in __transform: {str(e)}")
return None
def __validate_orientation(occurrence: adsk.fusion.Occurrence) -> bool:
"""
Validates if the occurrence is oriented correctly.
- X-axis should align with the longest edge.
- Z-axis should align with the opposite normal of the largest face.
"""
try:
component = occurrence.component
target_body = component.bRepBodies.item(0)
# Identify geometric properties
longest_edge = max(target_body.edges, key=lambda e: e.length)
x_vector = get_normal_from_edge(longest_edge)
largest_face = max(target_body.faces, key=lambda f: f.area)
z_vector = get_normal_from_face(largest_face)
z_vector.scaleBy(-1) # Opposite direction
z_vector.normalize()
# Get the actual transform of the occurrence
transform = occurrence.transform2
x_actual = adsk.core.Vector3D.create(
transform.getCell(0, 0), transform.getCell(0, 1), transform.getCell(0, 2)
)
z_actual = adsk.core.Vector3D.create(
transform.getCell(2, 0), transform.getCell(2, 1), transform.getCell(2, 2)
)
x_actual.normalize()
z_actual.normalize()
# Check alignment thresholds (adjust tolerance as needed)
x_aligned = x_actual.isParallelTo(x_vector)
z_aligned = z_actual.isParallelTo(z_vector)
return x_aligned and z_aligned
except Exception as e:
ui = adsk.core.Application.get().userInterface
ui.messageBox(f"Error in __validate_orientation: {str(e)}")
return False
def get_normal_from_face(face :adsk.fusion.BRepFace) -> adsk.core.Vector3D:
evaluator = face.evaluator
point_3d = adsk.core.Point3D.create(face.centroid.x, face.centroid.y, face.centroid.z)
_, face_normal = evaluator.getNormalAtPoint(point_3d)
return face_normal
def get_normal_from_edge(edge :adsk.fusion.BRepEdge) -> adsk.core.Vector3D:
start = edge.startVertex.geometry
end = edge.endVertex.geometry
return adsk.core.Vector3D.create(end.x - start.x, end.y - start.y, end.z - start.z)