TriadCommandInput not setting initialTransform

TriadCommandInput not setting initialTransform

Joshua.mursic
Advocate Advocate
757 Views
6 Replies
Message 1 of 7

TriadCommandInput not setting initialTransform

Joshua.mursic
Advocate
Advocate

When trying to set the initial position of the Triad command,

 

 

initialMatrix = occurence.transform2
app.log(f'{occurence.transform2.asArray()}')
transformInput = inputs.addTriadCommandInput("constructionTransform",initialMatrix)
app.log(f'{transformInput.transform.asArray()}')

 

 

these are the logs,

(1.0, 5.551115123125783e-17, 5.551115123125783e-17, -2.466307277628033, 0.0, 1.0, 0.0, -2.2102425876010776, 0.0, -2.7755575615628914e-17, 1.0, 0.7004493042826652, 0.0, 0.0, 0.0, 1.0)

(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0).

 

Am I using the command input object incorrectly?

0 Likes
Accepted solutions (1)
758 Views
6 Replies
Replies (6)
Message 2 of 7

kandennti
Mentor
Mentor
Accepted solution

Hi @Joshua.mursic -San.

 

The fact that addTriadCommandInput cannot be set with any Matrix3D seems like a bug.
However, if I set it in the transform property, I get the result I want when it is displayed.

transformInput = inputs.addTriadCommandInput("constructionTransform",initialMatrix)
transformInput.transform = initialMatrix


During the commandCreated event, transformInput.transform.asArray did not get the correct values.
My guess is that this is because Command.commandInputs is not created until the commandCreated event is completed.
The following sample outputs transformInput.transform.asArray by pressing the OK button.

# 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'
}

transformInput: core.TriadCommandInput = 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)

            onExecute = MyExecuteHandler()
            cmd.execute.add(onExecute)
            _handlers.append(onExecute)

            app: core.Application = core.Application.get()
            des: fusion.Design = app.activeProduct
            root: fusion.Component = des.rootComponent
            occ: fusion.Occurrence = root.occurrences[0]

            initialMatrix: core.Matrix3D = occ.transform2
            app.log(f"occ.transform2:{initialMatrix.asArray()}")

            global transformInput
            transformInput = inputs.addTriadCommandInput(
                "constructionTransform",
                initialMatrix
            )

            transformInput.transform = initialMatrix
            app.log(f"Command Created Event:{transformInput.transform.asArray()}")

        except:
            _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))


class MyExecuteHandler(core.CommandEventHandler):
    def __init__(self):
        super().__init__()

    def notify(self, args: core.CommandEventArgs):
        global transformInput
        _app.log(f"Command Execute Event:{transformInput.transform.asArray()}")


class MyCommandDestroyHandler(core.CommandEventHandler):
    def __init__(self):
        super().__init__()

    def notify(self, args: core.CommandEventArgs):
        adsk.terminate()


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()))
Message 3 of 7

Joshua.mursic
Advocate
Advocate

Yes I think this is a bug, thank you @kandennti 

 

I am trying to create a function to prompt the user to transform a component. They get instances like this where the rotation triad is not aligned well with the part. To rotate the cube around its flat faces instead of the corners it become difficult. I made a button so the user can adjust the triad and align it how they want without rotating the part, but I am having a hard time getting the movement to be correct. 

Joshuamursic_0-1701450431003.png  Joshuamursic_2-1701450492970.png

 

When using the directional arrows the motion is correct, but when using the plane movement is unexpected.

Joshuamursic_3-1701450582317.png Joshuamursic_4-1701450616501.png

 

 

import adsk.core, adsk.fusion, adsk.cam, traceback
app = adsk.core.Application.get()
ui  = app.userInterface
handlers = []

cmdID = "testButton"
gOccurrence:adsk.fusion.Occurrence = None
allowRotate:bool = True
transformMatrix:adsk.core.Matrix3D = None

def run(context):
    global cmdID
    try:
        app = adsk.core.Application.get()
        ui  = app.userInterface

        # Get the CommandDefinitions collection.
        cmdDefs = ui.commandDefinitions

        # Create a button command definition.
        button = cmdDefs.addButtonDefinition(cmdID, 'Test', '')
        
        # Connect to the command created event.
        created = Create_Command()
        button.commandCreated.add(created)
        handlers.append(created)
        
        # Execute the command.
        button.execute()
        
        # Keep the script running.
        adsk.autoTerminate(False)
    except:
        if ui:
            ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

        
def stop(context):
    global cmdID
    try:
        app = adsk.core.Application.get()
        ui  = app.userInterface
        
        # Delete the command definition.
        cmdDef = ui.commandDefinitions.itemById(cmdID)
        if cmdDef:
            cmdDef.deleteMe()    

    except:
        ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))


