Snapshots.add reverts component position instead of capturing it..

Snapshots.add reverts component position instead of capturing it..

KarolisCAMax
Participant Participant
169 Views
0 Replies
Message 1 of 1

Snapshots.add reverts component position instead of capturing it..

KarolisCAMax
Participant
Participant

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)

 

0 Likes
170 Views
0 Replies
Replies (0)