Issues replacing joint.geometryOrOriginOne

Issues replacing joint.geometryOrOriginOne

en9y37
Advocate Advocate
595 Views
7 Replies
Message 1 of 8

Issues replacing joint.geometryOrOriginOne

en9y37
Advocate
Advocate

Hi all!

 

I want to replace the occurrence of a referenced component for another.

 

The already inserted component 'Insert1' is joined by a joint to 'Base' component, the joint.geometryOrOriginOne is a Joint origin defined in 'Insert1'.

 

en9y37_0-1676548817647.png

 

When the component 'Insert2' is inserted to 'Base', I'd like to replace the joint.geometryOrOriginOne for a Joint Origin defined the same way inside 'Insert2', but I always get this error: 

'RuntimeError: 5 : Provided input paths or alignments are not valid.'

 

This should be the final result, which can be easily replicated manually:

 

en9y37_1-1676549172820.png

 

 

Here is the code and the designs which reproduce my issue:

import adsk.core, adsk.fusion, adsk.cam, traceback

def run(context):
    ui = None
    try:
        app = adsk.core.Application.get()
        ui = app.userInterface
        design = adsk.fusion.Design.cast(app.activeProduct)
        rootComp = design.rootComponent
        
        #Active project
        project = app.activeDocument.dataFile.parentProject
        
        #Design to insert 
        designsInProject = project.rootFolder.dataFiles
        for designToInsert in designsInProject:
            if designToInsert.name == 'Insert2':
                break
        
        #Get the joint in 'Base' design
        joint = rootComp.joints.item(0)
        
        #Rollback timeline
        joint.timelineObject.rollTo(True)
        
        #Insert design 'Insert2'
        occInsert2 = rootComp.occurrences.addByInsert(designToInsert, adsk.core.Matrix3D.create(), True)
        
        #Get the joint origin from design 'Insert2'
        jointOriginInsert2 = occInsert2.component.jointOrigins.item(0)
        
        #Replacement of joint origin in joint
        joint.geometryOrOriginOne = jointOriginInsert2
        
        #Move timeline to end
        design.timeline.moveToEnd()
        
        #Delete 'Insert1'
        for occ in rootComp.allOccurrences:
            if occ.component.name == 'Insert1':
                occ.deleteMe()
                break          
        
    except:
        if ui:
            ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

 

Any idea about this? Thanks in advance.

0 Likes
596 Views
7 Replies
Replies (7)
Message 2 of 8

BrianEkins
Mentor
Mentor

I didn't test this, but I believe if you add the last line shown here, it will work.

#Get the joint origin from design 'Insert2'
jointOriginInsert2 = occInsert2.component.jointOrigins.item(0)
jointOriginInsert2 = jointOriginInsert2.createForAssemblyContext(occInsert2)

 

The best way to understand why this line is needed is to consider the case where you have two of the Insert2 parts in the assembly. When you get the joint origin, you're getting it from the component. The component doesn't know anything about how it's being used in the assembly. In the assembly, you would have two occurrences that both reference the component. The createForAssembly call is defining which occurrence you want the reference to the joint origin to be relative to. This topic in the help describes the concept of "proxies".

---------------------------------------------------------------
Brian Ekins
Inventor and Fusion 360 API Expert
Website/Blog: https://EkinsSolutions.com
Message 3 of 8

kandennti
Mentor
Mentor

@BrianEkins @en9y37 .

 

I tried using the joint as a proxy.
The error no longer occurs, but the model is not replaced.

1.png

 

At first I thought it might be due to an external component, but the same thing happened with the internal component and the joints were not replaced.

 

I do not know the cause, but I noticed one thing.
The geometryOrOriginOne property has changed and the value of Joint.occurrenceOne has not been replaced.
Looking at the documentation it should match the occurrence in the geometryOrOriginOne property.

 

Here is what I have tested.

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