# Event handler for the commandCreated event.
class Create_Command(adsk.core.CommandCreatedEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args: adsk.core.CommandCreatedEventArgs):
        global gOccurrence,transformMatrix

        try:
            cmd = args.command
            inputs = cmd.commandInputs

            design:adsk.fusion.Design = app.activeDocument.products.itemByProductType("DesignProductType")
            root:adsk.fusion.Component = design.rootComponent
            occurrence = root.occurrences.item(0)
            
            #set global variables
            gOccurrence = occurrence
            transformMatrix = occurrence.transform2
            
            #create triad input
            transformInput = inputs.addTriadCommandInput("constructionTransform",transformMatrix)
            transformInput.transform = transformMatrix
            transformInput.isVisible = True
            
            #create bool input
            alignTriadButton = inputs.addBoolValueInput("alignTriad","Align Transformer",True)

            execute = Command_Execute()
            cmd.execute.add(execute)
            handlers.append(execute)

            inputChanged = Input_Changed()
            cmd.inputChanged.add(inputChanged)
            handlers.append(inputChanged)

            preview = Preview()
            cmd.executePreview.add(preview)
            handlers.append(preview)

            destroy = Destroy()
            cmd.destroy.add(destroy)
            handlers.append(destroy)

        except:
            ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))


class Destroy(adsk.core.CommandEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args: adsk.core.CommandEventArgs):
        global gOccurrence,transformMatrix,allowRotate,handlers,cmdID

        handlers = []
        gOccurrence = None
        transformMatrix = None
        allowRotate = True

        app = adsk.core.Application.get()
        ui  = app.userInterface
        
        # Delete the command definition.
        cmdDef = ui.commandDefinitions.itemById(cmdID)
        if cmdDef:
            cmdDef.deleteMe()    


class Command_Execute(adsk.core.CommandEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args: adsk.core.CommandEventArgs):
        global gOccurrence
        gOccurrence.transform2 = transformMatrix


class Input_Changed(adsk.core.InputChangedEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args: adsk.core.InputChangedEventArgs):
        global transformMatrix,gOccurrence,allowRotate
        input = args.input

        transformInput:adsk.core.TriadCommandInput = args.inputs.itemById("constructionTransform")
        rotateTriad:adsk.core.BoolValueCommandInput = args.inputs.itemById("alignTriad")

        if input == rotateTriad and rotateTriad.value == True:
            allowRotate = False
        if input == rotateTriad and rotateTriad.value == False:
            allowRotate = True

        if input == transformInput:
            #get the matrix of change between last transform and this one
            fromMat = transformInput.lastTransform.getAsCoordinateSystem()
            toMat = transformInput.transform.getAsCoordinateSystem()
            changeMat = adsk.core.Matrix3D.create()
            changeMat.setToAlignCoordinateSystems(fromMat[0],fromMat[1],fromMat[2],fromMat[3],toMat[0],toMat[1],toMat[2],toMat[3])
            transformMatrix = gOccurrence.transform2
            transformMatrix.transformBy(changeMat)


class Preview(adsk.core.CommandEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args: adsk.core.CommandEventArgs):
        global transformMatrix,gOccurrence,allowRotate
        if allowRotate:
            gOccurrence.transform2 = transformMatrix

 

 

 

 

 

 

0 Likes
Message 4 of 7

kandennti
Mentor
Mentor

@Joshua.mursic -San.

 

I found the cause.
The direct cause is this part.

        if allowRotate:
            gOccurrence.transform2 = transformMatrix


I made the changes to do the processing you want.

import adsk.core, adsk.fusion, adsk.cam, traceback
app = adsk.core.Application.get()
ui  = app.userInterface
handlers = []

cmdID = "testButton"
gOccurrence:adsk.fusion.Occurrence = None
# allowRotate:bool = True
transformMatrix:adsk.core.Matrix3D = None
backupMatrix: adsk.core.Matrix3D = None

def run(context):
    global cmdID
    try:
        app = adsk.core.Application.get()
        ui  = app.userInterface

        # Get the CommandDefinitions collection.
        cmdDefs = ui.commandDefinitions

        # Create a button command definition.
        button = cmdDefs.addButtonDefinition(cmdID, 'Test', '')
        
        # Connect to the command created event.
        created = Create_Command()
        button.commandCreated.add(created)
        handlers.append(created)
        
        # Execute the command.
        button.execute()
        
        # Keep the script running.
        adsk.autoTerminate(False)
    except:
        if ui:
            ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

        
def stop(context):
    global cmdID
    try:
        app = adsk.core.Application.get()
        ui  = app.userInterface
        
        # Delete the command definition.
        cmdDef = ui.commandDefinitions.itemById(cmdID)
        if cmdDef:
            cmdDef.deleteMe()    

    except:
        ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))


