Error while setting transform in Occurrences.addNewComponentCopy

Error while setting transform in Occurrences.addNewComponentCopy

brent.hagany
Explorer Explorer
1,572 Views
13 Replies
Message 1 of 14

Error while setting transform in Occurrences.addNewComponentCopy

brent.hagany
Explorer
Explorer

I'm pretty new to the API, and only barely understand proxies, so I'm hoping that there is a simple solution that I've overlooked.  When I am dealing with occurrences that are direct children of the root component, I have no issues with setting their transform2 properties directly, or with adding new component copies via the Occurrences.addNewComponentCopy method.

 

However, when I am dealing with occurrences that are nested within other occurrences (that is, not direct children of the root component), I begin to encounter issues with transform2.  I believe I have figured out how to make this work using a proxy occurrence when setting transform2 directly, but I get the same transform error when using addNewComponentCopy in a nested occurrence, and I don't see a way around this.

 

I've created a minimal script that demonstrates the problem:

 

import adsk.core, adsk.fusion, traceback, math


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

        ###
        # setting up parent and child occurrences / components
        ###
        rootComponent = app.activeProduct.rootComponent
        parentOccurrence = rootComponent.occurrences.addNewComponent(adsk.core.Matrix3D.create())
        parentComponent = parentOccurrence.component
        childOccurrence = parentComponent.occurrences.addNewComponent(adsk.core.Matrix3D.create())


        ###
        # here's the demonstration part
        ###

        # setting transform works
        childOccurrence.transform = adsk.core.Matrix3D.create()

        # setting transform2 fails with
        # "RuntimeError: 3 : transform overrides can only be set on Occurrence proxy from root component"
        childOccurrence.transform2 = adsk.core.Matrix3D.create()

        # setting transform2 won't work unless I create a proxy occurrence
        # this works, but I'm not sure it's completely correct
        childOccurrenceProxy = childOccurrence.createForAssemblyContext(parentOccurrence)
        childOccurrenceProxy.transform2 = adsk.core.Matrix3D.create()

        # however, using addNewComponentCopy fails with the same error as
        # setting transform2 without a proxy
        childOccurrenceCopy = parentComponent.occurrences.addNewComponentCopy(
            childOccurrenceProxy.component,
            adsk.core.Matrix3D.create())
    except:
        if ui:
            ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

 

The error I get (if you comment out the first naive attempt to set transform2) is this:

 

brenthagany_0-1670627152376.png

 

Does anyone have any insight about how to work around this problem?

 

Thanks,

Brent

 

0 Likes
Accepted solutions (3)
1,573 Views
13 Replies
Replies (13)
Message 2 of 14

kandennti
Mentor
Mentor
Accepted solution

Hi @brent.hagany .

 

I think your understanding of proxies is correct.

 

I did a little testing.

Running the following script will end up with the image.

 

# Fusion360API Python script
import traceback
import adsk.fusion
import adsk.core

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

        mat: adsk.core.Matrix3D = adsk.core.Matrix3D.create()
        mat.translation = adsk.core.Vector3D.create(-1,-1,-1)

        rootComponent: adsk.fusion.Component = app.activeProduct.rootComponent
        rootComponent.isOriginFolderLightBulbOn = True

        parentOccurrence: adsk.fusion.Occurrence = rootComponent.occurrences.addNewComponent(
            mat
        )
        parentComponent: adsk.fusion.Component = parentOccurrence.component
        parentComponent.isOriginFolderLightBulbOn = True

        childOccurrence: adsk.fusion.Occurrence  = parentComponent.occurrences.addNewComponent(
            mat
        )
        childOccurrence.component.isOriginFolderLightBulbOn = True

        print(f'version:{app.version}\n')
        dumpMatrix3D('**childOccurrence.transform**', childOccurrence.transform)
        dumpMatrix3D('**childOccurrence.transform2**', childOccurrence.transform2)
        print(f'**childOccurrence.name**\n{childOccurrence.name}\n')
        print(f'**childOccurrence.fullPathName**\n{childOccurrence.fullPathName}')

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


def dumpMatrix3D(msg: str, mat: adsk.core.Matrix3D):
    origin, xAxis, yAxis, zAxis = mat.getAsCoordinateSystem()
    msgLst = [
        f'origin:{origin.asArray()}',
        f'xAxis:{xAxis.asArray()}',
        f'yAxis:{yAxis.asArray()}',
        f'zAxis:{zAxis.asArray()}',
        ''
    ]
    print(msg)
    print('\n'.join(msgLst))

 

1.png

The result of the print is as follows.

 

version:2.0.15027

**childOccurrence.transform**
origin:(-1.0, -1.0, -1.0)
xAxis:(1.0, 0.0, 0.0)
yAxis:(0.0, 1.0, 0.0)
zAxis:(0.0, 0.0, 1.0)