def run(context):
    ui = None
    try:
        app = adsk.core.Application.get()
        ui = app.userInterface
        design = adsk.fusion.Design.cast(app.activeProduct)
        rootComp = design.rootComponent

        #Active project
        # project = app.activeDocument.dataFile.parentProject

        #Design to insert 
        # designsInProject = project.rootFolder.dataFiles
        designsInProject: adsk.core.DataFiles = app.data.activeFolder.dataFiles
        for designToInsert in designsInProject:
            if designToInsert.name == 'Insert2':
                break

        #Get the joint in 'Base' design
        joint = rootComp.joints.item(0)

        #Rollback timeline
        joint.timelineObject.rollTo(True)

        #Insert design 'Insert2'
        occInsert2 = rootComp.occurrences.addByInsert(designToInsert, adsk.core.Matrix3D.create(), True)

        #Get the joint origin from design 'Insert2'
        jointOriginInsert2 = occInsert2.component.jointOrigins.item(0)
        jointOriginInsert2 = jointOriginInsert2.createForAssemblyContext(occInsert2)

        dump_joint_info(joint, '** before **')

        #Replacement of joint origin in joint
        joint.geometryOrOriginOne = jointOriginInsert2

        dump_joint_info(joint, '** after **')

        #Move timeline to end
        design.timeline.moveToEnd()

        #Delete 'Insert1'
        for occ in rootComp.allOccurrences:
            if occ.component.name == 'Insert1':
                occ.deleteMe()
                break

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


def dump_joint_info(
    joint: adsk.fusion.Joint,
    msg: str) -> None:

    infos = [
        f'{msg}',
        f'joint.geometryOrOriginOne.parentComponent.name:{joint.geometryOrOriginOne.parentComponent.name}',
        f'joint.occurrenceOne.component.name:{joint.occurrenceOne.component.name}'
    ]
    print('\n'.join(infos))

 

The result of the run looks like this.

** before **
joint.geometryOrOriginOne.parentComponent.name:Insert1 v1
joint.occurrenceOne.component.name:Insert1 v1
** after **
joint.geometryOrOriginOne.parentComponent.name:Insert2 v2 v1
joint.occurrenceOne.component.name:Insert1 v1

 

I feel like a bug.(ver2.0.15299)

Message 4 of 8

kandennti
Mentor
Mentor

Since we had no choice, we used a text command to change the geometryOrOriginOne property.

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

def run(context):
    ui = None
    try:
        app = adsk.core.Application.get()
        ui = app.userInterface
        design = adsk.fusion.Design.cast(app.activeProduct)
        rootComp = design.rootComponent

        #Active project
        # project = app.activeDocument.dataFile.parentProject

        #Design to insert 
        # designsInProject = project.rootFolder.dataFiles
        designsInProject: adsk.core.DataFiles = app.data.activeFolder.dataFiles
        for designToInsert in designsInProject:
            if designToInsert.name == 'Insert2':
                break

        #Get the joint in 'Base' design
        joint = rootComp.joints.item(0)

        #Rollback timeline
        joint.timelineObject.rollTo(True)

        #Insert design 'Insert2'
        occInsert2 = rootComp.occurrences.addByInsert(designToInsert, adsk.core.Matrix3D.create(), True)

        #Get the joint origin from design 'Insert2'
        jointOriginInsert2 = occInsert2.component.jointOrigins.item(0)
        jointOriginInsert2 = jointOriginInsert2.createForAssemblyContext(occInsert2)

        dump_joint_info(joint, '** before **')

        removeOcc: adsk.fusion.Occurrence = joint.occurrenceOne

        #Replacement of joint origin in joint
        # joint.geometryOrOriginOne = jointOriginInsert2
        design.timeline.moveToEnd()
        replace_geometryOrOriginOne(joint, jointOriginInsert2)

        dump_joint_info(joint, '** after **')

        #Move timeline to end
        # design.timeline.moveToEnd()

        #Delete 'Insert1'
        # for occ in rootComp.allOccurrences:
        #     if occ.component.name == 'Insert1':
        #         occ.deleteMe()
        #         break
        removeOcc.deleteMe()

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