# Event handler for the commandCreated event.
class Create_Command(adsk.core.CommandCreatedEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args: adsk.core.CommandCreatedEventArgs):
        global gOccurrence,transformMatrix

        try:
            cmd = args.command
            inputs = cmd.commandInputs

            design:adsk.fusion.Design = app.activeDocument.products.itemByProductType("DesignProductType")
            root:adsk.fusion.Component = design.rootComponent
            occurrence = root.occurrences.item(0)
            
            #set global variables
            gOccurrence = occurrence
            transformMatrix = occurrence.transform2
            
            #create triad input
            transformInput = inputs.addTriadCommandInput("constructionTransform",transformMatrix)
            transformInput.transform = transformMatrix
            transformInput.isVisible = True
            
            #create bool input
            alignTriadButton = inputs.addBoolValueInput("alignTriad","Align Transformer",True)
            alignTriadButton.value = True

            # execute = Command_Execute()
            # cmd.execute.add(execute)
            # handlers.append(execute)

            inputChanged = Input_Changed()
            cmd.inputChanged.add(inputChanged)
            handlers.append(inputChanged)

            preview = Preview()
            cmd.executePreview.add(preview)
            handlers.append(preview)

            destroy = Destroy()
            cmd.destroy.add(destroy)
            handlers.append(destroy)

        except:
            ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))


class Destroy(adsk.core.CommandEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args: adsk.core.CommandEventArgs):
        # global gOccurrence,transformMatrix,allowRotate,handlers,cmdID
        global gOccurrence,transformMatrix,handlers,cmdID

        handlers = []
        gOccurrence = None
        transformMatrix = None
        # allowRotate = True

        app = adsk.core.Application.get()
        ui  = app.userInterface
        
        # Delete the command definition.
        cmdDef = ui.commandDefinitions.itemById(cmdID)
        if cmdDef:
            cmdDef.deleteMe()    


# class Command_Execute(adsk.core.CommandEventHandler):
#     def __init__(self):
#         super().__init__()
#     def notify(self, args: adsk.core.CommandEventArgs):
#         global gOccurrence
#         gOccurrence.transform2 = transformMatrix


class Input_Changed(adsk.core.InputChangedEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args: adsk.core.InputChangedEventArgs):
        global transformMatrix,gOccurrence#,allowRotate
        input = args.input

        transformInput:adsk.core.TriadCommandInput = args.inputs.itemById("constructionTransform")
        rotateTriad:adsk.core.BoolValueCommandInput = args.inputs.itemById("alignTriad")

        global backupMatrix
        if input == rotateTriad:
            transformInput.setRotateVisibility(
                rotateTriad.value
            )
            transformInput.transform = backupMatrix

        backupMatrix = transformInput.transform

        # if input == rotateTriad and rotateTriad.value == True:
        #     # allowRotate = False
        #     transformInput.setRotateVisibility(
        #         True
        #     )
        # if input == rotateTriad and rotateTriad.value == False:
        #     # allowRotate = True
        #     transformInput.setRotateVisibility(
        #         False
        #     )
        # if input == transformInput:
        #     #get the matrix of change between last transform and this one
        #     fromMat = transformInput.lastTransform.getAsCoordinateSystem()
        #     toMat = transformInput.transform.getAsCoordinateSystem()
        #     changeMat = adsk.core.Matrix3D.create()
        #     changeMat.setToAlignCoordinateSystems(fromMat[0],fromMat[1],fromMat[2],fromMat[3],toMat[0],toMat[1],toMat[2],toMat[3])
        #     transformMatrix = gOccurrence.transform2
        #     transformMatrix.transformBy(changeMat)


class Preview(adsk.core.CommandEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args: adsk.core.CommandEventArgs):
        global transformMatrix,gOccurrence#,allowRotate

        # if allowRotate:
        #     gOccurrence.transform2 = transformMatrix

        transformInput:adsk.core.TriadCommandInput = args.command.commandInputs.itemById("constructionTransform")
        gOccurrence.transform2 = transformInput.transform

        des: adsk.fusion.Design = app.activeProduct
        des.snapshots.add()

        args.isValidResult = True
0 Likes
Message 5 of 7

Joshua.mursic
Advocate
Advocate
Thank you very much for your help!
Message 6 of 7

BrianEkins
Mentor
Mentor

I wasn't following this thread very closely. Was it an error in the code, or is there a bug in the API?

---------------------------------------------------------------
Brian Ekins
Inventor and Fusion 360 API Expert
Website/Blog: https://EkinsSolutions.com
0 Likes
Message 7 of 7

Joshua.mursic
Advocate
Advocate

Hey @BrianEkins, it seems like an API bug.

 

transformInput = inputs.addTriadCommandInput("constructionTransform",initialMatrix)
transformInput.transform = initialMatrix

 

when using addTriadCommandInput, the initial matrix that is provided is ignored or not used (line1).

But can be later set after the command Input has been created (line2).

0 Likes