**childOccurrence.transform2**
origin:(-1.0, -1.0, -1.0)
xAxis:(1.0, 0.0, 0.0)
yAxis:(0.0, 1.0, 0.0)
zAxis:(0.0, 0.0, 1.0)

**childOccurrence.name**
Component2:1

**childOccurrence.fullPathName**
Component2:1

 

 

The result I expected is as follows

 

version:2.0.15027

**childOccurrence.transform**
origin:(-1.0, -1.0, -1.0)
xAxis:(1.0, 0.0, 0.0)
yAxis:(0.0, 1.0, 0.0)
zAxis:(0.0, 0.0, 1.0)

**childOccurrence.transform2**
origin:(-2.0, -2.0, -2.0)
xAxis:(1.0, 0.0, 0.0)
yAxis:(0.0, 1.0, 0.0)
zAxis:(0.0, 0.0, 1.0)

**childOccurrence.name**
Component2:1

**childOccurrence.fullPathName**
Component1:1+Component2:1

 

 

I think "transform2" and "fullPathName" are not working correctly.

0 Likes
Message 3 of 14

brent.hagany
Explorer
Explorer
Interesting! There is definitely something I don't understand about the history behind transform and transform2, so I'm not coming to this with any expectations about how they should work. The fullPathName thing definitely doesn't match my expectations though. Thank you for looking into this! If there is indeed a bug here, is there a process for reporting it?
Message 4 of 14

kandennti
Mentor
Mentor
Accepted solution
0 Likes
Message 5 of 14

brent.hagany
Explorer
Explorer

Many thanks!

0 Likes
Message 6 of 14

kandennti
Mentor
Mentor

@brent.hagany .

 

I had made a big mistake.
"transform2" and "fullPathName" are working correctly.

# Fusion360API Python script
import traceback
import adsk.fusion
import adsk.core

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

        mat: adsk.core.Matrix3D = adsk.core.Matrix3D.create()
        mat.translation = adsk.core.Vector3D.create(-1,-1,-1)

        rootComponent: adsk.fusion.Component = app.activeProduct.rootComponent
        rootComponent.isOriginFolderLightBulbOn = True

        parentOccurrence: adsk.fusion.Occurrence = rootComponent.occurrences.addNewComponent(
            mat
        )
        parentComponent: adsk.fusion.Component = parentOccurrence.component
        parentComponent.isOriginFolderLightBulbOn = True

        childOccurrence: adsk.fusion.Occurrence = parentComponent.occurrences.addNewComponent(
            mat
        )
        childOccurrence.component.isOriginFolderLightBulbOn = True

        # Fixed the following
        childOccProxy: adsk.fusion.Occurrence = childOccurrence.createForAssemblyContext(parentOccurrence)

        print(f'version:{app.version}\n')
        dumpMatrix3D('**childOccurrence.transform**', childOccProxy.transform)
        dumpMatrix3D('**childOccurrence.transform2**', childOccProxy.transform2)
        print(f'**childOccurrence.name**\n{childOccProxy.name}\n')
        print(f'**childOccurrence.fullPathName**\n{childOccProxy.fullPathName}')

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

 

It is not mentioned in the documentation, but I feel that the reassignment of childOccurrenceProxy.transform2 is not allowed, as per the error message.

0 Likes
Message 7 of 14

kandennti
Mentor
Mentor

@brent.hagany .

 

Regarding the Occurrences.addNewComponentCopy method, when I do the same thing as the script in the GUI, I get a warning in position.

1.png

 

Although it is not mentioned in the documentation, I felt that the only components that can be used with the addNewComponentCopy method are those in rootComponent.occurrences.

https://help.autodesk.com/view/fusion360/ENU/?guid=GUID-2E04975A-94C1-4C85-8077-A01DAC1B12F1 

0 Likes
Message 8 of 14

brent.hagany
Explorer
Explorer

Thanks for following up @kanndenti.  I'm pretty confused by both of your messages, though.  I'll try to be clear about why, for each.

 

First confusion

 

In message 6 of this thread, you said "I feel that the reassignment of childOccurrenceProxy.transform2 is not allowed, as per the error message."  But I don't get an error when reassigning childOccurrenceProxy.transform2 (to be specific, line 33 of my script above does not throw an error) -- it appears to work correctly.  I didn't have a problem with this part, I was just demonstrating what I knew to work.

 

Second confusion

 

In message 7, you show an error from following steps in the GUI.  However, my script is trying to recreate steps I can do without error in the GUI.  Specifically, I follow these steps in a new document:

  • Create a new component (Component1)
  • With Component1 selected, create a second new component (Component2) as a child of Component1
  • Right click Component2 in the browser, and select "Copy"
  • Right click Component1 in the browser, and select "Paste New".  This creates a second child of Component1, called Component3.