def replace_geometryOrOriginOne(
    joint: adsk.fusion.Joint,
    jointOrigin: adsk.fusion.JointOrigin,
) -> None:

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

    sels.clear()
    sels.add(joint)

    app.executeTextCommand(u'Commands.Start DcEditJointAssembleCmd')
    app.executeTextCommand(u'UI.EnableCommandInput Snap11')
    sels.add(jointOrigin)
    app.executeTextCommand(u'NuCommands.CommitCmd')


def dump_joint_info(
    joint: adsk.fusion.Joint,
    msg: str) -> None:

    infos = [
        f'{msg}',
        f'joint.geometryOrOriginOne.parentComponent.name:{joint.geometryOrOriginOne.parentComponent.name}',
        f'joint.occurrenceOne.component.name:{joint.occurrenceOne.component.name}'
    ]
    print('\n'.join(infos))

 

1.png

 

joint.occurrenceOne was also changed correctly.

** before **
joint.geometryOrOriginOne.parentComponent.name:Insert1 v1
joint.occurrenceOne.component.name:Insert1 v1
** after **
joint.geometryOrOriginOne.parentComponent.name:Insert2 v2 v1
joint.occurrenceOne.component.name:Insert2 v2 v1

 

Message 5 of 8

en9y37
Advocate
Advocate

Thanks again for your time @kandennti and @BrianEkins , quite a tricky thing the proxies stuff...

 

I've tested the text command based solution, and it works properly. I'll try to deploy it in the add-in I'm developing and I'll let you know about the results.

 

I've also tried with another walkaround which works properly. The idea is based on collecting the properties from the joint, and then create a new one with those properties. Here I leave the code:

 

import adsk.core, adsk.fusion, adsk.cam, traceback

def run(context):
    ui = None
    try:
        app = adsk.core.Application.get()
        ui = app.userInterface
        design = adsk.fusion.Design.cast(app.activeProduct)
        rootComp = design.rootComponent
        
        #Active project
        project = app.activeDocument.dataFile.parentProject
        
        #Design to insert 
        designsInProject = project.rootFolder.dataFiles
        for designToInsert in designsInProject:
            if designToInsert.name == 'Insert2':
                break
        
        #Get the joint in 'Base' design
        joint = rootComp.joints.item(0)
        removeOcc = joint.occurrenceOne
        
        #Rollback timeline
        joint.timelineObject.rollTo(True)
        
        #Insert design 'Insert2'
        occInsert2 = rootComp.occurrences.addByInsert(designToInsert, adsk.core.Matrix3D.create(), True)
        
        #Get the joint origin from design 'Insert2'
        jointOriginInsert2 = occInsert2.component.jointOrigins.item(0).createForAssemblyContext(occInsert2)
        
        #Get properties from the joint
        jointGeometryOriginTwo = joint.geometryOrOriginTwo
        flipped = joint.isFlipped
        
        #Create input for new joint
        jointInput = rootComp.joints.createInput(jointOriginInsert2, jointGeometryOriginTwo)
        jointInput.isFlipped = flipped
        
        #Add new joint
        newJoint = rootComp.joints.add(jointInput)
               
        #Move timeline to end
        design.timeline.moveToEnd()
        
        #Delete joint
        joint.deleteMe()
        
        #Delete 'Insert1'
        removeOcc.deleteMe()
        
    except:
        if ui:
            ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

 

Anyway, it seems there's some kind of bug that doesn't allow us to make this thing in the proper way.

0 Likes
Message 6 of 8

BrianEkins
Mentor
Mentor

I played with this some more, and it appears there is a bug. I'll make sure a bug gets filed.

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

en9y37
Advocate
Advocate

Hi again. I've tried to implement mine and @kandennti 's walkarounds in my add-in, and none of them works.

 

The script I published in this thread was a sheer simplification of a much more complex command, and I guess there are other factors that doesn't allow to make those walkarounds to work properly. I hope that once the bug is fixed, everything works fine.

 

Thanks @BrianEkins for reporting this bug, from your experience, can you guess how long it takes this kind of bugs to be fixed more or less?

 

 

0 Likes
Message 8 of 8

kandennti
Mentor
Mentor
0 Likes