Hey @andreas ,
It's been awhile since I've worked on or used this script, but I was ultimately able to get my whole assembly exported with the right positioning. It took some reworking of some of my designs so they actually exported correctly. I doubt this will work 100% for you but maybe it can serve as a starting point. Hope this helps:
import adsk.core, adsk.fusion, adsk.cam, traceback
import pprint
import json
import os
import glob
outputDir = 'C:\\Users\\User\\dev\\pfweb\\dist\\assets'
jsonOutputDir = 'C:\\Users\\User\\dev\\pfweb\\src\\models'
uniqueComps = dict()
references = dict()
def traverseFolders(folder):
parentFolder = folder.parentFolder
if parentFolder:
return traverseFolders(parentFolder) + '>' + folder.name
else:
return folder.name
def fullFolderPath(occ):
try:
folder = occ.component.parentDesign.parentDocument.dataFile.parentFolder
return traverseFolders(folder)
except Exception as identifier:
return ' FAILED TO GET FOLDER'
def exportTest(occurrence, currentLevel):
# TODO: This is a 'quick fix' for top level components getting exported like 'Left Section'
# Find a better way
if currentLevel == 1:
if occurrence.component.partNumber == "Baltic Birch":
return True
else:
return False
if occurrence.component.partNumber == "Candy Cane Shot Section v101":
return False
occurrences = occurrence.childOccurrences
if not(occurrence.isLightBulbOn):
return False
# if I don't have any children then I am a leaf component so I should be exported
elif not(occurrences):
return True
numReferencedComponents = 0
for i in range(0, occurrences.count):
occ = occurrences.item(i)
# if any of these children are visible and
if occ.isLightBulbOn and occ.isReferencedComponent:
return False
return True
def isIdentityMatrix(m):
mIdent = m.copy()
mIdent.setToIdentity()
return m.isEqualTo(mIdent)
# Performs a recursive traversal of an entire assembly structure.
def traverseAssembly(occurrences, currentLevel, inputString):
toBeExported = None
for j in range(0, occurrences.count):
occ = occurrences.item(j)
toBeExported = exportTest(occ, currentLevel)
inputString += spaces(currentLevel*5) + ' Name: ' + occ.name + ', toBeExported: ' + str(toBeExported) + '\n'
# TODO: This is for testing purposes, need to remove
if not(toBeExported):
inputString = traverseAssembly(occ.childOccurrences, currentLevel+1, inputString)
else:
# Fusion is outputting these units as CENTIMETERS
m = []
t1 = adsk.core.Matrix3D.create()
t2 = adsk.core.Matrix3D.create()
t3 = occ.transform
# transform in relation to its parent component
if occ.nativeObject:
t1 = occ.nativeObject.transform
# transform in relation to the current document
if occ.assemblyContext:
t2 = occ.assemblyContext.transform
t1.transformBy(t2)
for row in range(0, 4):
m.append([0]*4)
for column in range(0, 4):
m[row][column] = t1.getCell(row, column)
partNumber = occ.component.partNumber
uniqueComps[partNumber]['items'].append(m)
return inputString
def spaces(spaceCount):
result = ''
for i in range(0, spaceCount):
result += ' '
return result
def uniqueComponents(occs):
comps = []
for i in range(0, occs.count):
comps.append(occs.item(i).component)
return comps
def run(context):
# traverse assembly
# locate all occurrences, part numbers that are to be exported with a position
ui = None
try:
app = adsk.core.Application.get()
ui = app.userInterface
product = app.activeProduct
design = adsk.fusion.Design.cast(product)
if not design:
ui.messageBox('No active Fusion design', 'No Design')
return
# Get the root component of the active design.
rootComp = design.rootComponent
# Create the title for the output.
resultString = 'Root (' + design.parentDocument.name + ')\n'
# identify all unique components
occurrences = rootComp.allOccurrences
for i in range(0, occurrences.count):
occ = occurrences.item(i)
pn = occ.component.partNumber
if pn not in uniqueComps.keys():
uniqueComps[pn] = dict()
references[pn] = dict()
#uniqueComps[pn]['filename'] = str(i)
uniqueComps[pn]['items'] = []
references[pn]['occurrence'] = occ
references[pn]['component'] = occ.component
# Call the recursive function to traverse the assembly and build the output string.
resultString = traverseAssembly(rootComp.occurrences.asList, 1, resultString)
# Display the result.
# Write the results to the TEXT COMMANDS window.
textPalette = ui.palettes.itemById('TextCommands')
if not textPalette.isVisible:
textPalette.isVisible = True
textPalette.writeText(resultString)
# clear out existing files
files = glob.glob(outputDir + '//*')
for f in files:
os.remove(f)
#
filteredComps = dict(filter(lambda elem: len(elem[1]['items']) > 0, uniqueComps.items()))
fn = 0
for pn in filteredComps:
comp = filteredComps[pn]
if len(comp['items']) > 0:
# iterate through uniqueComps
# remove entries with empty item
try:
filename = fn
filteredComps[pn]['filename'] = filename
fn += 1
exportMgr = adsk.fusion.ExportManager.cast(design.exportManager)
stlOptions = exportMgr.createSTLExportOptions(references[pn]['component'])
stlOptions.meshRefinement = adsk.fusion.MeshRefinementSettings.MeshRefinementLow
stlOptions.filename = outputDir + '//' + str(filename)
exportMgr.execute(stlOptions)
except Exception as e:
print(e)
print('Failed part number is: ' + pn)
finally:
pass
with open(jsonOutputDir + '//models.json', 'w') as fp:
json.dump(filteredComps, fp, sort_keys=True, indent=4)
except:
if ui:
ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
# # export code
# # Save the file as STL.
# exportMgr = adsk.fusion.ExportManager.cast(des.exportManager)
# stlOptions = exportMgr.createSTLExportOptions(rootComp)
# stlOptions.meshRefinement = adsk.fusion.MeshRefinementSettings.MeshRefinementMedium
# stlOptions.filename = filename
# exportMgr.execute(stlOptions)