When I follow these steps, the timeline for the document looks like this

brenthagany_0-1671048333278.png

and my browser looks like this

brenthagany_1-1671048358478.png

I'm confused about several things here:

  • what steps did you take to try to recreate my script?
  • where is the position feature in your timeline coming from?
  • since I can copy Component2 and "Paste New" to create Component3 in the GUI, and the documentation for addNewComponentCopy says 'This is the equivalent of copying and using the "Paste New" command in the user interface,' I feel I must be missing something to recreate the GUI interaction I just described.

Thanks again for your help and patience

0 Likes
Message 9 of 14

brent.hagany
Explorer
Explorer

For clarity -- recreating the GUI steps I outlined in the last message is my goal, and I am not primarily concerned with transforms.  I am only talking about transforms because addNewComponentCopy throws an error about transforms when I try to use it.

 

More concretely, the following script is trying to recreate the GUI steps I outlined in message 8, but it fails with "RuntimeError: 3 : transform overrides can only be set on Occurrence proxy from root component".  I would be very pleased if I could make something like this work

import adsk.core, adsk.fusion, traceback, math


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

        ###
        # setting up parent and child occurrences / components
        ###
        rootComponent = app.activeProduct.rootComponent
        parentOccurrence = rootComponent.occurrences.addNewComponent(adsk.core.Matrix3D.create())
        parentComponent = parentOccurrence.component
        childOccurrence = parentComponent.occurrences.addNewComponent(adsk.core.Matrix3D.create())

        ###
        # Fails with "RuntimeError: 3 : transform overrides can only be set on Occurrence proxy from root component"
        ###
        childOccurrenceCopy = parentComponent.occurrences.addNewComponentCopy(
            childOccurrence.component,
            adsk.core.Matrix3D.create())
    except:
        if ui:
            ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

 

0 Likes
Message 10 of 14

kandennti
Mentor
Mentor

@brent.hagany .

 

I was confused because I had tried so many things.

 

First confusion

The proxy was working correctly.

 

Second confusion

I was getting different results because I was trying a Matrix3D that I was moving around, like this

        mat: adsk.core.Matrix3D = adsk.core.Matrix3D.create()
        mat.translation = adsk.core.Vector3D.create(-1,-1,-1)

 

Indeed, when the same process was performed in the GUI, no warning was issued. I do not know why.

0 Likes
Message 11 of 14

kandennti
Mentor
Mentor
Accepted solution

@brent.hagany .

 

I don't know the cause, but so far it seems that the only way to avoid stopping with an error is to use Try or a text command.

import adsk.core, adsk.fusion, traceback

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

        ###
        # setting up parent and child occurrences / components
        ###
        rootComponent = app.activeProduct.rootComponent
        parentOccurrence = rootComponent.occurrences.addNewComponent(adsk.core.Matrix3D.create())

        parentComponent = parentOccurrence.component
        childOccurrence = parentComponent.occurrences.addNewComponent(adsk.core.Matrix3D.create())
        childOccurrenceProxy = childOccurrence.createForAssemblyContext(parentOccurrence)

        ###
        # Fails with "RuntimeError: 3 : transform overrides can only be set on Occurrence proxy from root component"
        ###
        try:
            childOccurrenceCopy = parentComponent.occurrences.addNewComponentCopy(
                childOccurrence.component,
                adsk.core.Matrix3D.create())
        except:
            pass

        childOccurrenceCopy_from_textCmd = exec_addNewComponentCopy(childOccurrenceProxy, parentOccurrence)

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


def exec_addNewComponentCopy(
    refarenceOcc: adsk.fusion.Occurrence,
    targetOcc: adsk.fusion.Occurrence) -> adsk.fusion.Occurrence:

    app: adsk.core.Application = adsk.core.Application.get()
    sels: adsk.core.Selections = app.userInterface.activeSelections

    sels.clear()
    sels.add(refarenceOcc)
    app.executeTextCommand(u'Commands.Start CopyCommand')

    sels.clear()
    sels.add(targetOcc)
    app.executeTextCommand(u'Commands.Start FusionPasteNewCommand')
    app.executeTextCommand(u'NuCommands.CommitCmd')

    return targetOcc.component.occurrences[-1]
0 Likes
Message 12 of 14

brent.hagany
Explorer
Explorer

@kandennti thank you again for spending so much time on this.  I hadn't even heard of text commands before, so I'm delighted at this workaround.  Hopefully a solution for the original addNewComponentCopy issue will soon reveal itself, but in the meantime, I'm more than satisfied at making it work this way.  Thanks again!

0 Likes
Message 13 of 14

kandennti
Mentor
Mentor
0 Likes
Message 14 of 14

brent.hagany
Explorer
Explorer

@kandennti no apologies are necessary, I assure you!  You have been a great help